diff -u --recursive --new-file v1.3.72/linux/CREDITS linux/CREDITS
--- v1.3.72/linux/CREDITS	Sun Mar 10 09:49:45 1996
+++ linux/CREDITS	Mon Mar 11 11:25:57 1996
@@ -1027,6 +1027,16 @@
 S: Utrecht
 S: The Netherlands
 
+N: Henrik Storner
+E: storner@osiris.ping.dk
+E: storner@olicom.dk
+W: http://eolicom.olicom.dk/~storner/
+D: Configure script: tristate, bugfixes
+D: vfat/msdos integration, kerneld docs, Linux promotion
+S: Chr. Winthersvej 1 B, st.th.
+S: DK-1860 Frederiksberg C
+S: Denmark
+
 N: Drew Sullivan
 E: drew@lethe.north.net
 D: iBCS2 developer
diff -u --recursive --new-file v1.3.72/linux/Documentation/BUG-HUNTING linux/Documentation/BUG-HUNTING
--- v1.3.72/linux/Documentation/BUG-HUNTING	Thu Jan  1 02:00:00 1970
+++ linux/Documentation/BUG-HUNTING	Sun Mar 10 09:28:55 1996
@@ -0,0 +1,92 @@
+[Sat Mar  2 10:32:33 PST 1996 KERNEL_BUG-HOWTO lm@sgi.com (Larry McVoy)]
+
+This is how to track down a bug if you know nothing about kernel hacking.  
+It's a brute force approach but it works pretty well.
+
+You need:
+
+        . A reproducable bug - it has to happen predictably (sorry)
+        . All the kernel tar files from a revision that worked to the
+          revision that doesn't
+
+You will then do:
+
+        . Rebuild a revision that you believe works, install, and verify that.
+        . Do a binary search over the kernels to figure out which one
+          introduced the bug.  I.e., suppose 1.3.28 didn't have the bug, but 
+          you know that 1.3.69 does.  Pick a kernel in the middle and build
+          that, like 1.3.50.  Build & test; if it works, pick the mid point
+          between .50 and .69, else the mid point between .28 and .50.
+        . You'll narrow it down to the kernel that introduced the bug.  You
+          can probably do better than this but it gets tricky.  
+
+        . Narrow it down to a subdirectory
+
+          - Copy kernel that works into "test".  Let's say that 3.62 works,
+            but 3.63 doesn't.  So you diff -r those two kernels and come
+            up with a list of directories that changed.  For each of those
+            directories:
+
+                Copy the non-working directory next to the working directory
+                as "dir.63".  
+                One directory at time, try moving the working directory to
+                "dir.62" and mv dir.63 dir"time, try 
+
+                        mv dir dir.62
+                        mv dir.63 dir
+                        find dir -name '*.[oa]' -print | xargs rm -f
+
+                And then rebuild and retest.  Assuming that all related
+                changes were contained in the sub directory, this should 
+                isolate the change to a directory.  
+
+                Problems: changes in header files may have occurred; I've
+                found in my case that they were self explanatory - you may 
+                or may not want to give up when that happens.
+
+        . Narrow it down to a file
+
+          - You can apply the same technique to each file in the directory,
+            hoping that the changes in that file are self contained.  
+            
+        . Narrow it down to a routine
+
+          - You can take the old file and the new file and manually create
+            a merged file that has
+
+                #ifdef VER62
+                routine()
+                {
+                        ...
+                }
+                #else
+                routine()
+                {
+                        ...
+                }
+                #endif
+
+            And then walk through that file, one routine at a time and
+            prefix it with
+
+                #define VER62
+                /* both routines here */
+                #undef VER62
+
+            Then recompile, retest, move the ifdefs until you find the one
+            that makes the difference.
+
+Finally, you take all the info that you have, kernel revisions, bug
+description, the extent to which you have narrowed it down, and pass 
+that off to whomever you believe is the maintainer of that section.
+A post to linux.dev.kernel isn't such a bad idea if you've done some
+work to narrow it down.
+
+If you get it down to a routine, you'll probably get a fix in 24 hours.
+
+My apologies to Linus and the other kernel hackers for describing this
+brute force approach, it's hardly what a kernel hack would do.  However,
+it does work and it lets non-hackers help bug fix.  And it is cool
+because Linux snapshots will let you do this - something that you can't
+do with vender supplied releases.
+
diff -u --recursive --new-file v1.3.72/linux/Documentation/Configure.help linux/Documentation/Configure.help
--- v1.3.72/linux/Documentation/Configure.help	Sun Mar 10 09:49:46 1996
+++ linux/Documentation/Configure.help	Mon Mar 11 18:09:57 1996
@@ -11,9 +11,9 @@
 #
 # Format of this file: description<nl>variable<nl>helptext<nl><nl>. 
 # If the question being documented is of type "choice", we list
-# only the first occuring config variable. The help texts
+# only the first occurring config variable. The help texts
 # must not contain empty lines. No variable should occur twice; if it
-# does, only the first occurance will be used by Configure. The lines
+# does, only the first occurrence will be used by Configure. The lines
 # in a help text should be indented two positions. Lines starting with
 # `#' are ignored. To be nice to menuconfig, limit your lines to 70
 # chars. Use emacs' kfill.el to edit this file or you lose.
@@ -79,6 +79,14 @@
   normal users won't need the RAM disk functionality, and can thus say
   N here.
 
+Initial RAM disk (initrd) support
+CONFIG_BLK_DEV_INITRD
+  The initial RAM disk is a RAM disk that is loaded by the boot loader
+  (LOADLIN or LILO) and that is mounted as root before the normal boot
+  procedure. It is typically used to load modules needed to mount the
+  "real" root file system, etc. See Documentation/initrd.txt for
+  details.
+
 Loop device support
 CONFIG_BLK_DEV_LOOP
   Enabling this option will allow you to mount a file as a file system.
@@ -86,9 +94,10 @@
   burning the CD, or want to use floppy images without first writing
   them to floppy.
   This option also allows one to mount a filesystem with encryption.
-  To use these features, you will need the program losetup, available
-  via ftp (user: anonymous) from sunsite.unc.edu in the package 
-  lo.X.Y.tar.gz.
+  To use these features, you need a recent version of mount, such as
+  the one found at ftp.win.tue.nl:/pub/linux/util/mount-2.5X.tar.gz.
+  If you want to use encryption, you might also be interested in the
+  (old) DES package ftp.funet.fi:/pub/OS/Linux/BETA/loop/des.1.tar.gz.
   Note that this loop device has nothing to do with the loopback
   device used for network connections from the machine to itself.
   Most users will answer N here.
@@ -236,6 +245,35 @@
   Very old 8 bit hard disk controllers used in the IBM XT
   computer. Pretty unlikely that you have this: say N.
 
+Multiple devices driver support
+CONFIG_BLK_DEV_MD
+  This driver lets you combine several harddisk partitions into one
+  logical block device. Information about how and why to use it and the
+  necessary tools are available over ftp (user: anonymous) from
+  sweet-smoke.ufr-info-p7.ibp.fr/pub/public/Linux in the md package
+  and the md-FAQ. Please read drivers/block/README.md. If unsure, say
+  N.
+
+Linear (append) mode
+CONFIG_MD_LINEAR
+  If you enable this, then your multiple devices driver will be able
+  to use the so-called linear mode, i.e. it will combine the harddisk
+  partitions by simply appending one to the other. If you want to
+  compile this as a module ( = code which can be inserted in and
+  removed from the running kernel whenever you want), say M here and
+  read Documentation/modules.txt. If unsure, say Y.
+
+RAID-0 (striping) mode
+CONFIG_MD_STRIPED
+  If you enable this, then your multiple devices driver will be able
+  to use the so-called raid0 mode, i.e. it will combine the harddisk
+  partitions into one logical device in such a fashion as to fill them
+  up evenly, one chunk here and one chunk there. This will increase
+  the throughput rate if the partitions reside on distinct disks.  If
+  you want to compile this as a module ( = code which can be inserted
+  in and removed from the running kernel whenever you want), say M
+  here and read Documentation/modules.txt. If unsure, say Y.
+
 Support for Deskstation RPC44 
 CONFIG_DESKSTATION_RPC44
   This is a machine with a R4400 100 MHz CPU. To compile a Linux
@@ -367,7 +405,7 @@
   ** EB66: "Evaluation Board"
   ** EB66+: "Evaluation Board"
 ###
-### Add info about Platform2000
+### Add info about Platform2000, EB164
 ###
 
 Limit memory to low 16MB
@@ -537,7 +575,9 @@
   specify "486" or "Pentium" or "PPro", then the kernel will run on
   486 and Pentium (=586) and Pentium Pro (=686) CPUs. In rare cases,
   it can make sense to specify "Pentium" even if running a 486: the
-  kernel will be smaller but slower.
+  kernel will be smaller but slower. On the other hand, if you use a
+  compiler before gcc 2.7 (say "gcc -v" to find out), then you have to
+  say "486" here even if running on a Pentium machine.
 
 Compile the kernel into the ELF object format 
 CONFIG_ELF_KERNEL
@@ -1039,9 +1079,9 @@
   understand if you enable this; it will enlarge your kernel by about
   12KB. If in doubt, say Y.
 
-Automatic Disk Geometery Translation 
+Automatic Disk Geometry Translation 
 CONFIG_SCSI_AUTO_BIOSP
-  When this is set to Y, Linux will examine the parition table to
+  When this is set to Y, Linux will examine the partition table to
   determine the mapping used under the other operating systems (e.g.
   DOS), and set these parameters to the determined values, or if the
   disk has no valid partition table, to an optimal value.
@@ -2328,7 +2368,8 @@
   NT installed on your MSDOS partitions, you should use the VFAT
   filesystem instead, or you will not be able to see the long
   filenames generated by Windows'95 / Windows NT. This option will
-  enlarge your kernel by about 7 kB. If unsure, say Y.  If you want to
+  enlarge your kernel by about 7 kB. If unsure, say Y. This will only
+  work if you said Y to "fat fs support" as well. If you want to
   compile this as a module however ( = code which can be inserted in
   and removed from the running kernel whenever you want), say M here
   and read Documentation/modules.txt. Note that the filesystem of your
@@ -2341,11 +2382,11 @@
   filenames used by Windows'95 and Windows NT fat-based (not NTFS)
   partitions. It does not support Windows'95 compressed filesystems.
   You cannot use the VFAT filesystem for your root partition; use
-  UMSDOS instead. This option enlarges your kernel by about 10 kB. 
+  UMSDOS instead. This option enlarges your kernel by about 10 kB and
+  it only works if you enabled the "fat fs support" above. 
   If unsure, say N. If you want to compile this as a module ( = code 
   which can be inserted in and removed from the running kernel whenever 
-  you want), say M here and read Documentation/modules.txt. Note that 
-  the filesystem of your root partition cannot be a module.
+  you want), say M here and read Documentation/modules.txt.
 
 umsdos: Unix like fs on top of std MSDOS fs
 CONFIG_UMSDOS_FS
@@ -2360,11 +2401,13 @@
   also allows unix style softlinks and owner/permissions of files on
   MSDOS floppies. You will need a program called umssync in order to
   make use of umsdos. Read Documentation/filesystems/umsdos.txt. This
-  option enlarges your kernel by about 25 kB. If unsure, say N.  If
-  you want to compile this as a module ( = code which can be inserted
-  in and removed from the running kernel whenever you want), say M
-  here and read Documentation/modules.txt. Note that the filesystem of
-  your root partition cannot be a module.
+  option enlarges your kernel by about 25 kB and it only works if you
+  enabled both "fat fs support" and "msdos fs support" above. If
+  unsure, say N.  If you want to compile this as a module ( = code
+  which can be inserted in and removed from the running kernel
+  whenever you want), say M here and read
+  Documentation/modules.txt. Note that the filesystem of your root
+  partition cannot be a module.
 
 /proc filesystem support
 CONFIG_PROC_FS
@@ -2708,7 +2751,7 @@
   result in rebooting the machine. This could be useful for a
   networked machine that needs to come back online as fast as possible
   after a lock-up. There's a watchdog implementation entirely in
-  software (which sometimes fail to reboot the machine) and a driver
+  software (which can sometimes fail to reboot the machine) and a driver
   for hardware watchdog boards, which are more robust and can also
   keep track of the temperature inside your computer. For details,
   read Documentation/watchdog.txt in the kernel source. If unsure, say
@@ -2917,4 +2960,5 @@
 # LocalWords:  Keepalive linefill RELCOM keepalive analogue CDR conf CDI INIT
 # LocalWords:  OPTi isp irq noisp VFAT vfat NTFS losetup dmsdosfs dosfs ISDN MP
 # LocalWords:  NOWAYOUT behaviour dialin isdn callback BTX Teles ICN EDSS Cisco
-# LocalWords:  ipppd syncppp RFC MPP VJ downloaded icn NICCY Creatix shmem
+# LocalWords:  ipppd syncppp RFC MPP VJ downloaded icn NICCY Creatix shmem ufr
+# LocalWords:  ibp md ARCnet ether encap NDIS arcether ODI Amigas AmiTCP NetBSD
diff -u --recursive --new-file v1.3.72/linux/Documentation/devices.tex linux/Documentation/devices.tex
--- v1.3.72/linux/Documentation/devices.tex	Tue Mar  5 10:10:44 1996
+++ linux/Documentation/devices.tex	Sun Mar 10 09:40:36 1996
@@ -42,7 +42,7 @@
 %
 \title{{\bf Linux Allocated Devices}}
 \author{Maintained by H. Peter Anvin $<$hpa@zytor.com$>$}
-\date{Last revised: March 2, 1996}
+\date{Last revised: March 9, 1996}
 \maketitle
 %
 \noindent
@@ -88,11 +88,11 @@
 \major{ 5}{}{char }{Alternate TTY devices}
 \major{ 6}{}{char }{Parallel printer devices}
 \major{ 7}{}{char }{Virtual console access devices}
+\major{  }{}{block}{Loopback devices}
 \major{ 8}{}{block}{SCSI disk devices}
 \major{ 9}{}{char }{SCSI tape devices}
 \major{  }{}{block}{Metadisk (RAID) devices}
 \major{10}{}{char }{Non-serial mice, misc features}
-\major{  }{}{block}{Loopback devices}
 \major{11}{}{char }{Raw keyboard device}
 \major{  }{}{block}{SCSI CD-ROM devices}
 \major{12}{}{char }{QIC-02 tape}
@@ -122,7 +122,7 @@
 \major{  }{}{block}{Sony CDU-535 CD-ROM}
 \major{25}{}{char }{Stallion serial card -- alternate devices}
 \major{  }{}{block}{First Matsushita (Panasonic/SoundBlaster) CD-ROM}
-\major{26}{}{char }{Frame grabbers}
+\major{26}{}{char }{Quanta WinVision frame grabber}
 \major{  }{}{block}{Second Matsushita (Panasonic/SoundBlaster) CD-ROM}
 \major{27}{}{char }{QIC-117 tape}
 \major{  }{}{block}{Third Matsushita (Panasonic/SoundBlaster) CD-ROM}
@@ -150,13 +150,15 @@
 \major{  }{}{block}{Zorro II ramdisk}
 \major{38}{}{char }{Myricom PCI Myrinet board}
 \major{39}{}{char }{ML-16P experimental I/O board}
-\major{40}{}{}{Unallocated}
+\major{40}{}{char }{Matrox Meteor frame grabber}
 \major{41}{}{char }{Yet Another Micro Monitor}
 \major{42}{}{}{Demo/sample use}
 \major{43}{}{char }{isdn4linux virtual modem}
 \major{44}{}{char }{isdn4linux virtual modem -- alternate devices}
 \major{45}{}{char }{isdn4linux ISDN BRI driver}
-\major{46}{--59}{}{Unallocated}
+\major{46}{}{char }{Comtrol Rocketport serial card}
+\major{47}{}{char }{Comtrol Rocketport serial card -- alternate devices}
+\major{48}{--59}{}{Unallocated}
 \major{60}{--63}{}{Local/experimental use}
 \major{64}{--119}{}{Unallocated}
 \major{120}{--127}{}{Local/experimental use}
@@ -354,6 +356,13 @@
 NOTE: These devices permit both read and write access.
 
 \begin{devicelist}
+\major{  }{}{block}{Loopback devices}
+	\minor{0}{/dev/loop0}{First loopback device}
+	\minor{1}{/dev/loop1}{Second loopback device}
+	\minordots
+\end{devicelist}
+
+\begin{devicelist}
 \major{ 8}{}{block}{SCSI disk devices}
 	\minor{0}{/dev/sda}{First SCSI disk whole disk}
 	\minor{16}{/dev/sdb}{Second SCSI disk whole disk}
@@ -402,11 +411,6 @@
 	\minor{131}{/dev/temperature}{Machine internal temperature}
 	\minor{132}{/dev/hwtrap}{Hardware fault trap}
 	\minor{133}{/dev/exttrp}{External device trap}
-\\
-\major{  }{}{block}{Loopback devices}
-	\minor{0}{/dev/loop0}{First loopback device}
-	\minor{1}{/dev/loop1}{Second loopback device}
-	\minordots
 \end{devicelist}
 
 \noindent
@@ -641,7 +645,7 @@
 \end{devicelist}
 
 \begin{devicelist}
-\major{26}{}{char }{Frame grabbers}
+\major{26}{}{char }{Quanta WinVision frame grabber}
 	\minor{0}{/dev/wvisfgrab}{Quanta WinVision frame grabber}
 \\
 \major{  }{}{block}{Second Matsushita (Panasonic/SoundBlaster) CD-ROM}
@@ -915,7 +919,8 @@
 \end{devicelist}
 
 \begin{devicelist}
-\major{40}{}{}{Unallocated}
+\major{40}{}{char }{Matrox Meteor frame grabber}
+	\minor{0}{/dev/mmetfgrab}{Matrox Meteor frame grabber}
 \end{devicelist}
 
 \begin{devicelist}
@@ -961,7 +966,21 @@
 \end{devicelist}
 
 \begin{devicelist}
-\major{46}{--59}{}{Unallocated}
+\major{46}{}{char }{Comtrol Rocketport serial card}
+	\minor{0}{/dev/ttyR0}{First Rocketport port}
+	\minor{1}{/dev/ttyR1}{Second Rocketport port}
+	\minordots
+\end{devicelist}
+
+\begin{devicelist}
+\major{47}{}{char }{Comtrol Rocketport serial card -- alternate devices}
+	\minor{0}{/dev/cur0}{Callout device corresponding to {\file ttyR0}}
+	\minor{1}{/dev/cur1}{Callout device corresponding to {\file ttyR1}}
+	\minordots
+\end{devicelist}
+
+\begin{devicelist}
+\major{48}{--59}{}{Unallocated}
 \end{devicelist}
 
 \begin{devicelist}
diff -u --recursive --new-file v1.3.72/linux/Documentation/devices.txt linux/Documentation/devices.txt
--- v1.3.72/linux/Documentation/devices.txt	Tue Mar  5 10:10:44 1996
+++ linux/Documentation/devices.txt	Sun Mar 10 09:40:36 1996
@@ -2,7 +2,7 @@
 
 	     Maintained by H. Peter Anvin <hpa@zytor.com>
 
-		     Last revised: March 2, 1996
+		     Last revised: March 9, 1996
 
 This list is the successor to Rick Miller's Linux Device List, which
 he stopped maintaining when he got busy with other things in 1993.  It
@@ -187,6 +187,15 @@
 	
 		NOTE: These devices permit both read and write access.
 
+    block	Loopback devices
+		  0 = /dev/loop0	First loopback device
+		  1 = /dev/loop1	Second loopback device
+		      ...
+
+		The loopback devices are used to mount filesystems not
+		associated with block devices.  The binding to the
+		loopback devices is usually handled by mount(1).
+
   8 block	SCSI disk devices
     		  0 = /dev/sda		First SCSI disk whole disk
 		 16 = /dev/sdb		Second SCSI disk whole disk
@@ -229,15 +238,6 @@
 		132 = /dev/hwtrap	Hardware fault trap
 		133 = /dev/exttrp	External device trap
 
-    block	Loopback devices
-		  0 = /dev/loop0	First loopback device
-		  1 = /dev/loop1	Second loopback device
-		      ...
-
-		The loopback devices are used to mount filesystems not
-		associated with block devices.  The binding to the
-		loopback devices is usually handled by mount(1).
-
  11 char	Raw keyboard device
 		  0 = /dev/kbd		Raw keyboard device
 
@@ -414,7 +414,7 @@
 		  2 = /dev/sbpcd2	Panasonic CD-ROM controller 0 unit 2
 		  3 = /dev/sbpcd3	Panasonic CD-ROM controller 0 unit 3
 
- 26 char	Frame grabbers
+ 26 char	Quanta WinVision frame grabber
 		  0 = /dev/wvisfgrab	Quanta WinVision frame grabber
     block	Second Matsushita (Panasonic/SoundBlaster) CD-ROM
 		  0 = /dev/sbpcd4	Panasonic CD-ROM controller 1 unit 0
@@ -627,7 +627,8 @@
 		 51 = /dev/ml16pb-c2	Second card, third counter/timer
 		      ...
 
- 40		UNALLOCATED
+ 40		Matrox Meteor frame grabber
+		  0 = /dev/mmetfgrab	Matrox Meteor frame grabber
 
  41		Yet Another Micro Monitor
 		  0 = /dev/yamm		Yet Another Micro Monitor
@@ -661,7 +662,17 @@
 		 31 = /dev/isdnctrl15	16th channel control/debug
 		128 = /dev/isdninfo	ISDN monitor interface
 
- 46-59		UNALLOCATED
+ 46 char	Comtrol Rocketport serial card
+		  0 = /dev/ttyR0	First Rocketport port
+		  1 = /dev/ttyR1	Second Rocketport port
+		      ...
+
+ 47 char	Comtrol Rocketport serial card - alternate devices
+		  0 = /dev/cur0		Callout device corresponding to ttyR0
+		  1 = /dev/cur1		Callout device corresponding to ttyR1
+		      ...
+
+ 48-59		UNALLOCATED
 
  60-63		LOCAL/EXPERIMENTAL USE
 		Allocated for local/experimental use.  For devices not
diff -u --recursive --new-file v1.3.72/linux/Documentation/filesystems/vfat.txt linux/Documentation/filesystems/vfat.txt
--- v1.3.72/linux/Documentation/filesystems/vfat.txt	Sun Mar 10 09:49:46 1996
+++ linux/Documentation/filesystems/vfat.txt	Sat Mar  9 15:41:12 1996
@@ -62,6 +62,15 @@
 chaffee@bugs-bunny.cs.berkeley.edu.  Please specify the filename
 and the operation that gave you trouble.
 
+TEST SUITE
+----------------------------------------------------------------------
+If you plan to make any modifications to the vfat filesystem, please
+get the test suite that comes with the vfat distribution at
+
+  http://www-plateau.cs.berkeley.edu/people/chaffee/vfat.html
+
+This tests quite a few parts of the vfat filesystem and additional
+tests for new features or untested features would be appreciated.
 
 NOTES ON THE STRUCTURE OF THE VFAT FILESYTEM
 ----------------------------------------------------------------------
diff -u --recursive --new-file v1.3.72/linux/Documentation/initrd.txt linux/Documentation/initrd.txt
--- v1.3.72/linux/Documentation/initrd.txt	Thu Jan  1 02:00:00 1970
+++ linux/Documentation/initrd.txt	Sat Mar  9 13:31:44 1996
@@ -0,0 +1,286 @@
+Using the initial RAM disk (initrd)
+===================================
+
+Written 1996 by Werner Almesberger <almesber@lrc.epfl.ch> and
+		Hans Lermen <lermen@elserv.ffm.fgan.de>
+
+
+initrd adds the capability to load a RAM disk by the boot loader. This
+RAM disk can then be mounted as the root file system and programs can be
+run from it. Afterwards, a new root file system can be mounted from a
+different device. The previous root (from initrd) is then either moved
+to the directory /initrd or it is unmounted.
+
+initrd is mainly designed to allow system startup to occur in two phases,
+where the kernel comes up with a minimum set of compiled-in drivers, and
+where additional modules are loaded from initrd.
+
+
+Operation
+---------
+
+When using initrd, the system boots as follows:
+
+  1) the boot loader loads the kernel and the initial RAM disk
+  2) the kernel converts initrd into a "normal" RAM disk and
+     frees the memory used by initrd
+  3) initrd is mounted read-write as root
+  4) /linuxrc is executed (this can be any valid executable, including
+     shell scripts; it is run with uid 0 and can do basically everything
+     init can do)
+  5) when linuxrc terminates, the "real" root file system is mounted
+  6) if a directory /initrd exists, the initrd is moved there
+     otherwise, initrd is unmounted
+  7) the usual boot sequence (e.g. invocation of /sbin/init) is performed
+     on the root file system
+
+Note that moving initrd from / to /initrd does not involve unmounting it.
+It is therefore possible to leave processes running on initrd (or leave
+file systems mounted, but see below) during that procedure. However, if
+/initrd doesn't exist, initrd can only be unmounted if it is not used by
+anything. If it can't be unmounted, it will stay in memory.
+
+Also note that file systems mounted under initrd continue to be accessible,
+but their /proc/mounts entries are not updated. Also, if /initrd doesn't
+exist, initrd can't be unmounted and will "disappear" and take those file
+systems with it, thereby preventing them from being re-mounted. It is
+therefore strongly suggested to generally unmount all file systems (except
+of course for the root file system, but including /proc) before switching
+from initrd to the "normal" root file system.
+
+In order to deallocate the memory used for the initial RAM disk, you have
+to execute freeramdisk (see 'Resources' below) after unmounting /initrd.
+
+
+Boot command-line options
+-------------------------
+
+initrd adds the following new options:
+
+  initrd=<path>    (LOADLIN only)
+
+    Loads the specified file as the initial RAM disk. When using LILO, you
+    have to specify the RAM disk image file in /etc/lilo.conf, using the
+    INITRD configuration variable.
+
+  noinitrd
+
+    initrd data is preserved but it is not converted to a RAM disk and
+    the "normal" root file system is mounted. initrd data can be read
+    from /dev/initrd. Note that the data in initrd can have any structure
+    in this case and doesn't necessarily have to be a file system image.
+    This option is used mainly for debugging.
+
+    Note that /dev/initrd is read-only and that it can only be used once.
+    As soon as the last process has closed it, all data is freed and
+    /dev/initrd can't be opened any longer.
+
+  root=/dev/ram
+
+    initrd is mounted as root, and /linuxrc is started. If no /linuxrc
+    exists, the normal boot procedure is followed, with the RAM disk
+    still mounted as root. This option is mainly useful when booting from
+    a floppy disk. Compared to directly mounting an on-disk file system,
+    the intermediate step of going via initrd adds a little speed
+    advantage and it allows the use of a compressed file system.
+    Also, together with LOADLIN you may load the RAM disk directly from
+    CDrom or disk, hence having a floppyless boot from CD,
+    e.g.: E:\loadlin E:\bzImage root=/dev/ram initrd=E:\rdimage
+
+
+Installation
+------------
+
+First, the "normal" root file system has to be prepared as follows:
+
+# mknod /dev/initrd b 0 250 
+# chmod 400 /dev/initrd
+# mkdir /initrd
+
+If the root file system is created during the boot procedure (i.e. if
+you're creating an install floppy), the root file system creation
+procedure should perform these operations.
+
+Note that neither /dev/initrd nor /initrd are strictly required for
+correct operation of initrd, but it is a lot easier to experiment with
+initrd if you have them, and you may also want to use /initrd to pass
+data to the "real" system.
+
+Second, the kernel has to be compiled with RAM disk support and with
+support for the initial RAM disk enabled. Also, at least all components
+needed to execute programs from initrd (e.g. executable format and file
+system) must be compiled into the kernel.
+
+Third, you have to create the RAM disk image. This is done by creating a
+file system on a block device and then by copying files to it as needed.
+With recent kernels, at least three types of devices are suitable for
+that:
+
+ - a floppy disk (works everywhere but it's painfully slow)
+ - a RAM disk (fast, but allocates physical memory)
+ - a loopback device (the most elegant solution, but currently requires a
+   modified mount)
+
+We'll describe the RAM disk method:
+
+ 1) make sure you have a RAM disk device /dev/ram (block, major 1, minor 0)
+ 2) create an empty file system of the appropriate size, e.g.
+    # mke2fs -m0 /dev/ram 300   
+    (if space is critical, you may want to use the Minix FS instead of Ext2)
+ 3) mount the file system on an appropriate directory, e.g.
+    # mount -t ext2 /dev/ram /mnt
+ 4) create the console device:
+    # mkdir /mnt/dev
+    # mknod /mnt/dev/tty1 c 4 1
+ 5) copy all the files that are needed to properly use the initrd
+    environment. Don't forget the most important file, /linuxrc
+    Note that /linuxrc's permissions must include "x" (execute).
+ 6) unmount the RAM disk
+    # umount /dev/ram
+ 7) copy the image to a file
+    # dd if=/dev/ram bs=1k count=300 of=/boot/initrd
+ 8) deallocate the RAM disk
+    # freeramdisk /dev/ram
+
+For experimenting with initrd, you may want to take a rescue floppy (e.g.
+rescue.gz from Slackware) and only add a symbolic link from /linuxrc to
+/bin/sh, e.g.
+
+ # gunzip <rescue.gz >/dev/ram
+ # mount -t minix /dev/ram /mnt
+ # ln -s /bin/sh /mnt/linuxrc
+ # umount /dev/ram
+ # dd if=/dev/ram bs=1k count=1440 of=/boot/initrd
+ # freeramdisk /dev/ram
+
+Finally, you have to boot the kernel and load initrd. Currently,
+preliminary versions of LOADLIN 1.6 and LILO 18 support initrd (see
+below for where to get them). With LOADLIN, you simply execute
+
+     LOADLIN <kernel> initrd=<disk_image>
+e.g. LOADLIN C:\LINUX\VMLINUZ initrd=C:\LINUX\INITRD
+
+With LILO, you add the option INITRD=<path> to either the global section
+or to the section of the respective kernel in /etc/lilo.conf, e.g.
+
+  image = /vmlinuz
+    initrd = /boot/initrd
+
+and run /sbin/lilo
+
+Now you can boot and enjoy using initrd.
+
+
+Setting the root device
+-----------------------
+
+By default, the standard settings in the kernel are used for the root
+device, i.e. the default compiled in or set with rdev, or what was passed
+with root=xxx on the command line, or, with LILO, what was specified in
+/etc/lilo.conf It is also possible to use initrd with an NFS-mounted
+root; you have to use the nfs_root_name and nfs_root_addrs boot options
+for this.
+
+It is also possible to change the root device from within the initrd
+environment. In order to do so, /proc has to be mounted. Then, the
+following files are available:
+
+  /proc/sys/kernel/real-root-dev
+  /proc/sys/kernel/nfs-root-name
+  /proc/sys/kernel/nfs-root-addrs
+
+real-root-dev can be changed by writing the number of the new root FS
+device to it, e.g.
+
+  # echo 0x301 >/proc/sys/kernel/real-root-dev
+
+for /dev/hda1. When using an NFS-mounted root, nfs-root-name and
+nfs-root-addrs have to be set accordingly and then real-root-dev has to
+be set to 0xff, e.g.
+
+  # echo /var/nfsroot >/proc/sys/kernel/nfs-root-name
+  # echo 193.8.232.2:193.8.232.7::255.255.255.0:idefix \
+    >/proc/sys/kernel/nfs-root-addrs
+  # echo 255 >/proc/sys/kernel/real-root-dev
+
+If the root device is set to the RAM disk, the root file system is not
+moved to /initrd, but the boot procedure is simply continued by starting
+init on the initial RAM disk.
+
+
+Usage scenarios
+---------------
+
+The main motivation for implementing initrd was to allow for modular
+kernel configuration at system installation. The procedure would work
+as follows:
+
+  1) systems boots from floppy or other media with a minimal kernel
+     (e.g. support for RAM disks, initrd, a.out, and the ext2 FS) and
+     loads initrd
+  2) /linuxrc determines what is needed to (1) mount the "real" root FS
+     (i.e. device type, device drivers, file system) and (2) the
+     distribution media (e.g. CD-ROM, network, tape, ...). This can be
+     done by asking the user, by auto-probing, or by using a hybrid
+     approach.
+  3) /linuxrc loads the necessary modules
+  4) /linuxrc creates and populates the root file system (this doesn't
+     have to be a very usable system yet)
+  5) /linuxrc unmounts the root file system and possibly any other file
+     systems it has mounted, sets /proc/sys/kernel/..., and terminates
+  6) the root file system is mounted
+  7) now that we're sure that the file system is accessible and intact,
+     the boot loader can be installed
+  8) the boot loader is configured to load an initrd with the set of
+     modules that was used to bring up the system (e.g. /initrd can be
+     modified, then unmounted, and finally, the image is written from
+     /dev/ram to a file)
+  9) now the system is bootable and additional installation tasks can be
+     performed
+
+The key role of initrd here is to re-use the configuration data during
+normal system operation without requiring the use of a bloated "generic"
+kernel or re-compilation or re-linking of the kernel.
+
+A second scenario is for installations where Linux runs on systems with
+different hardware configurations in a single administrative domain. In
+such cases, it is desirable to generate only a small set of kernels
+(ideally only one) and to keep the system-specific part of configuration
+information as small as possible. In this case, a common initrd could be
+generated with all the necessary modules. Then, only /linuxrc or a file
+read by it would have to be different.
+
+A third scenario are more convenient recovery disks, because information
+like the location of the root FS partition doesn't have to be provided at
+boot time, but the system loaded from initrd can use a user-friendly
+dialog and it can also perform some sanity checks (or even some form of
+auto-detection).
+
+Last not least, CDrom distributors may use it for better installation from CD,
+either using a LILO boot floppy and bootstrapping a bigger ramdisk via
+initrd from CD, or using LOADLIN to directly load the ramdisk from CD
+without need of floppys.
+
+Since initrd is a fairly generic mechanism, it is likely that additional
+uses will be found.
+
+
+Resources
+---------
+
+The bzImage+initrd patch (bzImage is an extension to load kernels directly
+above 1 MB, which allows kernels sizes of up to approximately 2 MB) can be
+found at
+ftp://lrcftp.epfl.ch/pub/people/almesber/lilo/bzImage+initrd-1.3.71.patch.gz
+and
+ftp://elserv.ffm.fgan.de/pub/linux/loadlin-1.6/bzImage+initrd-1.3.71.patch.gz
+
+A preliminary version of LOADLIN 1.6 is available on
+ftp://elserv.ffm.fgan.de/pub/linux/loadlin-1.6/loadlin-1.6-pre8-bin.tgz
+
+A preliminary version of LILO 18 is available on
+ftp://lrcftp.epfl.ch/pub/people/almesber/lilo/lilo.18dev3.tar.gz
+
+A very simple example for building an image for initrd, also including
+the programm 'freeramdisk', can be found on
+ftp://elserv.ffm.fgan.de/pub/linux/loadlin-1.6/initrd-example.tgz
diff -u --recursive --new-file v1.3.72/linux/Documentation/watchdog.txt linux/Documentation/watchdog.txt
--- v1.3.72/linux/Documentation/watchdog.txt	Wed Dec 27 09:12:12 1995
+++ linux/Documentation/watchdog.txt	Tue Mar 12 13:37:56 1996
@@ -65,3 +65,11 @@
 }
 
 
+> People keep asking about the WDT watchdog timer hardware: The phone contacts
+> for Industrial Computer Source are:
+> 
+> US: 619 677 0898 (sales)  0895 (general)
+> UK: 01243 533900
+> France (1) 69.18.74.30
+> 
+> and please mention Linux when enquiring.
diff -u --recursive --new-file v1.3.72/linux/MAINTAINERS linux/MAINTAINERS
--- v1.3.72/linux/MAINTAINERS	Sun Mar 10 09:49:46 1996
+++ linux/MAINTAINERS	Sun Mar 10 13:49:15 1996
@@ -83,6 +83,12 @@
 L:	linux-hams@vger.rutges.edu
 S:	Maintained
 
+BUSLOGIC SCSI DRIVER
+P:	Leonard N. Zubkoff
+M:	Leonard N. Zubkoff <lnz@dandelion.com>
+L:	None
+S:	Maintained
+
 FUTURE DOMAIN TMC-16x0 SCSI DRIVER (16-bit)
 P:      Rik Faith
 M:      faith@cs.unc.edu
@@ -113,6 +119,12 @@
 L:	linux-kernel@vger.rutgers.edu
 S:	Maintained
 
+NCP FILESYSTEM:
+P:	Volker Lendecke
+M:	lendecke@namu01.gwdg.de
+L:	linware@sh.cvut.cz
+S:	Maintained
+
 NETROM NETWORK LAYER
 P:	Jon Naylor
 M:	jsn@cs.nott.ac.uk
@@ -130,6 +142,12 @@
 M:	longyear@netcom.com, Cc: longyear@sii.com
 L:	linux-ppp@vger.rutgers.edu
 S:	Maintained
+
+SMB FILESYSTEM:
+P:	Volker Lendecke
+M:	lendecke@namu01.gwdg.de
+L:	samba@listproc.anu.edu.au
+S:	Odd Fixes
 
 SMP:
 P:	Alan Cox
diff -u --recursive --new-file v1.3.72/linux/Makefile linux/Makefile
--- v1.3.72/linux/Makefile	Sun Mar 10 09:49:46 1996
+++ linux/Makefile	Sun Mar 10 09:56:04 1996
@@ -1,6 +1,6 @@
 VERSION = 1
 PATCHLEVEL = 3
-SUBLEVEL = 72
+SUBLEVEL = 73
 
 ARCH = i386
 
@@ -344,6 +344,9 @@
 backup: mrproper
 	cd .. && tar cf - linux/ | gzip -9 > backup.gz
 	sync
+
+sums:
+	find . -type f -print | sort | xargs sum > .SUMS
 
 dep-files: archdep .hdepend include/linux/version.h
 	$(AWK) -f scripts/depend.awk init/*.c > .tmpdepend
diff -u --recursive --new-file v1.3.72/linux/arch/alpha/defconfig linux/arch/alpha/defconfig
--- v1.3.72/linux/arch/alpha/defconfig	Sat Mar  2 10:43:20 1996
+++ linux/arch/alpha/defconfig	Mon Mar 11 13:44:46 1996
@@ -44,6 +44,7 @@
 #
 # CONFIG_BLK_DEV_HD_ONLY is not set
 CONFIG_BLK_DEV_RAM=y
+# CONFIG_BLK_DEV_INITRD is not set
 # CONFIG_BLK_DEV_LOOP is not set
 # CONFIG_BLK_DEV_XD is not set
 # CONFIG_BLK_DEV_MD is not set
@@ -94,6 +95,7 @@
 #
 # CONFIG_SCSI_MULTI_LUN is not set
 CONFIG_SCSI_CONSTANTS=y
+# CONFIG_SCSI_AUTO_BIOSP is not set
 
 #
 # SCSI low-level drivers
@@ -182,6 +184,7 @@
 # CONFIG_MS_BUSMOUSE is not set
 # CONFIG_ATIXL_BUSMOUSE is not set
 # CONFIG_QIC02_TAPE is not set
+# CONFIG_FTAPE is not set
 # CONFIG_APM is not set
 # CONFIG_WATCHDOG is not set
 
diff -u --recursive --new-file v1.3.72/linux/arch/alpha/kernel/irq.c linux/arch/alpha/kernel/irq.c
--- v1.3.72/linux/arch/alpha/kernel/irq.c	Tue Mar  5 10:10:45 1996
+++ linux/arch/alpha/kernel/irq.c	Mon Mar 11 13:44:46 1996
@@ -135,9 +135,9 @@
 	struct irqaction * action;
 
 	for (i = 0 ; i < NR_IRQS ; i++) {
-	        action = irq_action[i];
+		action = irq_action[i];
 		if (!action) 
-		        continue;
+			continue;
 		len += sprintf(buf+len, "%2d: %8d %c %s",
 			i, kstat.interrupts[i],
 			(action->flags & SA_INTERRUPT) ? '+' : ' ',
@@ -172,36 +172,40 @@
 		const char * devname,
 		void *dev_id)
 {
-	struct irqaction *action, *tmp = NULL;
+	int shared = 0;
+	struct irqaction * action, **p;
 	unsigned long flags;
 
 	if (irq >= NR_IRQS)
 		return -EINVAL;
-	/* don't accept requests for irq #0 */
-	if (!irq)
-		return -EINVAL;
 	if (!handler)
-	    return -EINVAL;
-	action = irq_action[irq];
+		return -EINVAL;
+	p = irq_action + irq;
+	action = *p;
 	if (action) {
-	    if ((action->flags & SA_SHIRQ) && (irqflags & SA_SHIRQ)) {
-		for (tmp = action; tmp->next; tmp = tmp->next);
-	    } else {
-		return -EBUSY;
-	    }
-	    if ((action->flags & SA_INTERRUPT) ^ (irqflags & SA_INTERRUPT)) {
-	      printk("Attempt to mix fast and slow interrupts on IRQ%d denied\n", irq);
-	      return -EBUSY;
-	    }   
+		/* Can't share interrupts unless both agree to */
+		if (!(action->flags & irqflags & SA_SHIRQ))
+			return -EBUSY;
+
+		/* Can't share interrupts unless both are same type */
+		if ((action->flags ^ irqflags) & SA_INTERRUPT)
+			return -EBUSY;
+
+		/* add new interrupt at end of irq queue */
+		do {
+			p = &action->next;
+			action = *p;
+		} while (action);
+		shared = 1;
 	}
-	save_flags(flags);
-	cli();
+
 	action = (struct irqaction *)kmalloc(sizeof(struct irqaction), GFP_KERNEL);
-	if (!action) { 
-	    restore_flags(flags);
-	    return -ENOMEM;
-	}
-	
+	if (!action)
+		return -ENOMEM;
+
+	if (irqflags & SA_SAMPLE_RANDOM)
+		rand_initialize_irq(irq);
+
 	action->handler = handler;
 	action->flags = irqflags;
 	action->mask = 0;
@@ -209,61 +213,41 @@
 	action->next = NULL;
 	action->dev_id = dev_id;
 
-	if (tmp) {
-	    tmp->next = action;
-	} else {
-	    irq_action[irq] = action;
-	    enable_irq(irq);
-	    if (irq >= 8 && irq < 16) {
-		enable_irq(2);	/* ensure cascade is enabled too */
-	    }
-	}
+	save_flags(flags);
+	cli();
+	*p = action;
+
+	if (!shared)
+		unmask_irq(irq);
 
 	restore_flags(flags);
 	return 0;
 }
-
+		
 void free_irq(unsigned int irq, void *dev_id)
 {
-	struct irqaction * action = irq_action[irq];
-	struct irqaction * tmp = NULL;
+	struct irqaction * action, **p;
 	unsigned long flags;
 
 	if (irq >= NR_IRQS) {
-		printk("Trying to free IRQ%d\n", irq);
+		printk("Trying to free IRQ%d\n",irq);
 		return;
 	}
-	if (!action || !action->handler) {
-		printk("Trying to free free IRQ%d\n", irq);
+	for (p = irq + irq_action; (action = *p) != NULL; p = &action->next) {
+		if (action->dev_id != dev_id)
+			continue;
+
+		/* Found it - now free it */
+		save_flags(flags);
+		cli();
+		*p = action->next;
+		if (!irq[irq_action])
+			mask_irq(irq);
+		restore_flags(flags);
+		kfree(action);
 		return;
 	}
-	if (dev_id) {
-	    for (; action; action = action->next) {
-	        if (action->dev_id == dev_id) break;
-		tmp = action;
-	    }
-	    if (!action) {
-		printk("Trying to free free shared IRQ%d\n",irq);
-		return;
-	    }
-	} else if (action->flags & SA_SHIRQ) {
-	    printk("Trying to free shared IRQ%d with NULL device ID\n", irq);
-	    return;
-	}
-	save_flags(flags);
-	cli();
-	if (action && tmp) {
-	    tmp->next = action->next;
-	} else {
-	    irq_action[irq] = action->next;
-	}
-	kfree_s(action, sizeof(struct irqaction));
-
-	if (!irq_action[irq]) {
-	    mask_irq(irq);
-	}
-
-	restore_flags(flags);
+	printk("Trying to free free IRQ%d\n",irq);
 }
 
 static inline void handle_nmi(struct pt_regs * regs)
@@ -281,9 +265,9 @@
 	printk("PC = %016lx PS=%04lx\n", regs->pc, regs->ps);
 	printk("Expecting: ");
 	for (i = 0; i < 16; i++)
-	        if ((action = irq_action[i]))
-		        while (action->handler) {
-			        printk("[%s:%d] ", action->name, i);
+		if ((action = irq_action[i]))
+			while (action->handler) {
+				printk("[%s:%d] ", action->name, i);
 				action = action->next;
 			}
 	printk("\n");
@@ -303,12 +287,12 @@
 
 	kstat.interrupts[irq]++;
 	if (!action) {
-	    unexpected_irq(irq, regs);
-	    return;
+		unexpected_irq(irq, regs);
+		return;
 	}
 	do {
-	    action->handler(irq, action->dev_id, regs);
-	    action = action->next;
+		action->handler(irq, action->dev_id, regs);
+		action = action->next;
 	} while (action);
 }
 
@@ -326,10 +310,10 @@
 	if (action) {
 		/* quick interrupts get executed with no extra overhead */
 		if (action->flags & SA_INTERRUPT) {
-		        while (action) {
-			        action->handler(irq, action->dev_id, regs);
-			        action = action->next;
-		        }
+			while (action) {
+				action->handler(irq, action->dev_id, regs);
+				action = action->next;
+			}
 			ack_irq(ack);
 			return;
 		}
@@ -369,7 +353,7 @@
 #elif defined(CONFIG_ALPHA_ALCOR)
 #	define IACK_SC	ALCOR_IACK_SC
 #else
-    	/*
+	/*
 	 * This is bogus but necessary to get it to compile
 	 * on all platforms.  If you try to use this on any
 	 * other than the intended platforms, you'll notice
@@ -390,10 +374,10 @@
 	j = *(volatile int *) IACK_SC;
 	j &= 0xff;
 	if (j == 7) {
-	    if (!(inb(0x20) & 0x80)) {
-		/* it's only a passive release... */
-		return;
-	    }
+		if (!(inb(0x20) & 0x80)) {
+			/* it's only a passive release... */
+			return;
+		}
 	}
 	device_interrupt(j, j, regs);
 #else
@@ -558,7 +542,7 @@
 	unsigned int i;
 
 	for (i = NR_IRQS - 1; i > 0; i--) {
-	        action = irq_action[i];
+		action = irq_action[i];
 		if (!action) {
 			enable_irq(i);
 			irqs |= (1 << i);
@@ -679,4 +663,5 @@
 	outb(cache_26, 0x26);
 	outb(cache_27, 0x27);
 #endif
+	enable_irq(2);		/* enable cascade */
 }
diff -u --recursive --new-file v1.3.72/linux/arch/alpha/kernel/signal.c linux/arch/alpha/kernel/signal.c
--- v1.3.72/linux/arch/alpha/kernel/signal.c	Sat Feb 17 16:02:45 1996
+++ linux/arch/alpha/kernel/signal.c	Mon Mar 11 09:39:33 1996
@@ -283,6 +283,7 @@
 				/* fall through */
 			default:
 				current->signal |= _S(signr & 0x7f);
+				current->flags |= PF_SIGNALED;
 				do_exit(signr);
 			}
 		}
diff -u --recursive --new-file v1.3.72/linux/arch/alpha/kernel/traps.c linux/arch/alpha/kernel/traps.c
--- v1.3.72/linux/arch/alpha/kernel/traps.c	Tue Feb 20 14:37:23 1996
+++ linux/arch/alpha/kernel/traps.c	Tue Mar 12 15:31:10 1996
@@ -64,8 +64,8 @@
 			return;		/* emulation was successful */
 		}
 	}
-	printk("Arithmetic trap at %016lx: %02lx %016lx\n",
-	       regs.pc, summary, write_mask);
+	printk("%s: arithmetic trap at %016lx: %02lx %016lx\n",
+		current->comm, regs.pc, summary, write_mask);
 	die_if_kernel("Arithmetic fault", &regs, 0);
 	send_sig(SIGFPE, current, 1);
 }
diff -u --recursive --new-file v1.3.72/linux/arch/alpha/mm/fault.c linux/arch/alpha/mm/fault.c
--- v1.3.72/linux/arch/alpha/mm/fault.c	Tue Dec 26 04:45:35 1995
+++ linux/arch/alpha/mm/fault.c	Tue Mar 12 15:31:10 1996
@@ -78,7 +78,8 @@
  */
 bad_area:
 	if (user_mode(&regs)) {
-		printk("memory violation at pc=%08lx (%08lx)\n", regs.pc, address);
+		printk("%s: memory violation at pc=%08lx rp=%08lx (bad address = %08lx)\n",
+			current->comm, regs.pc, regs.r26, address);
 		die_if_kernel("oops", &regs, cause);
 		send_sig(SIGSEGV, current, 1);
 		return;
diff -u --recursive --new-file v1.3.72/linux/arch/i386/Makefile linux/arch/i386/Makefile
--- v1.3.72/linux/arch/i386/Makefile	Fri Feb  9 17:52:57 1996
+++ linux/arch/i386/Makefile	Sat Mar  9 13:31:42 1996
@@ -16,11 +16,17 @@
 #
 # Set these to indicate how to link it..
 #
-# -zmagic:   
+# -zmagic:   (aout, old GCC-2.5.2)
 #
 # ZLINKFLAGS   = -Ttext 0x1000
+# BZLINKFLAGS  = -Ttext 0x100000     # (for big high loaded kernels)
 # LINKFLAGS    = -Ttext 0x100000
 #
+# -qmagic:   (aout)
+#
+# ZLINKFLAGS   = -Ttext 0x0xfe0
+# BZLINKFLAGS  = -Ttext 0xfffe0      # (for big high loaded kernels)
+# LINKFLAGS    = -Ttext 0xfffe0
 #
 
 AS86    =$(CROSS_COMPILE)as86 -0 -a
@@ -39,6 +45,7 @@
 ZIMAGE_OFFSET=0x1000
 IMAGE_OFFSET=0x100000
 ZLINKFLAGS =-Ttext $(ZIMAGE_OFFSET) $(ZLDFLAGS)
+BZLINKFLAGS =-Ttext $(IMAGE_OFFSET) $(ZLDFLAGS)
 LINKFLAGS =-Ttext $(IMAGE_OFFSET) $(LDFLAGS)
 
 else
@@ -47,8 +54,10 @@
 # -qmagic (we need to remove the 32 byte header for bootup purposes)
 #
 ZLINKFLAGS =-qmagic -Ttext 0xfe0
+BZLINKFLAGS =-qmagic -Ttext 0xfffe0
 LINKFLAGS =-qmagic -Ttext 0xfffe0
 endif
+
 CFLAGS := $(CFLAGS) -pipe
 
 ifdef CONFIG_M386
@@ -93,13 +102,22 @@
 zImage: vmlinux
 	@$(MAKEBOOT) zImage
 
+bzImage: vmlinux
+	@$(MAKEBOOT) bzImage
+
 compressed: zImage
 
 zlilo: vmlinux
-	@$(MAKEBOOT) zlilo
+	@$(MAKEBOOT) BOOTIMAGE=zImage zlilo
+
+bzlilo: vmlinux
+	@$(MAKEBOOT) BOOTIMAGE=bzImage zlilo
 
 zdisk: vmlinux
-	@$(MAKEBOOT) zdisk
+	@$(MAKEBOOT) BOOTIMAGE=zImage zdisk
+
+bzdisk: vmlinux
+	@$(MAKEBOOT) BOOTIMAGE=bzImage zdisk
 
 install: vmlinux
 	@$(MAKEBOOT) install
diff -u --recursive --new-file v1.3.72/linux/arch/i386/boot/Makefile linux/arch/i386/boot/Makefile
--- v1.3.72/linux/arch/i386/boot/Makefile	Wed Feb  7 15:11:20 1996
+++ linux/arch/i386/boot/Makefile	Sat Mar  9 13:31:42 1996
@@ -25,16 +25,28 @@
 endif
 	sync
 
+bzImage: $(CONFIGURE) bbootsect setup compressed/bvmlinux tools/bbuild
+ifdef CONFIG_KERNEL_ELF
+	$(OBJDUMP) $(OBJDUMP_FLAGS) -o $(IMAGE_OFFSET) compressed/bvmlinux > compressed/bvmlinux.out
+	tools/bbuild bbootsect setup compressed/bvmlinux.out $(ROOT_DEV) > bzImage
+else
+	tools/bbuild bbootsect setup compressed/bvmlinux $(ROOT_DEV) > bzImage
+endif
+	sync
+
 compressed/vmlinux: $(TOPDIR)/vmlinux
 	@$(MAKE) -C compressed vmlinux
 
-zdisk: zImage
-	dd bs=8192 if=zImage of=/dev/fd0
+compressed/bvmlinux: $(TOPDIR)/vmlinux
+	@$(MAKE) -C compressed bvmlinux
+
+zdisk: $(BOOTIMAGE)
+	dd bs=8192 if=$(BOOTIMAGE) of=/dev/fd0
 
-zlilo: $(CONFIGURE) zImage
+zlilo: $(CONFIGURE) $(BOOTIMAGE)
 	if [ -f $(INSTALL_PATH)/vmlinuz ]; then mv $(INSTALL_PATH)/vmlinuz $(INSTALL_PATH)/vmlinuz.old; fi
 	if [ -f $(INSTALL_PATH)/System.map ]; then mv $(INSTALL_PATH)/System.map $(INSTALL_PATH)/System.old; fi
-	cat zImage > $(INSTALL_PATH)/vmlinuz
+	cat $(BOOTIMAGE) > $(INSTALL_PATH)/vmlinuz
 	cp $(TOPDIR)/System.map $(INSTALL_PATH)/
 	if [ -x /sbin/lilo ]; then /sbin/lilo; else /etc/lilo/install; fi
 
@@ -44,6 +56,9 @@
 tools/build: tools/build.c
 	$(HOSTCC) $(HOSTCFLAGS) -o $@ $< -I$(TOPDIR)/include
 
+tools/bbuild: tools/build.c
+	$(HOSTCC) $(HOSTCFLAGS) -D__BIG_KERNEL__ -o $@ $< -I$(TOPDIR)/include
+
 setup: setup.o
 	$(LD86) -s -o $@ $<
 
@@ -62,9 +77,19 @@
 bootsect.s: bootsect.S $(CONFIGURE) $(TOPDIR)/include/linux/config.h Makefile
 	$(CPP) -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@
 
+bbootsect: bbootsect.o
+	$(LD86) -s -o $@ $<
+
+bbootsect.o: bbootsect.s
+	$(AS86) -o $@ $<
+
+bbootsect.s: bootsect.S $(CONFIGURE) $(TOPDIR)/include/linux/config.h Makefile
+	$(CPP) -D__BIG_KERNEL__ -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@
+
 dep:
 
 clean:
 	rm -f bootsect setup
 	rm -f zImage tools/build compressed/vmlinux.out
+	rm -f bzImage tools/bbuild compressed/bvmlinux.out
 	@$(MAKE) -C compressed clean
diff -u --recursive --new-file v1.3.72/linux/arch/i386/boot/bootsect.S linux/arch/i386/boot/bootsect.S
--- v1.3.72/linux/arch/i386/boot/bootsect.S	Sat Mar  2 10:43:21 1996
+++ linux/arch/i386/boot/bootsect.S	Sat Mar  9 13:31:42 1996
@@ -268,8 +268,14 @@
 die:	jne die			! es must be at 64kB boundary
 	xor bx,bx		! bx is starting address within segment
 rp_read:
+#ifdef __BIG_KERNEL__
+#define CALL_HIGHLOAD_KLUDGE .word 0x1eff,0x220 ! call far * bootsect_kludge
+				! NOTE: as86 can't assemble this
+	CALL_HIGHLOAD_KLUDGE	! this is within setup.S
+#else
 	mov ax,es
 	sub ax,#SYSSEG
+#endif
 	cmp ax,syssize		! have we loaded all yet?
 	jbe ok1_read
 	ret
diff -u --recursive --new-file v1.3.72/linux/arch/i386/boot/compressed/Makefile linux/arch/i386/boot/compressed/Makefile
--- v1.3.72/linux/arch/i386/boot/compressed/Makefile	Sat Feb 17 16:02:45 1996
+++ linux/arch/i386/boot/compressed/Makefile	Sat Mar  9 13:31:42 1996
@@ -26,6 +26,9 @@
 vmlinux: piggy.o $(OBJECTS)
 	$(LD) $(ZLINKFLAGS) -o vmlinux $(OBJECTS) piggy.o
 
+bvmlinux: piggy.o $(OBJECTS)
+	$(LD) $(BZLINKFLAGS) -o bvmlinux $(OBJECTS) piggy.o
+
 ifdef SMP
 
 head.o: head.S $(TOPDIR)/include/linux/tasks.h
@@ -63,4 +66,4 @@
 endif
 
 clean:
-	rm -f xtract piggyback vmlinux
+	rm -f xtract piggyback vmlinux bvmlinux
diff -u --recursive --new-file v1.3.72/linux/arch/i386/boot/compressed/head.S linux/arch/i386/boot/compressed/head.S
--- v1.3.72/linux/arch/i386/boot/compressed/head.S	Wed Nov  8 07:11:29 1995
+++ linux/arch/i386/boot/compressed/head.S	Sat Mar  9 13:31:42 1996
@@ -21,6 +21,10 @@
  * useful for future device drivers that either access the BIOS via VM86 
  * mode.
  */
+
+/*
+ * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996
+ */
 .text
 
 #define __ASSEMBLY__
@@ -82,7 +86,55 @@
 /*
  * Do the decompression, and jump to the new kernel..
  */
+	subl $16,%esp	# place for structure on the stack
+	pushl %esp	# address of structure as first arg
 	call SYMBOL_NAME(decompress_kernel)
+	orl  %eax,%eax 
+	jnz  3f
 	xorl %ebx,%ebx
 	ljmp $(KERNEL_CS), $0x100000
 
+/*
+ * We come here, if we were loaded high.
+ * We need to move the move-in-place routine down to 0x1000
+ * and then start it with the buffer addresses in registers,
+ * which we got from the stack.
+ */
+3:
+	movl $move_routine_start,%esi
+	movl $0x1000,%edi
+	movl $move_routine_end,%ecx
+	subl %esi,%ecx
+	cld
+	rep
+	movsb
+
+	popl %esi	# discard the address
+	popl %esi	# low_buffer_start
+	popl %ecx	# lcount
+	popl %edx	# high_buffer_start
+	popl %eax	# hcount
+	movl $0x100000,%edi
+	cli		# make sure we don't get interrupted
+	ljmp $(KERNEL_CS), $0x1000 # and jump to the move routine
+
+/*
+ * Routine (template) for moving the decompressed kernel in place,
+ * if we were high loaded. This _must_ PIC-code !
+ */
+move_routine_start:
+	rep
+	movsb
+	movl %edx,%esi
+	movl %eax,%ecx	# NOTE: rep movsb won't move if %ecx == 0
+	rep
+	movsb
+	xorl %ebx,%ebx
+/*
+ * Well, the kernel relies on %esp pointing into low mem,
+ * with the decompressor loaded high this is no longer true,
+ * so we set esp here.
+ */
+	mov  $0x90000,%esp
+	ljmp $(KERNEL_CS), $0x100000
+move_routine_end:
diff -u --recursive --new-file v1.3.72/linux/arch/i386/boot/compressed/misc.c linux/arch/i386/boot/compressed/misc.c
--- v1.3.72/linux/arch/i386/boot/compressed/misc.c	Sun Jan 14 16:30:09 1996
+++ linux/arch/i386/boot/compressed/misc.c	Sat Mar  9 13:31:43 1996
@@ -6,6 +6,7 @@
  *
  * malloc by Hannu Savolainen 1993 and Matthias Urlichs 1994
  * puts by Nick Holloway 1993, better puts by Martin Mares 1995
+ * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996
  */
 
 #include <string.h>
@@ -104,6 +105,7 @@
 static long bytes_out = 0;
 static uch *output_data;
 static unsigned long output_ptr = 0;
+
  
 static void *malloc(int size);
 static void free(void *where);
@@ -116,6 +118,15 @@
   
 extern int end;
 static long free_mem_ptr = (long)&end;
+static long free_mem_end_ptr = 0x90000;
+ 
+#define INPLACE_MOVE_ROUTINE  0x1000
+#define LOW_BUFFER_START      0x2000
+#define LOW_BUFFER_END       0x90000
+#define LOW_BUFFER_SIZE      ( LOW_BUFFER_END - LOW_BUFFER_START )
+#define HEAP_SIZE             0x2000
+static int high_loaded =0;
+static uch *high_buffer_start /* = (uch *)(((ulg)&end) + HEAP_SIZE)*/;
 
 static char *vidmem = (char *)0xb8000;
 static int vidport;
@@ -135,7 +146,7 @@
 	p = (void *)free_mem_ptr;
 	free_mem_ptr += size;
 
-	if (free_mem_ptr >= 0x90000)
+	if (free_mem_ptr >= free_mem_end_ptr)
 		error("\nOut of memory\n");
 
 	return p;
@@ -239,7 +250,7 @@
  * Write the output window window[0..outcnt-1] and update crc and bytes_out.
  * (Used for the decompressed data only.)
  */
-static void flush_window()
+static void flush_window_low()
 {
     ulg c = crc;         /* temporary variable */
     unsigned n;
@@ -257,6 +268,28 @@
     outcnt = 0;
 }
 
+static void flush_window_high()
+{
+    ulg c = crc;         /* temporary variable */
+    unsigned n;
+    uch *in,  ch;
+    in = window;
+    for (n = 0; n < outcnt; n++) {
+	ch = *output_data++ = *in++;
+	if ((ulg)output_data == LOW_BUFFER_END) output_data=high_buffer_start;
+	c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8);
+    }
+    crc = c;
+    bytes_out += (ulg)outcnt;
+    outcnt = 0;
+}
+
+static void flush_window()
+{
+	if (high_loaded) flush_window_high();
+	else flush_window_low();
+}
+
 static void error(char *x)
 {
 	puts("\n\n");
@@ -303,7 +336,44 @@
 
 #else
 
-void decompress_kernel()
+void setup_normal_output_buffer()
+{
+	if (EXT_MEM_K < 1024) error("Less than 2MB of memory.\n");
+	output_data = (char *)0x100000; /* Points to 1M */
+}
+
+struct moveparams {
+	uch *low_buffer_start;  int lcount;
+	uch *high_buffer_start; int hcount;
+};
+
+void setup_output_buffer_if_we_run_high(struct moveparams *mv)
+{
+	high_buffer_start = (uch *)(((ulg)&end) + HEAP_SIZE);
+	if (EXT_MEM_K < (4*1024)) error("Less than 4MB of memory.\n");
+	mv->low_buffer_start = output_data = (char *)LOW_BUFFER_START;
+	high_loaded = 1;
+	free_mem_end_ptr = (long)high_buffer_start;
+	if ( (0x100000 + LOW_BUFFER_SIZE) > ((ulg)high_buffer_start)) {
+		high_buffer_start = (uch *)(0x100000 + LOW_BUFFER_SIZE);
+		mv->hcount = 0; /* say: we need not to move high_buffer */
+	}
+	else mv->hcount = -1;
+	mv->high_buffer_start = high_buffer_start;
+}
+
+void close_output_buffer_if_we_run_high(struct moveparams *mv)
+{
+	mv->lcount = bytes_out;
+	if (bytes_out > LOW_BUFFER_SIZE) {
+		mv->lcount = LOW_BUFFER_SIZE;
+		if (mv->hcount) mv->hcount = bytes_out - LOW_BUFFER_SIZE;
+	}
+	else mv->hcount = 0;
+}
+
+
+int decompress_kernel(struct moveparams *mv)
 {
 	if (SCREEN_INFO.orig_video_mode == 7) {
 		vidmem = (char *) 0xb0000;
@@ -316,13 +386,15 @@
 	lines = SCREEN_INFO.orig_video_lines;
 	cols = SCREEN_INFO.orig_video_cols;
 
-	if (EXT_MEM_K < 1024) error("Less than 2MB of memory.\n");
+	if (free_mem_ptr < 0x100000) setup_normal_output_buffer();
+	else setup_output_buffer_if_we_run_high(mv);
 
-	output_data = (char *)0x100000;	/* Points to 1M */
 	makecrc();
 	puts("Uncompressing Linux...");
 	gunzip();
 	puts("done.\nNow booting the kernel\n");
+	if (high_loaded) close_output_buffer_if_we_run_high(mv);
+	return high_loaded;
 }
 #endif
 
diff -u --recursive --new-file v1.3.72/linux/arch/i386/boot/setup.S linux/arch/i386/boot/setup.S
--- v1.3.72/linux/arch/i386/boot/setup.S	Mon Dec 11 15:42:00 1995
+++ linux/arch/i386/boot/setup.S	Sat Mar  9 13:31:43 1996
@@ -20,11 +20,16 @@
 ! add APM BIOS checking by Stephen Rothwell, May 1994
 ! (Stephen.Rothwell@pd.necisa.oz.au)
 !
+! High load stuff, initrd support and position independency
+! by Hans Lermen & Werner Almesberger, February 1996
+! <lermen@elserv.ffm.fgan.de>, <almesber@lrc.epfl.ch>
 
 ! NOTE! These had better be the same as in bootsect.s!
 #define __ASSEMBLY__
 #include <linux/config.h>
 #include <asm/segment.h>
+#include <linux/version.h>
+#include <linux/compile.h>
 
 #ifndef SVGA_MODE
 #define SVGA_MODE ASK_VGA
@@ -34,9 +39,11 @@
 #define SIG1	0xAA55
 #define SIG2	0x5A5A
 
-INITSEG  = DEF_INITSEG	! we move boot here - out of the way
-SYSSEG   = DEF_SYSSEG	! system loaded at 0x10000 (65536).
-SETUPSEG = DEF_SETUPSEG	! this is the current segment
+INITSEG  = DEF_INITSEG	! 0x9000, we move boot here - out of the way
+SYSSEG   = DEF_SYSSEG	! 0x1000, system loaded at 0x10000 (65536).
+SETUPSEG = DEF_SETUPSEG	! 0x9020, this is the current segment
+			! ... and the former contents of CS
+DELTA_INITSEG = SETUPSEG - INITSEG ! 0x0020
 
 .globl begtext, begdata, begbss, endtext, enddata, endbss
 .text
@@ -49,14 +56,61 @@
 
 entry start
 start:
+	jmp	start_of_setup
+! ------------------------ start of header --------------------------------
+!
+! SETUP-header, must start at CS:2 (old 0x9020:2)
+!
+		.ascii	"HdrS"		! Signature for SETUP-header
+		.word	0x0200		! Version number of header format
+					! (must be >= 0x0105
+					! else old loadlin-1.5 will fail)
+realmode_swtch:	.word	0,0		! default_switch,SETUPSEG
+start_sys_seg:	.word	SYSSEG
+		.word	kernel_version	! pointing to kernel version string
+  ! note: above part of header is compatible with loadlin-1.5 (header v1.5),
+  !        must not change it
+
+type_of_loader:	.byte	0		! = 0, old one (LILO, Loadlin,
+					!      Bootlin, SYSLX, bootsect...)
+					! else it is set by the loader:
+					! 0xTV: T=0 for LILO
+					!       T=1 for Loadlin
+					!       T=2 for bootsect-loader
+					!       V = version
+loadflags:	.byte	0	! unused bits =0 (reserved for future development)
+LOADED_HIGH	= 1		! bit within loadflags,
+				! if set, then the kernel is loaded high
+setup_move_size: .word  0x8000	! size to move, when we (setup) are not
+				! loaded at 0x90000. We will move ourselves
+				! to 0x90000 then just before jumping into
+				! the kernel. However, only the loader
+				! know how much of data behind us also needs
+				! to be loaded.
+code32_start:	.long	0x1000		! here loaders can put a different
+					! start address for 32-bit code.
+					!   0x1000 = default for zImage
+					! 0x100000 = default for big kernel
+ramdisk_image:	.long	0	! address of loaded ramdisk image
+				! Here the loader (or kernel generator) puts
+				! the 32-bit address were it loaded the image.
+				! This only will be interpreted by the kernel.
+ramdisk_size:	.long	0	! its size in bytes
+bootsect_kludge:
+		.word   bootsect_helper,SETUPSEG
+! ------------------------ end of header ----------------------------------
+
+start_of_setup:
 ! Bootlin depends on this being done early
 	mov	ax,#0x01500
 	mov	dl,#0x81
 	int	0x13
 
-! Check signature at end of setup
-	mov	ax,#SETUPSEG
+! set DS=CS, we know that SETUPSEG == CS at this point
+	mov	ax,cs		! aka #SETUPSEG
 	mov	ds,ax
+
+! Check signature at end of setup
 	cmp	setup_sig1,#SIG1
 	jne	bad_sig
 	cmp	setup_sig2,#SIG2
@@ -89,14 +143,14 @@
 	
 no_sig_mess:	.ascii	"No setup signature found ..."
 		db	0x00
-start_sys_seg:	.word	SYSSEG
 
 good_sig1:
 	jmp	good_sig
 
 ! We now have to find the rest of the setup code/data
 bad_sig:
-	mov	ax,#INITSEG
+	mov	ax,cs		! aka #SETUPSEG
+	sub	ax,#DELTA_INITSEG ! aka #INITSEG
 	mov	ds,ax
 	xor	bh,bh
 	mov	bl,[497]	! get setup sects from boot sector
@@ -111,14 +165,14 @@
 ! Move rest of setup code/data to here
 	mov	di,#2048	! four sectors loaded by LILO
 	sub	si,si
-	mov	ax,#SETUPSEG
+	mov	ax,cs		! aka #SETUPSEG
 	mov	es,ax
 	mov	ax,#SYSSEG
 	mov	ds,ax
 	rep
 	movsw
 
-	mov	ax,#SETUPSEG
+	mov	ax,cs		! aka #SETUPSEG
 	mov	ds,ax
 	cmp	setup_sig1,#SIG1
 	jne	no_sig
@@ -133,9 +187,29 @@
 	jmp	no_sig_loop
 
 good_sig:
-	mov	ax,#INITSEG
+	mov	ax,cs		! aka #SETUPSEG
+	sub	ax,#DELTA_INITSEG ! aka #INITSEG
 	mov	ds,ax
 
+! check if an old loader tries to load a big-kernel
+	seg cs
+	test	byte ptr loadflags,#LOADED_HIGH ! have we a big kernel ?
+	jz	loader_ok	! NO, no danger even for old loaders
+				! YES, we have a big-kernel
+	seg cs
+	cmp	byte ptr type_of_loader,#0 ! have we one of the new loaders ?
+	jnz	loader_ok	! YES, ok
+				! NO, we have an old loader, must give up
+	push    cs
+	pop	ds
+	lea	si,loader_panic_mess
+	call	prtstr
+	jmp	no_sig_loop
+loader_panic_mess: 
+	.ascii	"Wrong loader, giving up..."
+	db	0
+
+loader_ok:
 ! Get memory size (extended mem, kB)
 
 	mov	ah,#0x88
@@ -191,7 +265,8 @@
 	xor	ax,ax		! clear ax
 	mov	ds,ax
 	lds	si,[4*0x41]
-	mov	ax,#INITSEG
+	mov	ax,cs		! aka #SETUPSEG
+	sub	ax,#DELTA_INITSEG ! aka #INITSEG
 	push	ax
 	mov	es,ax
 	mov	di,#0x0080
@@ -221,7 +296,8 @@
 	cmp	ah,#3
 	je	is_disk1
 no_disk1:
-	mov	ax,#INITSEG
+	mov	ax,cs		! aka #SETUPSEG
+	sub	ax,#DELTA_INITSEG ! aka #INITSEG
 	mov	es,ax
 	mov	di,#0x0090
 	mov	cx,#0x10
@@ -233,7 +309,8 @@
 
 ! check for PS/2 pointing device
 
-	mov	ax,#INITSEG
+	mov	ax,cs		! aka #SETUPSEG
+	sub	ax,#DELTA_INITSEG ! aka #INITSEG
 	mov	ds,ax
 	mov	[0x1ff],#0	! default is no pointing device
 	int	0x11		! int 0x11: equipment determination
@@ -244,7 +321,8 @@
 
 #ifdef CONFIG_APM
 ! check for APM BIOS
-
+		! NOTE:	DS is pointing to the bootsector
+		!
 	mov	[64],#0		! version == 0 means no APM BIOS
 
 	mov	ax,#0x05300	! APM BIOS installation check
@@ -285,21 +363,43 @@
 
 ! now we want to move to protected mode ...
 
-	cli			! no interrupts allowed !
-	mov	al,#0x80	! disable NMI for the bootup sequence
-	out	#0x70,al
+	seg cs
+	cmp	realmode_swtch,#0
+	jz	rmodeswtch_normal
+	seg cs
+	callf	far * realmode_swtch
+	jmp	rmodeswtch_end
+rmodeswtch_normal:
+        push	cs
+	call	default_switch
+rmodeswtch_end:
 
-! first we move the system to its rightful place
+! we get the code32 start address and modify the below 'jmpi'
+! (loader may have changed it)
+	seg cs
+	mov	eax,code32_start
+	seg cs
+	mov	code32,eax
+
+! Now we move the system to its rightful place
+! ...but we check, if we have a big-kernel.
+! in this case we *must* not move it ...
+	seg cs
+	test	byte ptr loadflags,#LOADED_HIGH
+	jz	do_move0	! we have a normal low loaded zImage
+				! we have a high loaded big kernel
+	jmp	end_move	! ... and we skip moving
 
+do_move0:
 	mov	ax,#0x100	! start of destination segment
+	mov	bp,cs		! aka #SETUPSEG
+	sub	bp,#DELTA_INITSEG ! aka #INITSEG
 	seg cs
 	mov	bx,start_sys_seg	! start of source segment
 	cld			! 'direction'=0, movs moves forward
 do_move:
 	mov	es,ax		! destination segment
 	inc	ah		! instead of add ax,#0x100
-	cmp	ax,#0x9000
-	jz	end_move
 	mov	ds,bx		! source segment
 	add	bx,#0x100
 	sub	di,di
@@ -307,13 +407,58 @@
 	mov 	cx,#0x800
 	rep
 	movsw
-	jmp	do_move
+	cmp	bx,bp		! we assume start_sys_seg > 0x200,
+				! so we will perhaps read one page more then
+				! needed, but never overwrite INITSEG because
+				! destination is minimum one page below source
+	jb	do_move
 
 ! then we load the segment descriptors
 
 end_move:
-	mov	ax,#SETUPSEG	! right, forgot this at first. didn't work :-)
+	mov	ax,cs ! aka #SETUPSEG	! right, forgot this at first. didn't work :-)
 	mov	ds,ax
+
+! If we have our code not at 0x90000, we need to move it there now.
+! We also then need to move the params behind it (commandline)
+! Because we would overwrite the code on the current IP, we move
+! it in two steps, jumping high after the first one.
+	mov	ax,cs
+	cmp	ax,#SETUPSEG
+	je	end_move_self
+	cli	! make sure we really have interrupts disabled !
+		! because after this the stack should not be used
+	sub	ax,#DELTA_INITSEG ! aka #INITSEG
+	mov	dx,ss
+	cmp	dx,ax
+	jb	move_self_1
+	add	dx,#INITSEG
+	sub	dx,ax		! this will be SS after the move
+move_self_1:
+	mov	ds,ax
+	mov	ax,#INITSEG	! real INITSEG
+	mov	es,ax
+	seg cs
+	mov	cx,setup_move_size
+	std		! we have to move up, so we use direction down
+			! because the areas may overlap
+	mov	di,cx
+	dec	di
+	mov	si,di
+	sub	cx,#move_self_here+0x200
+	rep
+	movsb
+	jmpi	move_self_here,SETUPSEG ! jump to our final place
+move_self_here:
+	mov	cx,#move_self_here+0x200
+	rep
+	movsb
+	mov	ax,#SETUPSEG
+	mov	ds,ax
+	mov	ss,dx
+			! now we are at the right place
+end_move_self:
+
 	lidt	idt_48		! load idt with 0,0
 	lgdt	gdt_48		! load gdt with whatever appropriate
 
@@ -379,7 +524,8 @@
 ! Well, now's the time to actually move into protected mode. To make
 ! things as simple as possible, we do no register set-up or anything,
 ! we let the gnu-compiled 32-bit programs do that. We just jump to
-! absolute address 0x00000, in 32-bit protected mode.
+! absolute address 0x1000 (or the loader supplied one),
+! in 32-bit protected mode.
 !
 ! Note that the short jump isn't strictly needed, although there are
 ! reasons why it might be a good idea. It won't hurt in any case.
@@ -390,7 +536,116 @@
 	jmp	flush_instr
 flush_instr:
 	mov	bx,#0		! Flag to indicate a boot
-	jmpi	0x1000,KERNEL_CS	! jmp offset 1000 of segment 0x10 (cs)
+
+! NOTE: For high loaded big kernels we need a
+!	jmpi    0x100000,KERNEL_CS
+!
+!	but we yet haven't reloaded the CS register, so the default size 
+!	of the target offset still is 16 bit.
+!       However, using an operant prefix (0x66), the CPU will properly
+!	take our 48 bit far pointer. (INTeL 80386 Programmer's Reference
+!	Manual, Mixing 16-bit and 32-bit code, page 16-6)
+	db	0x66,0xea	! prefix + jmpi-opcode
+code32:	dd	0x1000		! will be set to 0x100000 for big kernels
+	dw	KERNEL_CS
+
+
+kernel_version:	.ascii	UTS_RELEASE
+		.ascii	" ("
+		.ascii	LINUX_COMPILE_BY
+		.ascii	"@"
+		.ascii	LINUX_COMPILE_HOST
+		.ascii	") "
+		.ascii	UTS_VERSION
+		db	0
+
+! This is the default real mode switch routine.
+! to be called just before protected mode transition
+
+default_switch:
+	cli			! no interrupts allowed !
+	mov	al,#0x80	! disable NMI for the bootup sequence
+	out	#0x70,al
+	retf
+
+! This routine only gets called, if we get loaded by the simple
+! bootsect loader _and_ have a bzImage to load.
+! Because there is no place left in the 512 bytes of the boot sector,
+! we must emigrate to code space here.
+!
+bootsect_helper:
+	seg cs
+	cmp	word ptr bootsect_es,#0
+	jnz	bootsect_second
+	seg cs
+	mov	byte ptr type_of_loader,#0x20
+	mov	ax,es
+	shr	ax,#4
+	seg	cs
+	mov	byte ptr bootsect_src_base+2,ah
+	mov	ax,es
+	seg cs
+	mov	bootsect_es,ax
+	sub	ax,#SYSSEG
+	retf			! nothing else to do for now
+bootsect_second:
+	push	cx
+	push	si
+	push	bx
+	test	bx,bx	! 64K full ?
+	jne	bootsect_ex
+	mov	cx,#0x8000	! full 64K move, INT15 moves words
+	push	cs
+	pop	es
+	mov	si,#bootsect_gdt
+	mov	ax,#0x8700
+	int	0x15
+	jc	bootsect_panic	! this, if INT15 fails
+	seg cs
+	mov	es,bootsect_es	! we reset es to always point to 0x10000
+	seg cs
+	inc	byte ptr bootsect_dst_base+2
+bootsect_ex:
+	seg cs
+	mov	ah, byte ptr bootsect_dst_base+2
+	shl	ah,4	! we now have the number of moved frames in ax
+	xor	al,al
+	pop	bx
+	pop	si
+	pop	cx
+	retf
+
+bootsect_gdt:
+	.word	0,0,0,0
+	.word	0,0,0,0
+bootsect_src:
+	.word	0xffff
+bootsect_src_base:
+	.byte	0,0,1			! base = 0x010000
+	.byte	0x93			! typbyte
+	.word	0			! limit16,base24 =0
+bootsect_dst:
+	.word	0xffff
+bootsect_dst_base:
+	.byte	0,0,0x10		! base = 0x100000
+	.byte	0x93			! typbyte
+	.word	0			! limit16,base24 =0
+	.word	0,0,0,0			! BIOS CS
+	.word	0,0,0,0			! BIOS DS
+bootsect_es:
+	.word	0
+
+bootsect_panic:
+	push	cs
+	pop	ds
+	cld
+	lea	si,bootsect_panic_mess
+	call	prtstr
+bootsect_panic_loop:
+	jmp	bootsect_panic_loop
+bootsect_panic_mess:
+	.ascii	"INT15 refuses to access high mem, giving up..."
+	db	0
 
 ! This routine checks that the keyboard command queue is empty
 ! (after emptying the output buffers)
@@ -975,15 +1230,15 @@
 
 	.word	0,0,0,0		! unused
 
-	.word	0x07FF		! 8Mb - limit=2047 (2048*4096=8Mb)
+	.word	0xFFFF		! 4Gb - (0x100000*0x1000 = 4Gb)
 	.word	0x0000		! base address=0
 	.word	0x9A00		! code read/exec
-	.word	0x00C0		! granularity=4096, 386
+	.word	0x00CF		! granularity=4096, 386 (+5th nibble of limit)
 
-	.word	0x07FF		! 8Mb - limit=2047 (2048*4096=8Mb)
+	.word	0xFFFF		! 4Gb - (0x100000*0x1000 = 4Gb)
 	.word	0x0000		! base address=0
 	.word	0x9200		! data read/write
-	.word	0x00C0		! granularity=4096, 386
+	.word	0x00CF		! granularity=4096, 386 (+5th nibble of limit)
 
 idt_48:
 	.word	0			! idt limit=0
diff -u --recursive --new-file v1.3.72/linux/arch/i386/boot/tools/build.c linux/arch/i386/boot/tools/build.c
--- v1.3.72/linux/arch/i386/boot/tools/build.c	Wed Aug  2 13:20:58 1995
+++ linux/arch/i386/boot/tools/build.c	Sat Mar  9 13:31:43 1996
@@ -18,6 +18,7 @@
 
 /*
  * Changes by tytso to allow root device specification
+ * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996
  */
 
 #include <stdio.h>	/* fprintf */
@@ -39,7 +40,11 @@
 static int GCC_HEADER = sizeof(struct exec);
 #endif
 
+#ifdef __BIG_KERNEL__
+#define SYS_SIZE 0xffff
+#else
 #define SYS_SIZE DEF_SYSSIZE
+#endif
 
 #define DEFAULT_MAJOR_ROOT 0
 #define DEFAULT_MINOR_ROOT 0
@@ -172,8 +177,22 @@
 	if (((long *) buf)[7] != 0)
 		die("Illegal symbol table in 'setup'");
 	for (i=0 ; (c=read(id,buf,sizeof buf))>0 ; i+=c )
+#ifdef __BIG_KERNEL__
+	{
+		if (!i) {
+			if (*((long *)(&buf[2])) != 0x53726448 )
+				die("Wrong magic in loader header of 'setup'");
+			if (*((int *)(&buf[6])) < 0x200 )
+				die("Wrong version of loader header of 'setup'");
+			buf[0x11] = 1; /* LOADED_HIGH */
+			*((long *)(&buf[0x14])) = 0x100000; /* code32_start */
+		}
+#endif
 		if (write(1,buf,c)!=c)
 			die("Write call failed");
+#ifdef __BIG_KERNEL__
+	}
+#endif
 	if (c != 0)
 		die("read-error on 'setup'");
 	close (id);
diff -u --recursive --new-file v1.3.72/linux/arch/i386/kernel/entry.S linux/arch/i386/kernel/entry.S
--- v1.3.72/linux/arch/i386/kernel/entry.S	Tue Feb 20 14:37:23 1996
+++ linux/arch/i386/kernel/entry.S	Sun Mar 10 09:28:55 1996
@@ -128,6 +128,8 @@
 #define	LEAVE_KERNEL \
 	pushfl; \
 	cli; \
+	GET_PROCESSOR_ID \
+	btrl $ SMP_FROM_SYSCALL,SYMBOL_NAME(smp_proc_in_lock)(,%eax,4); \
 	decl SYMBOL_NAME(syscall_count); \
 	decl SYMBOL_NAME(kernel_counter); \
 	jnz 1f;	\
@@ -166,6 +168,7 @@
 	pushfl; \
 	cli; \
 	GET_PROCESSOR_ID \
+	btsl $ SMP_FROM_SYSCALL,SYMBOL_NAME(smp_proc_in_lock)(,%eax,4); \
 	SMP_PROF_A \
 1:	lock; \
 	btsl $0, SYMBOL_NAME(kernel_flag); \
diff -u --recursive --new-file v1.3.72/linux/arch/i386/kernel/irq.c linux/arch/i386/kernel/irq.c
--- v1.3.72/linux/arch/i386/kernel/irq.c	Sun Mar 10 09:49:46 1996
+++ linux/arch/i386/kernel/irq.c	Mon Mar 11 12:47:28 1996
@@ -41,43 +41,50 @@
 static unsigned int int_count[NR_CPUS][NR_IRQS] = {{0},};
 #endif
 
-void disable_irq(unsigned int irq_nr)
+static inline void mask_irq(unsigned int irq_nr)
 {
-	unsigned long flags;
 	unsigned char mask;
 
 	mask = 1 << (irq_nr & 7);
-	save_flags(flags);
 	if (irq_nr < 8) {
-		cli();
 		cache_21 |= mask;
 		outb(cache_21,0x21);
-		restore_flags(flags);
-		return;
+	} else {
+		cache_A1 |= mask;
+		outb(cache_A1,0xA1);
 	}
-	cli();
-	cache_A1 |= mask;
-	outb(cache_A1,0xA1);
-	restore_flags(flags);
 }
 
-void enable_irq(unsigned int irq_nr)
+static inline void unmask_irq(unsigned int irq_nr)
 {
-	unsigned long flags;
 	unsigned char mask;
 
 	mask = ~(1 << (irq_nr & 7));
-	save_flags(flags);
 	if (irq_nr < 8) {
-		cli();
 		cache_21 &= mask;
 		outb(cache_21,0x21);
-		restore_flags(flags);
-		return;
+	} else {
+		cache_A1 &= mask;
+		outb(cache_A1,0xA1);
 	}
+}
+
+void disable_irq(unsigned int irq_nr)
+{
+	unsigned long flags;
+
+	save_flags(flags);
 	cli();
-	cache_A1 &= mask;
-	outb(cache_A1,0xA1);
+	mask_irq(irq_nr);
+	restore_flags(flags);
+}
+
+void enable_irq(unsigned int irq_nr)
+{
+	unsigned long flags;
+	save_flags(flags);
+	cli();
+	unmask_irq(irq_nr);
 	restore_flags(flags);
 }
 
@@ -167,13 +174,54 @@
 /*
  * Initial irq handlers.
  */
-static struct irqaction timer_irq   = { NULL, 0, 0, NULL, NULL, NULL};
-static struct irqaction cascade_irq = { NULL, 0, 0, NULL, NULL, NULL};
-static struct irqaction math_irq    = { NULL, 0, 0, NULL, NULL, NULL};
+
+static void no_action(int cpl, void *dev_id, struct pt_regs *regs) { }
+
+#ifdef __SMP__
+
+/*
+ * On SMP boards, irq13 is used for interprocessor interrupts (IPI's).
+ */
+static struct irqaction irq13 = { smp_message_irq, SA_INTERRUPT, 0, "IPI", NULL, NULL }:
+
+#else
+
+/*
+ * Note that on a 486, we don't want to do a SIGFPE on a irq13
+ * as the irq is unreliable, and exception 16 works correctly
+ * (ie as explained in the intel literature). On a 386, you
+ * can't use exception 16 due to bad IBM design, so we have to
+ * rely on the less exact irq13.
+ *
+ * Careful.. Not only is IRQ13 unreliable, but it is also
+ * leads to races. IBM designers who came up with it should
+ * be shot.
+ */
+ 
+
+static void math_error_irq(int cpl, void *dev_id, struct pt_regs *regs)
+{
+	outb(0,0xF0);
+	if (ignore_irq13 || !hard_math)
+		return;
+	math_error();
+}
+
+static struct irqaction irq13 = { math_error_irq, 0, 0, "math error", NULL, NULL };
+
+#endif
+
+/*
+ * IRQ0 is timer, IRQ2 is cascade interrupt to second interrupt controller
+ */
+extern struct irqaction irq0;
+static struct irqaction irq2  = { no_action, 0, 0, "cascade", NULL, NULL};
 
 static struct irqaction *irq_action[16] = {
-	  NULL, NULL, NULL, NULL, NULL, NULL , NULL, NULL,
-	  NULL, NULL, NULL, NULL, NULL, NULL , NULL, NULL
+	&irq0, NULL, &irq2, NULL,
+	NULL, NULL, NULL, NULL,
+	NULL, NULL, NULL, NULL,
+	NULL, &irq13 , NULL, NULL
 };
 
 int get_irq_list(char *buf)
@@ -182,9 +230,9 @@
 	struct irqaction * action;
 
 	for (i = 0 ; i < 16 ; i++) {
-	        action = *(i + irq_action);
+		action = irq_action[i];
 		if (!action) 
-		        continue;
+			continue;
 		len += sprintf(buf+len, "%2d: %8d %c %s",
 			i, kstat.interrupts[i],
 			(action->flags & SA_INTERRUPT) ? '+' : ' ',
@@ -209,69 +257,77 @@
 #ifdef __SMP_PROF__
 
 int get_smp_prof_list(char *buf) {
-        int i,j, len = 0;
-        struct irqaction * action;
-        unsigned long sum_spins = 0;
-        unsigned long sum_spins_syscall = 0;
-        unsigned long sum_spins_sys_idle = 0;
-        unsigned long sum_smp_idle_count = 0;
-
-        for (i=0;i<=smp_num_cpus;i++) {
-          sum_spins+=smp_spins[i];
-          sum_spins_syscall+=smp_spins_syscall[i];
-          sum_spins_sys_idle+=smp_spins_sys_idle[i];
-          sum_smp_idle_count+=smp_idle_count[i];
-        }
+	int i,j, len = 0;
+	struct irqaction * action;
+	unsigned long sum_spins = 0;
+	unsigned long sum_spins_syscall = 0;
+	unsigned long sum_spins_sys_idle = 0;
+	unsigned long sum_smp_idle_count = 0;
+
+	for (i=0;i<=smp_num_cpus;i++) {
+		sum_spins+=smp_spins[i];
+		sum_spins_syscall+=smp_spins_syscall[i];
+		sum_spins_sys_idle+=smp_spins_sys_idle[i];
+		sum_smp_idle_count+=smp_idle_count[i];
+	}
 
 	len += sprintf(buf+len,"CPUS: %10i \n", 
 		0==smp_num_cpus?1:smp_num_cpus);
-        len += sprintf(buf+len,"            SUM ");
-        for (i=0;i<smp_num_cpus;i++)
-          len += sprintf(buf+len,"        P%1d ",i);
-        len += sprintf(buf+len,"\n");
-        for (i = 0 ; i < NR_IRQS ; i++) {
-	        action = *(i + irq_action);
-                if (!action->handler)
-                        continue;
-                len += sprintf(buf+len, "%3d: %10d ",
-                        i, kstat.interrupts[i]);
-                for (j=0;j<smp_num_cpus;j++)
-                  len+=sprintf(buf+len, "%10d ",int_count[j][i]);
-                len += sprintf(buf+len, "%c %s\n",
-                        (action->flags & SA_INTERRUPT) ? '+' : ' ',
-                        action->name);
+	len += sprintf(buf+len,"            SUM ");
+	for (i=0;i<smp_num_cpus;i++)
+		len += sprintf(buf+len,"        P%1d ",i);
+	len += sprintf(buf+len,"\n");
+	for (i = 0 ; i < NR_IRQS ; i++) {
+		action = *(i + irq_action);
+		if (!action->handler)
+			continue;
+		len += sprintf(buf+len, "%3d: %10d ",
+			i, kstat.interrupts[i]);
+		for (j=0;j<smp_num_cpus;j++)
+			len+=sprintf(buf+len, "%10d ",int_count[j][i]);
+		len += sprintf(buf+len, "%c %s\n",
+			(action->flags & SA_INTERRUPT) ? '+' : ' ',
+			action->name);
 		for (action=action->next; action; action = action->next) {
 			len += sprintf(buf+len, ",%s %s",
 				(action->flags & SA_INTERRUPT) ? " +" : "",
 				action->name);
 		}
-        }
-        len+=sprintf(buf+len, "LCK: %10lu",
-                sum_spins);
-        for (i=0;i<smp_num_cpus;i++)
-          len+=sprintf(buf+len," %10lu",smp_spins[i]);
-        len +=sprintf(buf+len,"   spins from int\n");
-
-        len+=sprintf(buf+len, "LCK: %10lu",
-                sum_spins_syscall);
-        for (i=0;i<smp_num_cpus;i++)
-          len+=sprintf(buf+len," %10lu",smp_spins_syscall[i]);
-        len +=sprintf(buf+len,"   spins from syscall\n");
-
-        len+=sprintf(buf+len, "LCK: %10lu",
-                sum_spins_sys_idle);
-        for (i=0;i<smp_num_cpus;i++)
-          len+=sprintf(buf+len," %10lu",smp_spins_sys_idle[i]);
-        len +=sprintf(buf+len,"   spins from sysidle\n");
-        len+=sprintf(buf+len,"IDLE %10lu",sum_smp_idle_count);
-        for (i=0;i<smp_num_cpus;i++)
-          len+=sprintf(buf+len," %10lu",smp_idle_count[i]);
-        len +=sprintf(buf+len,"   idle ticks\n");
+	}
+	len+=sprintf(buf+len, "LCK: %10lu",
+		sum_spins);
+
+	for (i=0;i<smp_num_cpus;i++)
+		len+=sprintf(buf+len," %10lu",smp_spins[i]);
+
+	len +=sprintf(buf+len,"   spins from int\n");
 
-        len+=sprintf(buf+len, "IPI: %10lu   received\n",
-                ipi_count);
+	len+=sprintf(buf+len, "LCK: %10lu",
+		sum_spins_syscall);
 
-        return len;
+	for (i=0;i<smp_num_cpus;i++)
+		len+=sprintf(buf+len," %10lu",smp_spins_syscall[i]);
+
+	len +=sprintf(buf+len,"   spins from syscall\n");
+
+	len+=sprintf(buf+len, "LCK: %10lu",
+		sum_spins_sys_idle);
+
+	for (i=0;i<smp_num_cpus;i++)
+		len+=sprintf(buf+len," %10lu",smp_spins_sys_idle[i]);
+
+	len +=sprintf(buf+len,"   spins from sysidle\n");
+	len+=sprintf(buf+len,"IDLE %10lu",sum_smp_idle_count);
+
+	for (i=0;i<smp_num_cpus;i++)
+		len+=sprintf(buf+len," %10lu",smp_idle_count[i]);
+
+	len +=sprintf(buf+len,"   idle ticks\n");
+
+	len+=sprintf(buf+len, "IPI: %10lu   received\n",
+		ipi_count);
+
+	return len;
 }
 #endif 
 
@@ -295,14 +351,13 @@
 
 	kstat.interrupts[irq]++;
 #ifdef __SMP_PROF__
-        int_count[smp_processor_id()][irq]++;
+	int_count[smp_processor_id()][irq]++;
 #endif
 	while (action) {
-	    if (action->flags & SA_SAMPLE_RANDOM) {
-	        add_interrupt_randomness(irq);
-            }
-	    action->handler(irq, action->dev_id, regs);
-	    action = action->next;
+		if (action->flags & SA_SAMPLE_RANDOM)
+			add_interrupt_randomness(irq);
+		action->handler(irq, action->dev_id, regs);
+		action = action->next;
 	}
 }
 
@@ -322,60 +377,53 @@
 
 	kstat.interrupts[irq]++;
 #ifdef __SMP_PROF__
-        int_count[smp_processor_id()][irq]++;
+	int_count[smp_processor_id()][irq]++;
 #endif
 	while (action) {
-	    if (action->flags & SA_SAMPLE_RANDOM)
-		add_interrupt_randomness(irq);
-	    action->handler(irq, action->dev_id, NULL);
-	    action = action->next;
+		action->handler(irq, action->dev_id, NULL);
+		action = action->next;
 	}
 }
 
-#define SA_PROBE SA_ONESHOT
-
 int request_irq(unsigned int irq, 
 		void (*handler)(int, void *, struct pt_regs *),
 		unsigned long irqflags, 
 		const char * devname,
 		void *dev_id)
 {
-	struct irqaction * action, *tmp = NULL;
+	int shared = 0;
+	struct irqaction * action, **p;
 	unsigned long flags;
 
 	if (irq > 15)
-	    return -EINVAL;
+		return -EINVAL;
 	if (!handler)
-	    return -EINVAL;
-	action = *(irq + irq_action);
+		return -EINVAL;
+	p = irq_action + irq;
+	action = *p;
 	if (action) {
-	    if ((action->flags & SA_SHIRQ) && (irqflags & SA_SHIRQ)) {
-		for (tmp = action; tmp->next; tmp = tmp->next);
-	    } else {
-		return -EBUSY;
-	    }
-	    if ((action->flags & SA_INTERRUPT) ^ (irqflags & SA_INTERRUPT)) {
-	      printk("Attempt to mix fast and slow interrupts on IRQ%d denied\n", irq);
-	      return -EBUSY;
-	    }   
-	}
+		/* Can't share interrupts unless both agree to */
+		if (!(action->flags & irqflags & SA_SHIRQ))
+			return -EBUSY;
+
+		/* Can't share interrupts unless both are same type */
+		if ((action->flags ^ irqflags) & SA_INTERRUPT)
+			return -EBUSY;
+
+		/* add new interrupt at end of irq queue */
+		do {
+			p = &action->next;
+			action = *p;
+		} while (action);
+		shared = 1;
+	}
+
+	action = (struct irqaction *)kmalloc(sizeof(struct irqaction), GFP_KERNEL);
+	if (!action)
+		return -ENOMEM;
+
 	if (irqflags & SA_SAMPLE_RANDOM)
 		rand_initialize_irq(irq);
-	save_flags(flags);
-	cli();
-	if (irq == 2)
-	    action = &cascade_irq;
-	else if (irq == 13)
-	  action = &math_irq;
-	else if (irq == TIMER_IRQ)
-	  action = &timer_irq;
-	else
-	  action = (struct irqaction *)kmalloc(sizeof(struct irqaction), GFP_KERNEL);
-
-	if (!action) { 
-	    restore_flags(flags);
-	    return -ENOMEM;
-	}
 
 	action->handler = handler;
 	action->flags = irqflags;
@@ -384,140 +432,69 @@
 	action->next = NULL;
 	action->dev_id = dev_id;
 
-	if (tmp) {
-	    tmp->next = action;
-	} else {
-	    *(irq + irq_action) = action;
-	    if (!(action->flags & SA_PROBE)) {/* SA_ONESHOT used by probing */
+	save_flags(flags);
+	cli();
+	*p = action;
+
+	if (!shared) {
 		if (action->flags & SA_INTERRUPT)
-		  set_intr_gate(0x20+irq,fast_interrupt[irq]);
+			set_intr_gate(0x20+irq,fast_interrupt[irq]);
 		else
-		  set_intr_gate(0x20+irq,interrupt[irq]);
-	    }
-	    if (irq < 8) {
-		cache_21 &= ~(1<<irq);
-		outb(cache_21,0x21);
-	    } else {
-		cache_21 &= ~(1<<2);
-		cache_A1 &= ~(1<<(irq-8));
-		outb(cache_21,0x21);
-		outb(cache_A1,0xA1);
-	    }
+			set_intr_gate(0x20+irq,interrupt[irq]);
+		unmask_irq(irq);
 	}
-
 	restore_flags(flags);
 	return 0;
 }
 		
 void free_irq(unsigned int irq, void *dev_id)
 {
-	struct irqaction * action = *(irq + irq_action);
-	struct irqaction * tmp = NULL;
+	struct irqaction * action, **p;
 	unsigned long flags;
 
 	if (irq > 15) {
 		printk("Trying to free IRQ%d\n",irq);
 		return;
 	}
-	if (!action->handler) {
-		printk("Trying to free free IRQ%d\n",irq);
-		return;
-	}
-	if (dev_id) {
-	    for (; action; action = action->next) {
-	        if (action->dev_id == dev_id) break;
-		tmp = action;
-	    }
-	    if (!action) {
-		printk("Trying to free free shared IRQ%d\n",irq);
-		return;
-	    }
-	} else if (action->flags & SA_SHIRQ) {
-	    printk("Trying to free shared IRQ%d with NULL device ID\n", irq);
-	    return;
-	}
-	save_flags(flags);
-	cli();
-	if (action && tmp) {
-	    tmp->next = action->next;
-	} else {
-	    *(irq + irq_action) = action->next;
-	}
-
-	if ((irq == 2) || (irq == 13) | (irq == TIMER_IRQ))
-	  memset(action, 0, sizeof(struct irqaction));
-	else 
-	  kfree_s(action, sizeof(struct irqaction));
-	
-	if (!(*(irq + irq_action))) {
-	    if (irq < 8) {
-		cache_21 |= 1 << irq;
-		outb(cache_21,0x21);
-	    } else {
-		cache_A1 |= 1 << (irq-8);
-		outb(cache_A1,0xA1);
-	    }
-	    set_intr_gate(0x20+irq,bad_interrupt[irq]);
-	}
-
-	restore_flags(flags);
-}
-
-#ifndef __SMP__
+	for (p = irq + irq_action; (action = *p) != NULL; p = &action->next) {
+		if (action->dev_id != dev_id)
+			continue;
 
-/*
- * Note that on a 486, we don't want to do a SIGFPE on a irq13
- * as the irq is unreliable, and exception 16 works correctly
- * (ie as explained in the intel literature). On a 386, you
- * can't use exception 16 due to bad IBM design, so we have to
- * rely on the less exact irq13.
- *
- * Careful.. Not only is IRQ13 unreliable, but it is also
- * leads to races. IBM designers who came up with it should
- * be shot.
- */
- 
-
-static void math_error_irq(int cpl, void *dev_id, struct pt_regs *regs)
-{
-	outb(0,0xF0);
-	if (ignore_irq13 || !hard_math)
+		/* Found it - now free it */
+		save_flags(flags);
+		cli();
+		*p = action->next;
+		if (!irq[irq_action]) {
+			mask_irq(irq);
+			set_intr_gate(0x20+irq,bad_interrupt[irq]);
+		}
+		restore_flags(flags);
+		kfree(action);
 		return;
-	math_error();
+	}
+	printk("Trying to free free IRQ%d\n",irq);
 }
 
-#endif
-
-static void no_action(int cpl, void *dev_id, struct pt_regs *regs) { }
-
 unsigned long probe_irq_on (void)
 {
 	unsigned int i, irqs = 0, irqmask;
 	unsigned long delay;
 
-	/* first, snaffle up any unassigned irqs */
+	/* first, enable any unassigned irqs */
 	for (i = 15; i > 0; i--) {
-		if (!request_irq(i, no_action, SA_PROBE, "probe", NULL)) {
+		if (!irq_action[i]) {
 			enable_irq(i);
 			irqs |= (1 << i);
 		}
 	}
 
 	/* wait for spurious interrupts to mask themselves out again */
-	for (delay = jiffies + 2; delay > jiffies; );	/* min 10ms delay */
+	for (delay = jiffies + HZ/10; delay > jiffies; )
+		/* about 100ms delay */;
 
 	/* now filter out any obviously spurious interrupts */
 	irqmask = (((unsigned int)cache_A1)<<8) | (unsigned int)cache_21;
-	for (i = 15; i > 0; i--) {
-		if (irqs & (1 << i) & irqmask) {
-			irqs ^= (1 << i);
-			free_irq(i, NULL);
-		}
-	}
-#ifdef DEBUG
-	printk("probe_irq_on:  irqs=0x%04x irqmask=0x%04x\n", irqs, irqmask);
-#endif
-	return irqs;
+	return irqs & ~irqmask;
 }
 
 int probe_irq_off (unsigned long irqs)
@@ -525,11 +502,6 @@
 	unsigned int i, irqmask;
 
 	irqmask = (((unsigned int)cache_A1)<<8) | (unsigned int)cache_21;
-	for (i = 15; i > 0; i--) {
-		if (irqs & (1 << i)) {
-			free_irq(i, NULL);
-		}
-	}
 #ifdef DEBUG
 	printk("probe_irq_off: irqs=0x%04x irqmask=0x%04x\n", irqs, irqmask);
 #endif
@@ -561,15 +533,8 @@
 #ifdef __SMP__	
 	set_intr_gate(0x20+i, interrupt[i]);	/* IRQ '16' - IPI for rescheduling */
 #endif	
-	if (request_irq(2, no_action, SA_INTERRUPT, "cascade", NULL))
-		printk("Unable to get IRQ2 for cascade.\n");
-#ifndef __SMP__		
-	if (request_irq(13, math_error_irq, 0, "math error", NULL))
-		printk("Unable to get IRQ13 for math-error handler.\n");
-#else
-	if (request_irq(13, smp_message_irq, SA_INTERRUPT, "IPI", NULL))
-		printk("Unable to get IRQ13 for IPI.\n");
-#endif				
 	request_region(0x20,0x20,"pic1");
 	request_region(0xa0,0x20,"pic2");
+	enable_irq(2);
+	enable_irq(13);
 } 
diff -u --recursive --new-file v1.3.72/linux/arch/i386/kernel/process.c linux/arch/i386/kernel/process.c
--- v1.3.72/linux/arch/i386/kernel/process.c	Wed Feb 28 11:49:59 1996
+++ linux/arch/i386/kernel/process.c	Sun Mar 10 09:28:55 1996
@@ -149,6 +149,20 @@
 	{
 		if(cpu_data[smp_processor_id()].hlt_works_ok && !hlt_counter && !need_resched)
 			__asm("hlt");
+                if(0==(0x7fffffff & smp_process_available)) 
+                	continue;
+                while(0x80000000 & smp_process_available);
+	        cli();
+                while(set_bit(31,&smp_process_available))
+                	while(test_bit(31,&smp_process_available));
+                if (0==(0x7fffffff & smp_process_available)){
+                        clear_bit(31,&smp_process_available);
+                        sti();
+                        continue;
+                }
+                smp_process_available--;
+                clear_bit(31,&smp_process_available);
+                sti();
 		idle();
 	}
 }
diff -u --recursive --new-file v1.3.72/linux/arch/i386/kernel/setup.c linux/arch/i386/kernel/setup.c
--- v1.3.72/linux/arch/i386/kernel/setup.c	Tue Jan 23 21:15:36 1996
+++ linux/arch/i386/kernel/setup.c	Sat Mar  9 13:31:43 1996
@@ -26,7 +26,9 @@
 #ifdef CONFIG_APM
 #include <linux/apm_bios.h>
 #endif
-
+#ifdef CONFIG_BLK_DEV_RAM
+#include <linux/blk.h>
+#endif
 #include <asm/segment.h>
 #include <asm/system.h>
 #include <asm/smp.h>
@@ -88,6 +90,10 @@
 #define RAMDISK_FLAGS (*(unsigned short *) (PARAM+0x1F8))
 #define ORIG_ROOT_DEV (*(unsigned short *) (PARAM+0x1FC))
 #define AUX_DEVICE_INFO (*(unsigned char *) (PARAM+0x1FF))
+#define LOADER_TYPE (*(unsigned char *) (PARAM+0x210))
+#define KERNEL_START (*(unsigned long *) (PARAM+0x214))
+#define INITRD_START (*(unsigned long *) (PARAM+0x218))
+#define INITRD_SIZE (*(unsigned long *) (PARAM+0x21c))
 #define COMMAND_LINE ((char *) (PARAM+2048))
 #define COMMAND_LINE_SIZE 256
 
@@ -149,6 +155,7 @@
 		 * memory size
 		 */
 		if (c == ' ' && *(const unsigned long *)from == *(const unsigned long *)"mem=") {
+			if (to != command_line) to--;
 			if (!memcmp(from+4, "nopentium", 9)) {
 				from += 9+4;
 				x86_capability &= ~8;
@@ -174,6 +181,20 @@
 	*cmdline_p = command_line;
 	*memory_start_p = memory_start;
 	*memory_end_p = memory_end;
+
+#ifdef CONFIG_BLK_DEV_INITRD
+	if (LOADER_TYPE) {
+		initrd_start = INITRD_START;
+		initrd_end = INITRD_START+INITRD_SIZE;
+		if (initrd_end > memory_end) {
+			printk("initrd extends beyond end of memory "
+			    "(0x%08lx > 0x%08lx)\ndisabling initrd\n",
+			    initrd_end,memory_end);
+			initrd_start = 0;
+		}
+	}
+#endif
+
 	/* request io space for devices used on all i[345]86 PC'S */
 	request_region(0x00,0x20,"dma1");
 	request_region(0x40,0x20,"timer");
diff -u --recursive --new-file v1.3.72/linux/arch/i386/kernel/signal.c linux/arch/i386/kernel/signal.c
--- v1.3.72/linux/arch/i386/kernel/signal.c	Sat Feb 17 16:02:45 1996
+++ linux/arch/i386/kernel/signal.c	Mon Mar 11 09:39:33 1996
@@ -215,6 +215,7 @@
 				/* fall through */
 			default:
 				current->signal |= _S(signr & 0x7f);
+				current->flags |= PF_SIGNALED;
 				do_exit(signr);
 			}
 		}
diff -u --recursive --new-file v1.3.72/linux/arch/i386/kernel/smp.c linux/arch/i386/kernel/smp.c
--- v1.3.72/linux/arch/i386/kernel/smp.c	Tue Mar  5 10:10:45 1996
+++ linux/arch/i386/kernel/smp.c	Sun Mar 10 10:06:32 1996
@@ -23,7 +23,6 @@
 
 #include <linux/kernel.h>
 #include <linux/string.h>
-#include <linux/config.h>
 #include <linux/timer.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
@@ -81,6 +80,9 @@
 volatile unsigned long smp_idle_map=0;			/* Map for idle processors 				*/
 #endif
 
+volatile unsigned long  smp_proc_in_lock[NR_CPUS] = {0,};/* for computing process time */
+volatile unsigned long smp_process_available=0;
+
 /*#define SMP_DEBUG*/
 
 #ifdef SMP_DEBUG
@@ -1063,82 +1065,8 @@
 	if(smp_processor_id()!=active_kernel_processor)
 		panic("SMP Reschedule on CPU #%d, but #%d is active.\n",
 			smp_processor_id(), active_kernel_processor);
-	/*
-	 *	Update resource usage on the slave timer tick.
-	 */
-			
-	if (user_mode(regs)) 
-	{
-		current->utime++;
-		if (current->pid) 
-		{
-			if (current->priority < 15)
-				kstat.cpu_nice++;
-			else
-				kstat.cpu_user++;
-		}
-		/* Update ITIMER_VIRT for current task if not in a system call */
-		if (current->it_virt_value && !(--current->it_virt_value)) {
-			current->it_virt_value = current->it_virt_incr;
-			send_sig(SIGVTALRM,current,1);
-		}
-	} else {
-		current->stime++;
-		if(current->pid)
-			kstat.cpu_system++;
-#ifdef CONFIG_PROFILE
-		if (prof_buffer && current->pid) {
-			extern int _stext;
-			unsigned long eip = regs->eip - (unsigned long) &_stext;
-			eip >>= CONFIG_PROFILE_SHIFT;
-			if (eip < prof_len)
-				prof_buffer[eip]++;
-		}
-#endif
-	}
-	/*
-	 * check the cpu time limit on the process.
-	 */
-	if ((current->rlim[RLIMIT_CPU].rlim_max != RLIM_INFINITY) &&
-	    (((current->stime + current->utime) / HZ) >= current->rlim[RLIMIT_CPU].rlim_max))
-		send_sig(SIGKILL, current, 1);
-	if ((current->rlim[RLIMIT_CPU].rlim_cur != RLIM_INFINITY) &&
-	    (((current->stime + current->utime) % HZ) == 0)) {
-		unsigned long psecs = (current->stime + current->utime) / HZ;
-		/* send when equal */
-		if (psecs == current->rlim[RLIMIT_CPU].rlim_cur)
-			send_sig(SIGXCPU, current, 1);
-		/* and every five seconds thereafter. */
-		else if ((psecs > current->rlim[RLIMIT_CPU].rlim_cur) &&
-		        ((psecs - current->rlim[RLIMIT_CPU].rlim_cur) % 5) == 0)
-			send_sig(SIGXCPU, current, 1);
-	}
-
-	/* Update ITIMER_PROF for the current task */
-	if (current->it_prof_value && !(--current->it_prof_value)) {
-		current->it_prof_value = current->it_prof_incr;
-		send_sig(SIGPROF,current,1);
-	}
-
 
-	/*
-	 *	Don't reschedule if we are in an interrupt...
-	 *	[This is test code and not needed in the end]
-	 */
-	 
-/*	if(intr_count==1)
-	{*/
-
-		/*
-		 *	See if the slave processors need a schedule.
-		 */
-
-		if ( 0 > --current->counter || current->pid == 0) 
-		{
-			current->counter = 0;
-			need_resched=1;
-		}
-/*	}*/
+	need_resched=1;
 
 	/*
 	 *	Clear the IPI
diff -u --recursive --new-file v1.3.72/linux/arch/i386/kernel/time.c linux/arch/i386/kernel/time.c
--- v1.3.72/linux/arch/i386/kernel/time.c	Sun Mar 10 09:49:46 1996
+++ linux/arch/i386/kernel/time.c	Mon Mar 11 10:50:20 1996
@@ -17,6 +17,7 @@
 #include <linux/param.h>
 #include <linux/string.h>
 #include <linux/mm.h>
+#include <linux/interrupt.h>
 
 #include <asm/segment.h>
 #include <asm/io.h>
@@ -264,7 +265,7 @@
 	   basically because we don't yet share IRQ's around. This message is
 	   rigged to be safe on the 386 - basically its a hack, so don't look
 	   closely for now.. */
-	smp_message_pass(MSG_ALL_BUT_SELF, MSG_RESCHEDULE, 0L, 0); 
+	/*smp_message_pass(MSG_ALL_BUT_SELF, MSG_RESCHEDULE, 0L, 0); */
 	    
 }
 
@@ -352,27 +353,26 @@
 	return mktime(year, mon, day, hour, min, sec);
 }
 
+struct irqaction irq0  = { timer_interrupt, 0, 0, "timer", NULL, NULL};
+
 void time_init(void)
 {
-	void (*irq_handler)(int, void *, struct pt_regs *);
 	xtime.tv_sec = get_cmos_time();
 	xtime.tv_usec = 0;
 
 	/* If we have the CPU hardware time counters, use them */
-	irq_handler = timer_interrupt;
 #ifndef CONFIG_APM
 				/* Don't use them if a suspend/resume could
                                    corrupt the timer value.  This problem
                                    needs more debugging. */
 	if (x86_capability & 16) {
-		irq_handler = pentium_timer_interrupt;
 		do_gettimeoffset = do_fast_gettimeoffset;
 		/* read Pentium cycle counter */
 		__asm__(".byte 0x0f,0x31"
 			:"=a" (((unsigned long *) &init_timer_cc)[0]),
 			 "=d" (((unsigned long *) &init_timer_cc)[1]));
+		irq0.handler = pentium_timer_interrupt;
 	}
 #endif
-	if (request_irq(TIMER_IRQ, irq_handler, 0, "timer", NULL) != 0)
-		panic("Could not allocate timer IRQ!");
+	enable_irq(0);
 }
diff -u --recursive --new-file v1.3.72/linux/arch/i386/kernel/vm86.c linux/arch/i386/kernel/vm86.c
--- v1.3.72/linux/arch/i386/kernel/vm86.c	Thu Sep  7 17:17:16 1995
+++ linux/arch/i386/kernel/vm86.c	Mon Mar 11 10:33:56 1996
@@ -379,6 +379,7 @@
 			set_vflags_long(popl(ssp, sp), regs);
 			return;
 		}
+		break;
 
 	/* pushf */
 	case 0x9c:
@@ -425,8 +426,10 @@
 		IP(regs)++;
 		set_IF(regs);
 		return;
-
-	default:
-		return_to_32bit(regs, VM86_UNKNOWN);
 	}
+
+	/*
+	 * We didn't recognize it, let the emulator take care of it..
+	 */
+	return_to_32bit(regs, VM86_UNKNOWN);
 }
diff -u --recursive --new-file v1.3.72/linux/arch/i386/mm/init.c linux/arch/i386/mm/init.c
--- v1.3.72/linux/arch/i386/mm/init.c	Sun Jan 14 16:30:10 1996
+++ linux/arch/i386/mm/init.c	Sat Mar  9 13:31:43 1996
@@ -17,6 +17,9 @@
 #include <linux/mm.h>
 #include <linux/swap.h>
 #include <linux/smp.h>
+#ifdef CONFIG_BLK_DEV_INITRD
+#include <linux/blk.h>
+#endif
 
 #include <asm/system.h>
 #include <asm/segment.h>
@@ -243,7 +246,11 @@
 			continue;
 		}
 		mem_map[MAP_NR(tmp)].count = 1;
-		free_page(tmp);
+#ifdef CONFIG_BLK_DEV_INITRD
+		if (!initrd_start || (tmp < initrd_start || tmp >=
+		    initrd_end))
+#endif
+			free_page(tmp);
 	}
 	tmp = nr_free_pages << PAGE_SHIFT;
 	printk("Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data)\n",
diff -u --recursive --new-file v1.3.72/linux/arch/mips/kernel/signal.c linux/arch/mips/kernel/signal.c
--- v1.3.72/linux/arch/mips/kernel/signal.c	Sun Dec 17 11:43:11 1995
+++ linux/arch/mips/kernel/signal.c	Mon Mar 11 09:39:33 1996
@@ -302,6 +302,7 @@
 				/* fall through */
 			default:
 				current->signal |= _S(signr & 0x7f);
+				current->flags |= PF_SIGNALED;
 				do_exit(signr);
 			}
 		}
diff -u --recursive --new-file v1.3.72/linux/arch/ppc/kernel/signal.c linux/arch/ppc/kernel/signal.c
--- v1.3.72/linux/arch/ppc/kernel/signal.c	Mon Nov 27 12:48:26 1995
+++ linux/arch/ppc/kernel/signal.c	Mon Mar 11 09:39:33 1996
@@ -166,6 +166,7 @@
 				/* fall through */
 			default:
 				current->signal |= _S(signr & 0x7f);
+				current->flags |= PF_SIGNALED;
 				do_exit(signr);
 			}
 		}
diff -u --recursive --new-file v1.3.72/linux/arch/sparc/kernel/signal.c linux/arch/sparc/kernel/signal.c
--- v1.3.72/linux/arch/sparc/kernel/signal.c	Tue Mar  5 10:10:48 1996
+++ linux/arch/sparc/kernel/signal.c	Mon Mar 11 09:39:34 1996
@@ -260,6 +260,7 @@
 				/* fall through */
 			default:
 				current->signal |= _S(signr & 0x7f);
+				current->flags |= PF_SIGNALED;
 				do_exit(signr);
 			}
 		}
diff -u --recursive --new-file v1.3.72/linux/drivers/block/Config.in linux/drivers/block/Config.in
--- v1.3.72/linux/drivers/block/Config.in	Sat Mar  2 10:43:21 1996
+++ linux/drivers/block/Config.in	Sat Mar  9 13:31:43 1996
@@ -30,6 +30,10 @@
 fi
 
 tristate 'RAM disk support' CONFIG_BLK_DEV_RAM
+if [ "$CONFIG_BLK_DEV_RAM" = "y" ]; then
+  bool '   Initial RAM disk (initrd) support' CONFIG_BLK_DEV_INITRD
+fi
+
 tristate 'Loopback device support' CONFIG_BLK_DEV_LOOP
 
 if [ "$CONFIG_BLK_DEV_HD_IDE" = "y" -o "$CONFIG_BLK_DEV_HD_ONLY" = "y" ]; then
diff -u --recursive --new-file v1.3.72/linux/drivers/block/floppy.c linux/drivers/block/floppy.c
--- v1.3.72/linux/drivers/block/floppy.c	Tue Mar  5 10:10:52 1996
+++ linux/drivers/block/floppy.c	Mon Mar 11 18:09:16 1996
@@ -448,8 +448,7 @@
  * Track buffer
  * Because these are written to by the DMA controller, they must
  * not contain a 64k byte boundary crossing, or data will be
- * corrupted/lost. Alignment of these is enforced in boot/head.S.
- * Note that you must not change the sizes below without updating head.S.
+ * corrupted/lost.
  */
 static char *floppy_track_buffer=0;
 static int max_buffer_sectors=0;
@@ -3522,7 +3521,7 @@
 	int drive = DRIVE(dev);
 
 	if (MAJOR(dev) != MAJOR_NR) {
-		DPRINT("floppy_changed: not a floppy\n");
+		DPRINT("check_floppy_change: not a floppy\n");
 		return 0;
 	}
 
diff -u --recursive --new-file v1.3.72/linux/drivers/block/genhd.c linux/drivers/block/genhd.c
--- v1.3.72/linux/drivers/block/genhd.c	Sat Mar  2 10:43:22 1996
+++ linux/drivers/block/genhd.c	Sat Mar  9 13:31:43 1996
@@ -24,6 +24,9 @@
 #include <linux/kernel.h>
 #include <linux/major.h>
 #include <linux/string.h>
+#ifdef CONFIG_BLK_DEV_INITRD
+#include <linux/blk.h>
+#endif
 
 #include <asm/system.h>
 
@@ -48,6 +51,7 @@
 static int current_minor = 0;
 extern int *blk_size[];
 extern void rd_load(void);
+extern void initrd_load(void);
 
 extern int chr_dev_init(void);
 extern int blk_dev_init(void);
@@ -601,6 +605,10 @@
 		nr += p->nr_real;
 	}
 #ifdef CONFIG_BLK_DEV_RAM
+#ifdef CONFIG_BLK_DEV_INITRD
+	if (initrd_start && mount_initrd) initrd_load();
+	else
+#endif
 	rd_load();
 #endif
 }
diff -u --recursive --new-file v1.3.72/linux/drivers/block/ide-cd.c linux/drivers/block/ide-cd.c
--- v1.3.72/linux/drivers/block/ide-cd.c	Sat Feb 17 16:02:46 1996
+++ linux/drivers/block/ide-cd.c	Mon Mar 11 11:13:20 1996
@@ -86,6 +86,7 @@
  *                       Work around sporadic Sony55e audio play problem.
  * 3.07a Feb 11, 1996 -- check drive->id for NULL before dereferencing, to fix
  *                        problem with "hde=cdrom" with no drive present.  -ml
+ * 3.08  Mar  6, 1996 -- More Vertos workarounds.
  *
  * NOTE: Direct audio reads will only work on some types of drive.
  * So far, i've received reports of success for Sony and Toshiba drives.
@@ -2720,23 +2721,31 @@
         CDROM_CONFIG_FLAGS (drive)->no_playaudio12 = 1;
       }
 
-    /* Vertos 300.
-       There seem to be at least two different, incompatible versions
-       of this drive floating around.  Luckily, they appear to return their
-       id strings with different byte orderings. */
+    /* Vertos 300. */
     else if (strcmp (drive->id->model, "V003S0DS") == 0)
       {
-        CDROM_CONFIG_FLAGS (drive)->vertos_lossage = 1;
-        CDROM_CONFIG_FLAGS (drive)->playmsf_uses_bcd = 1;
         CDROM_CONFIG_FLAGS (drive)->no_lba_toc = 1;
+
+	/* Some versions of this drive like to talk BCD. */
+	if (drive->id->fw_rev[4] == '1' &&
+	    drive->id->fw_rev[6] <= '2')
+	  {
+	    CDROM_CONFIG_FLAGS (drive)->vertos_lossage = 1;
+	    CDROM_CONFIG_FLAGS (drive)->playmsf_uses_bcd = 1;
+	  }
       }
     else if (strcmp (drive->id->model, "0V300SSD") == 0 ||
-  	   strcmp (drive->id->model, "V003M0DP") == 0)
+	     strcmp (drive->id->model, "V003M0DP") == 0 ||
+	     strcmp (drive->id->model, "0V300MPD") == 0 ||
+	     strcmp (drive->id->model, "0V300HPD") == 0 ||
+	     strcmp (drive->id->model, "V003H0DP") == 0)
       CDROM_CONFIG_FLAGS (drive)->no_lba_toc = 1;
 
     /* Vertos 400. */
     else if (strcmp (drive->id->model, "V004E0DT") == 0 ||
-  	   strcmp (drive->id->model, "0V400ETD") == 0)
+	     strcmp (drive->id->model, "0V400ETD") == 0 ||
+	     strcmp (drive->id->model, "V004H0DT") == 0 ||
+	     strcmp (drive->id->model, "0V400HTD") == 0)
       CDROM_CONFIG_FLAGS (drive)->no_lba_toc = 1;
 
     else if ( strcmp (drive->id->model, "CD-ROM CDU55D") == 0) /*sony cdu55d */
diff -u --recursive --new-file v1.3.72/linux/drivers/block/ide.c linux/drivers/block/ide.c
--- v1.3.72/linux/drivers/block/ide.c	Sun Mar 10 09:49:47 1996
+++ linux/drivers/block/ide.c	Sat Mar  9 12:23:10 1996
@@ -2994,6 +2994,7 @@
 #ifdef CONFIG_BLK_DEV_RZ1000
 		ide_pci_init_proc_t init_rz1000;
 		ide_probe_pci (PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1000, &init_rz1000, 0);
+		ide_probe_pci (PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1001, &init_rz1000, 0);
 #endif /* CONFIG_BLK_DEV_RZ1000 */
 #ifdef CONFIG_BLK_DEV_TRITON
 		/*
diff -u --recursive --new-file v1.3.72/linux/drivers/block/ide.h linux/drivers/block/ide.h
--- v1.3.72/linux/drivers/block/ide.h	Sat Mar  2 10:43:22 1996
+++ linux/drivers/block/ide.h	Tue Mar 12 16:12:06 1996
@@ -223,6 +223,7 @@
   {
     struct 			
     {
+      u_char    reserved;
       u_char	minute;
       u_char	second;
       u_char	frame;
@@ -233,6 +234,7 @@
   {
     struct 
     {
+      u_char    reserved;
       u_char	minute;
       u_char	second;
       u_char	frame;
diff -u --recursive --new-file v1.3.72/linux/drivers/block/loop.c linux/drivers/block/loop.c
--- v1.3.72/linux/drivers/block/loop.c	Tue Mar  5 10:10:52 1996
+++ linux/drivers/block/loop.c	Mon Mar 11 18:09:16 1996
@@ -237,24 +237,30 @@
 
 static int loop_set_fd(struct loop_device *lo, unsigned int arg)
 {
+	struct file	*file;
 	struct inode	*inode;
 	
-	if (arg >= NR_OPEN || !current->files->fd[arg])
+	if (arg >= NR_OPEN || !(file = current->files->fd[arg]))
 		return -EBADF;
 	if (lo->lo_inode)
 		return -EBUSY;
-	inode = current->files->fd[arg]->f_inode;
+	inode = file->f_inode;
 	if (!inode) {
 		printk("loop_set_fd: NULL inode?!?\n");
 		return -EINVAL;
 	}
-	if (S_ISREG(inode->i_mode)) {
+	if (S_ISBLK(inode->i_mode)) {
+		int error = blkdev_open(inode, file);
+		if (error)
+			return error;
+		lo->lo_device = inode->i_rdev;
+		lo->lo_flags = 0;
+	} else if (S_ISREG(inode->i_mode)) {
 		lo->lo_device = inode->i_dev;
-		lo->lo_flags |= LO_FLAGS_DO_BMAP;
-	} else if (S_ISBLK(inode->i_mode))
-			lo->lo_device = inode->i_rdev;
-		else
-			return -EINVAL;
+		lo->lo_flags = LO_FLAGS_DO_BMAP;
+	} else
+		return -EINVAL;
+
 	invalidate_inode_pages (inode);
 	lo->lo_inode = inode;
 	lo->lo_inode->i_count++;
@@ -270,6 +276,8 @@
 		return -ENXIO;
 	if (lo->lo_refcnt > 1)
 		return -EBUSY;
+	if (S_ISBLK(lo->lo_inode->i_mode))
+		blkdev_release (lo->lo_inode);
 	iput(lo->lo_inode);
 	lo->lo_device = 0;
 	lo->lo_inode = NULL;
@@ -293,7 +301,7 @@
 	if (!arg)
 		return -EINVAL;
 	memcpy_fromfs(&info, arg, sizeof(info));
-	if (info.lo_encrypt_key_size > LO_KEY_SIZE)
+	if ((unsigned int) info.lo_encrypt_key_size > LO_KEY_SIZE)
 		return -EINVAL;
 	switch (info.lo_encrypt_type) {
 	case LO_CRYPT_NONE:
diff -u --recursive --new-file v1.3.72/linux/drivers/block/rd.c linux/drivers/block/rd.c
--- v1.3.72/linux/drivers/block/rd.c	Sat Feb 17 16:02:46 1996
+++ linux/drivers/block/rd.c	Sat Mar  9 13:31:43 1996
@@ -30,8 +30,11 @@
  *	Cosmetic changes in #ifdef MODULE, code movement, etc...
  * 	When the ramdisk is rmmod'ed, free the protected buffers
  * 	Default ramdisk size changed to 2.88MB
+ *
+ *  Added initrd: Werner Almesberger & Hans Lermen, Feb '96
  */
 
+#include <linux/config.h>
 #include <linux/sched.h>
 #include <linux/minix_fs.h>
 #include <linux/ext2_fs.h>
@@ -68,6 +71,10 @@
 
 void rd_load(void);
 static int crd_load(struct file *fp, struct file *outfp);
+
+#ifdef CONFIG_BLK_DEV_INITRD
+static int initrd_users = 0;
+#endif
 #endif
 
 /* Various static variables go here... mostly used within the ramdisk code only. */
@@ -85,6 +92,10 @@
 int rd_doload = 0;		/* 1 = load ramdisk, 0 = don't load */
 int rd_prompt = 1;		/* 1 = prompt for ramdisk, 0 = don't prompt */
 int rd_image_start = 0;		/* starting block # of image */
+#ifdef CONFIG_BLK_DEV_INITRD
+unsigned long initrd_start,initrd_end;
+int mount_initrd = 1;		/* zero if initrd should not be mounted */
+#endif
 #endif
 
 /*
@@ -161,8 +172,61 @@
 	return 0;
 }
 
+
+#ifdef CONFIG_BLK_DEV_INITRD
+
+static int initrd_read(struct inode *inode,struct file *file,char *buf,
+    int count)
+{
+	int left;
+
+	left = initrd_end-initrd_start-file->f_pos;
+	if (count > left) count = left;
+	if (count <= 0) return 0;
+	memcpy_tofs(buf,(char *) initrd_start+file->f_pos,count);
+	file->f_pos += count;
+	return count;
+}
+
+
+static void initrd_release(struct inode *inode,struct file *file)
+{
+	unsigned long i;
+
+	if (--initrd_users) return;
+	for (i = initrd_start; i < initrd_end; i += PAGE_SIZE)
+		free_page(i);
+	initrd_start = 0;
+}
+
+
+static struct file_operations initrd_fops = {
+	NULL,		/* lseek */
+	initrd_read,	/* read */
+	NULL,		/* write */
+	NULL,		/* readdir */
+	NULL,		/* select */
+	NULL, 		/* ioctl */
+	NULL,		/* mmap */
+	NULL,		/* open */
+	initrd_release,	/* release */
+	NULL		/* fsync */ 
+};
+
+#endif
+
+
 static int rd_open(struct inode * inode, struct file * filp)
 {
+#ifdef CONFIG_BLK_DEV_INITRD
+	if (DEVICE_NR(inode->i_rdev) == INITRD_MINOR) {
+		if (!initrd_start) return -ENODEV;
+		initrd_users++;
+		filp->f_op = &initrd_fops;
+		return 0;
+	}
+#endif
+
 	if (DEVICE_NR(inode->i_rdev) >= NUM_RAMDISKS)
 		return -ENODEV;
 
@@ -180,7 +244,7 @@
 
 static struct file_operations fd_fops = {
 	NULL,		/* lseek - default */
-	block_read,	/* read - block dev write */
+	block_read,	/* read - block dev read */
 	block_write,	/* write - block dev write */
 	NULL,		/* readdir - not here! */
 	NULL,		/* select */
@@ -350,31 +414,19 @@
 /*
  * This routine loads in the ramdisk image.
  */
-void rd_load()
+static void rd_load_image(kdev_t device,int offset)
 {
 	struct inode inode, out_inode;
 	struct file infile, outfile;
 	unsigned short fs;
-	kdev_t device, ram_device;
+	kdev_t ram_device;
 	int nblocks, i;
 	char *buf;
 	unsigned short rotate = 0;
 	char rotator[4] = { '|' , '/' , '-' , '\\' };
 
-	if (rd_doload == 0)
-		return;
-	
-	device = ROOT_DEV;
 	ram_device = MKDEV(MAJOR_NR, 0);
 
-	if (MAJOR(device) != FLOPPY_MAJOR) return;
-
-	if (rd_prompt) {
-		printk(KERN_NOTICE
-		       "VFS: Insert root floppy disk to be loaded into ramdisk and press ENTER\n");
-		wait_for_keypress();
-	}
-
 	memset(&infile, 0, sizeof(infile));
 	memset(&inode, 0, sizeof(inode));
 	inode.i_rdev = device;
@@ -393,7 +445,7 @@
 	fs = get_fs();
 	set_fs(KERNEL_DS);
 	
-	nblocks = identify_ramdisk_image(device, &infile, rd_image_start);
+	nblocks = identify_ramdisk_image(device, &infile, offset);
 	if (nblocks < 0)
 		goto done;
 
@@ -439,7 +491,7 @@
 	kfree(buf);
 
 successful_load:
-	invalidate_buffers(ROOT_DEV);
+	invalidate_buffers(device);
 	ROOT_DEV = MKDEV(MAJOR_NR,0);
 
 done:
@@ -447,6 +499,33 @@
 		infile.f_op->release(&inode, &infile);
 	set_fs(fs);
 }
+
+
+void rd_load()
+{
+	if (rd_doload == 0)
+		return;
+	
+	if (MAJOR(ROOT_DEV) != FLOPPY_MAJOR) return;
+
+	if (rd_prompt) {
+		printk(KERN_NOTICE
+		       "VFS: Insert root floppy disk to be loaded into ramdisk and press ENTER\n");
+		wait_for_keypress();
+	}
+
+	rd_load_image(ROOT_DEV,rd_image_start);
+
+}
+
+
+#ifdef CONFIG_BLK_DEV_INITRD
+void initrd_load(void)
+{
+	rd_load_image(MKDEV(MAJOR_NR, INITRD_MINOR),0);
+}
+#endif
+
 #endif /* RD_LOADER */
 
 #ifdef BUILD_CRAMDISK
diff -u --recursive --new-file v1.3.72/linux/drivers/char/README.stallion linux/drivers/char/README.stallion
--- v1.3.72/linux/drivers/char/README.stallion	Fri Feb 16 11:34:06 1996
+++ linux/drivers/char/README.stallion	Mon Mar 11 11:20:32 1996
@@ -2,8 +2,8 @@
 Stallion Multiport Serial Drivers
 ---------------------------------
 
-Version: 1.0.2
-Date:    01FEB96
+Version: 1.0.6
+Date:    11MAR96
 Author:  Greg Ungerer (gerg@stallion.oz.au)
 
 
@@ -19,7 +19,7 @@
 driver utility package. This package is available at most of the Linux
 archive sites (and on CD's that contain these archives). The file will be
 called stallion-X.X.X.tar.gz where X.X.X will be the version number. In
-particular this package contains the board embedded executable images that
+particular this package contains the board embeded executable images that
 are required for these boards. It also contains the downloader program.
 These boards cannot be used without this.
 
@@ -85,7 +85,7 @@
 driver will emit some kernel trace messages about whether the configured
 boards where detected or not. Depending on how your system logger is set
 up these may come out on the console, or just be logged to
-/usr/adm/messages. You should check the messages to confirm that all is well.
+/var/adm/messages. You should check the messages to confirm that all is well.
 
 
 2.1 SHARING INTERRUPTS
@@ -310,6 +310,23 @@
     ./stlstty maprts mapcts < /dev/cue0
 This enables RTS to act like DTR and CTS to act like DCD on the specified
 port.
+
+The ports of the EasyIO-8M board do not have DCD or DTR signals. So these
+ports cannot be used as real modem devices. Generally when using these
+ports you should only use the cueX devices.
+
+There is another new utility in this package that reports statistics on
+the serial ports. You will need to have the curses libray installed on
+your system to build it.
+
+To build the statistics display program type:
+    make stlstats
+Once compiled simply run it (you will need to be root) and it will display
+a port summary for the first board and panel installed. Use the digits to
+select different board numbers, or 'n' to cycle through the panels on a
+board. To look at detailed port information then hit 'p', that will display
+detailed port 0 information. Use the digits and letteres 'a' through 'f' to
+select the different ports (on this board and panel).
 
 
 
diff -u --recursive --new-file v1.3.72/linux/drivers/char/istallion.c linux/drivers/char/istallion.c
--- v1.3.72/linux/drivers/char/istallion.c	Fri Feb 16 11:34:06 1996
+++ linux/drivers/char/istallion.c	Mon Mar 11 11:20:32 1996
@@ -38,6 +38,7 @@
 #include <linux/tty_flip.h>
 #include <linux/serial.h>
 #include <linux/cdk.h>
+#include <linux/comstats.h>
 #include <linux/string.h>
 #include <linux/malloc.h>
 #include <linux/ioport.h>
@@ -179,7 +180,7 @@
  *	all the local structures required by a serial tty driver.
  */
 static char	*stli_drvname = "Stallion Intelligent Multiport Serial Driver";
-static char	*stli_drvversion = "1.0.2";
+static char	*stli_drvversion = "1.0.6";
 static char	*stli_serialname = "ttyE";
 static char	*stli_calloutname = "cue";
 
@@ -228,6 +229,14 @@
 	INIT_C_CC
 };
 
+/*
+ *	Define global stats structures. Not used often, and can be
+ *	re-used for each stats call.
+ */
+static comstats_t	stli_comstats;
+static combrd_t		stli_brdstats;
+static asystats_t	stli_cdkstats;
+
 /*****************************************************************************/
 
 /*
@@ -270,6 +279,7 @@
 	struct termios		normaltermios;
 	struct termios		callouttermios;
 	asysigs_t		asig;
+	comstats_t		stats;
 	unsigned long		addr;
 	unsigned long		rxoffset;
 	unsigned long		txoffset;
@@ -302,6 +312,7 @@
 	int		slaveoffset;
 	int		bitsize;
 	int		panels[STL_MAXPANELS];
+	int		panelids[STL_MAXPANELS];
 	void		(*init)(struct stlbrd *brdp);
 	void		(*enable)(struct stlbrd *brdp);
 	void		(*reenable)(struct stlbrd *brdp);
@@ -661,6 +672,9 @@
 static void	stli_read(stlibrd_t *brdp, stliport_t *portp);
 static void	stli_getserial(stliport_t *portp, struct serial_struct *sp);
 static int	stli_setserial(stliport_t *portp, struct serial_struct *sp);
+static int	stli_getbrdstats(combrd_t *bp);
+static int	stli_getportstats(stliport_t *portp, comstats_t *cp);
+static int	stli_clrportstats(stliport_t *portp, comstats_t *cp);
 static void	*stli_memalloc(int len);
 
 static void	stli_ecpinit(stlibrd_t *brdp);
@@ -696,6 +710,8 @@
 static char	*stli_stalgetmemptr(stlibrd_t *brdp, unsigned long offset, int line);
 static void	stli_stalreset(stlibrd_t *brdp);
 
+static stliport_t *stli_getport(int brdnr, int panelnr, int portnr);
+
 #if STLI_HIMEMORY
 static void *stli_mapbrdmem(unsigned long physaddr, unsigned int size);
 #endif
@@ -1938,6 +1954,14 @@
 			stli_setport(portp);
 		}
 		break;
+	case COM_GETPORTSTATS:
+		if ((rc = verify_area(VERIFY_WRITE, (void *) arg, sizeof(comstats_t))) == 0)
+			rc = stli_getportstats(portp, (comstats_t *) arg);
+		break;
+	case COM_CLRPORTSTATS:
+		if ((rc = verify_area(VERIFY_WRITE, (void *) arg, sizeof(comstats_t))) == 0)
+			rc = stli_clrportstats(portp, (comstats_t *) arg);
+		break;
 	case TIOCSERCONFIG:
 	case TIOCSERGWILD:
 	case TIOCSERSWILD:
@@ -3543,6 +3567,7 @@
 			brdp->nrports += 8;
 			nxtid++;
 		}
+		brdp->panelids[panelnr] = status;
 		brdp->nrpanels++;
 	}
 
@@ -3692,6 +3717,7 @@
 		}
 		brdp->nrports = i;
 	}
+	brdp->panels[0] = brdp->nrports;
 
 	request_region(brdp->iobase, ONB_IOSIZE, "serial(ONB/BBY)");
 	brdp->state |= BST_FOUND;
@@ -4244,6 +4270,169 @@
 /*****************************************************************************/
 
 /*
+ *	Return the board stats structure to user app.
+ */
+
+static int stli_getbrdstats(combrd_t *bp)
+{
+	stlibrd_t	*brdp;
+	int		i;
+
+	memcpy_fromfs(&stli_brdstats, bp, sizeof(combrd_t));
+	if (stli_brdstats.brd >= STL_MAXBRDS)
+		return(-ENODEV);
+	brdp = stli_brds[stli_brdstats.brd];
+	if (brdp == (stlibrd_t *) NULL)
+		return(-ENODEV);
+
+	memset(&stli_brdstats, 0, sizeof(combrd_t));
+	stli_brdstats.brd = brdp->brdnr;
+	stli_brdstats.type = brdp->brdtype;
+	stli_brdstats.hwid = 0;
+	stli_brdstats.state = brdp->state;
+	stli_brdstats.ioaddr = brdp->iobase;
+	stli_brdstats.memaddr = brdp->memaddr;
+	stli_brdstats.nrpanels = brdp->nrpanels;
+	stli_brdstats.nrports = brdp->nrports;
+	for (i = 0; (i < brdp->nrpanels); i++) {
+		stli_brdstats.panels[i].panel = i;
+		stli_brdstats.panels[i].hwid = brdp->panelids[i];
+		stli_brdstats.panels[i].nrports = brdp->panels[i];
+	}
+
+	memcpy_tofs(bp, &stli_brdstats, sizeof(combrd_t));
+	return(0);
+}
+
+/*****************************************************************************/
+
+/*
+ *	Resolve the referenced port number into a port struct pointer.
+ */
+
+static stliport_t *stli_getport(int brdnr, int panelnr, int portnr)
+{
+	stlibrd_t	*brdp;
+	int		i;
+
+	if ((brdnr < 0) || (brdnr >= STL_MAXBRDS))
+		return((stliport_t *) NULL);
+	brdp = stli_brds[brdnr];
+	if (brdp == (stlibrd_t *) NULL)
+		return((stliport_t *) NULL);
+	for (i = 0; (i < panelnr); i++)
+		portnr += brdp->panels[i];
+	if ((portnr < 0) || (portnr >= brdp->nrports))
+		return((stliport_t *) NULL);
+	return(brdp->ports[portnr]);
+}
+
+/*****************************************************************************/
+
+/*
+ *	Return the port stats structure to user app. A NULL port struct
+ *	pointer passed in means that we need to find out from the app
+ *	what port to get stats for (used through board control device).
+ */
+
+static int stli_getportstats(stliport_t *portp, comstats_t *cp)
+{
+	stlibrd_t	*brdp;
+	int		rc;
+
+	if (portp == (stliport_t *) NULL) {
+		memcpy_fromfs(&stli_comstats, cp, sizeof(comstats_t));
+		portp = stli_getport(stli_comstats.brd, stli_comstats.panel, stli_comstats.port);
+		if (portp == (stliport_t *) NULL)
+			return(-ENODEV);
+	}
+
+	brdp = stli_brds[portp->brdnr];
+	if (brdp == (stlibrd_t *) NULL)
+		return(-ENODEV);
+
+	portp->stats.state = portp->state;
+	portp->stats.flags = portp->flags;
+	if (portp->tty != (struct tty_struct *) NULL) {
+		portp->stats.ttystate = portp->tty->flags;
+		portp->stats.cflags = portp->tty->termios->c_cflag;
+		portp->stats.iflags = portp->tty->termios->c_iflag;
+		portp->stats.oflags = portp->tty->termios->c_oflag;
+		portp->stats.lflags = portp->tty->termios->c_lflag;
+		portp->stats.rxbuffered = portp->tty->flip.count;
+	} else {
+		portp->stats.ttystate = 0;
+		portp->stats.cflags = 0;
+		portp->stats.iflags = 0;
+		portp->stats.oflags = 0;
+		portp->stats.lflags = 0;
+		portp->stats.rxbuffered = 0;
+	}
+
+	if ((rc = stli_cmdwait(brdp, portp, A_GETSTATS, &stli_cdkstats, sizeof(asystats_t), 1)) < 0)
+		return(rc);
+
+	portp->stats.txtotal = stli_cdkstats.txchars;
+	portp->stats.rxtotal = stli_cdkstats.rxchars + stli_cdkstats.ringover;
+	portp->stats.txbuffered = stli_cdkstats.txringq;
+	portp->stats.rxbuffered += stli_cdkstats.rxringq;
+	portp->stats.rxoverrun = stli_cdkstats.overruns;
+	portp->stats.rxparity = stli_cdkstats.parity;
+	portp->stats.rxframing = stli_cdkstats.framing;
+	portp->stats.rxlost = stli_cdkstats.ringover;
+	portp->stats.rxbreaks = stli_cdkstats.rxbreaks;
+	portp->stats.txbreaks = stli_cdkstats.txbreaks;
+	portp->stats.txxon = stli_cdkstats.txstart;
+	portp->stats.txxoff = stli_cdkstats.txstop;
+	portp->stats.rxxon = stli_cdkstats.rxstart;
+	portp->stats.rxxoff = stli_cdkstats.rxstop;
+	portp->stats.rxrtsoff = stli_cdkstats.rtscnt / 2;
+	portp->stats.rxrtson = stli_cdkstats.rtscnt - portp->stats.rxrtsoff;
+	portp->stats.modem = stli_cdkstats.dcdcnt;
+	portp->stats.hwid = stli_cdkstats.hwid;
+	portp->stats.signals = stli_mktiocm(stli_cdkstats.signals);
+
+	memcpy_tofs(cp, &portp->stats, sizeof(comstats_t));
+	return(0);
+}
+
+/*****************************************************************************/
+
+/*
+ *	Clear the port stats structure. We also return it zeroed out...
+ */
+
+static int stli_clrportstats(stliport_t *portp, comstats_t *cp)
+{
+	stlibrd_t	*brdp;
+	int		rc;
+
+	if (portp == (stliport_t *) NULL) {
+		memcpy_fromfs(&stli_comstats, cp, sizeof(comstats_t));
+		portp = stli_getport(stli_comstats.brd, stli_comstats.panel, stli_comstats.port);
+		if (portp == (stliport_t *) NULL)
+			return(-ENODEV);
+	}
+
+	brdp = stli_brds[portp->brdnr];
+	if (brdp == (stlibrd_t *) NULL)
+		return(-ENODEV);
+
+	memset(&portp->stats, 0, sizeof(comstats_t));
+	portp->stats.brd = portp->brdnr;
+	portp->stats.panel = portp->panelnr;
+	portp->stats.port = portp->portnr;
+
+	if ((rc = stli_cmdwait(brdp, portp, A_CLEARSTATS, 0, 0, 0)) < 0)
+		return(rc);
+
+	memcpy_tofs(cp, &portp->stats, sizeof(comstats_t));
+	return(0);
+}
+
+/*****************************************************************************/
+
+/*
  *	The "staliomem" device is also required to do some special operations on
  *	the board. We need to be able to send an interrupt to the board,
  *	reset it, and start/stop it.
@@ -4286,6 +4475,18 @@
 			if (brdp->reenable != NULL)
 				(* brdp->reenable)(brdp);
 		}
+		break;
+	case COM_GETPORTSTATS:
+		if ((rc = verify_area(VERIFY_WRITE, (void *) arg, sizeof(comstats_t))) == 0)
+			rc = stli_getportstats((stliport_t *) NULL, (comstats_t *) arg);
+		break;
+	case COM_CLRPORTSTATS:
+		if ((rc = verify_area(VERIFY_WRITE, (void *) arg, sizeof(comstats_t))) == 0)
+			rc = stli_clrportstats((stliport_t *) NULL, (comstats_t *) arg);
+		break;
+	case COM_GETBRDSTATS:
+		if ((rc = verify_area(VERIFY_WRITE, (void *) arg, sizeof(combrd_t))) == 0)
+			rc = stli_getbrdstats((combrd_t *) arg);
 		break;
 	default:
 		rc = -ENOIOCTLCMD;
diff -u --recursive --new-file v1.3.72/linux/drivers/char/stallion.c linux/drivers/char/stallion.c
--- v1.3.72/linux/drivers/char/stallion.c	Sat Mar  2 10:43:25 1996
+++ linux/drivers/char/stallion.c	Mon Mar 11 11:20:32 1996
@@ -37,6 +37,7 @@
 #include <linux/tty_flip.h>
 #include <linux/serial.h>
 #include <linux/cd1400.h>
+#include <linux/comstats.h>
 #include <linux/string.h>
 #include <linux/malloc.h>
 #include <linux/ioport.h>
@@ -110,6 +111,9 @@
  *	Define some important driver characteristics. Device major numbers
  *	allocated as per Linux Device Registery.
  */
+#ifndef	STL_SIOMEMMAJOR
+#define	STL_SIOMEMMAJOR		28
+#endif
 #ifndef	STL_SERIALMAJOR
 #define	STL_SERIALMAJOR		24
 #endif
@@ -141,7 +145,7 @@
  *	all the local structures required by a serial tty driver.
  */
 static char	*stl_drvname = "Stallion Multiport Serial Driver";
-static char	*stl_drvversion = "1.0.2";
+static char	*stl_drvversion = "1.0.6";
 static char	*stl_serialname = "ttyE";
 static char	*stl_calloutname = "cue";
 
@@ -177,6 +181,13 @@
 };
 
 /*
+ *	Define global stats structures. Not used often, and can be
+ *	re-used for each stats call.
+ */
+static comstats_t	stl_comstats;
+static combrd_t		stl_brdstats;
+
+/*
  *	Keep track of what interrupts we have requested for us.
  *	We don't need to request an interrupt twice if it is being
  *	shared with another Stallion board.
@@ -237,12 +248,15 @@
 	unsigned int		sigs;
 	unsigned int		rxignoremsk;
 	unsigned int		rxmarkmsk;
+	unsigned long		clk;
+	unsigned long		hwid;
 	struct tty_struct	*tty;
 	struct wait_queue	*open_wait;
 	struct wait_queue	*close_wait;
 	struct termios		normaltermios;
 	struct termios		callouttermios;
 	struct tq_struct	tqueue;
+	comstats_t		stats;
 	stlrq_t			tx;
 } stlport_t;
 
@@ -252,6 +266,7 @@
 	int		pagenr;
 	int		nrports;
 	int		iobase;
+	unsigned int	hwid;
 	unsigned int	ackmask;
 	stlport_t	*ports[STL_PORTSPERPANEL];
 } stlpanel_t;
@@ -269,6 +284,8 @@
 	unsigned int	iostatus;
 	unsigned int	ioctrl;
 	unsigned int	ioctrlval;
+	unsigned int	hwid;
+	unsigned long	clk;
 	stlpanel_t	*panels[STL_MAXPANELS];
 } stlbrd_t;
 
@@ -359,6 +376,10 @@
 #define	ECH_PNLINTRPEND	0x80
 #define	ECH_ADDR2MASK	0x1e0
 
+#define	EIO_CLK		25000000
+#define	EIO_CLK8M	20000000
+#define	ECH_CLK		EIO_CLK
+
 /*
  *	Define the offsets within the register bank for all io registers.
  *	These io address offsets are common to both the EIO and ECH.
@@ -467,6 +488,7 @@
 static void	stl_start(struct tty_struct *tty);
 static void	stl_flushbuffer(struct tty_struct *tty);
 static void	stl_hangup(struct tty_struct *tty);
+static int	stl_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, unsigned long arg);
 
 static int	stl_initbrds(void);
 static int	stl_brdinit(stlbrd_t *brdp);
@@ -476,11 +498,14 @@
 static int	stl_mapirq(int irq);
 static void	stl_getserial(stlport_t *portp, struct serial_struct *sp);
 static int	stl_setserial(stlport_t *portp, struct serial_struct *sp);
+static int	stl_getbrdstats(combrd_t *bp);
+static int	stl_getportstats(stlport_t *portp, comstats_t *cp);
+static int	stl_clrportstats(stlport_t *portp, comstats_t *cp);
 static void	stl_setreg(stlport_t *portp, int regnr, int value);
 static int	stl_getreg(stlport_t *portp, int regnr);
 static int	stl_updatereg(stlport_t *portp, int regnr, int value);
 static void	stl_setport(stlport_t *portp, struct termios *tiosp);
-static void	stl_getsignals(stlport_t *portp);
+static int	stl_getsignals(stlport_t *portp);
 static void	stl_setsignals(stlport_t *portp, int dtr, int rts);
 static void	stl_ccrwait(stlport_t *portp);
 static void	stl_enablerxtx(stlport_t *portp, int rx, int tx);
@@ -492,6 +517,7 @@
 static void	stl_intr(int irq, void *dev_id, struct pt_regs *regs);
 static void	stl_offintr(void *private);
 static void	*stl_memalloc(int len);
+static stlport_t *stl_getport(int brdnr, int panelnr, int portnr);
 
 #ifdef	CONFIG_PCI
 static int	stl_findpcibrds(void);
@@ -499,6 +525,25 @@
 
 /*****************************************************************************/
 
+/*
+ *	Define the driver info for a user level control device. Used mainly
+ *	to get at port stats - only ont using the port device itself.
+ */
+static struct file_operations	stl_fsiomem = {
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+	stl_memioctl,
+	NULL,
+	NULL,
+	NULL,
+	NULL
+};
+
+/*****************************************************************************/
+
 #ifdef MODULE
 
 /*
@@ -553,6 +598,8 @@
 		restore_flags(flags);
 		return;
 	}
+	if ((i = unregister_chrdev(STL_SIOMEMMAJOR, "staliomem")))
+		printk("STALLION: failed to un-register serial memory device, errno=%d\n", -i);
 
 	if (stl_tmpwritebuf != (char *) NULL)
 		kfree_s(stl_tmpwritebuf, STL_TXBUFSIZE);
@@ -666,7 +713,7 @@
 			portp->tx.tail = portp->tx.buf;
 		}
 		stl_setport(portp, tty->termios);
-		stl_getsignals(portp);
+		portp->sigs = stl_getsignals(portp);
 		stl_setsignals(portp, 1, 1);
 		stl_enablerxtx(portp, 1, 1);
 		stl_startrxtx(portp, 1, 0);
@@ -1160,6 +1207,7 @@
 static int stl_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg)
 {
 	stlport_t	*portp;
+	unsigned long	val;
 	int		rc;
 
 #if DEBUG
@@ -1200,8 +1248,8 @@
 		break;
 	case TIOCMGET:
 		if ((rc = verify_area(VERIFY_WRITE, (void *) arg, sizeof(unsigned int))) == 0) {
-			stl_getsignals(portp);
-			put_fs_long(portp->sigs, (unsigned long *) arg);
+			val = (unsigned long) stl_getsignals(portp);
+			put_fs_long(val, (unsigned long *) arg);
 		}
 		break;
 	case TIOCMBIS:
@@ -1230,6 +1278,14 @@
 		if ((rc = verify_area(VERIFY_READ, (void *) arg, sizeof(struct serial_struct))) == 0)
 			rc = stl_setserial(portp, (struct serial_struct *) arg);
 		break;
+	case COM_GETPORTSTATS:
+		if ((rc = verify_area(VERIFY_WRITE, (void *) arg, sizeof(comstats_t))) == 0)
+			rc = stl_getportstats(portp, (comstats_t *) arg);
+		break;
+	case COM_CLRPORTSTATS:
+		if ((rc = verify_area(VERIFY_WRITE, (void *) arg, sizeof(comstats_t))) == 0)
+			rc = stl_clrportstats(portp, (comstats_t *) arg);
+		break;
 	case TIOCSERCONFIG:
 	case TIOCSERGWILD:
 	case TIOCSERSWILD:
@@ -1305,11 +1361,13 @@
 	if (tty->termios->c_iflag & IXOFF) {
 		stl_ccrwait(portp);
 		stl_setreg(portp, CCR, CCR_SENDSCHR2);
+		portp->stats.rxxoff++;
 		stl_ccrwait(portp);
 	}
 	if (tty->termios->c_cflag & CRTSCTS) {
 		stl_setreg(portp, MCOR1, (stl_getreg(portp, MCOR1) & 0xf0));
 		stl_setreg(portp, MSVR2, 0);
+		portp->stats.rxrtsoff++;
 	}
 	BRDDISABLE(portp->brdnr);
 	restore_flags(flags);
@@ -1343,6 +1401,7 @@
 	if (tty->termios->c_iflag & IXOFF) {
 		stl_ccrwait(portp);
 		stl_setreg(portp, CCR, CCR_SENDSCHR1);
+		portp->stats.rxxon++;
 		stl_ccrwait(portp);
 	}
 /*
@@ -1354,6 +1413,7 @@
 	if (tty->termios->c_cflag & CRTSCTS) {
 		stl_setreg(portp, MCOR1, (stl_getreg(portp, MCOR1) | FIFO_RTSTHRESHOLD));
 		stl_setreg(portp, MSVR2, MSVR2_RTS);
+		portp->stats.rxrtson++;
 	}
 	BRDDISABLE(portp->brdnr);
 	restore_flags(flags);
@@ -1588,6 +1648,7 @@
 		outb(srer, (ioaddr + EREG_DATA));
 	} else {
 		len = MIN(len, CD1400_TXFIFOSIZE);
+		portp->stats.txtotal += len;
 		stlen = MIN(len, ((portp->tx.buf + STL_TXBUFSIZE) - tail));
 		outb((TDR + portp->uartaddr), ioaddr);
 		outsb((ioaddr + EREG_DATA), tail, stlen);
@@ -1647,6 +1708,8 @@
 				((buflen = TTY_FLIPBUF_SIZE - tty->flip.count) == 0)) {
 			outb((RDSR + portp->uartaddr), ioaddr);
 			insb((ioaddr + EREG_DATA), &unwanted[0], len);
+			portp->stats.rxlost += len;
+			portp->stats.rxtotal += len;
 		} else {
 			len = MIN(len, buflen);
 			if (len > 0) {
@@ -1657,12 +1720,28 @@
 				tty->flip.char_buf_ptr += len;
 				tty->flip.count += len;
 				tty_schedule_flip(tty);
+				portp->stats.rxtotal += len;
 			}
 		}
 	} else if ((ioack & ACK_TYPMASK) == ACK_TYPRXBAD) {
 		outb((RDSR + portp->uartaddr), ioaddr);
 		status = inb(ioaddr + EREG_DATA);
 		ch = inb(ioaddr + EREG_DATA);
+		if (status & ST_PARITY)
+			portp->stats.rxparity++;
+		if (status & ST_FRAMING)
+			portp->stats.rxframing++;
+		if (status & ST_OVERRUN)
+			portp->stats.rxoverrun++;
+		if (status & ST_BREAK)
+			portp->stats.rxbreaks++;
+		if (status & ST_SCHARMASK) {
+			if ((status & ST_SCHARMASK) == ST_SCHAR1)
+				portp->stats.txxon++;
+			if ((status & ST_SCHARMASK) == ST_SCHAR2)
+				portp->stats.txxoff++;
+			goto stl_rxalldone;
+		}
 		if ((tty != (struct tty_struct *) NULL) && ((portp->rxignoremsk & status) == 0)) {
 			if (portp->rxmarkmsk & status) {
 				if (status & ST_BREAK) {
@@ -1697,6 +1776,7 @@
 		return;
 	}
 
+stl_rxalldone:
 	outb((EOSRR + portp->uartaddr), ioaddr);
 	outb(0, (ioaddr + EREG_DATA));
 }
@@ -1731,6 +1811,7 @@
 	if (misr & MISR_DCD) {
 		set_bit(ASYI_DCDCHANGE, &portp->istate);
 		queue_task_irq_off(&portp->tqueue, &tq_scheduler);
+		portp->stats.modem++;
 	}
 
 	outb((EOSRR + portp->uartaddr), ioaddr);
@@ -1910,7 +1991,7 @@
 	if (test_bit(ASYI_DCDCHANGE, &portp->istate)) {
 		clear_bit(ASYI_DCDCHANGE, &portp->istate);
 		oldsigs = portp->sigs;
-		stl_getsignals(portp);
+		portp->sigs = stl_getsignals(portp);
 		if ((portp->sigs & TIOCM_CD) && ((oldsigs & TIOCM_CD) == 0))
 			wake_up_interruptible(&portp->open_wait);
 		if ((oldsigs & TIOCM_CD) && ((portp->sigs & TIOCM_CD) == 0)) {
@@ -2069,7 +2150,7 @@
 
 	if (baudrate > 0) {
 		for (clk = 0; (clk < CD1400_NUMCLKS); clk++) {
-			clkdiv = ((CD1400_CLKHZ / stl_cd1400clkdivs[clk]) / baudrate);
+			clkdiv = ((portp->clk / stl_cd1400clkdivs[clk]) / baudrate);
 			if (clkdiv < 0x100)
 				break;
 		}
@@ -2093,7 +2174,7 @@
  */
 	if (tiosp->c_iflag & IXON) {
 		cor2 |= COR2_TXIBE;
-		cor3 |= (COR3_FCT | COR3_SCD12);
+		cor3 |= COR3_SCD12;
 		if (tiosp->c_iflag & IXANY)
 			cor2 |= COR2_IXM;
 	}
@@ -2194,13 +2275,14 @@
 /*****************************************************************************/
 
 /*
- *	Get the state of the signals.
+ *	Return the state of the signals.
  */
 
-static void stl_getsignals(stlport_t *portp)
+static int stl_getsignals(stlport_t *portp)
 {
 	unsigned char	msvr1, msvr2;
 	unsigned long	flags;
+	int		sigs;
 
 #if DEBUG
 	printk("stl_getsignals(portp=%x)\n", (int) portp);
@@ -2213,14 +2295,15 @@
 	msvr1 = stl_getreg(portp, MSVR1);
 	msvr2 = stl_getreg(portp, MSVR2);
 	BRDDISABLE(portp->brdnr);
-	portp->sigs = 0;
-	portp->sigs |= (msvr1 & MSVR1_DCD) ? TIOCM_CD : 0;
-	portp->sigs |= (msvr1 & MSVR1_CTS) ? TIOCM_CTS : 0;
-	portp->sigs |= (msvr1 & MSVR1_RI) ? TIOCM_RI : 0;
-	portp->sigs |= (msvr1 & MSVR1_DSR) ? TIOCM_DSR : 0;
-	portp->sigs |= (msvr1 & MSVR1_DTR) ? TIOCM_DTR : 0;
-	portp->sigs |= (msvr2 & MSVR2_RTS) ? TIOCM_RTS : 0;
+	sigs = 0;
+	sigs |= (msvr1 & MSVR1_DCD) ? TIOCM_CD : 0;
+	sigs |= (msvr1 & MSVR1_CTS) ? TIOCM_CTS : 0;
+	sigs |= (msvr1 & MSVR1_RI) ? TIOCM_RI : 0;
+	sigs |= (msvr1 & MSVR1_DSR) ? TIOCM_DSR : 0;
+	sigs |= (msvr1 & MSVR1_DTR) ? TIOCM_DTR : 0;
+	sigs |= (msvr2 & MSVR2_RTS) ? TIOCM_RTS : 0;
 	restore_flags(flags);
+	return(sigs);
 }
 
 /*****************************************************************************/
@@ -2339,6 +2422,7 @@
 	BRDDISABLE(portp->brdnr);
 	len = len / 5;
 	portp->brklen = (len > 255) ? 255 : len;
+	portp->stats.txbreaks++;
 	restore_flags(flags);
 }
 
@@ -2455,6 +2539,7 @@
 		portp->ioaddr = ioaddr;
 		portp->uartaddr = (i & 0x04) << 5;
 		portp->pagenr = panelp->pagenr + (i >> 3);
+		portp->clk = brdp->clk;
 		portp->baud_base = STL_BAUDBASE;
 		portp->close_delay = STL_CLOSEDELAY;
 		portp->closing_wait = 30 * HZ;
@@ -2462,8 +2547,12 @@
 		portp->callouttermios = stl_deftermios;
 		portp->tqueue.routine = stl_offintr;
 		portp->tqueue.data = portp;
+		portp->stats.brd = portp->brdnr;
+		portp->stats.panel = portp->panelnr;
+		portp->stats.port = portp->portnr;
 		stl_setreg(portp, CAR, (i & 0x03));
 		stl_setreg(portp, LIVR, (i << 3));
+		portp->hwid = stl_getreg(portp, GFRCR);
 		panelp->ports[i] = portp;
 	}
 
@@ -2489,11 +2578,14 @@
 
 	brdp->ioctrl = brdp->ioaddr1 + 1;
 	brdp->iostatus = brdp->ioaddr1 + 2;
+	brdp->clk = EIO_CLK;
 
 	status = inb(brdp->iostatus);
 	switch (status & EIO_IDBITMASK) {
-	case EIO_8PORTRS:
 	case EIO_8PORTM:
+		brdp->clk = EIO_CLK8M;
+		/* fall thru */
+	case EIO_8PORTRS:
 	case EIO_8PORTDI:
 		brdp->nrports = 8;
 		break;
@@ -2529,9 +2621,11 @@
 	panelp->panelnr = 0;
 	panelp->nrports = brdp->nrports;
 	panelp->iobase = brdp->ioaddr1;
+	panelp->hwid = status;
 	brdp->panels[0] = panelp;
 	brdp->nrpanels = 1;
 	brdp->state |= BRD_FOUND;
+	brdp->hwid = status;
 	rc = stl_mapirq(brdp->irq);
 	return(rc);
 }
@@ -2553,6 +2647,8 @@
 	printk("stl_initech(brdp=%x)\n", (int) brdp);
 #endif
 
+	status = 0;
+
 /*
  *	Set up the initial board register contents for boards. This varys a
  *	bit between the different board types. So we need to handle each
@@ -2601,6 +2697,9 @@
 		request_region(brdp->ioaddr2, 8, "serial(EC8/32-PCI-secondary)");
 	}
 
+	brdp->clk = ECH_CLK;
+	brdp->hwid = status;
+
 /*
  *	Scan through the secondary io address space looking for panels.
  *	As we find'em allocate and initialize panel structures for each.
@@ -2627,6 +2726,7 @@
 		panelp->panelnr = panelnr;
 		panelp->iobase = ioaddr;
 		panelp->pagenr = nxtid;
+		panelp->hwid = status;
 		if (status & ECH_PNL16PORT) {
 			if ((brdp->nrports + 16) > 32)
 				break;
@@ -2845,6 +2945,190 @@
 
 /*****************************************************************************/
 
+/*
+ *	Return the board stats structure to user app.
+ */
+
+static int stl_getbrdstats(combrd_t *bp)
+{
+	stlbrd_t	*brdp;
+	stlpanel_t	*panelp;
+	int		i;
+
+	memcpy_fromfs(&stl_brdstats, bp, sizeof(combrd_t));
+	if (stl_brdstats.brd >= STL_MAXBRDS)
+		return(-ENODEV);
+	brdp = stl_brds[stl_brdstats.brd];
+	if (brdp == (stlbrd_t *) NULL)
+		return(-ENODEV);
+
+	memset(&stl_brdstats, 0, sizeof(combrd_t));
+	stl_brdstats.brd = brdp->brdnr;
+	stl_brdstats.type = brdp->brdtype;
+	stl_brdstats.hwid = brdp->hwid;
+	stl_brdstats.state = brdp->state;
+	stl_brdstats.ioaddr = brdp->ioaddr1;
+	stl_brdstats.ioaddr2 = brdp->ioaddr2;
+	stl_brdstats.irq = brdp->irq;
+	stl_brdstats.nrpanels = brdp->nrpanels;
+	stl_brdstats.nrports = brdp->nrports;
+	for (i = 0; (i < brdp->nrpanels); i++) {
+		panelp = brdp->panels[i];
+		stl_brdstats.panels[i].panel = i;
+		stl_brdstats.panels[i].hwid = panelp->hwid;
+		stl_brdstats.panels[i].nrports = panelp->nrports;
+	}
+
+	memcpy_tofs(bp, &stl_brdstats, sizeof(combrd_t));
+	return(0);
+}
+
+/*****************************************************************************/
+
+/*
+ *	Resolve the referenced port number into a port struct pointer.
+ */
+
+static stlport_t *stl_getport(int brdnr, int panelnr, int portnr)
+{
+	stlbrd_t	*brdp;
+	stlpanel_t	*panelp;
+
+	if ((brdnr < 0) || (brdnr >= STL_MAXBRDS))
+		return((stlport_t *) NULL);
+	brdp = stl_brds[brdnr];
+	if (brdp == (stlbrd_t *) NULL)
+		return((stlport_t *) NULL);
+	if ((panelnr < 0) || (panelnr >= brdp->nrpanels))
+		return((stlport_t *) NULL);
+	panelp = brdp->panels[panelnr];
+	if (panelp == (stlpanel_t *) NULL)
+		return((stlport_t *) NULL);
+	if ((portnr < 0) || (portnr >= panelp->nrports))
+		return((stlport_t *) NULL);
+	return(panelp->ports[portnr]);
+}
+
+/*****************************************************************************/
+
+/*
+ *	Return the port stats structure to user app. A NULL port struct
+ *	pointer passed in means that we need to find out from the app
+ *	what port to get stats for (used through board control device).
+ */
+
+static int stl_getportstats(stlport_t *portp, comstats_t *cp)
+{
+	unsigned char	*head, *tail;
+
+	if (portp == (stlport_t *) NULL) {
+		memcpy_fromfs(&stl_comstats, cp, sizeof(comstats_t));
+		portp = stl_getport(stl_comstats.brd, stl_comstats.panel, stl_comstats.port);
+		if (portp == (stlport_t *) NULL)
+			return(-ENODEV);
+	}
+
+	portp->stats.state = portp->istate;
+	portp->stats.flags = portp->flags;
+	portp->stats.hwid = portp->hwid;
+	if (portp->tty != (struct tty_struct *) NULL) {
+		portp->stats.ttystate = portp->tty->flags;
+		portp->stats.cflags = portp->tty->termios->c_cflag;
+		portp->stats.iflags = portp->tty->termios->c_iflag;
+		portp->stats.oflags = portp->tty->termios->c_oflag;
+		portp->stats.lflags = portp->tty->termios->c_lflag;
+		portp->stats.rxbuffered = portp->tty->flip.count;
+	} else {
+		portp->stats.ttystate = 0;
+		portp->stats.cflags = 0;
+		portp->stats.iflags = 0;
+		portp->stats.oflags = 0;
+		portp->stats.lflags = 0;
+		portp->stats.rxbuffered = 0;
+	}
+
+	head = portp->tx.head;
+	tail = portp->tx.tail;
+	portp->stats.txbuffered = ((head >= tail) ? (head - tail) : (STL_TXBUFSIZE - (tail - head)));
+
+	portp->stats.signals = (unsigned long) stl_getsignals(portp);
+
+	memcpy_tofs(cp, &portp->stats, sizeof(comstats_t));
+	return(0);
+}
+
+/*****************************************************************************/
+
+/*
+ *	Clear the port stats structure. We also return it zeroed out...
+ */
+
+static int stl_clrportstats(stlport_t *portp, comstats_t *cp)
+{
+	if (portp == (stlport_t *) NULL) {
+		memcpy_fromfs(&stl_comstats, cp, sizeof(comstats_t));
+		portp = stl_getport(stl_comstats.brd, stl_comstats.panel, stl_comstats.port);
+		if (portp == (stlport_t *) NULL)
+			return(-ENODEV);
+	}
+
+	memset(&portp->stats, 0, sizeof(comstats_t));
+	portp->stats.brd = portp->brdnr;
+	portp->stats.panel = portp->panelnr;
+	portp->stats.port = portp->portnr;
+	memcpy_tofs(cp, &portp->stats, sizeof(comstats_t));
+	return(0);
+}
+
+/*****************************************************************************/
+
+/*
+ *	The "staliomem" device is also required to do some special operations
+ *	on the board and/or ports. In this driver it is mostly used for stats
+ *	collection.
+ */
+
+static int stl_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, unsigned long arg)
+{
+	stlbrd_t	*brdp;
+	int		brdnr, rc;
+
+#if DEBUG
+	printk("stl_memioctl(ip=%x,fp=%x,cmd=%x,arg=%x)\n", (int) ip, (int) fp, cmd, (int) arg);
+#endif
+
+	brdnr = MINOR(ip->i_rdev);
+	if (brdnr >= stl_nrbrds)
+		return(-ENODEV);
+	brdp = stl_brds[brdnr];
+	if (brdp == (stlbrd_t *) NULL)
+		return(-ENODEV);
+
+	rc = 0;
+
+	switch (cmd) {
+	case COM_GETPORTSTATS:
+		if ((rc = verify_area(VERIFY_WRITE, (void *) arg, sizeof(comstats_t))) == 0)
+			rc = stl_getportstats((stlport_t *) NULL, (comstats_t *) arg);
+		break;
+	case COM_CLRPORTSTATS:
+		if ((rc = verify_area(VERIFY_WRITE, (void *) arg, sizeof(comstats_t))) == 0)
+			rc = stl_clrportstats((stlport_t *) NULL, (comstats_t *) arg);
+		break;
+	case COM_GETBRDSTATS:
+		if ((rc = verify_area(VERIFY_WRITE, (void *) arg, sizeof(combrd_t))) == 0)
+			rc = stl_getbrdstats((combrd_t *) arg);
+		break;
+	default:
+		rc = -ENOIOCTLCMD;
+		break;
+	}
+
+	return(rc);
+}
+
+/*****************************************************************************/
+
 int stl_init(void)
 {
 	printk("%s: version %s\n", stl_drvname, stl_drvversion);
@@ -2857,6 +3141,13 @@
 	stl_tmpwritebuf = (char *) stl_memalloc(STL_TXBUFSIZE);
 	if (stl_tmpwritebuf == (char *) NULL)
 		printk("STALLION: failed to allocate memory (size=%d)\n", STL_TXBUFSIZE);
+
+/*
+ *	Set up a character driver for per board stuff. This is mainly used
+ *	to do stats ioctls on the ports.
+ */
+	if (register_chrdev(STL_SIOMEMMAJOR, "staliomem", &stl_fsiomem))
+		printk("STALLION: failed to register serial board device\n");
 
 /*
  *	Set up the tty driver structure and register us as a driver.
diff -u --recursive --new-file v1.3.72/linux/drivers/net/3c503.c linux/drivers/net/3c503.c
--- v1.3.72/linux/drivers/net/3c503.c	Tue Mar  5 10:10:57 1996
+++ linux/drivers/net/3c503.c	Sun Mar 10 08:54:05 1996
@@ -456,9 +456,9 @@
  *  Set up then start the internal memory transfer to Tx Start Page
  */
 
-    tmp_rev = htons((unsigned short)start_page);
-    outb(tmp_rev&0xFF, E33G_DMAAH);
-    outb(tmp_rev>>8, E33G_DMAAL);
+    tmp_rev = (unsigned short)start_page;
+    outb(tmp_rev&0xFF, E33G_DMAAL);
+    outb(tmp_rev>>8, E33G_DMAAH);
 
     outb_p((ei_status.interface_num ? ECNTRL_AUI : ECNTRL_THIN ) | ECNTRL_OUTPUT
 	   | ECNTRL_START, E33G_CNTRL);
@@ -519,9 +519,9 @@
  *  No shared memory, use programmed I/O.
  */
 
-    tmp_rev = htons((unsigned short)ring_page);
-    outb(tmp_rev&0xFF, E33G_DMAAH);
-    outb(tmp_rev>>8, E33G_DMAAL);
+    tmp_rev = (unsigned short)ring_page;
+    outb(tmp_rev&0xFF, E33G_DMAAL);
+    outb(tmp_rev>>8, E33G_DMAAH);
 
     outb_p((ei_status.interface_num == 0 ? ECNTRL_THIN : ECNTRL_AUI) | ECNTRL_INPUT
 	   | ECNTRL_START, E33G_CNTRL);
@@ -570,7 +570,7 @@
 /*
  *  No shared memory, use programmed I/O.
  */
-    tmp_rev = htons((unsigned short) ring_offset);
+    tmp_rev = (unsigned short) ring_offset;
     outb(tmp_rev&0xFF, E33G_DMAAL);
     outb(tmp_rev>>8, E33G_DMAAH);
 
diff -u --recursive --new-file v1.3.72/linux/drivers/net/3c509.c linux/drivers/net/3c509.c
--- v1.3.72/linux/drivers/net/3c509.c	Sat Mar  2 10:43:30 1996
+++ linux/drivers/net/3c509.c	Sun Mar 10 09:44:17 1996
@@ -94,8 +94,17 @@
 #define WN4_MEDIA	0x0A		/* Window 4: Various transcvr/media bits. */
 #define  MEDIA_TP	0x00C0		/* Enable link beat and jabber for 10baseT. */
 
+/*
+ * Must be a power of two (we use a binary and in the
+ * circular queue)
+ */
+#define SKB_QUEUE_SIZE	64
+
 struct el3_private {
 	struct enet_statistics stats;
+	/* skb send-queue */
+	int head, size;
+	struct sk_buff *queue[SKB_QUEUE_SIZE];
 };
 
 static ushort id_read_eeprom(int index);
@@ -378,75 +387,40 @@
 	return 0;					/* Always succeed */
 }
 
-static int
-el3_start_xmit(struct sk_buff *skb, struct device *dev)
+static void
+el3_tx(struct device *dev)
 {
 	struct el3_private *lp = (struct el3_private *)dev->priv;
 	int ioaddr = dev->base_addr;
+	struct sk_buff * skb;
 
-	/* Transmitter timeout, serious problems. */
-	if (dev->tbusy) {
-		int tickssofar = jiffies - dev->trans_start;
-		if (tickssofar < 10)
-			return 1;
-		printk("%s: transmit timed out, tx_status %2.2x status %4.4x.\n",
-			   dev->name, inb(ioaddr + TX_STATUS), inw(ioaddr + EL3_STATUS));
-		dev->trans_start = jiffies;
-		/* Issue TX_RESET and TX_START commands. */
-		outw(TxReset, ioaddr + EL3_CMD);
-		outw(TxEnable, ioaddr + EL3_CMD);
-		dev->tbusy = 0;
-	}
+	if (el3_debug > 5)
+		printk("	TX room bit was handled.\n");
 
-	if (skb == NULL) {
-		dev_tint(dev);
-		return 0;
-	}
-
-	if (skb->len <= 0)
-		return 0;
+	outw(AckIntr | 0x08, ioaddr + EL3_CMD);
+	if (!lp->size)
+		return;
 
-	if (el3_debug > 4) {
-		printk("%s: el3_start_xmit(length = %ld) called, status %4.4x.\n",
-			   dev->name, skb->len, inw(ioaddr + EL3_STATUS));
-	}
-#ifndef final_version
-	{	/* Error-checking code, delete for 1.30. */
-		ushort status = inw(ioaddr + EL3_STATUS);
-		if (status & 0x0001 		/* IRQ line active, missed one. */
-			&& inw(ioaddr + EL3_STATUS) & 1) { 			/* Make sure. */
-			printk("%s: Missed interrupt, status then %04x now %04x"
-				   "  Tx %2.2x Rx %4.4x.\n", dev->name, status,
-				   inw(ioaddr + EL3_STATUS), inb(ioaddr + TX_STATUS),
-				   inw(ioaddr + RX_STATUS));
-			/* Fake interrupt trigger by masking, acknowledge interrupts. */
-			outw(SetReadZero | 0x00, ioaddr + EL3_CMD);
-			outw(AckIntr | 0x69, ioaddr + EL3_CMD); /* Ack IRQ */
-			outw(SetReadZero | 0xff, ioaddr + EL3_CMD);
-		}
-	}
-#endif
+	/* There's room in the FIFO for a full-sized packet. */
+	while (inw(ioaddr + TX_FREE) > 1536) {
+		skb = lp->queue[lp->head];
+		lp->head = (lp->head + 1) & (SKB_QUEUE_SIZE-1);
+		lp->size--;
 
-	/* Avoid timer-based retransmission conflicts. */
-	if (set_bit(0, (void*)&dev->tbusy) != 0)
-		printk("%s: Transmitter access conflict.\n", dev->name);
-	else {
 		/* Put out the doubleword header... */
 		outw(skb->len, ioaddr + TX_FIFO);
 		outw(0x00, ioaddr + TX_FIFO);
 		/* ... and the packet rounded to a doubleword. */
 		outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2);
 
+		/* free the skb, we're done with it */
+		dev_kfree_skb(skb, FREE_WRITE);
 		dev->trans_start = jiffies;
-		if (inw(ioaddr + TX_FREE) > 1536) {
-			dev->tbusy = 0;
-		} else
-			/* Interrupt us when the FIFO has room for max-sized packet. */
-			outw(SetTxThreshold + 1536, ioaddr + EL3_CMD);
+		if (!lp->size)
+			return;
 	}
-
-	dev_kfree_skb (skb, FREE_WRITE);
-
+	/* Interrupt us when the FIFO has room for max-sized packet. */
+	outw(SetTxThreshold + 1536, ioaddr + EL3_CMD);
 	/* Clear the Tx status stack. */
 	{
 		short tx_status;
@@ -459,6 +433,44 @@
 			outb(0x00, ioaddr + TX_STATUS); /* Pop the status stack. */
 		}
 	}
+}
+
+static int
+el3_start_xmit(struct sk_buff *skb, struct device *dev)
+{
+	struct el3_private *lp = (struct el3_private *)dev->priv;
+	unsigned long flags;
+	int ioaddr = dev->base_addr;
+
+	save_flags(flags);
+	cli();
+	/*
+	 * Do we have room in the send queue?
+	 */
+	if (lp->size < SKB_QUEUE_SIZE) {
+		int tail = (lp->head + lp->size) & (SKB_QUEUE_SIZE-1);
+		lp->queue[tail] = skb;
+		lp->size++;
+		/* fake a transmit interrupt to get it started */
+		el3_tx(dev);
+		restore_flags(flags);
+		return 0;
+	}
+
+	/*
+	 * No space, check if we might have timed out?
+	 */
+	if (jiffies - dev->trans_start > HZ) {
+		printk("%s: transmit timed out, tx_status %2.2x status %4.4x.\n",
+			   dev->name, inb(ioaddr + TX_STATUS), inw(ioaddr + EL3_STATUS));
+		dev->trans_start = jiffies;
+		/* Issue TX_RESET and TX_START commands. */
+		outw(TxReset, ioaddr + EL3_CMD);
+		outw(TxEnable, ioaddr + EL3_CMD);
+	}
+	/* free the skb, we might as well drop it on the floor */
+	dev_kfree_skb(skb, FREE_WRITE);
+	restore_flags(flags);
 	return 0;
 }
 
@@ -490,14 +502,9 @@
 		if (status & 0x10)
 			el3_rx(dev);
 
-		if (status & 0x08) {
-			if (el3_debug > 5)
-				printk("	TX room bit was handled.\n");
-			/* There's room in the FIFO for a full-sized packet. */
-			outw(AckIntr | 0x08, ioaddr + EL3_CMD);
-			dev->tbusy = 0;
-			mark_bh(NET_BH);
-		}
+		if (status & 0x08)
+			el3_tx(dev);
+
 		if (status & 0x80)				/* Statistics full. */
 			update_stats(ioaddr, dev);
 
diff -u --recursive --new-file v1.3.72/linux/drivers/net/Makefile linux/drivers/net/Makefile
--- v1.3.72/linux/drivers/net/Makefile	Sun Mar 10 09:49:49 1996
+++ linux/drivers/net/Makefile	Sun Mar 10 09:28:55 1996
@@ -464,4 +464,7 @@
 de620.o: de620.c CONFIG
 	$(CC) $(CPPFLAGS) $(CFLAGS) $(DE620_OPTS) -c $<
 
+lance.o: lance.c CONFIG
+	$(CC) $(CPPFLAGS) $(CFLAGS) $(LANCE_OPTS) -c $<
+
 8390.o: 8390.c 8390.h CONFIG
diff -u --recursive --new-file v1.3.72/linux/drivers/net/Space.c linux/drivers/net/Space.c
--- v1.3.72/linux/drivers/net/Space.c	Sun Mar 10 09:49:49 1996
+++ linux/drivers/net/Space.c	Mon Mar 11 11:10:41 1996
@@ -69,7 +69,7 @@
 extern int SK_init(struct device *);
 extern int seeq8005_probe(struct device *);
 extern int tc59x_probe(struct device *);
-extern int smc9_init( struct device * );
+extern int smc_init( struct device * );
 
 /* Detachable devices ("pocket adaptors") */
 extern int atp_init(struct device *);
@@ -98,7 +98,7 @@
 	&& ultra_probe(dev)
 #endif
 #if defined(CONFIG_SMC9194)
-	&& smc9_init(dev)
+	&& smc_init(dev)
 #endif
 #if defined(CONFIG_WD80x3) || defined(WD80x3)
 	&& wd_probe(dev)
diff -u --recursive --new-file v1.3.72/linux/drivers/net/eexpress.c linux/drivers/net/eexpress.c
--- v1.3.72/linux/drivers/net/eexpress.c	Tue Mar  5 10:10:58 1996
+++ linux/drivers/net/eexpress.c	Sun Mar 10 09:28:55 1996
@@ -5,6 +5,10 @@
  * Modularized by Pauline Middelink <middelin@polyware.iaf.nl>
  * Changed to support io= irq= by Alan Cox <Alan.Cox@linux.org>
  * Reworked 1995 by John Sullivan <js10039@cam.ac.uk>
+ *
+ *  06mar96 Philip Blundell <pjb27@cam.ac.uk>
+ *     - move started, buffer sizes, and so on into private data area.
+ *     - fix module loading for multiple cards
  * 
  *  31jan96 Philip Blundell <pjb27@cam.ac.uk>
  *     - Tidy up
@@ -17,7 +21,6 @@
  *     - look at RAM size check
  *
  * ToDo:
- *   Move private globals into net_local structure
  *   Multicast/Promiscuous mode handling
  *   Put back debug reporting?
  *   More documentation
@@ -149,6 +152,9 @@
 
 #include "eth82586.h"
 
+#define PRIV(x)         ((struct net_local *)(x)->priv)
+#define EEXP_IO_EXTENT  16
+
 /*
  * Private data declarations
  */
@@ -164,6 +170,11 @@
 	unsigned short tx_tail;         /* previous tx buf to tx_head */
 	unsigned short tx_link;         /* last known-executing tx buf */
 	unsigned short last_tx_restart; /* set to tx_link when we restart the CU */
+	unsigned char started;
+	unsigned short rx_buf_start;
+	unsigned short rx_buf_end;
+	unsigned short num_tx_bufs;
+	unsigned short num_rx_bufs;
 };
 
 unsigned short start_code[] = {
@@ -208,8 +219,6 @@
 /* maps irq number to EtherExpress magic value */
 static char irqrmap[] = { 0,0,1,2,3,4,0,0,0,1,5,6,0,0,0,0 };
 
-static unsigned char started=0;
-
 /*
  * Prototypes for Linux interface
  */
@@ -294,10 +303,10 @@
 	if (irq2dev_map[irq] ||
 	      /* more consistent, surely? */
 	   ((irq2dev_map[irq]=dev),0) ||
-	     request_irq(irq,&eexp_irq,0,"EExpress",NULL)) 
+	     request_irq(irq,&eexp_irq,0,"eexpress",NULL)) 
 		return -EAGAIN;
 
-	request_region(ioaddr,16,"EExpress");
+	request_region(ioaddr, EEXP_IO_EXTENT, "eexpress");
 	dev->tbusy = 0;
 	dev->interrupt = 0;
 	eexp_hw_init586(dev);
@@ -318,7 +327,7 @@
 	dev->start = 0;
   
 	outb(SIRQ_dis|irqrmap[irq],ioaddr+SET_IRQ);
-	started = 0;
+	PRIV(dev)->started = 0;
 	outw(SCB_CUsuspend|SCB_RUsuspend,ioaddr+SCB_CMD);
 	outb(0,ioaddr+SIGNAL_CA);
 	free_irq(irq,NULL);
@@ -366,7 +375,7 @@
 		 * tbusy==0. If it happens too much, we probably ought
 		 * to think about unwedging ourselves...
 		 */
-		if (test_bit(0,(void *)&started)) 
+		if (test_bit(0,(void *)&PRIV(dev)->started)) 
 		{
 			if ((jiffies - dev->trans_start)>5) 
 			{
@@ -506,16 +515,16 @@
 	status = inw(ioaddr+SCB_STATUS);
 	ack_cmd = SCB_ack(status);
 
-	if (started==0 && SCB_complete(status)) 
+	if (PRIV(dev)->started==0 && SCB_complete(status)) 
 	{
 		if (SCB_CUstat(status)==2) 
 			while (SCB_CUstat(inw(ioaddr+SCB_STATUS))==2);
-		started=1;
+		PRIV(dev)->started=1;
 		outw(lp->tx_link,ioaddr+SCB_CBL);
-		outw(RX_BUF_START,ioaddr+SCB_RFA);
+		outw(PRIV(dev)->rx_buf_start,ioaddr+SCB_RFA);
 		ack_cmd |= SCB_CUstart | SCB_RUstart;
 	}
-	else if (started) 
+	else if (PRIV(dev)->started) 
 	{
 		unsigned short txstatus;
 		txstatus = eexp_hw_lasttxstat(dev);
@@ -526,17 +535,17 @@
 		eexp_hw_rx(dev);
 	}
 
-	if ((started&2)!=0 && SCB_RUstat(status)!=4) 
+	if ((PRIV(dev)->started&2)!=0 && SCB_RUstat(status)!=4) 
 	{
 		printk("%s: RU stopped status %04x, restarting...\n",
 			dev->name,status);
 		lp->stats.rx_errors++;
 		eexp_hw_rxinit(dev);
-		outw(RX_BUF_START,ioaddr+SCB_RFA);
+		outw(PRIV(dev)->rx_buf_start,ioaddr+SCB_RFA);
 		ack_cmd |= SCB_RUstart;
 	} 
-	else if (started==1 && SCB_RUstat(status)==4) 
-		started|=2;
+	else if (PRIV(dev)->started==1 && SCB_RUstat(status)==4) 
+		PRIV(dev)->started|=2;
 
 	outw(ack_cmd,ioaddr+SCB_CMD);
 	outb(0,ioaddr+SIGNAL_CA);
@@ -563,7 +572,7 @@
 	unsigned short old_wp = inw(ioaddr+WRITE_PTR);
 	unsigned short old_rp = inw(ioaddr+READ_PTR);
 	unsigned short rx_block = lp->rx_first;
-	unsigned short boguscount = NUM_RX_BUFS;
+	unsigned short boguscount = lp->num_rx_bufs;
 
 #if NET_DEBUG > 6
 	printk("%s: eexp_hw_rx()\n", dev->name);
@@ -665,7 +674,7 @@
 	outw(lp->tx_head,ioaddr);
 	dev->trans_start = jiffies;
 	lp->tx_tail = lp->tx_head;
-	if (lp->tx_head==TX_BUF_START+((NUM_TX_BUFS-1)*TX_BUF_SIZE)) 
+	if (lp->tx_head==TX_BUF_START+((lp->num_tx_bufs-1)*TX_BUF_SIZE)) 
 		lp->tx_head = TX_BUF_START;
 	else 
 		lp->tx_head += TX_BUF_SIZE;
@@ -723,6 +732,9 @@
 
 	eexp_hw_ASICrst(dev);
 
+	dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL);
+	memset(dev->priv, 0, sizeof(struct net_local));
+
 	{
 		unsigned short i586mso = 0x023e;
 		unsigned short old_wp,old_rp,old_a0,old_a1;
@@ -753,14 +765,15 @@
 			(a1_0 != 0x5a5a) || (a0_0 != 0x55aa)) 
 		{
 			printk("32k\n");
-			RX_BUF_END = 0x7ff6;
+			PRIV(dev)->rx_buf_end = 0x7ff6;
+			PRIV(dev)->num_tx_bufs = 4;
 		}
 		else
 		{
 			printk("64k\n");
-			NUM_TX_BUFS = 8;
-			RX_BUF_START = TX_BUF_START + (NUM_TX_BUFS*TX_BUF_SIZE);
-			RX_BUF_END = 0xfff6;
+			PRIV(dev)->num_tx_bufs = 8;
+			PRIV(dev)->rx_buf_start = TX_BUF_START + (PRIV(dev)->num_tx_bufs*TX_BUF_SIZE);
+			PRIV(dev)->rx_buf_end = 0xfff6;
 		}
 
 		outw(0x8000+i586mso,ioaddr+WRITE_PTR);
@@ -773,9 +786,6 @@
   
 	if (net_debug) 
 		printk(version);
-
-	dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL);
-	memset(dev->priv, 0, sizeof(struct net_local));
 	dev->open = eexp_open;
 	dev->stop = eexp_close;
 	dev->hard_start_xmit = eexp_xmit;
@@ -875,7 +885,7 @@
 			else
 				lp->stats.tx_packets++;
 		}
-		if (tx_block == TX_BUF_START+((NUM_TX_BUFS-1)*TX_BUF_SIZE)) 
+		if (tx_block == TX_BUF_START+((lp->num_tx_bufs-1)*TX_BUF_SIZE)) 
 			lp->tx_reap = tx_block = TX_BUF_START;
 		else
 			lp->tx_reap = tx_block += TX_BUF_SIZE;
@@ -959,7 +969,7 @@
 	unsigned short tx_block = TX_BUF_START;
 	unsigned short curtbuf;
 
-	for ( curtbuf=0 ; curtbuf<NUM_TX_BUFS ; curtbuf++ ) 
+	for ( curtbuf=0 ; curtbuf<lp->num_tx_bufs ; curtbuf++ ) 
 	{
 		outw(tx_block,ioaddr+WRITE_PTR);
 		outw(0x0000,ioaddr);
@@ -979,7 +989,7 @@
 	lp->tx_reap = TX_BUF_START;
 	lp->tx_tail = tx_block - TX_BUF_SIZE;
 	lp->tx_link = lp->tx_tail + 0x08;
-	RX_BUF_START = tx_block;
+	lp->rx_buf_start = tx_block;
 	outw(old_wp,ioaddr+WRITE_PTR);
 }
 
@@ -1004,13 +1014,13 @@
 	struct net_local *lp = (struct net_local *)dev->priv;
 	unsigned short ioaddr = dev->base_addr;
 	unsigned short old_wp = inw(ioaddr+WRITE_PTR);
-	unsigned short rx_block = RX_BUF_START;
+	unsigned short rx_block = lp->rx_buf_start;
 
-	NUM_RX_BUFS = 0;
+	lp->num_rx_bufs = 0;
 	lp->rx_first = rx_block;
 	do 
 	{
-		NUM_RX_BUFS++;
+		lp->num_rx_bufs++;
 		outw(rx_block,ioaddr+WRITE_PTR);
 		outw(0x0000,ioaddr);
 		outw(0x0000,ioaddr);
@@ -1024,7 +1034,7 @@
 		outw(0x8000|(RX_BUF_SIZE-0x20),ioaddr);
 		lp->rx_last = rx_block;
 		rx_block += RX_BUF_SIZE;
-	} while (rx_block <= RX_BUF_END-RX_BUF_SIZE);
+	} while (rx_block <= lp->rx_buf_end-RX_BUF_SIZE);
 
 	outw(lp->rx_last+4,ioaddr+WRITE_PTR);
 	outw(lp->rx_first,ioaddr);
@@ -1072,7 +1082,7 @@
 	struct net_local *lp = (struct net_local *)dev->priv;
 	unsigned short ioaddr = dev->base_addr;
 
-	started = 0;
+	PRIV(dev)->started = 0;
 	set_loopback;
 
 	outb(SIRQ_dis|irqrmap[dev->irq],ioaddr+SET_IRQ);
@@ -1082,11 +1092,11 @@
 		unsigned short wcnt;
 		wcnt = 0;
 		outw(0,ioaddr+WRITE_PTR);
-		while ((wcnt+=2) != RX_BUF_END+12) 
+		while ((wcnt+=2) != lp->rx_buf_end+12) 
 			outw(0,ioaddr);
 	} 
   
-	outw(RX_BUF_END,ioaddr+WRITE_PTR);
+	outw(lp->rx_buf_end,ioaddr+WRITE_PTR);
 	outsw(ioaddr, start_code, sizeof(start_code)>>1);
 	outw(CONF_HW_ADDR,ioaddr+WRITE_PTR);
 	outsw(ioaddr,dev->dev_addr,3);
@@ -1150,7 +1160,7 @@
 	outb(SIRQ_en|irqrmap[dev->irq],ioaddr+SET_IRQ);
 	clear_loopback;
 	lp->init_time = jiffies;
-	if (started) 
+	if (PRIV(dev)->started) 
 		printk("%s: Uh? We haven't started yet\n",dev->name);
 	return;
 }
@@ -1170,8 +1180,8 @@
 
 	set_loopback;  /* yet more paranoia - since we're resetting the ASIC
 			* that controls this function, how can it possibly work?
-                        */
-	started = 0;
+			*/
+	PRIV(dev)->started = 0;
 	outb(ASIC_RST|i586_RST,ioaddr+EEPROM_Ctrl);
 	while (succount<20) 
 	{
@@ -1201,30 +1211,61 @@
 /*
  * MODULE stuff
  */
-
 #ifdef MODULE
 
-static struct device dev_eexpress = 
+#define EEXP_MAX_CARDS     4    /* max number of cards to support */
+#define NAMELEN            8    /* max length of dev->name (inc null) */
+
+static char namelist[NAMELEN * EEXP_MAX_CARDS] = { 0, };
+
+static struct device dev_eexp[EEXP_MAX_CARDS] = 
 {
-	"EExpress", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, express_probe 
+        NULL,         /* will allocate dynamically */
+	0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, express_probe 
 };
 
-int irq = 0;
-int io = 0;
+int irq[MAX_EEXP_CARDS] = {0, };
+int io[MAX_EEXP_CARDS] = {0, };
 
+/* Ideally the user would give us io=, irq= for every card.  If any parameters
+ * are specified, we verify and then use them.  If no parameters are given, we
+ * autoprobe for one card only.
+ */
 int init_module(void)
 {
-	dev_eexpress.base_addr = io;
-	dev_eexpress.irq = irq;
-	if (register_netdev(&dev_eexpress) != 0) 
-		return -EIO;
+	int this_dev, found = 0;
+
+	for (this_dev = 0; this_dev < EEXP_MAX_CARDS; this_dev++) {
+		struct device *dev = &dev_eexp[this_dev];
+		dev->name = namelist + (NAMELEN*this_dev);
+		dev->irq = irq[this_dev];
+		dev->base_addr = io[this_dev];
+		if (io[this_dev] == 0) {
+			if (this_dev) break;
+			printk(KERN_NOTICE "eexpress.c: Module autoprobe not recommended, give io=xx.\n");
+		}
+		if (register_netdev(dev) != 0) {
+			printk(KERN_WARNING "eexpress.c: Failed to register card at 0x%x.\n", io[this_dev]);
+			if (found != 0) return 0;
+			return -ENXIO;
+		}
+		found++;
+	}
 	return 0;
 }
 
 void cleanup_module(void)
 {
-	unregister_netdev(&dev_eexpress);
-	kfree_s(dev_eexpress.priv,sizeof(struct net_local));
-	dev_eexpress.priv = NULL;
+	int this_dev;
+        
+	for (this_dev = 0; this_dev < EEXP_MAX_CARDS; this_dev++) {
+		struct device *dev = &dev_eexp[this_dev];
+		if (dev->priv != NULL) {
+			kfree_s(dev->priv. sizeof(struct net_local));
+			dev->priv = NULL;
+			release_region(dev->base_addr, EEXP_IO_EXTENT);
+			unregister_netdev(dev);
+		}
+	}
 }
 #endif
diff -u --recursive --new-file v1.3.72/linux/drivers/net/eth82586.h linux/drivers/net/eth82586.h
--- v1.3.72/linux/drivers/net/eth82586.h	Tue Mar  5 10:10:58 1996
+++ linux/drivers/net/eth82586.h	Sun Mar 10 09:28:55 1996
@@ -81,11 +81,7 @@
  */
 #define TX_BUF_START 0x0100
 #define TX_BUF_SIZE ((24+ETH_FRAME_LEN+31)&~0x1f)
-unsigned short NUM_TX_BUFS=4;
-unsigned short RX_BUF_START;
 #define RX_BUF_SIZE ((32+ETH_FRAME_LEN+31)&~0x1f)
-unsigned short RX_BUF_END=0x7ff6; /* updated automatically to 0xfff6 on 64k cards */
-unsigned short NUM_RX_BUFS = 4;
 
 
 
diff -u --recursive --new-file v1.3.72/linux/drivers/net/lance.c linux/drivers/net/lance.c
--- v1.3.72/linux/drivers/net/lance.c	Tue Mar  5 10:10:58 1996
+++ linux/drivers/net/lance.c	Sun Mar 10 09:28:56 1996
@@ -13,9 +13,26 @@
 	The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O
 	Center of Excellence in Space Data and Information Sciences
 	   Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
+
+
+	Fixing alignment problem with 1.3.* kernel and some minor changes
+	by Andrey V. Savochkin, 1996.
+
+	Problems or questions may be send to Donald Becker (see above) or to
+	Andrey Savochkin -- saw@shade.msu.ru or
+		Laboratory of Computation Methods, 
+		Department of Mathematics and Mechanics,
+		Moscow State University,
+		Leninskye Gory, Moscow 119899
+
+	But I should to inform you that I'm not an expert in the LANCE card
+	and it may occurs that you will receive no answer on your mail
+	to Donald Becker. I didn't receive any answer on all my letters
+	to him. Who knows why... But may be you are more lucky?  ;-)
+                                                          SAW
 */
 
-static const char *version = "lance.c:v1.08 4/10/95 dplatt@3do.com\n";
+static const char *version = "lance.c:v1.08.01 Mar 6 1996 saw@shade.msu.ru\n";
 
 #include <linux/config.h>
 #include <linux/kernel.h>
@@ -137,9 +154,14 @@
 
 */
 
+/* Memory accessed from LANCE card must be aligned on 8-byte boundaries.
+   But we can't believe that kmalloc()'ed memory satisfyes it. -- SAW */
+#define LANCE_KMALLOC(x) \
+	((void *) (((unsigned long)kmalloc((x)+7, GFP_DMA | GFP_KERNEL)+7) & ~7))
+
 /* Set the number of Tx and Rx buffers, using Log_2(# buffers).
-   Reasonable default values are 4 Tx buffers, and 16 Rx buffers.
-   That translates to 2 (4 == 2^^2) and 4 (16 == 2^^4). */
+   Reasonable default values are 16 Tx buffers, and 16 Rx buffers.
+   That translates to 4 and 4 (16 == 2^^4). */
 #ifndef LANCE_LOG_TX_BUFFERS
 #define LANCE_LOG_TX_BUFFERS 4
 #define LANCE_LOG_RX_BUFFERS 4
@@ -186,22 +208,21 @@
 };
 
 struct lance_private {
-	/* The Tx and Rx ring entries must be aligned on 8-byte boundaries.
-	   This is always true for kmalloc'ed memory */
+	/* The Tx and Rx ring entries must be aligned on 8-byte boundaries. */
 	struct lance_rx_head rx_ring[RX_RING_SIZE];
 	struct lance_tx_head tx_ring[TX_RING_SIZE];
-	struct lance_init_block		init_block;
+	struct lance_init_block	init_block;
 	const char *name;
 	/* The saved address of a sent-in-place packet/buffer, for skfree(). */
 	struct sk_buff* tx_skbuff[TX_RING_SIZE];
-	long rx_buffs;				/* Address of Rx and Tx buffers. */
+	unsigned long rx_buffs;		/* Address of Rx and Tx buffers. */
 	/* Tx low-memory "bounce buffer" address. */
 	char (*tx_bounce_buffs)[PKT_BUF_SZ];
 	int cur_rx, cur_tx;			/* The next free ring entry */
 	int dirty_rx, dirty_tx;		/* The ring entries to be free()ed. */
 	int dma;
 	struct enet_statistics stats;
-	unsigned char chip_version;			/* See lance_chip_type. */
+	unsigned char chip_version;	/* See lance_chip_type. */
 	char tx_full;
 	char lock;
 };
@@ -338,7 +359,7 @@
 	int i, reset_val, lance_version;
 	const char *chipname;
 	/* Flags for specific chips or boards. */
-	unsigned char hpJ2405A = 0;						/* HP ISA adaptor */
+	unsigned char hpJ2405A = 0;			/* HP ISA adaptor */
 	int hp_builtin = 0;					/* HP on-board ethernet. */
 	static int did_version = 0;			/* Already printed version info. */
 
@@ -403,14 +424,16 @@
 	request_region(ioaddr, LANCE_TOTAL_SIZE, chip_table[lance_version].name);
 
 	/* Make certain the data structures used by the LANCE are aligned and DMAble. */
-	lp = (struct lance_private *) kmalloc(sizeof(*lp), GFP_DMA | GFP_KERNEL);
+	lp = (struct lance_private *) LANCE_KMALLOC(sizeof(*lp));
+	if (lance_debug > 6) printk(" (#0x%05lx)", (unsigned long)lp);
 	memset(lp, 0, sizeof(*lp));
 	dev->priv = lp;
 	lp->name = chipname;
-	lp->rx_buffs = (unsigned long) kmalloc(PKT_BUF_SZ*RX_RING_SIZE, GFP_DMA | GFP_KERNEL);
+	/* I'm not sure that buffs also must be aligned but it's safer to do it -- SAW */
+	lp->rx_buffs = (unsigned long) LANCE_KMALLOC(PKT_BUF_SZ*RX_RING_SIZE);
 	lp->tx_bounce_buffs = NULL;
 	if (lance_need_isa_bounce_buffers)
-		lp->tx_bounce_buffs = kmalloc(PKT_BUF_SZ*TX_RING_SIZE, GFP_DMA | GFP_KERNEL);
+		lp->tx_bounce_buffs = LANCE_KMALLOC(PKT_BUF_SZ*TX_RING_SIZE);
 
 	lp->chip_version = lance_version;
 
diff -u --recursive --new-file v1.3.72/linux/drivers/net/new_tunnel.c linux/drivers/net/new_tunnel.c
--- v1.3.72/linux/drivers/net/new_tunnel.c	Wed Feb 28 11:50:05 1996
+++ linux/drivers/net/new_tunnel.c	Sun Mar 10 09:28:56 1996
@@ -18,7 +18,8 @@
 		-Alan Cox	(Alan.Cox@linux.org) 21 March 95
 
 	Reworked:
-		Changed to tunnel to destination gateway instead of pointopoint
+		Changed to tunnel to destination gateway in addition to the
+			tunnel's pointopoint address
 		Almost completely rewritten
 		Note:  There is currently no firewall or ICMP handling done.
 
@@ -81,7 +82,7 @@
  *	[36 bytes]
  */
  
-#define TUNL_HLEN	(((ETH_HLEN+15)&~15)+tunl_hlen)
+#define TUNL_HLEN	(((ETH_HLEN+15)&~15)+tunnel_hlen)
 
 
 #ifdef MODULE
@@ -168,15 +169,22 @@
 		/* No route to host */
 		/* Where did the packet come from? */
 		/*icmp_send(skb, ICMP_DEST_UNREACH, ICMP_NET_UNREACH, 0, dev);*/
-		printk ( KERN_INFO "%s: Packet with no route!\n", dev->name );
+		printk ( KERN_INFO "%s: Packet with no route!\n", dev->name);
 		dev->tbusy=0;
 		stats->tx_errors++;
 		return(1);
 	}
 
-	if (!(rt->rt_flags & RTF_GATEWAY))
-	{ 
-		/* No gateway to tunnel through? */
+	/*
+	 * Get the target address (other end of IP tunnel)
+	 */
+	if (rt->rt_flags & RTF_GATEWAY)
+		target = rt->rt_gateway;
+	else
+		target = dev->pa_dstaddr;
+
+	if ( ! target )
+	{	/* No gateway to tunnel through? */
 		/* Where did the packet come from? */
 		/*icmp_send(skb, ICMP_DEST_UNREACH, ICMP_NET_UNREACH, 0, dev);*/
 		printk ( KERN_INFO "%s: Packet with no target gateway!\n", dev->name);
@@ -185,7 +193,6 @@
 		stats->tx_errors++;
 		return(1);
 	}
-	target = rt->rt_gateway;
 	ip_rt_put(rt);
 
 	if ((rt = ip_rt_route(target, 0)) == NULL)
@@ -203,7 +210,7 @@
 	if (tdev == dev)
 	{ 
 		/* Tunnel to ourselves?  -- I don't think so. */
-		printk ( KERN_INFO "%s: Packet targetted at myself!\n" ,dev->name);
+		printk ( KERN_INFO "%s: Packet targetted at myself!\n" , dev->name);
 		ip_rt_put(rt);
 		dev->tbusy=0;
 		stats->tx_errors++;
@@ -218,7 +225,7 @@
 	/*
 	 * Okay, now see if we can stuff it in the buffer as-is.
 	 */
-	max_headroom = ((tunnel_hlen+tdev->hard_header_len+15)&~15);
+	max_headroom = (((tdev->hard_header_len+15)&~15)+tunnel_hlen);
 #ifdef TUNNEL_DEBUG
 printk("Room left at head: %d\n", skb_headroom(skb));
 printk("Room left at tail: %d\n", skb_tailroom(skb));
@@ -241,13 +248,13 @@
 		new_skb->free = 1;
 
 		/*
-		 * Reserve space for our header
+		 * Reserve space for our header and the lower device header
 		 */
-		skb_reserve(new_skb, tunnel_hlen);
-		new_skb->h.iph = (struct iphdr *) skb_push(new_skb, tunnel_hlen);
+		skb_reserve(new_skb, max_headroom);
+
 		/*
 		 * Copy the old packet to the new buffer.
-		 * Note that new_skb->h.iph is our (tunnel driver's) header
+		 * Note that new_skb->h.iph will be our (tunnel driver's) header
 		 * and new_skb->ip_hdr is the IP header of the old packet.
 		 */
 		new_skb->ip_hdr = (struct iphdr *) skb_put(new_skb, skb->len);
@@ -255,6 +262,9 @@
 		/* Is this necessary? */
 		memcpy(new_skb->proto_priv, skb->proto_priv, sizeof(skb->proto_priv));
 
+		/* Tack on our header */
+		new_skb->h.iph = (struct iphdr *) skb_push(new_skb, tunnel_hlen);
+
 		/* Free the old packet, we no longer need it */
 		kfree_skb(skb, FREE_WRITE);
 		skb = new_skb;
@@ -353,12 +363,10 @@
 	dev->header_cache_update= NULL;
 
 	dev->type				= ARPHRD_TUNNEL;
-	dev->hard_header_len 	= (tunnel_hlen+ETH_HLEN);
+	dev->hard_header_len 	= TUNL_HLEN;
 	dev->mtu		= 1500-tunnel_hlen; 	/* eth_mtu */
 	dev->addr_len		= 0;		/* Is this only for ARP? */
 	dev->tx_queue_len	= 2;		/* Small queue */
-
-	/* it should all run through */
 	memset(dev->broadcast,0xFF, ETH_ALEN);
 
 	/* New-style flags. */
@@ -417,11 +425,4 @@
 	dev_tunnel.priv=NULL;
 }
 #endif /* MODULE */
-
-
-
-
- 
-
-
 
diff -u --recursive --new-file v1.3.72/linux/drivers/pci/pci.c linux/drivers/pci/pci.c
--- v1.3.72/linux/drivers/pci/pci.c	Sun Mar 10 09:49:55 1996
+++ linux/drivers/pci/pci.c	Sat Mar  9 12:22:09 1996
@@ -101,7 +101,7 @@
 	DEVICE( SI,		SI_5513,		"85C5513"),
 	DEVICE( HP,		HP_J2585A,	"J2585A"),
 	DEVICE( PCTECH,		PCTECH_RZ1000,  "RZ1000 (buggy)"),
-	DEVICE( PCTECH,		PCTECH_RZ1001,  "RZ1000"),
+	DEVICE( PCTECH,		PCTECH_RZ1001,  "RZ1001 (buggy?)"),
 	DEVICE( DPT,		DPT,		"SmartCache/Raid"),
 	DEVICE( OPTI,		OPTI_92C178,	"92C178"),
 	DEVICE( OPTI,		OPTI_82C557,	"82C557"),
diff -u --recursive --new-file v1.3.72/linux/drivers/scsi/BusLogic.c linux/drivers/scsi/BusLogic.c
--- v1.3.72/linux/drivers/scsi/BusLogic.c	Sat Mar  2 10:43:36 1996
+++ linux/drivers/scsi/BusLogic.c	Sat Mar  9 15:41:12 1996
@@ -1765,6 +1765,7 @@
 */
 
 static void BusLogic_InterruptHandler(int IRQ_Channel,
+				      void *DeviceIdentifier,
 				      Registers_T *InterruptRegisters)
 {
   BusLogic_CCB_T *FirstCompletedCCB = NULL, *LastCompletedCCB = NULL;
@@ -2210,7 +2211,7 @@
 	     HostAdapter->HostNumber, HostAdapter->IRQ_Channel);
       save_flags(ProcessorFlags);
       cli();
-      BusLogic_InterruptHandler(HostAdapter->IRQ_Channel, NULL);
+      BusLogic_InterruptHandler(HostAdapter->IRQ_Channel, NULL, NULL);
       restore_flags(ProcessorFlags);
       return SCSI_ABORT_SNOOZE;
     }
diff -u --recursive --new-file v1.3.72/linux/drivers/scsi/BusLogic.h linux/drivers/scsi/BusLogic.h
--- v1.3.72/linux/drivers/scsi/BusLogic.h	Thu Jan  4 21:54:55 1996
+++ linux/drivers/scsi/BusLogic.h	Sat Mar  9 15:41:12 1996
@@ -969,7 +969,7 @@
   Internal Functions.
 */
 
-static void BusLogic_InterruptHandler(int, Registers_T *);
+static void BusLogic_InterruptHandler(int, void *, Registers_T *);
 static int BusLogic_ResetHostAdapter(BusLogic_HostAdapter_T *,
 				     SCSI_Command_T *);
 
diff -u --recursive --new-file v1.3.72/linux/drivers/scsi/Config.in linux/drivers/scsi/Config.in
--- v1.3.72/linux/drivers/scsi/Config.in	Sun Mar 10 09:49:55 1996
+++ linux/drivers/scsi/Config.in	Mon Mar 11 18:09:16 1996
@@ -11,7 +11,7 @@
 
 bool 'Verbose SCSI error reporting (kernel size +=12K)' CONFIG_SCSI_CONSTANTS
 
-bool 'Automatic Disk Geometery determination' CONFIG_SCSI_AUTO_BIOSP
+bool 'Automatic Disk Geometry determination' CONFIG_SCSI_AUTO_BIOSP
 
 mainmenu_option next_comment
 comment 'SCSI low-level drivers'
diff -u --recursive --new-file v1.3.72/linux/fs/binfmt_aout.c linux/fs/binfmt_aout.c
--- v1.3.72/linux/fs/binfmt_aout.c	Tue Mar  5 10:11:06 1996
+++ linux/fs/binfmt_aout.c	Mon Mar 11 09:39:34 1996
@@ -129,6 +129,7 @@
 	if (!file.f_op->write)
 		goto close_coredump;
 	has_dumped = 1;
+	current->flags |= PF_DUMPCORE;
        	strncpy(dump.u_comm, current->comm, sizeof(current->comm));
 	dump.u_ar0 = (void *)(((unsigned long)(&dump.regs)) - ((unsigned long)(&dump)));
 	dump.signal = signr;
@@ -313,6 +314,7 @@
 	current->mm->mmap = NULL;
 	current->suid = current->euid = current->fsuid = bprm->e_uid;
 	current->sgid = current->egid = current->fsgid = bprm->e_gid;
+ 	current->flags &= ~PF_FORKNOEXEC;
 	if (N_MAGIC(ex) == OMAGIC) {
 #ifdef __alpha__
 		do_mmap(NULL, N_TXTADDR(ex) & PAGE_MASK,
diff -u --recursive --new-file v1.3.72/linux/fs/binfmt_elf.c linux/fs/binfmt_elf.c
--- v1.3.72/linux/fs/binfmt_elf.c	Tue Mar  5 10:11:06 1996
+++ linux/fs/binfmt_elf.c	Tue Mar 12 08:22:32 1996
@@ -165,7 +165,8 @@
 	int retval;
 	unsigned int last_bss;
 	int error;
-	int i, k;
+	int i;
+	unsigned int k;
 	
 	elf_bss = 0;
 	last_bss = 0;
@@ -220,13 +221,13 @@
 	    if (eppnt->p_flags & PF_R) elf_prot =  PROT_READ;
 	    if (eppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
 	    if (eppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;
-	    if (interp_elf_ex->e_type == ET_EXEC) {
+	    if (interp_elf_ex->e_type == ET_EXEC || load_addr != 0) {
 	    	elf_type |= MAP_FIXED;
 	    	vaddr = eppnt->p_vaddr;
 	    }
 	    
 	    error = do_mmap(file, 
-			    vaddr & 0xfffff000,
+			    load_addr + (vaddr & 0xfffff000),
 			    eppnt->p_filesz + (eppnt->p_vaddr & 0xfff),
 			    elf_prot,
 			    elf_type,
@@ -404,7 +405,7 @@
 	
 	elf_stack = 0xffffffff;
 	elf_interpreter = NULL;
-	start_code = 0;
+	start_code = 0xffffffff;
 	end_code = 0;
 	end_data = 0;
 	
@@ -414,6 +415,7 @@
 			{
 				kfree (elf_phdata);
 				kfree(elf_interpreter);
+				sys_close(elf_exec_fileno);
 				return -EINVAL;
 			}
 
@@ -426,6 +428,7 @@
 							   GFP_KERNEL);
 			if (elf_interpreter == NULL) {
 				kfree (elf_phdata);
+				sys_close(elf_exec_fileno);
 				return -ENOMEM;
 			}
 			
@@ -458,6 +461,7 @@
 			if(retval < 0) {
 				kfree (elf_phdata);
 				kfree(elf_interpreter);
+				sys_close(elf_exec_fileno);
 				return retval;
 			}
 		}
@@ -482,6 +486,7 @@
 		  {
 		    kfree(elf_interpreter);
 		    kfree(elf_phdata);
+		    sys_close(elf_exec_fileno);
 		    return -ELIBBAD;
 		  }
 	}
@@ -506,6 +511,7 @@
 			      kfree(elf_interpreter);
 			}
 			kfree (elf_phdata);
+			sys_close(elf_exec_fileno);
 			return -E2BIG;
 		}
 	}
@@ -582,11 +588,11 @@
 			if(!load_addr) 
 			  load_addr = elf_ppnt->p_vaddr - elf_ppnt->p_offset;
 			k = elf_ppnt->p_vaddr;
-			if(k > start_code) start_code = k;
+			if(k < start_code) start_code = k;
 			k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz;
 			if(k > elf_bss) elf_bss = k;
 #if 1
-			if((elf_ppnt->p_flags | PF_W) && end_code <  k)
+			if((elf_ppnt->p_flags & PF_X) && end_code <  k)
 #else
 			if( !(elf_ppnt->p_flags & PF_W) && end_code <  k)
 #endif
@@ -620,10 +626,11 @@
 	bprm->inode->i_count++;
 #endif
 #ifdef LOW_ELF_STACK
-	current->start_stack = p = elf_stack - 4;
+	current->start_stack = bprm->p = elf_stack - 4;
 #endif
 	current->suid = current->euid = current->fsuid = bprm->e_uid;
 	current->sgid = current->egid = current->fsgid = bprm->e_gid;
+	current->flags &= ~PF_FORKNOEXEC;
 	bprm->p = (unsigned long) 
 	  create_elf_tables((char *)bprm->p,
 			bprm->argc,
@@ -834,6 +841,8 @@
  */
 static inline int maydump(struct vm_area_struct *vma)
 {
+	if (!(vma->vm_flags & (VM_READ|VM_WRITE|VM_EXEC)))
+		return 0;
 #if 1
 	if (vma->vm_flags & (VM_WRITE|VM_GROWSUP|VM_GROWSDOWN))
 		return 1;
@@ -1020,6 +1029,7 @@
 	if (!file.f_op->write)
 		goto close_coredump;
 	has_dumped = 1;
+	current->flags |= PF_DUMPCORE;
 
 	DUMP_WRITE(&elf, sizeof(elf));
 	offset += sizeof(elf);				/* Elf header */
diff -u --recursive --new-file v1.3.72/linux/fs/buffer.c linux/fs/buffer.c
--- v1.3.72/linux/fs/buffer.c	Tue Mar  5 10:11:06 1996
+++ linux/fs/buffer.c	Mon Mar 11 11:01:29 1996
@@ -112,7 +112,7 @@
 
 
 /* These are the min and max parameter values that we will allow to be assigned */
-int bdflush_min[N_PARAM] = {  0,  10,    5,   60,  0,   100,   100, 1, 1};
+int bdflush_min[N_PARAM] = {  0,  10,    5,   25,  0,   100,   100, 1, 1};
 int bdflush_max[N_PARAM] = {100,5000, 2000, 2000,100, 60000, 60000, 2047, 5};
 
 /*
@@ -1012,20 +1012,24 @@
  * the unused_list here.
  *
  * The reuse_list receives buffers from interrupt routines, so we need
- * to be IRQ-safe here.
+ * to be IRQ-safe here (but note that interrupts only _add_ to the
+ * reuse_list, never take away. So we don't need to worry about the
+ * reuse_list magically emptying).
  */
 static inline void recover_reusable_buffer_heads(void)
 {
-	struct buffer_head *bh;
-	unsigned long flags;
+	if (reuse_list) {
+		struct buffer_head *bh;
+		unsigned long flags;
 	
-	save_flags(flags);
-	while (reuse_list) {
-		cli();
-		bh = reuse_list;
-		reuse_list = bh->b_next_free;
-		restore_flags(flags);
-		put_unused_buffer_head(bh);
+		save_flags(flags);
+		do {
+			cli();
+			bh = reuse_list;
+			reuse_list = bh->b_next_free;
+			restore_flags(flags);
+			put_unused_buffer_head(bh);
+		} while (reuse_list);
 	}
 }
 
@@ -1146,15 +1150,19 @@
 	if (nr)
 		ll_rw_block(rw, nr, arr);
 	else {
+		unsigned long flags;
 		page->locked = 0;
 		page->uptodate = 1;
 		wake_up(&page->wait);
 		next = bh;
+		save_flags(flags);
+		cli();
 		do {
 			next->b_next_free = reuse_list;
 			reuse_list = next;
 			next = next->b_this_page;
 		} while (next != bh);
+		restore_flags(flags);
 	}
 	++current->maj_flt;
 	return 0;
diff -u --recursive --new-file v1.3.72/linux/fs/fat/dir.c linux/fs/fat/dir.c
--- v1.3.72/linux/fs/fat/dir.c	Sun Mar 10 09:49:55 1996
+++ linux/fs/fat/dir.c	Mon Mar 11 11:25:57 1996
@@ -113,7 +113,7 @@
 	unsigned char long_len = 0; /* Make compiler warning go away */
 	unsigned char alias_checksum = 0; /* Make compiler warning go away */
 	unsigned char long_slots = 0;
-	int uni_xlate = MSDOS_SB(sb)->unicode_xlate;
+	int uni_xlate = MSDOS_SB(sb)->options.unicode_xlate;
 	unsigned char *unicode = NULL;
 
 	if (!inode || !S_ISDIR(inode->i_mode))
@@ -138,10 +138,10 @@
 	ino = fat_get_entry(inode,&filp->f_pos,&bh,&de);
 	while (ino > -1) {
 		/* Check for long filename entry */
-		if (MSDOS_SB(sb)->vfat && (de->name[0] == (__s8) DELETED_FLAG)) {
+		if (MSDOS_SB(sb)->options.isvfat && (de->name[0] == (__s8) DELETED_FLAG)) {
 			is_long = 0;
 			oldpos = filp->f_pos;
-		} else if (MSDOS_SB(sb)->vfat && de->attr ==  ATTR_EXT) {
+		} else if (MSDOS_SB(sb)->options.isvfat && de->attr ==  ATTR_EXT) {
 			int get_new_entry;
 			struct msdos_dir_slot *ds;
 			int offset;
@@ -227,7 +227,7 @@
 				}
 			}
 
-			if ((de->attr & ATTR_HIDDEN) && MSDOS_SB(sb)->dotsOK) {
+			if ((de->attr & ATTR_HIDDEN) && MSDOS_SB(sb)->options.dotsOK) {
 				bufname[0] = '.';
 				dotoffset = 1;
 				ptname = bufname+1;
diff -u --recursive --new-file v1.3.72/linux/fs/fat/inode.c linux/fs/fat/inode.c
--- v1.3.72/linux/fs/fat/inode.c	Sun Mar 10 09:49:55 1996
+++ linux/fs/fat/inode.c	Mon Mar 11 11:25:57 1996
@@ -65,72 +65,71 @@
 }
 
 
-static int parse_options(char *options,char *check,char *conversion,uid_t *uid,
-    gid_t *gid,int *umask,int *debug,int *fat,int *quiet,
-	int *blksize, char *dotsOK, char *sys_immutable, char *showexec)
+static int parse_options(char *options,int *fat, int *blksize, int *debug,
+			 struct fat_mount_options *opts)
 {
 	char *this_char,*value;
 
-	*check = 'n';
-	*conversion = 'b';
-	*dotsOK = 0;
-	*showexec = 0;
-	*uid = current->uid;
-	*gid = current->gid;
-	*umask = current->fs->umask;
-	*debug = *fat = *quiet = *sys_immutable = 0;
+	opts->name_check = 'n';
+	opts->conversion = 'b';
+	opts->fs_uid = current->uid;
+	opts->fs_gid = current->gid;
+	opts->fs_umask = current->fs->umask;
+	opts->quiet = opts->sys_immutable = opts->dotsOK = opts->showexec = opts->isvfat = 0;
+	*debug = *fat = 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,"check") && value) {
 			if (value[0] && !value[1] && strchr("rns",*value))
-				*check = *value;
-			else if (!strcmp(value,"relaxed")) *check = 'r';
-			else if (!strcmp(value,"normal")) *check = 'n';
-			else if (!strcmp(value,"strict")) *check = 's';
+				opts->name_check = *value;
+			else if (!strcmp(value,"relaxed")) opts->name_check = 'r';
+			else if (!strcmp(value,"normal")) opts->name_check = 'n';
+			else if (!strcmp(value,"strict")) opts->name_check = 's';
 			else return 0;
 		}
 		else if (!strcmp(this_char,"conv") && value) {
 			if (value[0] && !value[1] && strchr("bta",*value))
-				*conversion = *value;
-			else if (!strcmp(value,"binary")) *conversion = 'b';
-			else if (!strcmp(value,"text")) *conversion = 't';
-			else if (!strcmp(value,"auto")) *conversion = 'a';
+				opts->conversion = *value;
+			else if (!strcmp(value,"binary")) opts->conversion = 'b';
+			else if (!strcmp(value,"text")) opts->conversion = 't';
+			else if (!strcmp(value,"auto")) opts->conversion = 'a';
 			else return 0;
 		}
 		else if (!strcmp(this_char,"dots")) {
-			*dotsOK = 1;
+			opts->dotsOK = 1;
 		}
 		else if (!strcmp(this_char,"nodots")) {
-			*dotsOK = 0;
+			opts->dotsOK = 0;
 		}
 		else if (!strcmp(this_char,"showexec")) {
-			*showexec = 1;
+			opts->showexec = 1;
 		}
 		else if (!strcmp(this_char,"dotsOK") && value) {
-			if (!strcmp(value,"yes")) *dotsOK = 1;
-			else if (!strcmp(value,"no")) *dotsOK = 0;
+			if (!strcmp(value,"yes")) opts->dotsOK = 1;
+			else if (!strcmp(value,"no")) opts->dotsOK = 0;
 			else return 0;
 		}
 		else if (!strcmp(this_char,"uid")) {
 			if (!value || !*value)
 				return 0;
-			*uid = simple_strtoul(value,&value,0);
+			opts->fs_uid = simple_strtoul(value,&value,0);
 			if (*value)
 				return 0;
 		}
 		else if (!strcmp(this_char,"gid")) {
 			if (!value || !*value)
 				return 0;
-			*gid = simple_strtoul(value,&value,0);
+			opts->fs_gid = simple_strtoul(value,&value,0);
 			if (*value)
 				return 0;
 		}
 		else if (!strcmp(this_char,"umask")) {
 			if (!value || !*value)
 				return 0;
-			*umask = simple_strtoul(value,&value,8);
+			opts->fs_umask = simple_strtoul(value,&value,8);
 			if (*value)
 				return 0;
 		}
@@ -147,7 +146,7 @@
 		}
 		else if (!strcmp(this_char,"quiet")) {
 			if (value) return 0;
-			*quiet = 1;
+			opts->quiet = 1;
 		}
 		else if (!strcmp(this_char,"blocksize")) {
 			*blksize = simple_strtoul(value,&value,0);
@@ -160,7 +159,7 @@
 		else if (!strcmp(this_char,"sys_immutable")) {
 			if (value)
 				return 0;
-			*sys_immutable = 1;
+			opts->sys_immutable = 1;
 		}
 	}
 	return 1;
@@ -174,12 +173,9 @@
 	struct buffer_head *bh;
 	struct msdos_boot_sector *b;
 	int data_sectors,logical_sector_size,sector_mult,fat_clusters=0;
-	int debug,error,fat,quiet;
-	char check,conversion,dotsOK,sys_immutable,showexec;
-	uid_t uid;
-	gid_t gid;
-	int umask;
+	int debug,error,fat;
 	int blksize = 512;
+	struct fat_mount_options opts;
 
 	MOD_INC_USE_COUNT;
 	if (hardsect_size[MAJOR(sb->s_dev)] != NULL){
@@ -188,8 +184,7 @@
 			printk ("MSDOS: Hardware sector size is %d\n",blksize);
 		}
 	}
-	if (!parse_options((char *) data,&check,&conversion,&uid,&gid,&umask,
-	    &debug,&fat,&quiet,&blksize,&dotsOK,&sys_immutable,&showexec)
+	if (!parse_options((char *) data, &fat, &blksize, &debug, &opts)
 		|| (blksize != 512 && blksize != 1024)) {
 		sb->s_dev = 0;
 		MOD_DEC_USE_COUNT;
@@ -271,15 +266,17 @@
 	if (error || debug) {
 		/* The MSDOS_CAN_BMAP is obsolete, but left just to remember */
 		printk("[MS-DOS FS Rel. 12,FAT %d,check=%c,conv=%c,"
-		    "uid=%d,gid=%d,umask=%03o%s]\n",MSDOS_SB(sb)->fat_bits,check,
-		    conversion,uid,gid,umask,MSDOS_CAN_BMAP(MSDOS_SB(sb)) ?
-		    ",bmap" : "");
+		       "uid=%d,gid=%d,umask=%03o%s]\n",
+		       MSDOS_SB(sb)->fat_bits,opts.name_check,
+		       opts.conversion,opts.fs_uid,opts.fs_gid,opts.fs_umask,
+		       MSDOS_CAN_BMAP(MSDOS_SB(sb)) ? ",bmap" : "");
 		printk("[me=0x%x,cs=%d,#f=%d,fs=%d,fl=%d,ds=%d,de=%d,data=%d,"
-		    "se=%d,ts=%ld,ls=%d]\n",b->media,MSDOS_SB(sb)->cluster_size,
-		    MSDOS_SB(sb)->fats,MSDOS_SB(sb)->fat_start,MSDOS_SB(sb)->
-		    fat_length,MSDOS_SB(sb)->dir_start,MSDOS_SB(sb)->dir_entries,
-		    MSDOS_SB(sb)->data_start,CF_LE_W(*(unsigned short *) &b->
-		    sectors),(unsigned long)b->total_sect,logical_sector_size);
+		       "se=%d,ts=%ld,ls=%d]\n",b->media,MSDOS_SB(sb)->cluster_size,
+		       MSDOS_SB(sb)->fats,MSDOS_SB(sb)->fat_start,MSDOS_SB(sb)->fat_length,
+		       MSDOS_SB(sb)->dir_start,MSDOS_SB(sb)->dir_entries,
+		       MSDOS_SB(sb)->data_start,
+		       CF_LE_W(*(unsigned short *) &b->sectors),
+		       (unsigned long)b->total_sect,logical_sector_size);
 		printk ("Transaction block size = %d\n",blksize);
 	}
 	if (MSDOS_SB(sb)->clusters+2 > fat_clusters)
@@ -293,22 +290,12 @@
 		return NULL;
 	}
 	sb->s_magic = MSDOS_SUPER_MAGIC;
-	MSDOS_SB(sb)->name_check = check;
-	MSDOS_SB(sb)->conversion = conversion;
 	/* set up enough so that it can read an inode */
-	MSDOS_SB(sb)->fs_uid = uid;
-	MSDOS_SB(sb)->fs_gid = gid;
-	MSDOS_SB(sb)->fs_umask = umask;
-	MSDOS_SB(sb)->quiet = quiet;
-	MSDOS_SB(sb)->dotsOK = dotsOK;
-	MSDOS_SB(sb)->showexec = showexec;
-	MSDOS_SB(sb)->sys_immutable = sys_immutable;
-	MSDOS_SB(sb)->vfat = 0;   /* vfat_read_super sets this */
-	MSDOS_SB(sb)->umsdos = 0; /* umsdos_read_super will set this */
 	MSDOS_SB(sb)->free_clusters = -1; /* don't know yet */
 	MSDOS_SB(sb)->fat_wait = NULL;
 	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))) {
 		sb->s_dev = 0;
 		printk("get root inode failed\n");
@@ -382,11 +369,11 @@
 	MSDOS_I(inode)->i_busy = 0;
 	MSDOS_I(inode)->i_depend = MSDOS_I(inode)->i_old = NULL;
 	MSDOS_I(inode)->i_binary = 1;
-	inode->i_uid = MSDOS_SB(inode->i_sb)->fs_uid;
-	inode->i_gid = MSDOS_SB(inode->i_sb)->fs_gid;
+	inode->i_uid = MSDOS_SB(inode->i_sb)->options.fs_uid;
+	inode->i_gid = MSDOS_SB(inode->i_sb)->options.fs_gid;
 	inode->i_version = ++event;
 	if (inode->i_ino == MSDOS_ROOT_INO) {
-		inode->i_mode = (S_IRWXUGO & ~MSDOS_SB(inode->i_sb)->fs_umask) |
+		inode->i_mode = (S_IRWXUGO & ~MSDOS_SB(inode->i_sb)->options.fs_umask) |
 		    S_IFDIR;
 		inode->i_op = fs_dir_inode_ops;
 		inode->i_nlink = fat_subdirs(inode)+2;
@@ -412,7 +399,7 @@
 	    [inode->i_ino & (MSDOS_DPB-1)];
 	if ((raw_entry->attr & ATTR_DIR) && !IS_FREE(raw_entry->name)) {
 		inode->i_mode = MSDOS_MKMODE(raw_entry->attr,S_IRWXUGO &
-		    ~MSDOS_SB(inode->i_sb)->fs_umask) | S_IFDIR;
+		    ~MSDOS_SB(inode->i_sb)->options.fs_umask) | S_IFDIR;
 		inode->i_op = fs_dir_inode_ops;
 
 		MSDOS_I(inode)->i_start = CF_LE_W(raw_entry->start);
@@ -437,10 +424,11 @@
 			}
 	} else { /* not a directory */
 		inode->i_mode = MSDOS_MKMODE(raw_entry->attr,
-		    ((IS_NOEXEC(inode) || (MSDOS_SB(inode->i_sb)->showexec &&
-						!is_exec(raw_entry->ext)))
+		    ((IS_NOEXEC(inode) || 
+		      (MSDOS_SB(inode->i_sb)->options.showexec &&
+		       !is_exec(raw_entry->ext)))
 		    	? S_IRUGO|S_IWUGO : S_IRWXUGO)
-		    & ~MSDOS_SB(inode->i_sb)->fs_umask) | S_IFREG;
+		    & ~MSDOS_SB(inode->i_sb)->options.fs_umask) | S_IFREG;
 		inode->i_op = (sb->s_blocksize == 1024)
 			? &fat_file_inode_operations_1024
 			: &fat_file_inode_operations;
@@ -449,9 +437,9 @@
 		inode->i_size = CF_LE_L(raw_entry->size);
 	}
 	if(raw_entry->attr & ATTR_SYS)
-		if (MSDOS_SB(inode->i_sb)->sys_immutable)
+		if (MSDOS_SB(inode->i_sb)->options.sys_immutable)
 			inode->i_flags |= S_IMMUTABLE;
-	MSDOS_I(inode)->i_binary = is_binary(MSDOS_SB(inode->i_sb)->conversion,
+	MSDOS_I(inode)->i_binary = is_binary(MSDOS_SB(inode->i_sb)->options.conversion,
 	    raw_entry->ext);
 	MSDOS_I(inode)->i_attrs = raw_entry->attr & ATTR_UNUSED;
 	/* this is as close to the truth as we can get ... */
@@ -461,7 +449,7 @@
 	inode->i_mtime = inode->i_atime =
 	    date_dos2unix(CF_LE_W(raw_entry->time),CF_LE_W(raw_entry->date));
 	inode->i_ctime =
-		MSDOS_SB(inode->i_sb)->vfat
+		MSDOS_SB(inode->i_sb)->options.isvfat
 		? date_dos2unix(CF_LE_W(raw_entry->ctime),CF_LE_W(raw_entry->cdate))
 		: inode->i_mtime;
 	brelse(bh);
@@ -498,7 +486,7 @@
 	fat_date_unix2dos(inode->i_mtime,&raw_entry->time,&raw_entry->date);
 	raw_entry->time = CT_LE_W(raw_entry->time);
 	raw_entry->date = CT_LE_W(raw_entry->date);
-	if (MSDOS_SB(sb)->vfat) {
+	if (MSDOS_SB(sb)->options.isvfat) {
 		fat_date_unix2dos(inode->i_ctime,&raw_entry->ctime,&raw_entry->cdate);
 		raw_entry->ctime = CT_LE_W(raw_entry->ctime);
 		raw_entry->cdate = CT_LE_W(raw_entry->cdate);
@@ -517,15 +505,15 @@
 		return error;
 
 	if (((attr->ia_valid & ATTR_UID) && 
-	     (attr->ia_uid != MSDOS_SB(inode->i_sb)->fs_uid)) ||
+	     (attr->ia_uid != MSDOS_SB(inode->i_sb)->options.fs_uid)) ||
 	    ((attr->ia_valid & ATTR_GID) && 
-	     (attr->ia_gid != MSDOS_SB(inode->i_sb)->fs_gid)) ||
+	     (attr->ia_gid != MSDOS_SB(inode->i_sb)->options.fs_gid)) ||
 	    ((attr->ia_valid & ATTR_MODE) &&
 	     (attr->ia_mode & ~MSDOS_VALID_MODE)))
 		error = -EPERM;
 
 	if (error)
-		return MSDOS_SB(inode->i_sb)->quiet ? 0 : error;
+		return MSDOS_SB(inode->i_sb)->options.quiet ? 0 : error;
 
 	inode_setattr(inode, attr);
 
@@ -535,8 +523,8 @@
 		inode->i_mode |= S_IXUGO;
 
 	inode->i_mode = ((inode->i_mode & S_IFMT) | ((((inode->i_mode & S_IRWXU
-	    & ~MSDOS_SB(inode->i_sb)->fs_umask) | S_IRUSR) >> 6)*S_IXUGO)) &
-	    ~MSDOS_SB(inode->i_sb)->fs_umask;
+	    & ~MSDOS_SB(inode->i_sb)->options.fs_umask) | S_IRUSR) >> 6)*S_IXUGO)) &
+	    ~MSDOS_SB(inode->i_sb)->options.fs_umask;
 	return 0;
 }
 
diff -u --recursive --new-file v1.3.72/linux/fs/fifo.c linux/fs/fifo.c
--- v1.3.72/linux/fs/fifo.c	Tue Dec 26 04:45:37 1995
+++ linux/fs/fifo.c	Mon Mar 11 11:23:22 1996
@@ -131,7 +131,7 @@
 	NULL
 };
 
-static struct inode_operations fifo_inode_operations = {
+struct inode_operations fifo_inode_operations = {
 	&def_fifo_fops,		/* default file operations */
 	NULL,			/* create */
 	NULL,			/* lookup */
diff -u --recursive --new-file v1.3.72/linux/fs/filesystems.c linux/fs/filesystems.c
--- v1.3.72/linux/fs/filesystems.c	Fri Feb  9 17:53:06 1996
+++ linux/fs/filesystems.c	Sat Mar  9 13:31:43 1996
@@ -27,12 +27,6 @@
 extern void device_setup(void);
 extern void binfmt_setup(void);
 
-#ifdef CONFIG_ROOT_NFS
-extern int nfs_root_init(char *nfsname, char *nfsaddrs);
-extern char nfs_root_name [];
-extern char nfs_root_addrs [];
-#endif
-
 /* This may be used only once, enforced by 'static int callable' */
 asmlinkage int sys_setup(void)
 {
@@ -104,15 +98,6 @@
 
 #ifdef CONFIG_HPFS_FS
 	init_hpfs_fs();
-#endif
-
-#ifdef CONFIG_ROOT_NFS
-	if (ROOT_DEV == MKDEV(UNNAMED_MAJOR, 255)) {
-		if (nfs_root_init(nfs_root_name, nfs_root_addrs) < 0) {
-			printk(KERN_ERR "Root-NFS: Unable to contact NFS server for root fs, using /dev/fd0 instead\n");
-			ROOT_DEV = MKDEV(FLOPPY_MAJOR, 0);
-		}
-	}
 #endif
 
 	mount_root();
diff -u --recursive --new-file v1.3.72/linux/fs/inode.c linux/fs/inode.c
--- v1.3.72/linux/fs/inode.c	Fri Feb 23 13:54:37 1996
+++ linux/fs/inode.c	Sat Mar  9 13:31:43 1996
@@ -194,7 +194,8 @@
 	for (i=0 ; i < nr_inodes ; i++, inode = inode->i_next) {
 		if (inode->i_dev != dev || !inode->i_count)
 			continue;
-		if (inode == mount_root && inode->i_count == 1)
+		if (inode == mount_root && inode->i_count ==
+		    (inode->i_mount != inode ? 1 : 2))
 			continue;
 		return 0;
 	}
diff -u --recursive --new-file v1.3.72/linux/fs/ioctl.c linux/fs/ioctl.c
--- v1.3.72/linux/fs/ioctl.c	Mon Sep 18 14:54:06 1995
+++ linux/fs/ioctl.c	Sun Mar 10 09:28:56 1996
@@ -72,6 +72,10 @@
 			return 0;
 
 		case FIONBIO:
+			on = verify_area(VERIFY_READ, (unsigned int *)arg,
+				sizeof(unsigned int));
+			if(on)	
+				return on;
 			on = get_user((unsigned int *) arg);
 			if (on)
 				filp->f_flags |= O_NONBLOCK;
@@ -81,6 +85,10 @@
 
 		case FIOASYNC: /* O_SYNC is not yet implemented,
 				  but it's here for completeness. */
+			on = verify_area(VERIFY_READ, (unsigned int *)arg,
+				sizeof(unsigned int));
+			if(on)	
+				return on;
 			on = get_user ((unsigned int *) arg);
 			if (on)
 				filp->f_flags |= O_SYNC;
diff -u --recursive --new-file v1.3.72/linux/fs/minix/bitmap.c linux/fs/minix/bitmap.c
--- v1.3.72/linux/fs/minix/bitmap.c	Mon Nov 27 12:48:31 1995
+++ linux/fs/minix/bitmap.c	Tue Mar 12 07:54:11 1996
@@ -14,29 +14,17 @@
 
 #include <asm/bitops.h>
 
-static int nibblemap[] = { 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4 };
+static int nibblemap[] = { 4,3,3,2,3,2,2,1,3,2,2,1,2,1,1,0 };
 
-static unsigned long count_used(struct buffer_head *map[], unsigned numblocks,
-	unsigned numbits)
+static unsigned long count_free(struct buffer_head *map[], unsigned numblocks)
 {
-	unsigned i, j, end, sum = 0;
+	unsigned i, j, sum = 0;
 	struct buffer_head *bh;
   
-	for (i=0; (i<numblocks) && numbits; i++) {
+	for (i=0; i<numblocks; i++) {
 		if (!(bh=map[i])) 
 			return(0);
-		if (numbits >= (8*BLOCK_SIZE)) { 
-			end = BLOCK_SIZE;
-			numbits -= 8*BLOCK_SIZE;
-		} else {
-			int tmp;
-			end = numbits >> 3;
-			numbits &= 0x7;
-			tmp = bh->b_data[end] & ((1<<numbits)-1);
-			sum += nibblemap[tmp&0xf] + nibblemap[(tmp>>4)&0xf];
-			numbits = 0;
-		}  
-		for (j=0; j<end; j++)
+		for (j=0; j<BLOCK_SIZE; j++)
 			sum += nibblemap[bh->b_data[j] & 0xf] 
 				+ nibblemap[(bh->b_data[j]>>4)&0xf];
 	}
@@ -87,11 +75,11 @@
 	}
 repeat:
 	j = 8192;
-	for (i=0 ; i<8 ; i++)
+	for (i=0 ; i<64 ; i++)
 		if ((bh=sb->u.minix_sb.s_zmap[i]) != NULL)
 			if ((j=find_first_zero_bit(bh->b_data, 8192)) < 8192)
 				break;
-	if (i>=8 || !bh || j>=8192)
+	if (i>=64 || !bh || j>=8192)
 		return 0;
 	if (set_bit(j,bh->b_data)) {
 		printk("new_block: bit already set");
@@ -115,8 +103,76 @@
 
 unsigned long minix_count_free_blocks(struct super_block *sb)
 {
-	return (sb->u.minix_sb.s_nzones - count_used(sb->u.minix_sb.s_zmap,sb->u.minix_sb.s_zmap_blocks,sb->u.minix_sb.s_nzones))
-		 << sb->u.minix_sb.s_log_zone_size;
+	return (count_free(sb->u.minix_sb.s_zmap,sb->u.minix_sb.s_zmap_blocks)
+		 << sb->u.minix_sb.s_log_zone_size);
+}
+
+static struct buffer_head *V1_minix_clear_inode(struct inode *inode)
+{
+	struct buffer_head *bh;
+	struct minix_inode *raw_inode;
+	int ino, block;
+
+	ino = inode->i_ino;
+	if (!ino || ino >= inode->i_sb->u.minix_sb.s_ninodes) {
+		printk("Bad inode number on dev %s: %d is out of range\n",
+		       kdevname(inode->i_dev), ino);
+		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);
+	bh = bread(inode->i_dev, block, BLOCK_SIZE);
+	if (!bh) {
+		printk("unable to read i-node block\n");
+		return 0;
+	}
+	raw_inode = ((struct minix_inode *)bh->b_data +
+		     (ino - 1) % MINIX_INODES_PER_BLOCK);
+	raw_inode->i_nlinks = 0;
+	raw_inode->i_mode = 0;
+	mark_buffer_dirty(bh, 1);
+	return bh;
+}
+
+static struct buffer_head *V2_minix_clear_inode(struct inode *inode)
+{
+	struct buffer_head *bh;
+	struct minix2_inode *raw_inode;
+	int ino, block;
+
+	ino = inode->i_ino;
+	if (!ino || ino >= inode->i_sb->u.minix_sb.s_ninodes) {
+		printk("Bad inode number on dev %s: %d is out of range\n",
+		       kdevname(inode->i_dev), ino);
+		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);
+	bh = bread(inode->i_dev, block, BLOCK_SIZE);
+	if (!bh) {
+		printk("unable to read i-node block\n");
+		return 0;
+	}
+	raw_inode = ((struct minix2_inode *) bh->b_data +
+		     (ino - 1) % MINIX2_INODES_PER_BLOCK);
+	raw_inode->i_nlinks = 0;
+	raw_inode->i_mode = 0;
+	mark_buffer_dirty(bh, 1);
+	return bh;
+}
+
+/* Clear the link count and mode of a deleted inode on disk. */
+
+static void minix_clear_inode(struct inode *inode)
+{
+	struct buffer_head *bh;
+	if (INODE_VERSION(inode) == MINIX_V1)
+		bh = V1_minix_clear_inode(inode);
+	else
+		bh = V2_minix_clear_inode(inode);
+	brelse (bh);
 }
 
 void minix_free_inode(struct inode * inode)
@@ -151,6 +207,7 @@
 		printk("free_inode: nonexistent imap in superblock\n");
 		return;
 	}
+	minix_clear_inode(inode);
 	clear_inode(inode);
 	if (!clear_bit(ino & 8191, bh->b_data))
 		printk("free_inode: bit %lu already cleared.\n",ino);
@@ -205,5 +262,5 @@
 
 unsigned long minix_count_free_inodes(struct super_block *sb)
 {
-	return sb->u.minix_sb.s_ninodes - count_used(sb->u.minix_sb.s_imap,sb->u.minix_sb.s_imap_blocks,sb->u.minix_sb.s_ninodes);
+	return count_free(sb->u.minix_sb.s_imap,sb->u.minix_sb.s_imap_blocks);
 }
diff -u --recursive --new-file v1.3.72/linux/fs/msdos/namei.c linux/fs/msdos/namei.c
--- v1.3.72/linux/fs/msdos/namei.c	Sun Mar 10 09:49:56 1996
+++ linux/fs/msdos/namei.c	Mon Mar 11 11:25:58 1996
@@ -154,9 +154,9 @@
 	char dotsOK;
 	char scantype;
 
-	dotsOK = MSDOS_SB(dir->i_sb)->dotsOK;
-	res = msdos_format_name(MSDOS_SB(dir->i_sb)->name_check,
-	    name,len, msdos_name,1,dotsOK);
+	dotsOK = MSDOS_SB(dir->i_sb)->options.dotsOK;
+	res = msdos_format_name(MSDOS_SB(dir->i_sb)->options.name_check,
+				name,len, msdos_name,1,dotsOK);
 	if (res < 0)
 		return -ENOENT;
 	if((name[0]=='.') && dotsOK){
@@ -302,8 +302,9 @@
 	int ino,res,is_hid;
 
 	if (!dir) return -ENOENT;
-	if ((res = msdos_format_name(MSDOS_SB(dir->i_sb)->name_check,name,len,
-	    msdos_name,0,MSDOS_SB(dir->i_sb)->dotsOK)) < 0) {
+	if ((res = msdos_format_name(MSDOS_SB(dir->i_sb)->options.name_check,
+				     name,len,msdos_name,0,
+				     MSDOS_SB(dir->i_sb)->options.dotsOK)) < 0) {
 		iput(dir);
 		return res;
 	}
@@ -427,8 +428,9 @@
 	char msdos_name[MSDOS_NAME];
 	int ino,res,is_hid;
 
-	if ((res = msdos_format_name(MSDOS_SB(dir->i_sb)->name_check,name,len,
-	    msdos_name,0,MSDOS_SB(dir->i_sb)->dotsOK)) < 0) {
+	if ((res = msdos_format_name(MSDOS_SB(dir->i_sb)->options.name_check,
+				     name,len,msdos_name,0,
+				     MSDOS_SB(dir->i_sb)->options.dotsOK)) < 0) {
 		iput(dir);
 		return res;
 	}
@@ -740,11 +742,13 @@
 	int old_ino,error;
 	int is_hid,old_hid; /* if new file and old file are hidden */
 
-	if ((error = msdos_format_name(MSDOS_SB(old_dir->i_sb)->name_check,
-	    old_name,old_len,old_msdos_name,1,MSDOS_SB(old_dir->i_sb)->dotsOK))
+	if ((error = msdos_format_name(MSDOS_SB(old_dir->i_sb)->options.name_check,
+				       old_name,old_len,old_msdos_name,1,
+				       MSDOS_SB(old_dir->i_sb)->options.dotsOK))
 	    < 0) goto rename_done;
-	if ((error = msdos_format_name(MSDOS_SB(new_dir->i_sb)->name_check,
-	    new_name,new_len,new_msdos_name,0,MSDOS_SB(new_dir->i_sb)->dotsOK))
+	if ((error = msdos_format_name(MSDOS_SB(new_dir->i_sb)->options.name_check,
+				       new_name,new_len,new_msdos_name,0,
+				       MSDOS_SB(new_dir->i_sb)->options.dotsOK))
 	    < 0) goto rename_done;
 	is_hid = (new_name[0]=='.') && (new_msdos_name[0]!='.');
 	old_hid = (old_name[0]=='.') && (old_msdos_name[0]!='.');
diff -u --recursive --new-file v1.3.72/linux/fs/ncpfs/dir.c linux/fs/ncpfs/dir.c
--- v1.3.72/linux/fs/ncpfs/dir.c	Tue Mar  5 10:11:07 1996
+++ linux/fs/ncpfs/dir.c	Sun Mar 10 13:49:16 1996
@@ -416,8 +416,8 @@
 						      info.volume_name,
 						      &(entry->i)) != 0)
 				{
-					printk("ncpfs: could not lookup vol "
-					       "%s\n", info.volume_name);
+					DPRINTK("ncpfs: could not lookup vol "
+						"%s\n", info.volume_name);
 					continue;
 				}
 
@@ -709,7 +709,13 @@
 	{
 		if (   (result->dir->finfo.i.DosDirNum == dir_info->DosDirNum)
 		    && (result->dir->finfo.i.volNumber == dir_info->volNumber)
-		    && (strcmp(result->finfo.i.entryName, name) == 0))
+		    && (strcmp(result->finfo.i.entryName, name) == 0)
+		    /* The root dir is never looked up using this
+		     * routine.  Without the following test a root
+		     * directory 'sys' in a volume named 'sys' could
+		     * never be looked up, because
+		     * server->root->dir==server->root. */
+		    && (result != &(server->root)))
 		{
                         return result;
 		}
diff -u --recursive --new-file v1.3.72/linux/fs/ncpfs/sock.c linux/fs/ncpfs/sock.c
--- v1.3.72/linux/fs/ncpfs/sock.c	Tue Mar  5 10:11:08 1996
+++ linux/fs/ncpfs/sock.c	Sun Mar 10 13:49:16 1996
@@ -512,9 +512,8 @@
 		 * a null buffer yet. */
 		_recvfrom(sock, (void *)&reply, sizeof(reply), 1, 0, NULL,
 			  &addrlen);
-#if 1
-		printk("ncp_rpc_call: reply mismatch\n");
-#endif
+
+		DPRINTK("ncp_rpc_call: reply mismatch\n");
 		goto re_select;
 	}
 	/* 
diff -u --recursive --new-file v1.3.72/linux/fs/nfs/dir.c linux/fs/nfs/dir.c
--- v1.3.72/linux/fs/nfs/dir.c	Sun Mar 10 09:49:56 1996
+++ linux/fs/nfs/dir.c	Tue Mar 12 16:06:44 1996
@@ -612,7 +612,7 @@
 		printk("nfs_refresh_inode: inode number mismatch\n");
 		return;
 	}
-	was_empty = inode->i_mode == 0;
+	was_empty = (inode->i_mode == 0);
 	inode->i_mode = fattr->mode;
 	inode->i_nlink = fattr->nlink;
 	inode->i_uid = fattr->uid;
@@ -631,22 +631,21 @@
 	inode->i_atime = fattr->atime.seconds;
 	inode->i_mtime = fattr->mtime.seconds;
 	inode->i_ctime = fattr->ctime.seconds;
-	if (was_empty) {
-		if (S_ISREG(inode->i_mode))
-			inode->i_op = &nfs_file_inode_operations;
-		else if (S_ISDIR(inode->i_mode))
-			inode->i_op = &nfs_dir_inode_operations;
-		else if (S_ISLNK(inode->i_mode))
-			inode->i_op = &nfs_symlink_inode_operations;
-		else if (S_ISCHR(inode->i_mode))
-			inode->i_op = &chrdev_inode_operations;
-		else if (S_ISBLK(inode->i_mode))
-			inode->i_op = &blkdev_inode_operations;
-		else if (S_ISFIFO(inode->i_mode))
+	if (S_ISREG(inode->i_mode))
+		inode->i_op = &nfs_file_inode_operations;
+	else if (S_ISDIR(inode->i_mode))
+		inode->i_op = &nfs_dir_inode_operations;
+	else if (S_ISLNK(inode->i_mode))
+		inode->i_op = &nfs_symlink_inode_operations;
+	else if (S_ISCHR(inode->i_mode))
+		inode->i_op = &chrdev_inode_operations;
+	else if (S_ISBLK(inode->i_mode))
+		inode->i_op = &blkdev_inode_operations;
+	else if (S_ISFIFO(inode->i_mode)) {
+		if (was_empty)
 			init_fifo(inode);
-		else
-			inode->i_op = NULL;
-	}
+	} else
+		inode->i_op = NULL;
 	nfs_lookup_cache_refresh(inode, fattr);
 }
 
diff -u --recursive --new-file v1.3.72/linux/fs/nfs/inode.c linux/fs/nfs/inode.c
--- v1.3.72/linux/fs/nfs/inode.c	Sun Mar 10 09:49:56 1996
+++ linux/fs/nfs/inode.c	Tue Mar 12 16:24:10 1996
@@ -50,19 +50,20 @@
  * The "read_inode" function doesn't actually do anything:
  * the real data is filled in later in nfs_fhget. Here we
  * just mark the cache times invalid, and zero out i_mode
- * (the latter makes "nfs_refresh_inode" do the right thing)
+ * (the latter makes "nfs_refresh_inode" do the right thing
+ * wrt pipe inodes)
  */
 static void nfs_read_inode(struct inode * inode)
 {
 	inode->i_mode = 0;
+	inode->i_op = NULL;
 	NFS_CACHEINV(inode);
 }
 
 static void nfs_put_inode(struct inode * inode)
 {
-#if 0
-	clear_inode(inode);
-#endif
+	if (inode->i_pipe)
+		clear_inode(inode);
 }
 
 void nfs_put_super(struct super_block *sb)
diff -u --recursive --new-file v1.3.72/linux/fs/super.c linux/fs/super.c
--- v1.3.72/linux/fs/super.c	Tue Mar  5 10:11:08 1996
+++ linux/fs/super.c	Mon Mar 11 18:09:16 1996
@@ -11,6 +11,7 @@
  * GK 2/5/95  -  Changed to support mounting the root fs via NFS
  *
  *  Added kerneld support: Jacques Gelinas and Bjorn Ekwall
+ *  Added change_root: Werner Almesberger & Hans Lermen, Feb '96
  */
 
 #include <stdarg.h>
@@ -35,6 +36,10 @@
 #include <linux/kerneld.h>
 #endif
  
+#ifdef CONFIG_ROOT_NFS
+#include <linux/nfs_fs.h>
+#endif
+
 extern void wait_for_keypress(void);
 extern struct file_operations * get_blkfops(unsigned int major);
 extern void blkdev_release (struct inode *);
@@ -43,10 +48,6 @@
 
 static int do_remount_sb(struct super_block *sb, int flags, char * data);
 
-#ifdef CONFIG_ROOT_NFS
-extern int nfs_root_mount(struct super_block *sb);
-#endif
-
 /* this is initialized in init/main.c */
 kdev_t ROOT_DEV;
 
@@ -482,12 +483,12 @@
 			kdevname(dev));
 }
 
-static int do_umount(kdev_t dev)
+static int do_umount(kdev_t dev,int unmount_root)
 {
 	struct super_block * sb;
 	int retval;
 	
-	if (dev==ROOT_DEV) {
+	if (dev==ROOT_DEV && !unmount_root) {
 		/*
 		 * Special case for "unmounting" root. We just try to remount
 		 * it readonly, and sync() the device.
@@ -581,7 +582,7 @@
 		iput(inode);
 		return -ENXIO;
 	}
-	if (!(retval = do_umount(dev)) && dev != ROOT_DEV) {
+	if (!(retval = do_umount(dev,0)) && dev != ROOT_DEV) {
 		blkdev_release (inode);
 		if (MAJOR(dev) == UNNAMED_MAJOR)
 			put_unnamed_dev(dev);
@@ -818,7 +819,7 @@
 	return retval;
 }
 
-void mount_root(void)
+static void do_mount_root(void)
 {
 	struct file_system_type * fs_type;
 	struct super_block * sb;
@@ -827,12 +828,18 @@
 	struct file filp;
 	int retval;
   
-	memset(super_blocks, 0, sizeof(super_blocks));
 #ifdef CONFIG_ROOT_NFS
+	if (MAJOR(ROOT_DEV) == UNNAMED_MAJOR)
+		if (nfs_root_init(nfs_root_name, nfs_root_addrs) < 0) {
+			printk(KERN_ERR "Root-NFS: Unable to contact NFS "
+			    "server for root fs, using /dev/fd0 instead\n");
+			ROOT_DEV = MKDEV(FLOPPY_MAJOR, 0);
+		}
 	if (MAJOR(ROOT_DEV) == UNNAMED_MAJOR) {
 		ROOT_DEV = 0;
 		if ((fs_type = get_fs_type("nfs"))) {
 			sb = &super_blocks[0];
+			while (sb->s_dev) sb++;
 			sb->s_dev = get_unnamed_dev();
 			sb->s_flags = root_mountflags & ~MS_RDONLY;
 			if (nfs_root_mount(sb) >= 0) {
@@ -873,15 +880,19 @@
 	else
 		filp.f_mode = 3; /* read write */
 	retval = blkdev_open(&d_inode, &filp);
-	if(retval == -EROFS){
+	if (retval == -EROFS) {
 		root_mountflags |= MS_RDONLY;
 		filp.f_mode = 1;
 		retval = blkdev_open(&d_inode, &filp);
 	}
-
-	for (fs_type = file_systems ; fs_type ; fs_type = fs_type->next) {
-		if(retval)
-			break;
+	if (retval)
+	        /*
+		 * Allow the user to distinguish between failed open
+		 * and bad superblock on root device.
+		 */
+		printk("VFS: Cannot open root device %s\n",
+		       kdevname(ROOT_DEV));
+	else for (fs_type = file_systems ; fs_type ; fs_type = fs_type->next) {
   		if (!fs_type->requires_dev)
   			continue;
   		sb = read_super(ROOT_DEV,fs_type->name,root_mountflags,NULL,1);
@@ -896,10 +907,75 @@
 				fs_type->name,
 				(sb->s_flags & MS_RDONLY) ? " readonly" : "");
 			vfsmnt = add_vfsmnt(ROOT_DEV, "rootfs", "/");
+			if (!vfsmnt)
+				panic("VFS: add_vfsmnt failed for root fs");
 			vfsmnt->mnt_sb = sb;
+			vfsmnt->mnt_flags = root_mountflags;
 			return;
 		}
 	}
 	panic("VFS: Unable to mount root fs on %s",
 		kdevname(ROOT_DEV));
 }
+
+
+void mount_root(void)
+{
+	memset(super_blocks, 0, sizeof(super_blocks));
+	do_mount_root();
+}
+
+
+#ifdef CONFIG_BLK_DEV_INITRD
+
+int change_root(kdev_t new_root_dev,const char *put_old)
+{
+	kdev_t old_root_dev;
+	struct vfsmount *vfsmnt;
+	struct inode *old_root,*old_pwd,*inode;
+	unsigned long old_fs;
+	int error;
+
+	old_root = current->fs->root;
+	old_pwd = current->fs->pwd;
+	old_root_dev = ROOT_DEV;
+	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 && (inode->i_count != 1 || inode->i_mount)) error = -EBUSY;
+	if (!error && !S_ISDIR(inode->i_mode)) error = -ENOTDIR;
+	iput(old_root); /* current->fs->root */
+	iput(old_pwd); /* current->fs->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 {
+			printk(KERN_NOTICE "okay\n");
+			invalidate_buffers(old_root_dev);
+		}
+		return umount_error ? error : 0;
+	}
+	iput(old_root); /* sb->s_covered */
+	remove_vfsmnt(old_root_dev);
+	vfsmnt = add_vfsmnt(old_root_dev,"old_rootfs",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_flags = vfsmnt->mnt_sb->s_flags;
+	}
+	inode->i_mount = old_root;
+	return 0;
+}
+
+#endif
diff -u --recursive --new-file v1.3.72/linux/fs/umsdos/inode.c linux/fs/umsdos/inode.c
--- v1.3.72/linux/fs/umsdos/inode.c	Fri Feb  9 17:53:07 1996
+++ linux/fs/umsdos/inode.c	Mon Mar 11 11:25:58 1996
@@ -404,8 +404,7 @@
 	printk ("UMSDOS Beta 0.6 (compatibility level %d.%d, fast msdos)\n"
 		,UMSDOS_VERSION,UMSDOS_RELEASE);
 	if (sb != NULL){
-		MSDOS_SB(sb)->dotsOK = 0;  /* disable hidden==dotfile */
-		MSDOS_SB(sb)->umsdos = 1;  /* Tell fat-support we're umsdos */
+		MSDOS_SB(sb)->options.dotsOK = 0;  /* disable hidden==dotfile */
 		sb->s_op = &umsdos_sops;
 		PRINTK (("umsdos_read_super %p\n",sb->s_mounted));
 		umsdos_setup_dir_inode (sb->s_mounted);
diff -u --recursive --new-file v1.3.72/linux/fs/umsdos/ioctl.c linux/fs/umsdos/ioctl.c
--- v1.3.72/linux/fs/umsdos/ioctl.c	Wed Feb 28 11:50:11 1996
+++ linux/fs/umsdos/ioctl.c	Mon Mar 11 11:25:58 1996
@@ -303,9 +303,9 @@
 					umsdos_dirent.uid and gid sets the owner and group.
 					umsdos_dirent.mode set the permissions flags.
 				*/
-				dir->i_sb->u.msdos_sb.fs_uid = data.umsdos_dirent.uid;
-				dir->i_sb->u.msdos_sb.fs_gid = data.umsdos_dirent.gid;
-				dir->i_sb->u.msdos_sb.fs_umask = data.umsdos_dirent.mode;
+				dir->i_sb->u.msdos_sb.options.fs_uid = data.umsdos_dirent.uid;
+				dir->i_sb->u.msdos_sb.options.fs_gid = data.umsdos_dirent.gid;
+				dir->i_sb->u.msdos_sb.options.fs_umask = data.umsdos_dirent.mode;
 				ret = 0;
 			}
 		}
diff -u --recursive --new-file v1.3.72/linux/fs/vfat/namei.c linux/fs/vfat/namei.c
--- v1.3.72/linux/fs/vfat/namei.c	Sun Mar 10 09:49:56 1996
+++ linux/fs/vfat/namei.c	Mon Mar 11 11:28:46 1996
@@ -76,32 +76,52 @@
 	NULL
 };
 
-static int parse_options(char *options,	char *uni_xlate, char *posix,
-			 char *numtail)
+static int parse_options(char *options,	struct fat_mount_options *opts)
 {
-	char *this_char,*value;
+	char *this_char,*value,save,*savep;
+	int ret;
 
-	*uni_xlate = *posix = 0;
-	*numtail = 1;
+	opts->unicode_xlate = opts->posixfs = 0;
+	opts->numtail = 1;
 
 	if (!options) return 1;
+	save = 0;
+	savep = NULL;
+	ret = 1;
 	for (this_char = strtok(options,","); this_char; this_char = strtok(NULL,",")) {
-		if ((value = strchr(this_char,'=')) != NULL)
+		if ((value = strchr(this_char,'=')) != NULL) {
+			save = *value;
+			savep = value;
 			*value++ = 0;
+		}
 		if (!strcmp(this_char,"uni_xlate")) {
-			if (value)
-				return 0;
-			*uni_xlate = 1;
+			if (value) {
+				ret = 0;
+			} else {
+				opts->unicode_xlate = 1;
+			}
 		}
 		else if (!strcmp(this_char,"posix")) {
-			if (value)
-				return 0;
-			*posix = 1;
+			if (value) {
+				ret = 0;
+			} else {
+				opts->posixfs = 1;
+			}
 		}
 		else if (!strcmp(this_char,"nonumtail")) {
-			if (value)
-				return 0;
-			*numtail = 0;
+			if (value) {
+				ret = 0;
+			} else {
+				opts->numtail = 0;
+			}
+		}
+		if (this_char != options)
+			*(this_char-1) = ',';
+		if (value) {
+			*savep = save;
+		}
+		if (ret == 0) {
+			return 0;
 		}
 	}
 	return 1;
@@ -111,26 +131,22 @@
 				    int silent)
 {
 	struct super_block *res;
-	char uni_xlate, posix, numtail;
   
 	MOD_INC_USE_COUNT;
 	
 	sb->s_op = &vfat_sops;
-	if (!parse_options((char *) data,&uni_xlate,&posix,&numtail)) {
+	res = fat_read_super(sb, data, silent);
+	if (res == NULL) {
 		sb->s_dev = 0;
 		MOD_DEC_USE_COUNT;
 		return NULL;
 	}
-	MSDOS_SB(sb)->unicode_xlate = uni_xlate;
-	MSDOS_SB(sb)->posix = posix;
-	MSDOS_SB(sb)->numtail = numtail;
 
-	res = fat_read_super(sb, data, silent);
-	if (res == NULL) {
+	if (!parse_options((char *) data, &(MSDOS_SB(sb)->options))) {
 		MOD_DEC_USE_COUNT;
 	} else {
-		MSDOS_SB(sb)->vfat = 1;
-		MSDOS_SB(sb)->dotsOK = 0;
+		MSDOS_SB(sb)->options.isvfat = 1;
+		MSDOS_SB(sb)->options.dotsOK = 0;
 	}
 
 	return res;
@@ -493,9 +509,9 @@
 	msdos_name[baselen] = '.';
 	strcpy(&msdos_name[baselen+1], ext);
 
-	totlen = baselen + extlen + 1;
+	totlen = baselen + extlen + (extlen > 0);
 	res = 0;
-	if (MSDOS_SB(dir->i_sb)->numtail == 0) {
+	if (MSDOS_SB(dir->i_sb)->options.numtail == 0) {
 		res = vfat_find(dir, msdos_name, totlen, 0, 0, 0, &sinfo);
 	}
 	i = 0;
@@ -704,7 +720,7 @@
 
 	PRINTK(("Entering vfat_build_slots: name=%s, len=%d\n", name, len));
 	de = (struct msdos_dir_entry *) ds;
-	xlate = MSDOS_SB(dir->i_sb)->unicode_xlate;
+	xlate = MSDOS_SB(dir->i_sb)->options.unicode_xlate;
 
 	*slots = 1;
 	*is_long = 0;
@@ -804,7 +820,7 @@
 	vf.len = len;
 	vf.new_filename = new_filename;
 	vf.found = 0;
-	vf.posix = MSDOS_SB(sb)->posix;
+	vf.posix = MSDOS_SB(sb)->options.posixfs;
 	res = fat_readdirx(dir,&fil,(void *)&vf,vfat_readdir_cb,NULL,1,find_long,0);
 	PRINTK(("vfat_find: Debug 1\n"));
 	if (res < 0) return res;
diff -u --recursive --new-file v1.3.72/linux/include/asm-alpha/stat.h linux/include/asm-alpha/stat.h
--- v1.3.72/linux/include/asm-alpha/stat.h	Fri Jun  2 13:51:17 1995
+++ linux/include/asm-alpha/stat.h	Mon Mar 11 11:12:17 1996
@@ -10,9 +10,9 @@
 	unsigned int	st_gid;
 	unsigned int	st_rdev;
 	long		st_size;
-	unsigned int	st_atime, st_res1;
-	unsigned int	st_mtime, st_res2;
-	unsigned int	st_ctime, st_res3;
+	unsigned long	st_atime;
+	unsigned long	st_mtime;
+	unsigned long	st_ctime;
 	unsigned int	st_blkize;
 	int		st_blocks;
 	unsigned int	st_flags;
@@ -28,9 +28,9 @@
 	unsigned int	st_gid;
 	unsigned int	st_rdev;
 	long		st_size;
-	unsigned int	st_atime, st_res1;
-	unsigned int	st_mtime, st_res2;
-	unsigned int	st_ctime, st_res3;
+	unsigned long	st_atime;
+	unsigned long	st_mtime;
+	unsigned long	st_ctime;
 	unsigned int	st_blksize;
 	int		st_blocks;
 	unsigned int	st_flags;
diff -u --recursive --new-file v1.3.72/linux/include/asm-i386/irq.h linux/include/asm-i386/irq.h
--- v1.3.72/linux/include/asm-i386/irq.h	Sun Mar 10 09:49:56 1996
+++ linux/include/asm-i386/irq.h	Sun Mar 10 09:28:56 1996
@@ -151,6 +151,7 @@
 	"pushfl\n\t" \
 	"cli\n\t" \
 	GET_PROCESSOR_ID \
+	"btsl $" STR(SMP_FROM_INT) ","SYMBOL_NAME_STR(smp_proc_in_lock)"(,%eax,4)\n\t" \
 	"1: " \
 	"lock\n\t" \
 	"btsl $0, "SYMBOL_NAME_STR(kernel_flag)"\n\t" \
@@ -178,6 +179,8 @@
 	"popl %eax\n\t"
 
 #define	LEAVE_KERNEL \
+	GET_PROCESSOR_ID \
+	"btrl $" STR(SMP_FROM_INT) ","SYMBOL_NAME_STR(smp_proc_in_lock)"(,%eax,4)\n\t" \
 	"pushfl\n\t" \
 	"cli\n\t" \
 	"decl "SYMBOL_NAME_STR(kernel_counter)"\n\t" \
@@ -290,6 +293,8 @@
 	"addl $8,%esp\n\t" \
 	"cli\n\t" \
 	UNBLK_##chip(mask) \
+	GET_PROCESSOR_ID \
+	"btrl $" STR(SMP_FROM_INT) ","SYMBOL_NAME_STR(smp_proc_in_lock)"(,%eax,4)\n\t" \
 	"decl "SYMBOL_NAME_STR(intr_count)"\n\t" \
 	"incl "SYMBOL_NAME_STR(syscall_count)"\n\t" \
 	"jmp ret_from_sys_call\n" \
diff -u --recursive --new-file v1.3.72/linux/include/asm-i386/smp.h linux/include/asm-i386/smp.h
--- v1.3.72/linux/include/asm-i386/smp.h	Tue Mar  5 10:11:08 1996
+++ linux/include/asm-i386/smp.h	Sun Mar 10 09:28:56 1996
@@ -200,6 +200,9 @@
 extern void smp_boot_cpus(void);
 extern void smp_store_cpu_info(int id);		/* Store per cpu info (like the initial udelay numbers */
 
+extern volatile unsigned long smp_proc_in_lock[NR_CPUS]; /* for computing process time */
+extern volatile unsigned long smp_process_available;
+
 /*
  *	APIC handlers: Note according to the Intel specification update
  *	you should put reads between APIC writes.
@@ -245,6 +248,8 @@
  
 #define PROC_CHANGE_PENALTY	20		/* Schedule penalty */
 
+#define SMP_FROM_INT		1
+#define SMP_FROM_SYSCALL	2
 
 #endif
 #endif
diff -u --recursive --new-file v1.3.72/linux/include/asm-i386/termios.h linux/include/asm-i386/termios.h
--- v1.3.72/linux/include/asm-i386/termios.h	Tue Feb 20 14:37:28 1996
+++ linux/include/asm-i386/termios.h	Sun Mar 10 09:28:56 1996
@@ -114,7 +114,7 @@
 #define VEOL2 16
 
 #ifdef __KERNEL__
-/*	intr=^C		quit=^|		erase=del	kill=^U
+/*	intr=^C		quit=^\		erase=del	kill=^U
 	eof=^D		vtime=\0	vmin=\1		sxtc=\0
 	start=^Q	stop=^S		susp=^Z		eol=\0
 	reprint=^R	discard=^U	werase=^W	lnext=^V
diff -u --recursive --new-file v1.3.72/linux/include/asm-sparc/termios.h linux/include/asm-sparc/termios.h
--- v1.3.72/linux/include/asm-sparc/termios.h	Tue Mar  5 10:11:11 1996
+++ linux/include/asm-sparc/termios.h	Sun Mar 10 09:28:56 1996
@@ -192,7 +192,7 @@
 #define VTIME    VEOL
 
 #ifdef __KERNEL__
-/*	intr=^C		quit=^|		erase=del	kill=^U
+/*	intr=^C		quit=^\		erase=del	kill=^U
 	eof/vmin=\1	eol/vtime=\0	eol2=\0		sxtc=\0
 	start=^Q	stop=^S		susp=^Z		dsusp=^Y
 	reprint=^R	discard=^U	werase=^W	lnext=^V
diff -u --recursive --new-file v1.3.72/linux/include/linux/acct.h linux/include/linux/acct.h
--- v1.3.72/linux/include/linux/acct.h	Thu Jan  1 02:00:00 1970
+++ linux/include/linux/acct.h	Mon Mar 11 09:39:34 1996
@@ -0,0 +1,29 @@
+#ifndef __LINUX_ACCT_H
+#define __LINUX_ACCT_H
+
+#define ACCT_COMM 16
+
+struct acct
+{
+	char	ac_comm[ACCT_COMM];	/* Accounting command name */
+	time_t	ac_utime;		/* Accounting user time */
+	time_t	ac_stime;		/* Accounting system time */
+	time_t	ac_etime;		/* Accounting elapsed time */
+	time_t	ac_btime;		/* Beginning time */
+	uid_t	ac_uid;			/* Accounting user ID */
+	gid_t	ac_gid;			/* Accounting group ID */
+	dev_t	ac_tty;			/* controlling tty */
+	char	ac_flag;		/* Accounting flag */
+	long	ac_minflt;		/* Accounting minor pagefaults */
+	long	ac_majflt;		/* Accounting major pagefaults */
+	long	ac_exitcode;		/* Accounting process exitcode */
+};
+
+#define AFORK	0001	/* has executed fork, but no exec */
+#define ASU	0002	/* used super-user privileges */
+#define ACORE	0004	/* dumped core */
+#define AXSIG	0010	/* killed by a signal */
+
+#define AHZ     100
+
+#endif
diff -u --recursive --new-file v1.3.72/linux/include/linux/ax25.h linux/include/linux/ax25.h
--- v1.3.72/linux/include/linux/ax25.h	Mon Dec 11 15:42:05 1995
+++ linux/include/linux/ax25.h	Sun Mar 10 09:28:56 1996
@@ -46,6 +46,8 @@
 #define	AX25_BACKOFF	6
 #define	AX25_EXTSEQ	7
 #define	AX25_HDRINCL	8
+#define AX25_IDLE	9
+#define AX25_PACLEN	10
 
 #define SIOCAX25GETUID		(SIOCPROTOPRIVATE)
 #define SIOCAX25ADDUID		(SIOCPROTOPRIVATE+1)
@@ -74,6 +76,8 @@
 #define	AX25_VALUES_T3		10	/* Default T3 timeout value */
 #define	AX25_VALUES_N2		11	/* Default N2 value */
 #define	AX25_VALUES_DIGI	12	/* Digipeat mode */
+#define AX25_VALUES_IDLE	13	/* mode vc idle timer */
+#define AX25_VALUES_PACLEN	14	/* AX.25 MTU */
 #define	AX25_MAX_VALUES		20
 
 struct ax25_parms_struct
diff -u --recursive --new-file v1.3.72/linux/include/linux/blk.h linux/include/linux/blk.h
--- v1.3.72/linux/include/linux/blk.h	Wed Feb 28 11:50:11 1996
+++ linux/include/linux/blk.h	Tue Mar 12 16:10:39 1996
@@ -96,6 +96,16 @@
 extern int rd_prompt;		/* 1 = prompt for ramdisk, 0 = don't prompt */
 extern int rd_image_start;	/* starting block # of image */
 
+#ifdef CONFIG_BLK_DEV_INITRD
+
+#define INITRD_MINOR 250 /* shouldn't collide with /dev/ram* too soon ... */
+
+extern unsigned long initrd_start,initrd_end;
+extern int mount_initrd; /* zero if initrd should not be mounted */
+void initrd_init(void);
+
+#endif
+
 #define RO_IOCTLS(dev,where) \
   case BLKROSET: if (!suser()) return -EACCES; \
 		 set_device_ro((dev),get_fs_long((long *) (where))); return 0; \
diff -u --recursive --new-file v1.3.72/linux/include/linux/cd1400.h linux/include/linux/cd1400.h
--- v1.3.72/linux/include/linux/cd1400.h	Fri Sep 15 11:13:02 1995
+++ linux/include/linux/cd1400.h	Mon Mar 11 11:20:33 1996
@@ -3,7 +3,7 @@
 /*
  *	cd1400.h  -- cd1400 UART hardware info.
  *
- *	Copyright (C) 1994,1995  Greg Ungerer (gerg@stallion.oz.au).
+ *	Copyright (C) 1994-1996  Greg Ungerer (gerg@stallion.oz.au).
  *
  *	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
@@ -21,7 +21,6 @@
  */
 
 /*****************************************************************************/
-
 #ifndef	_CD1400_H
 #define	_CD1400_H
 /*****************************************************************************/
@@ -31,8 +30,6 @@
  */
 #define	CD1400_PORTS		4
 
-#define	CD1400_CLKHZ		25000000
-
 /*
  *	Define the cd1400 uarts internal FIFO sizes.
  */
@@ -260,6 +257,7 @@
 #define	ST_SCHAR3	0x30
 #define	ST_SCHAR4	0x40
 #define	ST_RANGE	0x70
+#define	ST_SCHARMASK	0x70
 #define	ST_TIMEOUT	0x80
 
 #define	MISR_DCD	0x80
diff -u --recursive --new-file v1.3.72/linux/include/linux/cdk.h linux/include/linux/cdk.h
--- v1.3.72/linux/include/linux/cdk.h	Fri Feb 16 11:34:11 1996
+++ linux/include/linux/cdk.h	Mon Mar 11 11:20:33 1996
@@ -21,7 +21,6 @@
  */
 
 /*****************************************************************************/
-
 #ifndef	_CDK_H
 #define	_CDK_H
 /*****************************************************************************/
@@ -192,6 +191,7 @@
 #define	A_GETSTATS	(ASYCMD | 17)
 #define	A_RQSTATE	(ASYCMD | 18)
 #define	A_FLOWSTATE	(ASYCMD | 19)
+#define	A_CLEARSTATS	(ASYCMD | 20)
 
 /*
  *	Define those arguments used for simple commands.
@@ -384,6 +384,8 @@
 	unsigned long	rxringq;
 	unsigned long	txmsgs;
 	unsigned long	rxmsgs;
+	unsigned long	txflushes;
+	unsigned long	rxflushes;
 	unsigned long	overruns;
 	unsigned long	framing;
 	unsigned long	parity;
@@ -403,6 +405,7 @@
 	unsigned long	rxbreaks;
 	unsigned long	signals;
 	unsigned long	state;
+	unsigned long	hwid;
 } asystats_t;
 
 /*****************************************************************************/
diff -u --recursive --new-file v1.3.72/linux/include/linux/comstats.h linux/include/linux/comstats.h
--- v1.3.72/linux/include/linux/comstats.h	Thu Jan  1 02:00:00 1970
+++ linux/include/linux/comstats.h	Mon Mar 11 11:20:33 1996
@@ -0,0 +1,108 @@
+/*****************************************************************************/
+
+/*
+ *	comstats.h  -- Serial Port Stats.
+ *
+ *	Copyright (C) 1994-1996  Greg Ungerer (gerg@stallion.oz.au).
+ *
+ *	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.
+ */
+
+/*****************************************************************************/
+#ifndef	_COMSTATS_H
+#define	_COMSTATS_H
+/*****************************************************************************/
+
+/*
+ *	Serial port stats structure. The structure itself is UART
+ *	independent, but some fields may be UART/driver specific (for
+ *	example state).
+ */
+
+typedef struct {
+	unsigned long	brd;
+	unsigned long	panel;
+	unsigned long	port;
+	unsigned long	hwid;
+	unsigned long	type;
+	unsigned long	txtotal;
+	unsigned long	rxtotal;
+	unsigned long	txbuffered;
+	unsigned long	rxbuffered;
+	unsigned long	rxoverrun;
+	unsigned long	rxparity;
+	unsigned long	rxframing;
+	unsigned long	rxlost;
+	unsigned long	txbreaks;
+	unsigned long	rxbreaks;
+	unsigned long	txxon;
+	unsigned long	txxoff;
+	unsigned long	rxxon;
+	unsigned long	rxxoff;
+	unsigned long	txctson;
+	unsigned long	txctsoff;
+	unsigned long	rxrtson;
+	unsigned long	rxrtsoff;
+	unsigned long	modem;
+	unsigned long	state;
+	unsigned long	flags;
+	unsigned long	ttystate;
+	unsigned long	cflags;
+	unsigned long	iflags;
+	unsigned long	oflags;
+	unsigned long	lflags;
+	unsigned long	signals;
+} comstats_t;
+
+
+/*
+ *	Board stats structure. Returns usefull info about the board.
+ */
+
+#define	COM_MAXPANELS	8
+
+typedef struct {
+	unsigned long	panel;
+	unsigned long	type;
+	unsigned long	hwid;
+	unsigned long	nrports;
+} companel_t;
+
+typedef struct {
+	unsigned long	brd;
+	unsigned long	type;
+	unsigned long	hwid;
+	unsigned long	state;
+	unsigned long	ioaddr;
+	unsigned long	ioaddr2;
+	unsigned long	memaddr;
+	unsigned long	irq;
+	unsigned long	nrpanels;
+	unsigned long	nrports;
+	companel_t	panels[COM_MAXPANELS];
+} combrd_t;
+
+
+/*
+ *	Define the ioctl operations for stats stuff.
+ */
+#include <linux/ioctl.h>
+
+#define	COM_GETPORTSTATS	_IO('c',30)
+#define	COM_CLRPORTSTATS	_IO('c',31)
+#define	COM_GETBRDSTATS		_IO('c',32)
+
+/*****************************************************************************/
+#endif
diff -u --recursive --new-file v1.3.72/linux/include/linux/fs.h linux/include/linux/fs.h
--- v1.3.72/linux/include/linux/fs.h	Wed Feb 28 11:50:11 1996
+++ linux/include/linux/fs.h	Tue Mar 12 16:10:39 1996
@@ -6,6 +6,7 @@
  * structures etc.
  */
 
+#include <linux/config.h>
 #include <linux/linkage.h>
 #include <linux/limits.h>
 #include <linux/wait.h>
@@ -490,6 +491,7 @@
 extern struct inode_operations chrdev_inode_operations;
 
 extern void init_fifo(struct inode * inode);
+struct inode_operations fifo_inode_operations;
 
 extern struct file_operations connecting_fifo_fops;
 extern struct file_operations read_fifo_fops;
@@ -607,6 +609,11 @@
 
 extern void show_buffers(void);
 extern void mount_root(void);
+
+#ifdef CONFIG_BLK_DEV_INITRD
+extern kdev_t real_root_dev;
+extern int change_root(kdev_t new_root_dev,const char *put_old);
+#endif
 
 extern int char_read(struct inode *, struct file *, char *, int);
 extern int block_read(struct inode *, struct file *, char *, int);
diff -u --recursive --new-file v1.3.72/linux/include/linux/kernel.h linux/include/linux/kernel.h
--- v1.3.72/linux/include/linux/kernel.h	Fri Feb 23 13:54:38 1996
+++ linux/include/linux/kernel.h	Mon Mar 11 09:39:34 1996
@@ -58,16 +58,9 @@
 	__attribute__ ((format (printf, 1, 2)));
 
 /*
- * This is defined as a macro, but at some point this might become a
- * real subroutine that sets a flag if it returns true (to do
- * BSD-style accounting where the process is flagged if it uses root
- * privs).  The implication of this is that you should do normal
- * permissions checks first, and check suser() last.
- *
  * "suser()" checks against the effective user id, while "fsuser()"
  * is used for file permission checking and checks against the fsuid..
  */
-#define suser() (current->euid == 0)
 #define fsuser() (current->fsuid == 0)
 
 #endif /* __KERNEL__ */
diff -u --recursive --new-file v1.3.72/linux/include/linux/msdos_fs_sb.h linux/include/linux/msdos_fs_sb.h
--- v1.3.72/linux/include/linux/msdos_fs_sb.h	Sun Mar 10 09:49:56 1996
+++ linux/include/linux/msdos_fs_sb.h	Mon Mar 11 11:25:58 1996
@@ -5,6 +5,23 @@
  * MS-DOS file system in-core superblock data
  */
 
+struct fat_mount_options {
+	uid_t fs_uid;
+	gid_t fs_gid;
+	unsigned short fs_umask;
+	unsigned char name_check; /* r = relaxed, n = normal, s = strict */
+	unsigned char conversion; /* b = binary, t = text, a = auto */
+	unsigned quiet:1,         /* set = fake successful chmods and chowns */
+		 showexec:1,      /* set = only set x bit for com/exe/bat */
+		 sys_immutable:1, /* set = system files are immutable */
+		 dotsOK:1,        /* set = hidden and system files are named '.filename' */
+		 isvfat:1,        /* 0=no vfat long filename support, 1=vfat support */
+		 unicode_xlate:1, /* create escape sequences for unhandled Unicode */
+		 posixfs:1,       /* Allow names like makefile and Makefile to coexist */
+		 numtail:1;       /* Does first alias have a numeric '~1' type tail? */
+};
+
+
 struct msdos_sb_info {
 	unsigned short cluster_size; /* sectors/cluster */
 	unsigned char fats,fat_bits; /* number of FATs, FAT bits (12 or 16) */
@@ -12,26 +29,11 @@
 	unsigned short dir_start,dir_entries; /* root dir start & entries */
 	unsigned short data_start;   /* first data sector */
 	unsigned long clusters;      /* number of clusters */
-	uid_t fs_uid;
-	gid_t fs_gid;
-	int quiet; /* fake successful chmods and chowns */
-	unsigned short fs_umask;
-	unsigned char name_check; /* r = relaxed, n = normal, s = strict */
-	unsigned char conversion; /* b = binary, t = text, a = auto */
 	struct wait_queue *fat_wait;
 	int fat_lock;
-	int prev_free; /* previously returned free cluster number */
-	int free_clusters; /* -1 if undefined */
-	char dotsOK;
-	char showexec; /* 1 = only set x bit for com/exe/bat */
-	char sys_immutable; /* system files are immutable */
-	int umsdos; /* 1 if mounted by umsdos, 0 if not */
-
-	/* vfat specific flags follow */
-	int vfat; /* 0=no vfat long filename support, 1=vfat support */
-	char unicode_xlate; /* create escape sequences for unhandled Unicode */
-	char posix; /* Allow names like makefile and Makefile to coexist */
-	char numtail; /* Does first alias have a numeric '~1' type tail? */
+	int prev_free;               /* previously returned free cluster number */
+	int free_clusters;           /* -1 if undefined */
+	struct fat_mount_options options;
 };
 
 #endif
diff -u --recursive --new-file v1.3.72/linux/include/linux/nfs_fs.h linux/include/linux/nfs_fs.h
--- v1.3.72/linux/include/linux/nfs_fs.h	Sun Mar 10 09:49:57 1996
+++ linux/include/linux/nfs_fs.h	Sat Mar  9 13:31:43 1996
@@ -126,6 +126,16 @@
 
 extern int nfs_mmap(struct inode * inode, struct file * file, struct vm_area_struct * vma);
 
+/* NFS root */
+
+#define NFS_ROOT_NAME_LEN	256
+#define NFS_ROOT_ADDRS_LEN	128
+
+extern int nfs_root_mount(struct super_block *sb);
+extern int nfs_root_init(char *nfsname, char *nfsaddrs);
+extern char nfs_root_name[];
+extern char nfs_root_addrs[];
+
 #endif /* __KERNEL__ */
 
 #endif
diff -u --recursive --new-file v1.3.72/linux/include/linux/nfs_fs_i.h linux/include/linux/nfs_fs_i.h
--- v1.3.72/linux/include/linux/nfs_fs_i.h	Tue Feb 20 14:37:28 1996
+++ linux/include/linux/nfs_fs_i.h	Tue Mar 12 16:08:22 1996
@@ -2,11 +2,13 @@
 #define _NFS_FS_I
 
 #include <linux/nfs.h>
+#include <linux/pipe_fs_i.h>
 
 /*
  * nfs fs inode data in memory
  */
 struct nfs_inode_info {
+	struct pipe_inode_info pipeinfo;
 	struct nfs_fh fhandle;
 	/*
 	 * read_cache_jiffies is when we started read-caching this inode,
diff -u --recursive --new-file v1.3.72/linux/include/linux/pipe_fs_i.h linux/include/linux/pipe_fs_i.h
--- v1.3.72/linux/include/linux/pipe_fs_i.h	Wed Feb 28 11:50:13 1996
+++ linux/include/linux/pipe_fs_i.h	Tue Mar 12 16:08:22 1996
@@ -1,9 +1,7 @@
 #ifndef _LINUX_PIPE_FS_I_H
 #define _LINUX_PIPE_FS_I_H
-#include <linux/nfs_fs_i.h>
 
 struct pipe_inode_info {
-	struct nfs_inode_info dummy;   /* NFS/fifo conflict workaround */
 	struct wait_queue * wait;
 	char * base;
 	unsigned int start;
diff -u --recursive --new-file v1.3.72/linux/include/linux/sched.h linux/include/linux/sched.h
--- v1.3.72/linux/include/linux/sched.h	Sat Mar  2 10:43:45 1996
+++ linux/include/linux/sched.h	Tue Mar 12 16:10:39 1996
@@ -259,6 +259,10 @@
 					/* Not implemented yet, only for 486*/
 #define PF_PTRACED	0x00000010	/* set if ptrace (0) has been called. */
 #define PF_TRACESYS	0x00000020	/* tracing system calls */
+#define PF_FORKNOEXEC	0x00000040	/* forked but didn't exec */
+#define PF_SUPERPREV	0x00000100	/* used super-user privileges */
+#define PF_DUMPCORE	0x00000200	/* dumped core */
+#define PF_SIGNALED	0x00000400	/* killed by a signal */
 
 #define PF_STARTING	0x00000100	/* being created */
 #define PF_EXITING	0x00000200	/* getting shut down */
@@ -348,6 +352,19 @@
 		       const char *device,
 		       void *dev_id);
 extern void free_irq(unsigned int irq, void *dev_id);
+
+/*
+ * This has now become a routine instead of a macro, it sets a flag if
+ * it returns true (to do BSD-style accounting where the process is flagged
+ * if it uses root privs). The implication of this is that you should do
+ * normal permissions checks first, and check suser() last.
+ */
+extern inline int suser(void)
+{
+	if (current->euid == 0)
+		current->flags |= PF_SUPERPREV;
+	return (current->euid == 0);
+}
 
 extern void copy_thread(int, unsigned long, unsigned long, struct task_struct *, struct pt_regs *);
 extern void flush_thread(void);
diff -u --recursive --new-file v1.3.72/linux/include/linux/skbuff.h linux/include/linux/skbuff.h
--- v1.3.72/linux/include/linux/skbuff.h	Tue Mar  5 10:11:13 1996
+++ linux/include/linux/skbuff.h	Tue Mar 12 16:10:49 1996
@@ -303,7 +303,8 @@
  *	Insert a packet before another one in a list.
  */
 
-extern __inline__ void __skb_insert(struct sk_buff *next, struct sk_buff *newsk)
+extern __inline__ void __skb_insert(struct sk_buff *next, struct sk_buff *newsk,
+	struct sk_buff_head * list)
 {
 	struct sk_buff * prev = next->prev;
 
@@ -311,8 +312,8 @@
 	newsk->prev = prev;
 	next->prev = newsk;
 	prev->next = newsk;
-	newsk->list = next->list;
-	newsk->list->qlen++;
+	newsk->list = list;
+	list->qlen++;
 }
 
 extern __inline__ void skb_insert(struct sk_buff *old, struct sk_buff *newsk)
@@ -321,7 +322,7 @@
 
 	save_flags(flags);
 	cli();
-	__skb_insert(old, newsk);
+	__skb_insert(old, newsk, old->list);
 	restore_flags(flags);
 }
 
@@ -329,7 +330,8 @@
  *	Place a packet after a given packet in a list.
  */
 
-extern __inline__ void __skb_append(struct sk_buff *prev, struct sk_buff *newsk)
+extern __inline__ void __skb_append(struct sk_buff *prev, struct sk_buff *newsk,
+	struct sk_buff_head * list)
 {
 	struct sk_buff * next = prev->next;
 
@@ -337,8 +339,8 @@
 	newsk->prev = prev;
 	next->prev = newsk;
 	prev->next = newsk;
-	newsk->list = prev->list;
-	newsk->list->qlen++;
+	newsk->list = list;
+	list->qlen++;
 }
 
 extern __inline__ void skb_append(struct sk_buff *old, struct sk_buff *newsk)
@@ -347,7 +349,7 @@
 
 	save_flags(flags);
 	cli();
-	__skb_append(old, newsk);
+	__skb_append(old, newsk, old->list);
 	restore_flags(flags);
 }
 
diff -u --recursive --new-file v1.3.72/linux/include/linux/sysctl.h linux/include/linux/sysctl.h
--- v1.3.72/linux/include/linux/sysctl.h	Sun Mar 10 09:49:57 1996
+++ linux/include/linux/sysctl.h	Sun Mar 10 10:06:09 1996
@@ -56,6 +56,9 @@
 #define KERN_MAXID	13
 #define KERN_SECURELVL	14	/* int: system security level */
 #define KERN_PANIC	15	/* int: panic timeout */
+#define KERN_REALROOTDEV 16	/* real root device to mount after initrd */
+#define KERN_NFSRNAME	17	/* NFS root name */
+#define KERN_NFSRADDRS	18	/* NFS root addresses */
 
 /* CTL_VM names: */
 #define VM_SWAPCTL	1	/* struct: Set vm swapping control */
diff -u --recursive --new-file v1.3.72/linux/include/net/ax25.h linux/include/net/ax25.h
--- v1.3.72/linux/include/net/ax25.h	Tue Mar  5 10:11:13 1996
+++ linux/include/net/ax25.h	Tue Mar 12 16:10:50 1996
@@ -124,6 +124,8 @@
 #define	AX25_DEF_T2		3
 #define	AX25_DEF_T3		300
 #define	AX25_DEF_N2		10
+#define AX25_DEF_IDLE		20
+#define AX25_DEF_PACLEN		256
 #define	AX25_DEF_DIGI		(AX25_DIGI_INBAND|AX25_DIGI_XBAND)
 
 typedef struct ax25_uid_assoc {
@@ -148,8 +150,9 @@
 	unsigned short		vs, vr, va;
 	unsigned char		condition, backoff;
 	unsigned char		n2, n2count;
-	unsigned short		t1, t2, t3, rtt;
-	unsigned short		t1timer, t2timer, t3timer;
+	unsigned short		t1, t2, t3, idle, rtt;
+	unsigned short		t1timer, t2timer, t3timer, idletimer;
+	unsigned short		paclen;
 	unsigned short		fragno, fraglen;
 	ax25_digi		*digipeat;
 	struct sk_buff_head	write_queue;
diff -u --recursive --new-file v1.3.72/linux/init/main.c linux/init/main.c
--- v1.3.72/linux/init/main.c	Sat Mar  2 10:43:45 1996
+++ linux/init/main.c	Sat Mar  9 13:31:43 1996
@@ -4,6 +4,7 @@
  *  Copyright (C) 1991, 1992  Linus Torvalds
  *
  *  GK 2/5/95  -  Changed to support mounting root fs via NFS
+ *  Added initrd & change_root: Werner Almesberger & Hans Lermen, Feb '96
  */
 
 #define __KERNEL_SYSCALLS__
@@ -16,6 +17,7 @@
 #include <linux/fcntl.h>
 #include <linux/config.h>
 #include <linux/sched.h>
+#include <linux/kernel.h>
 #include <linux/tty.h>
 #include <linux/head.h>
 #include <linux/unistd.h>
@@ -29,9 +31,13 @@
 #include <linux/hdreg.h>
 #include <linux/mm.h>
 #include <linux/major.h>
+#include <linux/blk.h>
 #ifdef CONFIG_APM
 #include <linux/apm_bios.h>
 #endif
+#ifdef CONFIG_ROOT_NFS
+#include <linux/nfs_fs.h>
+#endif
 
 #include <asm/bugs.h>
 
@@ -115,6 +121,9 @@
 static void ramdisk_start_setup(char *str, int *ints);
 static void load_ramdisk(char *str, int *ints);
 static void prompt_ramdisk(char *str, int *ints);
+#ifdef CONFIG_BLK_DEV_INITRD
+static void no_initrd(char *s,int *ints);
+#endif
 #endif CONFIG_BLK_DEV_RAM
 #ifdef CONFIG_ISDN_DRV_ICN
 extern void icn_setup(char *str, int *ints);
@@ -144,14 +153,17 @@
 extern int rd_doload;		/* 1 = load ramdisk, 0 = don't load */
 extern int rd_prompt;		/* 1 = prompt for ramdisk, 0 = don't prompt */
 extern int rd_image_start;	/* starting block # of image */
+#ifdef CONFIG_BLK_DEV_INITRD
+kdev_t real_root_dev;
+#endif
 #endif
 
 int root_mountflags = MS_RDONLY;
 char *execute_command = 0;
 
 #ifdef CONFIG_ROOT_NFS
-char nfs_root_name[256] = { NFS_ROOT };
-char nfs_root_addrs[128] = { "" };
+char nfs_root_name[NFS_ROOT_NAME_LEN] = { NFS_ROOT };
+char nfs_root_addrs[NFS_ROOT_ADDRS_LEN] = { "" };
 #endif
 
 extern void dquot_init(void);
@@ -201,6 +213,9 @@
 	{ "ramdisk_start=", ramdisk_start_setup },
 	{ "load_ramdisk=", load_ramdisk },
 	{ "prompt_ramdisk=", prompt_ramdisk },
+#ifdef CONFIG_BLK_DEV_INITRD
+	{ "noinitrd", no_initrd },
+#endif
 #endif
 	{ "swap=", swap_setup },
 	{ "buff=", buff_setup },
@@ -423,9 +438,9 @@
 {
 	char *next;
 	char *devnames[] = { "nfs", "hda", "hdb", "hdc", "hdd", "sda", "sdb",
-		"sdc", "sdd", "sde", "fd", "xda", "xdb", NULL };
+		"sdc", "sdd", "sde", "fd", "xda", "xdb", "ram", NULL };
 	int devnums[]    = { 0x0FF, 0x300, 0x340, 0x1600, 0x1640, 0x800,
-		0x810, 0x820, 0x830, 0x840, 0x200, 0xD00, 0xD40, 0};
+		0x810, 0x820, 0x830, 0x840, 0x200, 0xD00, 0xD40, 0x100, 0};
 	int args, envs;
 	if (!*line)
 		return;
@@ -663,6 +678,13 @@
 	memory_start = inode_init(memory_start,memory_end);
 	memory_start = file_table_init(memory_start,memory_end);
 	memory_start = name_cache_init(memory_start,memory_end);
+#ifdef CONFIG_BLK_DEV_INITRD
+	if (initrd_start && initrd_start < memory_start) {
+		printk(KERN_CRIT "initrd overwritten (0x%08lx < 0x%08lx) - "
+		    "disabling it.\n",initrd_start,memory_start);
+		initrd_start = 0;
+	}
+#endif
 	mem_init(memory_start,memory_end);
 	buffer_init();
 	sock_init();
@@ -729,15 +751,42 @@
 	return execve(shell, argv, envp);
 }
 
+#ifdef CONFIG_BLK_DEV_INITRD
+static int do_linuxrc(void * shell)
+{
+	static char *argv[] = { "linuxrc", NULL, };
+
+	close(0);close(1);close(2);
+	setsid();
+	(void) open("/dev/tty1",O_RDWR,0);
+	(void) dup(0);
+	(void) dup(0);
+	return execve(shell, argv, envp_init);
+}
+
+static void no_initrd(char *s,int *ints)
+{
+	mount_initrd = 0;
+}
+#endif
+
 static int init(void * unused)
 {
 	int pid,i;
+#ifdef CONFIG_BLK_DEV_INITRD
+	int real_root_mountflags;
+#endif
 
 	/* Launch bdflush from here, instead of the old syscall way. */
 	kernel_thread(bdflush, NULL, 0);
 	/* Start the background pageout daemon. */
 	kernel_thread(kswapd, NULL, 0);
 
+#ifdef CONFIG_BLK_DEV_INITRD
+	real_root_dev = ROOT_DEV;
+	real_root_mountflags = root_mountflags;
+	if (initrd_start && mount_initrd) root_mountflags &= ~MS_RDONLY;
+#endif
 	setup();
 
 #ifdef __SMP__
@@ -764,6 +813,23 @@
 	}
 	#endif
 
+#ifdef CONFIG_BLK_DEV_INITRD
+	root_mountflags = real_root_mountflags;
+	if (ROOT_DEV != real_root_dev && ROOT_DEV == MKDEV(RAMDISK_MAJOR,0)) {
+		int error;
+
+		pid = kernel_thread(do_linuxrc, "/linuxrc", SIGCHLD);
+		if (pid>0)
+			while (pid != wait(&i));
+		if (real_root_dev != MKDEV(RAMDISK_MAJOR, 0)) {
+			error = change_root(real_root_dev,"/initrd");
+			if (error)
+				printk(KERN_ERR "Change root to /initrd: "
+				    "error %d\n",error);
+		}
+	}
+#endif
+
 	(void) open("/dev/tty1",O_RDWR,0);
 	(void) dup(0);
 	(void) dup(0);
@@ -778,7 +844,7 @@
 		if (pid>0)
 			while (pid != wait(&i))
 				/* nothing */;
-		}
+	}
 
 	while (1) {
 		pid = kernel_thread(do_shell,
diff -u --recursive --new-file v1.3.72/linux/ipc/msg.c linux/ipc/msg.c
--- v1.3.72/linux/ipc/msg.c	Wed Feb 28 11:50:14 1996
+++ linux/ipc/msg.c	Sat Mar  9 15:41:12 1996
@@ -30,7 +30,10 @@
 static int max_msqid = 0;
 static struct wait_queue *msg_lock = NULL;
 static int kerneld_msqid = -1;
-static int kerneld_pid;
+
+#define MAX_KERNELDS 20
+static int kerneld_arr[MAX_KERNELDS];
+static int n_kernelds = 0;
 
 void msg_init (void)
 {
@@ -152,8 +155,37 @@
 	return 0;
 }
 
+/*
+ * Take care of missing kerneld, especially in case of multiple daemons
+ */
+#define KERNELD_TIMEOUT 1 * (HZ)
+#define DROP_TIMER if ((msgflg & IPC_KERNELD) && kd_timer.next && kd_timer.prev) del_timer(&kd_timer)
+
+static void kd_timeout(unsigned long msgid)
+{
+	struct msqid_ds *msq;
+	struct msg *tmsg;
+
+	msq = msgque [ (unsigned int) kerneld_msqid % MSGMNI ];
+	if (msq == IPC_NOID || msq == IPC_UNUSED)
+		return;
+
+	for (tmsg = msq->msg_first; tmsg; tmsg = tmsg->msg_next)
+		if (*(long *)(tmsg->msg_spot) == msgid)
+			break;
+	if (tmsg) { /* still there! */
+		struct kerneld_msg kmsp = { msgid, -ENODEV, "" };
+
+		printk(KERN_ALERT "Ouch, kerneld timed out, message failed\n");
+		real_msgsnd(kerneld_msqid, (struct msgbuf *)&kmsp,
+			sizeof(long),
+			S_IRUSR | S_IWUSR | IPC_KERNELD | MSG_NOERROR);
+	}
+}
+
 static int real_msgrcv (int msqid, struct msgbuf *msgp, size_t msgsz, long msgtyp, int msgflg)
 {
+	struct timer_list kd_timer;
 	struct msqid_ds *msq;
 	struct ipc_perm *ipcp;
 	struct msg *tmsg, *leastp = NULL;
@@ -180,6 +212,16 @@
 		return -EINVAL;
 	ipcp = &msq->msg_perm; 
 
+	/*
+	 * Start timer for missing kerneld
+	 */
+	if (msgflg & IPC_KERNELD) {
+		kd_timer.data = (unsigned long)msgtyp;
+		kd_timer.expires = jiffies + KERNELD_TIMEOUT;
+		kd_timer.function = kd_timeout;
+		add_timer(&kd_timer);
+	}
+
 	/* 
 	 *  find message of correct type.
 	 *  msgtyp = 0 => get first.
@@ -224,6 +266,7 @@
 		}
 		
 		if (nmsg) { /* done finding a message */
+			DROP_TIMER;
 			if ((msgsz < nmsg->msg_ts) && !(msgflg & MSG_NOERROR))
 				return -E2BIG;
 			msgsz = (msgsz > nmsg->msg_ts)? nmsg->msg_ts : msgsz;
@@ -274,11 +317,16 @@
 			kfree(nmsg);
 			return msgsz;
 		} else {  /* did not find a message */
-			if (msgflg & IPC_NOWAIT)
+			if (msgflg & IPC_NOWAIT) {
+				DROP_TIMER;
 				return -ENOMSG;
-			if (current->signal & ~current->blocked)
+			}
+			if (current->signal & ~current->blocked) {
+				DROP_TIMER;
 				return -EINTR; 
+			}
 			if (intr_count) {
+				DROP_TIMER;
 				/* Won't happen... */
 				printk("Ouch, kerneld:msgrcv wants to sleep at interrupt!\n");
 				return -EINTR;
@@ -286,6 +334,7 @@
 			interruptible_sleep_on (&msq->rwait);
 		}
 	} /* end while */
+	DROP_TIMER;
 	return -1;
 }
 
@@ -371,12 +420,20 @@
 	 * and a designated kerneld message queue is created/refered to
 	 */
 	if ((msgflg & IPC_KERNELD)) {
+		int i;
 		if (!suser())
 			return -EPERM;
 		if ((kerneld_msqid == -1) && (kerneld_msqid =
-				newque(IPC_PRIVATE, msgflg & S_IRWXU)) >= 0)
-			kerneld_pid = current->pid;
-		return kerneld_msqid;
+				newque(IPC_PRIVATE, msgflg & S_IRWXU)) < 0)
+			return -ENOSPC;
+		for (i = 0; i < MAX_KERNELDS; ++i) {
+			if (kerneld_arr[i] == 0) {
+				kerneld_arr[i] = current->pid;
+				++n_kernelds;
+				return kerneld_msqid;
+			}
+		}
+		return -ENOSPC;
 	}
 	/* else it is a "normal" request */
 	if (key == IPC_PRIVATE) 
@@ -545,7 +602,7 @@
 		 * mark it as non-existant
 		 */
 		if ((kerneld_msqid >= 0) && (msqid == kerneld_msqid))
-			kerneld_pid = kerneld_msqid = -1;
+			kerneld_msqid = -1;
 		freeque (id); 
 		return 0;
 	default:
@@ -558,12 +615,23 @@
  * so that if they are terminated, a call from do_exit
  * will minimize the possibility of orphaned received
  * messages in the queue.  For now we just make sure
- * that the queue is shut down whenever kerneld dies.
+ * that the queue is shut down whenever all kernelds have died.
  */
 void kerneld_exit(void)
 {
-        if ((current->pid == kerneld_pid) && (kerneld_msqid != -1))
-                sys_msgctl(kerneld_msqid, IPC_RMID, NULL);
+	int i;
+
+        if (kerneld_msqid == -1)
+		return;
+	for (i = 0; i < MAX_KERNELDS; ++i) {
+		if (kerneld_arr[i] == current->pid) {
+			kerneld_arr[i] = 0;
+			--n_kernelds;
+			if (n_kernelds == 0)
+				sys_msgctl(kerneld_msqid, IPC_RMID, NULL);
+			break;
+		}
+	}
 }
 
 /*
diff -u --recursive --new-file v1.3.72/linux/kernel/exit.c linux/kernel/exit.c
--- v1.3.72/linux/kernel/exit.c	Sat Feb 17 16:02:56 1996
+++ linux/kernel/exit.c	Mon Mar 11 09:39:34 1996
@@ -18,6 +18,7 @@
 
 #include <asm/segment.h>
 extern void sem_exit (void);
+extern void acct_process (long exitcode);
 extern void kerneld_exit(void);
 
 int getrusage(struct task_struct *, int, struct rusage *);
@@ -34,7 +35,7 @@
 			return 0;
 		/* some signals are ignored by default.. (but SIGCONT already did its deed) */
 		if ((sa->sa_handler == SIG_DFL) &&
-		    (sig == SIGCONT || sig == SIGCHLD || sig == SIGWINCH))
+		    (sig == SIGCONT || sig == SIGCHLD || sig == SIGWINCH || sig == SIGURG))
 			return 0;
 	}
 	p->signal |= mask;
@@ -509,6 +510,7 @@
 		intr_count = 0;
 	}
 fake_volatile:
+	acct_process(code);
 	current->flags |= PF_EXITING;
 	del_timer(&current->real_timer);
 	sem_exit();
diff -u --recursive --new-file v1.3.72/linux/kernel/fork.c linux/kernel/fork.c
--- v1.3.72/linux/kernel/fork.c	Sun Dec 17 11:43:33 1995
+++ linux/kernel/fork.c	Mon Mar 11 09:39:34 1996
@@ -226,7 +226,8 @@
 	p->kernel_stack_page = new_stack;
 	*(unsigned long *) p->kernel_stack_page = STACK_MAGIC;
 	p->state = TASK_UNINTERRUPTIBLE;
-	p->flags &= ~(PF_PTRACED|PF_TRACESYS);
+	p->flags &= ~(PF_PTRACED|PF_TRACESYS|PF_SUPERPREV);
+	p->flags |= PF_FORKNOEXEC;
 	p->pid = get_pid(clone_flags);
 	p->next_run = NULL;
 	p->prev_run = NULL;
diff -u --recursive --new-file v1.3.72/linux/kernel/ksyms.c linux/kernel/ksyms.c
--- v1.3.72/linux/kernel/ksyms.c	Sun Mar 10 09:49:57 1996
+++ linux/kernel/ksyms.c	Mon Mar 11 11:23:41 1996
@@ -448,6 +448,7 @@
 	X(init_fifo),
 	X(super_blocks),
 	X(reuse_list),
+	X(fifo_inode_operations),
 	X(chrdev_inode_operations),
 	X(blkdev_inode_operations),
 	X(read_ahead),
diff -u --recursive --new-file v1.3.72/linux/kernel/sched.c linux/kernel/sched.c
--- v1.3.72/linux/kernel/sched.c	Sun Mar 10 09:49:57 1996
+++ linux/kernel/sched.c	Mon Mar 11 17:21:32 1996
@@ -41,7 +41,7 @@
 
 int securelevel = 0;			/* system security level */
 
-long tick = 1000000 / HZ;               /* timer interrupt period */
+long tick = 1000000 / HZ;		/* timer interrupt period */
 volatile struct timeval xtime;		/* The current time */
 int tickadj = 500/HZ;			/* microsecs */
 
@@ -52,18 +52,18 @@
 /*
  * phase-lock loop variables
  */
-int time_state = TIME_BAD;     /* clock synchronization status */
+int time_state = TIME_BAD;	/* clock synchronization status */
 int time_status = STA_UNSYNC | STA_PLL;	/* clock status bits */
-long time_offset = 0;           /* time adjustment (us) */
-long time_constant = 2;         /* pll time constant */
-long time_tolerance = MAXFREQ;  /* frequency tolerance (ppm) */
-long time_precision = 1; 	/* clock precision (us) */
+long time_offset = 0;		/* time adjustment (us) */
+long time_constant = 2;		/* pll time constant */
+long time_tolerance = MAXFREQ;	/* frequency tolerance (ppm) */
+long time_precision = 1;	/* clock precision (us) */
 long time_maxerror = 0x70000000;/* maximum error */
 long time_esterror = 0x70000000;/* estimated error */
-long time_phase = 0;            /* phase offset (scaled us) */
-long time_freq = 0;             /* frequency offset (scaled ppm) */
-long time_adj = 0;              /* tick adjust (scaled 1 / HZ) */
-long time_reftime = 0;          /* time at last adjustment (s) */
+long time_phase = 0;		/* phase offset (scaled us) */
+long time_freq = 0;		/* frequency offset (scaled ppm) */
+long time_adj = 0;		/* tick adjust (scaled 1 / HZ) */
+long time_reftime = 0;		/* time at last adjustment (s) */
 
 long time_adjust = 0;
 long time_adjust_step = 0;
@@ -113,6 +113,21 @@
 	(p->prev_run = init_task.prev_run)->next_run = p;
 	p->next_run = &init_task;
 	init_task.prev_run = p;
+#ifdef __SMP__
+	/* this is safe only if called with cli()*/
+	while(set_bit(31,&smp_process_available))
+		while(test_bit(31,&smp_process_available));
+	smp_process_available++;
+	clear_bit(31,&smp_process_available);
+	if ((0!=p->pid) && smp_threads_ready){
+		int i, found=0;
+		for (i=0;i<smp_num_cpus;i++)
+			if (0==current_set[i]->pid) {
+				smp_message_pass(i, MSG_RESCHEDULE, 0L, 0);
+				break;
+			}
+	}
+#endif
 }
 
 static inline void del_from_runqueue(struct task_struct * p)
@@ -763,7 +778,7 @@
 	unsigned long mask;
 	struct timer_struct *tp;
 	long ltemp, psecs;
-#ifdef  __SMP_PROF__
+#ifdef  __SMP__
 	int cpu,i;
 #endif
 
@@ -794,11 +809,11 @@
 	     * in the range -tickadj .. +tickadj
 	     */
 	     if (time_adjust > tickadj)
-	       time_adjust_step = tickadj;
+		time_adjust_step = tickadj;
 	     else if (time_adjust < -tickadj)
-	       time_adjust_step = -tickadj;
+		time_adjust_step = -tickadj;
 	     else
-	       time_adjust_step = time_adjust;
+		time_adjust_step = time_adjust;
 	     
 	    /* Reduce by this step the amount of time left  */
 	    time_adjust -= time_adjust_step;
@@ -814,12 +829,7 @@
 
 	jiffies++;
 	calc_load();
-#ifdef  __SMP_PROF__
-	smp_idle_count[NR_CPUS]++;    /* count timer ticks */
-	cpu = smp_processor_id();
-	for (i=0;i<(0==smp_num_cpus?1:smp_num_cpus);i++) 
-		if (test_bit(i,&smp_idle_map)) smp_idle_count[i]++;
-#endif
+#ifndef  __SMP__
 	if (user_mode(regs)) {
 		current->utime++;
 		if (current->pid) {
@@ -873,6 +883,81 @@
 		current->it_prof_value = current->it_prof_incr;
 		send_sig(SIGPROF,current,1);
 	}
+#else
+	cpu = smp_processor_id();
+	for (i=0;i<(0==smp_num_cpus?1:smp_num_cpus);i++){
+#ifdef __SMP_PROF__
+	if (test_bit(i,&smp_idle_map)) smp_idle_count[i]++;
+#endif
+		if (((cpu==i) && user_mode(regs)) ||
+			((cpu!=i) && 0==smp_proc_in_lock[i])) {
+			current_set[i]->utime++;
+			if (current_set[i]->pid) {
+				if (current_set[i]->priority < DEF_PRIORITY)
+					kstat.cpu_nice++;
+				else
+					kstat.cpu_user++;
+			}
+			/* Update ITIMER_VIRT for current task if not in a system call */
+			if (current_set[i]->it_virt_value && !(--current_set[i]->it_virt_value)) {
+				current_set[i]->it_virt_value = current_set[i]->it_virt_incr;
+				send_sig(SIGVTALRM,current_set[i],1);
+			}
+		} else {
+			current_set[i]->stime++;
+			if(current_set[i]->pid)
+				kstat.cpu_system++;
+			if (prof_buffer && current_set[i]->pid) {
+				extern int _stext;
+				unsigned long ip = instruction_pointer(regs);
+				ip -= (unsigned long) &_stext;
+				ip >>= prof_shift;
+				if (ip < prof_len)
+					prof_buffer[ip]++;
+			}
+		}
+		/*
+		 * check the cpu time limit on the process.
+		 */
+		if ((current_set[i]->rlim[RLIMIT_CPU].rlim_max != RLIM_INFINITY) &&
+			  (((current_set[i]->stime + current_set[i]->utime) / HZ) >=
+			  current_set[i]->rlim[RLIMIT_CPU].rlim_max))
+			send_sig(SIGKILL, current_set[i], 1);
+		if ((current_set[i]->rlim[RLIMIT_CPU].rlim_cur != RLIM_INFINITY) &&
+			  (((current_set[i]->stime + current_set[i]->utime) % HZ) == 0)) {
+			psecs = (current_set[i]->stime + current_set[i]->utime) / HZ;
+			/* send when equal */
+			if (psecs == current_set[i]->rlim[RLIMIT_CPU].rlim_cur)
+				send_sig(SIGXCPU, current_set[i], 1);
+			/* and every five seconds thereafter. */
+			else if ((psecs > current_set[i]->rlim[RLIMIT_CPU].rlim_cur) &&
+				  ((psecs - current_set[i]->rlim[RLIMIT_CPU].rlim_cur) % 5) == 0)
+				send_sig(SIGXCPU, current_set[i], 1);
+		}
+		if (current_set[i]->pid && 0 > --current_set[i]->counter) {
+			current_set[i]->counter = 0;
+			if (i==cpu)
+				need_resched = 1;
+			else
+				smp_message_pass(i, MSG_RESCHEDULE, 0L, 0);
+		} else
+			if ((0==current_set[i]->pid) && (0x7fffffff & smp_process_available)){
+				/* runnable process found; wakeup idle process */
+				if (cpu==i)
+					need_resched = 1;
+				else
+					smp_message_pass(i, MSG_RESCHEDULE, 0L, 0);
+			}
+
+		/* Update ITIMER_PROF for the current task */
+		if (current_set[i]->it_prof_value && !(--current_set[i]->it_prof_value)) {
+			current_set[i]->it_prof_value = current_set[i]->it_prof_incr;
+			send_sig(SIGPROF,current_set[i],1);
+		}
+	}
+
+#endif
+
 	for (mask = 1, tp = timer_table+0 ; mask ; tp++,mask += mask) {
 		if (mask > timer_active)
 			break;
diff -u --recursive --new-file v1.3.72/linux/kernel/sys.c linux/kernel/sys.c
--- v1.3.72/linux/kernel/sys.c	Sun Mar 10 09:49:57 1996
+++ linux/kernel/sys.c	Mon Mar 11 09:39:34 1996
@@ -19,6 +19,10 @@
 #include <linux/mm.h>
 #include <linux/pagemap.h>
 #include <linux/swap.h>
+#include <linux/fcntl.h>
+#include <linux/acct.h>
+#include <linux/tty.h>
+#include <sys/sysmacros.h>
 
 #include <asm/segment.h>
 #include <asm/io.h>
@@ -37,19 +41,22 @@
 
 static int proc_sel(struct task_struct *p, int which, int who)
 {
-	switch (which) {
-		case PRIO_PROCESS:
-			if (!who && p == current)
-				return 1;
-			return(p->pid == who);
-		case PRIO_PGRP:
-			if (!who)
-				who = current->pgrp;
-			return(p->pgrp == who);
-		case PRIO_USER:
-			if (!who)
-				who = current->uid;
-			return(p->uid == who);
+	if(p->pid)
+	{
+		switch (which) {
+			case PRIO_PROCESS:
+				if (!who && p == current)
+					return 1;
+				return(p->pid == who);
+			case PRIO_PGRP:
+				if (!who)
+					who = current->pgrp;
+				return(p->pgrp == who);
+			case PRIO_USER:
+				if (!who)
+					who = current->uid;
+				return(p->uid == who);
+		}
 	}
 	return 0;
 }
@@ -272,10 +279,113 @@
 		current->dumpable = 0;
 	return 0;
 }
-
-asmlinkage int sys_acct(void)
-{
-	return -ENOSYS;
+  
+static char acct_active = 0;
+static struct file acct_file;
+
+int acct_process(long exitcode)
+{
+   struct acct ac;
+   unsigned short fs;
+
+   if (acct_active) {
+      strncpy(ac.ac_comm, current->comm, ACCT_COMM);
+      ac.ac_comm[ACCT_COMM] = '\0';
+      ac.ac_utime = current->utime;
+      ac.ac_stime = current->stime;
+      ac.ac_btime = CT_TO_SECS(current->start_time) + (xtime.tv_sec - (jiffies / HZ));
+      ac.ac_etime = CURRENT_TIME - ac.ac_btime;
+      ac.ac_uid   = current->uid;
+      ac.ac_gid   = current->gid;
+      ac.ac_tty   = (current)->tty == NULL ? -1 : 
+         makedev (4, current->tty->device);
+      ac.ac_flag  = 0;
+      if (current->flags & PF_FORKNOEXEC)
+         ac.ac_flag |= AFORK;
+      if (current->flags & PF_SUPERPREV)
+         ac.ac_flag |= ASU;
+      if (current->flags & PF_DUMPCORE)
+         ac.ac_flag |= ACORE;
+      if (current->flags & PF_SIGNALED)
+         ac.ac_flag |= AXSIG;
+      ac.ac_minflt = current->min_flt;
+      ac.ac_majflt = current->maj_flt;
+      ac.ac_exitcode = exitcode;
+
+      /* Kernel segment override */
+      fs = get_fs();
+      set_fs(KERNEL_DS);
+
+      acct_file.f_op->write(acct_file.f_inode, &acct_file,
+                             (char *)&ac, sizeof(struct acct));
+
+      set_fs(fs);
+   }
+   return 0;
+}
+
+asmlinkage int sys_acct(const char *name)
+{
+   struct inode *inode = (struct inode *)0;
+   char *tmp;
+   int error;
+
+   if (!suser())
+      return -EPERM;
+
+   if (name == (char *)0) {
+      if (acct_active) {
+         if (acct_file.f_op->release)
+            acct_file.f_op->release(acct_file.f_inode, &acct_file);
+
+         if (acct_file.f_inode != (struct inode *) 0)
+            iput(acct_file.f_inode);
+
+         acct_active = 0;
+      }
+      return 0;
+   } else {
+      if (!acct_active) {
+
+         if ((error = getname(name, &tmp)) != 0)
+            return (error);
+
+         error = open_namei(tmp, O_RDWR, 0600, &inode, 0);
+         putname(tmp);
+
+         if (error)
+            return (error);
+
+         if (!S_ISREG(inode->i_mode)) {
+            iput(inode);
+            return -EACCES;
+         }
+
+         if (!inode->i_op || !inode->i_op->default_file_ops || 
+             !inode->i_op->default_file_ops->write) {
+            iput(inode);
+            return -EIO;
+         }
+
+         acct_file.f_mode = 3;
+         acct_file.f_flags = 0;
+         acct_file.f_count = 1;
+         acct_file.f_inode = inode;
+         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);
+               return -EIO;
+            }
+
+         acct_active = 1;
+         return 0;
+      } else
+         return -EBUSY;
+   }
 }
 
 #ifndef __alpha__
diff -u --recursive --new-file v1.3.72/linux/kernel/sysctl.c linux/kernel/sysctl.c
--- v1.3.72/linux/kernel/sysctl.c	Sun Mar 10 09:49:57 1996
+++ linux/kernel/sysctl.c	Tue Mar 12 17:30:14 1996
@@ -25,6 +25,10 @@
 extern int panic_timeout;
 
 
+#ifdef CONFIG_ROOT_NFS
+#include <linux/nfs_fs.h>
+#endif
+
 static ctl_table root_table[];
 static struct ctl_table_header root_table_header = 
 	{root_table, DNODE_SINGLE(&root_table_header)};
@@ -122,6 +126,16 @@
 	 0444, NULL, &proc_dointvec, (ctl_handler *)&do_securelevel_strategy},
 	{KERN_PANIC, "panic", &panic_timeout, sizeof(int),
 	 0644, NULL, &proc_dointvec},
+#ifdef CONFIG_BLK_DEV_INITRD
+	{KERN_REALROOTDEV, "real-root-dev", &real_root_dev, sizeof(int),
+	 0644, NULL, &proc_dointvec},
+#endif
+#ifdef CONFIG_ROOT_NFS
+	{KERN_NFSRNAME, "nfs-root-name", nfs_root_name, NFS_ROOT_NAME_LEN,
+	 0644, NULL, &proc_dostring, &sysctl_string },
+	{KERN_NFSRNAME, "nfs-root-addrs", nfs_root_addrs, NFS_ROOT_ADDRS_LEN,
+	 0644, NULL, &proc_dostring, &sysctl_string },
+#endif
 	{0}
 };
 
diff -u --recursive --new-file v1.3.72/linux/net/appletalk/aarp.c linux/net/appletalk/aarp.c
--- v1.3.72/linux/net/appletalk/aarp.c	Sat Mar  2 10:43:45 1996
+++ linux/net/appletalk/aarp.c	Sun Mar 10 09:28:56 1996
@@ -438,13 +438,16 @@
 	if(dev->type==ARPHRD_LOCALTLK)
 	{
 		struct at_addr *at=atalk_find_dev_addr(dev);
+		struct ddpehdr *ddp=(struct ddpehdr *)skb->data;
 		int ft=2;
 		
 		/*
-		 *	Compressable ?
+		 *	Compressible ?
+		 * 
+		 *	IFF: src_net==dest_net==device_net
 		 */
 		 
-		if(at->s_net==sa->s_net)
+		if(at->s_net==sa->s_net && sa->s_net==ddp->deh_snet)
 		{
 			skb_pull(skb,sizeof(struct ddpehdr)-4);
 			/*
diff -u --recursive --new-file v1.3.72/linux/net/appletalk/ddp.c linux/net/appletalk/ddp.c
--- v1.3.72/linux/net/appletalk/ddp.c	Sat Mar  2 10:43:45 1996
+++ linux/net/appletalk/ddp.c	Sun Mar 10 09:28:56 1996
@@ -19,6 +19,7 @@
  *		Alan Cox		:	Added firewall hooks.
  *		Alan Cox		:	Supports new ARPHRD_LOOPBACK
  *		Christer Weinigel	: 	Routing and /proc fixes.
+ *		Bradford Johnson	:	Locatalk.
  *
  *		This program is free software; you can redistribute it and/or
  *		modify it under the terms of the GNU General Public License
@@ -348,7 +349,38 @@
 	int netct;
 	int nodect;
 	
-	
+	struct ifreq atreq;
+	struct sockaddr_at *sa;
+	int err;
+
+/*
+ *	THIS IS A HACK: Farallon cards want to do their own picking of
+ *	addresses. This needs tidying up post 1.4, but we need it in 
+ *	now for the 1.4 release as is.
+ *
+ */
+	if(atif->dev->type == ARPHRD_LOCALTLK &&
+		atif->dev->do_ioctl) 
+	{
+		/* fake up the request and pass it down */
+		sa = (struct sockaddr_at*)&atreq.ifr_addr;
+		sa->sat_addr.s_node = probe_node;
+        	sa->sat_addr.s_net = probe_net;
+		if (!(err=atif->dev->do_ioctl(atif->dev,&atreq,SIOCSIFADDR)))
+		{
+			(void)atif->dev->do_ioctl(atif->dev,&atreq,SIOCGIFADDR);
+			atif->address.s_net=htons(sa->sat_addr.s_net);
+			atif->address.s_node=sa->sat_addr.s_node;
+			return 0;
+		}
+		/*
+		 *	If it didnt like our faked request then fail:
+		 *	This should check against -ENOIOCTLCMD and fall
+		 *	through. That needs us to fix all the devices up
+		 *	properly. We can then also dump the localtalk test.
+		 */
+		return err;
+	}	
 	/*
 	 *	Offset the network we start probing with.
 	 */
@@ -1597,6 +1629,7 @@
 						   if we slip up later */
 		*((__u16 *)ddp)=htons(*((__u16 *)ddp));		/* Mend the byte order */
 	}
+	skb->h.raw = skb->data;
 	return atalk_rcv(skb,dev,pt);
 }
 
diff -u --recursive --new-file v1.3.72/linux/net/ax25/af_ax25.c linux/net/ax25/af_ax25.c
--- v1.3.72/linux/net/ax25/af_ax25.c	Fri Feb 23 13:54:41 1996
+++ linux/net/ax25/af_ax25.c	Sun Mar 10 09:28:57 1996
@@ -72,6 +72,12 @@
  *			Joerg(DL1BKE)		Added DAMA support, fixed (?) digipeating, fixed buffer locking
  *						for "virtual connect" mode... Result: Probably the
  *						"Most Buggiest Code You've Ever Seen" (TM)
+ *			HaJo(DD8NE)		implementation of a T5 (idle) timer
+ *			Joerg(DL1BKE)		renamed T5 to IDLE and changed behaviour:
+ *						the timer gets reloaded on every received or transmited
+ *						I frame for IP or NETROM. The idle timer is not active
+ *						on "vanilla AX.25" connections. Furthermore added PACLEN
+ *						to provide AX.25-layer based fragmentation (like WAMPES)
  *
  *	To do:
  *		Restructure the ax25_rcv code to be cleaner/faster and
@@ -544,6 +550,8 @@
 	ax25->t2      = AX25_DEF_T2 * PR_SLOWHZ;
 	ax25->t3      = AX25_DEF_T3 * PR_SLOWHZ;
 	ax25->n2      = AX25_DEF_N2;
+	ax25->paclen  = AX25_DEF_PACLEN;
+	ax25->idle    = 0;
 
 	ax25->modulus   = AX25_DEF_AXDEFMODE;
 	ax25->fragno    = 0;
@@ -555,6 +563,7 @@
 	ax25->t2timer   = 0;
 	ax25->t3timer   = 0;
 	ax25->n2count   = 0;
+	ax25->idletimer = 0;
 
 	ax25->va      = 0;
 	ax25->vr      = 0;
@@ -606,13 +615,15 @@
 {
 	ax25->device = dev;
 
-	ax25->rtt = ax25_dev_get_value(dev, AX25_VALUES_T1);
-	ax25->t1  = ax25_dev_get_value(dev, AX25_VALUES_T1);
-	ax25->t2  = ax25_dev_get_value(dev, AX25_VALUES_T2);
-	ax25->t3  = ax25_dev_get_value(dev, AX25_VALUES_T3);
-	ax25->n2  = ax25_dev_get_value(dev, AX25_VALUES_N2);
+	ax25->rtt    = ax25_dev_get_value(dev, AX25_VALUES_T1);
+	ax25->t1     = ax25_dev_get_value(dev, AX25_VALUES_T1);
+	ax25->t2     = ax25_dev_get_value(dev, AX25_VALUES_T2);
+	ax25->t3     = ax25_dev_get_value(dev, AX25_VALUES_T3);
+	ax25->n2     = ax25_dev_get_value(dev, AX25_VALUES_N2);
+	ax25->paclen = ax25_dev_get_value(dev, AX25_VALUES_PACLEN);
 
 	ax25->dama_slave = 0;
+	ax25->idle = 0;
 
 	ax25->modulus = ax25_dev_get_value(dev, AX25_VALUES_AXDEFMODE);
 
@@ -642,6 +653,7 @@
 
 		if (ax25cmp(&ax25->source_addr, src) == 0 && ax25cmp(&ax25->dest_addr, dest) == 0 && ax25->device == dev) {
 			ax25_output(ax25, skb);
+			ax25->idletimer = ax25->idle;	/* dl1bke 960228 */
 			return 1;		/* It already existed */
 		}
 	}
@@ -668,6 +680,10 @@
 		dama_establish_data_link(ax25);
 	else
 		ax25_establish_data_link(ax25);
+
+	/* idle timeouts only for mode vc connections */
+
+	ax25->idletimer = ax25->idle = ax25_dev_get_value(ax25->device, AX25_VALUES_IDLE);
 		
 	ax25_insert_socket(ax25);
 
@@ -780,6 +796,12 @@
 				return -EINVAL;
 			sk->ax25->t3 = opt * PR_SLOWHZ;
 			return 0;
+			
+		case AX25_IDLE:
+			if (opt < 0)
+				return -EINVAL;
+			sk->ax25->idle = opt * PR_SLOWHZ * 60;
+			return 0;
 
 		case AX25_BACKOFF:
 			sk->ax25->backoff = opt ? 1 : 0;
@@ -792,6 +814,12 @@
 		case AX25_HDRINCL:
 			sk->ax25->hdrincl = opt ? 1 : 0;
 			return 0;
+			
+		case AX25_PACLEN:
+			if (opt < 16 || opt > 65535)
+				return -EINVAL;
+			sk->ax25->paclen = opt;
+			return 0;
 
 		default:
 			return -ENOPROTOOPT;
@@ -833,6 +861,10 @@
 		case AX25_T3:
 			val = sk->ax25->t3 / PR_SLOWHZ;
 			break;
+			
+		case AX25_IDLE:
+			val = sk->ax25->idle / (PR_SLOWHZ * 60);
+			break;
 
 		case AX25_BACKOFF:
 			val = sk->ax25->backoff;
@@ -845,6 +877,10 @@
 		case AX25_HDRINCL:
 			val = sk->ax25->hdrincl;
 			break;
+			
+		case AX25_PACLEN:
+			val = sk->ax25->paclen;
+			break;
 
 		default:
 			return -ENOPROTOOPT;
@@ -1046,6 +1082,7 @@
 	ax25->t2      = osk->ax25->t2;
 	ax25->t3      = osk->ax25->t3;
 	ax25->n2      = osk->ax25->n2;
+	ax25->idle    = osk->ax25->idle;
 
 	ax25->window  = osk->ax25->window;
 
@@ -1659,6 +1696,7 @@
 		}
 
 		ax25_fillin_cb(ax25, dev);
+		ax25->idletimer = ax25->idle = ax25_dev_get_value(ax25->device, AX25_VALUES_IDLE);
 #else
 		if (mine)
 			ax25_return_dm(dev, &src, &dest, &dp);
@@ -2101,7 +2139,7 @@
   
 	cli();
 
-	len += sprintf(buffer, "dest_addr src_addr  dev  st  vs  vr  va    t1     t2     t3     n2  rtt wnd Snd-Q Rcv-Q\n");
+	len += sprintf(buffer, "dest_addr src_addr  dev  st  vs  vr  va    t1     t2     t3      idle   n2  rtt wnd paclen   dama Snd-Q Rcv-Q\n");
 
 	for (ax25 = ax25_list; ax25 != NULL; ax25 = ax25->next) {
 		if ((dev = ax25->device) == NULL)
@@ -2111,7 +2149,7 @@
 
 		len += sprintf(buffer + len, "%-9s ",
 			ax2asc(&ax25->dest_addr));
-		len += sprintf(buffer + len, "%-9s %-4s %2d %3d %3d %3d %3d/%03d %2d/%02d %3d/%03d %2d/%02d %3d %3d",
+		len += sprintf(buffer + len, "%-9s %-4s %2d %3d %3d %3d %3d/%03d %2d/%02d %3d/%03d %3d/%03d %2d/%02d %3d %3d  %5d",
 			ax2asc(&ax25->source_addr), devname,
 			ax25->state,
 			ax25->vs, ax25->vr, ax25->va,
@@ -2121,9 +2159,14 @@
 			ax25->t2      / PR_SLOWHZ,
 			ax25->t3timer / PR_SLOWHZ,
 			ax25->t3      / PR_SLOWHZ,
+			(ax25->idletimer / (PR_SLOWHZ*60))+1,
+			ax25->idle      / (PR_SLOWHZ*60),
 			ax25->n2count, ax25->n2,
 			ax25->rtt     / PR_SLOWHZ,
-			ax25->window);
+			ax25->window,
+			ax25->paclen);
+			
+		len += sprintf(buffer + len, " %s", ax25->dama_slave? " slave" : "    no");
 
 		if (ax25->sk != NULL) {
 			len += sprintf(buffer + len, " %5ld %5ld\n",
@@ -2387,20 +2430,6 @@
 		if (mode == 'V' || mode == 'v' || (mode == ' ' && ax25_dev_get_value(dev, AX25_VALUES_IPDEFMODE) == 'V')) {
 /*			skb_device_unlock(skb); *//* Don't unlock - it might vanish.. TCP will respond correctly to this lock holding */
 			skb_pull(skb, AX25_HEADER_LEN - 1);	/* Keep PID */
-#ifdef HUNTING_FOR_ENCAP_BUG
-		/* dl1bke 960131: This is a weird bug: the AX.25 frame is encapsulated */
-		/* 		  twice... We'll try a work-around here and hope for   */
-		/* 		  the best.                                            */
-
-			if (!(ax25cmp((ax25_address *)(bp + 8), (ax25_address *)(skb->data + 8)) ||
-			      ax25cmp((ax25_address *)(bp + 1), (ax25_address *)(skb->data + 1)))) {
-				printk("ax25_rebuild_header(): encap bug...\n");
-				skb_pull(skb, AX25_HEADER_LEN);
-			} else {
-				if (!*skb->data)
-					printk("ax25_rebuild_header(): probably encap bug...\n");
-			}
-#endif
 			ax25_send_frame(skb, (ax25_address *)(bp + 8), (ax25_address *)(bp + 1), NULL, dev);
 			return 1;
 		}
diff -u --recursive --new-file v1.3.72/linux/net/ax25/ax25_in.c linux/net/ax25/ax25_in.c
--- v1.3.72/linux/net/ax25/ax25_in.c	Fri Feb 23 13:54:41 1996
+++ linux/net/ax25/ax25_in.c	Sun Mar 10 09:28:57 1996
@@ -28,6 +28,10 @@
  *					Upgraded state machine for SABME.
  *					Added arbitrary protocol id support.
  *	AX.25 031	Joerg(DL1BKE)	Added DAMA support
+ *			HaJo(DD8NE)	Added Idle Disc Timer T5
+ *			Joerg(DL1BKE)   renamed it to "IDLE" with a slightly
+ *					different behaviour. Fixed defrag
+ *					routine (I hope)
  */
 
 #include <linux/config.h>
@@ -71,10 +75,15 @@
 	if (ax25->fragno != 0) {
 		if (!(*skb->data & SEG_FIRST)) {
 			if ((ax25->fragno - 1) == (*skb->data & SEG_REM)) {
+			
+				/* enqueue fragment */
+				
 				ax25->fragno = *skb->data & SEG_REM;
-				skb_pull(skb, 1);
+				skb_pull(skb, 1);	/* skip fragno */
 				ax25->fraglen += skb->len;
 				skb_queue_tail(&ax25->frag_queue, skb);
+				
+				/* last fragment received? */
 
 				if (ax25->fragno == 0) {
 					if ((skbn = alloc_skb(AX25_MAX_HEADER_LEN + ax25->fraglen, GFP_ATOMIC)) == NULL)
@@ -82,28 +91,45 @@
 
 					skbn->free = 1;
 					skbn->arp  = 1;
+					skbn->dev  = skb->dev;
 
 					if (ax25->sk != NULL) {
 						skbn->sk = ax25->sk;
 						ax25->sk->rmem_alloc += skbn->truesize;
 					}
 
-					skb_reserve(skbn, AX25_MAX_HEADER_LEN);
-					skbn->h.raw = skbn->data;
-
+					/* get first fragment from queue */
+					
 					skbo = skb_dequeue(&ax25->frag_queue);
-					hdrlen = skbo->data - skbo->h.raw;
-					skb_push(skbo, hdrlen);
+					hdrlen = skbo->data - skbo->h.raw - 2;	/* skip PID & fragno */
+					
+					skb_push(skbo, hdrlen + 2);		/* start of address field */
+					skbn->data = skb_put(skbn, hdrlen);	/* get space for info */
+					memcpy(skbn->data, skbo->data, hdrlen);	/* copy address field */
+					skb_pull(skbo, hdrlen + 2);		/* start of data */
+					skb_pull(skbn, hdrlen + 1);		/* dito */
+
+					/* copy data from first fragment */
+
 					memcpy(skb_put(skbn, skbo->len), skbo->data, skbo->len);
-					skb_pull(skbn, hdrlen);
 					kfree_skb(skbo, FREE_READ);
+					
+					/* add other fragment's data */
 
 					while ((skbo = skb_dequeue(&ax25->frag_queue)) != NULL) {
 						memcpy(skb_put(skbn, skbo->len), skbo->data, skbo->len);
 						kfree_skb(skbo, FREE_READ);
 					}
 
-					ax25->fraglen = 0;
+					ax25->fraglen = 0;		/* reset counter */
+					
+					/* 
+					 * mysteriously we need to re-adjust skb->data.
+					 * Anyway, it seems to work. Do we have the address fields
+					 * encoded TWICE in one sk_buff?
+					 */
+					
+					skb_pull(skbn, hdrlen);
 
 					if (ax25_rx_iframe(ax25, skbn) == 0)
 						kfree_skb(skbn, FREE_READ);
@@ -113,9 +139,11 @@
 			}
 		}
 	} else {
+		/* first fragment received? */
+
 		if (*skb->data & SEG_FIRST) {
 			ax25->fragno = *skb->data & SEG_REM;
-			skb_pull(skb, 1);
+			skb_pull(skb, 1);		/* skip fragno */
 			ax25->fraglen = skb->len;
 			skb_queue_tail(&ax25->frag_queue, skb);
 			return 1;
@@ -141,6 +169,7 @@
 	switch (pid) {
 #ifdef CONFIG_NETROM
 		case AX25_P_NETROM:
+			ax25->idletimer = ax25->idle = ax25_dev_get_value(ax25->device, AX25_VALUES_IDLE);
 			if (ax25_dev_get_value(ax25->device, AX25_VALUES_NETROM)) {
 				skb_pull(skb, 1);	/* Remove PID */
 				queued = nr_route_frame(skb, ax25);
@@ -149,6 +178,7 @@
 #endif
 #ifdef CONFIG_INET
 		case AX25_P_IP:
+			ax25->idletimer = ax25->idle = ax25_dev_get_value(ax25->device, AX25_VALUES_IDLE);
 			skb_pull(skb, 1);	/* Remove PID */
 			skb->h.raw = skb->data;
 			ax25_ip_mode_set(&ax25->dest_addr, ax25->device, 'V');
@@ -158,11 +188,13 @@
 			break;
 #endif
 		case AX25_P_SEGMENT:
+			ax25->idletimer = ax25->idle = ax25_dev_get_value(ax25->device, AX25_VALUES_IDLE);
 			skb_pull(skb, 1);	/* Remove PID */
 			queued = ax25_rx_fragment(ax25, skb);
 			break;
 
 		default:
+			ax25->idletimer = ax25->idle = 0;
 			if (ax25->sk != NULL && ax25_dev_get_value(ax25->device, AX25_VALUES_TEXT) && ax25->sk->protocol == pid) {
 				if (sock_queue_rcv_skb(ax25->sk, skb) == 0) {
 					queued = 1;
@@ -207,6 +239,7 @@
 				ax25_calculate_rtt(ax25);
 				ax25->t1timer = 0;
 				ax25->t3timer = ax25->t3;
+				ax25->idletimer = ax25->idle;
 				ax25->vs      = 0;
 				ax25->va      = 0;
 				ax25->vr      = 0;
@@ -353,6 +386,7 @@
 			ax25->condition = 0x00;
 			ax25->t1timer   = 0;
 			ax25->t3timer   = ax25->t3;
+			ax25->idletimer = ax25->idle;
 			ax25->vs        = 0;
 			ax25->va        = 0;
 			ax25->vr        = 0;
@@ -368,6 +402,7 @@
 			ax25->condition = 0x00;
 			ax25->t1timer   = 0;
 			ax25->t3timer   = ax25->t3;
+			ax25->idletimer = ax25->idle;
 			ax25->vs        = 0;
 			ax25->va        = 0;
 			ax25->vr        = 0;
@@ -546,6 +581,7 @@
 			ax25->condition = 0x00;
 			ax25->t1timer   = 0;
 			ax25->t3timer   = ax25->t3;
+			ax25->idletimer = ax25->idle;
 			ax25->vs        = 0;
 			ax25->va        = 0;
 			ax25->vr        = 0;
@@ -563,6 +599,7 @@
 			ax25->condition = 0x00;
 			ax25->t1timer   = 0;
 			ax25->t3timer   = ax25->t3;
+			ax25->idletimer = ax25->idle;
 			ax25->vs        = 0;
 			ax25->va        = 0;
 			ax25->vr        = 0;
@@ -620,8 +657,6 @@
 				}
 				break;
 			}
-			/* dl1bke 960114: replaced if(..) ax25_enquiry_response */
-			/* 		  with ax25_check_need_response()       */
 			 
 			ax25_check_need_response(ax25, type, pf);
 			if (ax25_validate_nr(ax25, nr)) {
@@ -654,10 +689,10 @@
 				break;
 			}
 
-			ax25_check_need_response(ax25, type, pf);	/* dl1bke 960114 */
+			ax25_check_need_response(ax25, type, pf);
 			if (ax25_validate_nr(ax25, nr)) {
 				ax25_frames_acked(ax25, nr);
-				dama_check_need_response(ax25, type, pf);	/* dl1bke 960114 */
+				dama_check_need_response(ax25, type, pf);
 			} else {
 				ax25_nr_error_recovery(ax25);
 				ax25->state = AX25_STATE_1;
@@ -685,13 +720,13 @@
 				break;
 			}
 			
-			ax25_check_need_response(ax25, type, pf);	/* dl1bke 960114 */
+			ax25_check_need_response(ax25, type, pf);	
 			if (ax25_validate_nr(ax25, nr)) {
 				ax25_frames_acked(ax25, nr);
 				if(ax25->vs != ax25->va) {
 					ax25_requeue_frames(ax25);
 				}
-				dama_check_need_response(ax25, type, pf);	/* dl1bke 960114 */
+				dama_check_need_response(ax25, type, pf);
 			} else {
 				ax25_nr_error_recovery(ax25);
 				ax25->state = AX25_STATE_1;
diff -u --recursive --new-file v1.3.72/linux/net/ax25/ax25_out.c linux/net/ax25/ax25_out.c
--- v1.3.72/linux/net/ax25/ax25_out.c	Fri Feb 23 13:54:41 1996
+++ linux/net/ax25/ax25_out.c	Sun Mar 10 09:28:57 1996
@@ -25,6 +25,9 @@
  *	AX.25 030	Jonathan(G4KLX)	Added fragmentation to ax25_output.
  *					Added support for extended AX.25.
  *	AX.25 031	Joerg(DL1BKE)	Added DAMA support
+ *
+ *			Joerg(DL1BKE)	modified fragmenter to fragment vanilla 
+ *					AX.25 I-Frames. Added PACLEN parameter.
  */
 
 #include <linux/config.h>
@@ -58,12 +61,35 @@
 {
 	struct sk_buff *skbn;
 	unsigned char *p;
-	int err, frontlen, mtu, len, fragno, first = 1;
+	int err, frontlen, mtu, len, fragno, ka9qfrag, first = 1;
 	
-	mtu = ax25->device->mtu;
+	/*
+	 * dl1bke 960301: We use the new PACLEN parameter as MTU of the AX.25 layer.
+	 *                This will (hopefully) allow user programs to write() data
+	 *                w/o having to think of the maximal amount of data we can
+	 *		  send with one call. It's called PACLEN to (1) avoid confusion
+	 *		  with (IP) MTU and (2) TAPR calls this PACLEN, too ;-)
+	 */
+
+	mtu = ax25->paclen;
 	
 	if ((skb->len - 1) > mtu) {
-		mtu -= 2;		/* Allow for fragment control info */
+		switch (*skb->data) {
+			case AX25_P_SEGMENT:
+				/* this is an error, but... */
+				printk("ax25_output(): woops, fragmentation of fragment?!\n");
+				/* okay, let's fragment it further (tss, tss...) */
+			case AX25_P_NETROM:	/* err, is this a good idea? */
+			case AX25_P_IP:
+				mtu -= 2;	/* Allow for fragment control info */
+				ka9qfrag = 1;
+				break;
+			default:
+				ka9qfrag = 0;
+				skb_pull(skb, 1); /* skip PID */
+				break;
+
+		}
 		
 		fragno = skb->len / mtu;
 		if (skb->len % mtu == 0) fragno--;
@@ -83,23 +109,29 @@
 			skbn->free = 1;
 			skbn->arp  = 1;
 
-			skb_reserve(skbn, frontlen + 2);
-
 			len = (mtu > skb->len) ? skb->len : mtu;
 			
-			memcpy(skb_put(skbn, len), skb->data, len);
-			skb_pull(skb, len);
+			if (ka9qfrag == 1) {
+				skb_reserve(skbn, frontlen + 2);
 
-			p = skb_push(skbn, 2);
+				memcpy(skb_put(skbn, len), skb->data, len);
+				p = skb_push(skbn, 2);
 
-			*p++ = AX25_P_SEGMENT;
+				*p++ = AX25_P_SEGMENT;
 
-			*p = fragno--;
-			if (first) {
-				*p |= SEG_FIRST;
-				first = 0;
+				*p = fragno--;
+				if (first) {
+					*p |= SEG_FIRST;
+					first = 0;
+				}
+			} else {
+				skb_reserve(skbn, frontlen + 1);
+				memcpy(skb_put(skbn, len), skb->data, len);
+				p = skb_push(skbn, 1);
+				*p = AX25_P_TEXT;
 			}
 
+			skb_pull(skb, len);
 			skb_queue_tail(&ax25->write_queue, skbn); /* Throw it on the queue */
 		}
 		
diff -u --recursive --new-file v1.3.72/linux/net/ax25/ax25_route.c linux/net/ax25/ax25_route.c
--- v1.3.72/linux/net/ax25/ax25_route.c	Fri Feb 23 13:54:41 1996
+++ linux/net/ax25/ax25_route.c	Sun Mar 10 09:28:57 1996
@@ -31,6 +31,9 @@
  *			Joerg(DL1BKE)	ax25_rt_build_path() find digipeater list and device by 
  *					destination call. Needed for IP routing via digipeater
  *			Jonathan(G4KLX)	Added routing for IP datagram packets.
+ *			Joerg(DL1BKE)	changed routing for IP datagram and VC to use a default
+ *					route if available. Does not overwrite default routes
+ *					on route-table overflow anymore.
  */
  
 #include <linux/config.h>
@@ -75,6 +78,15 @@
 	unsigned short values[AX25_MAX_VALUES];
 } *ax25_device = NULL;
 
+/*
+ * FIXME: heard and routing table should be two lists. The routing table
+ *        should be updated by connects only. (WAMPES way of doing it)
+ *
+ *        routing table should accept a new route to the same destination
+ *        if the old one was added manually. Nevertheless we should still
+ *        be able to add permanent routes. (dl1bke)
+ */
+
 void ax25_rt_rx_frame(ax25_address *src, struct device *dev, ax25_digi *digi)
 {
 	unsigned long flags;
@@ -87,7 +99,7 @@
 	oldest = NULL;
 
 	for (ax25_rt = ax25_route; ax25_rt != NULL; ax25_rt = ax25_rt->next) {
-		if (count == 0 || (ax25_rt->stamp.tv_sec != 0 && ax25_rt->stamp.tv_sec < oldest->stamp.tv_sec))
+		if (count == 0 || oldest->stamp.tv_sec == 0 || (ax25_rt->stamp.tv_sec != 0 && ax25_rt->stamp.tv_sec < oldest->stamp.tv_sec))
 			oldest = ax25_rt;
 		
 		if (ax25cmp(&ax25_rt->callsign, src) == 0 && ax25_rt->dev == dev) {
@@ -101,6 +113,8 @@
 	}
 
 	if (count > AX25_ROUTE_MAX) {
+		if (oldest->stamp.tv_sec == 0)
+			return;
 		if (oldest->digipeat != NULL)
 			kfree_s(oldest->digipeat, sizeof(ax25_digi));
 		ax25_rt = oldest;
@@ -394,6 +408,8 @@
 	if ((call = ax25_findbyuid(current->euid)) == NULL) {
 		if (ax25_uid_policy && !suser())
 			return -EPERM;
+		if (ax25->device == NULL)
+			return -ENODEV;
 		call = (ax25_address *)ax25->device->dev_addr;
 	}
 
@@ -413,27 +429,28 @@
 
 /*
  *	dl1bke 960117: build digipeater path
+ *	dl1bke 960301: use the default route if it exists
  */
 void ax25_rt_build_path(ax25_cb *ax25, ax25_address *addr)
 {
 	struct ax25_route *ax25_rt;
-
+	
 	for (ax25_rt = ax25_route; ax25_rt != NULL; ax25_rt = ax25_rt->next) {
-		if (ax25cmp(&ax25_rt->callsign, addr) == 0 && ax25_rt->digipeat != NULL) {
-			if (ax25_rt->dev == NULL)
-				continue;
-			
-			if ((ax25->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL)
-				return;
-
-			ax25->device = ax25_rt->dev;
-			*ax25->digipeat = *ax25_rt->digipeat;
-
-			return;
-		}
+		if (ax25cmp(&ax25_rt->callsign, addr) == 0 && ax25_rt->dev != NULL)
+			break;
+		
+		if (ax25cmp(&ax25_rt->callsign, &null_ax25_address) == 0 && ax25_rt->dev != NULL)
+			break;
 	}
+	
+	if (ax25_rt == NULL || ax25_rt->digipeat == NULL)
+		return;
+
+	if ((ax25->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL)
+		return;
 
-	ax25->digipeat = NULL;
+	ax25->device = ax25_rt->dev;
+	*ax25->digipeat = *ax25_rt->digipeat;
 }
 
 void ax25_dg_build_path(struct sk_buff *skb, ax25_address *addr, struct device *dev)
@@ -442,31 +459,37 @@
 	ax25_address src, dest;
 	unsigned char *bp;
 	int len;
-
+	
+	/*
+	 * dl1bke 960301: use the default route if available
+	 *
+	 */
+	
 	for (ax25_rt = ax25_route; ax25_rt != NULL; ax25_rt = ax25_rt->next) {
-		if (ax25cmp(&ax25_rt->callsign, addr) == 0 && ax25_rt->dev == dev) {
-			if (ax25_rt->digipeat == NULL)
-				return;
-
-			len = ax25_rt->digipeat->ndigi * AX25_ADDR_LEN;
-			
-			if (skb_headroom(skb) < len) {
-				printk("ax25_dg_build_path: not enough headroom for in skb\n");
-				return;
-			}
-
-			memcpy(&dest, skb->data + 1, AX25_ADDR_LEN);
-			memcpy(&src,  skb->data + 8, AX25_ADDR_LEN);
+		if (ax25cmp(&ax25_rt->callsign, addr) == 0 && ax25_rt->dev != NULL)
+			break;
+		if (ax25cmp(&ax25_rt->callsign, &null_ax25_address) == 0 && ax25_rt->dev != NULL)
+			break;
+	}
+	
+	
+	if (ax25_rt == NULL ||ax25_rt->digipeat == NULL)
+		return;
 
-			bp = skb_push(skb, len);
+	len = ax25_rt->digipeat->ndigi * AX25_ADDR_LEN;
+		
+	if (skb_headroom(skb) < len) {
+		printk("ax25_dg_build_path: not enough headroom for in skb\n");
+		return;
+	}
 
-			*bp++ = 0x00;		/* KISS Data */
+	memcpy(&dest, skb->data + 1, AX25_ADDR_LEN);
+	memcpy(&src,  skb->data + 8, AX25_ADDR_LEN);
 
-			build_ax25_addr(bp, &src, &dest, ax25_rt->digipeat, C_COMMAND, MODULUS);
+	bp = skb_push(skb, len);
+	*bp++ = 0x00;		/* KISS Data */
 
-			return;
-		}
-	}
+	build_ax25_addr(bp, &src, &dest, ax25_rt->digipeat, C_COMMAND, MODULUS);
 }
 
 /*
@@ -550,8 +573,10 @@
 	ax25_dev->values[AX25_VALUES_T1]        = AX25_DEF_T1 * PR_SLOWHZ;
 	ax25_dev->values[AX25_VALUES_T2]        = AX25_DEF_T2 * PR_SLOWHZ;
 	ax25_dev->values[AX25_VALUES_T3]        = AX25_DEF_T3 * PR_SLOWHZ;
+	ax25_dev->values[AX25_VALUES_IDLE]	= AX25_DEF_IDLE * PR_SLOWHZ * 60;
 	ax25_dev->values[AX25_VALUES_N2]        = AX25_DEF_N2;
 	ax25_dev->values[AX25_VALUES_DIGI]      = AX25_DEF_DIGI;
+	ax25_dev->values[AX25_VALUES_PACLEN]	= AX25_DEF_PACLEN;
 
 	save_flags(flags);
 	cli();
@@ -635,9 +660,13 @@
 				return -EINVAL;
 			if (ax25_parms.values[AX25_VALUES_T3] < 1)
 				return -EINVAL;
+			if (ax25_parms.values[AX25_VALUES_IDLE] > 100)
+				return -EINVAL;
 			if (ax25_parms.values[AX25_VALUES_N2] < 1 ||
 			    ax25_parms.values[AX25_VALUES_N2] > 31)
 				return -EINVAL;
+			if (ax25_parms.values[AX25_VALUES_PACLEN] < 16)
+				return -EINVAL;
 			if ((ax25_parms.values[AX25_VALUES_DIGI] &
 			    ~(AX25_DIGI_INBAND | AX25_DIGI_XBAND)) != 0)
 				return -EINVAL;
@@ -646,6 +675,7 @@
 			ax25_dev->values[AX25_VALUES_T1] /= 2;
 			ax25_dev->values[AX25_VALUES_T2] *= PR_SLOWHZ;
 			ax25_dev->values[AX25_VALUES_T3] *= PR_SLOWHZ;
+			ax25_dev->values[AX25_VALUES_IDLE] *= PR_SLOWHZ * 60;
 			break;
 
 		case SIOCAX25GETPARMS:
@@ -661,6 +691,7 @@
 			ax25_parms.values[AX25_VALUES_T1] /= PR_SLOWHZ;
 			ax25_parms.values[AX25_VALUES_T2] /= PR_SLOWHZ;
 			ax25_parms.values[AX25_VALUES_T3] /= PR_SLOWHZ;
+			ax25_parms.values[AX25_VALUES_IDLE] /= PR_SLOWHZ * 60;
 			memcpy_tofs(arg, &ax25_parms, sizeof(ax25_parms));
 			break;
 	}
diff -u --recursive --new-file v1.3.72/linux/net/ax25/ax25_subr.c linux/net/ax25/ax25_subr.c
--- v1.3.72/linux/net/ax25/ax25_subr.c	Tue Mar  5 10:11:15 1996
+++ linux/net/ax25/ax25_subr.c	Sun Mar 10 09:28:57 1996
@@ -29,6 +29,7 @@
  *					Thus we have ax25_kiss_cmd() now... ;-)
  *			Dave Brown(N2RJT)
  *					Killed a silly bug in the DAMA code.
+ *			Joerg(DL1BKE)	found the real bug in ax25.h --- sorry.
  */
 
 #include <linux/config.h>
@@ -348,7 +349,7 @@
 	}
 		
 	if (dama != NULL) 
-		*dama = ~(buf[13] & DAMA_FLAG);
+		*dama = ~buf[13] & DAMA_FLAG;
 		
 	/* Copy to, from */
 	if (dest != NULL) 
@@ -485,35 +486,35 @@
 {
 	struct sk_buff *skb;
 	unsigned char *p;
-	
+
 	if (ax25->device == NULL)
 		return;
 
 	if ((skb = alloc_skb(2, GFP_ATOMIC)) == NULL)
 		return;
-		
+
 	skb->free = 1;
 	skb->arp = 1;
-	
+
 	if (ax25->sk != NULL) {
 		skb->sk = ax25->sk;
 		ax25->sk->wmem_alloc += skb->truesize;
 	}
-	
+
 	skb->protocol = htons(ETH_P_AX25);
-	
+
 	p = skb_put(skb, 2);
-	
+
 	*p++=cmd;
 	*p  =param;
-	
-	dev_queue_xmit(skb, ax25->device, SOPRI_NORMAL);	
+
+	dev_queue_xmit(skb, ax25->device, SOPRI_NORMAL);
 }
 
 void ax25_dama_on(ax25_cb *ax25)
 {
 	int count = ax25_dev_is_dama_slave(ax25->device);
-
+	
 	if (count == 0) {
 		if (ax25->sk != NULL && ax25->sk->debug)
 			printk("ax25_dama_on: DAMA on\n");
diff -u --recursive --new-file v1.3.72/linux/net/ax25/ax25_timer.c linux/net/ax25/ax25_timer.c
--- v1.3.72/linux/net/ax25/ax25_timer.c	Fri Feb 23 13:54:41 1996
+++ linux/net/ax25/ax25_timer.c	Sun Mar 10 09:28:57 1996
@@ -170,6 +170,40 @@
 		}
 		ax25->t3timer = ax25->t3;
 	}
+	
+	if (ax25->idletimer > 0 && --ax25->idletimer == 0) {
+		/* dl1bke 960228: close the connection when IDLE expires */
+		/* 		  similar to DAMA T3 timeout but with    */
+		/* 		  a "clean" disconnect of the connection */
+
+		ax25_clear_queues(ax25);
+
+		ax25->n2count = 0;
+		if (!ax25->dama_slave)
+			ax25_send_control(ax25, DISC, POLLON, C_COMMAND);
+		
+		/* state 1 or 2 should not happen, but... */
+		
+		if (ax25->state == AX25_STATE_1 || ax25->state == AX25_STATE_2)
+			ax25->state = AX25_STATE_0;
+		else
+			ax25->state = AX25_STATE_2;
+
+		ax25->t3timer = 0;
+		ax25->t1timer = ax25->t1 = ax25_calculate_t1(ax25);
+		ax25->state   = AX25_STATE_2;
+
+		if (ax25->sk != NULL)
+		{
+			ax25->sk->state = TCP_CLOSE;
+			ax25->sk->err = 0;
+			if (!ax25->sk->dead)
+				ax25->sk->state_change(ax25->sk);
+			ax25->sk->dead = 1;
+			ax25->sk->destroy = 1;
+		}
+	}
+		                                                                                                                                                                                                                                                                                                                                        
 
 	/* dl1bke 960114: DAMA T1 timeouts are handled in ax25_dama_slave_transmit */
 	/* 		  nevertheless we have to re-enqueue the timer struct...   */
diff -u --recursive --new-file v1.3.72/linux/net/ipv4/af_inet.c linux/net/ipv4/af_inet.c
--- v1.3.72/linux/net/ipv4/af_inet.c	Sat Mar  2 10:43:46 1996
+++ linux/net/ipv4/af_inet.c	Tue Mar 12 15:31:10 1996
@@ -651,6 +651,7 @@
 	sk->allocation = GFP_KERNEL;
 	sk->sndbuf = SK_WMEM_MAX;
 	sk->rcvbuf = SK_RMEM_MAX;
+	sk->ato = HZ/3;
 	sk->rto = TCP_TIMEOUT_INIT;		/*TCP_WRITE_TIME*/
 	sk->cong_window = 1; /* start with only sending one packet at a time. */
 	sk->priority = 1;
diff -u --recursive --new-file v1.3.72/linux/net/ipv4/ip_output.c linux/net/ipv4/ip_output.c
--- v1.3.72/linux/net/ipv4/ip_output.c	Fri Feb  9 17:53:11 1996
+++ linux/net/ipv4/ip_output.c	Sun Mar 10 09:28:57 1996
@@ -363,7 +363,7 @@
 	 */
 
 	iph = skb->ip_hdr;
-	iph->tot_len = ntohs(skb->len-(((unsigned char *)iph)-skb->data));
+	iph->tot_len = htons(skb->len-(((unsigned char *)iph)-skb->data));
 
 #ifdef CONFIG_FIREWALL
 	if(call_out_firewall(PF_INET, skb, iph) < FW_ACCEPT)
diff -u --recursive --new-file v1.3.72/linux/net/ipv4/raw.c linux/net/ipv4/raw.c
--- v1.3.72/linux/net/ipv4/raw.c	Tue Feb 20 14:37:30 1996
+++ linux/net/ipv4/raw.c	Sun Mar 10 09:28:57 1996
@@ -174,7 +174,8 @@
 	if(offset==0)
 	{
 		struct iphdr *iph=(struct iphdr *)to;
-		iph->saddr=saddr;
+		if(!iph->saddr)
+			iph->saddr=saddr;
 		iph->check=0;
 		iph->tot_len=htons(fraglen);	/* This is right as you cant frag
 					   RAW packets */
diff -u --recursive --new-file v1.3.72/linux/net/ipv4/tcp.c linux/net/ipv4/tcp.c
--- v1.3.72/linux/net/ipv4/tcp.c	Fri Feb 23 13:54:43 1996
+++ linux/net/ipv4/tcp.c	Tue Mar 12 16:57:56 1996
@@ -1347,7 +1347,6 @@
  
 static inline void tcp_eat_skb(struct sock *sk, struct sk_buff * skb)
 {
-	sk->ack_backlog++;
 	skb->sk = sk;
 	__skb_unlink(skb, &sk->receive_queue);
 	kfree_skb(skb, FREE_READ);
@@ -1363,7 +1362,6 @@
 static void cleanup_rbuf(struct sock *sk)
 {
 	struct sk_buff *skb;
-	unsigned long rspace;
 
 	/*
 	 * NOTE! The socket must be locked, so that we don't get
@@ -1375,51 +1373,10 @@
 		tcp_eat_skb(sk, skb);
 	}
 
-	/*
-	 *	FIXME:
-	 *	At this point we should send an ack if the difference
-	 *	in the window, and the amount of space is bigger than
-	 *	TCP_WINDOW_DIFF.
-	 */
-
-	rspace=sock_rspace(sk);
-	if(sk->debug)
-		printk("sk->rspace = %lu\n", rspace);
-	/*
-	 * This area has caused the most trouble.  The current strategy
-	 * is to simply do nothing if the other end has room to send at
-	 * least 3 full packets, because the ack from those will auto-
-	 * matically update the window.  If the other end doesn't think
-	 * we have much space left, but we have room for at least 1 more
-	 * complete packet than it thinks we do, we will send an ack
-	 * immediately.  Otherwise we will wait up to .5 seconds in case
-	 * the user reads some more.
-	 */
-
-	/*
-	 * It's unclear whether to use sk->mtu or sk->mss here.  They differ only
-	 * if the other end is offering a window smaller than the agreed on MSS
-	 * (called sk->mtu here).  In theory there's no connection between send
-	 * and receive, and so no reason to think that they're going to send
-	 * small packets.  For the moment I'm using the hack of reducing the mss
-	 * only on the send side, so I'm putting mtu here.
-	 */
-
-	if (rspace > (sk->window - sk->bytes_rcv + sk->mtu)) 
-	{
-		/* Send an ack right now. */
+	/* If we raised the window due to cleaning up, tell the world.. */
+	if (tcp_raise_window(sk)) {
+		sk->ack_backlog++;
 		tcp_read_wakeup(sk);
-	} 
-	else 
-	{
-		/* Force it to send an ack soon. */
-		int was_active = del_timer(&sk->retransmit_timer);
-		if (!was_active || jiffies+TCP_ACK_TIME < sk->timer.expires) 
-		{
-			tcp_reset_xmit_timer(sk, TIME_WRITE, TCP_ACK_TIME);
-		} 
-		else
-			add_timer(&sk->retransmit_timer);
 	}
 } 
 
diff -u --recursive --new-file v1.3.72/linux/net/ipv4/tcp_input.c linux/net/ipv4/tcp_input.c
--- v1.3.72/linux/net/ipv4/tcp_input.c	Tue Mar  5 10:11:15 1996
+++ linux/net/ipv4/tcp_input.c	Tue Mar 12 16:39:31 1996
@@ -396,6 +396,7 @@
 	newsk->send_tail = NULL;
 	skb_queue_head_init(&newsk->back_log);
 	newsk->rtt = 0;		/*TCP_CONNECT_TIME<<3*/
+	newsk->ato = HZ/3;
 	newsk->rto = TCP_TIMEOUT_INIT;
 	newsk->mdev = 0;
 	newsk->max_window = 0;
@@ -1181,6 +1182,95 @@
 	return(0);
 }
 
+/*
+ * Called for each packet when we find a new ACK endpoint sequence in it
+ */
+static inline u32 tcp_queue_ack(struct sk_buff * skb, struct sock * sk)
+{
+	/*
+	 *	When we ack the fin, we do the FIN 
+	 *	processing.
+	 */
+	skb->acked = 1;
+	if (skb->h.th->fin)
+		tcp_fin(skb,sk,skb->h.th);
+	return skb->end_seq;
+}
+	  
+
+/*
+ * Add a sk_buff to the TCP receive queue, calculating
+ * the ACK sequence as we go..
+ */
+static void tcp_queue(struct sk_buff * skb, struct sock * sk,
+	struct tcphdr *th, unsigned long saddr)
+{
+	struct sk_buff_head * list = &sk->receive_queue;
+	struct sk_buff * next;
+	u32 ack_seq;
+
+	/*
+	 * Find where the new skb goes.. (This goes backwards,
+	 * on the assumption that we get the packets in order)
+	 */
+	next = list->prev;
+	while (next != (struct sk_buff *) list) {
+		if (!after(next->seq, skb->seq))
+			break;
+		next = next->prev;
+	}
+	/*
+	 * put it after the packet we found (which
+	 * may be the list-head, but that's fine).
+	 */
+	__skb_append(next, skb, list);
+	next = skb->next;
+
+	/*
+	 * Did we get anything new to ack?
+	 */
+	ack_seq = sk->acked_seq;
+	if (!after(skb->seq, ack_seq) && after(skb->end_seq, ack_seq)) {
+		ack_seq = tcp_queue_ack(skb, sk);
+
+		/*
+		 * Do we have any old packets to ack that the above
+		 * made visible? (Go forward from skb)
+		 */
+		while (next != (struct sk_buff *) list) {
+			if (after(next->seq, ack_seq))
+				break;
+			if (after(next->end_seq, ack_seq))
+				ack_seq = tcp_queue_ack(next, sk);
+			next = next->next;
+		}
+
+		/*
+		 * Ok, we found new data, update acked_seq as
+		 * necessary (and possibly send the actual
+		 * ACK packet).
+		 *
+		 *      rules for delaying an ack:
+		 *      - delay time <= 0.5 HZ
+		 *      - we don't have a window update to send
+		 *      - must send at least every 2 full sized packets
+		 */
+		sk->acked_seq = ack_seq;
+		if (!sk->delay_acks ||
+		    /* sk->ack_backlog >= sk->max_ack_backlog || */
+		    sk->bytes_rcv > sk->max_unacked || th->fin ||
+		    sk->ato > HZ/2) {
+			tcp_send_ack(sk->sent_seq, sk->acked_seq, sk, th, saddr);
+		}
+		else 
+		{	
+			sk->ack_backlog++;
+			if(sk->debug)				
+				printk("Ack queued.\n");
+			tcp_reset_xmit_timer(sk, TIME_WRITE, sk->ato);	
+		}		
+	}
+}
 
 
 /*
@@ -1192,9 +1282,7 @@
 static int tcp_data(struct sk_buff *skb, struct sock *sk, 
 	 unsigned long saddr, unsigned short len)
 {
-	struct sk_buff *skb1, *skb2;
 	struct tcphdr *th;
-	int dup_dumped=0;
 	u32 new_seq, shut_seq;
 
 	th = skb->h.th;
@@ -1277,170 +1365,7 @@
 
 #endif
 
-	/*
-	 * 	Now we have to walk the chain, and figure out where this one
-	 * 	goes into it.  This is set up so that the last packet we received
-	 * 	will be the first one we look at, that way if everything comes
-	 * 	in order, there will be no performance loss, and if they come
-	 * 	out of order we will be able to fit things in nicely.
-	 *
-	 *	[AC: This is wrong. We should assume in order first and then walk
-	 *	 forwards from the first hole based upon real traffic patterns.]
-	 *	
-	 */
-
-	if (skb_peek(&sk->receive_queue) == NULL) 	/* Empty queue is easy case */
-	{
-		skb_queue_head(&sk->receive_queue,skb);
-		skb1= NULL;
-	} 
-	else
-	{
-		for(skb1=sk->receive_queue.prev; ; skb1 = skb1->prev) 
-		{
-			if(sk->debug)
-			{
-				printk("skb1=%p :", skb1);
-				printk("skb1->seq = %d: ", skb1->seq);
-				printk("skb->seq = %d\n",skb->seq);
-				printk("copied_seq = %d acked_seq = %d\n", sk->copied_seq,
-						sk->acked_seq);
-			}
-			
-			/*
-			 *	Optimisation: Duplicate frame or extension of previous frame from
-			 *	same sequence point (lost ack case).
-			 *	The frame contains duplicate data or replaces a previous frame
-			 *	discard the previous frame (safe as sk->users is set) and put
-			 *	the new one in its place.
-			 */
-			 
-			if (skb->seq==skb1->seq && skb->len>=skb1->len)
-			{
-				skb_append(skb1,skb);
-				skb_unlink(skb1);
-				kfree_skb(skb1,FREE_READ);
-				dup_dumped=1;
-				skb1=NULL;
-				break;
-			}
-			
-			/*
-			 *	Found where it fits
-			 */
-			 
-			if (after(skb->seq+1, skb1->seq))
-			{
-				skb_append(skb1,skb);
-				break;
-			}
-			
-			/*
-			 *	See if we've hit the start. If so insert.
-			 */
-			if (skb1 == skb_peek(&sk->receive_queue))
-			{
-				skb_queue_head(&sk->receive_queue, skb);
-				break;
-			}
-		}
-  	}
-
-	/*
-	 *	Figure out what the ack value for this frame is
-	 */
-	 
-	if (before(sk->acked_seq, sk->copied_seq)) 
-	{
-		printk("*** tcp.c:tcp_data bug acked < copied\n");
-		sk->acked_seq = sk->copied_seq;
-	}
-
-	/*
-	 *	Now figure out if we can ack anything. This is very messy because we really want two
-	 *	receive queues, a completed and an assembly queue. We also want only one transmit
-	 *	queue.
-	 */
-
-	if ((!dup_dumped && (skb1 == NULL || skb1->acked)) || before(skb->seq, sk->acked_seq+1)) 
-	{
-		if (before(skb->seq, sk->acked_seq+1)) 
-		{
-
-			if (after(skb->end_seq, sk->acked_seq)) 
-				sk->acked_seq = skb->end_seq;
-
-			skb->acked = 1;
-
-			/*
-			 *	When we ack the fin, we do the FIN 
-			 *	processing.
-			 */
-
-			if (skb->h.th->fin) 
-			{
-				tcp_fin(skb,sk,skb->h.th);
-			}
-	  
-			for(skb2 = skb->next;
-			    skb2 != (struct sk_buff *)&sk->receive_queue;
-			    skb2 = skb2->next) 
-			{
-				if (before(skb2->seq, sk->acked_seq+1)) 
-				{
-					if (after(skb2->end_seq, sk->acked_seq))
-						sk->acked_seq = skb2->end_seq;
-
-					skb2->acked = 1;
-					/*
-					 * 	When we ack the fin, we do
-					 * 	the fin handling.
-					 */
-					if (skb2->h.th->fin) 
-					{
-						tcp_fin(skb,sk,skb->h.th);
-					}
-
-					/*
-					 *	Force an immediate ack.
-					 */
-					 
-					sk->ack_backlog = sk->max_ack_backlog;
-				}
-				else
-				{
-					break;
-				}
-			}
-
-			/*
-			 *	This also takes care of updating the window.
-			 *	This if statement needs to be simplified.
-			 *
-			 *      rules for delaying an ack:
-			 *      - delay time <= 0.5 HZ
-			 *      - we don't have a window update to send
-			 *      - must send at least every 2 full sized packets
-			 */
-			if (!sk->delay_acks ||
-			    /* sk->ack_backlog >= sk->max_ack_backlog || */
-			    sk->bytes_rcv > sk->max_unacked || th->fin ||
-			    sk->ato > HZ/2 ||
-			    tcp_raise_window(sk)) {
-				tcp_send_ack(sk->sent_seq, sk->acked_seq,sk,th, saddr);
-			}
-			else 
-			{	
-				sk->ack_backlog++;
-			
-				if(sk->debug)				
-					printk("Ack queued.\n");
-				
-				tcp_reset_xmit_timer(sk, TIME_WRITE, sk->ato);
-				
-			}
-		}
-	}
+	tcp_queue(skb, sk, th, saddr);
 
 	/*
 	 *	If we've missed a packet, send an ack.
@@ -1459,7 +1384,7 @@
 		 
 		while (sock_rspace(sk) < sk->mtu) 
 		{
-			skb1 = skb_peek(&sk->receive_queue);
+			struct sk_buff * skb1 = skb_peek(&sk->receive_queue);
 			if (skb1 == NULL) 
 			{
 				printk("INET: tcp.c:tcp_data memory leak detected.\n");
diff -u --recursive --new-file v1.3.72/linux/net/ipv4/tcp_output.c linux/net/ipv4/tcp_output.c
--- v1.3.72/linux/net/ipv4/tcp_output.c	Fri Feb 23 13:54:43 1996
+++ linux/net/ipv4/tcp_output.c	Sun Mar 10 09:28:57 1996
@@ -464,7 +464,8 @@
 		 */
 		 
 		ct++;
-		sk->prot->retransmits ++;
+		sk->retransmits++;
+		sk->prot->retransmits++;
 		tcp_statistics.TcpRetransSegs++;
 		
 
diff -u --recursive --new-file v1.3.72/linux/net/ipv4/tcp_timer.c linux/net/ipv4/tcp_timer.c
--- v1.3.72/linux/net/ipv4/tcp_timer.c	Sat Feb 17 16:02:58 1996
+++ linux/net/ipv4/tcp_timer.c	Sun Mar 10 09:28:57 1996
@@ -70,8 +70,6 @@
 	 * the 120 second clamps though!
 	 */
 
-	sk->retransmits++;
-	sk->prot->retransmits++;
 	sk->backoff++;
 	sk->rto = min(sk->rto << 1, 120*HZ);
 	tcp_reset_xmit_timer(sk, TIME_WRITE, sk->rto);
@@ -208,8 +206,6 @@
 	/*
 	 *	Retransmission
 	 */
-	sk->retransmits++;
-	sk->prot->retransmits++;
 	sk->prot->retransmit (sk, 0);
 	tcp_write_timeout(sk);
 }
diff -u --recursive --new-file v1.3.72/linux/net/unix/af_unix.c linux/net/unix/af_unix.c
--- v1.3.72/linux/net/unix/af_unix.c	Tue Mar  5 10:11:16 1996
+++ linux/net/unix/af_unix.c	Sun Mar 10 09:28:57 1996
@@ -691,6 +691,7 @@
 static struct cmsghdr *unix_copyrights(void *userp, int len)
 {
 	struct cmsghdr *cm;
+
 	if(len>256|| len <=0)
 		return NULL;
 	cm=kmalloc(len, GFP_KERNEL);
@@ -710,6 +711,7 @@
 
 /*
  *	Copy file descriptors into system space.
+ *	Return number copied or negative error code
  */
  
 static int unix_fd_copy(struct sock *sk, struct cmsghdr *cmsg, struct file **fp)
@@ -719,6 +721,7 @@
 	int *fdp=(int *)cmsg->cmsg_data;
 	num/=4;	/* Odd bytes are forgotten in BSD not errored */
 	
+
 	if(num>=UNIX_MAX_FD)
 		return -EINVAL;
 	
@@ -726,11 +729,17 @@
 	 *	Verify the descriptors.
 	 */
 	 
-	for(i=0;i<=num;i++)
+	for(i=0; i< num; i++)
 	{
-		if(fdp[i]<0||fdp[i]>=NR_OPEN)
-			return -EINVAL;
-		if(current->files->fd[fdp[i]]==NULL)
+		int fd;
+		
+		fd = fdp[i];	
+#if 0
+		printk("testing  fd %d\n", fd);
+#endif
+		if(fd < 0|| fd >=NR_OPEN)
+			return -EBADF;
+		if(current->files->fd[fd]==NULL)
 			return -EBADF;
 	}
 	
@@ -741,7 +750,8 @@
 	if(unix_gc_free<num)
 		return -ENOBUFS;
 	
-	for(i=0;i<=num;i++)
+        /* add another reference to these files */
+	for(i=0; i< num; i++)
 	{
 		fp[i]=current->files->fd[fdp[i]];
 		fp[i]->f_count++;
@@ -781,6 +791,7 @@
 		if(current->files->fd[i])
 			n++;
 	}
+	
 	i=NR_OPEN;
 	if(i>current->rlim[RLIMIT_NOFILE].rlim_cur)
 		i=current->rlim[RLIMIT_NOFILE].rlim_cur;
@@ -891,8 +902,9 @@
 	if(flags&MSG_OOB)
 		return -EOPNOTSUPP;
 			
-	if(flags)	/* For now */
+	if(flags)	/* For now */ {
 		return -EINVAL;
+	}
 		
 	if(sunaddr!=NULL)
 	{
@@ -923,13 +935,20 @@
 		   cm->cmsg_level!=SOL_SOCKET ||
 		   msg->msg_accrightslen!=cm->cmsg_len)
 		{
+#if 0
+			printk("Sendmsg: bad access rights\n");
+#endif
 			kfree(cm);
 		   	return -EINVAL;
 		}
 		fpnum=unix_fd_copy(sk,cm,fp);
 		kfree(cm);
-		if(fpnum<0)
+		if(fpnum<0) {
+#if 0
+			printk("Sendmsg error = %d\n", fpnum);
+#endif
 			return fpnum;
+		}
 	}
 
 	while(sent < len)
@@ -1071,14 +1090,21 @@
 
 	if(msg->msg_accrights) 
 	{
+		printk("recvmsg with accrights\n");
 		cm=unix_copyrights(msg->msg_accrights, 
 			msg->msg_accrightslen);
-		if(msg->msg_accrightslen<sizeof(struct cmsghdr)||
+		if(msg->msg_accrightslen<sizeof(struct cmsghdr)
+#if 0 
+/*		investigate this furthur -- Stevens example doen't seem to care */
+		||
 		   cm->cmsg_type!=SCM_RIGHTS ||
 		   cm->cmsg_level!=SOL_SOCKET ||
-		   msg->msg_accrightslen!=cm->cmsg_len)
+		   msg->msg_accrightslen!=cm->cmsg_len
+#endif
+		)
 		{
 			kfree(cm);
+			printk("recvmsg: Bad msg_accrights\n");
 		   	return -EINVAL;
 		}
 	}
diff -u --recursive --new-file v1.3.72/linux/scripts/Makefile linux/scripts/Makefile
--- v1.3.72/linux/scripts/Makefile	Wed Feb  7 15:11:44 1996
+++ linux/scripts/Makefile	Sat Mar  9 13:05:20 1996
@@ -1,4 +1,4 @@
-# HOSTCFLAGS:=$(HOSTCFLAGS) -g
+HOSTCFLAGS:=$(HOSTCFLAGS) -g -Wall
 HEADER=header.tk
 TAIL=tail.tk
 
diff -u --recursive --new-file v1.3.72/linux/scripts/header.tk linux/scripts/header.tk
--- v1.3.72/linux/scripts/header.tk	Wed Feb 28 11:50:18 1996
+++ linux/scripts/header.tk	Sat Mar  9 13:05:20 1996
@@ -5,6 +5,11 @@
 set winy 200
 
 #
+# Create a "reference" object to steal colors from.
+#
+button .ref
+
+#
 # Define some macros we will need to parse the config.in file.
 #
 proc mainmenu_name { text } {
@@ -87,7 +92,7 @@
 	label $w.bm -bitmap questhead
 	pack  $w.bm -pady 10 -side top -padx 10
 	message $w.m -width 400 -aspect 300 \
-		-text "Changes will be lost.  Are you sure?"  -relief raised
+		-text "Changes will be lost.  Are you sure?" -relief flat
 	pack  $w.m -pady 10 -side top -padx 10
 	wm title $w "Are you sure?" 
 
@@ -170,10 +175,14 @@
 			if { $value == "m" } then { set cmd "global $var; set $var 2" }
 			eval $cmd
 		}
-		if [regexp {# ([0-9A-Z_]+) is not set} $line foo var] {
+		if [regexp {# ([0-9A-Za-z_]+) is not set} $line foo var] {
 			set cmd "global $var; set $var 0"
 			eval $cmd
 		}
+		if [regexp {([0-9A-Za-z_]+)=([0-9A-Fa-f]+)} $line foo var value] {
+			set cmd "global $var; set $var $value"
+			eval $cmd
+		}
 	}
 	close $file1
 	update_choices
@@ -189,7 +198,7 @@
 	puts $file2 " */"
 }
 
-proc write_variable { file1 file2 varname variable dep } {
+proc write_tristate { file1 file2 varname variable dep } {
 	if { $variable == 0 } \
 		then { puts $file1 "# $varname is not set"; \
 		       puts $file2 "#undef $varname"} \
@@ -204,6 +213,26 @@
 	}
 }
 
+proc write_int { file1 file2 varname variable dep } {
+	if { $dep == 0 } \
+		then { puts $file1 "# $varname is not set"; \
+		       puts $file2 "#undef $varname"} \
+	else {
+		puts $file1 "$varname=$variable"; \
+		puts $file2 "#define $varname $variable"; \
+	}
+}
+
+proc write_hex { file1 file2 varname variable dep } {
+	if { $dep == 0 } \
+		then { puts $file1 "# $varname is not set"; \
+		       puts $file2 "#undef $varname"} \
+	else {
+		puts $file1 "$varname=$variable"; \
+		puts $file2 "#define $varname 0x$variable"; \
+	}
+}
+
 proc option_name {w mnum line text variable} {
 	button $w.x$line.help -text "Help" -relief raised \
 		-command "dohelp .dohelp $variable"
@@ -237,24 +266,29 @@
 	pack $w.x$line -anchor w -fill both -expand on
 }
 
-proc dep_tristate {w mnum line text variable } {
+proc dep_tristate {w mnum line text variable depend } {
 	tristate $w $mnum $line $text $variable
 }
 
 proc int { w mnum line text variable } {
 	frame $w.x$line
 	option_name $w $mnum $line $text $variable
-	entry $w.x$line.x -width 15 -relief sunken -borderwidth 2 \
+	entry $w.x$line.x -width 18 -relief sunken -borderwidth 2 \
 		-textvariable $variable
 	pack $w.x$line.x -anchor w -side right -fill y
 	pack $w.x$line -anchor w -fill both -expand on
 }
 
+proc hex { w mnum line text variable } {
+	int $w $mnum $line $text $variable
+}
+
 proc minimenu { w mnum line text variable } {
 	frame $w.x$line
 	option_name $w $mnum $line $text $variable
-	menubutton $w.x$line.x -text "Choose..." -menu $w.x$line.x.menu \
-		-relief raised -width 15
+	menubutton $w.x$line.x -textvariable $variable -menu \
+		$w.x$line.x.menu -relief raised -indicatoron 1 \
+		-width 15 -anchor w
 	pack $w.x$line.x -anchor w -side right -fill y
 	pack $w.x$line -anchor w -fill both -expand on
 }
@@ -267,7 +301,7 @@
 #nothing to do for now.
 }
 
-proc dohelp {w varname }  {
+proc dohelp_old_version_ignore_me {w varname }  {
 	catch {destroy $w}
 	toplevel $w -class Dialog
 
@@ -323,6 +357,75 @@
 		-width 10 -command "destroy $w; focus $oldFocus"
 	pack $w.f.back -side bottom -pady 10 -anchor s
 	pack $w.f -pady 10 -side top -padx 10 -anchor s
+	focus $w
+	global winx; global winy
+	set winx [expr [winfo x .]+30]; set winy [expr [winfo y .]+30]
+	wm geometry $w +$winx+$winy
+}
+
+
+proc dohelp {w varname }  {
+	catch {destroy $w}
+	toplevel $w -class Dialog
+
+	set filefound 0
+	set found 0
+	set lineno 0
+
+	if { [file readable Documentation/Configure.help] == 1} then {
+		set filefound 1
+		set message [exec awk "
+			BEGIN {
+				start=0;
+			}
+			/^$varname\[ 	\]*\$/ {
+				start=1;
+				printf(\"%s:\\n\\n\",\$0);
+				continue;
+			}
+			!/^\[ 	\]/ {
+				start=0;
+			}
+			/^\[ 	\]*/ && start==1 {
+				gsub(\"^\[ 	\]*\",\"\");
+				printf(\"%s \",\$0);
+			}
+			" Documentation/Configure.help]
+		set found [expr [string length "$message"] > 0]
+	}
+	
+	frame $w.f1
+
+	if { $found == 0 } then {
+		if { $filefound == 0 } then {
+		message $w.f1.m -width 750 -aspect 300 -relief flat -text \
+			"No help available - unable to open file Documentation/Configure.help.  This file should have come with your kernel."
+		} else {
+		message $w.f1.m -width 400 -aspect 300 -relief flat -text \
+			"No help available for $varname"
+		}
+		label $w.f1.bm -bitmap error
+		wm title $w "RTFM"
+	} else {
+		message $w.f1.m -width 400 -aspect 300 -text $message \
+			 -relief flat
+		label $w.f1.bm -bitmap info
+		wm title $w "Configuration help" 
+	}
+	pack $w.f1.bm $w.f1.m -side left -padx 10
+	pack $w.f1 -side top
+	set oldFocus [focus]
+	
+	# Do the OK button
+	#
+	frame $w.f2
+	button $w.f2.ok -text "OK" -activebackground green \
+		-width 10 -command "destroy $w; focus $oldFocus"
+	pack $w.f2.ok -side bottom -pady 10 -anchor s
+	pack $w.f2 -side bottom -padx 10 -anchor s
+
+	# Finish off the window
+	#
 	focus $w
 	global winx; global winy
 	set winx [expr [winfo x .]+30]; set winy [expr [winfo y .]+30]
diff -u --recursive --new-file v1.3.72/linux/scripts/patch-kernel linux/scripts/patch-kernel
--- v1.3.72/linux/scripts/patch-kernel	Sun Mar 10 09:49:57 1996
+++ linux/scripts/patch-kernel	Mon Mar 11 09:06:15 1996
@@ -36,11 +36,11 @@
     fi
 
     echo -n "Applying $patch... "
-    if (gunzip -dc $patchdir/$patch | grep -v '^\\' | patch -p1 -s -E -d $sourcedir)
+    if gunzip -dc $patchdir/$patch | patch -p1 -s -N -E -d $sourcedir
     then
-	echo "done"
+	echo "done."
     else
-        echo "Patch failed.  Clean up yourself."
+        echo "failed.  Clean up yourself."
         break
     fi
     if [ "`find $sourcedir '(' -name '*.rej' -o -name '.*.rej' ')' -print`" ]
diff -u --recursive --new-file v1.3.72/linux/scripts/tkcond.c linux/scripts/tkcond.c
--- v1.3.72/linux/scripts/tkcond.c	Thu Nov  9 11:23:56 1995
+++ linux/scripts/tkcond.c	Sat Mar  9 13:05:20 1996
@@ -39,7 +39,7 @@
  * Walk a condition chain and invert it so that the logical result is
  * inverted.
  */
-static int invert_condition(struct condition * cnd)
+static void invert_condition(struct condition * cnd)
 {
   /*
    * This is simple.  Just walk through the list, and invert
@@ -69,6 +69,8 @@
 	case op_eq:
 	  cnd->op = op_neq;
 	  break;
+	default:
+	  break;
 	}
     }
 }
@@ -76,7 +78,7 @@
 /*
  * Walk a condition chain, and free the memory associated with it.
  */
-static int free_condition(struct condition * cnd)
+static void free_condition(struct condition * cnd)
 {
   struct condition * next;
   for(;cnd; cnd = next)
@@ -190,7 +192,9 @@
 		   */
 		  for(cfg = config;cfg != NULL; cfg = cfg->next)
 		    {
-		      if( cfg->tok != tok_bool && cfg->tok != tok_int
+		      if( cfg->tok != tok_bool
+		         && cfg->tok != tok_int
+		         && cfg->tok != tok_hex
 			 && cfg->tok != tok_tristate 
 			 && cfg->tok != tok_choice
 			 && cfg->tok != tok_dep_tristate)
@@ -251,12 +255,10 @@
 struct condition * get_token_cond_frag(struct condition * cond, 
 				       struct condition ** last)
 {
-  int i;
   struct condition * newcond;
   struct condition * tail;
   struct condition * new;
   struct condition * ocond;
-  struct kconfig * cfg;
 
   newcond = tail = NULL;
 
@@ -293,7 +295,7 @@
 /*
  * Walk through the if conditionals and maintain a chain.
  */
-int fix_conditionals(struct kconfig * scfg)
+void fix_conditionals(struct kconfig * scfg)
 {
   int depth = 0;
   int i;
@@ -354,8 +356,8 @@
 	case tok_menuoption:
 	case tok_bool:
 	case tok_tristate:
-	case tok_dep_tristate:
 	case tok_int:
+	case tok_hex:
 	case tok_choice:
 	  /*
 	   * We need to duplicate the chain of conditions and attach them to
@@ -363,6 +365,18 @@
 	   */
 	  cfg->cond = get_token_cond(&conditions[0], depth);
 	  break;
+	case tok_dep_tristate:
+	  /*
+	   * Same as tok_tristate et al except we have a temporary
+	   * conditional. (Sort of a hybrid tok_if, tok_tristate, tok_fi
+	   * option)
+	   */
+	  conditions[depth] = cfg->cond;
+	  depth++;
+	  cfg->cond = get_token_cond(&conditions[0], depth);
+	  depth--;
+	  free_condition(conditions[depth]);
+	  conditions[depth] = NULL;
 	default:
 	  break;
 	}
@@ -386,6 +400,7 @@
 	case tok_tristate:
 	case tok_dep_tristate:
 	case tok_int:
+	case tok_hex:
 	  for(cfg1=cfg;cfg1 != NULL; cfg1 = cfg1->next)
 	    {
 	      switch(cfg1->tok)
@@ -395,6 +410,7 @@
 		case tok_tristate:
 		case tok_dep_tristate:
 		case tok_int:
+		case tok_hex:
 		  if( strcmp(cfg->optionname, cfg1->optionname) == 0)
 		    {
 		      cfg->flags |= CFG_DUP;
diff -u --recursive --new-file v1.3.72/linux/scripts/tkgen.c linux/scripts/tkgen.c
--- v1.3.72/linux/scripts/tkgen.c	Sat Mar  2 10:43:47 1996
+++ linux/scripts/tkgen.c	Sat Mar  9 13:05:20 1996
@@ -4,12 +4,41 @@
  * Eric Youngdale
  * 10/95
  *
- * 1996 01 04 - Avery Pennarun - Aesthetic improvements
- *              <apenwarr@foxnet.net>
+ * 1996 01 04
+ * Avery Pennarun - Aesthetic improvements.
  *
- * 1996 01 24 - Avery Pennarun - Bugfixes and more aesthetics
+ * 1996 01 24
+ * Avery Pennarun - Bugfixes and more aesthetics.
+ *
+ * 1996 03 08
+ * Avery Pennarun - The int and hex config.in commands work right.
+ *                - Choice buttons are more user-friendly.
+ *                - Disabling a text entry line greys it out properly.
+ *		  - dep_tristate now works like in Configure. (not pretty)
+ *                - No warnings in gcc -Wall. (Fixed some "interesting" bugs.)
+ *                - Faster/prettier "Help" lookups.
+ *
+ * TO DO:
+ *   - clean up - there are useless ifdef's everywhere.
+ *   - do more sensible things with the 'config -resizable" business.
+ *   - better comments throughout - C code generating tcl is really cryptic.
+ *   - eliminate silly "update idletasks" hack to improve display speed.
+ *   - make tabstops work left->right instead of right->left.
+ *   - make canvas contents resize with the window (good luck).
+ *   - make next/prev buttons go to next/previous menu.
+ *   - some way to make submenus inside of submenus (ie. Main->Networking->IP)
+ *           (perhaps a button where the description would be)
+ *   - make the main menu use the same tcl code as the submenus.
+ *   - make choice and int/hex input types line up vertically with
+ *           bool/tristate.
+ *   - general speedups - how?  The canvas seems to slow it down a lot.
+ *   - choice buttons should default to the first menu option, rather than a
+ *           blank.  Also look up the right variable when the help button
+ *           is pressed.
+ *   
  */
 #include <stdio.h>
+#include <unistd.h>
 #include "tkparse.h"
 
 #ifndef TRUE
@@ -36,15 +65,15 @@
  * Generate portion of wish script for the beginning of a submenu.
  * The guts get filled in with the various options.
  */
-static start_proc(char * label, int menu_num, int flag)
+static void start_proc(char * label, int menu_num, int flag)
 {
   if( flag )
     printf("menu_option menu%d %d \"%s\"\n", menu_num, menu_num, label);
   printf("proc menu%d {w title} {\n", menu_num);
   printf("\tcatch {destroy $w}\n");
   printf("\ttoplevel $w -class Dialog\n");
-  printf("\tmessage $w.m -width 400 -aspect 300 -background grey -text \\\n");
-  printf("\t\t\"%s\"  -relief raised -bg grey\n",label);
+  printf("\tmessage $w.m -width 400 -aspect 300 -text \\\n");
+  printf("\t\t\"%s\"  -relief raised\n",label);
   printf("\tpack $w.m -pady 10 -side top -padx 10\n");
   printf("\twm title $w \"%s\" \n\n", label);
   
@@ -75,7 +104,7 @@
  * a global declaration so we know whether we need to insert one for a
  * given function or not.
  */
-clear_globalflags(struct kconfig * cfg)
+void clear_globalflags(struct kconfig * cfg)
 {
   for(; cfg != NULL; cfg = cfg->next)
   {
@@ -87,12 +116,11 @@
  * This function walks the chain of conditions that we got from cond.c,
  * and creates a wish conditional to enable/disable a given widget.
  */
-generate_if(struct kconfig * item,
+void generate_if(struct kconfig * item,
 	    struct condition * cond,
 	    int menu_num,
 	    int line_num)
 {
-  int i;
   struct condition * ocond;
 
   ocond = cond;
@@ -173,8 +201,10 @@
 	else if( strcmp(cond->variable.str, "m") == 0 )
 	  printf("2");
 	else
-	  printf("\"%s\"", cond->variable);
+	  printf("\"%s\"", cond->variable.str);
 	break;
+      default:
+        break;
       }
       cond = cond->next;
     }
@@ -195,11 +225,12 @@
 	     menu_num, menu_num);
       break;
     case tok_int:
+    case tok_hex:
       printf("} then { ");
-      printf(".menu%d.config.f.x%d.x configure -state normal; ", menu_num, line_num);
+      printf(".menu%d.config.f.x%d.x configure -state normal -fore [ .ref cget -foreground ]; ", menu_num, line_num);
       printf(".menu%d.config.f.x%d.l configure -state normal; ", menu_num, line_num);
       printf("} else { ");
-      printf(".menu%d.config.f.x%d.x configure -state disabled -fore gray60;", menu_num, line_num );
+      printf(".menu%d.config.f.x%d.x configure -state disabled -fore [ .ref cget -disabledforeground ];", menu_num, line_num );
       printf(".menu%d.config.f.x%d.l configure -state disabled;", menu_num, line_num );
       printf("}\n");
       break;
@@ -234,7 +265,8 @@
       if( item->tok == tok_dep_tristate )
 	{
 	  printf("global %s;", item->depend.str);
-	  printf("if { $%s == 2 } then {", item->depend.str);
+	  printf("if { $%s != 1 && $%s != 0 } then {", 
+	  	item->depend.str,item->depend.str);
 	  printf(".menu%d.config.f.x%d.y configure -state disabled;",menu_num, line_num);
 	  printf("} else {");
 	  printf(".menu%d.config.f.x%d.y configure -state normal;",menu_num, line_num);
@@ -280,7 +312,7 @@
  * need to decide whether to write out a given configuration variable
  * to the output file.
  */
-generate_if_for_outfile(struct kconfig * item,
+void generate_if_for_outfile(struct kconfig * item,
 	    struct condition * cond)
 {
   struct condition * ocond;
@@ -352,8 +384,10 @@
 	else if( strcmp(cond->variable.str, "m") == 0 )
 	  printf("2");
 	else
-	  printf("\"%s\"", cond->variable);
+	  printf("\"%s\"", cond->variable.str);
 	break;
+      default:
+        break;
       }
       cond = cond->next;
     }
@@ -368,21 +402,28 @@
   switch(item->tok)
     {
     case tok_define:
-      printf("} then {write_variable $cfg $autocfg %s %s $notmod }\n", item->optionname, item->value);
+      printf("} then {write_tristate $cfg $autocfg %s %s $notmod }\n", item->optionname, item->value);
       break;
     case tok_comment:
       printf("} then {write_comment $cfg $autocfg \"%s\"}\n", item->label);
       break;
     case tok_dep_tristate:
-      printf("} then { write_variable $cfg $autocfg %s $%s $%s } \n", 
+      printf("} then { write_tristate $cfg $autocfg %s $%s $%s } \n", 
 	     item->optionname, item->optionname, item->depend.str);
       break;
     case tok_tristate:
     case tok_bool:
-    case tok_int:
-      printf("} then { write_variable $cfg $autocfg %s $%s $notmod }\n", 
+      printf("} then { write_tristate $cfg $autocfg %s $%s $notmod }\n", 
 	     item->optionname, item->optionname);
       break;
+    case tok_int:
+      printf("} then { write_int $cfg $autocfg %s $%s $notmod }\n",
+             item->optionname, item->optionname);
+      break;
+    case tok_hex:
+      printf("} then { write_hex $cfg $autocfg %s $%s $notmod }\n",
+             item->optionname, item->optionname);
+      break;
     case tok_choose:
     case tok_choice:
       fprintf(stderr,"Fixme\n");
@@ -395,7 +436,7 @@
 /*
  * Generates a fragment of wish script that closes out a submenu procedure.
  */
-static end_proc(int menu_num, int first, int last)
+static void end_proc(int menu_num, int first, int last)
 {
   struct kconfig * cfg;
 
@@ -521,10 +562,10 @@
 	  if(cfg->tok == tok_dep_tristate)
 	    {
 	      printf("\tglobal %s;", cfg->depend.str);
-	      printf("\tif {$%s == 2 } then { .menu%d.config.f.x%d.y configure -state disabled } else { .menu%d.config.f.x%d.y configure -state normal}\n",cfg->depend.str,
+	      printf("\tif {$%s != 1 && $%s != 0 } then { .menu%d.config.f.x%d.y configure -state disabled } else { .menu%d.config.f.x%d.y configure -state normal}\n",
+		     cfg->depend.str,cfg->depend.str,
 		     menu_num, cfg->menu_line,
 		     menu_num, cfg->menu_line);
-	      
 	    }
 	}
 
@@ -540,14 +581,13 @@
  * into submenus.  This function just calculates how many submenus,
  * and how many items go in each submenu.
  */
-static int find_menu_size(struct kconfig *cfg,
+static void find_menu_size(struct kconfig *cfg,
 			  int *menu_max, 
 			  int *menu_maxlines)
 
 {
   struct kconfig * pnt;
   int tot;
-  int div;
   
   /*
    * First count up the number of options in this menu.
@@ -562,6 +602,7 @@
       case tok_tristate:
       case tok_dep_tristate:
       case tok_int:
+      case tok_hex:
       case tok_choose:
       case tok_sound:
 	tot++;
@@ -572,26 +613,15 @@
       }
   }
 
-#ifdef OLD_SPLIT_MENUS
-  /*
-   * Now figure out how many items go on each page.
-   */
-  div = 1;
-  while(tot / div > 15) div++;
-  *menu_max = cfg->menu_number + div - 1;
-  *menu_maxlines = (tot + div -1) / div;
-#else
   *menu_max = cfg->menu_number;
   *menu_maxlines = tot;
-#endif
 }
 
 /*
  * This is the top level function for generating the tk script.
  */
-dump_tk_script(struct kconfig *scfg)
+void dump_tk_script(struct kconfig *scfg)
 {
-  int i;
   int menu_num =0;
   int menu_max =0;
   int menu_min =0;
@@ -629,6 +659,7 @@
 	case tok_tristate:
 	case tok_dep_tristate:
 	case tok_int:
+	case tok_hex:
 	case tok_choose:
 	case tok_sound:
 	  /*
@@ -707,11 +738,11 @@
 	  break;
 
 	case tok_choice:
-	  printf("\t$w.config.f.x%d.x.menu add radiobutton -label \"%s\" -variable %s -value %d -command \"update_menu%d .menu%d.config.f\"\n",
+	  printf("\t$w.config.f.x%d.x.menu add radiobutton -label \"%s\" -variable %s -value \"%s\" -command \"update_menu%d .menu%d.config.f\"\n",
 		 cfg1->menu_line,
 		 cfg->label,
 		 cfg1->optionname,
-		 cfg->choice_value,
+		 cfg->label,
 		 cfg1->menu_number, cfg1->menu_number);
 	  break;
 	case tok_choose:
@@ -721,20 +752,13 @@
 	      start_proc(menulabel, cfg->menu_number, FALSE);
 	      menu_num = cfg->menu_number;
 	    }
-#if 0
-	  printf("\tmenubutton $w.config.f.line%d -text \"%s\" -menu $w.config.f.line%d.menu \\\n",
-		 cfg->menu_line, cfg->label, cfg->menu_line);
-	  printf("\t	-relief raised -width 35\n");
-	  printf("\tpack $w.config.f.line%d -anchor w\n", cfg->menu_line);
-	  printf("\tmenu $w.config.f.line%d.menu\n", cfg->menu_line);
-#else
+	  printf("\tglobal %s\n",cfg->optionname);
 	  printf("\tminimenu $w.config.f %d %d \"%s\" %s\n",
 	  	cfg->menu_number,
 	  	cfg->menu_line,
 	  	cfg->label,
 	  	cfg->optionname);
 	  printf("\tmenu $w.config.f.x%d.x.menu\n", cfg->menu_line);
-#endif
 	  cfg1 = cfg;
 	  break;
 	case tok_tristate:
@@ -757,12 +781,12 @@
 	      start_proc(menulabel, cfg->menu_number, FALSE);
 	      menu_num = cfg->menu_number;
 	    }
-	  printf("\tdep_tristate $w.config.f %d %d \"%s\" %s\n",
+	  printf("\tdep_tristate $w.config.f %d %d \"%s\" %s %s\n",
 		 cfg->menu_number,
 		 cfg->menu_line,
 		 cfg->label,
 		 cfg->optionname,
-		 cfg->depend);
+		 cfg->depend.str);
 	  break;
 	case tok_int:
 	  if( cfg->menu_number != menu_num )
@@ -777,6 +801,20 @@
 		 cfg->label,
 		 cfg->optionname);
 	  break;
+	case tok_hex:
+	  if( cfg->menu_number != menu_num )
+	    {
+	      end_proc(menu_num, menu_min, menu_max);
+	      start_proc(menulabel, cfg->menu_number, FALSE);
+	      menu_num = cfg->menu_number;
+	    }
+	  printf("\thex $w.config.f %d %d \"%s\" %s\n",
+		 cfg->menu_number,
+		 cfg->menu_line,
+		 cfg->label,
+		 cfg->optionname);
+	  break;
+#ifdef INCOMPAT_SOUND_CONFIG
 	case tok_sound:
 	  if( cfg->menu_number != menu_num )
 	    {
@@ -788,6 +826,7 @@
 		 cfg->menu_number,
 		 cfg->menu_line);
 	  break;
+#endif
 	default:
 	  break;
 	}
@@ -869,15 +908,18 @@
     {
       switch (cfg->tok)
 	{
-	case tok_int:
 	case tok_bool:
 	case tok_tristate:
 	case tok_dep_tristate:
 	case tok_choice:
 	  printf("set %s 0\n", cfg->optionname);
 	  break;
+	case tok_int:
+	case tok_hex:
+	  printf("set %s %s\n", cfg->optionname, cfg->value);
+	  break;
 	case tok_choose:
-	  printf("set %s %d\n", cfg->optionname, cfg->choice_value);
+	  printf("set %s \"(not set)\"\n",cfg->optionname);
 	default:
 	  break;
 	}
@@ -906,6 +948,7 @@
       switch (cfg->tok)
 	{
 	case tok_int:
+	case tok_hex:
 	case tok_bool:
 	case tok_tristate:
 	case tok_dep_tristate:
@@ -923,9 +966,9 @@
 	      if(cfg->tok == tok_dep_tristate)
 		{
 		  printf("\tif {$%s == 0 } then {\n"
-		  	 "\t\twrite_variable $cfg $autocfg %s $notset $notmod\n"
+		  	 "\t\twrite_tristate $cfg $autocfg %s $notset $notmod\n"
 		  	 "\t} else {\n"
-		  	 "\t\twrite_variable $cfg $autocfg %s $%s $%s\n"
+		  	 "\t\twrite_tristate $cfg $autocfg %s $%s $%s\n"
 		  	 "\t}\n",
 		  	 cfg->depend.str,
 			 cfg->optionname,
@@ -950,18 +993,29 @@
 		      cfg1 != NULL && cfg1->tok == tok_choice;
 		      cfg1 = cfg1->next)
 		    {
-		      printf("\tif { $%s == %d } then { write_variable $cfg $autocfg %s 1 $notmod }\n",
+		      printf("\tif { $%s == \"%s\" } then { write_tristate $cfg $autocfg %s 1 $notmod }\n",
 			     cfg->optionname,
-			     cfg1->choice_value,
+			     cfg1->label,
 			     cfg1->optionname);
 		    }
 		}
+	      else if (cfg->tok == tok_int )
+	        {
+		  printf("\twrite_int $cfg $autocfg %s $%s $notmod\n",
+			 cfg->optionname,
+			 cfg->optionname);
+	        }
+	      else if (cfg->tok == tok_hex )
+	        {
+		  printf("\twrite_hex $cfg $autocfg %s $%s $notmod\n",
+			 cfg->optionname,
+			 cfg->optionname);
+	        }
 	      else
 		{
-		  printf("\twrite_variable $cfg $autocfg %s $%s $notmod\n",
+		  printf("\twrite_tristate $cfg $autocfg %s $%s $notmod\n",
 			 cfg->optionname,
 			 cfg->optionname);
-			 
 		}
 	    }
 	  break;
@@ -1001,10 +1055,10 @@
 	  cfg1 = cfg1->next)
 	{
 	  printf("\tglobal %s\n", cfg1->optionname);
-	  printf("\tif { $%s == 1 } then { set %s %d }\n",
+	  printf("\tif { $%s == 1 } then { set %s \"%s\" }\n",
 		 cfg1->optionname,
 		 cfg->optionname,
-		 cfg1->choice_value);
+		 cfg1->label);
 	}
     }
   printf("}\n\n\n");
diff -u --recursive --new-file v1.3.72/linux/scripts/tkparse.c linux/scripts/tkparse.c
--- v1.3.72/linux/scripts/tkparse.c	Tue Jan 23 21:15:56 1996
+++ linux/scripts/tkparse.c	Sat Mar  9 13:05:20 1996
@@ -250,7 +250,8 @@
       if( strcmp(kcfg->label, choice_kcfg->value) == 0 )
 	choice_kcfg->choice_value = kcfg->choice_value;
     }
-
+    
+    return pnt;
 }
 
 
@@ -262,7 +263,6 @@
  */
 static char * get_string(char *pnt, char ** labl)
 {
-  char quotechar;
   char newlabel[1024];
   char * pnt1;
   char * pnt2;
@@ -290,10 +290,10 @@
  * and the result is that we create a token that describes this line
  * and insert it into our linked list.
  */
-int parse(char * pnt) {
+void parse(char * pnt) {
   enum token tok;
   struct kconfig * kcfg;
-  char tmpbuf[24];
+  char tmpbuf[24],fake_if[1024];
 
   /*
    * Ignore comments and leading whitespace.
@@ -366,6 +366,11 @@
       tok = tok_int;
       pnt += 3;
     }
+  else if (strncmp(pnt, "hex", 3) == 0) 
+    {
+      tok = tok_hex;
+      pnt += 3;
+    }
   else if (strncmp(pnt, "if", 2) == 0) 
     {
       tok = tok_if;
@@ -390,13 +395,13 @@
   if( tok == tok_unknown)
     {
       if( clast != NULL && clast->tok == tok_if 
-	  && strcmp(pnt,"then") == 0) return 0;
+	  && strcmp(pnt,"then") == 0) return;
       if( current_file != NULL )
 	fprintf(stderr, "unknown command=%s(%s %d)\n", pnt,
 		current_file, lineno);
       else
 	fprintf(stderr, "unknown command=%s(%d)\n", pnt,lineno);
-      return 1;
+      return;
     }
 
   /*
@@ -448,9 +453,14 @@
       break;
     case tok_bool:
     case tok_tristate:
+      pnt = get_qstring(pnt, &kcfg->label);
+      pnt = get_string(pnt, &kcfg->optionname);
+      break;
     case tok_int:
+    case tok_hex:
       pnt = get_qstring(pnt, &kcfg->label);
       pnt = get_string(pnt, &kcfg->optionname);
+      pnt = get_string(pnt, &kcfg->value);
       break;
     case tok_dep_tristate:
       pnt = get_qstring(pnt, &kcfg->label);
@@ -458,6 +468,26 @@
       pnt = skip_whitespace(pnt);
       if( *pnt == '$') pnt++;
       pnt = get_string(pnt, &kcfg->depend.str);
+
+      /*
+       * Create a conditional for this object's dependency.
+       *
+       * We can't use "!= n" because this is internally converted to "!= 0"
+       * and if UMSDOS depends on MSDOS which depends on FAT, then when FAT
+       * is disabled MSDOS has 16 added to its value, making UMSDOS fully
+       * available.  Whew.
+       *
+       * This is more of a hack than a fix.  Nested "if" conditionals are
+       * probably affected too - that +/- 16 affects things in too many
+       * places.  But this should do for now.
+       */
+      sprintf(fake_if,"[ \"$%s\" = \"y\" -o \"$%s\" = \"m\" ]; then",
+	      	kcfg->depend.str,kcfg->depend.str);
+      kcfg->cond = parse_if(fake_if);
+      if(kcfg->cond == NULL )
+	{
+	  exit(1);
+	}
       break;
     case tok_comment:
       pnt = get_qstring(pnt, &kcfg->label);
@@ -486,7 +516,7 @@
     case tok_if:
       /*
        * Conditionals are different.  For the first level parse, only
-       * tok_if items have a ->cond chain attached.
+       * tok_if and tok_dep_tristate items have a ->cond chain attached.
        */
       kcfg->cond = parse_if(pnt);
       if(kcfg->cond == NULL )
@@ -496,14 +526,15 @@
       break;
     default:
       exit(0);
-
     }
+    
+    return;
 }
 
 /*
  * Simple function to dump to the screen what the condition chain looks like.
  */
-dump_if(struct condition * cond)
+void dump_if(struct condition * cond)
 {
   printf(" ");
   while(cond != NULL )
@@ -528,11 +559,13 @@
 	printf(")");
 	break;
       case op_variable:
-	printf("$%s", cond->variable);
+	printf("$%s", cond->variable.str);
 	break;
       case op_constant:
-	printf("'%s'", cond->variable);
+	printf("'%s'", cond->variable.str);
 	break;
+      default:
+        break;
       }
       cond = cond->next;
     }
@@ -604,12 +637,14 @@
   return 0;
 }
 
-main(int argc, char * argv[])
+int main(int argc, char * argv[])
 {
+#if 0
   char buffer[1024];
   char * pnt;
   struct kconfig * cfg;
   int    i;
+#endif
 
   /*
    * Read stdin to get the top level script.
@@ -663,6 +698,9 @@
 	case tok_int:
 	  printf("int ");
 	  break;
+	case tok_hex:
+	  printf("hex ");
+	  break;
 	case tok_comment:
 	  printf("comment ");
 	  break;
@@ -692,6 +730,7 @@
 	case tok_tristate:
 	case tok_dep_tristate:
 	case tok_int:
+	case tok_hex:
 	  printf("%s %s\n", cfg->label, cfg->optionname);
 	  break;
 	case tok_if:
diff -u --recursive --new-file v1.3.72/linux/scripts/tkparse.h linux/scripts/tkparse.h
--- v1.3.72/linux/scripts/tkparse.h	Tue Jan 23 21:15:56 1996
+++ linux/scripts/tkparse.h	Sat Mar  9 13:05:20 1996
@@ -11,6 +11,7 @@
   tok_else, 
   tok_fi, 
   tok_int,
+  tok_hex,
   tok_sound,
   tok_define,
   tok_choose,
@@ -75,3 +76,8 @@
 extern struct kconfig * clast;
 extern struct kconfig * koption;
 
+/*
+ * Prototypes
+ */
+void fix_conditionals(struct kconfig * scfg);	/* tkcond.c */
+void dump_tk_script(struct kconfig *scfg);	/* tkgen.c  */
