diff -u --recursive --new-file v2.0.10/linux/Documentation/Changes linux/Documentation/Changes
--- v2.0.10/linux/Documentation/Changes	Tue Jul 23 10:26:49 1996
+++ linux/Documentation/Changes	Sat Aug  3 11:46:51 1996
@@ -26,7 +26,11 @@
 valtozasokrol, az alabbi cimen megtalaljak Nyitrai Tamas forditasat:
 http://www.datanet.hu/generations/linux/newkernel.html.
 
-Last updated: July 21, 1996.
+   For people who prefer Japanse (thanks to Mitsuhiro Kojima): Kono
+bunshou no nihongo ban ha
+http://jf.gee.kyoto-u.ac.jp/JF/v2.0/Changes-2.0.html ni arimasu.
+
+Last updated: July 29, 1996.
 Current Author: Chris Ricker (gt1355b@prism.gatech.edu).
 
 Current Releases
@@ -41,7 +45,7 @@
 - Linux C++ Library	 2.7.1.4
 - Termcap		 2.0.8
 - Procps		 1.01
-- Gpm			 1.09
+- Gpm			 1.10
 - SysVinit		 2.64
 - Util-linux		 2.5
 - Mount                  2.5k
@@ -82,6 +86,11 @@
 you're using more unusual loaders like SysLinux or etherboot, the
 latest versions are 1.3 and 2.0, respectively.
 
+   Ramdisk support does not work with the latest kernels if ramdisk=0
+option is present.  Many older distributions (mainly Slackware) have
+this option in their lilo.config file.  Comment it out and re-run lilo
+if you need ramdisks.
+
 The Linux C Library
 ===================
 
@@ -123,14 +132,8 @@
 
    in linux/fs/locks.c and recompile.  If you're still running a.out,
 there's an unofficial libc-4.7.6 release out to which you can upgrade
-to fix this problem.
-
-The Termcap Library
-===================
-
-   The current Termcap release is 2.0.8. If you upgrade to this release
-read the `README' file contained into the package to get some important
-information about the `tgetent' function changes!
+to fix this problem.  Libc is available from
+ftp://sunsite.unc.edu/pub/Linux/GCC/.
 
 Procps utilities
 ================
@@ -138,18 +141,17 @@
    Due to changes in the structure of the /proc filesystem, you need to
 upgrade procps to the latest release, currently 1.01.  Otherwise,
 you'll get floating point errors with some ps commands or other similar
-surprises.
+surprises.  Grab
+ftp://sunsite.unc.edu/pub/Linux/system/Status/ps/procps-1.01.tgz.
 
 Kernel Modules
 ==============
 
    Almost all drivers in 2.0.x can be modules, and kerneld is now
 incorporated into the kernel.  To take advantage of this, you'll need
-the latest version of the module support apps, currently 2.0.0. These
-should be available at the same place you picked up your kernel
-(ftp://ftp.funet.fi/pub/Linux/kernel/src/) or the home page,
-http://www.pi.se/blox/modules/index.html.  Note: If you try to load a
-module and get a message like
+the latest version of the module support apps. These are available at
+http://www.pi.se/blox/modules/modules-2.0.0.tar.gz.  Note: If you try to
+load a module and get a message like
 
    `gcc2_compiled, undefined Failed to load module!  The symbols from
 kernel 1.3.foo don't match 1.3.foo'
@@ -190,7 +192,8 @@
 
    If you're trying to run NCSA httpd, you might have problems with
 pre-spawning daemons.  Upgrade to the latest release (1.5.2), available
-from http://hoohoo.ncsa.uiuc.edu/.
+from http://hoohoo.ncsa.uiuc.edu/ or check out Apache
+(http://www.apache.org/).
 
    The new named pipe behavior also causes problems with Hylafax.  If
 you're running the hylafax daemon, it will just keep eating up CPU time
@@ -223,7 +226,7 @@
 
    Older uugettys will not allow use of a bidirectional serial line.  To
 fix this problem, upgrade to
-ftp://sunsite.unc.edu/pub/Linux/system/Serial/getty_ps-2.0.7h.tar.gz.
+ftp://sunsite.unc.edu/pub/Linux/system/Serial/getty_ps-2.0.7i.tar.gz.
 
 Kbd
 ===
@@ -253,7 +256,10 @@
    ln -s /usr/lib/terminfo/l/linux /usr/lib/terminfo/c/console
 
    Better yet, just get the latest official Linux termcap from
-ftp://sunsite.unc.edu/pub/Linux/GCC/termcap-2.0.8.tar.gz
+ftp://sunsite.unc.edu/pub/Linux/GCC/termcap-2.0.8.tar.gz.  If you
+upgrade to this release read the `README' file contained into the
+package to get some important information about the `tgetent' function
+changes!
 
    Also, the console driver is now responsible for keeping track of
 correspondence between character codes and glyph bitmaps.  If you
@@ -265,7 +271,7 @@
 
    Hdparm has been upgraded to take advantage of the latest features of
 the kernel drivers.  The latest non-beta version can be found at
-ftp://sunsite.unc.edu/pub/Linux/kernel/patches/diskdrives/hdparm-2.9.tar.gz.
+ftp://sunsite.unc.edu/pub/Linux/kernel/patches/diskdrives/hdparm-3.0.tar.gz.
 
 IP Accounting
 =============
@@ -307,9 +313,18 @@
 ============
 
    The new kernels support ISDN.  You'll need ISDN utils available from
-ftp://ftp.franken.de/pub/isdn4linux/isdn4k-utils-2.0.0.tar.gz to try
+ftp://ftp.franken.de/pub/isdn4linux/v2.0/isdn4k-utils-2.0.tar.gz to try
 this.
 
+Frame Relay
+===========
+
+   Frame relay support for Linux is now available as well.  Currently,
+only Sangoma cards are supported, but the interface is such that others
+will be as drivers become available.  To use this, grab
+ftp://ftp.invlogic.com/linux/frad-0.15.tgz and
+ftp://ftp.invlogic.com/linux/routing.tgz.
+
 Networking
 ==========
 
@@ -369,30 +384,30 @@
 modified version of mount from
 ftp://ftp.win.tue.nl/pub/linux/util/mount-2.5k.tar.gz; preliminary work
 on encrypted file system support can be found in
-ftp.funet.fi:/pub/OS/Linux/BETA/loop/des.1.tar.gz.
+ftp.funet.fi:/pub/Linux/BETA/loop/des.1.tar.gz.
 
 Multiple device
 ===============
 
    Multiple device support (allowing you to group several partitions
 into one logical device) has also been added.  Check out
-ftp://sweet-smoke.ufr-info-p7.ibp.fr/pub/Linux/md034.tar.gz to try this
+ftp://sweet-smoke.ufr-info-p7.ibp.fr/pub/Linux/md035.tar.gz to try this
 out.
 
 Arp
 ===
 
    Arp daemon support has been added.  Check out
-http://www.loran.com/~layes/arpd/index.html for more info and a copy of
-arpd.
+http://www.loran.com/~layes/arpd/index.html for more info and
+http://www.loran.com/~layes/arpd/arpd-1.0.2.tar.gz for a copy of arpd.
 
 Quota
 =====
 
    Quota support has also been added.  You need to get quotas-1.55 from
-ftp://ftp.funet.fi/pub/Linux/PEOPLE/Linus/subsystems/quota/all.tar.gz.
-You may need to copy its mntent.h over to /usr/include/mntent.h to get
-it to compile.
+ftp://ftp.funet.fi/pub/Linux/kernel/src/subsystems/quota/all.tar.gz. You
+may need to copy its mntent.h over to /usr/include/mntent.h to get it to
+compile.
 
 Process Accounting
 ==================
@@ -401,13 +416,18 @@
 kernels. To use this feature, you'll need to get
 ftp://iguana.hut.fi/pub/linux/Kernel/process_accounting/acct_1.3.73.tar.gz.
 
-Bdflush
-=======
+Bdflush and Updated
+===================
 
    Bdflush has also been integrated into the new kernels, so those of
 you using it on older systems no longer need to hunt for the patches to
 implement it once you upgrade to 2.0.x.  You do still need to run the
-update daemon, however.
+update daemon, however.  You should probably upgrade to the latest
+updated, currently
+ftp://sunsite.unc.edu/pub/Linux/system/Daemons/updated-1.2.tar.gz.  This
+(and later) versions will not spawn a bdflush daemon, since that is now
+done by the kernel (kflushd).  If you upgrade, be sure to leave update
+in your init scripts and remove bdflush.
 
 APM support
 ===========
@@ -426,7 +446,7 @@
 
    For a version of Dosemu that works (well, at least as well as DOS
 ever works ;-), get
-ftp://tsx-11.mit.edu/pub/linux/ALPHA/dosemu/Development/dosemu-0.63.1.36.tgz
+ftp://tsx-11.mit.edu/pub/linux/ALPHA/dosemu/Development/dosemu-0.63.1.55.tgz
 or check out http://www.ednet.ns.ca/auto/rddc. Be sure to follow the
 instructions in README.newkernels about patching your include files, or
 it will not compile.
@@ -449,7 +469,15 @@
    In the future, fdformat might disappear entirely, so get used to
 using superformat instead.
 
-NCR 83c510 SCSI Driver
+Cyclades Serial Driver
+======================
+
+   The Cyclades driver has been changed so that the minor numbers start
+at 0 instead of 32 (ie: ttyC0 should be major 19, minor 0 in the 2.0.x
+kernels while it used to be major 19, minor 32 in the older kernels).
+You can use mknod to manually fix this or use a newer version of MAKEDEV.
+
+NCR 53c810 SCSI Driver
 ======================
 
    Drivers for this card are now included in the standard linux source.
@@ -471,7 +499,7 @@
 using an old version of Perl, due to changes in libc.  Upgrade to a
 more current Perl to avoid any unpleasantness.
 
-groff
+Groff
 =====
 
    Those of you running Slackware may experience weirdness with man
@@ -482,6 +510,14 @@
 solution is to edit the file /usr/lib/man.config and change all
 `-Tlatin1' options to `-Tascii'.
 
+E2fsprogs
+=========
+
+   e2fsprogs 1.02 will work with the latest kernels, but it cannot be
+compiled on them.  If you need (or want) to compile your own copy,
+you'll need to get the latest version, currently available at
+ftp://tsx-11.mit.edu/pub/linux/packages/ext2fs/e2fsprogs-1.04.tar.gz.
+
 How to know the version of the installed programs
 *************************************************
 
@@ -573,8 +609,8 @@
 Gpm mouse utilities
 ===================
 
-ftp://iride.unipv.it/pub/gpm/gpm-1.09.tar.gz
-ftp://sunsite.unc.edu/pub/Linux/system/Daemons/gpm-1.09.tar.gz
+ftp://iride.unipv.it/pub/gpm/gpm-1.10.tar.gz
+ftp://sunsite.unc.edu/pub/Linux/system/Daemons/gpm-1.10.tar.gz
 
 SysVinit utilities
 ==================
diff -u --recursive --new-file v2.0.10/linux/Documentation/Configure.help linux/Documentation/Configure.help
--- v2.0.10/linux/Documentation/Configure.help	Wed Jul 17 07:17:29 1996
+++ linux/Documentation/Configure.help	Mon Aug  5 08:12:24 1996
@@ -202,10 +202,9 @@
   "SiS" chipset.  Unfortunately, it has a number of rather nasty
   design flaws that can cause severe data corruption under many common
   conditions.  Say Y here to include code which tries to automatically
-  detect and correct the problems under Linux.  This also provides
-  support for the enhanced features of the CMD640, for improved
-  support/operation under linux, including access to the secondary IDE
-  ports in some systems.  This driver will work automatically in PCI
+  detect and correct the problems under Linux.  
+  This option also enables access to the secondary IDE ports in some
+  CMD640 based systems.  This driver will work automatically in PCI
   based systems (most new systems have PCI slots).  But if your system
   uses VESA local bus (VLB) instead of PCI, you must also supply a
   kernel boot parameter to enable the CMD640 bugfix/support:
@@ -213,6 +212,13 @@
   Acculogic, and on the "CSA-6400E PCI to IDE controller" that some
   people have. If unsure, say Y.
 
+CMD640 enhanced support
+CONFIG_BLK_DEV_CMD640_ENHANCED
+  This option includes support for setting/autotuning PIO modes
+  and prefetch on CMD640 IDE interfaces.  If you have a CMD640 IDE
+  interface and your BIOS does not already do this for you, then say Y
+  here.  Otherwise say N.
+
 RZ1000 chipset bugfix/support
 CONFIG_BLK_DEV_RZ1000
   The PC-Technologies RZ1000 chip is used on many common 486 and
@@ -3470,6 +3476,15 @@
   from the running kernel whenever you want). If you want to compile
   it as a module, say M here and read Documentation/modules.txt.
 
+Berkshire Products PC Watchdog card
+CONFIG_PCWATCHDOG
+  This is the driver for the Berkshire Products PC Watchdog card.  This card
+  simply watches your kernel to make sure it doesn't freeze, and if it does,
+  it resets your computer after a certain amount of time.  This driver is
+  like the WDT501 driver but for different hardware. The PC watchdog cards
+  can be ordered from http://www.berkprod.com. Some example rc.local files
+  are available from ftp.bitgame.com.
+
 Enhanced Real Time Clock Support
 CONFIG_RTC
   If you enable this option and create a character special file
@@ -3824,7 +3839,7 @@
 # LocalWords:  Bernd informatik rwth aachen uae affs multihosting bytecode java
 # LocalWords:  applets applet JDK ncsa cabi SNI Alphatronix readme LANs scarab
 # LocalWords:  winsock RNIS caltech OSPF honour Honouring Mbit Localtalk DEFRAG
-# LocalWords:  localtalk download Packetwin Baycom baycom interwork ascii JNT
+# LocalWords:  Camtec Berkshire
 # LocalWords:  Camtec proxying indyramp defragment defragmented UDP FAS FASXX
 # LocalWords:  FastSCSI SIO FDC qlogicfas QLogic qlogicisp setbaycom ife ee LJ
 # LocalWords:  ethz ch Travelmates ProAudioSpectrum ProAudio SoundMan SB SBPro
diff -u --recursive --new-file v2.0.10/linux/Documentation/cdrom/aztcd linux/Documentation/cdrom/aztcd
--- v2.0.10/linux/Documentation/cdrom/aztcd	Mon Jul 15 09:55:11 1996
+++ linux/Documentation/cdrom/aztcd	Sat Aug  3 11:46:51 1996
@@ -351,7 +351,7 @@
      aztGetQChannelInfo()   repeated several times
      aztGetToc()
      aztGetQChannelInfo()   repeated several times
-     a list of track informations
+     a list of track information
      do_aztcd_request()  }  
      azt_transfer()    } repeated several times
      azt_poll          }
diff -u --recursive --new-file v2.0.10/linux/Documentation/digiboard.txt linux/Documentation/digiboard.txt
--- v2.0.10/linux/Documentation/digiboard.txt	Sat Apr 20 11:25:31 1996
+++ linux/Documentation/digiboard.txt	Thu Aug  1 15:31:04 1996
@@ -45,8 +45,8 @@
 # mkdigidev [<number of devices>]
 # 
 
-DIGI_MAJOR=22
-DIGICU_MAJOR=23
+DIGI_MAJOR=23
+DIGICU_MAJOR=22
 
 BOARDS=$1
 
@@ -60,8 +60,8 @@
   for c in 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15;
   do
 	name=`expr $boardnum \* 16 + $c`
-	mknod /dev/cud$name c $DIGIMAJOR $name
-	mknod /dev/ttyD$name c $DIGICUMAJOR $name
+	mknod /dev/cud$name c $DIGI_CUMAJOR $name
+	mknod /dev/ttyD$name c $DIGI_MAJOR $name
   done
   boardnum=`expr $boardnum + 1`
 done
@@ -97,7 +97,7 @@
 +	digi)
 +		major1=`Major ttyD` || continue
 +		major2=`Major cud` || continue
-+		for i in 0 1 2 3 4 5 6 7 # 8 9 10 11 12 13 14 15
++		for i in 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
 +		do
 +			makedev ttyD$i c $major1 `expr 32 + $i` $tty
 +			makedev cud$i c $major2 `expr 32 + $i` $dialout
@@ -152,3 +152,4 @@
 does it want to initialize it.  At least not the EISA version.
 
 Mike McLagan <mike.mclagan@linux.org> 5, April 1996.
+
diff -u --recursive --new-file v2.0.10/linux/Documentation/ide.txt linux/Documentation/ide.txt
--- v2.0.10/linux/Documentation/ide.txt	Tue Jul 23 11:33:32 1996
+++ linux/Documentation/ide.txt	Mon Aug  5 08:12:24 1996
@@ -1,4 +1,4 @@
-ide.txt -- Information regarding the Enhanced IDE drive in Linux 2.0.x
+ide.txt -- Information regarding the Enhanced IDE drive in Linux 2.0.xx
 ===============================================================================
 Supported by:
 	Mark Lord    <mlord@pobox.com>		-- disks, interfaces, probing
@@ -37,8 +37,8 @@
 NEW!	- support for reliable operation of buggy CMD-640 interfaces
 		- PCI support is automatic when cmd640 support is configured
 		- for VLB, use kernel command line option:   ide0=cmd640_vlb
-		- this support also enables the secondary i/f on most cards
-		- experimental interface timing parameter support
+		- this support also enables the secondary i/f when needed
+		- interface PIO timing & prefetch parameter support
 NEW!	- experimental support for UMC 8672 interfaces
 NEW!	- support for secondary interface on the FGI/Holtek HT-6560B VLB i/f
 		- use kernel command line option:   ide0=ht6560
@@ -62,7 +62,7 @@
 		  and direct reads of audio data.
 NEW!	- experimental support for Promise DC4030VL caching interface card
 NEW!		- email thanks/problems to: peterd@pnd-pc.demon.co.uk
-NEW!	- the hdparm-2.7 package can be used to set PIO modes for some chipsets.
+NEW!	- the hdparm-3.1 package can be used to set PIO modes for some chipsets.
 
 For work in progress, see the comments in ide.c, ide-cd.c, and triton.c.
 
@@ -71,17 +71,28 @@
 Look for this support to be added to the kernel soon.
 
 
-***  IMPORTANT NOTICES (for kernel versions after 1.3.21)
+***  IMPORTANT NOTICES:  BUGGY IDE CHIPSETS CAN CORRUPT DATA!!
 ***  =================
 ***  PCI versions of the CMD640 and RZ1000 interfaces are now detected
 ***  automatically at startup when PCI BIOS support is configured.
-***  Linux disables the "pre-fetch" or "read-ahead" modes of these interfaces
+***
+***  Linux disables the "prefetch" ("readahead") mode of the RZ1000
 ***  to prevent data corruption possible due to hardware design flaws.
-***  Use of the "serialize" option is no longer necessary.
+***
+***  For the CMD640, linux disables "IRQ unmasking" (hdparm -u1) on any
+***  drive for which the "prefetch" mode of the CMD640 is turned on.
+***  If "prefetch" is disabled (hdparm -p8), then "IRQ unmasking" can be
+***  used again.
+***
+***  For the CMD640, linux disables "32bit I/O" (hdparm -c1) on any drive
+***  for which the "prefetch" mode of the CMD640 is turned off.
+***  If "prefetch" is enabled (hdparm -p9), then "32bit I/O" can be
+***  used again.
 ***
 ***  The CMD640 is also used on some Vesa Local Bus (VLB) cards, and is *NOT*
 ***  automatically detected by Linux.  For safe, reliable operation with such
 ***  interfaces, one *MUST* use the "ide0=cmd640_vlb" kernel option.
+***
 ***  Use of the "serialize" option is no longer necessary.
 
 This is the multiple IDE interface driver, as evolved from hd.c.
@@ -107,7 +118,7 @@
 Interfaces beyond the first two are not normally probed for, but may be
 specified using kernel "command line" options.  For example,
 
-	ide3=0x168,0x36e,10	/* ioports 0x168-0x16f,0x36e, irq 11 */
+	ide3=0x168,0x36e,10	/* ioports 0x168-0x16f,0x36e, irq 10 */
 
 Normally the irq number need not be specified, as ide.c will probe for it:
 
@@ -244,6 +255,16 @@
 				Not fully supported by all chipset types,
 				and quite likely to cause trouble with
 				older/odd IDE drives.
+
+ "idebus=xx"		: inform IDE driver of VESA/PCI bus speed in Mhz,
+				where "xx" is between 25 and 66 inclusive,
+				used when tuning chipset PIO modes.
+				For PCI bus, 25 is correct for a P75 system,
+				30 is correct for P90,P120,P180 systems,
+				and 33 is used for P100,P133,P166 systems.
+				If in doubt, use idebus=33 for PCI.
+				As for VLB, it is safest to not specify it.
+				Bigger values are safer than smaller ones.
 
  "idex=noprobe"		: do not attempt to access/use this interface
  "idex=base"		: probe for an interface at the addr specified,
diff -u --recursive --new-file v2.0.10/linux/MAINTAINERS linux/MAINTAINERS
--- v2.0.10/linux/MAINTAINERS	Sun Jun  9 12:47:01 1996
+++ linux/MAINTAINERS	Thu Aug  1 15:43:04 1996
@@ -150,13 +150,13 @@
 EATA-DMA SCSI DRIVER
 P:	Michael Neuffer
 M:	mike@i-Connect.Net
-L:	linux-scsi@vger.rutgers.edu
+L:	linux-eata@i-connect.net, linux-scsi@vger.rutgers.edu
 S:	Maintained
 
 EATA-PIO SCSI DRIVER
 P:	Michael Neuffer
 M:	mike@i-Connect.Net
-L:	linux-scsi@vger.rutgers.edu
+L:	linux-eata@i-connect.net, linux-scsi@vger.rutgers.edu
 S:	Maintained
 
 FRAME RELAY DLCI/FRAD (Sangoma drivers too)
diff -u --recursive --new-file v2.0.10/linux/Makefile linux/Makefile
--- v2.0.10/linux/Makefile	Thu Aug  1 15:53:34 1996
+++ linux/Makefile	Thu Aug  1 14:22:38 1996
@@ -1,6 +1,6 @@
 VERSION = 2
 PATCHLEVEL = 0
-SUBLEVEL = 10
+SUBLEVEL = 11
 
 ARCH = i386
 
diff -u --recursive --new-file v2.0.10/linux/arch/alpha/Makefile linux/arch/alpha/Makefile
--- v2.0.10/linux/arch/alpha/Makefile	Sat Mar 16 13:52:12 1996
+++ linux/arch/alpha/Makefile	Sun Aug  4 13:37:59 1996
@@ -14,8 +14,12 @@
 # enable this for linking under OSF/1:
 LINKFLAGS = -non_shared -T 0xfffffc0000310000 -N
 else
-# enable this for linking under Linux:
-LINKFLAGS = -static -T arch/alpha/vmlinux.lds -N
+ elf=$(shell if $(LD) --help | grep elf64alpha >/dev/null; then echo yes; fi)
+ ifeq ($(elf),yes)
+   LINKFLAGS = -static -Ttext 0xfffffc0000310000 -N
+ else
+   LINKFLAGS = -static -T arch/alpha/vmlinux.lds -N
+ endif
 # GNU gcc/cc1/as can use pipes instead of temporary files
 CFLAGS := $(CFLAGS) -pipe
 endif
diff -u --recursive --new-file v2.0.10/linux/arch/alpha/boot/Makefile linux/arch/alpha/boot/Makefile
--- v2.0.10/linux/arch/alpha/boot/Makefile	Tue Jul  9 08:37:20 1996
+++ linux/arch/alpha/boot/Makefile	Sun Aug  4 13:37:59 1996
@@ -12,8 +12,12 @@
 # enable this for linking under OSF/1:
 LINKFLAGS = -non_shared -T 0x20000000 -N
 else
-# enable this for linking under Linux:
-LINKFLAGS = -static -T bootloader.lds -N 
+ elf=$(shell if $(LD) --help | grep elf64alpha >/dev/null; then echo yes; fi)
+ ifeq ($(elf),yes)
+  LINKFLAGS = -static -Ttext 0x20000000 -N
+ else
+  LINKFLAGS = -static -T bootloader.lds -N
+ endif
 endif
 
 .S.s:
@@ -22,13 +26,15 @@
 	$(CC) -D__ASSEMBLY__ -traditional -c -o $*.o $<
 
 OBJECTS = head.o main.o
-TARGETS = vmlinux.gz
+TARGETS = vmlinux.gz tools/objstrip # also needed by aboot & milo
+VMLINUX = $(TOPDIR)/vmlinux
+OBJSTRIP = tools/objstrip
 
 all:	$(TARGETS)
 	@echo Ready to install kernel in $(shell pwd)/vmlinux.gz
 
 # normally no need to build these:
-rawboot: vmlinux.nh tools/lxboot tools/bootlx vmlinux
+rawboot: vmlinux.nh tools/lxboot tools/bootlx
 
 msb:	tools/lxboot tools/bootlx vmlinux.nh
 	( cat tools/lxboot tools/bootlx vmlinux.nh ) > /dev/rz0a
@@ -51,21 +57,33 @@
 #
 # A raw binary without header.  Used by raw boot.
 #
-vmlinux.nh: tools/build
-	tools/build -v $(TOPDIR)/vmlinux > vmlinux.nh
+main.o: ksize.h
+
+ksize.h: $(OBJSTRIP) vmlinux.nh
+	echo "#define KERNEL_SIZE `$(OBJSTRIP) -p vmlinux.nh /dev/null`" > $@
+
+vmlinux.nh: $(VMLINUX) $(OBJSTRIP)
+ifeq ($(elf),yes)
+	cp $(VMLINUX) vmlinux.stripped
+	strip vmlinux.stripped		# work around ELF binutils bug...
+	$(OBJSTRIP) -v vmlinux.stripped vmlinux.nh
+	rm -f vmlinux.stripped
+else
+	$(OBJSTRIP) -v $(VMLINUX) vmlinux.nh
+endif
 
 vmlinux: $(TOPDIR)/vmlinux
 	cp $(TOPDIR)/vmlinux vmlinux
 	strip vmlinux
 
-tools/lxboot: tools/build
-	tools/build > tools/lxboot
+tools/lxboot: $(OBJSTRIP) bootloader
+	$(OBJSTRIP) -p bootloader tools/lxboot
 
-tools/bootlx: bootloader tools/build
-	tools/build -vb bootloader > tools/bootlx
+tools/bootlx: bootloader $(OBJSTRIP)
+	$(OBJSTRIP) -vb bootloader tools/bootlx
 
-tools/build: tools/build.c
-	$(HOSTCC) tools/build.c -o tools/build
+$(OBJSTRIP): $(OBJSTRIP).c
+	$(HOSTCC) $(OBJSTRIP).c -o $(OBJSTRIP)
 
 tools/mkbb: tools/mkbb.c
 	$(HOSTCC) tools/mkbb.c -o tools/mkbb
@@ -74,11 +92,11 @@
 	$(LD) $(LINKFLAGS) \
 		$(OBJECTS) \
 		$(LIBS) \
-		-o bootloader || \
+		-o bootloader && strip bootloader || \
 		(rm -f bootloader && exit 1)
 
 clean:
-	rm -f $(TARGETS) bootloader bootimage vmlinux.nh tools/build \
+	rm -f $(TARGETS) bootloader bootimage vmlinux.nh \
 		tools/mkbb tools/bootlx tools/lxboot
 
 dep:
diff -u --recursive --new-file v2.0.10/linux/arch/alpha/boot/main.c linux/arch/alpha/boot/main.c
--- v2.0.10/linux/arch/alpha/boot/main.c	Wed May 15 10:49:36 1996
+++ linux/arch/alpha/boot/main.c	Sun Aug  4 13:37:59 1996
@@ -17,6 +17,8 @@
 
 #include <stdarg.h>
 
+#include "ksize.h"
+
 extern int vsprintf(char *, const char *, va_list);
 extern unsigned long switch_to_osf_pal(unsigned long nr,
 	struct pcb_struct * pcb_va, struct pcb_struct * pcb_pa,
@@ -152,8 +154,6 @@
 	flush_tlb_all();
 }
 
-extern int _end;
-
 static inline long openboot(void)
 {
 	char bootdev[256];
@@ -173,7 +173,8 @@
 static inline long load(long dev, unsigned long addr, unsigned long count)
 {
 	char bootfile[256];
-	long result;
+	extern char _end;
+	long result, boot_size = &_end - (char *) BOOT_ADDR;
 
 	result = dispatch(CCB_GET_ENV, ENV_BOOTED_FILE, bootfile, 255);
 	if (result < 0)
@@ -181,8 +182,9 @@
 	result &= 255;
 	bootfile[result] = '\0';
 	if (result)
-		printk("Boot file specification (%s) not implemented\n", bootfile);
-	return dispatch(CCB_READ, dev, count, addr, BOOT_SIZE/512 + 1);
+		printk("Boot file specification (%s) not implemented\n",
+		       bootfile);
+	return dispatch(CCB_READ, dev, count, addr, boot_size/512 + 1);
 }
 
 /*
@@ -219,9 +221,9 @@
 	}
 	dev &= 0xffffffff;
 	printk("Loading vmlinux ...");
-	i = load(dev, START_ADDR, START_SIZE);
+	i = load(dev, START_ADDR, KERNEL_SIZE);
 	close(dev);
-	if (i != START_SIZE) {
+	if (i != KERNEL_SIZE) {
 		printk("Failed (%lx)\n", i);
 		return;
 	}
diff -u --recursive --new-file v2.0.10/linux/arch/alpha/boot/tools/build.c linux/arch/alpha/boot/tools/build.c
--- v2.0.10/linux/arch/alpha/boot/tools/build.c	Wed May 15 10:49:36 1996
+++ linux/arch/alpha/boot/tools/build.c	Thu Jan  1 02:00:00 1970
@@ -1,173 +0,0 @@
-/*
- * arch/alpha/boot/tools/build.c
- *
- * Build a bootable image from the vmlinux binary
- */
-#include <string.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <fcntl.h>
-
-#include <linux/a.out.h>
-
-#include <asm/system.h>
-
-#define MAXSECT 10
-#define MAXBUF 8192
-
-int verbose = 0;
-int pad = 0;
-char * program = "tools/build";
-char buffer[MAXBUF];
-unsigned long bootblock[64];
-struct filehdr fhdr;
-struct aouthdr ahdr;
-struct scnhdr  shdr[MAXSECT];
-
-char * usage = "'build [-b] system > secondary' or 'build > primary'";
-
-static void die(char * str)
-{
-	fprintf(stderr,"%s: %s\n", program, str);
-	exit(1);
-}
-
-static int comp(struct scnhdr * a, struct scnhdr * b)
-{
-	return a->s_vaddr - b->s_vaddr;
-}
-
-int main(int argc, char ** argv)
-{
-	int fd, i;
-	unsigned long tmp, start;
-	unsigned long system_start, system_size;
-	char * infile = NULL;
-
-	system_start = START_ADDR;
-	system_size = START_SIZE;
-	if (argc) {
-		program = *(argv++);
-		argc--;
-	}
-	while (argc > 0) {
-		if (**argv == '-') {
-			while (*++*argv) {
-				switch (**argv) {
-					case 'b':
-						system_start = BOOT_ADDR;
-						system_size = BOOT_SIZE;
-						pad = 1;
-						break;
-					case 'v':
-						verbose++;
-						break;
-					default:
-						die(usage);
-				}
-			}
-		} else if (infile)
-			die(usage);
-		else
-			infile = *argv;
-		argv++;
-		argc--;
-	}
-	if (!infile) {
-		memcpy(bootblock, "Linux Test", 10);
-		bootblock[60] = BOOT_SIZE / 512;	/* count */
-		bootblock[61] = 1;			/* starting LBM */
-		bootblock[62] = 0;			/* flags */
-		tmp = 0;
-		for (i = 0 ; i < 63 ; i++)
-			tmp += bootblock[i];
-		bootblock[63] = tmp;
-		if (write(1, (char *) bootblock, 512) != 512) {
-			perror("bbwrite");
-			exit(1);
-		}
-		return 0;
-	}
-	fd = open(infile, O_RDONLY);
-	if (fd < 0) {
-		perror(infile);
-		exit(1);
-	}
-	if (read(fd, &fhdr, sizeof(struct filehdr)) != sizeof(struct filehdr))
-		die("unable to read file header");
-	if (fhdr.f_nscns > MAXSECT)
-		die("Too many sections");
-	if (fhdr.f_opthdr != AOUTHSZ)
-		die("optional header doesn't look like a.out");
-	if (read(fd, &ahdr, sizeof(struct aouthdr)) != sizeof(struct aouthdr))
-		die("unable to read a.out header");
-	for (i = 0 ; i < fhdr.f_nscns ; i++) {
-		if (read(fd, i+shdr, sizeof(struct scnhdr)) != sizeof(struct scnhdr))
-			die("unable to read section header");
-		if (shdr[i].s_paddr != shdr[i].s_vaddr)
-			die("unable to handle different phys/virt addresses");
-		if (shdr[i].s_relptr)
-			die("Unable to handle relocation info");
-		if (verbose) {
-			fprintf(stderr, "section %d (%.8s):\t%lx - %lx (at %x)\n",
-				i, shdr[i].s_name,
-				shdr[i].s_vaddr,
-				shdr[i].s_vaddr + shdr[i].s_size,
-				shdr[i].s_scnptr);
-		}
-	}
-	qsort(shdr, fhdr.f_nscns, sizeof(shdr[1]), comp);
-	start = system_start;
-	for (i = 0 ; i < fhdr.f_nscns ; i++) {
-		unsigned long size, offset;
-		memset(buffer, 0, MAXBUF);
-		if (!strcmp(shdr[i].s_name, ".comment"))
-			continue;
-		if (shdr[i].s_vaddr != start)
-			die("Unordered or badly placed segments");
-		size = shdr[i].s_size;
-		start += size;
-		offset = shdr[i].s_scnptr;
-		if (lseek(fd, offset, SEEK_SET) != offset)
-			die("Unable to seek in in-file");
-		while (size > 0) {
-			unsigned long num = size;
-			if (num > MAXBUF)
-				num = MAXBUF;
-			if (offset)
-				if (read(fd, buffer, num) != num)
-					die("partial read");
-			if (write(1, buffer, num) != num)
-				die("partial write");
-			size -= num;
-		}
-		if (verbose) {
-			fprintf(stderr, "section %d (%.8s):\t%lx - %lx (at %x)\n",
-				i, shdr[i].s_name,
-				shdr[i].s_vaddr,
-				shdr[i].s_vaddr + shdr[i].s_size,
-				shdr[i].s_scnptr);
-		}
-	}
-	if (start > system_start + system_size) {
-		fprintf(stderr, "Boot image too large\n");
-		exit(1);
-	}
-	if (pad) {
-		unsigned long count = (system_start + system_size) - start;
-		memset(buffer, 0, MAXBUF);
-		while (count > 0) {
-			int i = MAXBUF;
-			if (i > count)
-				i = count;
-			i = write(1, buffer, i);
-			if (i <= 0) {
-				perror("pad write");
-				exit(1);
-			}
-			count -= i;
-		}
-	}
-		
-	return 0;
-}
diff -u --recursive --new-file v2.0.10/linux/arch/alpha/boot/tools/objstrip.c linux/arch/alpha/boot/tools/objstrip.c
--- v2.0.10/linux/arch/alpha/boot/tools/objstrip.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/alpha/boot/tools/objstrip.c	Sun Aug  4 13:37:59 1996
@@ -0,0 +1,280 @@
+/*
+ * arch/alpha/boot/tools/objstrip.c
+ *
+ * Strip the object file headers/trailers from an executable (ELF or ECOFF).
+ *
+ * Copyright (C) 1996 David Mosberger-Tang.
+ */
+/*
+ * Converts an ECOFF or ELF object file into a bootable file.  The
+ * object file must be a OMAGIC file (i.e., data and bss follow immediatly
+ * behind the text).  See DEC "Assembly Language Programmer's Guide"
+ * documentation for details.  The SRM boot process is documented in
+ * the Alpha AXP Architecture Reference Manual, Second Edition by
+ * Richard L. Sites and Richard T. Witek.
+ */
+#include <stdio.h>
+#include <unistd.h>
+
+#include <sys/fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <linux/a.out.h>
+#include <linux/coff.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#ifdef __ELF__
+# include <asm/elf.h>
+# include <linux/elf.h>
+#endif
+
+/* bootfile size must be multiple of BLOCK_SIZE: */
+#define BLOCK_SIZE	512
+
+const char * prog_name;
+
+
+void
+usage (void)
+{
+    fprintf(stderr,
+	    "usage: %s [-v] -p file primary\n"
+	    "       %s [-vb] file [secondary]\n", prog_name, prog_name);
+    exit(1);
+}
+
+
+int
+main (int argc, char *argv[])
+{
+    size_t nwritten, tocopy, n, mem_size, fil_size, pad = 0;
+    int fd, ofd, i, j, verbose = 0, primary = 0;
+    char buf[8192], *inname;
+    struct exec * aout;		/* includes file & aout header */
+    long offset;
+#ifdef __ELF__
+    struct elfhdr *elf;
+    struct elf_phdr *elf_phdr;	/* program header */
+    unsigned long long e_entry;
+#endif
+
+    prog_name = argv[0];
+
+    for (i = 1; i < argc && argv[i][0] == '-'; ++i) {
+	for (j = 1; argv[i][j]; ++j) {
+	    switch (argv[i][j]) {
+	      case 'v':
+		  verbose = ~verbose;
+		  break;
+
+	      case 'b':
+		  pad = BLOCK_SIZE;
+		  break;
+
+	      case 'p':
+		  primary = 1;		/* make primary bootblock */
+		  break;
+	    }
+	}
+    }
+
+    if (i >= argc) {
+	usage();
+    }
+    inname = argv[i++];
+
+    fd = open(inname, O_RDONLY);
+    if (fd == -1) {
+	perror("open");
+	exit(1);
+    }
+
+    ofd = 1;
+    if (i < argc) {
+	ofd = open(argv[i++], O_WRONLY | O_CREAT | O_TRUNC, 0666);
+	if (fd == -1) {
+	    perror("open");
+	    exit(1);
+	}
+    }
+
+    if (primary) {
+	/* generate bootblock for primary loader */
+	
+	unsigned long bb[64], sum = 0;
+	struct stat st;
+	off_t size;
+	int i;
+
+	if (ofd == 1) {
+	    usage();
+	}
+
+	if (fstat(fd, &st) == -1) {
+	    perror("fstat");
+	    exit(1);
+	}
+
+	size = (st.st_size + BLOCK_SIZE - 1) & ~(BLOCK_SIZE - 1);
+	memset(bb, 0, sizeof(bb));
+	strcpy((char *) bb, "Linux SRM bootblock");
+	bb[60] = size / BLOCK_SIZE;	/* count */
+	bb[61] = 1;			/* starting sector # */
+	bb[62] = 0;			/* flags---must be 0 */
+	for (i = 0; i < 63; ++i) {
+	    sum += bb[i];
+	}
+	bb[63] = sum;
+	if (write(ofd, bb, sizeof(bb)) != sizeof(bb)) {
+	    perror("boot-block write");
+	    exit(1);
+	}
+	printf("%lu\n", size);
+	return 0;
+    }
+
+    /* read and inspect exec header: */
+
+    if (read(fd, buf, sizeof(buf)) < 0) {
+	perror("read");
+	exit(1);
+    }
+
+#ifdef __ELF__
+    elf = (struct elfhdr *) buf;
+
+    if (elf->e_ident[0] == 0x7f && strncmp(elf->e_ident + 1, "ELF", 3) == 0) {
+	if (elf->e_type != ET_EXEC) {
+	    fprintf(stderr, "%s: %s is not an ELF executable\n",
+		    prog_name, inname);
+	    exit(1);
+	}
+	if (!elf_check_arch(elf->e_machine)) {
+	    fprintf(stderr, "%s: is not for this processor (e_machine=%d)\n",
+		    prog_name, elf->e_machine);
+	    exit(1);
+	}
+	if (elf->e_phnum != 1) {
+	    fprintf(stderr,
+		    "%s: %d program headers (forgot to link with -N?)\n",
+		    prog_name, elf->e_phnum);
+	}
+
+	e_entry = elf->e_entry;
+
+	lseek(fd, elf->e_phoff, SEEK_SET);
+	if (read(fd, buf, sizeof(*elf_phdr)) != sizeof(*elf_phdr)) {
+	    perror("read");
+	    exit(1);
+	}
+
+	elf_phdr = (struct elf_phdr *) buf;
+	offset	 = elf_phdr->p_offset;
+	mem_size = elf_phdr->p_memsz;
+	fil_size = elf_phdr->p_filesz;
+
+	/* work around ELF bug: */
+	if (elf_phdr->p_vaddr < e_entry) {
+	    unsigned long delta = e_entry - elf_phdr->p_vaddr;
+	    offset   += delta;
+	    mem_size -= delta;
+	    fil_size -= delta;
+	    elf_phdr->p_vaddr += delta;
+	}
+
+	if (verbose) {
+	    fprintf(stderr, "%s: extracting %#016lx-%#016lx (at %lx)\n",
+		    prog_name, (long) elf_phdr->p_vaddr,
+		    elf_phdr->p_vaddr + fil_size, offset);
+	}
+    } else
+#endif
+    {
+	aout = (struct exec *) buf;
+
+	if (!(aout->fh.f_flags & COFF_F_EXEC)) {
+	    fprintf(stderr, "%s: %s is not in executable format\n",
+		    prog_name, inname);
+	    exit(1);
+	}
+
+	if (aout->fh.f_opthdr != sizeof(aout->ah)) {
+	    fprintf(stderr, "%s: %s has unexpected optional header size\n",
+		    prog_name, inname);
+	    exit(1);
+	}
+
+	if (N_MAGIC(*aout) != OMAGIC) {
+	    fprintf(stderr, "%s: %s is not an OMAGIC file\n",
+		    prog_name, inname);
+	    exit(1);
+	}
+	offset = N_TXTOFF(*aout);
+	fil_size = aout->ah.tsize + aout->ah.dsize;
+	mem_size = fil_size + aout->ah.bsize;
+
+	if (verbose) {
+	    fprintf(stderr, "%s: extracting %#016lx-%#016lx (at %lx)\n",
+		    prog_name, aout->ah.text_start,
+		    aout->ah.text_start + fil_size, offset);
+	}
+    }
+
+    if (lseek(fd, offset, SEEK_SET) != offset) {
+	perror("lseek");
+	exit(1);
+    }
+
+    if (verbose) {
+	fprintf(stderr, "%s: copying %lu byte from %s\n",
+		prog_name, (unsigned long) fil_size, inname);
+    }
+
+    tocopy = fil_size;
+    while (tocopy > 0) {
+	n = tocopy;
+	if (n > sizeof(buf)) {
+	    n = sizeof(buf);
+	}
+	tocopy -= n;
+	if ((size_t) read(fd, buf, n) != n) {
+	    perror("read");
+	    exit(1);
+	}
+	do {
+	    nwritten = write(ofd, buf, n);
+	    if ((ssize_t) nwritten == -1) {
+		perror("write");
+		exit(1);
+	    }
+	    n -= nwritten;
+	} while (n > 0);
+    }
+
+    if (pad) {
+	mem_size = ((mem_size + pad - 1) / pad) * pad;
+    }
+
+    tocopy = mem_size - fil_size;
+    if (tocopy > 0) {
+	fprintf(stderr,
+		"%s: zero-filling bss and aligning to %lu with %lu bytes\n",
+		prog_name, pad, (unsigned long) tocopy);
+
+	memset(buf, 0x00, sizeof(buf));
+	do {
+	    n = tocopy;
+	    if (n > sizeof(buf)) {
+		n = sizeof(buf);
+	    }
+	    nwritten = write(ofd, buf, n);
+	    if ((ssize_t) nwritten == -1) {
+		perror("write");
+		exit(1);
+	    }
+	    tocopy -= nwritten;
+	} while (tocopy > 0);
+    }
+    return 0;
+}
diff -u --recursive --new-file v2.0.10/linux/arch/alpha/config.in linux/arch/alpha/config.in
--- v2.0.10/linux/arch/alpha/config.in	Mon Jul 15 09:47:41 1996
+++ linux/arch/alpha/config.in	Sun Aug  4 13:38:59 1996
@@ -68,7 +68,7 @@
 	define_bool CONFIG_ALPHA_EV5 y
 	define_bool CONFIG_ALPHA_CIA y
 else
-	# EV5 and newer supports all rounding modes in hw:
+	# EV45 and older do not support all rounding modes in hw:
 	define_bool CONFIG_ALPHA_NEED_ROUNDING_EMULATION y
 fi
 
diff -u --recursive --new-file v2.0.10/linux/arch/alpha/defconfig linux/arch/alpha/defconfig
--- v2.0.10/linux/arch/alpha/defconfig	Thu Jul 25 20:24:49 1996
+++ linux/arch/alpha/defconfig	Sun Aug  4 14:20:22 1996
@@ -41,7 +41,7 @@
 CONFIG_NET=y
 CONFIG_SYSVIPC=y
 CONFIG_BINFMT_AOUT=y
-# CONFIG_BINFMT_ELF is not set
+CONFIG_BINFMT_ELF=y
 
 #
 # Floppy, IDE, and other block devices
diff -u --recursive --new-file v2.0.10/linux/arch/alpha/kernel/ksyms.c linux/arch/alpha/kernel/ksyms.c
--- v2.0.10/linux/arch/alpha/kernel/ksyms.c	Tue Apr 23 12:49:55 1996
+++ linux/arch/alpha/kernel/ksyms.c	Sun Aug  4 13:37:59 1996
@@ -8,6 +8,8 @@
 #include <linux/string.h>
 #include <linux/module.h>
 #include <linux/string.h>
+#include <linux/user.h>
+#include <linux/elfcore.h>
 #include <asm/io.h>
 #include <asm/hwrpb.h>
 
@@ -24,6 +26,10 @@
 extern void __divqu (void);
 extern void __remqu (void);
 
+extern void dump_thread(struct pt_regs *, struct user *);
+extern int dump_fpu(struct pt_regs *, elf_fpregset_t *);
+
+
 static struct symbol_table arch_symbol_table = {
 #include <linux/symtab_begin.h>
 	/* platform dependent support */
@@ -62,11 +68,16 @@
 	X(strstr),
 	X(strtok),
 	X(strchr),
-	X(hwrpb),
 	X(memcmp),
 	X(memmove),
 	X(__memcpy),
 	X(__constant_c_memset),
+
+	X(dump_thread),
+	X(dump_fpu),
+	X(hwrpb),
+	X(wrusp),
+
 	/*
 	 * The following are special because they're not called
 	 * explicitly (the C compiler or assembler generates them in
diff -u --recursive --new-file v2.0.10/linux/arch/alpha/kernel/process.c linux/arch/alpha/kernel/process.c
--- v2.0.10/linux/arch/alpha/kernel/process.c	Tue Jul  2 19:08:34 1996
+++ linux/arch/alpha/kernel/process.c	Sun Aug  4 13:37:59 1996
@@ -25,6 +25,7 @@
 #include <linux/major.h>
 #include <linux/stat.h>
 #include <linux/mman.h>
+#include <linux/elfcore.h>
 
 #include <asm/reg.h>
 #include <asm/segment.h>
@@ -205,6 +206,14 @@
 	dump->regs[EF_A1]  = pt->r17;
 	dump->regs[EF_A2]  = pt->r18;
 	memcpy((char *)dump->regs + EF_SIZE, sw->fp, 32 * 8);
+}
+
+int dump_fpu (struct pt_regs * regs, elf_fpregset_t *r)
+{
+	/* switch stack follows right below pt_regs: */
+	struct switch_stack * sw = ((struct switch_stack *) regs) - 1;
+	memcpy(r, sw->fp, 32 * 8);
+	return 1;
 }
 
 /*
diff -u --recursive --new-file v2.0.10/linux/arch/alpha/lib/memcpy.c linux/arch/alpha/lib/memcpy.c
--- v2.0.10/linux/arch/alpha/lib/memcpy.c	Fri Dec 22 08:22:05 1995
+++ linux/arch/alpha/lib/memcpy.c	Sun Aug  4 13:37:59 1996
@@ -128,4 +128,8 @@
  * gcc-2.7.1 and newer generate calls to memset and memcpy.  So we
  * need to define that here:
  */
-asm (".weakext memcpy, __memcpy");
+#ifdef __ELF__
+ asm (".weak memcpy; memcpy = __memcpy");
+#else
+ asm (".weakext memcpy, __memcpy");
+#endif
diff -u --recursive --new-file v2.0.10/linux/arch/alpha/lib/memset.S linux/arch/alpha/lib/memset.S
--- v2.0.10/linux/arch/alpha/lib/memset.S	Tue Apr 23 20:49:01 1996
+++ linux/arch/alpha/lib/memset.S	Sun Aug  4 13:37:59 1996
@@ -103,4 +103,8 @@
 	ret $31,($26),1		/* E1 */
 	.end __memset
 
-.weakext memset, __memset
+#ifdef __ELF__
+ .weak memset; memset = __memset
+#else
+ .weakext memset, __memset
+#endif
diff -u --recursive --new-file v2.0.10/linux/arch/i386/defconfig linux/arch/i386/defconfig
--- v2.0.10/linux/arch/i386/defconfig	Wed Jun  5 14:51:03 1996
+++ linux/arch/i386/defconfig	Mon Aug  5 08:41:50 1996
@@ -44,8 +44,9 @@
 # CONFIG_BLK_DEV_IDETAPE is not set
 # CONFIG_BLK_DEV_IDE_PCMCIA is not set
 CONFIG_BLK_DEV_CMD640=y
-# CONFIG_BLK_DEV_TRITON is not set
+# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
 CONFIG_BLK_DEV_RZ1000=y
+# CONFIG_BLK_DEV_TRITON is not set
 # CONFIG_IDE_CHIPSETS is not set
 
 #
@@ -55,6 +56,7 @@
 # CONFIG_BLK_DEV_MD is not set
 # CONFIG_BLK_DEV_RAM is not set
 # CONFIG_BLK_DEV_XD is not set
+# CONFIG_BLK_DEV_HD is not set
 
 #
 # Networking options
diff -u --recursive --new-file v2.0.10/linux/arch/i386/kernel/process.c linux/arch/i386/kernel/process.c
--- v2.0.10/linux/arch/i386/kernel/process.c	Fri Apr 19 18:35:15 1996
+++ linux/arch/i386/kernel/process.c	Sun Aug  4 14:09:11 1996
@@ -332,7 +332,7 @@
 /*
  * fill in the fpu structure for a core dump..
  */
-int dump_fpu (struct user_i387_struct* fpu)
+int dump_fpu (struct pt_regs * regs, struct user_i387_struct* fpu)
 {
 	int fpvalid;
 
@@ -377,7 +377,7 @@
 
 	dump->regs = *regs;
 
-	dump->u_fpvalid = dump_fpu (&dump->i387);
+	dump->u_fpvalid = dump_fpu (regs, &dump->i387);
 }
 
 asmlinkage int sys_fork(struct pt_regs regs)
diff -u --recursive --new-file v2.0.10/linux/arch/i386/kernel/traps.c linux/arch/i386/kernel/traps.c
--- v2.0.10/linux/arch/i386/kernel/traps.c	Wed May 15 07:56:41 1996
+++ linux/arch/i386/kernel/traps.c	Thu Aug  1 12:30:25 1996
@@ -173,8 +173,12 @@
 DO_ERROR(10, SIGSEGV, "invalid TSS", invalid_TSS, current)
 DO_ERROR(11, SIGBUS,  "segment not present", segment_not_present, current)
 DO_ERROR(12, SIGBUS,  "stack segment", stack_segment, current)
-DO_ERROR(15, SIGSEGV, "reserved", reserved, current)
 DO_ERROR(17, SIGSEGV, "alignment check", alignment_check, current)
+
+asmlinkage void do_reserved(struct pt_regs * regs, long error_code)
+{
+	printk("Uhhuh.. Reserved trap code, whazzup? (%ld)\n", error_code);
+}
 
 asmlinkage void do_general_protection(struct pt_regs * regs, long error_code)
 {
diff -u --recursive --new-file v2.0.10/linux/drivers/block/Config.in linux/drivers/block/Config.in
--- v2.0.10/linux/drivers/block/Config.in	Tue Jul 23 11:33:32 1996
+++ linux/drivers/block/Config.in	Mon Aug  5 08:12:25 1996
@@ -15,6 +15,9 @@
   bool '   Include IDE/ATAPI TAPE support' CONFIG_BLK_DEV_IDETAPE
   bool '   Support removable IDE interfaces (PCMCIA)' CONFIG_BLK_DEV_IDE_PCMCIA
   bool '   CMD640 chipset bugfix/support' CONFIG_BLK_DEV_CMD640
+  if [ "$CONFIG_BLK_DEV_CMD640" = "y" ]; then
+    bool '     CMD640 enhanced support' CONFIG_BLK_DEV_CMD640_ENHANCED
+  fi
   if [ "$CONFIG_PCI" = "y" ]; then
     bool '   RZ1000 chipset bugfix/support' CONFIG_BLK_DEV_RZ1000
     bool '   Intel 82371 PIIX (Triton I/II) DMA support' CONFIG_BLK_DEV_TRITON
diff -u --recursive --new-file v2.0.10/linux/drivers/block/ali14xx.c linux/drivers/block/ali14xx.c
--- v2.0.10/linux/drivers/block/ali14xx.c	Tue Jul 23 11:33:32 1996
+++ linux/drivers/block/ali14xx.c	Mon Aug  5 08:12:25 1996
@@ -51,20 +51,6 @@
 #include "ide.h"
 #include "ide_modes.h"
 
-/*
- * This should be set to the system's local bus (PCI or VLB) speed,
- * e.g., 33 for a 486DX33 or 486DX2/66.  Legal values are anything
- * from 25 to 50.  Setting this too *low* will make the EIDE
- * controller unable to communicate with the disks.
- *
- * The value is 50 by default -- this should work ok with any system.
- * (Low values cause problems because it multiplies by bus speed
- * to get cycles, and thus gets a too-small cycle count and tries to
- * access the disks too fast.  I tried this once under DOS and it locked
- * up the system.)	-- derekn@vw.ece.cmu.edu
- */
-#define ALI_14xx_BUS_SPEED	50	/* PCI / VLB bus speed */
-
 /* port addresses for auto-detection */
 #define ALI_NUM_PORTS 4
 static int ports[ALI_NUM_PORTS] = {0x074, 0x0f4, 0x034, 0x0e4};
@@ -82,15 +68,7 @@
 	{0x35, 0x03}, {0x00, 0x00}
 };
 
-/* default timing parameters for each PIO mode */
 #define ALI_MAX_PIO 4
-static struct { int time1, time2; } timeTab[ALI_MAX_PIO+1] = {
-	{600, 165},	/* PIO 0 */
-	{383, 125},	/* PIO 1 */
-	{240, 100},	/* PIO 2 */
-	{180,  80},	/* PIO 3 */
-	{120,  70}	/* PIO 4 */
-};
 
 /* timing parameter registers for each drive */
 static struct { byte reg1, reg2, reg3, reg4; } regTab[4] = {
@@ -134,26 +112,19 @@
 static void ali14xx_tune_drive (ide_drive_t *drive, byte pio)
 {
 	int driveNum;
-	int time1, time2, time1a;
+	int time1, time2;
 	byte param1, param2, param3, param4;
-	struct hd_driveid *id = drive->id;
 	unsigned long flags;
+	ide_pio_data_t d;
+	int bus_speed = ide_system_bus_speed();
 
-	if (pio == 255)
-		pio = ide_get_best_pio_mode(drive);
-	if (pio > ALI_MAX_PIO)
-		pio = ALI_MAX_PIO;
+	pio = ide_get_best_pio_mode(drive, pio, ALI_MAX_PIO, &d);
 
 	/* calculate timing, according to PIO mode */
-	time1 = timeTab[pio].time1;
-	time2 = timeTab[pio].time2;
-	if (pio >= 3) {
-		time1a = (id->capability & 0x08) ? id->eide_pio_iordy : id->eide_pio;
-		if (time1a != 0 && time1a < time1)
-			time1 = time1a;
-	}
-	param3 = param1 = (time2 * ALI_14xx_BUS_SPEED + 999) / 1000;
-	param4 = param2 = (time1 * ALI_14xx_BUS_SPEED + 999) / 1000 - param1;
+	time1 = d.cycle_time;
+	time2 = ide_pio_timings[pio].active_time;
+	param3 = param1 = (time2 * bus_speed + 999) / 1000;
+	param4 = param2 = (time1 * bus_speed + 999) / 1000 - param1;
 	if (pio < 3) {
 		param3 += 8;
 		param4 += 8;
diff -u --recursive --new-file v2.0.10/linux/drivers/block/cmd640.c linux/drivers/block/cmd640.c
--- v2.0.10/linux/drivers/block/cmd640.c	Thu Aug  1 15:53:34 1996
+++ linux/drivers/block/cmd640.c	Mon Aug  5 08:49:54 1996
@@ -1,5 +1,5 @@
 /*
- *  linux/drivers/block/cmd640.c	Version 0.13  Jul 23, 1996
+ *  linux/drivers/block/cmd640.c	Version 0.97  Aug  4, 1996
  *
  *  Copyright (C) 1995-1996  Linus Torvalds & authors (see below)
  */
@@ -7,8 +7,8 @@
 /*
  *  Original author:	abramov@cecmow.enet.dec.com (Igor Abramov)
  *
- *  Maintained by:	s0033las@sun10.vsz.bme.hu (Laszlo Peter)
- *			mlord@pobox.com (Mark Lord)
+ *  Maintained by:	mlord@pobox.com (Mark Lord)
+ *			with fanatical support from a legion of hackers!
  *
  *  This file provides support for the advanced features and bugs
  *  of IDE interfaces using the CMD Technologies 0640 IDE interface chip.
@@ -17,32 +17,45 @@
  *  to work on every motherboard design that uses this screwed chip seems
  *  bloody well impossible.  However, we're still trying.
  *
- *  We think version 0.12 should work for most folks.
- *  User feedback is essential.
+ *  Version 0.96 worked for just about everybody.
+ *  Version 0.97 should work for everyone
  *
+ *  User feedback is essential.  Many thanks to the beta test team:
+ *
+ *  A.Hartgers@stud.tue.nl, JZDQC@CUNYVM.CUNY.edu, abramov@cecmow.enet.dec.com,
+ *  bardj@utopia.ppp.sn.no, bart@gaga.tue.nl, bbol001@cs.auckland.ac.nz,
+ *  chrisc@dbass.demon.co.uk, dalecki@namu26.Num.Math.Uni-Goettingen.de,
+ *  derekn@vw.ece.cmu.edu, florian@btp2x3.phy.uni-bayreuth.de,
+ *  flynn@dei.unipd.it, gadio@netvision.net.il, godzilla@futuris.net,
+ *  j@pobox.com, jkemp1@mises.uni-paderborn.de, jtoppe@hiwaay.net,
+ *  kerouac@ssnet.com, meskes@informatik.rwth-aachen.de, hzoli@cs.elte.hu,
+ *  peter@udgaard.isgtec.com, phil@tazenda.demon.co.uk, roadcapw@cfw.com,
+ *  s0033las@sun10.vsz.bme.hu, schaffer@tam.cornell.edu, sjd@slip.net,
+ *  steve@ei.org, ulrpeg@bigcomm.gun.de, ism@tardis.ed.ac.uk, mack@cray.com
+ *  liug@mama.indstate.edu, and others.
  *
  *  Version 0.01	Initial version, hacked out of ide.c,
  *			and #include'd rather than compiled separately.
  *			This will get cleaned up in a subsequent release.
  *
- *  Version 0.02	Fixes for vlb initialization code, enable
- *			read-ahead for versions 'B' and 'C' of chip by
- *			default, some code cleanup.
+ *  Version 0.02	Fixes for vlb initialization code, enable prefetch
+ *			for versions 'B' and 'C' of chip by default,
+ *			some code cleanup.
  *
  *  Version 0.03	Added reset of secondary interface,
  *			and black list for devices which are not compatible
- *			with read ahead mode. Separate function for setting
- *			readahead is added, possibly it will be called some
+ *			with prefetch mode. Separate function for setting
+ *			prefetch is added, possibly it will be called some
  *			day from ioctl processing code.
  *
- *  Version 0.04	Now configs/compiles separate from ide.c  -ml
+ *  Version 0.04	Now configs/compiles separate from ide.c
  *
  *  Version 0.05	Major rewrite of interface timing code.
  *			Added new function cmd640_set_mode to set PIO mode
  *			from ioctl call. New drives added to black list.
  *
- *  Version 0.06	More code cleanup. Readahead is enabled only for
- *			detected hard drives, not included in readahead
+ *  Version 0.06	More code cleanup. Prefetch is enabled only for
+ *			detected hard drives, not included in prefetch
  *			black list.
  *
  *  Version 0.07	Changed to more conservative drive tuning policy.
@@ -51,21 +64,37 @@
  *			List of known drives extended by info provided by
  *			CMD at their ftp site.
  *
- *  Version 0.08	Added autotune/noautotune support.  -ml
+ *  Version 0.08	Added autotune/noautotune support.
  *
- *  Version 0.09	Try to be smarter about 2nd port enabling.  -ml
- *  Version 0.10	Be nice and don't reset 2nd port.  -ml
- *  Version 0.11	Try to handle more wierd situations.  -ml
+ *  Version 0.09	Try to be smarter about 2nd port enabling.
+ *  Version 0.10	Be nice and don't reset 2nd port.
+ *  Version 0.11	Try to handle more wierd situations.
  *
  *  Version 0.12	Lots of bug fixes from Laszlo Peter
- *			irq unmasking disabled for reliability.  -lp
- *			try to be even smarter about the second port.  -lp
- *			tidy up source code formatting.  -ml
- *  Version 0.13	permit irq unmasking again.  -ml
+ *			irq unmasking disabled for reliability.
+ *			try to be even smarter about the second port.
+ *			tidy up source code formatting.
+ *  Version 0.13	permit irq unmasking again.
+ *  Version 0.90	massive code cleanup, some bugs fixed.
+ *			defaults all drives to PIO mode0, prefetch off.
+ *			autotune is OFF by default, with compile time flag.
+ *			prefetch can be turned OFF/ON using "hdparm -p8/-p9"
+ *			 (requires hdparm-3.1 or newer)
+ *  Version 0.91	first release to linux-kernel list.
+ *  Version 0.92	move initial reg dump to separate callable function
+ *			change "readahead" to "prefetch" to avoid confusion
+ *  Version 0.95	respect original BIOS timings unless autotuning.
+ *			tons of code cleanup and rearrangement.
+ *			added CONFIG_BLK_DEV_CMD640_ENHANCED option
+ *			prevent use of unmask when prefetch is on
+ *  Version 0.96	prevent use of io_32bit when prefetch is off
+ *  Version 0.97	fix VLB secondary interface for sjd@slip.net
+ *			other minor tune-ups:  0.96 was very good.
  */
 
 #undef REALLY_SLOW_IO		/* most systems can safely undef this */
 
+#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/delay.h>
@@ -78,8 +107,9 @@
 #include "ide.h"
 #include "ide_modes.h"
 
-#define PARANOID_ABOUT_CMD640	1	/* used to tag superstitious code */
-
+/*
+ * This flag is set in ide.c by the parameter:  ide0=cmd640_vlb
+ */
 int cmd640_vlb = 0;
 
 /*
@@ -120,70 +150,97 @@
 #define ARTTIM1 	0x55
 #define DRWTIM1		0x56
 #define ARTTIM23	0x57
-#define   DIS_RA2		0x04
-#define   DIS_RA3		0x08
+#define   ARTTIM23_DIS_RA2	0x04
+#define   ARTTIM23_DIS_RA3	0x08
 #define DRWTIM23	0x58
 #define BRST		0x59
 
-static ide_tuneproc_t cmd640_tune_drive;
+/*
+ * Registers and masks for easy access by drive index:
+ */
+static byte prefetch_regs[4]  = {CNTRL, CNTRL, ARTTIM23, ARTTIM23};
+static byte prefetch_masks[4] = {CNTRL_DIS_RA0, CNTRL_DIS_RA1, ARTTIM23_DIS_RA2, ARTTIM23_DIS_RA3};
+
+#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
+
+static byte arttim_regs[4] = {ARTTIM0, ARTTIM1, ARTTIM23, ARTTIM23};
+static byte drwtim_regs[4] = {DRWTIM0, DRWTIM1, DRWTIM23, DRWTIM23};
+
+/*
+ * Current cmd640 timing values for each drive.
+ * The defaults for each are the slowest possible timings.
+ */
+static byte setup_counts[4]    = {4, 4, 4, 4};     /* Address setup count (in clocks) */
+static byte active_counts[4]   = {16, 16, 16, 16}; /* Active count   (encoded) */
+static byte recovery_counts[4] = {16, 16, 16, 16}; /* Recovery count (encoded) */
+
+#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
+
+/*
+ * These are initialized to point at the devices we control
+ */
+static ide_hwif_t  *cmd_hwif0, *cmd_hwif1;
+static ide_drive_t *cmd_drives[4];
+
+/*
+ * Interface to access cmd640x registers
+ */
+static unsigned int cmd640_key;
+static void (*put_cmd640_reg)(unsigned short reg, byte val);
+static byte (*get_cmd640_reg)(unsigned short reg);
 
-/* Interface to access cmd640x registers */
-void (*put_cmd640_reg)(int reg_no, int val);
-byte (*get_cmd640_reg)(int reg_no);
-
-enum { none, vlb, pci1, pci2 };
-static int	bus_type = none;
-static int	cmd640_chip_version;
-static int	cmd640_key;
-static int 	bus_speed; /* MHz */
+/*
+ * This is read from the CFR reg, and is used in several places.
+ */
+static unsigned int cmd640_chip_version;
 
 /*
  * The CMD640x chip does not support DWORD config write cycles, but some
  * of the BIOSes use them to implement the config services.
- * We use direct IO instead.
+ * Therefore, we must use direct IO instead.
  */
 
 /* PCI method 1 access */
 
-static void put_cmd640_reg_pci1(int reg_no, int val)
+static void put_cmd640_reg_pci1 (unsigned short reg, byte val)
 {
 	unsigned long flags;
 
 	save_flags(flags);
 	cli();
-	outl_p((reg_no & 0xfc) | cmd640_key, 0xcf8);
-	outb_p(val, (reg_no & 3) + 0xcfc);
+	outl_p((reg & 0xfc) | cmd640_key, 0xcf8);
+	outb_p(val, (reg & 3) | 0xcfc);
 	restore_flags(flags);
 }
 
-static byte get_cmd640_reg_pci1(int reg_no)
+static byte get_cmd640_reg_pci1 (unsigned short reg)
 {
 	byte b;
 	unsigned long flags;
 
 	save_flags(flags);
 	cli();
-	outl_p((reg_no & 0xfc) | cmd640_key, 0xcf8);
-	b = inb_p(0xcfc + (reg_no & 3));
+	outl_p((reg & 0xfc) | cmd640_key, 0xcf8);
+	b = inb_p((reg & 3) | 0xcfc);
 	restore_flags(flags);
 	return b;
 }
 
 /* PCI method 2 access (from CMD datasheet) */
 
-static void put_cmd640_reg_pci2(int reg_no, int val)
+static void put_cmd640_reg_pci2 (unsigned short reg, byte val)
 {
 	unsigned long flags;
 
 	save_flags(flags);
 	cli();
 	outb_p(0x10, 0xcf8);
-	outb_p(val, cmd640_key + reg_no);
+	outb_p(val, cmd640_key + reg);
 	outb_p(0, 0xcf8);
 	restore_flags(flags);
 }
 
-static byte get_cmd640_reg_pci2(int reg_no)
+static byte get_cmd640_reg_pci2 (unsigned short reg)
 {
 	byte b;
 	unsigned long flags;
@@ -191,7 +248,7 @@
 	save_flags(flags);
 	cli();
 	outb_p(0x10, 0xcf8);
-	b = inb_p(cmd640_key + reg_no);
+	b = inb_p(cmd640_key + reg);
 	outb_p(0, 0xcf8);
 	restore_flags(flags);
 	return b;
@@ -199,48 +256,51 @@
 
 /* VLB access */
 
-static void put_cmd640_reg_vlb(int reg_no, int val)
+static void put_cmd640_reg_vlb (unsigned short reg, byte val)
 {
 	unsigned long flags;
 
 	save_flags(flags);
 	cli();
-	outb_p(reg_no, cmd640_key + 8);
-	outb_p(val, cmd640_key + 0xc);
+	outb_p(reg, cmd640_key);
+	outb_p(val, cmd640_key + 4);
 	restore_flags(flags);
 }
 
-static byte get_cmd640_reg_vlb(int reg_no)
+static byte get_cmd640_reg_vlb (unsigned short reg)
 {
 	byte b;
 	unsigned long flags;
 
 	save_flags(flags);
 	cli();
-	outb_p(reg_no, cmd640_key + 8);
-	b = inb_p(cmd640_key + 0xc);
+	outb_p(reg, cmd640_key);
+	b = inb_p(cmd640_key + 4);
 	restore_flags(flags);
 	return b;
 }
 
+static int match_pci_cmd640_device (void)
+{
+	const byte ven_dev[4] = {0x95, 0x10, 0x40, 0x06};
+	unsigned int i;
+	for (i = 0; i < 4; i++) {
+		if (get_cmd640_reg(i) != ven_dev[i])
+			return 0;
+	}
+	return 1; /* success */
+}
+
 /*
  * Probe for CMD640x -- pci method 1
  */
-
-static int probe_for_cmd640_pci1(void)
+static int probe_for_cmd640_pci1 (void)
 {
-	long id;
-	int	k;
-
-	for (k = 0x80000000; k <= 0x8000f800; k += 0x800) {
-		outl(k, 0xcf8);
-		id = inl(0xcfc);
-		if (id != 0x06401095)
-			continue;
-		put_cmd640_reg = put_cmd640_reg_pci1;
-		get_cmd640_reg = get_cmd640_reg_pci1;
-		cmd640_key = k;
-		return 1;
+	get_cmd640_reg = get_cmd640_reg_pci1;
+	put_cmd640_reg = put_cmd640_reg_pci1;
+	for (cmd640_key = 0x80000000; cmd640_key <= 0x8000f800; cmd640_key += 0x800) {
+		if (match_pci_cmd640_device())
+			return 1; /* success */
 	}
 	return 0;
 }
@@ -248,24 +308,13 @@
 /*
  * Probe for CMD640x -- pci method 2
  */
-
-static int probe_for_cmd640_pci2(void)
+static int probe_for_cmd640_pci2 (void)
 {
-	int i;
-	int v_id;
-	int d_id;
-
-	for (i = 0xc000; i <= 0xcf00; i += 0x100) {
-		outb(0x10, 0xcf8);
-		v_id = inw(i);
-		d_id = inw(i + 2);
-		outb(0, 0xcf8);
-		if (v_id != 0x1095 || d_id != 0x640)
-			continue;
-		put_cmd640_reg = put_cmd640_reg_pci2;
-		get_cmd640_reg = get_cmd640_reg_pci2;
-		cmd640_key = i;
-		return 1;
+	get_cmd640_reg = get_cmd640_reg_pci2;
+	put_cmd640_reg = put_cmd640_reg_pci2;
+	for (cmd640_key = 0xc000; cmd640_key <= 0xcf00; cmd640_key += 0x100) {
+		if (match_pci_cmd640_device())
+			return 1; /* success */
 	}
 	return 0;
 }
@@ -273,50 +322,22 @@
 /*
  * Probe for CMD640x -- vlb
  */
-
-static int probe_for_cmd640_vlb(void) {
+static int probe_for_cmd640_vlb (void)
+{
 	byte b;
 
-	outb(CFR, 0x178);
-	b = inb(0x17c);
-	if (b == 0xff || b == 0 || (b & CFR_AT_VESA_078h)) {
-		outb(CFR, 0x78);
-		b = inb(0x7c);
-		if (b == 0xff || b == 0 || !(b & CFR_AT_VESA_078h))
+	get_cmd640_reg = get_cmd640_reg_vlb;
+	put_cmd640_reg = put_cmd640_reg_vlb;
+	cmd640_key = 0x178;
+	b = get_cmd640_reg(CFR);
+	if (b == 0xff || b == 0x00 || (b & CFR_AT_VESA_078h)) {
+		cmd640_key = 0x78;
+		b = get_cmd640_reg(CFR);
+		if (b == 0xff || b == 0x00 || !(b & CFR_AT_VESA_078h))
 			return 0;
-		cmd640_key = 0x70;
-	} else {
-		cmd640_key = 0x170;
 	}
-	put_cmd640_reg = put_cmd640_reg_vlb;
-	get_cmd640_reg = get_cmd640_reg_vlb;
-	return 1;
-}
-
-#if 0
-/*
- * Low level reset for controller, actually it has nothing specific for
- * CMD640, but I don't know how to use standard reset routine before
- * we recognized any drives.
- */
-static void cmd640_reset_controller(int iface_no)
-{
-	int retry_count = 600;
-	int base_port = iface_no ? 0x170 : 0x1f0;
-
-	outb_p(4, base_port + 7);
-	udelay(5);
-	outb_p(0, base_port + 7);
-
-	do {
-		udelay(5);
-		retry_count -= 1;
-	} while ((inb_p(base_port + 7) & 0x80) && retry_count);
-
-	if (retry_count == 0)
-		printk("cmd640: failed to reset controller %d\n", iface_no);
+	return 1; /* success */
 }
-#endif /* 0 */
 
 /*
  *  Returns 1 if an IDE interface/drive exists at 0x170,
@@ -324,516 +345,461 @@
  */
 static int secondary_port_responding (void)
 {
-	/*
-	 * Test for hardware at 0x170 (secondary IDE port).
-	 */
-	outb_p(0xa0, 0x170 + IDE_SELECT_OFFSET);	/* select drive0 */
+	unsigned long flags;
+
+	save_flags(flags);
+	cli();
+
+	outb_p(0x0a, 0x170 + IDE_SELECT_OFFSET);	/* select drive0 */
 	udelay(100);
-	if (inb_p(0x170 + IDE_SELECT_OFFSET) != 0xa0) {
-		outb_p(0xb0, 0x170 + IDE_SELECT_OFFSET); /* select drive1 */
+	if ((inb_p(0x170 + IDE_SELECT_OFFSET) & 0x1f) != 0x0a) {
+		outb_p(0x1a, 0x170 + IDE_SELECT_OFFSET); /* select drive1 */
 		udelay(100);
-		if (inb_p(0x170 + IDE_SELECT_OFFSET) != 0xb0)
-			return 0;	/* nothing is there */
+		if ((inb_p(0x170 + IDE_SELECT_OFFSET) & 0x1f) != 0x1a) {
+			restore_flags(flags);
+			return 0; /* nothing responded */
+		}
 	}
-	return 1;			/* something is there */
+	restore_flags(flags);
+	return 1; /* success */
 }
 
+#ifdef CMD640_DUMP_REGS
 /*
- * Probe for Cmd640x and initialize it if found
+ * Dump out all cmd640 registers.  May be called from ide.c
  */
-
-int ide_probe_for_cmd640x(void)
+void cmd640_dump_regs (void)
 {
-	int second_port_toggled = 0;
-	int second_port_cmd640 = 0;
-	byte b;
-
-	if (probe_for_cmd640_pci1()) {
-		bus_type = pci1;
-	} else if (probe_for_cmd640_pci2()) {
-		bus_type = pci2;
-	} else if (cmd640_vlb && probe_for_cmd640_vlb()) {
-		/* May be remove cmd640_vlb at all, and probe in any case */
-		bus_type = vlb;
-	} else {
-		return 0;
-	}
-
-#ifdef PARANOID_ABOUT_CMD640
-	ide_hwifs[0].serialized = 1;	/* ensure this *always* gets set */
-	ide_hwifs[1].serialized = 1;	/* ensure this *always* gets set */
-#endif
-
-#if 0
-	/* Dump initial state of chip registers */
-	for (b = 0; b != 0xff; b++) {
-		printk(" %2x%c", get_cmd640_reg(b),
-				((b&0xf) == 0xf) ? '\n' : ',');
-	}
-#endif
-
-	/*
-	 * Undocumented magic. (There is no 0x5b port in specs)
-	 */
-
-	put_cmd640_reg(0x5b, 0xbd);
-	if (get_cmd640_reg(0x5b) != 0xbd) {
-		printk("ide: can't initialize cmd640 -- wrong value in 0x5b\n");
-		return 0;
-	}
-	put_cmd640_reg(0x5b, 0);
-
-	/*
-	 * Documented magic.
-	 */
-
-	cmd640_chip_version = get_cmd640_reg(CFR) & CFR_DEVREV;
-	if (cmd640_chip_version == 0) {
-		printk ("ide: wrong CMD640 version -- 0\n");
-		return 0;
-	}
-
-	/*
-	 * Setup the most conservative timings for all drives,
-	 */
-
-	put_cmd640_reg(CMDTIM, 0);
-
-	put_cmd640_reg(ARTTIM0, 0xc0);
-	put_cmd640_reg(ARTTIM1, 0xc0);
-	put_cmd640_reg(ARTTIM23, 0xcc); /* disable read-ahead for drives 2&3 */
-
-	put_cmd640_reg(DRWTIM0, 0);
-	put_cmd640_reg(DRWTIM1, 0);
-	put_cmd640_reg(DRWTIM23, 0);
-
-	/*
-	 * Set the maximum allowed bus speed (it is safest until we
-	 * 				      find how to detect bus speed)
-	 * Normally PCI bus runs at 33MHz, but often works overclocked to 40
-	 */
-	bus_speed = (bus_type == vlb) ? 50 : 40;
-
-	/*
-	 * Setup Control Register
-	 */
-	b = get_cmd640_reg(CNTRL);
-
-	/*
-	 * Disable readahead for drives at primary interface
-	 */
-	b |= (CNTRL_DIS_RA0 | CNTRL_DIS_RA1);
-	put_cmd640_reg(CNTRL, b);
-
-	if (!ide_hwifs[1].noprobe) {
-
-		if (secondary_port_responding()) {
-
-			if ((b & CNTRL_ENA_2ND) || (bus_type == vlb))
-				second_port_cmd640 = 1;
-
-		} else if (!(b & CNTRL_ENA_2ND) && (bus_type != vlb)) {
-
-			second_port_toggled = 1;
-			put_cmd640_reg(CNTRL, b | CNTRL_ENA_2ND); /* Enable second interface */
-
-			if (secondary_port_responding())
-				second_port_cmd640 = 1;
-			else {
-				second_port_toggled = 0;
-				put_cmd640_reg(CNTRL, b); /* Disable second interface */
-			}
-		}
-	}
-
-	/*
-	 * Note that we assume that the first interface is at 0x1f0,
-	 * and that the second interface, if enabled, is at 0x170.
-	 */
-	ide_hwifs[0].chipset = ide_cmd640;
-	ide_hwifs[0].tuneproc = &cmd640_tune_drive;
-#if 0
-	ide_hwifs[0].no_unmask = 1;
-#endif
-
-	if (ide_hwifs[0].drives[0].autotune == 0)
-		ide_hwifs[0].drives[0].autotune = 1;
-	if (ide_hwifs[0].drives[1].autotune == 0)
-		ide_hwifs[0].drives[1].autotune = 1;
-
-	/*
-	 * Initialize 2nd IDE port, if required
-	 */
-	if (second_port_cmd640) {
-
-#ifndef PARANOID_ABOUT_CMD640
-		ide_hwifs[0].serialized = 1;
-		ide_hwifs[1].serialized = 1;
-#endif
-
-		ide_hwifs[1].chipset = ide_cmd640;
-		ide_hwifs[1].tuneproc = &cmd640_tune_drive;
-#if 0
-		ide_hwifs[1].no_unmask = 1;
-#endif
-		if (ide_hwifs[1].drives[0].autotune == 0)
-			ide_hwifs[1].drives[0].autotune = 1;
-		if (ide_hwifs[1].drives[1].autotune == 0)
-			ide_hwifs[1].drives[1].autotune = 1;
-
-#if 0
-		/* reset the secondary interface */
-		cmd640_reset_controller(1);
-#endif
-	}
+	unsigned int reg = cmd640_vlb ? 0x50 : 0x00;
 
-	printk("ide: buggy CMD640%c interface on ",
-	       'A' - 1 + cmd640_chip_version);
-	switch (bus_type) {
-		case vlb :
-			printk("vlb (0x%x)", cmd640_key);
-			break;
-		case pci1:
-			printk("pci (0x%x)", cmd640_key);
-			break;
-		case pci2:
-			printk("pci (access method 2) (0x%x)", cmd640_key);
-			break;
+	/* Dump current state of chip registers */
+	printk("ide: cmd640 internal register dump:");
+	for (; reg <= 0x59; reg++) {
+		if (!(reg & 0x0f))
+			printk("\n%04x:", reg);
+		printk(" %02x", get_cmd640_reg(reg));
 	}
-
-	/*
-	 * Tell everyone what we did to their system
-	 */
-	printk(":%s serialized, second port %s\n",
-		second_port_cmd640 ? "" : " not",
-		second_port_toggled ? "toggled" : "untouched");
-	return 1;
+	printk("\n");
 }
-
-#if 0  /* not used anywhere */
-int cmd640_off(void) {
-	static int a = 0;
-	byte b;
-
-	if (bus_type == none || a == 1)
-		return 0;
-	a = 1;
-	b = get_cmd640_reg(CNTRL);
-	b &= ~CNTRL_ENA_2ND;
-	put_cmd640_reg(CNTRL, b);
-	return 1;
-}
-#endif /* 0 */
+#endif
 
 /*
- * Sets readahead mode for specific drive
- *  in the future it could be called from ioctl
+ * Check whether prefetch is on for a drive,
+ * and initialize the unmask flags for safe operation.
  */
-
-static void set_readahead_mode(ide_drive_t* drive, int mode)
+static void check_prefetch (unsigned int index)
 {
-	static int masks[2][2] =
-		{
-			{CNTRL_DIS_RA0, CNTRL_DIS_RA1},
-			{DIS_RA2, 	DIS_RA3}
-		};
-	byte b;
-
-	int interface_number = HWIF(drive)->index;
-	int drive_number = drive->select.b.unit;
-
-	int port = (interface_number == 0) ? CNTRL : ARTTIM23;
-	int mask = masks[interface_number][drive_number];
-
-	b = get_cmd640_reg(port);
-
-	/*
-	 * I don't know why it is necessary, but without this my machine
-	 * locks up, if bus_speed is not correct. And it even allows me
-	 * to use 32 bit transfers on the primary port (hdparm -c1).
-	 */
-	if ((interface_number == 0) && mode)
-		b|=0x27;
-
-	if (mode)
-		b &= ~mask;	/* Enable readahead for specific drive */
-	else
-		b |= mask;	/* Disable readahead for specific drive */
+	ide_drive_t *drive = cmd_drives[index];
+	byte b = get_cmd640_reg(prefetch_regs[index]);
 
-	put_cmd640_reg(port, b);
-}
-
-static const struct readahead_black_list {
-	const char* 	name;
-	int		mode;
-} drives_ra[] = {
-	{ "QUANTUM LIGHTNING 540A", 0 },
-	{ "ST3655A",	0 },
-	{ "SAMSUNG",	0 },	/* Be conservative */
-	{ NULL,		0 }
-};
-
-static int strmatch(const char* pattern, const char* name) {
-	char c1, c2;
-
-	while (1) {
-		c1 = *pattern++;
-		c2 = *name++;
-		if (c1 == 0) {
-			return 0;
-		}
-		if (c1 != c2)
-			return 1;
+	if (b & prefetch_masks[index]) {	/* is prefetch off? */
+		drive->no_unmask = 0;
+		drive->no_io_32bit = 1;
+		drive->io_32bit = 0;
+	} else {
+		drive->no_unmask = 1;
+		drive->no_io_32bit = 0;
+		drive->unmask = 0;
 	}
 }
 
-static int known_drive_readahead(char* name) {
-	int i;
+/*
+ * Figure out which devices we control
+ */
+static void setup_device_ptrs (void)
+{
+	unsigned int i;
 
-	for (i = 0; drives_ra[i].name != NULL; i++) {
-		if (strmatch(drives_ra[i].name, name) == 0) {
-			return drives_ra[i].mode;
+	cmd_hwif0 = &ide_hwifs[0]; /* default, if not found below */
+	cmd_hwif1 = &ide_hwifs[1]; /* default, if not found below */
+	for (i = 0; i < MAX_HWIFS; i++) {
+		ide_hwif_t *hwif = &ide_hwifs[i];
+		if (hwif->chipset == ide_unknown || hwif->chipset == ide_generic) {
+			if (hwif->io_base == 0x1f0)
+				cmd_hwif0 = hwif;
+			else if (hwif->io_base == 0x170)
+				cmd_hwif1 = hwif;
 		}
 	}
-	return -1;
+	cmd_drives[0] = &cmd_hwif0->drives[0];
+	cmd_drives[1] = &cmd_hwif0->drives[1];
+	cmd_drives[2] = &cmd_hwif1->drives[0];
+	cmd_drives[3] = &cmd_hwif1->drives[1];
 }
 
-static int arttim[4]  = {2, 2, 2, 2};	/* Address setup count (in clocks) */
-static int a_count[4] = {1, 1, 1, 1};	/* Active count   (encoded) */
-static int r_count[4] = {1, 1, 1, 1};	/* Recovery count (encoded) */
+#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
 
 /*
- * Convert address setup count from number of clocks
- * to representation used by controller
+ * Sets prefetch mode for a drive.
  */
-
-inline static int pack_arttim(int clocks)
+static void set_prefetch_mode (unsigned int index, int mode)
 {
-	if (clocks <= 2) return 0x40;
-	else if (clocks == 3) return 0x80;
-	else if (clocks == 4) return 0x00;
-	else return 0xc0;
+	ide_drive_t *drive = cmd_drives[index];
+	int reg = prefetch_regs[index];
+	byte b;
+	unsigned long flags;
+
+	save_flags(flags);
+	cli();
+	b = get_cmd640_reg(reg);
+	if (mode) {	/* want prefetch on? */
+		drive->no_unmask = 1;
+		drive->unmask = 0;
+		drive->no_io_32bit = 0;
+		b &= ~prefetch_masks[index];	/* enable prefetch */
+	} else {
+		drive->no_unmask = 0;
+		drive->no_io_32bit = 1;
+		drive->io_32bit = 0;
+		b |= prefetch_masks[index];	/* disable prefetch */
+	}
+	put_cmd640_reg(reg, b);
+	restore_flags(flags);
 }
 
 /*
  * Pack active and recovery counts into single byte representation
  * used by controller
  */
-
-inline static int pack_counts(int act_count, int rec_count)
+inline static byte pack_nibbles (byte upper, byte lower)
 {
-	return ((act_count & 0x0f)<<4) | (rec_count & 0x0f);
+	return ((upper & 0x0f) << 4) | (lower & 0x0f);
 }
 
-inline int max(int a, int b) { return a > b ? a : b; }
-inline int max4(int *p) { return max(p[0], max(p[1], max(p[2], p[3]))); }
-
 /*
- * Set timing parameters
+ * This routine retrieves the initial drive timings from the chipset.
  */
-
-static void cmd640_set_timing(int if_num, int dr_num)
+static void retrieve_drive_counts (unsigned int index)
 {
-	int	b_reg;
-	int	ac, rc, at;
 	byte b;
 
 	/*
-	 * Set address setup count and drive read/write timing registers.
-	 * Primary interface has individual count/timing registers for
-	 * each drive. Secondary interface has common set of registers, and
-	 * we should set timings for the slowest drive.
+	 * Get the internal setup timing, and convert to clock count
 	 */
-
-	if (if_num == 0) {
-		b_reg = dr_num ? ARTTIM1 : ARTTIM0;
-		at = arttim[dr_num];
-		ac = a_count[dr_num];
-		rc = r_count[dr_num];
-		b = pack_arttim(at);
-	} else {
-		b_reg = ARTTIM23;
-		at = max(arttim[2], arttim[3]);
-		ac = max(a_count[2], a_count[3]);
-		rc = max(r_count[2], r_count[3]);
-
-		/*
-		 * Protect the readahead bits
-		 */
-		b = pack_arttim(at) | (get_cmd640_reg(ARTTIM23) & (DIS_RA2 | DIS_RA3));
+	b = get_cmd640_reg(arttim_regs[index]) & ~0x3f;
+	switch (b) {
+		case 0x00: b = 4; break;
+		case 0x80: b = 3; break;
+		case 0x40: b = 2; break;
+		default:   b = 5; break;
 	}
-
-	put_cmd640_reg(b_reg, b);
-	put_cmd640_reg(b_reg + 1, pack_counts(ac, rc));
+	setup_counts[index] = b;
 
 	/*
-	 * Update CMDTIM (IDE Command Block Timing Register)
+	 * Get the active/recovery counts
 	 */
-
-	ac = max4(a_count);
-	rc = max4(r_count);
-	put_cmd640_reg(CMDTIM, pack_counts(ac, rc));
+	b = get_cmd640_reg(drwtim_regs[index]);
+	active_counts[index]   = (b >> 4)   ? (b >> 4)   : 0x10;
+	recovery_counts[index] = (b & 0x0f) ? (b & 0x0f) : 0x10;
 }
 
+
 /*
- * Standard timings for PIO modes
+ * This routine writes the prepared setup/active/recovery counts
+ * for a drive into the cmd640 chipset registers to active them.
  */
-
-static const struct pio_timing {
-	int	mc_time;	/* Address setup (ns) min */
-	int	av_time;	/* Active pulse (ns) min */
-	int	ds_time;	/* Cycle time (ns) min = Active pulse + Recovery pulse */
-} pio_timings[6] = {
-	{ 70,	165,	600 },	/* PIO Mode 0 */
-	{ 50,	125,	383 },	/* PIO Mode 1 */
-	{ 30,	100,	240 },	/* PIO Mode 2 */
-	{ 30,	80,	180 },	/* PIO Mode 3 w/IORDY */
-	{ 25,	70,	125 },	/* PIO Mode 4 w/IORDY -- should be 120, not 125 */
-	{ 20,	50,	100 }	/* PIO Mode 5 w/IORDY (nonstandard) */
-};
-
-static void cmd640_timings_to_clocks(int mc_time, int av_time, int ds_time,
-				int clock_time, int drv_idx)
+static void program_drive_counts (unsigned int index)
 {
-	int a, b;
+	unsigned long flags;
+	byte setup_count    = setup_counts[index];
+	byte active_count   = active_counts[index];
+	byte recovery_count = recovery_counts[index];
 
-	arttim[drv_idx] = (mc_time + clock_time - 1)/clock_time;
+	/*
+	 * Set up address setup count and drive read/write timing registers.
+	 * Primary interface has individual count/timing registers for
+	 * each drive.  Secondary interface has one common set of registers,
+	 * so we merge the timings, using the slowest value for each timing.
+	 */
+	if (index > 1) {
+		unsigned int mate;
+		if (cmd_drives[mate = index ^ 1]->present) {
+			if (setup_count < setup_counts[mate])
+				setup_count = setup_counts[mate];
+			if (active_count < active_counts[mate])
+				active_count = active_counts[mate];
+			if (recovery_count < recovery_counts[mate])
+				recovery_count = recovery_counts[mate];
+		}
+	}
 
-	a = (av_time + clock_time - 1)/clock_time;
-	if (a < 2)
-		a = 2;
-	b = (ds_time + clock_time - 1)/clock_time - a;
-	if (b < 2)
-		b = 2;
-	if (b > 0x11) {
-		a += b - 0x11;
-		b = 0x11;
+	/*
+	 * Convert setup_count to internal chipset representation
+	 */
+	switch (setup_count) {
+		case 4:	 setup_count = 0x00;
+		case 3:	 setup_count = 0x80;
+		case 2:	 setup_count = 0x40;
+		default: setup_count = 0xc0; /* case 5 */
 	}
-	if (a > 0x10)
-		a = 0x10;
-	if (cmd640_chip_version > 1)
-		b -= 1;
-	if (b > 0x10)
-		b = 0x10;
 
-	a_count[drv_idx] = a;
-	r_count[drv_idx] = b;
+	/*
+	 * Now that everything is ready, program the new timings
+	 */
+	save_flags (flags);
+	cli();
+	/*
+	 * Program the address_setup clocks into ARTTIM reg,
+	 * and then the active/recovery counts into the DRWTIM reg
+	 * (this converts counts of 16 into counts of zero -- okay).
+	 */
+	setup_count |= get_cmd640_reg(arttim_regs[index]) & 0x3f;
+	put_cmd640_reg(arttim_regs[index], setup_count);
+	put_cmd640_reg(drwtim_regs[index], pack_nibbles(active_count, recovery_count));
+	restore_flags(flags);
 }
 
-static void set_pio_mode(int if_num, int drv_num, int mode_num) {
-	int p_base;
-	int i;
-
-	p_base = if_num ? 0x170 : 0x1f0;
+/*
+ * Set a specific pio_mode for a drive
+ */
+static void cmd640_set_mode (unsigned int index, byte pio_mode, unsigned int cycle_time)
+{
+	int setup_time, active_time, recovery_time, clock_time;
+	byte setup_count, active_count, recovery_count, recovery_count2, cycle_count;
+	int bus_speed = ide_system_bus_speed();
+
+	if (pio_mode > 5)
+		pio_mode = 5;
+	setup_time  = ide_pio_timings[pio_mode].setup_time;
+	active_time = ide_pio_timings[pio_mode].active_time;
+	recovery_time = cycle_time - (setup_time + active_time);
+	clock_time = 1000 / bus_speed;
+	cycle_count = (cycle_time + clock_time - 1) / clock_time; 
+
+	setup_count = (setup_time + clock_time - 1) / clock_time;
+
+	active_count = (active_time + clock_time - 1) / clock_time;
+	if (active_count < 2)
+		active_count = 2; /* minimum allowed by cmd640 */
+
+	recovery_count = (recovery_time + clock_time - 1) / clock_time;
+	recovery_count2 = cycle_count - (setup_count + active_count);
+	if (recovery_count2 > recovery_count)
+		recovery_count = recovery_count2;
+	if (recovery_count < 2)
+		recovery_count = 2; /* minimum allowed by cmd640 */
+	if (recovery_count > 17) {
+		active_count += recovery_count - 17;
+		recovery_count = 17;
+	}
+	if (active_count > 16)
+		active_count = 16; /* maximum allowed by cmd640 */
+	if (cmd640_chip_version > 1)
+		recovery_count -= 1;  /* cmd640b uses (count + 1)*/
+	if (recovery_count > 16)
+		recovery_count = 16; /* maximum allowed by cmd640 */
 
-	outb_p(3, p_base + IDE_FEATURE_OFFSET);
-	outb_p(mode_num | 0x08, p_base + IDE_NSECTOR_OFFSET);
-	outb_p((drv_num | 0x0a) << 4, p_base + IDE_SELECT_OFFSET);
-	outb_p(WIN_SETFEATURES, p_base + IDE_COMMAND_OFFSET);
+	setup_counts[index]    = setup_count;
+	active_counts[index]   = active_count;
+	recovery_counts[index] = recovery_count;
 
-	for (i = 0; (i < 100) && (inb(p_base + IDE_STATUS_OFFSET) & BUSY_STAT); i++)
-		udelay(10000);
+	/*
+	 * In a perfect world, we might set the drive pio mode here
+	 * (using WIN_SETFEATURE) before continuing.
+	 *
+	 * But we do not, because:
+	 *	1) this is the wrong place to do it (proper is do_special() in ide.c)
+	 * 	2) in practice this is rarely, if ever, necessary
+	 */
+	program_drive_counts (index);
 }
 
 /*
- * Set a specific pio_mode for a drive
+ * Drive PIO mode selection:
  */
+static void cmd640_tune_drive (ide_drive_t *drive, byte mode_wanted)
+{
+	ide_pio_data_t  d;
+	unsigned int index = 0;
 
-static void cmd640_set_mode(ide_drive_t* drive, byte pio_mode, int ds_time) {
-	int interface_number;
-	int drive_number;
-	int clock_time; /* ns */
-	int mc_time, av_time;
-
-	if (pio_mode > 5) return;
-
-	interface_number = HWIF(drive)->index;
-	drive_number = drive->select.b.unit;
-	clock_time = 1000/bus_speed;
+	while (drive != cmd_drives[index]) {
+		if (++index > 3) {
+			printk("%s: bad news in cmd640_tune_drive\n", drive->name);
+			return;
+		}
+	}
+	/*
+	 * If the user asks for pio_mode 9 (no such mode),
+	 * we take it to mean "turn ON prefetch" for this drive.
+	 *
+	 * If the user asks for pio_mode 8 (no such mode),
+	 * we take it to mean "turn OFF prefetch" for this drive.
+	 */
+	if ((mode_wanted & 0xfe) == 0x08) {	/* program prefetch? */
+		mode_wanted &= 1;
+		set_prefetch_mode(index, mode_wanted);
+		printk("%s: %sabled cmd640 prefetch\n", drive->name, mode_wanted ? "en" : "dis");
+		return;
+	}
 
-	mc_time = pio_timings[pio_mode].mc_time;
-	av_time = pio_timings[pio_mode].av_time;
-	ds_time = (ds_time != 0) ? ds_time : pio_timings[pio_mode].ds_time;
+	(void) ide_get_best_pio_mode (drive, mode_wanted, 5, &d);
+	cmd640_set_mode (index, d.pio_mode, d.cycle_time);
 
-	cmd640_timings_to_clocks(mc_time, av_time, ds_time, clock_time,
-				interface_number*2 + drive_number);
-	set_pio_mode(interface_number, drive_number, pio_mode);
-	cmd640_set_timing(interface_number, drive_number);
+	printk ("%s: selected cmd640 PIO mode%d (%dns) %s/IORDY%s\n",
+		drive->name,
+		d.pio_mode,
+		d.cycle_time,
+		d.use_iordy ? "w" : "wo",
+		d.overridden ? " (overriding vendor mode)" : "");
 }
 
+#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
+
 /*
- * Drive PIO mode "autoconfiguration".
+ * Probe for a cmd640 chipset, and initialize it if found.  Called from ide.c
  */
+int ide_probe_for_cmd640x (void)
+{
+#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
+	int second_port_toggled = 0;
+#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
+	int second_port_cmd640 = 0;
+	const char *bus_type, *port2;
+	unsigned int index;
+	byte b, cfr;
 
-static void cmd640_tune_drive(ide_drive_t *drive, byte pio_mode) {
-	int max_pio;
-	int ds_time;
-	int readahead;	/* there is a global named read_ahead */
-	int overridden;
-	int iordy;
-	struct hd_driveid* id;
+	if (cmd640_vlb && probe_for_cmd640_vlb()) {
+		bus_type = "VLB";
+	} else {
+		cmd640_vlb = 0;
+		if (probe_for_cmd640_pci1())
+			bus_type = "PCI (type1)";
+		else if (probe_for_cmd640_pci2())
+			bus_type = "PCI (type2)";
+		else
+			return 0;
+	}
+	/*
+	 * Undocumented magic (there is no 0x5b reg in specs)
+	 */
+	put_cmd640_reg(0x5b, 0xbd);
+	if (get_cmd640_reg(0x5b) != 0xbd) {
+		printk("ide: cmd640 init failed: wrong value in reg 0x5b\n");
+		return 0;
+	}
+	put_cmd640_reg(0x5b, 0);
 
-	if (pio_mode != 255) {
-		cmd640_set_mode(drive, pio_mode, 0);
-		return;
+#ifdef CMD640_DUMP_REGS
+	CMD640_DUMP_REGS;
+#endif
+
+	/*
+	 * Documented magic begins here
+	 */
+	cfr = get_cmd640_reg(CFR);
+	cmd640_chip_version = cfr & CFR_DEVREV;
+	if (cmd640_chip_version == 0) {
+		printk ("ide: bad cmd640 revision: %d\n", cmd640_chip_version);
+		return 0;
 	}
 
-	overridden = 0;
-	iordy = 0;
-	id = drive->id;
-
-	if ((max_pio = ide_scan_pio_blacklist(id->model)) != -1) {
-		ds_time = pio_timings[max_pio].ds_time;
-		overridden = 1;
-		iordy = (max_pio > 2);
+	/*
+	 * Initialize data for primary port
+	 */
+	setup_device_ptrs ();
+	printk("%s: buggy cmd640%c interface on %s, config=0x%02x\n",
+	       cmd_hwif0->name, 'a' + cmd640_chip_version - 1, bus_type, cfr);
+	cmd_hwif0->chipset = ide_cmd640;
+#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
+	cmd_hwif0->tuneproc = &cmd640_tune_drive;
+#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
+
+	/*
+	 * Ensure compatibility by always using the slowest timings
+	 * for access to the drive's command register block,
+	 * and reset the prefetch burstsize to default (512 bytes).
+	 *
+	 * Maybe we need a way to NOT do these on *some* systems?
+	 */
+	put_cmd640_reg(CMDTIM, 0);
+	put_cmd640_reg(BRST, 0x40);
+
+	/*
+	 * Try to enable the secondary interface, if not already enabled
+	 */
+	if (cmd_hwif1->noprobe) {
+		port2 = "not probed";
 	} else {
-		max_pio = id->tPIO;
-		ds_time = pio_timings[max_pio].ds_time;
-		if (id->field_valid & 2) {
-			if ((id->capability & 8) && (id->eide_pio_modes & 7)) {
-				if (id->eide_pio_modes & 4) max_pio = 5;
-				else if (id->eide_pio_modes & 2) max_pio = 4;
-				else max_pio = 3;
-				ds_time = id->eide_pio_iordy;
-				iordy = 1;
+		b = get_cmd640_reg(CNTRL);
+		if (secondary_port_responding()) {
+			if ((b & CNTRL_ENA_2ND)) {
+				second_port_cmd640 = 1;
+				port2 = "okay";
+			} else if (cmd640_vlb) {
+				second_port_cmd640 = 1;
+				port2 = "alive";
+			} else
+				port2 = "not cmd640";
+		} else {
+			put_cmd640_reg(CNTRL, b ^ CNTRL_ENA_2ND); /* toggle the bit */
+			if (secondary_port_responding()) {
+				second_port_cmd640 = 1;
+#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
+				second_port_toggled = 1;
+#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
+				port2 = "enabled";
 			} else {
-				ds_time = id->eide_pio;
-			}
-			if (ds_time == 0) {
-				ds_time = pio_timings[max_pio].ds_time;
-				iordy = (max_pio > 2);
+				put_cmd640_reg(CNTRL, b); /* restore original setting */
+				port2 = "not responding";
 			}
 		}
-
-		/*
-		 * Conservative "downgrade"
-		 */
-		if (max_pio < 4 && max_pio != 0) {
-			max_pio--;
-			overridden = 1;
-			iordy = (max_pio > 2);
-			ds_time = pio_timings[max_pio].ds_time;
-		}
 	}
 
-	cmd640_set_mode(drive, max_pio, ds_time);
-
 	/*
-	 * Disable (or set) readahead mode
+	 * Initialize data for secondary cmd640 port, if enabled
 	 */
-
-	readahead = 0;
-	if (cmd640_chip_version > 1) {	/* Mmmm.. probably should be > 2 ?? */
-		readahead = known_drive_readahead(id->model);
-		if (readahead == -1)
-	        	readahead = 1;	/* Mmmm.. probably be 0 ?? */
-		set_readahead_mode(drive, readahead);
+	if (second_port_cmd640) {
+		cmd_hwif0->serialized = 1;
+		cmd_hwif1->serialized = 1;
+		cmd_hwif1->chipset = ide_cmd640;
+#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
+		cmd_hwif1->tuneproc = &cmd640_tune_drive;
+#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
+	}
+	printk("%s: %sserialized, secondary interface %s\n", cmd_hwif1->name,
+		cmd_hwif0->serialized ? "" : "not ", port2);
+
+	/*
+	 * Establish initial timings/prefetch for all drives.
+	 * Do not unnecessarily disturb any prior BIOS setup of these.
+	 */
+	for (index = 0; index < (2 + (second_port_cmd640 << 1)); index++) {
+		ide_drive_t *drive = cmd_drives[index];
+#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
+		if (drive->autotune || ((index > 1) && second_port_toggled)) {
+	 		/*
+	 		 * Reset timing to the slowest speed and turn off prefetch.
+			 * This way, the drive identify code has a better chance.
+			 */
+			setup_counts    [index] = 4;	/* max possible */
+			active_counts   [index] = 16;	/* max possible */
+			recovery_counts [index] = 16;	/* max possible */
+			program_drive_counts (index);
+			set_prefetch_mode (index, 0);
+			printk("cmd640: drive%d timings/prefetch cleared\n", index);
+		} else {
+			/*
+			 * Record timings/prefetch without changing them.
+			 * This preserves any prior BIOS setup.
+			 */
+			retrieve_drive_counts (index);
+			check_prefetch (index);
+			printk("cmd640: drive%d timings/prefetch(%s) preserved\n",
+				index, drive->no_io_32bit ? "off" : "on");
+		}
+#else
+		/*
+		 * Set the drive unmask flags to match the prefetch setting
+		 */
+		check_prefetch (index);
+		printk("cmd640: drive%d timings/prefetch(%s) preserved\n",
+			index, drive->no_io_32bit ? "off" : "on");
+#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
 	}
 
-	printk ("Drive Timing: PIO Mode %d (%dns) %s/IORDY%s, Read-ahead: %s\n",
-		max_pio,
-		ds_time,
-		iordy ? "w" : "wo",
-		overridden ? " (overriding vendor mode)" : "",
-		readahead ? "enabled" : "disabled");
+#ifdef CMD640_DUMP_REGS
+	CMD640_DUMP_REGS;
+#endif
+	return 1;
 }
+
diff -u --recursive --new-file v2.0.10/linux/drivers/block/dtc2278.c linux/drivers/block/dtc2278.c
--- v2.0.10/linux/drivers/block/dtc2278.c	Tue Jul 23 11:33:32 1996
+++ linux/drivers/block/dtc2278.c	Mon Aug  5 08:12:25 1996
@@ -71,8 +71,7 @@
 {
 	unsigned long flags;
 
-	if (pio == 255)
-		pio = ide_get_best_pio_mode(drive);
+	pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
 
 	if (pio >= 3) {
 		save_flags(flags);
@@ -122,6 +121,8 @@
 	ide_hwifs[0].chipset = ide_dtc2278;
 	ide_hwifs[1].chipset = ide_dtc2278;
 	ide_hwifs[0].tuneproc = &tune_dtc2278;
-	ide_hwifs[0].no_unmask = 1;
-	ide_hwifs[1].no_unmask = 1;
+	ide_hwifs[0].drives[0].no_unmask = 1;
+	ide_hwifs[0].drives[1].no_unmask = 1;
+	ide_hwifs[1].drives[0].no_unmask = 1;
+	ide_hwifs[1].drives[1].no_unmask = 1;
 }
diff -u --recursive --new-file v2.0.10/linux/drivers/block/floppy.c linux/drivers/block/floppy.c
--- v2.0.10/linux/drivers/block/floppy.c	Mon Jul 15 16:59:30 1996
+++ linux/drivers/block/floppy.c	Sat Aug  3 11:46:51 1996
@@ -1231,7 +1231,6 @@
 		/*DPRINT("FIFO enabled\n");*/
 	}
 
-#ifndef __sparc__
 	switch (raw_cmd->rate & 0x03) {
 		case 3:
 			dtr = 1000;
@@ -1286,7 +1285,6 @@
 		output_byte(FDCS->spec1 = spec1);
 		output_byte(FDCS->spec2 = spec2);
 	}
-#endif
 } /* fdc_specify */
 
 /* Set the FDC's data transfer rate on behalf of the specified drive.
diff -u --recursive --new-file v2.0.10/linux/drivers/block/ht6560b.c linux/drivers/block/ht6560b.c
--- v2.0.10/linux/drivers/block/ht6560b.c	Fri Apr 12 09:49:32 1996
+++ linux/drivers/block/ht6560b.c	Mon Aug  5 08:12:25 1996
@@ -201,10 +201,8 @@
 		if (drive->media != ide_disk)
 			pio = 0; /* some cdroms don't like fast modes (?) */
 		else
-			pio = ide_get_best_pio_mode (drive);
+			pio = ide_get_best_pio_mode(drive, pio, 5, NULL);
 	}
-	if (pio > 5)
-		pio = 5;
 	unit = drive->select.b.unit;
 	hwif = HWIF(drive)->index;
 	ht6560b_timings[hwif][unit] = pio_to_timings[pio];
diff -u --recursive --new-file v2.0.10/linux/drivers/block/ide-cd.c linux/drivers/block/ide-cd.c
--- v2.0.10/linux/drivers/block/ide-cd.c	Wed Jul 10 13:11:15 1996
+++ linux/drivers/block/ide-cd.c	Thu Aug  1 15:36:31 1996
@@ -105,6 +105,7 @@
  *                        special help from Jeff Lightfoot 
  *                        <jeffml@netcom.com>
  * 3.15a July 9, 1996 -- Improved Sanyo 3 CD changer identification
+ * 3.16  Jul 28, 1996 -- Fix from Gadi to reduce kernel stack usage for ioctl.
  *
  * 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.
@@ -2308,7 +2309,7 @@
 		int stat, lba;
 		struct atapi_toc *toc;
 		struct cdrom_read_audio ra;
-		char buf[CD_FRAMESIZE_RAW];
+		char *buf;
 
 		/* Make sure the TOC is up to date. */
 		stat = cdrom_read_toc (drive, NULL);
@@ -2342,17 +2343,23 @@
 		if (lba < 0 || lba >= toc->capacity)
 			return -EINVAL;
 
+		buf = (char *) kmalloc (CD_FRAMESIZE_RAW, GFP_KERNEL);
+		if (buf == NULL)
+			return -ENOMEM;
+
 		while (ra.nframes > 0) {
 			stat = cdrom_read_block (drive, 1, lba, buf,
 						 CD_FRAMESIZE_RAW, NULL);
-			if (stat) return stat;
+			if (stat) break;
+
 			memcpy_tofs (ra.buf, buf, CD_FRAMESIZE_RAW);
 			ra.buf += CD_FRAMESIZE_RAW;
 			--ra.nframes;
 			++lba;
 		}
 
-		return 0;
+		kfree (buf);
+		return stat;
 	}
 
 	case CDROMREADMODE1:
@@ -2360,7 +2367,7 @@
 		struct cdrom_msf msf;
 		int blocksize, format, stat, lba;
 		struct atapi_toc *toc;
-		char buf[CD_FRAMESIZE_RAW0];
+		char *buf;
 
 		if (cmd == CDROMREADMODE1) {
 			blocksize = CD_FRAMESIZE;
@@ -2388,12 +2395,17 @@
 		if (lba < 0 || lba >= toc->capacity)
 			return -EINVAL;
 
+		buf = (char *) kmalloc (CD_FRAMESIZE_RAW0, GFP_KERNEL);
+		if (buf == NULL)
+			return -ENOMEM;
+
 		stat = cdrom_read_block (drive, format, lba, buf, blocksize,
 					 NULL);
-		if (stat) return stat;
+		if (stat == 0)
+			memcpy_tofs ((char *)arg, buf, blocksize);
 
-		memcpy_tofs ((char *)arg, buf, blocksize);
-		return 0;
+		kfree (buf);
+		return stat;
 	}
 
 	case CDROM_GET_UPC: {
diff -u --recursive --new-file v2.0.10/linux/drivers/block/ide.c linux/drivers/block/ide.c
--- v2.0.10/linux/drivers/block/ide.c	Thu Aug  1 15:53:34 1996
+++ linux/drivers/block/ide.c	Mon Aug  5 08:19:52 1996
@@ -1,5 +1,5 @@
 /*
- *  linux/drivers/block/ide.c	Version 5.46  Jul 23, 1996
+ *  linux/drivers/block/ide.c	Version 5.49  Aug  4, 1996
  *
  *  Copyright (C) 1994-1996  Linus Torvalds & authors (see below)
  */
@@ -246,6 +246,16 @@
  *			include mc68000 patches from Geert Uytterhoeven
  *			add Gadi's fix for PCMCIA cdroms
  * Version 5.46		remove the mc68000 #ifdefs for 2.0.x
+ * Version 5.47		fix set_tune race condition
+ *			fix bug in earlier PCMCIA cdrom update
+ * Version 5.48		if def'd, invoke CMD640_DUMP_REGS when irq probe fails
+ *			lengthen the do_reset1() pulse, for laptops
+ *			add idebus=xx parameter for cmd640 and ali chipsets
+ *			no_unmask flag now per-drive instead of per-hwif
+ *			fix tune_req so that it gets done immediately
+ *			fix missing restore_flags() in ide_ioctl
+ *			prevent use of io_32bit on cmd640 with no prefetch
+ * Version 5.49		fix minor quirks in probing routines
  *
  *  Some additional driver compile-time options are in ide.h
  *
@@ -294,6 +304,13 @@
 static const byte	ide_hwif_to_major[MAX_HWIFS] = {IDE0_MAJOR, IDE1_MAJOR, IDE2_MAJOR, IDE3_MAJOR};
 static const unsigned short default_io_base[MAX_HWIFS] = {0x1f0, 0x170, 0x1e8, 0x168};
 static const byte	default_irqs[MAX_HWIFS]     = {14, 15, 11, 10};
+static int	idebus_parameter; /* holds the "idebus=" parameter */
+static int	system_bus_speed; /* holds what we think is VESA/PCI bus speed */
+
+/*
+ * This is declared extern in ide.h, for access by other IDE modules:
+ */
+ide_hwif_t	ide_hwifs[MAX_HWIFS];	/* master data repository */
 
 #if (DISK_RECOVERY_TIME > 0)
 /*
@@ -402,6 +419,32 @@
 
 	for (index = 0; index < MAX_HWIFS; ++index)
 		init_hwif_data(index);
+
+	idebus_parameter = 0;
+	system_bus_speed = 0;
+}
+
+/*
+ * ide_system_bus_speed() returns what we think is the system VESA/PCI
+ * bus speed (in Mhz).  This is used for calculating interface PIO timings.
+ * The default is 40 for known PCI systems, 50 otherwise.
+ * The "idebus=xx" parameter can be used to override this value.
+ * The actual value to be used is computed/displayed the first time through.
+ */
+int ide_system_bus_speed (void)
+{
+	if (!system_bus_speed) {
+		if (idebus_parameter)
+			system_bus_speed = idebus_parameter;	/* user supplied value */
+#ifdef CONFIG_PCI
+		else if (pcibios_present())
+			system_bus_speed = 40;	/* safe default value for PCI */
+#endif /* CONFIG_PCI */
+		else
+			system_bus_speed = 50;	/* safe default value for VESA and PCI */
+		printk("ide: Assuming %dMhz system bus speed for PIO modes; override with idebus=xx\n", system_bus_speed);
+	}
+	return system_bus_speed;
 }
 
 #if SUPPORT_VLB_SYNC
@@ -770,9 +813,9 @@
 	 * recover from reset very quickly, saving us the first 50ms wait time.
 	 */
 	OUT_BYTE(drive->ctl|6,IDE_CONTROL_REG);	/* set SRST and nIEN */
-	udelay(5);			/* more than enough time */
+	udelay(10);			/* more than enough time */
 	OUT_BYTE(drive->ctl|2,IDE_CONTROL_REG);	/* clear SRST, leave nIEN */
-	udelay(5);			/* more than enough time */
+	udelay(10);			/* more than enough time */
 	hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
 	ide_set_handler (drive, &reset_pollfunc, HZ/20);
 #endif	/* OK_TO_RESET_CONTROLLER */
@@ -1183,7 +1226,7 @@
 static inline void do_special (ide_drive_t *drive)
 {
 	special_t *s = &drive->special;
-next:
+
 #ifdef DEBUG
 	printk("%s: do_special: 0x%02x\n", drive->name, s->all);
 #endif
@@ -1201,12 +1244,11 @@
 		s->b.recalibrate = 0;
 		if (drive->media == ide_disk && !IS_PROMISE_DRIVE)
 			ide_cmd(drive, WIN_RESTORE, drive->sect, &recal_intr);
-	} else if (s->b.set_pio) {
+	} else if (s->b.set_tune) {
 		ide_tuneproc_t *tuneproc = HWIF(drive)->tuneproc;
-		s->b.set_pio = 0;
+		s->b.set_tune = 0;
 		if (tuneproc != NULL)
-			tuneproc(drive, drive->pio_req);
-		goto next;
+			tuneproc(drive, drive->tune_req);
 	} else if (s->b.set_multmode) {
 		s->b.set_multmode = 0;
 		if (drive->media == ide_disk) {
@@ -1639,6 +1681,7 @@
 				if (!drive->present)
 					continue;
 				SELECT_DRIVE(hwif,drive);
+				udelay(100);  /* Ugly, but wait_stat() may not be safe here */
 				if (!OK_STAT(stat=GET_STAT(), drive->ready_stat, BAD_STAT)) {
 					/* Try to not flood the console with msgs */
 					static unsigned long last_msgtime = 0;
@@ -1653,6 +1696,7 @@
 		}
 	} while ((hwif = hwif->next) != hwgroup->hwif);
 	SELECT_DRIVE(hwif,hwgroup->drive); /* Ugh.. probably interrupts current I/O */
+	udelay(100);  /* Ugly, but wait_stat() may not be safe here */
 }
 
 /*
@@ -1917,10 +1961,6 @@
 	if (drive->media != ide_disk)
 		drive->part[0].start_sect = -1;
 	resetup_one_dev(HWIF(drive)->gd, drive->select.b.unit);
-#ifdef CONFIG_BLK_DEV_IDECD
-	if (drive->media == ide_cdrom)
-		ide_cdrom_setup(drive);
-#endif /* CONFIG_BLK_DEV_IDECD */
 
 	drive->busy = 0;
 	wake_up(&drive->wqueue);
@@ -2046,7 +2086,7 @@
 					drive->keep_settings = arg;
 					break;
 				case HDIO_SET_UNMASKINTR:
-					if (arg && HWIF(drive)->no_unmask) {
+					if (arg && drive->no_unmask) {
 						restore_flags(flags);
 						return -EPERM;
 					}
@@ -2056,8 +2096,14 @@
 					drive->bad_wstat = arg ? BAD_R_STAT : BAD_W_STAT;
 					break;
 				case HDIO_SET_32BIT:
-					if (arg > (1 + (SUPPORT_VLB_SYNC<<1)))
+					if (arg > (1 + (SUPPORT_VLB_SYNC<<1))) {
+						restore_flags(flags);
 						return -EINVAL;
+					}
+					if (arg && drive->no_io_32bit) {
+						restore_flags(flags);
+						return -EPERM;
+					}
 					drive->io_32bit = arg;
 #ifdef CONFIG_BLK_DEV_DTC2278
 					if (HWIF(drive)->chipset == ide_dtc2278)
@@ -2123,9 +2169,14 @@
 				return -ENOSYS;
 			save_flags(flags);
 			cli();
-			drive->pio_req = (int) arg;
-			drive->special.b.set_pio = 1;
+			if (drive->special.b.set_tune) {
+				restore_flags(flags);
+				return -EBUSY;
+			}
+			drive->tune_req = (byte) arg;
+			drive->special.b.set_tune = 1;
 			restore_flags(flags);
+			(void) ide_do_drive_cmd (drive, &rq, ide_wait);
 			return 0;
 
 		RO_IOCTLS(inode->i_rdev, arg);
@@ -2431,11 +2482,6 @@
 		save_flags(flags);
 		cli();			/* some systems need this */
 		do_identify(drive, cmd); /* drive returned ID */
-		if (drive->present && drive->media != ide_tape) {
-			ide_tuneproc_t *tuneproc = HWIF(drive)->tuneproc;
-			if (tuneproc != NULL && drive->autotune == 1)
-				tuneproc(drive, 255);	/* auto-tune PIO mode */
-		}
 		rc = 0;			/* drive responded with ID */
 		(void) GET_STAT();	/* clear drive IRQ */
 		restore_flags(flags);
@@ -2455,12 +2501,12 @@
 		} else {	/* Mmmm.. multiple IRQs.. don't know which was ours */
 			printk("%s: IRQ probe failed (%d)\n", drive->name, irqs);
 #ifdef CONFIG_BLK_DEV_CMD640
+#ifdef CMD640_DUMP_REGS
 			if (HWIF(drive)->chipset == ide_cmd640) {
-				extern byte (*get_cmd640_reg)(int);
 				printk("%s: Hmmm.. probably a driver problem.\n", drive->name);
-				printk("%s: cmd640 reg 09h == 0x%02x\n", drive->name, get_cmd640_reg(9));
-				printk("%s: cmd640 reg 51h == 0x%02x\n", drive->name, get_cmd640_reg(0x51));
+				CMD640_DUMP_REGS;
 			}
+#endif /* CMD640_DUMP_REGS */
 #endif /* CONFIG_BLK_DEV_CMD640 */
 		}
 	}
@@ -2486,7 +2532,7 @@
 static int do_probe (ide_drive_t *drive, byte cmd)
 {
 	int rc;
-	ide_hwif_t *hwif;
+	ide_hwif_t *hwif = HWIF(drive);
 #ifdef CONFIG_BLK_DEV_IDEATAPI
 	if (drive->present) {	/* avoid waiting for inappropriate probes */
 		if ((drive->media != ide_disk) && (cmd == WIN_IDENTIFY))
@@ -2498,12 +2544,12 @@
 		drive->name, drive->present, drive->media,
 		(cmd == WIN_IDENTIFY) ? "ATA" : "ATAPI");
 #endif
-	hwif = HWIF(drive);
 	SELECT_DRIVE(hwif,drive);
-	OUT_BYTE(drive->select.all,IDE_SELECT_REG);	/* select target drive */
-	delay_10ms();				/* wait for BUSY_STAT */
+	delay_10ms();		/* allow BUSY_STAT to assert & clear */
+	delay_10ms();
 	if (IN_BYTE(IDE_SELECT_REG) != drive->select.all && !drive->present) {
 		OUT_BYTE(0xa0,IDE_SELECT_REG);	/* exit with drive0 selected */
+		delay_10ms();		/* allow BUSY_STAT to assert & clear */
 		return 3;    /* no i/f present: avoid killing ethernet cards */
 	}
 
@@ -2665,6 +2711,14 @@
 			}
 		}
 		restore_flags(flags);
+		for (unit = 0; unit < MAX_DRIVES; ++unit) {
+			ide_drive_t *drive = &hwif->drives[unit];
+			if (drive->present && drive->media != ide_tape) {
+				ide_tuneproc_t *tuneproc = HWIF(drive)->tuneproc;
+				if (tuneproc != NULL && drive->autotune == 1)
+					tuneproc(drive, 255);	/* auto-tune PIO mode */
+			}
+		}
 	}
 }
 
@@ -2701,9 +2755,11 @@
 		 * Try matching against the supplied keywords,
 		 * and return -(index+1) if we match one
 		 */
-		for (i = 0; *keywords != NULL; ++i) {
-			if (!strcmp(s, *keywords++))
-				return -(i+1);
+		if (keywords != NULL) {
+			for (i = 0; *keywords != NULL; ++i) {
+				if (!strcmp(s, *keywords++))
+					return -(i+1);
+			}
 		}
 		/*
 		 * Look for a series of no more than "max_vals"
@@ -2750,6 +2806,15 @@
  *				and quite likely to cause trouble with
  *				older/odd IDE drives.
  *
+ * "idebus=xx"		: inform IDE driver of VESA/PCI bus speed in Mhz,
+ *				where "xx" is between 25 and 66 inclusive,
+ *				used when tuning chipset PIO modes.
+ *				For PCI bus, 25 is correct for a P75 system,
+ *				30 is correct for P90,P120,P180 systems,
+ *				and 33 is used for P100,P133,P166 systems.
+ *				If in doubt, use idebus=33 for PCI.
+ *				As for VLB, it is safest to not specify it.
+ *
  * "idex=noprobe"	: do not attempt to access/use this interface
  * "idex=base"		: probe for an interface at the addr specified,
  *				where "base" is usually 0x1f0 or 0x170
@@ -2838,10 +2903,25 @@
 				goto bad_option;
 		}
 	}
+
+	if (s[0] != 'i' || s[1] != 'd' || s[2] != 'e')
+		goto bad_option;
+	/*
+	 * Look for bus speed option:  "idebus="
+	 */
+	if (s[3] == 'b' && s[4] == 'u' && s[5] == 's') {
+		if (match_parm(&s[6], NULL, vals, 1) != 1)
+			goto bad_option;
+		if (vals[0] >= 25 && vals[0] <= 66)
+			idebus_parameter = vals[0];
+		else
+			printk(" -- BAD BUS SPEED! Expected value from 25 to 66");
+		goto done;
+	}
 	/*
 	 * Look for interface options:  "idex="
 	 */
-	if (s[0] == 'i' && s[1] == 'd' && s[2] == 'e' && s[3] >= '0' && s[3] <= max_hwif) {
+	if (s[3] >= '0' && s[3] <= max_hwif) {
 		/*
 		 * Be VERY CAREFUL changing this: note hardcoded indexes below
 		 */
@@ -2854,17 +2934,19 @@
 		/*
 		 * Cryptic check to ensure chipset not already set for hwif:
 		 */
-		if (i >= 0 || i <= -5) {
+		if (i > 0 || i <= -5) {
 			if (hwif->chipset != ide_unknown)
 				goto bad_option;
-			if (i < 0 && ide_hwifs[1].chipset != ide_unknown)
-				goto bad_option;
+			if (i <= -5) {
+				if (ide_hwifs[1].chipset != ide_unknown)
+					goto bad_option;
+				/*
+				 * Interface keywords work only for ide0:
+				 */
+				if (hw != 0)
+					goto bad_hwif;
+			}
 		}
-		/*
-		 * Interface keywords work only for ide0:
-		 */
-		if (i <= -5 && hw != 0)
-			goto bad_hwif;
 
 		switch (i) {
 #ifdef CONFIG_BLK_DEV_PROMISE
@@ -3329,6 +3411,7 @@
 {
 	int index, i, rc = -1;
 	ide_hwif_t *hwif;
+	ide_drive_t *drive;
 	unsigned long flags;
 
 	save_flags(flags);
@@ -3346,8 +3429,14 @@
 			probe_hwif(hwif);
 			if (!hwif_init(index))
 				break;
-			for (i = 0; i < hwif->gd->nr_real; i++)
+			for (i = 0; i < hwif->gd->nr_real; i++) {
+				drive = &hwif->drives[i];
 				revalidate_disk(MKDEV(hwif->major, i<<PARTN_BITS));
+#ifdef CONFIG_BLK_DEV_IDECD
+				if (drive->present && drive->media == ide_cdrom)
+					ide_cdrom_setup(drive);
+#endif /* CONFIG_BLK_DEV_IDECD */
+			}
 			rc = index;
 			break;
 		}
diff -u --recursive --new-file v2.0.10/linux/drivers/block/ide.h linux/drivers/block/ide.h
--- v2.0.10/linux/drivers/block/ide.h	Thu Aug  1 15:53:34 1996
+++ linux/drivers/block/ide.h	Mon Aug  5 09:11:17 1996
@@ -41,6 +41,13 @@
 #define FANCY_STATUS_DUMPS	1	/* 0 to reduce kernel size */
 #endif
 
+#ifdef CONFIG_BLK_DEV_CMD640
+#if 1
+void cmd640_dump_regs (void);
+#define CMD640_DUMP_REGS cmd640_dump_regs() /* for debugging cmd640 chipset */
+#endif
+#endif  /* CONFIG_BLK_DEV_CMD640 */
+
 #if defined(CONFIG_BLK_DEV_IDECD) || defined(CONFIG_BLK_DEV_IDETAPE)
 #define CONFIG_BLK_DEV_IDEATAPI 1
 #endif
@@ -291,7 +298,7 @@
 		unsigned set_geometry	: 1;	/* respecify drive geometry */
 		unsigned recalibrate	: 1;	/* seek to cyl 0      */
 		unsigned set_multmode	: 1;	/* set multmode count */
-		unsigned set_pio	: 1;	/* set pio mode */
+		unsigned set_tune	: 1;	/* tune interface for drive */
 		unsigned reserved	: 4;	/* unused */
 		} b;
 	} special_t;
@@ -317,6 +324,8 @@
 	unsigned using_dma	: 1;	/* disk is using dma for read/write */
 	unsigned forced_geom	: 1;	/* 1 if hdx=c,h,s was given at boot */
 	unsigned unmask		: 1;	/* flag: okay to unmask other irqs */
+	unsigned no_unmask	: 1;	/* disallow setting unmask bit */
+	unsigned no_io_32bit	: 1;	/* disallow enabling 32bit I/O */
 	unsigned nobios		: 1;	/* flag: do not probe bios for drive */
 	unsigned autotune	: 2;	/* 1=autotune, 2=noautotune, 0=default */
 #if FAKE_FDISK_FOR_EZDRIVE
@@ -328,7 +337,7 @@
 	byte		ready_stat;	/* min status value for drive ready */
 	byte		mult_count;	/* current multiple sector setting */
 	byte 		mult_req;	/* requested multiple sector setting */
-	byte 		pio_req;	/* requested drive pio setting */
+	byte 		tune_req;	/* requested drive tuning setting */
 	byte		io_32bit;	/* 0=16-bit, 1=32-bit, 2/3=32bit+sync */
 	byte		bad_wstat;	/* used for ignoring WRERR_STAT */
 	byte		sect0;		/* offset of first sector for DM6:DDO */
@@ -422,7 +431,6 @@
 	unsigned	noprobe    : 1;	/* don't probe for this interface */
 	unsigned	present    : 1;	/* this interface exists */
 	unsigned	serialized : 1;	/* serialized operation with mate hwif */
-	unsigned	no_unmask  : 1;	/* disallow setting unmask bits */
 	unsigned	sharing_irq: 1;	/* 1 = sharing irq with another hwif */
 #ifdef CONFIG_BLK_DEV_PROMISE
 	unsigned	is_promise2: 1;	/* 2nd i/f on promise DC4030 */
@@ -461,11 +469,10 @@
  * should be using pointers to a drive (ide_drive_t *) or 
  * pointers to a hwif (ide_hwif_t *), rather than indexing this
  * structure directly (the allocation/layout may change!).
+ *
  */
-#ifdef _IDE_C
-	ide_hwif_t	ide_hwifs[MAX_HWIFS];	/* master data repository */
-#else
-extern	ide_hwif_t	ide_hwifs[];
+#ifndef _IDE_C
+extern	ide_hwif_t	ide_hwifs[];		/* master data repository */
 #endif
 
 /*
@@ -597,6 +604,14 @@
  * stat/err are used only when (HWGROUP(drive)->rq->cmd == IDE_DRIVE_CMD).
  */
 void ide_end_drive_cmd (ide_drive_t *drive, byte stat, byte err);
+
+/*
+ * ide_system_bus_speed() returns what we think is the system VESA/PCI
+ * bus speed (in Mhz).  This is used for calculating interface PIO timings.
+ * The default is 40 for known PCI systems, 50 otherwise.
+ * The "idebus=xx" parameter can be used to override this value.
+ */
+int ide_system_bus_speed (void);
 
 /*
  * ide_multwrite() transfers a block of up to mcount sectors of data
diff -u --recursive --new-file v2.0.10/linux/drivers/block/ide_modes.h linux/drivers/block/ide_modes.h
--- v2.0.10/linux/drivers/block/ide_modes.h	Sun May 12 21:21:04 1996
+++ linux/drivers/block/ide_modes.h	Mon Aug  5 08:12:25 1996
@@ -15,13 +15,43 @@
 
 #if defined(CONFIG_BLK_DEV_CMD640) || defined(CONFIG_IDE_CHIPSETS)
 
+/*
+ * Standard (generic) timings for PIO modes, from ATA2 specification.
+ * These timings are for access to the IDE data port register *only*.
+ * Some drives may specify a mode, while also specifying a different
+ * value for cycle_time (from drive identification data).
+ */
+typedef struct ide_pio_timings_s {
+	int	setup_time;	/* Address setup (ns) minimum */
+	int	active_time;	/* Active pulse (ns) minimum */
+	int	cycle_time;	/* Cycle time (ns) minimum = (setup + active + recovery) */
+} ide_pio_timings_t;
+
+typedef struct ide_pio_data_s {
+	byte pio_mode;
+	byte use_iordy;
+	byte overridden;
+	byte blacklisted;
+	unsigned int cycle_time;
+} ide_pio_data_t;
+	
 #ifndef _IDE_C
 
 int ide_scan_pio_blacklist (char *model);
-unsigned int ide_get_best_pio_mode (ide_drive_t *drive);
+byte ide_get_best_pio_mode (ide_drive_t *drive, byte mode_wanted, byte max_mode, ide_pio_data_t *d);
+extern const ide_pio_timings_t ide_pio_timings[6];
 
 #else /* _IDE_C */
 
+const ide_pio_timings_t ide_pio_timings[6] = {
+	{ 70,	165,	600 },	/* PIO Mode 0 */
+	{ 50,	125,	383 },	/* PIO Mode 1 */
+	{ 30,	100,	240 },	/* PIO Mode 2 */
+	{ 30,	80,	180 },	/* PIO Mode 3 with IORDY */
+	{ 25,	70,	120 },	/* PIO Mode 4 with IORDY */
+	{ 20,	50,	100 }	/* PIO Mode 5 with IORDY (nonstandard) */
+};
+
 /*
  * Black list. Some drives incorrectly report their maximal PIO mode,
  * at least in respect to CMD640. Here we keep info on some known drives.
@@ -31,6 +61,7 @@
 	int		pio;
 } ide_pio_blacklist [] = {
 /*	{ "Conner Peripherals 1275MB - CFS1275A", 4 }, */
+	{ "Conner Peripherals 540MB - CFS540A", 3 },
 
 	{ "WDC AC2700",  3 },
 	{ "WDC AC2540",  3 },
@@ -38,6 +69,7 @@
 	{ "WDC AC2340",  3 },
 	{ "WDC AC2250",  0 },
 	{ "WDC AC2200",  0 },
+	{ "WDC AC21200", 4 },
 	{ "WDC AC2120",  0 },
 	{ "WDC AC2850",  3 },
 	{ "WDC AC1270",  3 },
@@ -46,7 +78,6 @@
 	{ "WDC AC280",   0 },
 /*	{ "WDC AC21000", 4 }, */
 	{ "WDC AC31000", 3 },
-/*	{ "WDC AC21200", 4 }, */
 	{ "WDC AC31200", 3 },
 /*	{ "WDC AC31600", 4 }, */
 
@@ -112,31 +143,80 @@
 }
 
 /*
- * This routine returns the recommended PIO mode for a given drive,
+ * This routine returns the recommended PIO settings for a given drive,
  * based on the drive->id information and the ide_pio_blacklist[].
  * This is used by most chipset support modules when "auto-tuning".
  */
-unsigned int ide_get_best_pio_mode (ide_drive_t *drive)
-{
-	unsigned int pio = 0;
-	struct hd_driveid *id = drive->id;
 
-	if (id != NULL) {
-		if (HWIF(drive)->chipset != ide_cmd640 && !strcmp("QUANTUM FIREBALL1080A", id->model))
-			pio = 4;
-		else
-			pio = ide_scan_pio_blacklist(id->model);
-		if (pio == -1) {
-			pio = (id->tPIO < 2) ? id->tPIO : 2;
-			if (id->field_valid & 2) {
-				byte modes = id->eide_pio_modes;
-				if      (modes & 4)	pio = 5;
-				else if (modes & 2)	pio = 4;
-				else if (modes & 1)	pio = 3;
+/*
+ * Drive PIO mode auto selection
+ */
+byte ide_get_best_pio_mode (ide_drive_t *drive, byte mode_wanted, byte max_mode, ide_pio_data_t *d)
+{
+	int pio_mode;
+	int cycle_time = 0;
+	int use_iordy = 0;
+	struct hd_driveid* id = drive->id;
+	int overridden  = 0;
+	int blacklisted = 0;
+
+	if (mode_wanted != 255) {
+		pio_mode = mode_wanted;
+	} else if (!drive->id) {
+		pio_mode = 0;
+	} else if ((pio_mode = ide_scan_pio_blacklist(id->model)) != -1) {
+		overridden = 1;
+		blacklisted = 1;
+		use_iordy = (pio_mode > 2);
+	} else {
+		pio_mode = id->tPIO;
+		if (pio_mode > 2) {	/* 2 is maximum allowed tPIO value */
+			pio_mode = 2;
+			overridden = 1;
+		}
+		if (id->field_valid & 2) {	  /* drive implements ATA2? */
+			if (id->capability & 8) { /* drive supports use_iordy? */
+				use_iordy = 1;
+				cycle_time = id->eide_pio_iordy;
+				if (id->eide_pio_modes & 7) {
+					overridden = 0;
+					if (id->eide_pio_modes & 4)
+						pio_mode = 5;
+					else if (id->eide_pio_modes & 2)
+						pio_mode = 4;
+					else
+						pio_mode = 3;
+				}
+			} else {
+				cycle_time = id->eide_pio;
 			}
 		}
+
+		/*
+		 * Conservative "downgrade" for all pre-ATA2 drives
+		 */
+		if (pio_mode && pio_mode < 4) {
+			pio_mode--;
+			overridden = 1;
+#if 0
+			use_iordy = (pio_mode > 2);
+#endif
+			if (cycle_time && cycle_time < ide_pio_timings[pio_mode].cycle_time)
+				cycle_time = 0; /* use standard timing */
+		}
+	}
+	if (pio_mode > max_mode) {
+		pio_mode = max_mode;
+		cycle_time = 0;
+	}
+	if (d) {
+		d->pio_mode = pio_mode;
+		d->cycle_time = cycle_time ? cycle_time : ide_pio_timings[pio_mode].cycle_time;
+		d->use_iordy = use_iordy;
+		d->overridden = overridden;
+		d->blacklisted = blacklisted;
 	}
-	return pio;
+	return pio_mode;
 }
 
 #endif /* _IDE_C */
diff -u --recursive --new-file v2.0.10/linux/drivers/block/qd6580.c linux/drivers/block/qd6580.c
--- v2.0.10/linux/drivers/block/qd6580.c	Fri May  3 11:07:24 1996
+++ linux/drivers/block/qd6580.c	Mon Aug  5 08:12:25 1996
@@ -47,10 +47,7 @@
 {
 	unsigned long flags;
 
-	if (pio == 255)
-		pio = ide_get_best_pio_mode (drive);
-	if (pio > 3)
-		pio = 3;
+	pio = ide_get_best_pio_mode(drive, pio, 3, NULL);
 
 	save_flags(flags);
 	cli();
diff -u --recursive --new-file v2.0.10/linux/drivers/block/rz1000.c linux/drivers/block/rz1000.c
--- v2.0.10/linux/drivers/block/rz1000.c	Thu Mar 28 08:19:44 1996
+++ linux/drivers/block/rz1000.c	Mon Aug  5 08:12:25 1996
@@ -45,8 +45,10 @@
 		if ((rc = pcibios_read_config_word(bus, fn, 0x40, &reg))
 		 || (rc =  pcibios_write_config_word(bus, fn, 0x40, reg & 0xdfff)))
 		{
-			ide_hwifs[0].no_unmask = 1;
-			ide_hwifs[1].no_unmask = 1;
+			ide_hwifs[0].drives[0].no_unmask = 1;
+			ide_hwifs[0].drives[1].no_unmask = 1;
+			ide_hwifs[1].drives[0].no_unmask = 1;
+			ide_hwifs[1].drives[1].no_unmask = 1;
 			ide_hwifs[0].serialized = 1;
 			ide_hwifs[1].serialized = 1;
 			ide_pci_access_error (rc);
diff -u --recursive --new-file v2.0.10/linux/drivers/block/umc8672.c linux/drivers/block/umc8672.c
--- v2.0.10/linux/drivers/block/umc8672.c	Fri May 10 08:03:33 1996
+++ linux/drivers/block/umc8672.c	Mon Aug  5 08:26:00 1996
@@ -1,5 +1,5 @@
 /*
- *  linux/drivers/block/umc8672.c	Version 0.04  May 09, 1996
+ *  linux/drivers/block/umc8672.c	Version 0.05  Jul 31, 1996
  *
  *  Copyright (C) 1995-1996  Linus Torvalds & author (see below)
  */
@@ -16,6 +16,8 @@
  *
  *  Version 0.02	now configs/compiles separate from ide.c  -ml
  *  Version 0.03	enhanced auto-tune, fix display bug
+ *  Version 0.05	replace sti() with restore_flags()  -ml
+ *			add detection of possible race condition  -ml
  */
 
 /*
@@ -81,10 +83,7 @@
 static void umc_set_speeds (byte speeds[])
 {
 	int i, tmp;
-	unsigned long flags;
 
-	save_flags(flags);
-	cli ();
 	outb_p (0x5A,0x108); /* enable umc */
 
 	out_umc (0xd7,(speedtab[0][speeds[2]] | (speedtab[0][speeds[3]]<<4)));
@@ -101,7 +100,6 @@
 		out_umc (0xd8+i,speedtab[2][speeds[i]]);
 	}
 	outb_p (0xa5,0x108); /* disable umc */
-	restore_flags(flags);
 
 	printk ("umc8672: drive speeds [0 to 11]: %d %d %d %d\n",
 		speeds[0], speeds[1], speeds[2], speeds[3]);
@@ -109,36 +107,44 @@
 
 static void tune_umc (ide_drive_t *drive, byte pio)
 {
-	if (pio == 255)
-		pio = ide_get_best_pio_mode(drive);
-	if (pio > 4)
-		pio = 4;
+	unsigned long flags;
+	ide_hwgroup_t *hwgroup = ide_hwifs[HWIF(drive)->index^1].hwgroup;
 
-	current_speeds[drive->name[2] - 'a'] = pio_to_umc[pio];
-	umc_set_speeds (current_speeds);
+	pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+	printk("%s: setting umc8672 to PIO mode%d (speed %d)\n", drive->name, pio, pio_to_umc[pio]);
+	save_flags(flags);
+	cli();
+	if (hwgroup && hwgroup->handler != NULL) {
+		printk("umc8672: other interface is busy: exiting tune_umc()\n");
+	} else {
+		current_speeds[drive->name[2] - 'a'] = pio_to_umc[pio];
+		umc_set_speeds (current_speeds);
+	}
+	restore_flags(flags);
 }
 
 void init_umc8672 (void)	/* called from ide.c */
 {
 	unsigned long flags;
 
+	save_flags(flags);
+	cli ();
 	if (check_region(0x108, 2)) {
+		restore_flags(flags);
 		printk("\numc8672: PORTS 0x108-0x109 ALREADY IN USE\n");
 		return;
 	}
-	save_flags(flags);
-	cli ();
 	outb_p (0x5A,0x108); /* enable umc */
 	if (in_umc (0xd5) != 0xa0)
 	{
-		sti ();
+		restore_flags(flags);
 		printk ("umc8672: not found\n");
 		return;  
 	}
 	outb_p (0xa5,0x108); /* disable umc */
-	restore_flags(flags);
 
 	umc_set_speeds (current_speeds);
+	restore_flags(flags);
 
 	request_region(0x108, 2, "umc8672");
 	ide_hwifs[0].chipset = ide_umc8672;
diff -u --recursive --new-file v2.0.10/linux/drivers/char/Config.in linux/drivers/char/Config.in
--- v2.0.10/linux/drivers/char/Config.in	Sat Jun  8 11:21:15 1996
+++ linux/drivers/char/Config.in	Thu Aug  1 15:43:04 1996
@@ -66,6 +66,7 @@
   else
      tristate '   Software Watchdog' CONFIG_SOFT_WATCHDOG
   fi
+  tristate '   Berkshire Products PC Watchdog' CONFIG_PCWATCHDOG
 fi
 bool 'Enhanced Real Time Clock Support' CONFIG_RTC
 endmenu
diff -u --recursive --new-file v2.0.10/linux/drivers/char/Makefile linux/drivers/char/Makefile
--- v2.0.10/linux/drivers/char/Makefile	Thu May 16 16:35:39 1996
+++ linux/drivers/char/Makefile	Thu Aug  1 15:43:04 1996
@@ -40,6 +40,10 @@
 
 ifeq ($(CONFIG_DIGI),y)
 L_OBJS += pcxx.o
+else
+  ifeq ($(CONFIG_DIGI),m)
+  M_OBJS += pcxx.o
+  endif
 endif
 
 ifeq ($(CONFIG_CYCLADES),y)
@@ -189,6 +193,16 @@
   M_OBJS += scc.o
   endif
 endif  
+
+ifeq ($(CONFIG_PCWATCHDOG),y)
+M = y
+L_OBJS += pcwd.o
+else
+  ifeq ($(CONFIG_PCWATCHDOG),m)
+  M_OBJS += pcwd.o
+  MM = m
+  endif
+endif
 
 ifeq ($(CONFIG_BAYCOM),y)
 L_OBJS += baycom.o
diff -u --recursive --new-file v2.0.10/linux/drivers/char/cyclades.c linux/drivers/char/cyclades.c
--- v2.0.10/linux/drivers/char/cyclades.c	Wed Apr 24 07:33:36 1996
+++ linux/drivers/char/cyclades.c	Thu Aug  1 15:31:04 1996
@@ -1,5 +1,5 @@
 static char rcsid[] =
-"$Revision: 1.36.3.7 $$Date: 1996/04/19 21:06:18 $";
+"$Revision: 1.36.3.7A $$Date: 1996/07/27 10:25:50 $";
 /*
  *  linux/drivers/char/cyclades.c
  *
@@ -2250,6 +2250,13 @@
                         (unsigned long *) arg);
             break;
         case TIOCSSOFTCAR:
+            error = verify_area(VERIFY_READ, (void *) arg
+                                 ,sizeof(unsigned long *));
+            if (error) {
+                 ret_val = error;
+                 break;
+            }
+
             arg = get_fs_long((unsigned long *) arg);
             tty->termios->c_cflag =
                     ((tty->termios->c_cflag & ~CLOCAL) |
@@ -2275,6 +2282,12 @@
                                    (struct serial_struct *) arg);
             break;
         case TIOCSSERIAL:
+            error = verify_area(VERIFY_READ, (void *) arg
+                                ,sizeof(struct serial_struct));
+            if (error){
+                ret_val = error;
+                break;
+            }
             ret_val = set_serial_info(info,
                                    (struct serial_struct *) arg);
             break;
@@ -2646,6 +2659,8 @@
 	return retval;
     }
 
+    MOD_INC_USE_COUNT;
+
     retval = block_til_ready(tty, filp, info);
     if (retval) {
 #ifdef SERIAL_DEBUG_OPEN
@@ -2661,7 +2676,6 @@
 #ifdef SERIAL_DEBUG_OPEN
     printk("cy_open done\n");/**/
 #endif
-    MOD_INC_USE_COUNT;
     return 0;
 } /* cy_open */
 
diff -u --recursive --new-file v2.0.10/linux/drivers/char/mem.c linux/drivers/char/mem.c
--- v2.0.10/linux/drivers/char/mem.c	Thu Jul 25 16:52:13 1996
+++ linux/drivers/char/mem.c	Thu Aug  1 15:43:04 1996
@@ -401,6 +401,9 @@
 #if CONFIG_QIC02_TAPE
 	qic02_tape_init();
 #endif
+#ifdef CONFIG_PCWATCHDOG
+	pcwatchdog_init();
+#endif
 #if CONFIG_ISDN
 	isdn_init();
 #endif
diff -u --recursive --new-file v2.0.10/linux/drivers/char/pcwd.c linux/drivers/char/pcwd.c
--- v2.0.10/linux/drivers/char/pcwd.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/char/pcwd.c	Thu Aug  1 16:12:26 1996
@@ -0,0 +1,331 @@
+/*
+ * PC Watchdog Driver
+ * by Ken Hollis (khollis@bitgate.com)
+ *
+ * Permission granted from Simon Machell (73244.1270@compuserve.com)
+ * Written for the Linux Kernel, and GPLed by Ken Hollis
+ *
+ * 960107	Added request_region routines, modulized the whole thing.
+ * 960108	Fixed end-of-file pointer (Thanks to Dan Hollis), added
+ *		WD_TIMEOUT define.
+ * 960216	Added eof marker on the file, and changed verbose messages.
+ * 960716	Made functional and cosmetic changes to the source for
+ *		inclusion in Linux 2.0.x kernels, thanks to Alan Cox.
+ * 960717	Removed read/seek routines, replaced with ioctl.  Also, added
+ *		check_region command due to Alan's suggestion.
+ */
+
+#include <linux/module.h>
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/tty.h>
+#include <linux/timer.h>
+#include <linux/kernel.h>
+#include <linux/wait.h>
+#include <linux/string.h>
+#include <linux/malloc.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/miscdevice.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/pcwd.h>
+
+#include <asm/io.h>
+
+#define WD_VER                  "0.41 (07/17/96)"
+#define	WD_MINOR		130	/* Minor device number */
+
+#define	WD_TIMEOUT		3	/* 1 1/2 seconds for a timeout */
+
+#define WD_TIMERRESET_PORT1     0x270	/* Reset port - first choice */
+#define WD_TIMERRESET_PORT2     0x370	/* Reset port - second choice */
+#define WD_CTLSTAT_PORT1        0x271	/* Control port - first choice */
+#define WD_CTLSTAT_PORT2        0x371	/* Control port - second choice */
+#define	WD_PORT_EXTENT		2	/* Takes up two addresses */
+
+#define WD_WDRST                0x01	/* Previously reset state */
+#define WD_T110                 0x02	/* Temperature overheat sense */
+#define WD_HRTBT                0x04	/* Heartbeat sense */
+#define WD_RLY2                 0x08	/* External relay triggered */
+#define WD_SRLY2                0x80	/* Software external relay triggered */
+
+static int current_ctlport, current_readport;
+static int is_open, is_eof;
+
+int pcwd_checkcard(void)
+{
+	int card_dat, prev_card_dat, found = 0, count = 0, done = 0;
+
+	/* As suggested by Alan Cox */
+	if (check_region(current_ctlport, WD_PORT_EXTENT)) {
+		printk("pcwd: Port 0x%x unavailable.\n", current_ctlport);
+		return 0;
+	}
+
+	card_dat = 0x00;
+	prev_card_dat = 0x00;
+
+	prev_card_dat = inb(current_readport);
+
+	while(count < WD_TIMEOUT) {
+#ifdef	DEBUG
+		printk("pcwd: Run #%d on port 0x%03x\n", count, current_readport);
+#endif
+
+	/* Read the raw card data from the port, and strip off the
+	   first 4 bits */
+
+		card_dat = inb_p(current_readport);
+		card_dat &= 0x000F;
+
+	/* Sleep 1/2 second (or 500000 microseconds :) */
+
+		udelay(500000L);
+		done = 0;
+
+	/* 0x0F usually means that no card data is present, or the card
+	   is not installed on this port.  If 0x0F is present here, it's
+	   normally safe to assume there's no card at that base address. */
+
+		if (card_dat == 0x0F) {
+			count++;
+			done = 1;
+
+#ifdef	DEBUG
+			printk("pcwd: I show nothing on this port.\n");
+#endif
+		}
+
+	/* If there's a heart beat in both instances, then this means we
+	   found our card.  This also means that either the card was
+	   previously reset, or the computer was power-cycled. */
+
+		if ((card_dat & WD_HRTBT) && (prev_card_dat & WD_HRTBT) &&
+			(!done)) {
+			found = 1;
+			done = 1;
+#ifdef	DEBUG
+			printk("pcwd: I show alternate heart beats.  Card detected.\n");
+#endif
+			break;
+		}
+
+	/* If the card data is exactly the same as the previous card data,
+	   it's safe to assume that we should check again.  The manual says
+	   that the heart beat will change every second (or the bit will
+	   toggle), and this can be used to see if the card is there.  If
+	   the card was powered up with a cold boot, then the card will
+	   not start blinking until 2.5 minutes after a reboot, so this
+	   bit will stay at 1. */
+
+		if ((card_dat == prev_card_dat) && (!done)) {
+			count++;
+#ifdef	DEBUG
+			printk("pcwd: The card data is exactly the same (possibility).\n");
+#endif
+			done = 1;
+		}
+
+	/* If the card data is toggling any bits, this means that the heart
+	   beat was detected, or something else about the card is set. */
+
+		if ((card_dat != prev_card_dat) && (!done)) {
+			done = 1;
+			found = 1;
+#ifdef	DEBUG
+			printk("pcwd: I show alternate heart beats.  Card detected.\n");
+#endif
+			break;
+		}
+
+	/* Otherwise something else strange happened. */
+
+		if (!done)
+			count++;
+	}
+
+	return((found) ? 1 : 0);
+}
+
+void pcwd_showprevstate(void)
+{
+	int card_status = 0x0000;
+
+	card_status = inb(current_readport);
+
+	if (card_status & WD_WDRST)
+		printk("pcwd: Previous reboot was caused by the card.\n");
+
+	if (card_status & WD_T110)
+		printk("pcwd: CPU overheat sense\n");
+}
+
+static int pcwd_return_data(void)
+{
+	return(inb(current_readport));
+}
+
+static int pcwd_write(struct inode *inode, struct file *file, const char *data,
+	int len)
+{
+	int wdrst_stat;
+
+	if (!is_open)
+		return -EIO;
+
+#ifdef	DEBUG
+	printk("pcwd: write request\n");
+#endif
+
+	wdrst_stat = inb_p(current_readport);
+	wdrst_stat &= 0x0F;
+
+	wdrst_stat |= WD_WDRST;
+
+	outb_p(wdrst_stat, current_ctlport);
+
+	return(1);
+}
+
+static int pcwd_ioctl(struct tty_struct *tty, struct file *file,
+	unsigned int cmd, unsigned long arg)
+{
+	int i, cdat, rv;
+
+	switch(cmd) {
+	default:
+		return -ENOIOCTLCMD;
+
+	case PCWD_GETSTAT:
+		i = verify_area(VERIFY_WRITE, (void*) arg, sizeof(int));
+		if (i)
+			return i;
+		else {
+			cdat = pcwd_return_data();
+			rv = 0;
+
+			if (cdat & WD_WDRST)
+				rv |= 0x01;
+
+			if (cdat & WD_T110)
+				rv |= 0x02;
+
+			put_user(rv, (int *) arg);
+			return 0;
+		}
+		break;
+
+	case PCWD_PING:
+		pcwd_write(NULL, NULL, NULL, 1);	/* Is this legal? */
+		break;
+	}
+
+	return 0;
+}
+
+static int pcwd_open(struct inode *ino, struct file *filep)
+{
+#ifdef	DEBUG
+	printk("pcwd: open request\n");
+#endif
+
+	MOD_INC_USE_COUNT;
+	is_eof = 0;
+	return(0);
+}
+
+static void pcwd_close(struct inode *ino, struct file *filep)
+{
+#ifdef	DEBUG
+	printk("pcwd: close request\n");
+#endif
+
+	MOD_DEC_USE_COUNT;
+}
+
+struct file_operations pcwd_fops = {
+	NULL,		/* Seek */
+	NULL,		/* Read */
+	pcwd_write,	/* Write */
+	NULL,		/* Readdir */
+	NULL,		/* Select */
+	pcwd_ioctl,	/* IOctl */
+	NULL,		/* MMAP */
+	pcwd_open,	/* Open */
+	pcwd_close,	/* Close */
+	NULL
+};
+
+static struct miscdevice pcwd_miscdev = {
+	WD_MINOR,
+	"pcwatchdog",
+	&pcwd_fops
+};
+ 
+#ifdef	MODULE
+int init_module(void)
+#else
+int pcwatchdog_init(void)
+#endif
+{
+#ifdef	DEBUG
+	printk("pcwd: Success.\n");
+#endif
+	printk("pcwd: v%s Ken Hollis (khollis@bitgate.com)\n", WD_VER);
+
+#ifdef	DEBUG
+	printk("pcwd: About to perform card autosense loop.\n");
+#endif
+
+	is_eof = 0;
+	is_open = 0;
+
+	current_ctlport = WD_TIMERRESET_PORT1;
+	current_readport = WD_CTLSTAT_PORT1;
+
+	if (!pcwd_checkcard()) {
+#ifdef	DEBUG
+		printk("pcwd: Trying port 0x370.\n");
+#endif
+
+		current_ctlport = WD_TIMERRESET_PORT2;
+		current_readport = WD_CTLSTAT_PORT2;
+
+		if (!pcwd_checkcard()) {
+			printk("pcwd: No card detected.\n");
+			return(-EIO);
+		} else
+			printk("pcwd: Port available at 0x370.\n");
+	} else
+		printk("pcwd: Port available at 0x270.\n");
+
+	pcwd_showprevstate();
+
+#ifdef	DEBUG
+	printk("pcwd: Requesting region entry\n");
+#endif
+
+	request_region(current_ctlport, WD_PORT_EXTENT, "PCWD (Berkshire)");
+
+#ifdef	DEBUG
+	printk("pcwd: character device creation.\n");
+#endif
+
+	misc_register(&pcwd_miscdev);
+
+	return 0;
+}
+
+#ifdef	MODULE
+void cleanup_module(void)
+{
+	misc_deregister(&pcwd_miscdev);
+	release_region(current_ctlport, 2);
+#ifdef	DEBUG
+	printk("pcwd: Cleanup successful.\n");
+#endif
+}
+#endif
diff -u --recursive --new-file v2.0.10/linux/drivers/char/pcxx.c linux/drivers/char/pcxx.c
--- v2.0.10/linux/drivers/char/pcxx.c	Sun May 19 15:24:50 1996
+++ linux/drivers/char/pcxx.c	Thu Aug  1 15:40:32 1996
@@ -30,8 +30,13 @@
  *              variable handling, instead of using the old pcxxconfig.h
  *  1.5.6 April 16, 1996 Christoph Lameter: Pointer cleanup, macro cleanup.
  *		Call out devices changed to /dev/cudxx.
+ *  1.5.7 July 22, 1996 Martin Mares: CLOCAL fix, pcxe_table clearing.
+ *		David Nugent: Bug in pcxe_open.
+ *		Brian J. Murrell: Modem Control fixes, Majors correctly assigned
  *
  */
+#undef MODULE
+/* Module code is broken right now. Don't enable this unless you want to fix it */
 
 #undef SPEED_HACK
 /* If you define SPEED_HACK then you get the following Baudrate translation
@@ -41,6 +46,7 @@
    some distributions like Slackware 3.0 don't like these high baudrates.
 */
 
+#include <linux/module.h>
 #include <linux/mm.h>
 #include <linux/ioport.h>
 #include <linux/errno.h>
@@ -59,18 +65,24 @@
 #include <linux/tty_driver.h>
 #include <linux/malloc.h>
 #include <linux/string.h>
+
+#ifndef MODULE
+
+/* is* routines not available in modules
+** the need for this should go away when probing is done.  :-)
+** brian@ilinx.com
+*/
+
 #include <linux/ctype.h>
+#endif
 
 #include <asm/system.h>
 #include <asm/io.h>
 #include <asm/segment.h>
 #include <asm/bitops.h>
 
-#define VERSION 	"1.5.6"
-static char *banner = "Digiboard PC/X{i,e,eve} driver v1.5.6.  Christoph Lameter <clameter@fuller.edu>.";
-
-/*#define	DEFAULT_HW_FLOW	1 */
-/*#define	DEBUG_IOCTL */
+#define VERSION 	"1.5.7"
+static char *banner = "Digiboard PC/X{i,e,eve} driver v1.5.7";
 
 #include "digi.h"
 #include "fep.h"
@@ -145,6 +157,62 @@
 
 #define TZ_BUFSZ 4096
 
+/* function definitions */
+#ifdef MODULE
+int		init_module(void);
+void		cleanup_module(void);
+
+/*
+ *	Loadable module initialization stuff.
+ */
+
+int init_module()
+{
+
+	return pcxe_init();
+
+}
+
+/*****************************************************************************/
+
+void cleanup_module()
+{
+
+	unsigned long	flags;
+	int crd, i;
+	int e1, e2;
+	struct board_info *bd;
+	struct channel *ch;
+
+	printk(KERN_INFO "Unloading PC/Xx: version %s\n", VERSION);
+
+	save_flags(flags);
+	cli();
+	timer_active &= ~(1 << DIGI_TIMER);
+	timer_table[DIGI_TIMER].fn = NULL;
+	timer_table[DIGI_TIMER].expires = 0;
+
+	if ((e1 = tty_unregister_driver(&pcxe_driver)))
+		printk("SERIAL: failed to unregister serial driver (%d)\n", e1);
+	if ((e2 = tty_unregister_driver(&pcxe_callout)))
+		printk("SERIAL: failed to unregister callout driver (%d)\n",e2);
+
+	for(crd=0; crd < numcards; crd++) {
+		bd = &boards[crd];
+		ch = digi_channels+bd->first_minor;
+		for(i=0; i < bd->numports; i++, ch++) {
+			kfree(ch->tmp_buf);
+		}
+		release_region(bd->port, 4);
+	}
+	kfree(digi_channels);
+	kfree(pcxe_termios_locked);
+	kfree(pcxe_termios);
+	kfree(pcxe_table);
+	restore_flags(flags);
+}
+#endif
+
 static inline struct channel *chan(register struct tty_struct *tty)
 {
 	if (tty) {
@@ -289,7 +357,6 @@
 }	
 
 
-/* static  ???why static??? */
 int pcxe_open(struct tty_struct *tty, struct file * filp)
 {
 	volatile struct board_chan *bc;
@@ -309,7 +376,7 @@
 
 	for(boardnum=0;boardnum<numcards;boardnum++)
 		if ((line >= boards[boardnum].first_minor) && 
-			(line <= boards[boardnum].first_minor + boards[boardnum].numports))
+			(line < boards[boardnum].first_minor + boards[boardnum].numports))
 		break;
 
 	if(boardnum >= numcards || boards[boardnum].status == DISABLED ||
@@ -325,6 +392,8 @@
 		return(-ENODEV);
 	}
 
+	/* flag the kernel that there is somebody using this guy */
+	MOD_INC_USE_COUNT;
 	/*
 	 * If the device is in the middle of being closed, then block
 	 * until it's done, and then try again.
@@ -393,6 +462,13 @@
 				return -EBUSY;
 		}
 		else {
+			/* this has to be set in order for the "block until
+			 * CD" code to work correctly.  i'm not sure under
+			 * what circumstances asyncflags should be set to
+			 * ASYNC_NORMAL_ACTIVE though
+			 * brian@ilinx.com
+			 */
+			ch->asyncflags |= ASYNC_NORMAL_ACTIVE;
 			if ((retval = pcxx_waitcarrier(tty, filp, ch)) != 0)
 				return retval;
 		}
@@ -460,11 +536,26 @@
 		cli();
 
 		if(tty_hung_up_p(filp)) {
+			/* flag that somebody is done with this module */
+			MOD_DEC_USE_COUNT;
 			restore_flags(flags);
 			return;
 		}
+		/* this check is in serial.c, it won't hurt to do it here too */
+		if ((tty->count == 1) && (info->count != 1)) {
+			/*
+			 * Uh, oh.  tty->count is 1, which means that the tty
+			 * structure will be freed.  Info->count should always
+			 * be one in these conditions.  If it's greater than
+			 * one, we've got real problems, since it means the
+			 * serial port won't be shutdown.
+			 */
+			printk("pcxe_close: bad serial port count; tty->count is 1, info->count is %d\n", info->count);
+			info->count = 1;
+		}
 		if (info->count-- > 1) {
 			restore_flags(flags);
+			MOD_DEC_USE_COUNT;
 			return;
 		}
 		if (info->count < 0) {
@@ -495,6 +586,13 @@
 		tty->closing = 0;
 		info->event = 0;
 		info->tty = NULL;
+#ifndef MODULE
+/* ldiscs[] is not available in a MODULE
+** worth noting that while I'm not sure what this hunk of code is supposed
+** to do, it is not present in the serial.c driver.  Hmmm.  If you know,
+** please send me a note.  brian@ilinx.com
+** Dont know either what this is supposed to do clameter@waterf.org.
+*/
 		if(tty->ldisc.num != ldiscs[N_TTY].num) {
 			if(tty->ldisc.close)
 				(tty->ldisc.close)(tty);
@@ -503,6 +601,7 @@
 			if(tty->ldisc.open)
 				(tty->ldisc.open)(tty);
 		}
+#endif
 		if(info->blocked_open) {
 			if(info->close_delay) {
 				current->state = TASK_INTERRUPTIBLE;
@@ -514,6 +613,7 @@
 		info->asyncflags &= ~(ASYNC_NORMAL_ACTIVE|
 							  ASYNC_CALLOUT_ACTIVE|ASYNC_CLOSING);
 		wake_up_interruptible(&info->close_wait);
+		MOD_DEC_USE_COUNT;
 		restore_flags(flags);
 	}
 }
@@ -562,9 +662,12 @@
 		cli();
 		globalwinon(ch);
 		head = bc->tin & (size - 1);
-		tail = bc->tout;
-		if (tail != bc->tout)
-			tail = bc->tout;
+		/* It seems to be necessary to make sure that the value is stable here somehow
+		   This is a rather odd pice of code here. */
+		do
+		{ tail = bc->tout;
+		} while (tail != bc->tout);
+		
 		tail &= (size - 1);
 		stlen = (head >= tail) ? (size - (head - tail) - 1) : (tail - head - 1);
 		count = MIN(stlen, count);
@@ -882,6 +985,11 @@
 
 			case 4:
 				t2 = str;
+#ifndef MODULE
+/* is* routines not available in modules
+** the need for this should go away when probing is done.  :-)
+** brian@ilinx.com
+*/
 				while (isdigit(*t2))
 					t2++;
 
@@ -890,12 +998,18 @@
 					printk("PC/Xx: Invalid port count %s\n", str);
 					return;
 				}
+#endif
 
 				board.numports = simple_strtoul(str, NULL, 0);
 				last = i;
 				break;
 
 			case 5:
+#ifndef MODULE
+/* is* routines not available in modules
+** the need for this should go away when probing is done.  :-)
+** brian@ilinx.com
+*/
 				t2 = str;
 				while (isxdigit(*t2))
 					t2++;
@@ -905,12 +1019,18 @@
 					printk("PC/Xx: Invalid port count %s\n", str);
 					return;
 				}
+#endif
 
 				board.port = simple_strtoul(str, NULL, 16);
 				last = i;
 				break;
 
 			case 6:
+#ifndef MODULE
+/* is* routines not available in modules
+** the need for this should go away when probing is done.  :-)
+** brian@ilinx.com
+*/
 				t2 = str;
 				while (isxdigit(*t2))
 					t2++;
@@ -920,6 +1040,7 @@
 					printk("PC/Xx: Invalid memory base %s\n", str);
 					return;
 				}
+#endif
 
 				board.membase = simple_strtoul(str, NULL, 16);
 				last = i;
@@ -958,10 +1079,6 @@
 
 int pcxe_init(void)
 {
-#if 0
-	ulong save_loops_per_sec;
-#endif
-
 	ulong flags, memory_seg=0, memory_size;
 	int lowwater, i, crd, shrinkmem=0, topwin = 0xff00L, botwin=0x100L;
 	unchar *fepos, *memaddr, *bios, v;
@@ -998,6 +1115,7 @@
 	pcxe_table =  kmalloc(sizeof(struct tty_struct *) * nbdevs, GFP_KERNEL);
 	if (!pcxe_table)
 		panic("Unable to allocate pcxe_table struct");
+	memset(pcxe_table, 0, sizeof(struct tty_struct *) * nbdevs);
 
 	pcxe_termios = kmalloc(sizeof(struct termios *) * nbdevs, GFP_KERNEL);
 	if (!pcxe_termios)
@@ -1007,7 +1125,6 @@
 	if (!pcxe_termios_locked)
 		panic("Unable to allocate pcxe_termios_locked struct");
 
-
 	init_bh(DIGI_BH,do_pcxe_bh);
 	enable_bh(DIGI_BH);
 
@@ -1016,7 +1133,7 @@
 
 	memset(&pcxe_driver, 0, sizeof(struct tty_driver));
 	pcxe_driver.magic = TTY_DRIVER_MAGIC;
-	pcxe_driver.name = "cud";
+	pcxe_driver.name = "ttyD";
 	pcxe_driver.major = DIGI_MAJOR; 
 	pcxe_driver.minor_start = 0;
 
@@ -1025,7 +1142,7 @@
 	pcxe_driver.type = TTY_DRIVER_TYPE_SERIAL;
 	pcxe_driver.subtype = SERIAL_TYPE_NORMAL;
 	pcxe_driver.init_termios = tty_std_termios;
-	pcxe_driver.init_termios.c_cflag = B9600 | CS8 | CREAD | CLOCAL | HUPCL;
+	pcxe_driver.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL;
 	pcxe_driver.flags = TTY_DRIVER_REAL_RAW;
 	pcxe_driver.refcount = &pcxe_refcount;
 
@@ -1050,22 +1167,10 @@
 	pcxe_driver.hangup = pcxe_hangup;
 
 	pcxe_callout = pcxe_driver;
-	pcxe_callout.name = "ttyD";
+	pcxe_callout.name = "cud";
 	pcxe_callout.major = DIGICU_MAJOR;
 	pcxe_callout.subtype = SERIAL_TYPE_CALLOUT;
-	pcxe_callout.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL;
-
-#if 0 
-
-/* strangely enough, this is FALSE */
-
-	/* 
-	 * loops_per_sec hasn't been set at this point :-(, so fake it out... 
-	 * I set it so that I can use the __delay() function.
-	 */
-	save_loops_per_sec = loops_per_sec;
-	loops_per_sec = 13L*500000L;
-#endif
+	pcxe_callout.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
 
 	save_flags(flags);
 	cli();
@@ -1346,6 +1451,10 @@
 			ch->normal_termios = pcxe_driver.init_termios;
 			ch->open_wait = 0;
 			ch->close_wait = 0;
+			/* zero out flags as it is unassigned at this point
+			 * brian@ilinx.com
+			 */
+			ch->asyncflags = 0;
 		}
 
 		printk("PC/Xx: %s (%s) I/O=0x%x Mem=0x%lx Ports=%d\n", 
@@ -1610,7 +1719,7 @@
 		if (cflag & B115200) res|=1;
 	}
 	else ch->digiext.digi_flags &= ~DIGI_FAST;
-	res |= cflag & (CBAUD | PARODD | PARENB | CSTOPB | CSIZE);
+	res |= cflag & (CBAUD | PARODD | PARENB | CSTOPB | CSIZE | CLOCAL);
 	return res;
 }
 
diff -u --recursive --new-file v2.0.10/linux/drivers/isdn/pcbit/edss1.c linux/drivers/isdn/pcbit/edss1.c
--- v2.0.10/linux/drivers/isdn/pcbit/edss1.c	Sat Jun 29 20:36:22 1996
+++ linux/drivers/isdn/pcbit/edss1.c	Thu Aug  1 15:43:04 1996
@@ -297,6 +297,7 @@
 		
 		printk(KERN_DEBUG "fsm error: event %x on state %x\n", 
                        event, chan->fsm_state);
+		restore_flags(flags);
 		return;
 	}
 
diff -u --recursive --new-file v2.0.10/linux/drivers/net/3c505.c linux/drivers/net/3c505.c
--- v2.0.10/linux/drivers/net/3c505.c	Wed Apr 17 07:20:07 1996
+++ linux/drivers/net/3c505.c	Thu Aug  1 15:43:04 1996
@@ -491,7 +491,6 @@
 			return TRUE;
 			break;
 		case ASF_PCB_NAK:
-			cli();
 			printk("%s: send_pcb got NAK\n", dev->name);
 			goto abort;
 			break;
diff -u --recursive --new-file v2.0.10/linux/drivers/net/3c509.c linux/drivers/net/3c509.c
--- v2.0.10/linux/drivers/net/3c509.c	Wed May 15 09:09:00 1996
+++ linux/drivers/net/3c509.c	Sun Aug  4 13:52:21 1996
@@ -430,7 +430,7 @@
 	/* Transmitter timeout, serious problems. */
 	if (dev->tbusy) {
 		int tickssofar = jiffies - dev->trans_start;
-		if (tickssofar < 40)
+		if (tickssofar < 40*HZ/100)
 			return 1;
 		printk("%s: transmit timed out, Tx_status %2.2x status %4.4x "
 			   "Tx FIFO room %d.\n",
diff -u --recursive --new-file v2.0.10/linux/drivers/scsi/aha1542.c linux/drivers/scsi/aha1542.c
--- v2.0.10/linux/drivers/scsi/aha1542.c	Mon May  6 12:26:10 1996
+++ linux/drivers/scsi/aha1542.c	Thu Aug  1 15:43:04 1996
@@ -1002,6 +1002,7 @@
 		    cli();
 		    if (request_irq(irq_level,aha1542_intr_handle, 0, "aha1542", NULL)) {
 			    printk("Unable to allocate IRQ for adaptec controller.\n");
+			    restore_flags(flags);
 			    goto unregister;
 		    }
 		    
@@ -1009,6 +1010,7 @@
 			    if (request_dma(dma_chan,"aha1542")) {
 				    printk("Unable to allocate DMA channel for Adaptec.\n");
 				    free_irq(irq_level, NULL);
+				    restore_flags(flags);
 				    goto unregister;
 			    }
 			    
diff -u --recursive --new-file v2.0.10/linux/drivers/scsi/eata_dma.c linux/drivers/scsi/eata_dma.c
--- v2.0.10/linux/drivers/scsi/eata_dma.c	Wed May  8 07:20:02 1996
+++ linux/drivers/scsi/eata_dma.c	Thu Aug  1 15:43:04 1996
@@ -19,6 +19,7 @@
  *       versions of the boards                             *
  *	-supports multiple HBAs with & without IRQ sharing  *
  *	-supports all SCSI channels on multi channel boards *
+ *      -supports ix86 and MIPS, untested on ALPHA          *
  *	-needs identical IDs on all channels of a HBA	    * 
  *	-can be loaded as module			    *
  *	-displays statistical and hardware information	    *
@@ -57,7 +58,7 @@
  * Jagdis who did a lot of testing and found quite a number *
  * of bugs during the development.                          *
  ************************************************************
- *  last change: 95/05/05                 OS: Linux 1.3.98  *
+ *  last change: 96/07/20                  OS: Linux 2.0.8  *
  ************************************************************/
 
 /* Look in eata_dma.h for configuration and revision information */
@@ -77,6 +78,10 @@
 #include <asm/types.h>
 #include <asm/io.h>
 #include <asm/dma.h>
+#include <asm/pgtable.h>
+#ifdef __mips__
+#include <asm/cachectl.h>
+#endif
 #include <linux/blk.h>
 #include "scsi.h"
 #include "sd.h"
@@ -244,13 +249,9 @@
     struct eata_ccb *ccb;
     struct eata_sp *sp;
     uint base;
-    ulong flags;
     uint x;
     struct Scsi_Host *sh;
 
-    save_flags(flags);
-    cli();
-
     for (x = 1, sh = first_HBA; x <= registered_HBAs; x++, sh = SD(sh)->next) {
 	if (sh->irq != irq)
 	    continue;
@@ -260,6 +261,9 @@
 	    int_counter++;
 	    
 	    sp = &SD(sh)->sp;
+#ifdef __mips__
+            sys_cacheflush(sp, sizeof(struct eata_sp), 2);
+#endif
 	    ccb = sp->ccb;
 	    
 	    if(ccb == NULL) {
@@ -288,16 +292,17 @@
 		break;
 	    } 
 	    
-	    if (ccb->status == LOCKED) {
-		ccb->status = FREE;
-		eata_stat = inb(base + HA_RSTATUS);
-		printk("eata_dma: int_handler, freeing locked queueslot\n");
-		DBG(DBG_INTR && DBG_DELAY, DELAY(1));
-		break;
+           sp->EOC = FALSE; /* Clean out this flag */
+
+           if (ccb->status == LOCKED || ccb->status == RESET) {
+               ccb->status = FREE;
+               eata_stat = inb(base + HA_RSTATUS);
+               printk("eata_dma: int_handler, reseted command returned,"
+                      " freeing reseted queueslot\n");
+	       DBG(DBG_INTR && DBG_DELAY, DELAY(1));
+	       break;
 	    }
 	    
-	    sp->EOC = FALSE; /* Clean out this flag */
-
 	    eata_stat = inb(base + HA_RSTATUS); 
 	    DBG(DBG_INTR, printk("IRQ %d received, base %#.4x, pid %ld, "
 				 "target: %x, lun: %x, ea_s: %#.2x, hba_s: "
@@ -306,11 +311,9 @@
 	    
 	    switch (hba_stat) {
 	    case HA_NO_ERROR:	/* NO Error */
-	        HD(cmd)->t_state[ccb->cp_channel][ccb->cp_id] = OK;
 		if(HD(cmd)->do_latency == TRUE && ccb->timestamp) 
 		    eata_latency_in(ccb, HD(cmd));
 		result = DID_OK << 16;
-		HD(cmd)->t_timeout[ccb->cp_channel][ccb->cp_id] = OK;
 		break;
 	    case HA_ERR_SEL_TO:	        /* Selection Timeout */
 	    case HA_ERR_CMD_TO:	        /* Command Timeout   */
@@ -329,7 +332,6 @@
 		    result = DID_ERROR << 16;
 		
 		for (i = 0; i < MAXTARGET; i++)
-		    HD(cmd)->t_state[ccb->cp_channel][i] = RESET;
 		DBG(DBG_STATUS, printk(KERN_DEBUG "scsi%d: cmd pid %ld "
 				       "returned with INIT_POWERUP\n", 
 				       HD(cmd)->HBA_number, cmd->pid));
@@ -342,7 +344,6 @@
  		break;
 	    case HA_CP_RESET_NA:
 	    case HA_CP_RESET:
-	        HD(cmd)->t_state[cmd->channel][cmd->target] = OK; 
 	        HD(cmd)->resetlevel[cmd->channel] = 0; 
 		result = DID_RESET << 16;
 		DBG(DBG_STATUS, printk(KERN_WARNING "scsi%d: reseted cmd "
@@ -385,8 +386,7 @@
 	    cmd->scsi_done(cmd);
 	}
     }
-    restore_flags(flags);
-    
+
     return;
 }
 
@@ -398,17 +398,26 @@
 	if (--loop == 0)
 	    return(FALSE);
 
+    if(addr != (u32) NULL)
+        addr = virt_to_bus((void *)addr);
+
+    /*
+     * This is overkill.....but the MIPSen seem to need this
+     * and it will be optimized away for i86 and ALPHA machines.
+     */
+    flush_cache_all();
+
     /* And now the address in nice little byte chunks */
 #ifdef __LITTLE_ENDIAN
-    outb( addr & 0x000000ff,	    base + HA_WDMAADDR);
-    outb((addr & 0x0000ff00) >> 8,  base + HA_WDMAADDR + 1);
-    outb((addr & 0x00ff0000) >> 16, base + HA_WDMAADDR + 2);
-    outb((addr & 0xff000000) >> 24, base + HA_WDMAADDR + 3);
+    outb(addr,       base + HA_WDMAADDR);
+    outb(addr >> 8,  base + HA_WDMAADDR + 1);
+    outb(addr >> 16, base + HA_WDMAADDR + 2);
+    outb(addr >> 24, base + HA_WDMAADDR + 3);
 #else
-    outb((addr & 0xff000000) >> 24, base + HA_WDMAADDR);
-    outb((addr & 0x00ff0000) >> 16, base + HA_WDMAADDR + 1);
-    outb((addr & 0x0000ff00) >> 8,  base + HA_WDMAADDR + 2);
-    outb((addr & 0x000000ff),       base + HA_WDMAADDR + 3);
+    outb(addr >> 24, base + HA_WDMAADDR);
+    outb(addr >> 16, base + HA_WDMAADDR + 1);
+    outb(addr >> 8,  base + HA_WDMAADDR + 2);
+    outb(addr,       base + HA_WDMAADDR + 3);
 #endif
     outb(command, base + HA_WCOMMAND);
     return(TRUE);
@@ -416,18 +425,27 @@
 
 inline int eata_send_immediate(u32 base, u32 addr, u8 ifc, u8 code, u8 code2)
 {
+    if(addr != (u32) NULL)
+        addr = virt_to_bus((void *)addr);
+
+    /*
+     * This is overkill.....but the MIPSen seem to need this
+     * and it will be optimized away for i86 and ALPHA machines.
+     */
+    flush_cache_all();
+
     outb(0x0, base + HA_WDMAADDR - 1);
     if(addr){
 #ifdef __LITTLE_ENDIAN
-        outb( addr & 0x000000ff,        base + HA_WDMAADDR);
-	outb((addr & 0x0000ff00) >> 8,  base + HA_WDMAADDR + 1);
-	outb((addr & 0x00ff0000) >> 16, base + HA_WDMAADDR + 2);
-	outb((addr & 0xff000000) >> 24, base + HA_WDMAADDR + 3);
+        outb(addr,       base + HA_WDMAADDR);
+	outb(addr >> 8,  base + HA_WDMAADDR + 1);
+	outb(addr >> 16, base + HA_WDMAADDR + 2);
+	outb(addr >> 24, base + HA_WDMAADDR + 3);
 #else
-	outb((addr & 0xff000000) >> 24, base + HA_WDMAADDR);
-	outb((addr & 0x00ff0000) >> 16, base + HA_WDMAADDR + 1);
-	outb((addr & 0x0000ff00) >> 8,  base + HA_WDMAADDR + 2);
-	outb((addr & 0x000000ff),       base + HA_WDMAADDR + 3);
+        outb(addr >> 24, base + HA_WDMAADDR);
+	outb(addr >> 16, base + HA_WDMAADDR + 1);
+	outb(addr >> 8,  base + HA_WDMAADDR + 2);
+	outb(addr,       base + HA_WDMAADDR + 3);
 #endif
     } else {
         outb(0x0, base + HA_WDMAADDR);
@@ -491,6 +509,8 @@
     memset(ccb, 0, sizeof(struct eata_ccb) - sizeof(struct eata_sg_list *));
     
     ccb->status = USED;			/* claim free slot */
+
+    restore_flags(flags);
     
     DBG(DBG_QUEUE, printk("eata_queue pid %ld, target: %x, lun: %x, y %d\n",
 			  cmd->pid, cmd->target, cmd->lun, y));
@@ -562,7 +582,7 @@
     ccb->cp_statDMA = htonl(virt_to_bus(&(hd->sp)));
     
     ccb->cp_viraddr = ccb; /* This will be passed thru, so we don't need to 
-                          * convert it */
+			    * convert it */
     ccb->cmd = cmd;
     cmd->host_scribble = (char *)&hd->ccb[y];	
     
@@ -571,25 +591,26 @@
 	DBG(DBG_QUEUE && DBG_ABNORM, 
 	    printk("eata_queue target %d, pid %ld, HBA busy, "
 		   "returning DID_BUS_BUSY\n",cmd->target, cmd->pid));
-	done(cmd);
 	ccb->status = FREE;    
-	restore_flags(flags);
+	done(cmd);
 	return(0);
     }
     DBG(DBG_QUEUE, printk("Queued base %#.4x pid: %ld target: %x lun: %x "
 			 "slot %d irq %d\n", (s32)sh->base, cmd->pid, 
 			 cmd->target, cmd->lun, y, sh->irq));
     DBG(DBG_QUEUE && DBG_DELAY, DELAY(1));
-    restore_flags(flags);
+
     return(0);
 }
 
 
 int eata_abort(Scsi_Cmnd * cmd)
 {
-    ulong loop = R_LIMIT;
+    ulong loop = HZ / 2;
     ulong flags;
-
+    int x;
+    struct Scsi_Host *sh;
+ 
     save_flags(flags);
     cli();
 
@@ -598,6 +619,15 @@
 			   cmd->abort_reason));
     DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));
 
+    /* Some interrupt controllers seem to loose interrupts */
+    for (x = 1, sh = first_HBA; x <= registered_HBAs; x++, sh = SD(sh)->next) {
+        if(inb((uint)sh->base + HA_RAUXSTAT) & HA_AIRQ) {
+            printk("eata_dma: scsi%d interrupt pending in eata_abort.\n"
+		   "          Calling interrupt handler.\n", sh->host_no);
+	    eata_int_handler(sh->irq, 0, 0);
+	}
+    }
+
     while (inb((u32)(cmd->host->base) + HA_RAUXSTAT) & HA_ABUSY) {
 	if (--loop == 0) {
 	    printk("eata_dma: abort, timeout error.\n");
@@ -634,12 +664,12 @@
 
 int eata_reset(Scsi_Cmnd * cmd, unsigned int resetflags)
 {
-    ushort x, z; 
-    ulong limit = 0;
+    uint x; 
     ulong loop = loops_per_sec / 3;
     ulong flags;
     unchar success = FALSE;
     Scsi_Cmnd *sp; 
+    struct Scsi_Host *sh;
     
     save_flags(flags);
     cli();
@@ -648,6 +678,14 @@
 			   " reason %x\n", cmd->pid, cmd->target, cmd->lun, 
 			   cmd->abort_reason));
 	
+    /* Some interrupt controllers seem to loose interrupts */
+    for (x = 1, sh = first_HBA; x <= registered_HBAs; x++, sh = SD(sh)->next) {
+        if(inb((uint)sh->base + HA_RAUXSTAT) & HA_AIRQ) {
+            printk("eata_dma: scsi%d interrupt pending in eata_reset.\n"
+		   "          Calling interrupt handler.\n", sh->host_no);
+            eata_int_handler(sh->irq, 0, 0);
+      }
+    }
     if (HD(cmd)->state == RESET) {
 	printk("eata_reset: exit, already in reset.\n");
 	restore_flags(flags);
@@ -663,30 +701,26 @@
 	    return (SCSI_RESET_ERROR);
 	}
  
-    for (x = 0; x < MAXCHANNEL; x++) {
-	for (z = 0; z < MAXTARGET; z++) {
-	    HD(cmd)->t_state[x][z] = RESET;
-	    HD(cmd)->t_timeout[x][z] = NO_TIMEOUT;
-	}
-    }
-
     for (x = 0; x < cmd->host->can_queue; x++) {
 	if (HD(cmd)->ccb[x].status == FREE)
 	    continue;
-	
+
 	if (HD(cmd)->ccb[x].status == LOCKED) {
 	    HD(cmd)->ccb[x].status = FREE;
 	    printk("eata_reset: locked slot %d forced free.\n", x);
 	    DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));
 	    continue;
 	}
+
+
 	sp = HD(cmd)->ccb[x].cmd;
 	HD(cmd)->ccb[x].status = RESET;
-	printk("eata_reset: slot %d in reset, pid %ld.\n", x, sp->pid);
-	DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));
 	
 	if (sp == NULL)
 	    panic("eata_reset: slot %d, sp==NULL.\n", x);
+
+	printk("eata_reset: slot %d in reset, pid %ld.\n", x, sp->pid);
+
 	DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));
 	
 	if (sp == cmd)
@@ -697,18 +731,21 @@
     inb((u32) (cmd->host->base) + HA_RSTATUS);	/* This might cause trouble */
     eata_send_command(0, (u32) cmd->host->base, EATA_CMD_RESET);
     
-    DBG(DBG_ABNORM, printk("eata_reset: board reset done, enabling interrupts.\n"));
     HD(cmd)->state = RESET;
 
-    DELAY(1); 
+    DBG(DBG_ABNORM, printk("eata_reset: board reset done, enabling "
+			   "interrupts.\n"));
+
+    DELAY(2); /* In theorie we should get interrupts and set free all
+	       * used queueslots */
     
-    DBG(DBG_ABNORM, printk("eata_reset: interrupts disabled, loops %ld.\n", 
-			   limit));
+    DBG(DBG_ABNORM, printk("eata_reset: interrupts disabled again.\n"));
     DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));
     
     for (x = 0; x < cmd->host->can_queue; x++) {
 	
-	/* Skip slots already set free by interrupt */
+	/* Skip slots already set free by interrupt and those that 
+         * are still LOCKED from the last reset */
 	if (HD(cmd)->ccb[x].status != RESET)
 	    continue;
 	
@@ -750,8 +787,13 @@
     Scsi_Device *device;
     int devcount = 0; 
     int factor = 0;
-    
-    
+
+#if CRIPPLE_QUEUE    
+    for(device = devicelist; device != NULL; device = device->next) {
+        if(device->host == host)
+	    device->queue_depth = 2;
+    }
+#else
     /* First we do a sample run go find out what we have */
     for(device = devicelist; device != NULL; device = device->next) {
         if (device->host == host) {
@@ -818,8 +860,10 @@
 		   device->queue_depth);
 	}
     }
+#endif
 }
 
+#if CHECK_BLINK
 int check_blink_state(long base)
 {
     ushort loops = 10;
@@ -841,6 +885,7 @@
     else
 	return (FALSE);
 }
+#endif
 
 char * get_board_data(u32 base, u32 irq, u32 id)
 {
@@ -848,7 +893,6 @@
     struct eata_sp  *sp;
     static char *buff;
     ulong i;
-    ulong limit = 0;
 
     cp = (struct eata_ccb *) scsi_init_malloc(sizeof(struct eata_ccb),
 					      GFP_ATOMIC | GFP_DMA);
@@ -1287,11 +1331,14 @@
 			register_HBA(base, buf, tpnt, IS_EISA);
 		    } else
 			printk("eata_dma: No valid IRQ. HBA removed from list\n");
-		} else {
+		}
+#if CHECK_BLINK
+		else {
 		    if (check_blink_state(base)) 
 			printk("HBA is in BLINK state. Consult your HBAs "
 			       "Manual to correct this.\n");
 		} 
+#endif
 		/* Nothing found here so we take it from the list */
 		EISAbases[i] = 0;  
 #if CHECKPAL
@@ -1311,11 +1358,14 @@
 	    if (get_conf_PIO(ISAbases[i],buf) == TRUE){
 		DBG(DBG_ISA, printk("Registering ISA HBA\n"));
 		register_HBA(ISAbases[i], buf, tpnt, IS_ISA);
-	    } else {
+	    } 
+#if CHECK_BLINK
+	    else {
 		if (check_blink_state(ISAbases[i])) 
 		    printk("HBA is in BLINK state. Consult your HBAs "
 			   "Manual to correct this.\n");
 	    }
+#endif
 	    ISAbases[i] = 0;
 	}
     }
@@ -1356,7 +1406,8 @@
 					       (u16 *) & com_adr))) {
 			if (!((com_adr & PCI_COMMAND_IO) && 
 			      (com_adr & PCI_COMMAND_MASTER))) {
-			    printk("eata_dma: find_PCI, HBA has IO or BUSMASTER mode disabled\n");
+			    printk("eata_dma: find_PCI, HBA has IO or"
+				   " BUSMASTER mode disabled\n");
 			    continue;
 			}
 		    } else
@@ -1366,7 +1417,8 @@
 		    printk("eata_dma: find_PCI, DEVICECLASSID %x didn't match\n", 
 			   rev_device);
 	    } else {
-		printk("eata_dma: find_PCI, error %x while reading PCI_CLASS_BASE\n", 
+		printk("eata_dma: find_PCI, error %x while reading "
+		       "PCI_CLASS_BASE\n", 
 		       error);
 		continue;
 	    }
@@ -1411,10 +1463,13 @@
 			    } else if ((base & 0x0fff) == 0x0c88) 
 				EISAbases[(base >> 12) & 0x0f] = 0;
 			    continue;  /* break; */
-			} else if (check_blink_state(base) == TRUE) {
+			} 
+#if CHECK_BLINK
+			else if (check_blink_state(base) == TRUE) {
 			    printk("eata_dma: HBA is in BLINK state.\n"
 				   "Consult your HBAs manual to correct this.\n");
 			}
+#endif
 		    }
 		}
 	    } else {
@@ -1461,7 +1516,7 @@
     for (i = 0; i <= MAXIRQ; i++) { /* Now that we know what we have, we     */
 	if (reg_IRQ[i] >= 1){       /* exchange the interrupt handler which  */
 	    free_irq(i, NULL);      /* we used for probing with the real one */
-	    request_irq(i, (void *)(eata_int_handler), SA_INTERRUPT, 
+	    request_irq(i, (void *)(eata_int_handler), SA_INTERRUPT|SA_SHIRQ, 
 			"eata_dma", NULL);
 	}
     }
diff -u --recursive --new-file v2.0.10/linux/drivers/scsi/eata_dma.h linux/drivers/scsi/eata_dma.h
--- v2.0.10/linux/drivers/scsi/eata_dma.h	Mon May  6 07:34:20 1996
+++ linux/drivers/scsi/eata_dma.h	Thu Aug  1 15:43:04 1996
@@ -4,7 +4,7 @@
 *             mike@i-Connect.Net                        *
 *             neuffer@mail.uni-mainz.de                 *
 *********************************************************
-* last change: 96/05/05                                 *
+* last change: 96/06/26                                 *
 ********************************************************/
 
 #ifndef _EATA_DMA_H
@@ -17,7 +17,7 @@
 
 #define VER_MAJOR 2
 #define VER_MINOR 5
-#define VER_SUB   "8d"
+#define VER_SUB   "8g"
 
 
 /************************************************************************
@@ -25,7 +25,12 @@
  ************************************************************************/
 
 #define CHECKPAL        0        /* EISA pal checking on/off            */
-#define NEWSTUFF        0        /* Some changes for ISA/EISA boards    */
+#define CHECK_BLINK     1        /* Switch Blink state check off, might *
+                                  * be nessessary for some MIPS machines*/ 
+#define CRIPPLE_QUEUE   0        /* Only enable this if the interrupt 
+                                  * controller on your motherboard is 
+                                  * broken and you are experiencing 
+                                  * massive interrupt losses */
 
 /************************************************************************
  * Debug options.                                                       * 
diff -u --recursive --new-file v2.0.10/linux/drivers/scsi/eata_dma_proc.c linux/drivers/scsi/eata_dma_proc.c
--- v2.0.10/linux/drivers/scsi/eata_dma_proc.c	Fri Apr 12 09:49:41 1996
+++ linux/drivers/scsi/eata_dma_proc.c	Thu Aug  1 15:43:04 1996
@@ -295,63 +295,66 @@
 	}
 	if (pos > offset + length)
 	    goto stop_output; 
-	
-	cmnd[0] = LOG_SENSE;
-	cmnd[1] = 0;
-	cmnd[2] = 0x32 + (3<<6); 
-	cmnd[3] = 0;
-	cmnd[4] = 0;
-	cmnd[5] = 0;
-	cmnd[6] = 0;
-	cmnd[7] = 0x01;
-	cmnd[8] = 0x44;
-	cmnd[9] = 0;
- 
-	scmd.cmd_len = 10;
-
-	/*
-	 * Do the command and wait for it to finish.
-	 */	
-	{
-	    struct semaphore sem = MUTEX_LOCKED;
-	    scmd.request.rq_status = RQ_SCSI_BUSY;
-	    scmd.request.sem = &sem;
-	    scsi_do_cmd (&scmd, cmnd, buff2, 0x144,
-			 eata_scsi_done, 1 * HZ, 1);
-	    down(&sem);
-	}
 
-	swap_statistics(buff2);
-	rhcs = (hst_cmd_stat *)(buff2 + 0x2c); 
-	whcs = (hst_cmd_stat *)(buff2 + 0x8c);		 
-	
-	for (x = 0; x <= 11; x++) {
-	    SD(HBA_ptr)->reads[x] += rhcs->sizes[x];
-	    SD(HBA_ptr)->writes[x] += whcs->sizes[x];
-	    SD(HBA_ptr)->reads[12] += rhcs->sizes[x];
-	    SD(HBA_ptr)->writes[12] += whcs->sizes[x];
-	}
-	size = sprintf(buffer + len, "Host<->Disk command statistics:\n"
-		       "         Reads:	     Writes:\n");
-	len += size; 
-	pos = begin + len;
-	for (x = 0; x <= 10; x++) {
-	    size = sprintf(buffer+len,"%5dk:%12u %12u\n", 1 << x,
-			   SD(HBA_ptr)->reads[x], 
-			   SD(HBA_ptr)->writes[x]);
+	if(SD(HBA_ptr)->do_latency == FALSE) { 
+
+	    cmnd[0] = LOG_SENSE;
+	    cmnd[1] = 0;
+	    cmnd[2] = 0x32 + (3<<6); 
+	    cmnd[3] = 0;
+	    cmnd[4] = 0;
+	    cmnd[5] = 0;
+	    cmnd[6] = 0;
+	    cmnd[7] = 0x01;
+	    cmnd[8] = 0x44;
+	    cmnd[9] = 0;
+	    
+	    scmd.cmd_len = 10;
+
+	    /*
+	     * Do the command and wait for it to finish.
+	     */	
+	    {
+	        struct semaphore sem = MUTEX_LOCKED;
+		scmd.request.rq_status = RQ_SCSI_BUSY;
+		scmd.request.sem = &sem;
+		scsi_do_cmd (&scmd, cmnd, buff2, 0x144,
+			     eata_scsi_done, 1 * HZ, 1);
+		down(&sem);
+	    }
+
+	    swap_statistics(buff2);
+	    rhcs = (hst_cmd_stat *)(buff2 + 0x2c); 
+	    whcs = (hst_cmd_stat *)(buff2 + 0x8c);		 
+	    
+	    for (x = 0; x <= 11; x++) {
+	        SD(HBA_ptr)->reads[x] += rhcs->sizes[x];
+		SD(HBA_ptr)->writes[x] += whcs->sizes[x];
+		SD(HBA_ptr)->reads[12] += rhcs->sizes[x];
+		SD(HBA_ptr)->writes[12] += whcs->sizes[x];
+	    }
+	    size = sprintf(buffer + len, "Host<->Disk command statistics:\n"
+			   "         Reads:	     Writes:\n");
+	    len += size; 
+	    pos = begin + len;
+	    for (x = 0; x <= 10; x++) {
+	        size = sprintf(buffer+len,"%5dk:%12u %12u\n", 1 << x,
+			       SD(HBA_ptr)->reads[x], 
+			       SD(HBA_ptr)->writes[x]);
+		len += size; 
+		pos = begin + len;
+	    }
+	    size = sprintf(buffer+len,">1024k:%12u %12u\n",
+			   SD(HBA_ptr)->reads[11], 
+			   SD(HBA_ptr)->writes[11]);
+	    len += size; 
+	    pos = begin + len;
+	    size = sprintf(buffer+len,"Sum   :%12u %12u\n",
+			   SD(HBA_ptr)->reads[12], 
+			   SD(HBA_ptr)->writes[12]);
 	    len += size; 
 	    pos = begin + len;
 	}
-	size = sprintf(buffer+len,">1024k:%12u %12u\n",
-		       SD(HBA_ptr)->reads[11], 
-		       SD(HBA_ptr)->writes[11]);
-	len += size; 
-	pos = begin + len;
-	size = sprintf(buffer+len,"Sum   :%12u %12u\n",
-		       SD(HBA_ptr)->reads[12], 
-		       SD(HBA_ptr)->writes[12]);
-	len += size; 
-	pos = begin + len;
     }
     
     if (pos < offset) {
@@ -362,9 +365,11 @@
 	goto stop_output;
 
     if(SD(HBA_ptr)->do_latency == TRUE) {
+        int factor = 1024/HZ;
 	size = sprintf(buffer + len, "Host Latency Command Statistics:\n"
-		       "Current timer resolution: 10ms\n"
-		       "         Reads:	      Min:(ms)     Max:(ms)     Ave:(ms)\n");
+		       "Current timer resolution: %2dms\n"
+		       "         Reads:	      Min:(ms)     Max:(ms)     Ave:(ms)\n",
+		       factor);
 	len += size; 
 	pos = begin + len;
 	for (x = 0; x <= 10; x++) {
@@ -372,9 +377,9 @@
 			   1 << x,
 			   SD(HBA_ptr)->reads_lat[x][0], 
 			   (SD(HBA_ptr)->reads_lat[x][1] == 0xffffffff) 
-			   ? 0:(SD(HBA_ptr)->reads_lat[x][1] * 10), 
-			   SD(HBA_ptr)->reads_lat[x][2] * 10, 
-			   SD(HBA_ptr)->reads_lat[x][3] * 10 /
+			   ? 0:(SD(HBA_ptr)->reads_lat[x][1] * factor), 
+			   SD(HBA_ptr)->reads_lat[x][2] * factor, 
+			   SD(HBA_ptr)->reads_lat[x][3] * factor /
 			   ((SD(HBA_ptr)->reads_lat[x][0])
 			    ? SD(HBA_ptr)->reads_lat[x][0]:1));
 	    len += size; 
@@ -383,9 +388,9 @@
 	size = sprintf(buffer+len,">1024k:%12u %12u %12u %12u\n",
 			   SD(HBA_ptr)->reads_lat[11][0], 
 			   (SD(HBA_ptr)->reads_lat[11][1] == 0xffffffff)
-			   ? 0:(SD(HBA_ptr)->reads_lat[11][1] * 10), 
-			   SD(HBA_ptr)->reads_lat[11][2] * 10, 
-			   SD(HBA_ptr)->reads_lat[11][3] * 10 /
+			   ? 0:(SD(HBA_ptr)->reads_lat[11][1] * factor), 
+			   SD(HBA_ptr)->reads_lat[11][2] * factor, 
+			   SD(HBA_ptr)->reads_lat[11][3] * factor /
 			   ((SD(HBA_ptr)->reads_lat[x][0])
 			    ? SD(HBA_ptr)->reads_lat[x][0]:1));
 	len += size; 
@@ -407,9 +412,9 @@
 			   1 << x,
 			   SD(HBA_ptr)->writes_lat[x][0], 
 			   (SD(HBA_ptr)->writes_lat[x][1] == 0xffffffff)
-			   ? 0:(SD(HBA_ptr)->writes_lat[x][1] * 10), 
-			   SD(HBA_ptr)->writes_lat[x][2] * 10, 
-			   SD(HBA_ptr)->writes_lat[x][3] * 10 /
+			   ? 0:(SD(HBA_ptr)->writes_lat[x][1] * factor), 
+			   SD(HBA_ptr)->writes_lat[x][2] * factor, 
+			   SD(HBA_ptr)->writes_lat[x][3] * factor /
 			   ((SD(HBA_ptr)->writes_lat[x][0])
 			    ? SD(HBA_ptr)->writes_lat[x][0]:1));
 	    len += size; 
@@ -418,9 +423,9 @@
 	size = sprintf(buffer+len,">1024k:%12u %12u %12u %12u\n",
 			   SD(HBA_ptr)->writes_lat[11][0], 
 			   (SD(HBA_ptr)->writes_lat[11][1] == 0xffffffff)
-			   ? 0:(SD(HBA_ptr)->writes_lat[x][1] * 10), 
-			   SD(HBA_ptr)->writes_lat[11][2] * 10, 
-			   SD(HBA_ptr)->writes_lat[11][3] * 10/
+			   ? 0:(SD(HBA_ptr)->writes_lat[x][1] * factor), 
+			   SD(HBA_ptr)->writes_lat[11][2] * factor, 
+			   SD(HBA_ptr)->writes_lat[11][3] * factor /
 			   ((SD(HBA_ptr)->writes_lat[x][0])
 			    ? SD(HBA_ptr)->writes_lat[x][0]:1));
 	len += size; 
diff -u --recursive --new-file v2.0.10/linux/drivers/scsi/eata_generic.h linux/drivers/scsi/eata_generic.h
--- v2.0.10/linux/drivers/scsi/eata_generic.h	Mon May  6 07:34:20 1996
+++ linux/drivers/scsi/eata_generic.h	Thu Aug  1 15:43:04 1996
@@ -5,7 +5,7 @@
 *             mike@i-Connect.Net                        *
 *             neuffer@mail.uni-mainz.de                 *
 *********************************************************
-* last change: 95/05/05                                 *
+* last change: 96/05/16                                 *
 ********************************************************/
 
 
@@ -90,10 +90,10 @@
 #define CD(cmd)	 ((struct eata_ccb *)(cmd->host_scribble))
 #define SD(host) ((hostdata *)&(host->hostdata))
 
-#define DELAY(x) { __u32 i; ulong flags;          \
+#define DELAY(x) { ulong flags, i;                \
                    save_flags(flags); sti();      \
                    i = jiffies + (x * HZ);        \
-                   while (jiffies < i) barrier(); \
+                   while (jiffies < i);           \
                    restore_flags(flags); }
 
 /***********************************************
@@ -130,6 +130,11 @@
 #define EATA_COLD_BOOT_HBA       0x06	   /* Only as a last resort	*/
 #define EATA_FORCE_IO            0x07
 
+#define HA_CTRLREG     0x206       /* control register for HBA    */
+#define HA_CTRL_DISINT 0x02        /* CTRLREG: disable interrupts */
+#define HA_CTRL_RESCPU 0x04        /* CTRLREG: reset processor    */
+#define HA_CTRL_8HEADS 0x08        /* CTRLREG: set for drives with* 
+				    * >=8 heads (WD1003 rudimentary :-) */
 
 #define HA_WCOMMAND    0x07	   /* command register offset	*/
 #define HA_WIFC        0x06	   /* immediate command offset  */
@@ -350,10 +355,6 @@
     __u32  reads_lat[12][4];
     __u32  writes_lat[12][4];
     __u32  all_lat[4];
-				 /* state of Target (RESET,..) */
-    __u8   t_state[MAXCHANNEL][MAXTARGET];   
-				 /* timeouts on target	       */
-    __u32  t_timeout[MAXCHANNEL][MAXTARGET]; 
     __u8   resetlevel[MAXCHANNEL]; 
     __u32  last_ccb;		 /* Last used ccb	       */
     __u32  cplen;		 /* size of CP in words	       */
diff -u --recursive --new-file v2.0.10/linux/drivers/scsi/eata_pio.c linux/drivers/scsi/eata_pio.c
--- v2.0.10/linux/drivers/scsi/eata_pio.c	Mon May  6 07:34:20 1996
+++ linux/drivers/scsi/eata_pio.c	Thu Aug  1 15:43:04 1996
@@ -32,7 +32,7 @@
  *  Cambridge, MA 02139, USA.                               *
  *                                                          *
  ************************************************************
- *  last change: 95/03/28                 OS: Linux 1.3.80  *
+ *  last change: 96/07/16                  OS: Linux 2.0.8  *
  ************************************************************/
 
 /* Look in eata_pio.h for configuration information */
@@ -79,21 +79,6 @@
 static ulong int_counter = 0;
 static ulong queue_counter = 0;
 
-void hprint(const char *str)
-{
-    char *hptr =(char *) 0x000b0000;
-    char *hptr2=(char *) 0x000b00a0; 
-    char *hptr3=(char *) 0x000b0f00;
-    int z;
-    
-    memmove(hptr,hptr2,24*80*2);
-    for (z=0; z<strlen(str); z++)
-	hptr3[z*2]=str[z];
-    for (; z<80; z++)
-	hptr3[z*2]=' ';
-}
-
-
 #include "eata_pio_proc.c"
  
 #ifdef MODULE
@@ -268,11 +253,17 @@
 
 inline uint eata_pio_send_command(uint base, unchar command)
 {
-    uint loop = R_LIMIT;
+    uint loop = HZ/2;
     
     while (inb(base + HA_RSTATUS) & HA_SBUSY)
 	if (--loop == 0)
 	    return(TRUE);
+
+    /* Enable interrupts for HBA.  It is not the best way to do it at this
+     * place, but I hope that it doesn't interfere with the IDE driver 
+     * initialization this way */
+
+    outb(HA_CTRL_8HEADS,base+HA_CTRLREG);
     
     outb(command, base + HA_WCOMMAND);
     return(FALSE);
@@ -405,7 +396,7 @@
 int eata_pio_abort(Scsi_Cmnd * cmd)
 {
     ulong flags;
-    uint loop = R_LIMIT;
+    uint loop = HZ;
     
     save_flags(flags);
     cli();
@@ -452,14 +443,13 @@
 
 int eata_pio_reset(Scsi_Cmnd * cmd, unsigned int dummy)
 {
-    uint x, z, time, limit = 0;
+    uint x, time, limit = 0;
     ulong flags;
     unchar success = FALSE;
     Scsi_Cmnd *sp; 
     
     save_flags(flags);
     cli();
-    hprint("reset");
     DBG(DBG_ABNORM, printk(KERN_WARNING "eata_pio_reset called pid:%ld target:"
                            " %x lun: %x reason %x\n", cmd->pid, cmd->target, 
                            cmd->lun, cmd->abort_reason));
@@ -471,11 +461,6 @@
 	return (SCSI_RESET_ERROR);
     }
     
-    for (z = 0; z < MAXTARGET; z++) {
-	HD(cmd)->t_state[0][z] = RESET;
-	HD(cmd)->t_timeout[0][z] = NO_TIMEOUT;
-    }
-    
     /* force all slots to be free */
     
     for (x = 0; x < cmd->host->can_queue; x++) {
@@ -495,7 +480,7 @@
     }
     
     /* hard reset the HBA  */
-    outb((uint) cmd->host->base+HA_WCOMMAND, EATA_CMD_RESET);
+    outb(EATA_CMD_RESET, (uint) cmd->host->base+HA_WCOMMAND);
     
     DBG(DBG_ABNORM, printk(KERN_WARNING "eata_pio_reset: board reset done.\n"));
     HD(cmd)->state = RESET;
@@ -586,7 +571,7 @@
 
 int get_pio_conf_PIO(u32 base, struct get_conf *buf)
 {
-    ulong loop = R_LIMIT;
+    ulong loop = HZ/2;
     int z;
     ushort *p;
     
@@ -603,14 +588,14 @@
 	printk(KERN_DEBUG "Issuing PIO READ CONFIG to HBA at %#x\n", base));
     eata_pio_send_command(base, EATA_CMD_PIO_READ_CONFIG);
 
-    loop = R_LIMIT;
+    loop = HZ/2;
     for (p = (ushort *) buf; 
 	 (long)p <= ((long)buf + (sizeof(struct get_conf) / 2)); p++) {
 	while (!(inb(base + HA_RSTATUS) & HA_SDRQ))
 	    if (--loop == 0)
 		return (FALSE);
 
-	loop = R_LIMIT;
+	loop = HZ/2;
 	*p = inw(base + HA_RDATA);
     }
     if (!(inb(base + HA_RSTATUS) & HA_SERROR)) {            /* Error ? */
diff -u --recursive --new-file v2.0.10/linux/drivers/scsi/eata_pio.h linux/drivers/scsi/eata_pio.h
--- v2.0.10/linux/drivers/scsi/eata_pio.h	Mon May  6 07:34:20 1996
+++ linux/drivers/scsi/eata_pio.h	Thu Aug  1 15:43:04 1996
@@ -2,7 +2,7 @@
 * Header file for eata_pio.c Linux EATA-PIO SCSI driver *
 * (c) 1993-96 Michael Neuffer  	                        *
 *********************************************************
-* last change: 95/06/21					*
+* last change: 96/05/05					*
 ********************************************************/
 
 
diff -u --recursive --new-file v2.0.10/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c
--- v2.0.10/linux/drivers/scsi/scsi.c	Tue Jul 23 10:26:49 1996
+++ linux/drivers/scsi/scsi.c	Thu Aug  1 15:43:04 1996
@@ -167,19 +167,6 @@
 #endif
 
 /*
- *  As the scsi do command functions are intelligent, and may need to
- *  redo a command, we need to keep track of the last command
- *  executed on each one.
- */
-
-#define WAS_RESET       0x01
-#define WAS_TIMEDOUT    0x02
-#define WAS_SENSE       0x04
-#define IS_RESETTING    0x08
-#define IS_ABORTING     0x10
-#define ASKED_FOR_SENSE 0x20
-
-/*
  *  This is the number  of clock ticks we should wait before we time out
  *  and abort the command.  This is for  where the scsi.c module generates
  *  the command, not where it originates from a higher level, in which
@@ -878,8 +865,7 @@
 	SCpnt->internal_timeout |= IN_RESET2;
         scsi_reset (SCpnt,
 		    SCSI_RESET_ASYNCHRONOUS | SCSI_RESET_SUGGEST_BUS_RESET);
-	return;
-	
+        return;
     case (IN_ABORT | IN_RESET | IN_RESET2):
 	/* Obviously the bus reset didn't work.
 	 * Let's try even harder and call for an HBA reset.
@@ -1204,6 +1190,15 @@
 #ifdef DEBUG_DELAY
     unsigned long clock;
 #endif
+
+#if DEBUG
+    unsigned long *ret = 0;
+#ifdef __mips__
+    __asm__ __volatile__ ("move\t%0,$31":"=r"(ret));
+#else
+   ret =  __builtin_return_address(0);
+#endif
+#endif
     
     host = SCpnt->host;
     
@@ -1393,9 +1388,9 @@
     SCpnt->serial_number = 0;
     SCpnt->bufflen = bufflen;
     SCpnt->buffer = buffer;
-    SCpnt->flags=0;
-    SCpnt->retries=0;
-    SCpnt->allowed=retries;
+    SCpnt->flags = 0;
+    SCpnt->retries = 0;
+    SCpnt->allowed = retries;
     SCpnt->done = done;
     SCpnt->timeout_per_command = timeout;
 
@@ -1413,7 +1408,7 @@
 
     /* Start the timer ticking.  */
 
-    SCpnt->internal_timeout = 0;
+    SCpnt->internal_timeout = NORMAL_TIMEOUT;
     SCpnt->abort_reason = 0;
     internal_cmnd (SCpnt);
 
@@ -1580,7 +1575,8 @@
 		if (SCpnt->flags & WAS_SENSE)
 		{
 #ifdef DEBUG
-		    printk ("In scsi_done, GOOD status, COMMAND COMPLETE, parsing sense information.\n");
+		    printk ("In scsi_done, GOOD status, COMMAND COMPLETE, "
+                            "parsing sense information.\n");
 #endif
 		    SCpnt->flags &= ~WAS_SENSE;
 #if 0	/* This cannot possibly be correct. */
@@ -1628,7 +1624,8 @@
 		else
 		{
 #ifdef DEBUG
-		    printk("COMMAND COMPLETE message returned, status = FINISHED. \n");
+		    printk("COMMAND COMPLETE message returned, "
+                           "status = FINISHED. \n");
 #endif
 		    exit =  DRIVER_OK;
 		    status = FINISHED;
@@ -2402,8 +2399,15 @@
 {
     unsigned int page, sector, nbits, mask;
     unsigned long flags;
-    
+
 #ifdef DEBUG
+    unsigned long ret = 0;
+
+#ifdef __mips__
+    __asm__ __volatile__ ("move\t%0,$31":"=r"(ret));
+#else
+   ret = __builtin_return_address(0);
+#endif
     printk("scsi_free %p %d\n",obj, len);
 #endif
     
@@ -2422,9 +2426,14 @@
 
             save_flags(flags);
             cli();
-            if((dma_malloc_freelist[page] & (mask << sector)) != (mask<<sector))
+            if((dma_malloc_freelist[page] & 
+                (mask << sector)) != (mask<<sector)){
+#ifdef DEBUG
+		printk("scsi_free(obj=%p, len=%d) called from %08lx\n", 
+                       obj, len, ret);
+#endif
                 panic("scsi_free:Trying to free unused memory");
-
+            }
             dma_free_sectors += nbits;
             dma_malloc_freelist[page] &= ~(mask << sector);
             restore_flags(flags);
diff -u --recursive --new-file v2.0.10/linux/drivers/scsi/scsicam.c linux/drivers/scsi/scsicam.c
--- v2.0.10/linux/drivers/scsi/scsicam.c	Thu Nov 30 14:04:51 1995
+++ linux/drivers/scsi/scsicam.c	Sun Aug  4 13:39:07 1996
@@ -22,6 +22,7 @@
 #include <linux/genhd.h>
 #include <linux/kernel.h>
 #include <linux/blk.h>
+#include <asm/unaligned.h>
 #include "scsi.h"
 #include "hosts.h"
 #include "sd.h"
@@ -121,7 +122,8 @@
     	    end_head * end_sector + end_sector;
 
 	/* This is the actual _sector_ number at the end */
-	logical_end = largest->start_sect + largest->nr_sects;
+	logical_end = get_unaligned(&largest->start_sect)
+			+ get_unaligned(&largest->nr_sects);
 
 	/* This is for >1023 cylinders */
         ext_cyl= (logical_end-(end_head * end_sector + end_sector))
diff -u --recursive --new-file v2.0.10/linux/drivers/scsi/sg.c linux/drivers/scsi/sg.c
--- v2.0.10/linux/drivers/scsi/sg.c	Wed Jul  3 10:12:26 1996
+++ linux/drivers/scsi/sg.c	Thu Aug  1 15:43:05 1996
@@ -276,7 +276,7 @@
      * wrong.
      */
     memcpy(device->header.sense_buffer, SCpnt->sense_buffer, sizeof(SCpnt->sense_buffer));
-    device->header.result=SCpnt->result;
+    device->header.result = (SCpnt->sense_buffer[0] == 0 ? 0 : EIO);
 
     /*
      * Now wake up the process that is waiting for the
diff -u --recursive --new-file v2.0.10/linux/drivers/scsi/sr.c linux/drivers/scsi/sr.c
--- v2.0.10/linux/drivers/scsi/sr.c	Thu Jul 18 14:28:48 1996
+++ linux/drivers/scsi/sr.c	Thu Aug  1 15:43:03 1996
@@ -485,11 +485,11 @@
 		printk(KERN_WARNING"sr_photocd: ioctl error (TOSHIBA #1): 0x%x\n",rc);
 	    break; /* if the first ioctl fails, we don't call the second one */
 	}
-	is_xa  = (rec[0] == 0x20);
 	min    = (unsigned long) rec[1]/16*10 + (unsigned long) rec[1]%16;
 	sec    = (unsigned long) rec[2]/16*10 + (unsigned long) rec[2]%16;
 	frame  = (unsigned long) rec[3]/16*10 + (unsigned long) rec[3]%16;
 	sector = min*CD_SECS*CD_FRAMES + sec*CD_FRAMES + frame;
+	is_xa  = (rec[0] == 0x20) || sector;
 	if (sector) {
 	    sector -= CD_BLOCK_OFFSET;
 #ifdef DEBUG
@@ -566,6 +566,9 @@
 	    break;
 	}
 	sector = rec[11] + (rec[10] << 8) + (rec[9] << 16) + (rec[8] << 24);
+	if (rec[6] <= 1) {
+	    sector = 0; /* ignore sector offsets from first track */
+	}
 	is_xa = !!sector;
 #ifdef DEBUG
 	if (sector)
diff -u --recursive --new-file v2.0.10/linux/drivers/scsi/st.c linux/drivers/scsi/st.c
--- v2.0.10/linux/drivers/scsi/st.c	Mon Jul  8 10:43:57 1996
+++ linux/drivers/scsi/st.c	Thu Aug  1 15:43:05 1996
@@ -2552,7 +2552,7 @@
 	 }
        }
 
-       i = flush_buffer(inode, file, mtc.mt_op == MTSEEK ||
+       i = flush_buffer(inode, file, /* mtc.mt_op == MTSEEK || */
 			mtc.mt_op == MTREW || mtc.mt_op == MTOFFL ||
 			mtc.mt_op == MTRETEN || mtc.mt_op == MTEOM ||
 			mtc.mt_op == MTLOCK || mtc.mt_op == MTLOAD ||
diff -u --recursive --new-file v2.0.10/linux/drivers/sound/.objects linux/drivers/sound/.objects
--- v2.0.10/linux/drivers/sound/.objects	Sun Jun 30 11:50:25 1996
+++ linux/drivers/sound/.objects	Thu Aug  1 15:43:05 1996
@@ -64,12 +64,8 @@
 	OBJS := $(OBJS)  pss.o
 endif
 
-ifdef CONFIG_SB
-	OBJS := $(OBJS) sb_card.o 
-endif
-
 ifdef CONFIG_SBDSP
-	OBJS := $(OBJS) sb_common.o sb_audio.o sb_mixer.o sb_midi.o
+	OBJS := $(OBJS) sb_card.o sb_common.o sb_audio.o sb_mixer.o sb_midi.o
 endif
 
 ifdef CONFIG_SEQUENCER
diff -u --recursive --new-file v2.0.10/linux/drivers/sound/sb_card.c linux/drivers/sound/sb_card.c
--- v2.0.10/linux/drivers/sound/sb_card.c	Sat Jul  6 11:31:42 1996
+++ linux/drivers/sound/sb_card.c	Thu Aug  1 15:43:05 1996
@@ -15,7 +15,7 @@
 
 #include "sound_config.h"
 
-#if defined(CONFIG_SB)
+#if defined(CONFIG_SBDSP)
 
 #include "sb_mixer.h"
 #include "sb.h"
diff -u --recursive --new-file v2.0.10/linux/drivers/sound/sb_common.c linux/drivers/sound/sb_common.c
--- v2.0.10/linux/drivers/sound/sb_common.c	Thu Jul 11 18:22:34 1996
+++ linux/drivers/sound/sb_common.c	Sun Aug  4 12:42:54 1996
@@ -1163,6 +1163,9 @@
 
   last_devc = 0;
 
+  if (hw_config->io_base <= 0)
+     return 0;
+
   if (check_region (hw_config->io_base, 4))
     {
       printk ("sbmpu: I/O port conflict (%x)\n", hw_config->io_base);
diff -u --recursive --new-file v2.0.10/linux/drivers/sound/sequencer.c linux/drivers/sound/sequencer.c
--- v2.0.10/linux/drivers/sound/sequencer.c	Sat Jul  6 11:31:43 1996
+++ linux/drivers/sound/sequencer.c	Sat Aug  3 11:46:51 1996
@@ -549,6 +549,7 @@
 	  if (chn == 9)
 	    {
 	      synth_devs[dev]->set_instr (dev, voice, 128 + note);
+              synth_devs[dev]->chn_info[chn].pgm_num = 128 + note;
 	      note = 60;	/* Middle C */
 
 	    }
diff -u --recursive --new-file v2.0.10/linux/fs/binfmt_elf.c linux/fs/binfmt_elf.c
--- v2.0.10/linux/fs/binfmt_elf.c	Sun Apr 14 11:14:43 1996
+++ linux/fs/binfmt_elf.c	Sun Aug  4 14:18:59 1996
@@ -39,8 +39,21 @@
 
 static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs);
 static int load_elf_library(int fd);
+extern int dump_fpu (struct pt_regs *, elf_fpregset_t *);
+extern void dump_thread(struct pt_regs *, struct user *);
+
+/*
+ * If we don't support core dumping, then supply a NULL so we
+ * don't even try.
+ */
+#ifdef USE_ELF_CORE_DUMP
 static int elf_core_dump(long signr, struct pt_regs * regs);
-extern int dump_fpu (elf_fpregset_t *);
+#else
+#define elf_core_dump	NULL
+#endif
+
+#define ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(ELF_EXEC_PAGESIZE-1))
+#define ELF_PAGEOFFSET(_v) ((_v) & (ELF_EXEC_PAGESIZE-1))
 
 static struct linux_binfmt elf_format = {
 #ifndef MODULE
@@ -90,12 +103,18 @@
 	}
 }
 
-unsigned long * create_elf_tables(char * p,int argc,int envc,struct elfhdr * exec, unsigned int load_addr, unsigned int interp_load_addr, int ibcs)
+unsigned long * create_elf_tables(char *p, int argc, int envc, 
+				  struct elfhdr * exec,
+				  unsigned long load_addr,
+				  unsigned long interp_load_addr, int ibcs)
 {
-	unsigned long *argv,*envp, *dlinfo;
-	unsigned long * sp;
+	unsigned long *argv, *envp, *dlinfo;
+	unsigned long *sp;
 
-	sp = (unsigned long *) (0xfffffffc & (unsigned long) p);
+	/*
+	 * Force 16 byte alignment here for generality.
+	 */
+	sp = (unsigned long *) (~15UL & (unsigned long) p);
 	sp -= exec ? DLINFO_ITEMS*2 : 2;
 	dlinfo = sp;
 	sp -= envc+1;
@@ -110,7 +129,8 @@
 #define NEW_AUX_ENT(id, val) \
 	  put_user ((id), dlinfo++); \
 	  put_user ((val), dlinfo++)
-	if(exec) { /* Put this here for an ELF program interpreter */
+
+	if (exec) { /* Put this here for an ELF program interpreter */
 	  struct elf_phdr * eppnt;
 	  eppnt = (struct elf_phdr *) exec->e_phoff;
 
@@ -128,7 +148,6 @@
 	}
 	NEW_AUX_ENT (AT_NULL, 0);
 #undef NEW_AUX_ENT
-
 	put_user((unsigned long)argc,--sp);
 	current->mm->arg_start = (unsigned long) p;
 	while (argc-->0) {
@@ -152,72 +171,79 @@
    is only provided so that we can read a.out libraries that have
    an ELF header */
 
-static unsigned int load_elf_interp(struct elfhdr * interp_elf_ex,
-			     struct inode * interpreter_inode, unsigned int *interp_load_addr)
+static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex,
+				     struct inode * interpreter_inode, 
+				     unsigned long *interp_load_addr)
 {
 	struct file * file;
 	struct elf_phdr *elf_phdata  =  NULL;
 	struct elf_phdr *eppnt;
-	unsigned int len;
-	unsigned int load_addr;
+	unsigned long load_addr;
 	int elf_exec_fileno;
-	int elf_bss;
 	int retval;
-	unsigned int last_bss;
-	int error;
+	unsigned long last_bss, elf_bss;
+	unsigned long error;
 	int i;
-	unsigned int k;
 	
 	elf_bss = 0;
 	last_bss = 0;
 	error = load_addr = 0;
 	
 	/* First of all, some simple consistency checks */
-	if((interp_elf_ex->e_type != ET_EXEC && 
+	if ((interp_elf_ex->e_type != ET_EXEC && 
 	    interp_elf_ex->e_type != ET_DYN) || 
-	   (interp_elf_ex->e_machine != EM_386 && interp_elf_ex->e_machine != EM_486) ||
+	   !elf_check_arch(interp_elf_ex->e_machine) ||
 	   (!interpreter_inode->i_op ||
 	    !interpreter_inode->i_op->default_file_ops->mmap)){
-		return 0xffffffff;
+		return ~0UL;
 	}
 	
 	/* Now read in all of the header information */
 	
-	if(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > PAGE_SIZE) 
-	    return 0xffffffff;
+	if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > PAGE_SIZE)
+	    return ~0UL;
 	
 	elf_phdata =  (struct elf_phdr *) 
-		kmalloc(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum, GFP_KERNEL);
-	if(!elf_phdata)
-	  return 0xffffffff;
+		kmalloc(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum, 
+			GFP_KERNEL);
+	if (!elf_phdata)
+	  return ~0UL;
 	
 	/*
 	 * If the size of this structure has changed, then punt, since
 	 * we will be doing the wrong thing.
 	 */
-	if( interp_elf_ex->e_phentsize != 32 )
+	if (interp_elf_ex->e_phentsize != sizeof(struct elf_phdr))
 	  {
 	    kfree(elf_phdata);
-	    return 0xffffffff;
+	    return ~0UL;
 	  }
 
-	retval = read_exec(interpreter_inode, interp_elf_ex->e_phoff, (char *) elf_phdata,
+	retval = read_exec(interpreter_inode, interp_elf_ex->e_phoff, 
+			   (char *) elf_phdata,
 			   sizeof(struct elf_phdr) * interp_elf_ex->e_phnum, 1);
 	
+	if (retval < 0) {
+		kfree (elf_phdata);
+		return retval;
+ 	}
+
 	elf_exec_fileno = open_inode(interpreter_inode, O_RDONLY);
 	if (elf_exec_fileno < 0) {
 	  kfree(elf_phdata);
-	  return 0xffffffff;
+	  return ~0UL;
 	}
 
 	file = current->files->fd[elf_exec_fileno];
 
 	eppnt = elf_phdata;
 	for(i=0; i<interp_elf_ex->e_phnum; i++, eppnt++)
-	  if(eppnt->p_type == PT_LOAD) {
+	  if (eppnt->p_type == PT_LOAD) {
 	    int elf_type = MAP_PRIVATE | MAP_DENYWRITE;
 	    int elf_prot = 0;
 	    unsigned long vaddr = 0;
+	    unsigned long k;
+
 	    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;
@@ -227,15 +253,20 @@
 	    }
 	    
 	    error = do_mmap(file, 
-			    load_addr + (vaddr & 0xfffff000),
-			    eppnt->p_filesz + (eppnt->p_vaddr & 0xfff),
+			    load_addr + ELF_PAGESTART(vaddr),
+			    eppnt->p_filesz + ELF_PAGEOFFSET(eppnt->p_vaddr),
 			    elf_prot,
 			    elf_type,
-			    eppnt->p_offset & 0xfffff000);
+			    ELF_PAGESTART(eppnt->p_offset));
 	    
-	    if(error < 0 && error > -1024) break;  /* Real error */
+	    if (error > -1024UL) {
+	      /* Real error */
+	      sys_close(elf_exec_fileno);
+	      kfree(elf_phdata);
+	      return ~0UL;
+	    }
 
-	    if(!load_addr && interp_elf_ex->e_type == ET_DYN)
+	    if (!load_addr && interp_elf_ex->e_type == ET_DYN)
 	      load_addr = error;
 
 	    /*
@@ -243,23 +274,19 @@
 	     * track of the largest address we see for this.
 	     */
 	    k = load_addr + eppnt->p_vaddr + eppnt->p_filesz;
-	    if(k > elf_bss) elf_bss = k;
+	    if (k > elf_bss) elf_bss = k;
 
 	    /*
 	     * Do the same thing for the memory mapping - between
 	     * elf_bss and last_bss is the bss section.
 	     */
 	    k = load_addr + eppnt->p_memsz + eppnt->p_vaddr;
-	    if(k > last_bss) last_bss = k;
+	    if (k > last_bss) last_bss = k;
 	  }
 	
 	/* Now use mmap to map the library into memory. */
 
 	sys_close(elf_exec_fileno);
-	if(error < 0 && error > -1024) {
-		kfree(elf_phdata);
-		return 0xffffffff;
-	}
 
 	/*
 	 * Now fill out the bss section.  First pad the last page up
@@ -268,24 +295,24 @@
 	 * bss page.
 	 */
 	padzero(elf_bss);
-	len = (elf_bss + 0xfff) & 0xfffff000; /* What we have mapped so far */
+	elf_bss = ELF_PAGESTART(elf_bss + ELF_EXEC_PAGESIZE - 1); /* What we have mapped so far */
 
 	/* Map the last of the bss segment */
-	if (last_bss > len)
-	  do_mmap(NULL, len, last_bss-len,
+	if (last_bss > elf_bss)
+	  do_mmap(NULL, elf_bss, last_bss-elf_bss,
 		  PROT_READ|PROT_WRITE|PROT_EXEC,
 		  MAP_FIXED|MAP_PRIVATE, 0);
 	kfree(elf_phdata);
 
 	*interp_load_addr = load_addr;
-	return ((unsigned int) interp_elf_ex->e_entry) + load_addr;
+	return ((unsigned long) interp_elf_ex->e_entry) + load_addr;
 }
 
-static unsigned int load_aout_interp(struct exec * interp_ex,
+static unsigned long load_aout_interp(struct exec * interp_ex,
 			     struct inode * interpreter_inode)
 {
   int retval;
-  unsigned int elf_entry;
+  unsigned long elf_entry;
   
   current->mm->brk = interp_ex->a_bss +
     (current->mm->end_data = interp_ex->a_data +
@@ -310,12 +337,12 @@
   } else
     retval = -1;
   
-  if(retval >= 0)
-    do_mmap(NULL, (interp_ex->a_text + interp_ex->a_data + 0xfff) & 
-	    0xfffff000, interp_ex->a_bss,
+  if (retval >= 0)
+    do_mmap(NULL, ELF_PAGESTART(interp_ex->a_text + interp_ex->a_data + ELF_EXEC_PAGESIZE - 1),
+	    interp_ex->a_bss,
 	    PROT_READ|PROT_WRITE|PROT_EXEC,
 	    MAP_FIXED|MAP_PRIVATE, 0);
-  if(retval < 0) return 0xffffffff;
+  if (retval < 0) return ~0UL;
   return elf_entry;
 }
 
@@ -337,7 +364,7 @@
 	struct file * file;
   	struct exec interp_ex;
 	struct inode *interpreter_inode;
-	unsigned int load_addr;
+	unsigned long load_addr;
 	unsigned int interpreter_type = INTERPRETER_NONE;
 	unsigned char ibcs2_interpreter;
 	int i;
@@ -345,13 +372,13 @@
 	int error;
 	struct elf_phdr * elf_ppnt, *elf_phdata;
 	int elf_exec_fileno;
-	unsigned int elf_bss, k, elf_brk;
+	unsigned long elf_bss, k, elf_brk;
 	int retval;
 	char * elf_interpreter;
-	unsigned int elf_entry, interp_load_addr = 0;
+	unsigned long elf_entry, interp_load_addr = 0;
 	int status;
-	unsigned int start_code, end_code, end_data;
-	unsigned int elf_stack;
+	unsigned long start_code, end_code, end_data;
+	unsigned long elf_stack;
 	char passed_fileno[6];
 	
 	ibcs2_interpreter = 0;
@@ -366,9 +393,9 @@
 	
 	
 	/* First of all, some simple consistency checks */
-	if((elf_ex.e_type != ET_EXEC &&
+	if ((elf_ex.e_type != ET_EXEC &&
 	    elf_ex.e_type != ET_DYN) || 
-	   (elf_ex.e_machine != EM_386 && elf_ex.e_machine != EM_486) ||
+	   (! elf_check_arch(elf_ex.e_machine)) ||
 	   (!bprm->inode->i_op || !bprm->inode->i_op->default_file_ops ||
 	    !bprm->inode->i_op->default_file_ops->mmap)){
 		return -ENOEXEC;
@@ -403,15 +430,15 @@
 	
 	file = current->files->fd[elf_exec_fileno];
 	
-	elf_stack = 0xffffffff;
+	elf_stack = ~0UL;
 	elf_interpreter = NULL;
-	start_code = 0xffffffff;
+	start_code = ~0UL;
 	end_code = 0;
 	end_data = 0;
 	
 	for(i=0;i < elf_ex.e_phnum; i++){
-		if(elf_ppnt->p_type == PT_INTERP) {
-		  	if( elf_interpreter != NULL )
+		if (elf_ppnt->p_type == PT_INTERP) {
+		  	if ( elf_interpreter != NULL )
 			{
 				kfree (elf_phdata);
 				kfree(elf_interpreter);
@@ -432,7 +459,8 @@
 				return -ENOMEM;
 			}
 			
-			retval = read_exec(bprm->inode,elf_ppnt->p_offset,elf_interpreter,
+			retval = read_exec(bprm->inode,elf_ppnt->p_offset,
+					   elf_interpreter,
 					   elf_ppnt->p_filesz, 1);
 			/* If the program interpreter is one of these two,
 			   then assume an iBCS2 image. Otherwise assume
@@ -443,22 +471,23 @@
 #if 0
 			printk("Using ELF interpreter %s\n", elf_interpreter);
 #endif
-			if(retval >= 0) {
+			if (retval >= 0) {
 				old_fs = get_fs(); /* This could probably be optimized */
 				set_fs(get_ds());
-				retval = namei(elf_interpreter, &interpreter_inode);
+				retval = open_namei(elf_interpreter, 0, 0,
+						    &interpreter_inode, NULL);
 				set_fs(old_fs);
 			}
 
-			if(retval >= 0)
+			if (retval >= 0)
 				retval = read_exec(interpreter_inode,0,bprm->buf,128, 1);
 			
-			if(retval >= 0) {
+			if (retval >= 0) {
 				interp_ex = *((struct exec *) bprm->buf);		/* exec-header */
 				interp_elf_ex = *((struct elfhdr *) bprm->buf);	  /* exec-header */
 				
 			}
-			if(retval < 0) {
+			if (retval < 0) {
 				kfree (elf_phdata);
 				kfree(elf_interpreter);
 				sys_close(elf_exec_fileno);
@@ -467,22 +496,22 @@
 		}
 		elf_ppnt++;
 	}
-	
+
 	/* Some simple consistency checks for the interpreter */
-	if(elf_interpreter){
+	if (elf_interpreter){
 		interpreter_type = INTERPRETER_ELF | INTERPRETER_AOUT;
 
 		/* Now figure out which format our binary is */
-		if((N_MAGIC(interp_ex) != OMAGIC) && 
-		   (N_MAGIC(interp_ex) != ZMAGIC) &&
-		   (N_MAGIC(interp_ex) != QMAGIC)) 
+		if ((N_MAGIC(interp_ex) != OMAGIC) && 
+		    (N_MAGIC(interp_ex) != ZMAGIC) &&
+		    (N_MAGIC(interp_ex) != QMAGIC)) 
 		  interpreter_type = INTERPRETER_ELF;
 
 		if (interp_elf_ex.e_ident[0] != 0x7f ||
 		    strncmp(&interp_elf_ex.e_ident[1], "ELF",3) != 0)
 		  interpreter_type &= ~INTERPRETER_ELF;
 
-		if(!interpreter_type)
+		if (!interpreter_type)
 		  {
 		    kfree(elf_interpreter);
 		    kfree(elf_phdata);
@@ -497,17 +526,17 @@
 	if (!bprm->sh_bang) {
 		char * passed_p;
 		
-		if(interpreter_type == INTERPRETER_AOUT) {
+		if (interpreter_type == INTERPRETER_AOUT) {
 		  sprintf(passed_fileno, "%d", elf_exec_fileno);
 		  passed_p = passed_fileno;
 		
-		  if(elf_interpreter) {
+		  if (elf_interpreter) {
 		    bprm->p = copy_strings(1,&passed_p,bprm->page,bprm->p,2);
 		    bprm->argc++;
 		  }
 		}
 		if (!bprm->p) {
-			if(elf_interpreter) {
+			if (elf_interpreter) {
 			      kfree(elf_interpreter);
 			}
 			kfree (elf_phdata);
@@ -523,7 +552,7 @@
 	current->mm->end_code = 0;
 	current->mm->start_mmap = ELF_START_MMAP;
 	current->mm->mmap = NULL;
-	elf_entry = (unsigned int) elf_ex.e_entry;
+	elf_entry = (unsigned long) elf_ex.e_entry;
 	
 	/* Do this so that we can load the interpreter, if need be.  We will
 	   change some of these later */
@@ -538,76 +567,69 @@
 	
 	old_fs = get_fs();
 	set_fs(get_ds());
-	
-	elf_ppnt = elf_phdata;
-	for(i=0;i < elf_ex.e_phnum; i++){
-		
-		if(elf_ppnt->p_type == PT_INTERP) {
-			/* Set these up so that we are able to load the interpreter */
-		  /* Now load the interpreter into user address space */
-		  set_fs(old_fs);
-
-		  if(interpreter_type & 1) elf_entry = 
-		    load_aout_interp(&interp_ex, interpreter_inode);
-
-		  if(interpreter_type & 2) elf_entry = 
-		    load_elf_interp(&interp_elf_ex, interpreter_inode, &interp_load_addr);
-
-		  old_fs = get_fs();
-		  set_fs(get_ds());
-
-		  iput(interpreter_inode);
-		  kfree(elf_interpreter);
-			
-		  if(elf_entry == 0xffffffff) { 
-		    set_fs(old_fs);
-		    printk("Unable to load interpreter\n");
-		    kfree(elf_phdata);
-		    send_sig(SIGSEGV, current, 0);
-		    return 0;
-		  }
-		}
-		
-		
-		if(elf_ppnt->p_type == PT_LOAD) {
-			int elf_prot = (elf_ppnt->p_flags & PF_R) ? PROT_READ : 0;
+	for(i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) {
+		if (elf_ppnt->p_type == PT_LOAD) {
+			int elf_prot = 0;
+			if (elf_ppnt->p_flags & PF_R) elf_prot |= PROT_READ;
 			if (elf_ppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
 			if (elf_ppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;
+
 			error = do_mmap(file,
-					elf_ppnt->p_vaddr & 0xfffff000,
-					elf_ppnt->p_filesz + (elf_ppnt->p_vaddr & 0xfff),
+					ELF_PAGESTART(elf_ppnt->p_vaddr),
+					(elf_ppnt->p_filesz +
+					 ELF_PAGEOFFSET(elf_ppnt->p_vaddr)),
 					elf_prot,
-					MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE,
-					elf_ppnt->p_offset & 0xfffff000);
+					(MAP_FIXED | MAP_PRIVATE |
+					 MAP_DENYWRITE | MAP_EXECUTABLE),
+					ELF_PAGESTART(elf_ppnt->p_offset));
 			
 #ifdef LOW_ELF_STACK
-			if((elf_ppnt->p_vaddr & 0xfffff000) < elf_stack) 
-				elf_stack = elf_ppnt->p_vaddr & 0xfffff000;
+			if (ELF_PAGESTART(elf_ppnt->p_vaddr) < elf_stack) 
+				elf_stack = ELF_PAGESTART(elf_ppnt->p_vaddr);
 #endif
 			
-			if(!load_addr) 
+			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 (k > elf_bss) elf_bss = k;
 #if 1
-			if((elf_ppnt->p_flags & PF_X) && end_code <  k)
+			if ((elf_ppnt->p_flags & PF_X) && end_code <  k)
 #else
-			if( !(elf_ppnt->p_flags & PF_W) && end_code <  k)
+			if ( !(elf_ppnt->p_flags & PF_W) && end_code <  k)
 #endif
 				end_code = k; 
-			if(end_data < k) end_data = k; 
+			if (end_data < k) end_data = k; 
 			k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz;
-			if(k > elf_brk) elf_brk = k;		     
-		      }
-		elf_ppnt++;
+			if (k > elf_brk) elf_brk = k;		     
+		}
 	}
 	set_fs(old_fs);
-	
+
+	if (elf_interpreter) {
+		if (interpreter_type & 1) 
+			elf_entry = load_aout_interp(&interp_ex,
+						     interpreter_inode);
+		else if (interpreter_type & 2) 
+			elf_entry = load_elf_interp(&interp_elf_ex, 
+						    interpreter_inode, 
+						    &interp_load_addr);
+
+		iput(interpreter_inode);
+		kfree(elf_interpreter);
+			
+		if (elf_entry == ~0UL) { 
+			printk("Unable to load interpreter\n");
+			kfree(elf_phdata);
+			send_sig(SIGSEGV, current, 0);
+			return 0;
+		}
+	}
+
 	kfree(elf_phdata);
 	
-	if(interpreter_type != INTERPRETER_AOUT) sys_close(elf_exec_fileno);
+	if (interpreter_type != INTERPRETER_AOUT) sys_close(elf_exec_fileno);
 	current->personality = (ibcs2_interpreter ? PER_SVR4 : PER_LINUX);
 
 	if (current->exec_domain && current->exec_domain->use_count)
@@ -639,7 +661,7 @@
 			load_addr,
 			interp_load_addr,
 			(interpreter_type == INTERPRETER_AOUT ? 0 : 1));
-	if(interpreter_type == INTERPRETER_AOUT)
+	if (interpreter_type == INTERPRETER_AOUT)
 	  current->mm->arg_start += strlen(passed_fileno) + 1;
 	current->mm->start_brk = current->mm->brk = elf_brk;
 	current->mm->end_code = end_code;
@@ -662,7 +684,7 @@
 	printk("(brk) %x\n" , current->mm->brk);
 #endif
 
-	if( current->personality == PER_SVR4 )
+	if ( current->personality == PER_SVR4 )
 	{
 		/* Why this, you ask???  Well SVr4 maps page 0 as read-only,
 		   and some applications "depend" upon this behavior.
@@ -672,14 +694,16 @@
 				MAP_FIXED | MAP_PRIVATE, 0);
 	}
 
-	/* SVR4/i386 ABI (pages 3-31, 3-32) says that when the program
-	   starts %edx contains a pointer to a function which might be
-	   registered using `atexit'.  This provides a mean for the
-	   dynamic linker to call DT_FINI functions for shared libraries
-	   that have been loaded before the code runs.
+#ifdef ELF_PLAT_INIT
+	/*
+	 * The ABI may specify that certain registers be set up in special
+	 * ways (on i386 %edx is the address of a DT_FINI function, for
+	 * example.  This macro performs whatever initialization to
+	 * the regs structure is required.
+	 */
+	ELF_PLAT_INIT(regs);
+#endif
 
-	   A value of 0 tells we have no such handler.  */
-	regs->edx = 0;
 
 	start_thread(regs, elf_entry, bprm->p);
 	if (current->flags & PF_PTRACED)
@@ -707,10 +731,10 @@
 	struct elfhdr elf_ex;
 	struct elf_phdr *elf_phdata  =  NULL;
 	struct  inode * inode;
-	unsigned int len;
+	unsigned long len;
 	int elf_bss;
 	int retval;
-	unsigned int bss;
+	unsigned long bss;
 	int error;
 	int i,j, k;
 
@@ -740,14 +764,14 @@
 		return -ENOEXEC;
 
 	/* First of all, some simple consistency checks */
-	if(elf_ex.e_type != ET_EXEC || elf_ex.e_phnum > 2 ||
+	if (elf_ex.e_type != ET_EXEC || elf_ex.e_phnum > 2 ||
 	   (elf_ex.e_machine != EM_386 && elf_ex.e_machine != EM_486) ||
 	   (!inode->i_op || !inode->i_op->default_file_ops->mmap))
 		return -ENOEXEC;
 	
 	/* Now read in all of the header information */
 	
-	if(sizeof(struct elf_phdr) * elf_ex.e_phnum > PAGE_SIZE)
+	if (sizeof(struct elf_phdr) * elf_ex.e_phnum > PAGE_SIZE)
 		return -ENOEXEC;
 	
 	elf_phdata =  (struct elf_phdr *) 
@@ -760,9 +784,9 @@
 	
 	j = 0;
 	for(i=0; i<elf_ex.e_phnum; i++)
-		if((elf_phdata + i)->p_type == PT_LOAD) j++;
+		if ((elf_phdata + i)->p_type == PT_LOAD) j++;
 	
-	if(j != 1)  {
+	if (j != 1)  {
 		kfree(elf_phdata);
 		return -ENOEXEC;
 	}
@@ -771,23 +795,23 @@
 	
 	/* Now use mmap to map the library into memory. */
 	error = do_mmap(file,
-			elf_phdata->p_vaddr & 0xfffff000,
-			elf_phdata->p_filesz + (elf_phdata->p_vaddr & 0xfff),
+			ELF_PAGESTART(elf_phdata->p_vaddr),
+			elf_phdata->p_filesz + ELF_PAGEOFFSET(elf_phdata->p_vaddr),
 			PROT_READ | PROT_WRITE | PROT_EXEC,
 			MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE,
-			elf_phdata->p_offset & 0xfffff000);
+			ELF_PAGESTART(elf_phdata->p_offset));
 
 	k = elf_phdata->p_vaddr + elf_phdata->p_filesz;
-	if(k > elf_bss) elf_bss = k;
+	if (k > elf_bss) elf_bss = k;
 	
-	if (error != (elf_phdata->p_vaddr & 0xfffff000)) {
+	if (error != ELF_PAGESTART(elf_phdata->p_vaddr)) {
 		kfree(elf_phdata);
 		return error;
 	}
 
 	padzero(elf_bss);
 
-	len = (elf_phdata->p_filesz + elf_phdata->p_vaddr+ 0xfff) & 0xfffff000;
+	len = ELF_PAGESTART(elf_phdata->p_filesz + elf_phdata->p_vaddr+ ELF_EXEC_PAGESIZE - 1);
 	bss = elf_phdata->p_memsz + elf_phdata->p_vaddr;
 	if (bss > len)
 	  do_mmap(NULL, len, bss-len,
@@ -806,7 +830,13 @@
 	MOD_DEC_USE_COUNT;
 	return retval;
 }
-	
+
+/*
+ * Note that some platforms still use traditional core dumps and not
+ * the ELF core dump.  Each platform can select it as appropriate.
+ */
+#ifdef USE_ELF_CORE_DUMP
+
 /*
  * ELF core dumper
  *
@@ -982,13 +1012,13 @@
 
 	/* Set up header */
 	memcpy(elf.e_ident, ELFMAG, SELFMAG);
-	elf.e_ident[EI_CLASS] = ELFCLASS32;
-	elf.e_ident[EI_DATA] = ELFDATA2LSB;
+	elf.e_ident[EI_CLASS] = ELF_CLASS;
+	elf.e_ident[EI_DATA] = ELF_DATA;
 	elf.e_ident[EI_VERSION] = EV_CURRENT;
 	memset(elf.e_ident+EI_PAD, 0, EI_NIDENT-EI_PAD);
 	
 	elf.e_type = ET_CORE;
-	elf.e_machine = EM_386;
+	elf.e_machine = ELF_ARCH;
 	elf.e_version = EV_CURRENT;
 	elf.e_entry = 0;
 	elf.e_phoff = sizeof(elf);
@@ -1062,6 +1092,14 @@
 	prstatus.pr_cutime.tv_usec = CT_TO_USECS(current->cutime);
 	prstatus.pr_cstime.tv_sec = CT_TO_SECS(current->cstime);
 	prstatus.pr_cstime.tv_usec = CT_TO_USECS(current->cstime);
+
+	/*
+	 * This transfers the registers from regs into the standard
+	 * coredump arrangement, whatever that is.
+	 */
+#ifdef ELF_CORE_COPY_REGS
+	ELF_CORE_COPY_REGS(prstatus.pr_reg, regs)
+#else
 	if (sizeof(elf_gregset_t) != sizeof(struct pt_regs))
 	{
 		printk("sizeof(elf_gregset_t) (%d) != sizeof(struct pt_regs) (%d)\n",
@@ -1069,6 +1107,7 @@
 	}
 	else
 		*(struct pt_regs *)&prstatus.pr_reg = *regs;
+#endif
 	
 #ifdef DEBUG
 	dump_regs("Passed in regs", (elf_greg_t *)regs);
@@ -1110,7 +1149,7 @@
 	notes[2].data = current;
 	
 	/* Try to dump the fpu. */
-	prstatus.pr_fpvalid = dump_fpu (&fpu);
+	prstatus.pr_fpvalid = dump_fpu (regs, &fpu);
 	if (!prstatus.pr_fpvalid)
 	{
 		numnote--;
@@ -1213,14 +1252,17 @@
 #endif
 	return has_dumped;
 }
+#endif		/* USE_ELF_CORE_DUMP */
 
-int init_elf_binfmt(void) {
+int init_elf_binfmt(void) 
+{
 	return register_binfmt(&elf_format);
 }
 
 #ifdef MODULE
 
-int init_module(void) {
+int init_module(void) 
+{
 	/* Install the COFF, ELF and XOUT loaders.
 	 * N.B. We *rely* on the table being the right size with the
 	 * right number of free slots...
@@ -1229,7 +1271,8 @@
 }
 
 
-void cleanup_module( void) {
+void cleanup_module( void) 
+{
 	/* Remove the COFF and ELF loaders. */
 	unregister_binfmt(&elf_format);
 }
diff -u --recursive --new-file v2.0.10/linux/fs/fat/inode.c linux/fs/fat/inode.c
--- v2.0.10/linux/fs/fat/inode.c	Fri May 10 07:54:52 1996
+++ linux/fs/fat/inode.c	Sun Aug  4 13:39:07 1996
@@ -23,6 +23,7 @@
 #include "tables.h"
 
 #include <asm/segment.h>
+#include <asm/unaligned.h>
 
 
 
@@ -242,7 +243,8 @@
 #define ROUND_TO_MULTIPLE(n,m) ((n) && (m) ? (n)+(m)-1-((n)-1)%(m) : 0)
     /* don't divide by zero */
 
-	logical_sector_size = CF_LE_W(*(unsigned short *) &b->sector_size);
+	logical_sector_size =
+		CF_LE_W(get_unaligned((unsigned short *) &b->sector_size));
 	sector_mult = logical_sector_size >> SECTOR_BITS;
 	MSDOS_SB(sb)->cluster_size = b->cluster_size*sector_mult;
 	MSDOS_SB(sb)->fats = b->fats;
@@ -250,14 +252,16 @@
 	MSDOS_SB(sb)->fat_length = CF_LE_W(b->fat_length)*sector_mult;
 	MSDOS_SB(sb)->dir_start = (CF_LE_W(b->reserved)+b->fats*CF_LE_W(
 	    b->fat_length))*sector_mult;
-	MSDOS_SB(sb)->dir_entries = CF_LE_W(*((unsigned short *) &b->dir_entries
-	    ));
+	MSDOS_SB(sb)->dir_entries =
+		CF_LE_W(get_unaligned((unsigned short *) &b->dir_entries));
 	MSDOS_SB(sb)->data_start = MSDOS_SB(sb)->dir_start+ROUND_TO_MULTIPLE((
 	    MSDOS_SB(sb)->dir_entries << MSDOS_DIR_BITS) >> SECTOR_BITS,
 	    sector_mult);
-	data_sectors = (CF_LE_W(*((unsigned short *) &b->sectors)) ?
-	    CF_LE_W(*((unsigned short *) &b->sectors)) :
-	    CF_LE_L(b->total_sect))*sector_mult-MSDOS_SB(sb)->data_start;
+	data_sectors = CF_LE_W(get_unaligned((unsigned short *) &b->sectors));
+	if (!data_sectors) {
+		data_sectors = CF_LE_L(b->total_sect);
+	}
+	data_sectors = data_sectors * sector_mult - MSDOS_SB(sb)->data_start;
 	error = !b->cluster_size || !sector_mult;
 	if (!error) {
 		MSDOS_SB(sb)->clusters = b->cluster_size ? data_sectors/
diff -u --recursive --new-file v2.0.10/linux/fs/file_table.c linux/fs/file_table.c
--- v2.0.10/linux/fs/file_table.c	Thu Jun  6 13:03:48 1996
+++ linux/fs/file_table.c	Sat Aug  3 10:43:18 1996
@@ -23,12 +23,16 @@
  */
 static inline void insert_file_free(struct file *file)
 {
-	file->f_count = 0;
-	file->f_next = first_file;
-	file->f_prev = first_file->f_prev;
-	file->f_next->f_prev = file;
-	file->f_prev->f_next = file;
+	struct file *next, *prev;
+
+	next = first_file;
 	first_file = file;
+	file->f_count = 0;
+	prev = next->f_prev;
+	file->f_next = next;
+	next->f_prev = file;
+	file->f_prev = prev;
+	prev->f_next = file;
 }
 
 /*
@@ -36,11 +40,15 @@
  */
 static inline void remove_file_free(struct file *file)
 {
-	if (first_file == file)
-		first_file = first_file->f_next;
-	file->f_next->f_prev = file->f_prev;
-	file->f_prev->f_next = file->f_next;
+	struct file *next, *prev;
+
+	next = file->f_next;
+	prev = file->f_prev;
 	file->f_next = file->f_prev = NULL;
+	if (first_file == file)
+		first_file = next;
+	next->f_prev = prev;
+	prev->f_next = next;
 }
 
 /*
@@ -48,10 +56,14 @@
  */
 static inline void put_last_free(struct file *file)
 {
-	file->f_prev = first_file->f_prev;
-	file->f_prev->f_next = file;
-	file->f_next = first_file;
-	file->f_next->f_prev = file;
+	struct file *next, *prev;
+
+	next = first_file;
+	file->f_next = next;
+	prev = next->f_prev;
+	next->f_prev = file;
+	file->f_prev = prev;
+	prev->f_next = file;
 }
 
 /*
diff -u --recursive --new-file v2.0.10/linux/fs/super.c linux/fs/super.c
--- v2.0.10/linux/fs/super.c	Sat Jun  8 11:10:49 1996
+++ linux/fs/super.c	Sun Aug  4 12:56:25 1996
@@ -967,6 +967,9 @@
 #ifdef CONFIG_BLK_DEV_FD
 	if (MAJOR(ROOT_DEV) == FLOPPY_MAJOR) {
 		floppy_eject();
+#ifdef CONFIG_BLK_DEV_RAM
+		printk(KERN_NOTICE "(Warning, this kernel has no ramdisk support)\n");
+#endif
 		printk(KERN_NOTICE "VFS: Insert root floppy and press ENTER\n");
 		wait_for_keypress();
 	}
@@ -1065,7 +1068,7 @@
 		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");
+			printk("okay\n");
 			invalidate_buffers(old_root_dev);
 		}
 		return umount_error ? error : 0;
diff -u --recursive --new-file v2.0.10/linux/include/asm-alpha/elf.h linux/include/asm-alpha/elf.h
--- v2.0.10/linux/include/asm-alpha/elf.h	Wed Jul  5 12:53:22 1995
+++ linux/include/asm-alpha/elf.h	Sun Aug  4 14:18:12 1996
@@ -5,7 +5,10 @@
  * ELF register definitions..
  */
 
-#define ELF_NGREG	32
+/* 
+ * Note: ELF_NGREG must ben the same as EF_SIZE/8.
+ */
+#define ELF_NGREG	33
 #define ELF_NFPREG	32
 
 typedef unsigned long elf_greg_t;
@@ -13,5 +16,26 @@
 
 typedef double elf_fpreg_t;
 typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
+
+/*
+ * This is used to ensure we don't load something for the wrong architecture.
+ */
+#define elf_check_arch(x) ((x) == EM_ALPHA)
+
+/*
+ * These are used to set parameters in the core dumps.
+ */
+#define ELF_CLASS	ELFCLASS64
+#define ELF_DATA	ELFDATA2LSB;
+#define ELF_ARCH	EM_ALPHA
+
+#define USE_ELF_CORE_DUMP
+#define ELF_EXEC_PAGESIZE	8192
+
+#define ELF_CORE_COPY_REGS(_dest,_regs)			\
+{ struct user _dump;					\
+	dump_thread(_regs, &_dump);			\
+	memcpy((char *) &_dest, (char *) &_dump.regs,	\
+	       sizeof(elf_gregset_t)); }
 
 #endif
diff -u --recursive --new-file v2.0.10/linux/include/asm-alpha/fcntl.h linux/include/asm-alpha/fcntl.h
--- v2.0.10/linux/include/asm-alpha/fcntl.h	Tue Apr 30 13:09:45 1996
+++ linux/include/asm-alpha/fcntl.h	Sun Aug  4 13:39:07 1996
@@ -58,9 +58,9 @@
 struct flock {
 	short l_type;
 	short l_whence;
-	off_t l_start;
-	off_t l_len;
-	pid_t l_pid;
+	__kernel_off_t l_start;
+	__kernel_off_t l_len;
+	__kernel_pid_t l_pid;
 };
 
 #endif
diff -u --recursive --new-file v2.0.10/linux/include/asm-alpha/posix_types.h linux/include/asm-alpha/posix_types.h
--- v2.0.10/linux/include/asm-alpha/posix_types.h	Fri Jul  5 13:48:39 1996
+++ linux/include/asm-alpha/posix_types.h	Sun Aug  4 13:39:07 1996
@@ -22,6 +22,7 @@
 typedef long		__kernel_clock_t;
 typedef int		__kernel_daddr_t;
 typedef char *		__kernel_caddr_t;
+typedef unsigned long	__kernel_sigset_t;	/* at least 32 bits */
 
 #ifdef __GNUC__
 typedef long long	__kernel_loff_t;
@@ -60,7 +61,7 @@
 }
 
 #undef __FD_ISSET
-static __inline__ int __FD_ISSET(unsigned long fd, __kernel_fd_set *p)
+static __inline__ int __FD_ISSET(unsigned long fd, const __kernel_fd_set *p)
 { 
 	unsigned long _tmp = fd / __NFDBITS;
 	unsigned long _rem = fd % __NFDBITS;
@@ -79,10 +80,21 @@
 
 	if (__builtin_constant_p(__FDSET_LONGS)) {
 		switch (__FDSET_LONGS) {
-			case 8:
-				tmp[0] = 0; tmp[1] = 0; tmp[2] = 0; tmp[3] = 0;
-				tmp[4] = 0; tmp[5] = 0; tmp[6] = 0; tmp[7] = 0;
-				return;
+		      case 16:
+			tmp[ 0] = 0; tmp[ 1] = 0; tmp[ 2] = 0; tmp[ 3] = 0;
+			tmp[ 4] = 0; tmp[ 5] = 0; tmp[ 6] = 0; tmp[ 7] = 0;
+			tmp[ 8] = 0; tmp[ 9] = 0; tmp[10] = 0; tmp[11] = 0;
+			tmp[12] = 0; tmp[13] = 0; tmp[14] = 0; tmp[15] = 0;
+			return;
+
+		      case 8:
+			tmp[ 0] = 0; tmp[ 1] = 0; tmp[ 2] = 0; tmp[ 3] = 0;
+			tmp[ 4] = 0; tmp[ 5] = 0; tmp[ 6] = 0; tmp[ 7] = 0;
+			return;
+
+		      case 4:
+			tmp[ 0] = 0; tmp[ 1] = 0; tmp[ 2] = 0; tmp[ 3] = 0;
+			return;
 		}
 	}
 	i = __FDSET_LONGS;
diff -u --recursive --new-file v2.0.10/linux/include/asm-alpha/system.h linux/include/asm-alpha/system.h
--- v2.0.10/linux/include/asm-alpha/system.h	Sat Apr 20 12:58:38 1996
+++ linux/include/asm-alpha/system.h	Sun Aug  4 13:37:59 1996
@@ -17,6 +17,7 @@
  */
 #define BOOT_PCB	0x20000000
 #define BOOT_ADDR	0x20000000
+/* Remove when official MILO sources have ELF support: */
 #define BOOT_SIZE	(16*1024)
 
 #define KERNEL_START	0xfffffc0000300000
@@ -27,6 +28,7 @@
 #define ZERO_PGE	0xfffffc000030A000
 
 #define START_ADDR	0xfffffc0000310000
+/* Remove when official MILO sources have ELF support: */
 #define START_SIZE	(2*1024*1024)
 
 #ifndef __ASSEMBLY__
diff -u --recursive --new-file v2.0.10/linux/include/asm-alpha/unistd.h linux/include/asm-alpha/unistd.h
--- v2.0.10/linux/include/asm-alpha/unistd.h	Sat Jun  8 11:09:40 1996
+++ linux/include/asm-alpha/unistd.h	Sun Aug  4 13:39:07 1996
@@ -165,53 +165,55 @@
 #define __NR_uname			339
 #define __NR_nanosleep			340
 #define __NR_mremap			341
+#define __NR_nfsctl			342
 
-#ifdef __LIBRARY__
-
-/*
- * Duh, the alpha gcc compiler doesn't allow us to specify regs
- * yet. I'll have to see about this later..
- */
+#if defined(__LIBRARY__) && defined(__GNUC__)
 
 /* XXX - _foo needs to be __foo, while __NR_bar could be _NR_bar. */
-#define _syscall0(type,name) \
-type name(void) \
-{ \
-	return (type) -1; \
+#define _syscall0(type, name)						\
+type name(void)								\
+{									\
+	extern long syscall (int, ...);					\
+	return syscall(__NR_##name));					\
 }
 
-#define _syscall1(type,name,type1,arg1) \
-type name(type1 arg1) \
-{ \
-	return (type) -1; \
+#define _syscall1(type,name,type1,arg1)					\
+type name(type1 arg1)							\
+{									\
+	extern long syscall (int, ...);					\
+	return syscall(__NR_##name, arg1);				\
 }
 
-#define _syscall2(type,name,type1,arg1,type2,arg2) \
-type name(type1 arg1,type2 arg2) \
-{ \
-	return (type) -1; \
+#define _syscall2(type,name,type1,arg1,type2,arg2)			\
+type name(type1 arg1,type2 arg2)					\
+{									\
+	extern long syscall (int, ...);					\
+	return syscall(__NR_##name, arg1, arg2);				\
 }
 
-#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \
-type name(type1 arg1,type2 arg2,type3 arg3) \
-{ \
-	return (type) -1; \
+#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3)		\
+type name(type1 arg1,type2 arg2,type3 arg3)				\
+{									\
+	extern long syscall (int, ...);					\
+	return syscall(__NR_##name, arg1, arg2, arg3);			\
 }
 
 #define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \
-type name (type1 arg1, type2 arg2, type3 arg3, type4 arg4) \
-{ \
-	return (type) -1; \
+type name (type1 arg1, type2 arg2, type3 arg3, type4 arg4)		 \
+{									 \
+	extern long syscall (int, ...);					 \
+	return syscall(__NR_##name, arg1, arg2, arg3, arg4);		 \
 } 
 
 #define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
-	  type5,arg5) \
-type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5) \
-{ \
-	return (type) -1; \
+	  type5,arg5)							 \
+type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5)	 \
+{									 \
+	extern long syscall (int, ...);					 \
+	return syscall(__NR_##name, arg1, arg2, arg3, arg4);		 \
 }
 
-#endif /* __LIBRARY__ */
+#endif /* __LIBRARY__ && __GNUC__ */
 
 #ifdef __KERNEL_SYSCALLS__
 
diff -u --recursive --new-file v2.0.10/linux/include/asm-i386/elf.h linux/include/asm-i386/elf.h
--- v2.0.10/linux/include/asm-i386/elf.h	Wed Jul  5 12:53:22 1995
+++ linux/include/asm-i386/elf.h	Sun Aug  4 14:12:40 1996
@@ -14,4 +14,28 @@
 
 typedef struct user_i387_struct elf_fpregset_t;
 
+/*
+ * This is used to ensure we don't load something for the wrong architecture.
+ */
+#define elf_check_arch(x) ( ((x) == EM_386) || ((x) == EM_486) )
+
+/*
+ * These are used to set parameters in the core dumps.
+ */
+#define ELF_CLASS	ELFCLASS32
+#define ELF_DATA	ELFDATA2LSB;
+#define ELF_ARCH	EM_386
+
+	/* SVR4/i386 ABI (pages 3-31, 3-32) says that when the program
+	   starts %edx contains a pointer to a function which might be
+	   registered using `atexit'.  This provides a mean for the
+	   dynamic linker to call DT_FINI functions for shared libraries
+	   that have been loaded before the code runs.
+
+	   A value of 0 tells we have no such handler.  */
+#define ELF_PLAT_INIT(_r)	_r->edx = 0
+
+#define USE_ELF_CORE_DUMP
+#define ELF_EXEC_PAGESIZE	4096
+
 #endif
diff -u --recursive --new-file v2.0.10/linux/include/asm-i386/system.h linux/include/asm-i386/system.h
--- v2.0.10/linux/include/asm-i386/system.h	Wed May 29 18:06:39 1996
+++ linux/include/asm-i386/system.h	Thu Aug  1 15:43:04 1996
@@ -5,11 +5,12 @@
 
 /*
  * Entry into gdt where to find first TSS. GDT layout:
- *   0 - nul
- *   1 - kernel code segment
- *   2 - kernel data segment
- *   3 - user code segment
- *   4 - user data segment
+ *   0 - null
+ *   1 - not used
+ *   2 - kernel code segment
+ *   3 - kernel data segment
+ *   4 - user code segment
+ *   5 - user data segment
  * ...
  *   8 - TSS #0
  *   9 - LDT #0
diff -u --recursive --new-file v2.0.10/linux/include/asm-m68k/elf.h linux/include/asm-m68k/elf.h
--- v2.0.10/linux/include/asm-m68k/elf.h	Mon May  6 12:44:32 1996
+++ linux/include/asm-m68k/elf.h	Sun Aug  4 14:12:40 1996
@@ -14,4 +14,20 @@
 
 typedef struct user_m68kfp_struct elf_fpregset_t;
 
+/*
+ * This is used to ensure we don't load something for the wrong architecture.
+ */
+#define elf_check_arch(x) ((x) == EM_M68K)
+
+/*
+ * These are used to set parameters in the core dumps.
+ * FIXME(eric) I don't know what the correct endianness to use is.
+ */
+#define ELF_CLASS	ELFCLASS32
+#define ELF_DATA	ELFDATA2MSB;
+#define ELF_ARCH	EM_M68K
+
+#define USE_ELF_CORE_DUMP
+#define ELF_EXEC_PAGESIZE	4096
+
 #endif
diff -u --recursive --new-file v2.0.10/linux/include/asm-mips/elf.h linux/include/asm-mips/elf.h
--- v2.0.10/linux/include/asm-mips/elf.h	Wed Dec 13 12:39:45 1995
+++ linux/include/asm-mips/elf.h	Sun Aug  4 14:12:40 1996
@@ -14,4 +14,20 @@
 typedef double elf_fpreg_t;
 typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
 
+/*
+ * This is used to ensure we don't load something for the wrong architecture.
+ */
+#define elf_check_arch(x) ((x) == EM_MIPS)
+
+/*
+ * These are used to set parameters in the core dumps.
+ * FIXME(eric) I don't know what the correct endianness to use is.
+ */
+#define ELF_CLASS	ELFCLASS32
+#define ELF_DATA	ELFDATA2MSB;
+#define ELF_ARCH	EM_MIPS
+
+#define USE_ELF_CORE_DUMP
+#define ELF_EXEC_PAGESIZE	4096
+
 #endif /* __ASM_MIPS_ELF_H */
diff -u --recursive --new-file v2.0.10/linux/include/asm-ppc/elf.h linux/include/asm-ppc/elf.h
--- v2.0.10/linux/include/asm-ppc/elf.h	Sat Nov 25 19:49:06 1995
+++ linux/include/asm-ppc/elf.h	Sun Aug  4 14:12:40 1996
@@ -14,4 +14,17 @@
 typedef double elf_fpreg_t;
 typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
 
+#define elf_check_arch(x) ((x) == EM_PPC)
+
+/*
+ * These are used to set parameters in the core dumps.
+ * FIXME(eric) I don't know what the correct endianness to use is.
+ */
+#define ELF_CLASS	ELFCLASS32
+#define ELF_DATA	ELFDATA2LSB;
+#define ELF_ARCH	EM_PPC
+
+#define USE_ELF_CORE_DUMP
+#define ELF_EXEC_PAGESIZE	4096
+
 #endif
diff -u --recursive --new-file v2.0.10/linux/include/asm-sparc/elf.h linux/include/asm-sparc/elf.h
--- v2.0.10/linux/include/asm-sparc/elf.h	Thu Apr 25 13:23:18 1996
+++ linux/include/asm-sparc/elf.h	Sun Aug  4 14:12:40 1996
@@ -15,6 +15,19 @@
 
 typedef unsigned long elf_fpregset_t;
 
+/*
+ * This is used to ensure we don't load something for the wrong architecture.
+ */
 #define elf_check_arch(x) ((x) == EM_SPARC)
+
+/*
+ * These are used to set parameters in the core dumps.
+ */
 #define ELF_ARCH EM_SPARC
+#define ELF_CLASS	ELFCLASS32
+#define ELF_DATA	ELFDATA2MSB;
+
+#define USE_ELF_CORE_DUMP
+#define ELF_EXEC_PAGESIZE	4096
+
 #endif
diff -u --recursive --new-file v2.0.10/linux/include/linux/elf.h linux/include/linux/elf.h
--- v2.0.10/linux/include/linux/elf.h	Mon May 27 12:00:59 1996
+++ linux/include/linux/elf.h	Sun Aug  4 14:19:24 1996
@@ -1,6 +1,8 @@
 #ifndef _LINUX_ELF_H
 #define _LINUX_ELF_H
 
+#include <asm/elf.h>
+
 typedef unsigned long	Elf32_Addr;
 typedef unsigned short	Elf32_Half;
 typedef unsigned long	Elf32_Off;
@@ -38,6 +40,25 @@
 #define EM_860   7
 #define EM_PPC   20
 
+#define EM_MIPS		8	/* MIPS R3000 (officially, big-endian only) */
+
+#define EM_MIPS_RS4_BE 10	/* MIPS R4000 big-endian */
+
+#define EM_SPARC64     11	/* SPARC v9 (not official) 64-bit */
+
+#define EM_PARISC      15	/* HPPA */
+
+#define EM_SPARC32PLUS 18	/* Sun's "v8plus" */
+
+#define EM_PPC	       20	/* PowerPC */
+
+/*
+ * This is an interim value that we will use until the committee comes
+ * up with a final number.
+ */
+#define EM_ALPHA	0x9026
+
+
 /* This is the info that is needed to parse the dynamic section of the file */
 #define DT_NULL		0
 #define DT_NEEDED	1
@@ -107,7 +128,13 @@
   } d_un;
 } Elf32_Dyn;
 
-extern Elf32_Dyn _DYNAMIC [];
+typedef struct {
+  unsigned long long d_tag;		/* entry tag value */
+  union {
+    unsigned long long d_val;
+    unsigned long long d_ptr;
+  } d_un;
+} Elf64_Dyn;
 
 /* The following are used with relocations */
 #define ELF32_R_SYM(x) ((x) >> 8)
@@ -131,12 +158,23 @@
   Elf32_Word	r_info;
 } Elf32_Rel;
 
+typedef struct elf64_rel {
+  unsigned long long r_offset;	/* Location at which to apply the action */
+  unsigned long long r_info;	/* index and type of relocation */
+} Elf64_Rel;
+
 typedef struct elf32_rela{
   Elf32_Addr	r_offset;
   Elf32_Word	r_info;
   Elf32_Sword	r_addend;
 } Elf32_Rela;
 
+typedef struct elf64_rela {
+  unsigned long long r_offset;	/* Location at which to apply the action */
+  unsigned long long r_info;	/* index and type of relocation */
+  unsigned long long r_addend;	/* Constant addend used to compute value */
+} Elf64_Rela;
+
 typedef struct elf32_sym{
   Elf32_Word	st_name;
   Elf32_Addr	st_value;
@@ -146,10 +184,19 @@
   Elf32_Half	st_shndx;
 } Elf32_Sym;
 
+typedef struct elf64_sym {
+  unsigned int	st_name;		/* Symbol name, index in string tbl */
+  unsigned char	st_info;		/* Type and binding attributes */
+  unsigned char	st_other;		/* No defined meaning, 0 */
+  unsigned short st_shndx;		/* Associated section index */
+  unsigned long long st_value;		/* Value of the symbol */
+  unsigned long long st_size;		/* Associated symbol size */
+} Elf64_Sym;
+
 
 #define EI_NIDENT	16
 
-typedef struct elfhdr{
+typedef struct elf32_hdr{
   unsigned char	e_ident[EI_NIDENT];
   Elf32_Half	e_type;
   Elf32_Half	e_machine;
@@ -166,13 +213,30 @@
   Elf32_Half	e_shstrndx;
 } Elf32_Ehdr;
 
+typedef struct elf64_hdr {
+  unsigned char	e_ident[16];		/* ELF "magic number" */
+  short int e_type;
+  short unsigned int e_machine;
+  int   e_version;
+  unsigned long long e_entry;		/* Entry point virtual address */
+  unsigned long long e_phoff;		/* Program header table file offset */
+  unsigned long long e_shoff;		/* Section header table file offset */
+  int   e_flags;
+  short int e_ehsize;
+  short int e_phentsize;
+  short int e_phnum;
+  short int e_shentsize;
+  short int e_shnum;
+  short int e_shstrndx;
+} Elf64_Ehdr;
+
 /* These constants define the permissions on sections in the program
    header, p_flags. */
 #define PF_R		0x4
 #define PF_W		0x2
 #define PF_X		0x1
 
-typedef struct elf_phdr{
+typedef struct elf32_phdr{
   Elf32_Word	p_type;
   Elf32_Off	p_offset;
   Elf32_Addr	p_vaddr;
@@ -183,6 +247,17 @@
   Elf32_Word	p_align;
 } Elf32_Phdr;
 
+typedef struct elf64_phdr {
+  int p_type;
+  int p_flags;
+  unsigned long long p_offset;		/* Segment file offset */
+  unsigned long long p_vaddr;		/* Segment virtual address */
+  unsigned long long p_paddr;		/* Segment physical address */
+  unsigned long long p_filesz;		/* Segment size in file */
+  unsigned long long p_memsz;		/* Segment size in memory */
+  unsigned long long p_align;		/* Segment alignment, file & memory */
+} Elf64_Phdr;
+
 /* sh_type */
 #define SHT_NULL	0
 #define SHT_PROGBITS	1
@@ -230,6 +305,19 @@
   Elf32_Word	sh_entsize;
 } Elf32_Shdr;
 
+typedef struct elf64_shdr {
+  unsigned int	sh_name;		/* Section name, index in string tbl */
+  unsigned int	sh_type;		/* Type of section */
+  unsigned long long sh_flags;		/* Miscellaneous section attributes */
+  unsigned long long sh_addr;		/* Section virtual addr at execution */
+  unsigned long long sh_offset;		/* Section file offset */
+  unsigned long long sh_size;		/* Size of section in bytes */
+  unsigned int	sh_link;		/* Index of another section */
+  unsigned int	sh_info;		/* Additional section information */
+  unsigned long long sh_addralign;	/* Section alignment */
+  unsigned long long sh_entsize;	/* Entry size if section holds table */
+} Elf64_Shdr;
+
 #define	EI_MAG0		0		/* e_ident[] indexes */
 #define	EI_MAG1		1
 #define	EI_MAG2		2
@@ -266,12 +354,41 @@
 #define NT_TASKSTRUCT	4
 
 /* Note header in a PT_NOTE section */
-typedef struct elf_note {
+typedef struct elf32_note {
   Elf32_Word	n_namesz;	/* Name size */
   Elf32_Word	n_descsz;	/* Content size */
   Elf32_Word	n_type;		/* Content type */
 } Elf32_Nhdr;
 
+/* Note header in a PT_NOTE section */
+/*
+ * For now we use the 32 bit version of the structure until we figure
+ * out whether we need anything better.  Note - on the Alpha, "unsigned int"
+ * is only 32 bits.
+ */
+typedef struct elf64_note {
+  unsigned int	n_namesz;	/* Name size */
+  unsigned int	n_descsz;	/* Content size */
+  unsigned int	n_type;		/* Content type */
+} Elf64_Nhdr;
+
 #define ELF_START_MMAP 0x80000000
+
+#if ELF_CLASS == ELFCLASS32
+
+extern Elf32_Dyn _DYNAMIC [];
+#define elfhdr		elf32_hdr
+#define elf_phdr	elf32_phdr
+#define elf_note	elf32_note
+
+#else
+
+extern Elf64_Dyn _DYNAMIC [];
+#define elfhdr		elf64_hdr
+#define elf_phdr	elf64_phdr
+#define elf_note	elf64_note
+
+#endif
+
 
 #endif /* _LINUX_ELF_H */
diff -u --recursive --new-file v2.0.10/linux/include/linux/elfcore.h linux/include/linux/elfcore.h
--- v2.0.10/linux/include/linux/elfcore.h	Thu Jul 18 14:59:05 1996
+++ linux/include/linux/elfcore.h	Mon Aug  5 09:03:18 1996
@@ -40,9 +40,9 @@
 	short	pr_what;	/* XXX More detailed reason */
 #endif
 	struct elf_siginfo pr_info;	/* Info associated with signal */
-	short	pr_cursig;	/* Current signal */
-	sigset_t pr_sigpend;	/* Set of pending signals */
-	sigset_t pr_sighold;	/* Set of held signals */
+	short	pr_cursig;		/* Current signal */
+	sigset_t pr_sigpend;		/* Set of pending signals */
+	sigset_t pr_sighold;		/* Set of held signals */
 #if 0
 	struct sigaltstack pr_altstack;	/* Alternate stack info */
 	struct sigaction pr_action;	/* Signal action for current sig */
diff -u --recursive --new-file v2.0.10/linux/include/linux/major.h linux/include/linux/major.h
--- v2.0.10/linux/include/linux/major.h	Fri Apr 26 10:30:52 1996
+++ linux/include/linux/major.h	Thu Aug  1 15:36:31 1996
@@ -42,9 +42,9 @@
 #define MITSUMI_X_CDROM_MAJOR 20
 #define SCSI_GENERIC_MAJOR 21
 #define Z8530_MAJOR 34
-#define DIGI_MAJOR 22
+#define DIGI_MAJOR 23
 #define IDE1_MAJOR	22
-#define DIGICU_MAJOR 23
+#define DIGICU_MAJOR 22
 #define MITSUMI_CDROM_MAJOR 23
 #define CDU535_CDROM_MAJOR 24
 #define STL_SERIALMAJOR 24
diff -u --recursive --new-file v2.0.10/linux/include/linux/mtio.h linux/include/linux/mtio.h
--- v2.0.10/linux/include/linux/mtio.h	Fri May  3 10:12:17 1996
+++ linux/include/linux/mtio.h	Sun Aug  4 13:39:07 1996
@@ -74,8 +74,8 @@
 	long	mt_gstat;	/* generic (device independent) status */
 	long	mt_erreg;	/* error register */
 	/* The next two fields are not always used */
-	daddr_t	mt_fileno;	/* number of current file on tape */
-	daddr_t	mt_blkno;	/* current block number */
+	__kernel_daddr_t mt_fileno;	/* number of current file on tape */
+	__kernel_daddr_t mt_blkno;	/* current block number */
 };
 
 
diff -u --recursive --new-file v2.0.10/linux/include/linux/netdevice.h linux/include/linux/netdevice.h
--- v2.0.10/linux/include/linux/netdevice.h	Thu Jul 25 20:28:47 1996
+++ linux/include/linux/netdevice.h	Mon Aug  5 09:12:24 1996
@@ -27,7 +27,6 @@
 #include <linux/config.h>
 #include <linux/if.h>
 #include <linux/if_ether.h>
-#include <linux/skbuff.h>
 
 /* for future expansion when we will have different priorities. */
 #define DEV_NUMBUFFS	3
@@ -52,6 +51,10 @@
 #define IS_INVBCAST	4		/* Wrong netmask bcast not for us (unused)*/
 #define IS_MULTICAST	5		/* Multicast IP address */
 
+#ifdef __KERNEL__
+
+#include <linux/skbuff.h>
+
 /*
  *	We tag multicasts with these structures.
  */
@@ -201,8 +204,6 @@
   struct packet_type	*next;
 };
 
-
-#ifdef __KERNEL__
 
 #include <linux/interrupt.h>
 #include <linux/notifier.h>
diff -u --recursive --new-file v2.0.10/linux/include/linux/pcwd.h linux/include/linux/pcwd.h
--- v2.0.10/linux/include/linux/pcwd.h	Thu Jan  1 02:00:00 1970
+++ linux/include/linux/pcwd.h	Thu Aug  1 15:43:05 1996
@@ -0,0 +1,12 @@
+/*
+ * Berkshire PC Watchdog Defines
+ * For version 0.41 of the driver
+ */
+
+#define	PCWD_IOCTL_BASE	'W'
+
+#define	PCWD_GETSTAT	_IOR(PCWD_IOCTL_BASE, 1, int)
+#define	PCWD_PING	_IOR(PCWD_IOCTL_BASE, 2, int)
+
+#define	PCWD_PREVRESET	0x01	/* System previously reset by card */
+#define	PCWD_TEMPSENSE	0x02	/* Temperature overheat sense */
diff -u --recursive --new-file v2.0.10/linux/include/linux/posix_types.h linux/include/linux/posix_types.h
--- v2.0.10/linux/include/linux/posix_types.h	Wed Jul 17 15:29:43 1996
+++ linux/include/linux/posix_types.h	Sun Aug  4 14:37:29 1996
@@ -41,7 +41,7 @@
 #undef __FDMASK
 #define	__FDMASK(d)	(1UL << ((d) % __NFDBITS))
 
-typedef struct {
+typedef struct fd_set {
 	unsigned long fds_bits [__FDSET_LONGS];
 } __kernel_fd_set;
 
diff -u --recursive --new-file v2.0.10/linux/include/linux/string.h linux/include/linux/string.h
--- v2.0.10/linux/include/linux/string.h	Thu Jul 18 14:54:04 1996
+++ linux/include/linux/string.h	Sun Aug  4 14:38:04 1996
@@ -13,25 +13,25 @@
 
 extern char * ___strtok;
 extern char * strcpy(char *,const char *);
-extern char * strncpy(char *,const char *,size_t);
+extern char * strncpy(char *,const char *, __kernel_size_t);
 extern char * strcat(char *, const char *);
-extern char * strncat(char *, const char *, size_t);
+extern char * strncat(char *, const char *, __kernel_size_t);
 extern char * strchr(const char *,int);
 extern char * strrchr(const char *,int);
 extern char * strpbrk(const char *,const char *);
 extern char * strtok(char *,const char *);
 extern char * strstr(const char *,const char *);
-extern size_t strlen(const char *);
-extern size_t strnlen(const char *,size_t);
-extern size_t strspn(const char *,const char *);
+extern __kernel_size_t strlen(const char *);
+extern __kernel_size_t strnlen(const char *,__kernel_size_t);
+extern __kernel_size_t strspn(const char *,const char *);
 extern int strcmp(const char *,const char *);
-extern int strncmp(const char *,const char *,size_t);
+extern int strncmp(const char *,const char *,__kernel_size_t);
 
-extern void * memset(void *,int,size_t);
-extern void * memcpy(void *,const void *,size_t);
-extern void * memmove(void *,const void *,size_t);
-extern void * memscan(void *,int,size_t);
-extern int memcmp(const void *,const void *,size_t);
+extern void * memset(void *,int,__kernel_size_t);
+extern void * memcpy(void *,const void *,__kernel_size_t);
+extern void * memmove(void *,const void *,__kernel_size_t);
+extern void * memscan(void *,int,__kernel_size_t);
+extern int memcmp(const void *,const void *,__kernel_size_t);
 
 /*
  * Include machine specific inline routines
diff -u --recursive --new-file v2.0.10/linux/include/net/spx.h linux/include/net/spx.h
--- v2.0.10/linux/include/net/spx.h	Thu Jan  1 02:00:00 1970
+++ linux/include/net/spx.h	Thu Aug  1 15:43:05 1996
@@ -0,0 +1,38 @@
+#ifndef __NET_SPX_H
+#define __NET_SPX_H
+
+/*
+ *	Internal definitions for the SPX protocol.
+ */
+ 
+/*
+ *	The SPX header following an IPX header.
+ */
+ 
+struct spxhdr
+{
+	__u8 cctl;	
+#define CCTL_SPXII_XHD	0x01	/* SPX2 extended header */
+#define CCTL_SPX_UNKNOWN 0x02	/* Unknown (unused ??) */
+#define CCTL_SPXII_NEG	0x04	/* Negotiate size */
+#define CCTL_SPXII	0x08	/* Set for SPX2 */
+#define CCTL_EOM	0x10	/* End of message marker */
+#define CCTL_URG	0x20	/* Urgent marker in SPP (not used in SPX?) */
+#define CCTL_ACK	0x40	/* Send me an ACK */
+#define CCTL_CTL	0x80	/* Control message */
+	__u8 dtype;
+#define SPX_DTYPE_ECONN	0xFE	/* Finished */
+#define SPX_DTYPE_ECACK	0xFF	/* Ok */
+	__u16 sconn;	/* Connection ID */
+	__u16 dconn;	/* Connection ID */
+	__u16 sequence;
+	__u16 ackseq;
+	__u16 allocseq;
+};
+
+#define IPXTYPE_SPX	5
+
+	
+	
+	
+#endif
diff -u --recursive --new-file v2.0.10/linux/kernel/sched.c linux/kernel/sched.c
--- v2.0.10/linux/kernel/sched.c	Wed Jul 17 14:43:32 1996
+++ linux/kernel/sched.c	Thu Aug  1 15:43:05 1996
@@ -938,7 +938,7 @@
 			if (cpu == i) {
 				utime = ticks-system;
 				stime = system;
-			} else if (smp_proc_in_lock[i]) {
+			} else if (smp_proc_in_lock[j]) {
 				utime = 0;
 				stime = ticks;
 			}
diff -u --recursive --new-file v2.0.10/linux/mm/filemap.c linux/mm/filemap.c
--- v2.0.10/linux/mm/filemap.c	Tue Jul 23 10:26:40 1996
+++ linux/mm/filemap.c	Sat Aug  3 11:46:51 1996
@@ -328,9 +328,9 @@
 #endif
 
 /*
- * Read-ahead profiling informations
- * ---------------------------------
- * Every PROFILE_MAXREADCOUNT, the following informations are written 
+ * Read-ahead profiling information
+ * --------------------------------
+ * Every PROFILE_MAXREADCOUNT, the following information is written 
  * to the syslog:
  *   Percentage of asynchronous read-ahead.
  *   Average of read-ahead fields context value.
diff -u --recursive --new-file v2.0.10/linux/mm/mmap.c linux/mm/mmap.c
--- v2.0.10/linux/mm/mmap.c	Thu Jun  6 09:29:59 1996
+++ linux/mm/mmap.c	Wed Jul 31 15:58:59 1996
@@ -823,7 +823,7 @@
 	 * If the one of the segments is only being partially unmapped,
 	 * it will put new vm_area_struct(s) into the address space.
 	 */
-	while (free) {
+	do {
 		unsigned long st, end;
 
 		mpnt = free;
@@ -840,9 +840,10 @@
 		zap_page_range(current->mm, st, end-st);
 		unmap_fixup(mpnt, st, end-st);
 		kfree(mpnt);
-	}
+	} while (free);
+
+	/* we could zap the page tables here too.. */
 
-	zap_page_range(current->mm, addr, len);
 	return 0;
 }
 
diff -u --recursive --new-file v2.0.10/linux/mm/vmalloc.c linux/mm/vmalloc.c
--- v2.0.10/linux/mm/vmalloc.c	Wed Apr  3 10:59:33 1996
+++ linux/mm/vmalloc.c	Sun Aug  4 13:39:07 1996
@@ -306,7 +306,7 @@
 	void * addr;
 	struct vm_struct * area;
 
-	if (offset < high_memory)
+	if (MAP_NR(offset) < MAP_NR(high_memory))
 		return NULL;
 	if (offset & ~PAGE_MASK)
 		return NULL;
diff -u --recursive --new-file v2.0.10/linux/net/core/dev.c linux/net/core/dev.c
--- v2.0.10/linux/net/core/dev.c	Thu Jun  6 21:22:24 1996
+++ linux/net/core/dev.c	Thu Aug  1 15:43:04 1996
@@ -617,7 +617,10 @@
 			cli();
 			skb_push(skb,offset);	/* Put header back on for bridge */
 			if(br_receive_frame(skb))
+			{
+				sti();
 				continue;
+			}
 			/*
 			 *	Pull the MAC header off for the copy going to
 			 *	the upper layers.
diff -u --recursive --new-file v2.0.10/linux/net/core/sock.c linux/net/core/sock.c
--- v2.0.10/linux/net/core/sock.c	Wed Jun 26 11:05:26 1996
+++ linux/net/core/sock.c	Sun Aug  4 13:06:57 1996
@@ -348,7 +348,7 @@
 struct sk_buff *sock_wmalloc(struct sock *sk, unsigned long size, int force, int priority)
 {
 	if (sk) {
-		if (force || sk->wmem_alloc + size < sk->sndbuf) {
+		if (force || sk->wmem_alloc < sk->sndbuf) {
 			struct sk_buff * skb = alloc_skb(size, priority);
 			if (skb)
 				atomic_add(skb->truesize, &sk->wmem_alloc);
@@ -362,7 +362,7 @@
 struct sk_buff *sock_rmalloc(struct sock *sk, unsigned long size, int force, int priority)
 {
 	if (sk) {
-		if (force || sk->rmem_alloc + size < sk->rcvbuf) {
+		if (force || sk->rmem_alloc < sk->rcvbuf) {
 			struct sk_buff *skb = alloc_skb(size, priority);
 			if (skb)
 				atomic_add(skb->truesize, &sk->rmem_alloc);
diff -u --recursive --new-file v2.0.10/linux/net/ethernet/eth.c linux/net/ethernet/eth.c
--- v2.0.10/linux/net/ethernet/eth.c	Mon May 13 12:15:24 1996
+++ linux/net/ethernet/eth.c	Sat Aug  3 11:46:51 1996
@@ -273,7 +273,7 @@
 	int ip_length;
 
 	IS_SKB(dest);
-	eth=(struct ethhdr *)dest->data;
+	eth=(struct ethhdr *)src;
 	if(eth->h_proto!=htons(ETH_P_IP))
 	{
 		memcpy(dest->data,src,length);
diff -u --recursive --new-file v2.0.10/linux/net/ipv4/af_inet.c linux/net/ipv4/af_inet.c
--- v2.0.10/linux/net/ipv4/af_inet.c	Mon Jul  8 10:21:46 1996
+++ linux/net/ipv4/af_inet.c	Sun Aug  4 12:56:25 1996
@@ -814,7 +814,7 @@
 		
 	/* check this error. */
 	if (sk->state != TCP_CLOSE)
-		return(-EIO);
+		return(-EINVAL);
 	if(addr_len<sizeof(struct sockaddr_in))
 		return -EINVAL;
 		
@@ -1104,6 +1104,12 @@
 		destroy_sock(sk2);
 		newsock->data = NULL;
 		return err;
+	}
+	if (sk2->state == TCP_CLOSE)
+	{
+		destroy_sock(sk2);
+		newsock->data=NULL;
+		return -ECONNABORTED;
 	}
 	newsock->state = SS_CONNECTED;
 	return(0);
diff -u --recursive --new-file v2.0.10/linux/net/ipv4/arp.c linux/net/ipv4/arp.c
--- v2.0.10/linux/net/ipv4/arp.c	Mon Jul  8 10:21:46 1996
+++ linux/net/ipv4/arp.c	Thu Aug  1 15:43:04 1996
@@ -1138,6 +1138,7 @@
 			else
 				dev_queue_xmit(skb,skb->dev,skb->sk->priority);
 		}
+		cli();
 	}
 	restore_flags(flags);
 }
diff -u --recursive --new-file v2.0.10/linux/net/ipv4/rarp.c linux/net/ipv4/rarp.c
--- v2.0.10/linux/net/ipv4/rarp.c	Mon May 13 12:15:24 1996
+++ linux/net/ipv4/rarp.c	Thu Aug  1 15:43:04 1996
@@ -150,7 +150,6 @@
 		if (entry->dev == dev)
 		{
 			*pentry = entry->next;
-			sti();
 			rarp_release_entry(entry);
 		}
 		else
diff -u --recursive --new-file v2.0.10/linux/net/ipv4/tcp.c linux/net/ipv4/tcp.c
--- v2.0.10/linux/net/ipv4/tcp.c	Thu Aug  1 15:53:34 1996
+++ linux/net/ipv4/tcp.c	Sun Aug  4 13:56:54 1996
@@ -856,6 +856,11 @@
 	lock_sock(sk);
 }
 
+static inline int tcp_memory_free(struct sock *sk)
+{
+	return sk->wmem_alloc < sk->sndbuf;
+}
+
 /*
  *	Wait for more memory for a socket
  */
@@ -863,9 +868,9 @@
 {
 	release_sock(sk);
 	cli();
-	if (sk->wmem_alloc*2 > sk->sndbuf &&
+	if (!tcp_memory_free(sk) &&
 	    (sk->state == TCP_ESTABLISHED||sk->state == TCP_CLOSE_WAIT)
-		&& sk->err == 0)
+		&& sk->err == 0 /* && check shutdown ?? */)
 	{
 		sk->socket->flags &= ~SO_NOSPACE;
 		interruptible_sleep_on(sk->sleep);
@@ -964,16 +969,20 @@
 			 */
 #ifndef CONFIG_NO_PATH_MTU_DISCOVERY
 			/*
-			 *	FIXME:  I'm almost sure that this fragment is BUG,
-			 *		but it works... I do not know why 8) --ANK
-			 *
 			 *	Really, we should rebuild all the queues...
 			 *	It's difficult. Temporary hack is to send all
 			 *	queued segments with allowed fragmentation.
 			 */
 			{
+				/*
+				 *	new_mss may be zero. That indicates
+				 *	we don't have a window estimate for
+				 *	the remote box yet. 
+				 *		-- AC
+				 */
+				
 				int new_mss = min(sk->mtu, sk->max_window);
-				if (new_mss < sk->mss)
+				if (new_mss && new_mss < sk->mss)
 				{
 					tcp_send_partial(sk);
 					sk->mss = new_mss;
@@ -1428,7 +1437,7 @@
 		if (copied)
 			break;
 
-		if (sk->err)
+		if (sk->err && !(flags&MSG_PEEK))
 		{
 			copied = sock_error(sk);
 			break;
diff -u --recursive --new-file v2.0.10/linux/net/ipv4/tcp_input.c linux/net/ipv4/tcp_input.c
--- v2.0.10/linux/net/ipv4/tcp_input.c	Sat Jul  6 13:32:44 1996
+++ linux/net/ipv4/tcp_input.c	Thu Aug  1 15:25:59 1996
@@ -1295,7 +1295,7 @@
 					 * and lost it from the queue before
 					 * changing the ack properly].
 					 */
-					printk(KERN_ERR "Lost timer or fin packet in tcp_fin.");
+					printk(KERN_ERR "Lost timer or fin packet in tcp_fin.\n");
 				}
 			}
 			tcp_set_state(sk,TCP_CLOSING);
diff -u --recursive --new-file v2.0.10/linux/net/ipv4/tcp_output.c linux/net/ipv4/tcp_output.c
--- v2.0.10/linux/net/ipv4/tcp_output.c	Thu Jul 11 14:56:06 1996
+++ linux/net/ipv4/tcp_output.c	Sun Aug  4 13:20:37 1996
@@ -623,7 +623,7 @@
 	 * and then put it into the queue to be sent.
 	 */
 
-	buff = sock_wmalloc(NULL, MAX_RESET_SIZE, 1, GFP_ATOMIC);
+	buff = alloc_skb(MAX_RESET_SIZE, GFP_ATOMIC);
 	if (buff == NULL) 
 	  	return;
 
