Linux 0.99 patchlevel 14

Linux 0.99 patchlevel 14 is available on nic.funet.fi in the usual place
(pub/OS/Linux/PEOPLE/Linus).  There are no diffs relative to pl13, as
too much has changed (the directory structure changed and the sound
driver was added).  Diffs relative to the last ALPHA version (13t) are
in the "pl13-ALPHA's" subdirectory along with the actual ALPHA versions.

The changes to pl13t are rather minor: most of them are just more printf
format fixes to make gcc-2.5.x happy (Chip Salzenberg).  Only one very
minor bugfix which made pl13t not notice the WP bit on a 486.

It would seem to be a good idea to use gcc-2.5.x to compile the kernel,
as that seems to fix at least one known bug in earlier gcc versions.  I
hope that pl14 will be even more stable than pl13 has turned out to be,
and especially the networking code seems to have become much more
dependable.  Thanks Alan & co.

Changes to the last official release (p13) are too numerous to mention
(or even to remember), but they include NTP support, updated SCSI and
networking drivers, >16MB swap area handling, added sound support,
read-only HPFS filesystem, memory management cleanups (especially
cleaned up mmap() some more).  Also, pl14 contains updated ext2fs code,
along with minor fixes (especially concerning the time values) in other
filesystems, and fixed unnamed/named pipe select() semantics.

The reorganizations include moving all device drivers to a subdirectory
of their own (linux/drivers), centralizing the major number handling
(<linux/major.h> etc...  Possibly cleaner and/or easier to keep track of
different drivers.  Finally, the first 4kB of physical memory is no
longer cleared on bootup: tytso reports that this feature now enables
some portables to use the power-saving features under linux.  This could
also be useful for the DOS emulator to check where the interrupt
pointers pointed at startup.

			Linus
diff --git a/CHANGES b/CHANGES
index dde6c32..4e74e16 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,16 @@
+CHANGES since 0.99 patchlevel 13:
+
+ - new kernel source layout: drivers separated
+ - lots of networking bugs fixed, and new network card drivers (Alan Cox,
+   Donald Becker &co)
+ - sound driver added to the default source distribution (Hannu
+   Savolainen)
+ - updated SCSI driver code (Eric Youngdale, Drew Eckhardt &co)
+ - readonly OS/2 filesystem support (HPFS) added (Chris Smith)
+ - NTP support (Philip Gladstone, Torsten Duwe, ??)
+ - fixed 16MB swap-area limit
+ - lots of minor cleanups, buxfixes etc.
+
 CHANGES since 0.99 patchlevel 12 and earlier:
 
  - the bad memory management one-liner bug in pl12 is naturally fixed.
diff --git a/Configure b/Configure
index 13197bb..77c8445 100644
--- a/Configure
+++ b/Configure
@@ -202,6 +202,7 @@
 		:)	[ "$branch" = "t" ] && echo "$raw_input_line" ;;
 		int)	[ "$branch" = "t" ] && int "$rest" ;;
 		bool)	[ "$branch" = "t" ] && bool "$rest" ;;
+		exec)	[ "$branch" = "t" ] && ( sh -c "$rest" ) ;;
 		if)	stack="$branch $stack"
 			if [ "$branch" = "t" ] && eval "$rest"; then
 				branch=t
diff --git a/Makefile b/Makefile
index fdf817c..451b050 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 VERSION = 0.99
-PATCHLEVEL = 13
-ALPHA = k
+PATCHLEVEL = 14
+ALPHA =
 
 all:	Version zImage
 
@@ -44,8 +44,7 @@
 # The number is the same as you would ordinarily press at bootup.
 #
 
-# SVGA_MODE=	-DSVGA_MODE=3
-SVGA_MODE=	-DSVGA_MODE=NORMAL_VGA
+SVGA_MODE=	-DSVGA_MODE=3
 
 # Special options.
 #OPTS	= -pro
@@ -58,6 +57,8 @@
 
 ifdef CONFIG_M486
 CFLAGS := $(CFLAGS) -m486
+else
+CFLAGS := $(CFLAGS) -m386
 endif
 
 #
@@ -114,14 +115,13 @@
 
 config:
 	$(CONFIG_SHELL) Configure $(OPTS) < config.in
+	@if grep -s '^CONFIG_SOUND' .config~ ; then \
+		$(MAKE) -C drivers/sound config; \
+		else : ; fi
 	mv .config~ .config
-	$(MAKE) soundconf
-
-soundconf:
-	cd drivers/sound;$(MAKE) config
 
 linuxsubdirs: dummy
-	@for i in $(SUBDIRS); do (cd $$i && echo $$i && $(MAKE)) || exit; done
+	set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i; done
 
 tools/./version.h: tools/version.h
 
@@ -149,7 +149,7 @@
 	$(CC) $(CFLAGS) $(PROFILING) -c -o $*.o $<
 
 tools/system:	boot/head.o init/main.o tools/version.o linuxsubdirs
-	$(LD) $(LDFLAGS) -M boot/head.o init/main.o tools/version.o \
+	$(LD) $(LDFLAGS) -T 1000 -M boot/head.o init/main.o tools/version.o \
 		$(ARCHIVES) \
 		$(FILESYSTEMS) \
 		$(DRIVERS) \
@@ -171,7 +171,7 @@
 	$(LD86) -s -o boot/bootsect boot/bootsect.o
 
 zBoot/zSystem: zBoot/*.c zBoot/*.S tools/zSystem
-	cd zBoot;$(MAKE)
+	$(MAKE) -C zBoot
 
 zImage: $(CONFIGURE) boot/bootsect boot/setup zBoot/zSystem tools/build
 	tools/build boot/bootsect boot/setup zBoot/zSystem $(ROOT_DEV) > zImage
@@ -209,16 +209,21 @@
 drivers: dummy
 	$(MAKE) linuxsubdirs SUBDIRS=drivers
 
+net: dummy
+	$(MAKE) linuxsubdirs SUBDIRS=net
+
 clean:
 	rm -f core `find . -name '*.[oas]' -print`
+	rm -f core `find . -name 'core' -print`
 	rm -f zImage zSystem.map tools/zSystem tools/system
-	rm -f Image System.map boot/bootsect boot/setup \
-		boot/bootsect.s boot/setup.s boot/head.s init/main.s
+	rm -f Image System.map boot/bootsect boot/setup
+	rm -f zBoot/zSystem zBoot/xtract zBoot/piggyback
+	rm -f drivers/sound/configure
 	rm -f init/*.o tools/build boot/*.o tools/*.o
-	for i in zBoot $(SUBDIRS); do (cd $$i && $(MAKE) clean); done
 
 mrproper: clean
 	rm -f include/linux/autoconf.h tools/version.h
+	rm -f drivers/sound/local.h
 	rm -f .version .config* config.old
 	rm -f .depend `find . -name .depend -print`
 
@@ -232,7 +237,7 @@
 	touch tools/version.h
 	for i in init/*.c;do echo -n "init/";$(CPP) -M $$i;done > .depend~
 	for i in tools/*.c;do echo -n "tools/";$(CPP) -M $$i;done >> .depend~
-	for i in $(SUBDIRS); do (cd $$i && $(MAKE) dep) || exit; done
+	set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i dep; done
 	rm -f tools/version.h
 	mv .depend~ .depend
 
diff --git a/boot/bootsect.S b/boot/bootsect.S
index 610acac..261d5a1 100644
--- a/boot/bootsect.S
+++ b/boot/bootsect.S
@@ -1,7 +1,7 @@
 !
 ! SYS_SIZE is the number of clicks (16 bytes) to be loaded.
-! 0x3000 is 0x30000 bytes = 196kB, more than enough for current
-! versions of linux
+! 0x7F00 is 0x7F000 bytes = 508kB, more than enough for current
+! versions of linux which compress the kernel
 !
 #include <linux/config.h>
 SYSSIZE = DEF_SYSSIZE
@@ -19,10 +19,11 @@
 ! It then loads 'setup' directly after itself (0x90200), and the system
 ! at 0x10000, using BIOS interrupts. 
 !
-! NOTE! currently system is at most 8*65536 bytes long. This should be no
-! problem, even in the future. I want to keep it simple. This 512 kB
+! NOTE! currently system is at most (8*65536-4096) bytes long. This should 
+! be no problem, even in the future. I want to keep it simple. This 508 kB
 ! kernel size should be enough, especially as this doesn't contain the
-! buffer cache as in minix
+! buffer cache as in minix (and especially now that the kernel is 
+! compressed :-)
 !
 ! The loader has been made as simple as possible, and continuos
 ! read errors will result in a unbreakable loop. Reboot by hand. It
diff --git a/boot/head.S b/boot/head.S
index 322f198..3caf93f 100644
--- a/boot/head.S
+++ b/boot/head.S
@@ -25,7 +25,8 @@
 #define CL_OFFSET	0x90022
 
 /*
- * swapper_pg_dir is the main page directory, address 0x00001000
+ * swapper_pg_dir is the main page directory, address 0x00001000 (or at
+ * address 0x00101000 for a compressed boot).
  */
 startup_32:
 	cld
@@ -237,6 +238,12 @@
 /*
  * page 0 is made non-existent, so that kernel NULL pointer references get
  * caught. Thus the swapper page directory has been moved to 0x1000
+ *
+ * XXX Actually, the swapper page directory is at 0x1000 plus 1 megabyte,
+ * with the introduction of the compressed boot code.  Theoretically,
+ * the original design of overlaying the startup code with the swapper
+ * page directory is still possible --- it would reduce the size of the kernel
+ * by 2-3k.  This would be a good thing to do at some point.....
  */
 .org 0x1000
 _swapper_pg_dir:
diff --git a/boot/setup.S b/boot/setup.S
index c775ead..2ba710f 100644
--- a/boot/setup.S
+++ b/boot/setup.S
@@ -152,19 +152,21 @@
 	mov	al,#0x80	! disable NMI for the bootup sequence
 	out	#0x70,al
 
-! first we move the system to it's rightful place
+! first we move the system to its rightful place
 
-	xor	ax,ax		! clear ax
+	mov	ax,#0x100	! start of destination segment
+	mov	bx,#0x1000	! start of source segment
 	cld			! 'direction'=0, movs moves forward
 do_move:
 	mov	es,ax		! destination segment
-	add	ax,#0x1000
+	add	ax,#0x100
 	cmp	ax,#0x9000
 	jz	end_move
-	mov	ds,ax		! source segment
+	mov	ds,bx		! source segment
+	add	bx,#0x100
 	sub	di,di
 	sub	si,si
-	mov 	cx,#0x8000
+	mov 	cx,#0x800
 	rep
 	movsw
 	jmp	do_move
@@ -248,7 +250,7 @@
 	lmsw	ax		! This is it!
 	jmp	flush_instr
 flush_instr:
-	jmpi	0,KERNEL_CS	! jmp offset 0 of segment 0x10 (cs)
+	jmpi	0x1000,KERNEL_CS	! jmp offset 1000 of segment 0x10 (cs)
 
 ! This routine checks that the keyboard command queue is empty
 ! (after emptying the output buffers)
@@ -392,7 +394,17 @@
 	mov	ax,#0x501c	! return 80x28
 	ret
 /* svga modes */
-svga:	cld	
+svga:   cld
+        lea     si,id9GXE	! Check for the #9GXE (jyanowit@orixa.mtholyoke.edu,thanks dlm40629@uxa.cso.uiuc.edu)
+        mov     di,#0x49	! id string is at c000:049
+        mov     cx,#0x11	! length of "Graphics Power By"
+        repe
+        cmpsb
+        jne     of1280
+is9GXE:	lea 	si,dsc9GXE	! table of descriptions of video modes for BIOS
+	lea	di,mo9GXE	! table of sizes of video modes for my BIOS
+	br	selmod		! go ask for video mode
+of1280:	cld	
 	lea	si,idf1280	! Check for Orchid F1280 (dingbat@diku.dk)
 	mov	di,#0x10a	! id string is at c000:010a
 	mov	cx,#0x21	! length
@@ -806,6 +818,7 @@
 idparadise:	.ascii	"VGA="
 idoakvga:	.ascii  "OAK VGA "
 idf1280:	.ascii	"Orchid Technology Fahrenheit 1280"
+id9GXE:		.ascii  "Graphics Power By"
 idVRAM:		.ascii	"Stealth VRAM"
 
 ! Manufacturer:	  Numofmodes+2:	Mode:
@@ -823,6 +836,7 @@
 motseng:	.byte	0x07,	0x26, 0x2a, 0x23, 0x24, 0x22
 movideo7:	.byte	0x08,	0x40, 0x43, 0x44, 0x41, 0x42, 0x45
 mooakvga:	.byte   0x08,   0x00, 0x07, 0x4e, 0x4f, 0x50, 0x51
+mo9GXE:		.byte	0x04,	0x54, 0x55
 mof1280:	.byte	0x04,	0x54, 0x55
 mounknown:	.byte	0x02
 
@@ -842,6 +856,7 @@
 dscvideo7:	.word	0x5032, 0x501c, 0x502b, 0x503c, 0x643c, 0x8419, 0x842c, 0x841c
 dscoakvga:	.word   0x5032, 0x501c, 0x2819, 0x5019, 0x503c, 0x843c, 0x8419, 0x842b
 dscf1280:	.word	0x5032, 0x501c, 0x842b, 0x8419
+dsc9GXE:	.word	0x5032, 0x501c, 0x842b, 0x8419
 dsunknown:	.word	0x5032, 0x501c
 modesave:	.word	SVGA_MODE
 
diff --git a/config.in b/config.in
index 0eb6046..e2c431a 100644
--- a/config.in
+++ b/config.in
@@ -5,11 +5,11 @@
 *
 * General setup
 *
-bool 'Kernel math emulation' CONFIG_MATH_EMULATION n
+bool 'Kernel math emulation' CONFIG_MATH_EMULATION y
 bool 'Normal harddisk support' CONFIG_BLK_DEV_HD y
 bool 'XT harddisk support' CONFIG_BLK_DEV_XD n
 bool 'TCP/IP networking' CONFIG_INET y
-bool 'Limit memory to low 16MB' CONFIG_MAX_16M y
+bool 'Limit memory to low 16MB' CONFIG_MAX_16M n
 bool 'System V IPC' CONFIG_SYSVIPC y
 bool 'Use -m486 flag for 486-specific optimizations' CONFIG_M486 y
 *
@@ -49,30 +49,39 @@
 *
 * Network device support
 *
-bool 'Network device support?' CONFIG_ETHERCARDS n
+bool 'Network device support?' CONFIG_ETHERCARDS y
 if [ "$CONFIG_ETHERCARDS" = "n" ]
 :
 : Skipping ethercard configuration options...
 :
 else
 bool 'SLIP (serial line) support' CONFIG_SLIP n
+if [ "$CONFIG_SLIP" = "y" ]
+  bool ' CSLIP compressed headers' SL_COMPRESSED y
+  bool ' SLIP debugging on' SL_DUMP y
+fi
+#bool 'PPP (point-to-point) support' CONFIG_PPP n
 bool 'PLIP (parallel port) support' CONFIG_PLIP n
 bool 'NE2000/NE1000 support' CONFIG_NE2000 n
 bool 'WD80*3 support' CONFIG_WD80x3 y
 bool 'SMC Ultra support' CONFIG_ULTRA n
 bool '3c501 support' CONFIG_EL1 n
 bool '3c503 support' CONFIG_EL2 n
+#bool '3c505 support' CONFIG_ELPLUS n
 #bool '3c507 support' CONFIG_EL16 n
-bool '3c509 support' CONFIG_EL3 n
+bool '3c509/3c579 support' CONFIG_EL3 n
 bool 'HP PCLAN support' CONFIG_HPLAN n
-bool 'AT1500 and NE2100 support' CONFIG_AT1500 n
-bool 'D-Link DE600 pocket adaptor support' CONFIG_DE600 n
+bool 'AT1500 and NE2100 (LANCE and PCnet-ISA) support' CONFIG_LANCE n
+bool 'AT1700 support' CONFIG_AT1700 n
 #bool 'Zenith Z-Note support' CONFIG_ZNET n
 #bool 'EtherExpress support' CONFIG_EEXPRESS n
 #bool 'DEPCA support' CONFIG_DEPCA n
 #bool 'NI52** support' CONFIG_NI52 n
 #bool 'NI65** support' CONFIG_NI65 n
-#bool 'AT-LAN-TEC pocket adaptor support' CONFIG_ATP n
+#bool 'Ansel Communications EISA 3200 support' CONFIG_AC3200 n
+#bool 'Cabletron E21xx support (not recommended)' CONFIG_E21 n
+bool 'D-Link DE600 pocket adaptor support' CONFIG_DE600 n
+#bool 'AT-LAN-TEC/RealTek pocket adaptor support' CONFIG_ATP n
 fi
 *
 bool 'Sony CDU31A CDROM driver support' CONFIG_CDU31A n
@@ -88,16 +97,17 @@
 bool '/proc filesystem support' CONFIG_PROC_FS y
 bool 'NFS filesystem support' CONFIG_NFS_FS y
 bool 'ISO9660 cdrom filesystem support' CONFIG_ISO9660_FS n
+bool 'OS/2 HPFS filesystem support (read only)' CONFIG_HPFS_FS n
 *
 *  character devices
 *
 bool 'Keyboard meta-key sends ESC-prefix' CONFIG_KBD_META y
-bool 'Keyboard Num Lock on by default' CONFIG_KBD_NUML n
+bool 'Keyboard Num Lock on by default' CONFIG_KBD_NUML y
 bool 'Parallel printer support' CONFIG_PRINTER y
 bool 'Logitech busmouse support' CONFIG_BUSMOUSE n
-bool 'QuickPort mouse support' CONFIG_QUICKPORT_MOUSE n
-if [ "$CONFIG_QUICKPORT_MOUSE" = "n" ]
 bool 'PS/2 mouse (aka "auxiliary device") support' CONFIG_PSMOUSE y
+if [ "$CONFIG_PSMOUSE" = "y" ]
+bool 'C&T 82C710 mouse port support (as on TI Travelmate)' CONFIG_82C710_MOUSE y
 fi
 bool 'Microsoft busmouse support' CONFIG_MS_BUSMOUSE n
 bool 'ATIXL busmouse support' CONFIG_ATIXL_BUSMOUSE n
@@ -106,12 +116,17 @@
 *
 * Sound
 *
-bool 'Sound card support (distributed separately)' CONFIG_SOUND n
+bool 'Sound card support' CONFIG_SOUND n
 *
 * Kernel hacking
 *
-bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC n
+#bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC n
 bool 'Kernel profiling support' CONFIG_PROFILE n
 if [ "$CONFIG_SCSI" = "y" ]
 bool 'Verbose scsi error reporting (kernel size +=12K)' CONFIG_SCSI_CONSTANTS y
 fi
+if [ "$CONFIG_SOUND" = "y" ]
+  exec touch .makesound
+else
+  exec rm -f .makesound
+fi
diff --git a/drivers/FPU-emu/Makefile b/drivers/FPU-emu/Makefile
index 13f619c..78ebb64 100644
--- a/drivers/FPU-emu/Makefile
+++ b/drivers/FPU-emu/Makefile
@@ -4,13 +4,14 @@
 
 #DEBUG	= -DDEBUGGING
 DEBUG	=
+REENTRANT	= -DREENTRANT_FPU
 CFLAGS	:= $(CFLAGS) -DPARANOID $(DEBUG) -fno-builtin
 
 .c.o:
 	$(CC) $(CFLAGS) $(MATH_EMULATION) -c $<
 
 .S.o:
-	$(CC) -D__ASSEMBLER__ -c $<
+	$(CC) -D__ASSEMBLER__ $(REENTRANT) -c $<
 
 .s.o:
 	$(CC) -c $<
@@ -31,9 +32,6 @@
 	$(AR) rcs math.a $(OBJS)
 	sync
 
-clean:
-	rm -f core *.o *.a *.s
-
 dep:
 	$(CPP) -M *.c > .depend
 	$(CPP) -D__ASSEMBLER__ -M *.S >> .depend
diff --git a/drivers/FPU-emu/README b/drivers/FPU-emu/README
index a000e4f..0b1a6f3 100644
--- a/drivers/FPU-emu/README
+++ b/drivers/FPU-emu/README
@@ -3,7 +3,7 @@
  |                                                                           |
  | Copyright (C) 1992,1993                                                   |
  |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
- |                       Australia.  E-mail apm233m@vaxc.cc.monash.edu.au    |
+ |                       Australia.  E-mail   billm@vaxc.cc.monash.edu.au    |
  |                                                                           |
  |    This program is free software; you can redistribute it and/or modify   |
  |    it under the terms of the GNU General Public License version 2 as      |
@@ -41,11 +41,13 @@
 See "Limitations" later in this file for a list of some differences.
 
 Please report bugs, etc to me at:
-       apm233m@vaxc.cc.monash.edu.au
+       billm@vaxc.cc.monash.edu.au
+  or at:
+       billm@jacobi.maths.monash.edu.au
 
 
 --Bill Metzenthen
-  July 1993
+  Sept 1993
 
 
 ----------------------- Internals of wm-FPU-emu -----------------------
diff --git a/drivers/FPU-emu/control_w.h b/drivers/FPU-emu/control_w.h
index 42bb1bf..6830321 100644
--- a/drivers/FPU-emu/control_w.h
+++ b/drivers/FPU-emu/control_w.h
@@ -3,7 +3,7 @@
  |                                                                           |
  | Copyright (C) 1992,1993                                                   |
  |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
- |                       Australia.  E-mail apm233m@vaxc.cc.monash.edu.au    |
+ |                       Australia.  E-mail   billm@vaxc.cc.monash.edu.au    |
  |                                                                           |
  +---------------------------------------------------------------------------*/
 
diff --git a/drivers/FPU-emu/div_small.S b/drivers/FPU-emu/div_small.S
index 0e3b71e..0225a96 100644
--- a/drivers/FPU-emu/div_small.S
+++ b/drivers/FPU-emu/div_small.S
@@ -5,7 +5,7 @@
  | Divide a 64 bit integer by a 32 bit integer & return remainder.           |
  |                                                                           |
  | Copyright (C) 1992    W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
- |                       Australia.  E-mail apm233m@vaxc.cc.monash.edu.au    |
+ |                       Australia.  E-mail   billm@vaxc.cc.monash.edu.au    |
  |                                                                           |
  |                                                                           |
  +---------------------------------------------------------------------------*/
diff --git a/drivers/FPU-emu/errors.c b/drivers/FPU-emu/errors.c
index 444a8af..cd3c03a 100644
--- a/drivers/FPU-emu/errors.c
+++ b/drivers/FPU-emu/errors.c
@@ -5,7 +5,7 @@
  |                                                                           |
  | Copyright (C) 1992,1993                                                   |
  |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
- |                       Australia.  E-mail apm233m@vaxc.cc.monash.edu.au    |
+ |                       Australia.  E-mail   billm@vaxc.cc.monash.edu.au    |
  |                                                                           |
  |                                                                           |
  +---------------------------------------------------------------------------*/
@@ -42,8 +42,8 @@
   byte1 = get_fs_byte((unsigned char *) FPU_ORIG_EIP);
   FPU_modrm = get_fs_byte(1 + (unsigned char *) FPU_ORIG_EIP);
 
-  printk("Unimplemented FPU Opcode at eip=%08x : %02x ",
-	 FPU_ORIG_EIP, byte1);
+  printk("Unimplemented FPU Opcode at eip=%p : %02x ",
+	 (void *) FPU_ORIG_EIP, byte1);
 
   if (FPU_modrm >= 0300)
     printk("%02x (%02x+%d)\n", FPU_modrm, FPU_modrm & 0xf8, FPU_modrm & 7);
@@ -86,14 +86,14 @@
 if ( partial_status & SW_Invalid )     printk("SW: invalid operation\n");
 #endif DEBUGGING
 
-  printk("At %08x: %02x ", FPU_ORIG_EIP, byte1);
+  printk("At %p: %02x ", (void *) FPU_ORIG_EIP, byte1);
   if (FPU_modrm >= 0300)
     printk("%02x (%02x+%d)\n", FPU_modrm, FPU_modrm & 0xf8, FPU_modrm & 7);
   else
     printk("/%d, mod=%d rm=%d\n",
 	   (FPU_modrm >> 3) & 7, (FPU_modrm >> 6) & 3, FPU_modrm & 7);
 
-  printk(" SW: b=%d st=%d es=%d sf=%d cc=%d%d%d%d ef=%d%d%d%d%d%d\n",
+  printk(" SW: b=%d st=%ld es=%d sf=%d cc=%d%d%d%d ef=%d%d%d%d%d%d\n",
 	 partial_status & 0x8000 ? 1 : 0,   /* busy */
 	 (partial_status & 0x3800) >> 11,   /* stack top pointer */
 	 partial_status & 0x80 ? 1 : 0,     /* Error summary status */
@@ -104,7 +104,7 @@
 	 partial_status & SW_Overflow?1:0, partial_status & SW_Zero_Div?1:0,
 	 partial_status & SW_Denorm_Op?1:0, partial_status & SW_Invalid?1:0);
   
-printk(" CW: ic=%d rc=%d%d pc=%d%d iem=%d     ef=%d%d%d%d%d%d\n",
+printk(" CW: ic=%d rc=%ld%ld pc=%ld%ld iem=%d     ef=%d%d%d%d%d%d\n",
 	 control_word & 0x1000 ? 1 : 0,
 	 (control_word & 0x800) >> 11, (control_word & 0x400) >> 10,
 	 (control_word & 0x200) >> 9, (control_word & 0x100) >> 8,
@@ -131,7 +131,7 @@
 	case TW_NaN:
 /*	case TW_Denormal: */
 	case TW_Infinity:
-	  printk("st(%d)  %c .%04x %04x %04x %04x e%+-6d ", i,
+	  printk("st(%d)  %c .%04lx %04lx %04lx %04lx e%+-6ld ", i,
 		 r->sign ? '-' : '+',
 		 (long)(r->sigh >> 16),
 		 (long)(r->sigh & 0xFFFF),
@@ -146,7 +146,7 @@
       printk("%s\n", tag_desc[(int) (unsigned) r->tag]);
     }
 
-  printk("[data] %c .%04x %04x %04x %04x e%+-6d ",
+  printk("[data] %c .%04lx %04lx %04lx %04lx e%+-6ld ",
 	 FPU_loaded_data.sign ? '-' : '+',
 	 (long)(FPU_loaded_data.sigh >> 16),
 	 (long)(FPU_loaded_data.sigh & 0xFFFF),
@@ -312,9 +312,9 @@
 
 /* Real operation attempted on two operands, one a NaN. */
 /* Returns nz if the exception is unmasked */
-asmlinkage int real_2op_NaN(FPU_REG *a, FPU_REG *b, FPU_REG *dest)
+asmlinkage int real_2op_NaN(FPU_REG const *a, FPU_REG const *b, FPU_REG *dest)
 {
-  FPU_REG *x;
+  FPU_REG const *x;
   int signalling;
 
   /* The default result for the case of two "equal" NaNs (signs may
diff --git a/drivers/FPU-emu/exception.h b/drivers/FPU-emu/exception.h
index 7f90ede..2e629a3 100644
--- a/drivers/FPU-emu/exception.h
+++ b/drivers/FPU-emu/exception.h
@@ -2,7 +2,7 @@
  |  exception.h                                                              |
  |                                                                           |
  | Copyright (C) 1992    W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
- |                       Australia.  E-mail apm233m@vaxc.cc.monash.edu.au    |
+ |                       Australia.  E-mail   billm@vaxc.cc.monash.edu.au    |
  |                                                                           |
  +---------------------------------------------------------------------------*/
 
diff --git a/drivers/FPU-emu/fpu_arith.c b/drivers/FPU-emu/fpu_arith.c
index 471d2c6..3871a56 100644
--- a/drivers/FPU-emu/fpu_arith.c
+++ b/drivers/FPU-emu/fpu_arith.c
@@ -5,7 +5,7 @@
  |                                                                           |
  | Copyright (C) 1992,1993                                                   |
  |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
- |                       Australia.  E-mail apm233m@vaxc.cc.monash.edu.au    |
+ |                       Australia.  E-mail   billm@vaxc.cc.monash.edu.au    |
  |                                                                           |
  |                                                                           |
  +---------------------------------------------------------------------------*/
diff --git a/drivers/FPU-emu/fpu_asm.h b/drivers/FPU-emu/fpu_asm.h
index b20a123..8eb6014 100644
--- a/drivers/FPU-emu/fpu_asm.h
+++ b/drivers/FPU-emu/fpu_asm.h
@@ -2,7 +2,7 @@
  |  fpu_asm.h                                                                |
  |                                                                           |
  | Copyright (C) 1992    W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
- |                       Australia.  E-mail apm233m@vaxc.cc.monash.edu.au    |
+ |                       Australia.  E-mail   billm@vaxc.cc.monash.edu.au    |
  |                                                                           |
  +---------------------------------------------------------------------------*/
 
diff --git a/drivers/FPU-emu/fpu_aux.c b/drivers/FPU-emu/fpu_aux.c
index 90301a4..c18194a 100644
--- a/drivers/FPU-emu/fpu_aux.c
+++ b/drivers/FPU-emu/fpu_aux.c
@@ -5,7 +5,7 @@
  |                                                                           |
  | Copyright (C) 1992,1993                                                   |
  |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
- |                       Australia.  E-mail apm233m@vaxc.cc.monash.edu.au    |
+ |                       Australia.  E-mail   billm@vaxc.cc.monash.edu.au    |
  |                                                                           |
  |                                                                           |
  +---------------------------------------------------------------------------*/
@@ -47,7 +47,7 @@
   FPU_entry_eip = ip_offset = 0;
 }
 
-static FUNC finit_table[] = {
+static FUNC const finit_table[] = {
   Un_impl, Un_impl, fclex, finit, Un_impl, Un_impl, Un_impl, Un_impl
 };
 
@@ -63,7 +63,7 @@
   NO_NET_INSTR_EFFECT;
 }
 
-static FUNC fstsw_table[] = {
+static FUNC const fstsw_table[] = {
   fstsw_ax, Un_impl, Un_impl, Un_impl, Un_impl, Un_impl, Un_impl, Un_impl
 };
 
@@ -78,7 +78,7 @@
 {
 }
 
-FUNC fp_nop_table[] = {
+static FUNC const fp_nop_table[] = {
   fnop, Un_impl, Un_impl, Un_impl, Un_impl, Un_impl, Un_impl, Un_impl
 };
 
diff --git a/drivers/FPU-emu/fpu_emu.h b/drivers/FPU-emu/fpu_emu.h
index 7b871fd..6d7c2db 100644
--- a/drivers/FPU-emu/fpu_emu.h
+++ b/drivers/FPU-emu/fpu_emu.h
@@ -3,7 +3,7 @@
  |                                                                           |
  | Copyright (C) 1992,1993                                                   |
  |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
- |                       Australia.  E-mail apm233m@vaxc.cc.monash.edu.au    |
+ |                       Australia.  E-mail   billm@vaxc.cc.monash.edu.au    |
  |                                                                           |
  +---------------------------------------------------------------------------*/
 
@@ -117,25 +117,25 @@
 /*----- Prototypes for functions written in assembler -----*/
 /* extern void reg_move(FPU_REG *a, FPU_REG *b); */
 
-asmlinkage void mul64(unsigned long long *a, unsigned long long *b,
+asmlinkage void mul64(unsigned long long const *a, unsigned long long const *b,
 		      unsigned long long *result);
 asmlinkage void poly_div2(unsigned long long *x);
 asmlinkage void poly_div4(unsigned long long *x);
 asmlinkage void poly_div16(unsigned long long *x);
-asmlinkage void polynomial(unsigned accum[], unsigned x[],
-		       unsigned short terms[][4], int n);
+asmlinkage void polynomial(unsigned accum[], unsigned const x[],
+		       unsigned short const terms[][4], int const n);
 asmlinkage void normalize(FPU_REG *x);
 asmlinkage void normalize_nuo(FPU_REG *x);
-asmlinkage int reg_div(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *answ,
-		    unsigned int control_w);
-asmlinkage int reg_u_sub(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *answ,
-		      unsigned int control_w);
-asmlinkage int reg_u_mul(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *answ,
-		      unsigned int control_w);
-asmlinkage int reg_u_div(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *answ,
-		      unsigned int control_w);
-asmlinkage int reg_u_add(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *answ,
-		      unsigned int control_w);
+asmlinkage int reg_div(FPU_REG const *arg1, FPU_REG const *arg2,
+		       FPU_REG *answ, unsigned int control_w);
+asmlinkage int reg_u_sub(FPU_REG const *arg1, FPU_REG const *arg2,
+			 FPU_REG *answ, unsigned int control_w);
+asmlinkage int reg_u_mul(FPU_REG const *arg1, FPU_REG const *arg2,
+			 FPU_REG *answ, unsigned int control_w);
+asmlinkage int reg_u_div(FPU_REG const *arg1, FPU_REG const *arg2,
+			 FPU_REG *answ, unsigned int control_w);
+asmlinkage int reg_u_add(FPU_REG const *arg1, FPU_REG const *arg2,
+			 FPU_REG *answ, unsigned int control_w);
 asmlinkage int wm_sqrt(FPU_REG *n, unsigned int control_w);
 asmlinkage unsigned	shrx(void *l, unsigned x);
 asmlinkage unsigned	shrxs(void *v, unsigned x);
diff --git a/drivers/FPU-emu/fpu_entry.c b/drivers/FPU-emu/fpu_entry.c
index 3ae0ff4..d511a1f 100644
--- a/drivers/FPU-emu/fpu_entry.c
+++ b/drivers/FPU-emu/fpu_entry.c
@@ -5,7 +5,7 @@
  |                                                                           |
  | Copyright (C) 1992,1993                                                   |
  |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
- |                       Australia.  E-mail apm233m@vaxc.cc.monash.edu.au    |
+ |                       Australia.  E-mail   billm@vaxc.cc.monash.edu.au    |
  |                                                                           |
  | See the files "README" and "COPYING" for further copyright and warranty   |
  | information.                                                              |
@@ -63,7 +63,7 @@
 #define _df_d0_ fstp_i    /* unofficial code (17) */
 #define _df_d8_ fstp_i    /* unofficial code (1f) */
 
-static FUNC st_instr_table[64] = {
+static FUNC const st_instr_table[64] = {
   fadd__,   fld_i_,  __BAD__, __BAD__, fadd_i,  ffree_,  faddp_,  _df_c0_,
   fmul__,   fxch_i,  __BAD__, __BAD__, fmul_i,  _dd_c8_, fmulp_,  _df_c8_,
   fcom_st,  fp_nop,  __BAD__, __BAD__, _dc_d0_, fst_i_,  _de_d0_, _df_d0_,
@@ -76,7 +76,7 @@
 
 #else     /* Support only documented FPU op-codes */
 
-static FUNC st_instr_table[64] = {
+static FUNC const st_instr_table[64] = {
   fadd__,   fld_i_,  __BAD__, __BAD__, fadd_i,  ffree_,  faddp_,  __BAD__,
   fmul__,   fxch_i,  __BAD__, __BAD__, fmul_i,  __BAD__, fmulp_,  __BAD__,
   fcom_st,  fp_nop,  __BAD__, __BAD__, __BAD__, fst_i_,  __BAD__, __BAD__,
@@ -105,7 +105,7 @@
 
 /* Un-documented FPU op-codes supported by default. (see above) */
 
-static unsigned char type_table[64] = {
+static unsigned char const type_table[64] = {
   _REGI_, _NONE_, _null_, _null_, _REGIi, _REGi_, _REGIp, _REGi_,
   _REGI_, _REGIn, _null_, _null_, _REGIi, _REGI_, _REGIp, _REGI_,
   _REGIc, _NONE_, _null_, _null_, _REGIc, _REG0_, _REGIc, _REG0_,
@@ -118,7 +118,7 @@
 
 #else     /* Support only documented FPU op-codes */
 
-static unsigned char type_table[64] = {
+static unsigned char const type_table[64] = {
   _REGI_, _NONE_, _null_, _null_, _REGIi, _REGi_, _REGIp, _null_,
   _REGI_, _REGIn, _null_, _null_, _REGIi, _null_, _REGIp, _null_,
   _REGIc, _NONE_, _null_, _null_, _null_, _REG0_, _null_, _null_,
@@ -189,12 +189,19 @@
     }
 
   /* user code space? */
-  if (FPU_CS != USER_CS)
+  if (FPU_CS == KERNEL_CS)
     {
-      printk("math_emulate: %04x:%08x\n",FPU_CS,FPU_EIP);
+      printk("math_emulate: %04x:%08lx\n",FPU_CS,FPU_EIP);
       panic("Math emulation needed in kernel");
     }
 
+  /* We cannot handle multiple segments yet */
+  if (FPU_CS != USER_CS || FPU_DS != USER_DS)
+    {
+      FPU_ORIG_EIP = FPU_EIP;
+      math_abort(FPU_info,SIGILL);
+    }
+
   FPU_lookahead = 1;
   if (current->flags & PF_PTRACED)
   	FPU_lookahead = 0;
@@ -523,6 +530,14 @@
 
 FPU_instruction_done:
 
+#ifdef DEBUG
+  { /* !!!!!!!!!!! */
+    static unsigned int count = 0;
+    if ( (++count % 10000) == 0 )
+	printk("%d FP instr., current=0x%04x\n", count, code);
+  } /* !!!!!!!!!!! */
+#endif DEBUG
+
   ip_offset = FPU_entry_eip;
   cs_selector = FPU_entry_op_cs;
   data_operand_offset = (unsigned long)FPU_data_address;
diff --git a/drivers/FPU-emu/fpu_etc.c b/drivers/FPU-emu/fpu_etc.c
index 7c4535f..d667759 100644
--- a/drivers/FPU-emu/fpu_etc.c
+++ b/drivers/FPU-emu/fpu_etc.c
@@ -5,7 +5,7 @@
  |                                                                           |
  | Copyright (C) 1992,1993                                                   |
  |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
- |                       Australia.  E-mail apm233m@vaxc.cc.monash.edu.au    |
+ |                       Australia.  E-mail   billm@vaxc.cc.monash.edu.au    |
  |                                                                           |
  |                                                                           |
  +---------------------------------------------------------------------------*/
@@ -117,7 +117,7 @@
   setcc(c);
 }
 
-static FUNC fp_etc_table[] = {
+static FUNC const fp_etc_table[] = {
   fchs, fabs, Un_impl, Un_impl, ftst_, fxam, Un_impl, Un_impl
 };
 
diff --git a/drivers/FPU-emu/fpu_proto.h b/drivers/FPU-emu/fpu_proto.h
index b7e7032..c10a4b2 100644
--- a/drivers/FPU-emu/fpu_proto.h
+++ b/drivers/FPU-emu/fpu_proto.h
@@ -7,7 +7,7 @@
 extern void stack_underflow_pop(int i);
 extern int set_precision_flag(int flags);
 asmlinkage void exception(int n);
-asmlinkage int real_2op_NaN(FPU_REG *a, FPU_REG *b, FPU_REG *dest);
+asmlinkage int real_2op_NaN(FPU_REG const *a, FPU_REG const *b, FPU_REG *dest);
 asmlinkage int arith_invalid(FPU_REG *dest);
 asmlinkage int divide_by_zero(int sign, FPU_REG *dest);
 asmlinkage void set_precision_flag_up(void);
@@ -57,7 +57,7 @@
 extern void fp_etc(void);
 
 /* fpu_trig.c */
-extern void convert_l2reg(long *arg, FPU_REG *dest);
+extern void convert_l2reg(long const *arg, FPU_REG *dest);
 extern void trig_a(void);
 extern void trig_b(void);
 
@@ -68,28 +68,30 @@
 extern void load_store_instr(char type);
 
 /* poly_2xm1.c */
-extern int poly_2xm1(FPU_REG *arg, FPU_REG *result);
+extern int poly_2xm1(FPU_REG const *arg, FPU_REG *result);
 
 /* poly_atan.c */
 extern void poly_atan(FPU_REG *arg);
 extern void poly_add_1(FPU_REG *src);
 
 /* poly_l2.c */
-extern void poly_l2(FPU_REG *arg, FPU_REG *result);
-extern int poly_l2p1(FPU_REG *arg, FPU_REG *result);
+extern void poly_l2(FPU_REG const *arg, FPU_REG *result);
+extern int poly_l2p1(FPU_REG const *arg, FPU_REG *result);
 
 /* poly_sin.c */
-extern void poly_sine(FPU_REG *arg, FPU_REG *result);
+extern void poly_sine(FPU_REG const *arg, FPU_REG *result);
 
 /* poly_tan.c */
-extern void poly_tan(FPU_REG *arg, FPU_REG *y_reg, int invert);
+extern void poly_tan(FPU_REG const *arg, FPU_REG *result, int invert);
 
 /* reg_add_sub.c */
-extern int reg_add(FPU_REG *a, FPU_REG *b, FPU_REG *dest, int control_w);
-extern int reg_sub(FPU_REG *a, FPU_REG *b, FPU_REG *dest, int control_w);
+extern int reg_add(FPU_REG const *a, FPU_REG const *b,
+		   FPU_REG *dest, int control_w);
+extern int reg_sub(FPU_REG const *a, FPU_REG const *b,
+		   FPU_REG *dest, int control_w);
 
 /* reg_compare.c */
-extern int compare(FPU_REG *b);
+extern int compare(FPU_REG const *b);
 extern int compare_st_data(void);
 extern void fcom_st(void);
 extern void fcompst(void);
@@ -124,4 +126,5 @@
 extern void fsave(void);
 
 /* reg_mul.c */
-extern int reg_mul(FPU_REG *a, FPU_REG *b, FPU_REG *dest, unsigned int control_w);
+extern int reg_mul(FPU_REG const *a, FPU_REG const *b,
+		   FPU_REG *dest, unsigned int control_w);
diff --git a/drivers/FPU-emu/fpu_system.h b/drivers/FPU-emu/fpu_system.h
index be6b0bb..e8e50c5 100644
--- a/drivers/FPU-emu/fpu_system.h
+++ b/drivers/FPU-emu/fpu_system.h
@@ -2,7 +2,7 @@
  |  fpu_system.h                                                             |
  |                                                                           |
  | Copyright (C) 1992    W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
- |                       Australia.  E-mail apm233m@vaxc.cc.monash.edu.au    |
+ |                       Australia.  E-mail   billm@vaxc.cc.monash.edu.au    |
  |                                                                           |
  +---------------------------------------------------------------------------*/
 
diff --git a/drivers/FPU-emu/fpu_trig.c b/drivers/FPU-emu/fpu_trig.c
index d20c4db..76db016 100644
--- a/drivers/FPU-emu/fpu_trig.c
+++ b/drivers/FPU-emu/fpu_trig.c
@@ -5,7 +5,7 @@
  |                                                                           |
  | Copyright (C) 1992,1993                                                   |
  |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
- |                       Australia.  E-mail apm233m@vaxc.cc.monash.edu.au    |
+ |                       Australia.  E-mail   billm@vaxc.cc.monash.edu.au    |
  |                                                                           |
  |                                                                           |
  +---------------------------------------------------------------------------*/
@@ -122,7 +122,7 @@
 
 
 /* Convert a long to register */
-void convert_l2reg(long *arg, FPU_REG *dest)
+void convert_l2reg(long const *arg, FPU_REG *dest)
 {
   long num = *arg;
 
@@ -1696,7 +1696,7 @@
 
 /*---------------------------------------------------------------------------*/
 
-static FUNC trig_table_a[] = {
+static FUNC const trig_table_a[] = {
   f2xm1, fyl2x, fptan, fpatan, fxtract, fprem1, fdecstp, fincstp
 };
 
@@ -1706,7 +1706,7 @@
 }
 
 
-static FUNC trig_table_b[] =
+static FUNC const trig_table_b[] =
   {
     fprem, fyl2xp1, fsqrt_, fsincos, frndint_, fscale, fsin, fcos
   };
diff --git a/drivers/FPU-emu/get_address.c b/drivers/FPU-emu/get_address.c
index 86ae753..98f97d6 100644
--- a/drivers/FPU-emu/get_address.c
+++ b/drivers/FPU-emu/get_address.c
@@ -5,7 +5,7 @@
  |                                                                           |
  | Copyright (C) 1992,1993                                                   |
  |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
- |                       Australia.  E-mail apm233m@vaxc.cc.monash.edu.au    |
+ |                       Australia.  E-mail   billm@vaxc.cc.monash.edu.au    |
  |                                                                           |
  |                                                                           |
  +---------------------------------------------------------------------------*/
diff --git a/drivers/FPU-emu/load_store.c b/drivers/FPU-emu/load_store.c
index 6e4b3d9..2966b07 100644
--- a/drivers/FPU-emu/load_store.c
+++ b/drivers/FPU-emu/load_store.c
@@ -6,7 +6,7 @@
  |                                                                           |
  | Copyright (C) 1992,1993                                                   |
  |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
- |                       Australia.  E-mail apm233m@vaxc.cc.monash.edu.au    |
+ |                       Australia.  E-mail   billm@vaxc.cc.monash.edu.au    |
  |                                                                           |
  |                                                                           |
  +---------------------------------------------------------------------------*/
@@ -35,7 +35,7 @@
 #define pop_0()	{ pop_ptr->tag = TW_Empty; top++; }
 
 
-static unsigned char type_table[32] = {
+static unsigned char const type_table[32] = {
   _PUSH_, _PUSH_, _PUSH_, _PUSH_,
   _null_, _null_, _null_, _null_,
   _REG0_, _REG0_, _REG0_, _REG0_,
diff --git a/drivers/FPU-emu/poly_2xm1.c b/drivers/FPU-emu/poly_2xm1.c
index 7e8aec7..4844aa7 100644
--- a/drivers/FPU-emu/poly_2xm1.c
+++ b/drivers/FPU-emu/poly_2xm1.c
@@ -5,7 +5,7 @@
  |                                                                           |
  | Copyright (C) 1992,1993                                                   |
  |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
- |                       Australia.  E-mail apm233m@vaxc.cc.monash.edu.au    |
+ |                       Australia.  E-mail   billm@vaxc.cc.monash.edu.au    |
  |                                                                           |
  |                                                                           |
  +---------------------------------------------------------------------------*/
@@ -17,7 +17,7 @@
 
 
 #define	HIPOWER	13
-static unsigned short	lterms[HIPOWER][4] =
+static unsigned short const	lterms[HIPOWER][4] =
 	{
 	{ 0x79b5, 0xd1cf, 0x17f7, 0xb172 },
 	{ 0x1b56, 0x058b, 0x7bff, 0x3d7f },
@@ -38,7 +38,7 @@
 /*--- poly_2xm1() -----------------------------------------------------------+
  | Requires a positive argument which is TW_Valid and < 1.                   |
  +---------------------------------------------------------------------------*/
-int	poly_2xm1(FPU_REG *arg, FPU_REG *result)
+int	poly_2xm1(FPU_REG const *arg, FPU_REG *result)
 {
   short		exponent;
   long long     Xll;
diff --git a/drivers/FPU-emu/poly_atan.c b/drivers/FPU-emu/poly_atan.c
index e0a0645..ea606f9 100644
--- a/drivers/FPU-emu/poly_atan.c
+++ b/drivers/FPU-emu/poly_atan.c
@@ -5,7 +5,7 @@
  |                                                                           |
  | Copyright (C) 1992,1993                                                   |
  |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
- |                       Australia.  E-mail apm233m@vaxc.cc.monash.edu.au    |
+ |                       Australia.  E-mail   billm@vaxc.cc.monash.edu.au    |
  |                                                                           |
  |                                                                           |
  +---------------------------------------------------------------------------*/
@@ -17,7 +17,7 @@
 
 
 #define	HIPOWERon	6	/* odd poly, negative terms */
-static unsigned oddnegterms[HIPOWERon][2] =
+static unsigned const oddnegterms[HIPOWERon][2] =
 {
   { 0x00000000, 0x00000000 }, /* for + 1.0 */
   { 0x763b6f3d, 0x1adc4428 },
@@ -28,7 +28,7 @@
 } ;
 
 #define	HIPOWERop	6	/* odd poly, positive terms */
-static unsigned	oddplterms[HIPOWERop][2] =
+static unsigned const	oddplterms[HIPOWERop][2] =
 {
   { 0xa6f67cb8, 0x94d910bd },
   { 0xa02ffab4, 0x0a43cb45 },
@@ -38,7 +38,7 @@
   { 0xf1dd2dbf, 0x000a530a }
 };
 
-static unsigned long long denomterm = 0xea2e6612fc4bd208LL;
+static unsigned long long const denomterm = 0xea2e6612fc4bd208LL;
 
 
 /*--- poly_atan() -----------------------------------------------------------+
diff --git a/drivers/FPU-emu/poly_div.S b/drivers/FPU-emu/poly_div.S
index cab7d72..a672933 100644
--- a/drivers/FPU-emu/poly_div.S
+++ b/drivers/FPU-emu/poly_div.S
@@ -5,7 +5,7 @@
  | A set of functions to divide 64 bit integers by fixed numbers.            |
  |                                                                           |
  | Copyright (C) 1992    W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
- |                       Australia.  E-mail apm233m@vaxc.cc.monash.edu.au    |
+ |                       Australia.  E-mail   billm@vaxc.cc.monash.edu.au    |
  |                                                                           |
  | Call from C as:                                                           |
  |   void poly_div2(unsigned long long *x)                                   |
diff --git a/drivers/FPU-emu/poly_l2.c b/drivers/FPU-emu/poly_l2.c
index 49085a0..6d36fef 100644
--- a/drivers/FPU-emu/poly_l2.c
+++ b/drivers/FPU-emu/poly_l2.c
@@ -5,7 +5,7 @@
  |                                                                           |
  | Copyright (C) 1992,1993                                                   |
  |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
- |                       Australia.  E-mail apm233m@vaxc.cc.monash.edu.au    |
+ |                       Australia.  E-mail   billm@vaxc.cc.monash.edu.au    |
  |                                                                           |
  |                                                                           |
  +---------------------------------------------------------------------------*/
@@ -19,7 +19,7 @@
 
 
 #define	HIPOWER	9
-static unsigned short	lterms[HIPOWER][4] =
+static unsigned short const	lterms[HIPOWER][4] =
 	{
 	/* Ideal computation with these coeffs gives about
 	   64.6 bit rel accuracy. */
@@ -40,7 +40,7 @@
 /*--- poly_l2() -------------------------------------------------------------+
  |   Base 2 logarithm by a polynomial approximation.                         |
  +---------------------------------------------------------------------------*/
-void	poly_l2(FPU_REG *arg, FPU_REG *result)
+void	poly_l2(FPU_REG const *arg, FPU_REG *result)
 {
   short		  exponent;
   char		  zero;		/* flag for an Xx == 0 */
@@ -224,7 +224,7 @@
  |   Base 2 logarithm by a polynomial approximation.                         |
  |   log2(x+1)                                                               |
  +---------------------------------------------------------------------------*/
-int	poly_l2p1(FPU_REG *arg, FPU_REG *result)
+int	poly_l2p1(FPU_REG const *arg, FPU_REG *result)
 {
   char		sign = 0;
   unsigned long long     Xsq;
diff --git a/drivers/FPU-emu/poly_mul64.S b/drivers/FPU-emu/poly_mul64.S
index 52fcee7..d62e24d 100644
--- a/drivers/FPU-emu/poly_mul64.S
+++ b/drivers/FPU-emu/poly_mul64.S
@@ -4,7 +4,7 @@
  | Multiply two 64 bit integers.                                             |
  |                                                                           |
  | Copyright (C) 1992    W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
- |                       Australia.  E-mail apm233m@vaxc.cc.monash.edu.au    |
+ |                       Australia.  E-mail   billm@vaxc.cc.monash.edu.au    |
  |                                                                           |
  | Call from C as:                                                           |
  |   void mul64(long long *a, long long *b, long long *result)               |
diff --git a/drivers/FPU-emu/poly_sin.c b/drivers/FPU-emu/poly_sin.c
index 5076741..b6a0507 100644
--- a/drivers/FPU-emu/poly_sin.c
+++ b/drivers/FPU-emu/poly_sin.c
@@ -5,7 +5,7 @@
  |                                                                           |
  | Copyright (C) 1992,1993                                                   |
  |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
- |                       Australia.  E-mail apm233m@vaxc.cc.monash.edu.au    |
+ |                       Australia.  E-mail   billm@vaxc.cc.monash.edu.au    |
  |                                                                           |
  |                                                                           |
  +---------------------------------------------------------------------------*/
@@ -18,7 +18,7 @@
 
 
 #define	HIPOWER	5
-static unsigned short	lterms[HIPOWER][4] =
+static unsigned short const	lterms[HIPOWER][4] =
 	{
 	{ 0x846a, 0x42d1, 0xb544, 0x921f},
 	{ 0xe110, 0x75aa, 0xbc67, 0x1466},
@@ -27,7 +27,7 @@
 	{ 0xda03, 0x06aa, 0x0000, 0x0000},
 	};
 
-static unsigned short	negterms[HIPOWER][4] =
+static unsigned short const	negterms[HIPOWER][4] =
 	{
 	{ 0x95ed, 0x2df2, 0xe731, 0xa55d},
 	{ 0xd159, 0xe62b, 0xd2cc, 0x0132},
@@ -40,7 +40,7 @@
 /*--- poly_sine() -----------------------------------------------------------+
  |                                                                           |
  +---------------------------------------------------------------------------*/
-void	poly_sine(FPU_REG *arg, FPU_REG *result)
+void	poly_sine(FPU_REG const *arg, FPU_REG *result)
 {
   short	exponent;
   FPU_REG	fixed_arg, arg_sqrd, arg_to_4, accum, negaccum;
diff --git a/drivers/FPU-emu/poly_tan.c b/drivers/FPU-emu/poly_tan.c
index 4c8a41b..6b11988 100644
--- a/drivers/FPU-emu/poly_tan.c
+++ b/drivers/FPU-emu/poly_tan.c
@@ -5,7 +5,7 @@
  |                                                                           |
  | Copyright (C) 1992,1993                                                   |
  |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
- |                       Australia.  E-mail apm233m@vaxc.cc.monash.edu.au    |
+ |                       Australia.  E-mail   billm@vaxc.cc.monash.edu.au    |
  |                                                                           |
  |                                                                           |
  +---------------------------------------------------------------------------*/
@@ -17,7 +17,7 @@
 
 
 #define	HIPOWERop	3	/* odd poly, positive terms */
-static unsigned short	oddplterms[HIPOWERop][4] =
+static unsigned short const	oddplterms[HIPOWERop][4] =
 	{
 	{ 0x846a, 0x42d1, 0xb544, 0x921f},
 	{ 0x6fb2, 0x0215, 0x95c0, 0x099c},
@@ -25,21 +25,21 @@
 	};
 
 #define	HIPOWERon	2	/* odd poly, negative terms */
-static unsigned short	oddnegterms[HIPOWERon][4] =
+static unsigned short const	oddnegterms[HIPOWERon][4] =
 	{
 	{ 0x6906, 0xe205, 0x25c8, 0x8838},
 	{ 0x1dd7, 0x3fe3, 0x944e, 0x002c}
 	};
 
 #define	HIPOWERep	2	/* even poly, positive terms */
-static unsigned short	evenplterms[HIPOWERep][4] =
+static unsigned short const	evenplterms[HIPOWERep][4] =
 	{
 	{ 0xdb8f, 0x3761, 0x1432, 0x2acf},
 	{ 0x16eb, 0x13c1, 0x3099, 0x0003}
 	};
 
 #define	HIPOWERen	2	/* even poly, negative terms */
-static unsigned short	evennegterms[HIPOWERen][4] =
+static unsigned short const	evennegterms[HIPOWERen][4] =
 	{
 	{ 0x3a7c, 0xe4c5, 0x7f87, 0x2945},
 	{ 0x572b, 0x664c, 0xc543, 0x018c}
@@ -49,7 +49,7 @@
 /*--- poly_tan() ------------------------------------------------------------+
  |                                                                           |
  +---------------------------------------------------------------------------*/
-void	poly_tan(FPU_REG *arg, FPU_REG *y_reg, int invert)
+void	poly_tan(FPU_REG const *arg, FPU_REG *result, int invert)
 {
   short		exponent;
   FPU_REG       odd_poly, even_poly, pos_poly, neg_poly;
@@ -61,7 +61,7 @@
 
 #ifdef PARANOID
   if ( arg->sign != 0 )	/* Can't hack a number < 0.0 */
-    { arith_invalid(y_reg); return; }  /* Need a positive number */
+    { arith_invalid(result); return; }  /* Need a positive number */
 #endif PARANOID
 
   arg_signif = significand(arg);
@@ -142,8 +142,8 @@
 
   /* Now ready to copy the results */
   if ( invert )
-    { reg_div(&even_poly, &odd_poly, y_reg, FULL_PRECISION); }
+    { reg_div(&even_poly, &odd_poly, result, FULL_PRECISION); }
   else
-    { reg_div(&odd_poly, &even_poly, y_reg, FULL_PRECISION); }
+    { reg_div(&odd_poly, &even_poly, result, FULL_PRECISION); }
 
 }
diff --git a/drivers/FPU-emu/polynomial.S b/drivers/FPU-emu/polynomial.S
index d3407ab..fa4da12 100644
--- a/drivers/FPU-emu/polynomial.S
+++ b/drivers/FPU-emu/polynomial.S
@@ -5,7 +5,7 @@
  |                                                                           |
  | Copyright (C) 1992,1993                                                   |
  |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
- |                       Australia.  E-mail apm233m@vaxc.cc.monash.edu.au    |
+ |                       Australia.  E-mail   billm@vaxc.cc.monash.edu.au    |
  |                                                                           |
  | Call from C as:                                                           |
  |   void polynomial(unsigned accum[], unsigned x[], unsigned terms[][2],    |
@@ -22,7 +22,7 @@
 #include "fpu_asm.h"
 
 
-/*	#define	EXTRA_PRECISE	Do not use: not complete */
+/*	#define	EXTRA_PRECISE	// Do not use: not complete */
 
 #define	TERM_SIZE	$8
 #define	SUM_MS		-20(%ebp)	/* sum ms long */
@@ -70,7 +70,7 @@
 
 	movl	SUM_MIDDLE,%eax
 	mull	(%esi)			/* x ls long */
-/*	movl	%eax,-16(%ebp)		Not needed */
+/*	movl	%eax,-16(%ebp)		// Not needed */
 	movl	%edx,ACCUM_LS
 
 	movl	SUM_MIDDLE,%eax
@@ -119,7 +119,7 @@
 
 L_accum_done:
 #ifdef EXTRA_PRECISE
-/* And round the result */
+/* Round the result */
 	testb	$128,SUM_LS_HI
 	je	L_poly_done
 
diff --git a/drivers/FPU-emu/reg_add_sub.c b/drivers/FPU-emu/reg_add_sub.c
index 890484e..d70889b 100644
--- a/drivers/FPU-emu/reg_add_sub.c
+++ b/drivers/FPU-emu/reg_add_sub.c
@@ -5,7 +5,7 @@
  |                                                                           |
  | Copyright (C) 1992,1993                                                   |
  |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
- |                       Australia.  E-mail apm233m@vaxc.cc.monash.edu.au    |
+ |                       Australia.  E-mail   billm@vaxc.cc.monash.edu.au    |
  |                                                                           |
  |                                                                           |
  +---------------------------------------------------------------------------*/
@@ -22,7 +22,7 @@
 #include "fpu_system.h"
 
 
-int reg_add(FPU_REG *a, FPU_REG *b, FPU_REG *dest, int control_w)
+int reg_add(FPU_REG const *a, FPU_REG const *b, FPU_REG *dest, int control_w)
 {
   char saved_sign = dest->sign;
   int diff;
@@ -162,7 +162,7 @@
 
 
 /* Subtract b from a.  (a-b) -> dest */
-int reg_sub(FPU_REG *a, FPU_REG *b, FPU_REG *dest, int control_w)
+int reg_sub(FPU_REG const *a, FPU_REG const *b, FPU_REG *dest, int control_w)
 {
   char saved_sign = dest->sign;
   int diff;
diff --git a/drivers/FPU-emu/reg_compare.c b/drivers/FPU-emu/reg_compare.c
index d1ec646..619ee0b 100644
--- a/drivers/FPU-emu/reg_compare.c
+++ b/drivers/FPU-emu/reg_compare.c
@@ -5,7 +5,7 @@
  |                                                                           |
  | Copyright (C) 1992,1993                                                   |
  |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
- |                       Australia.  E-mail apm233m@vaxc.cc.monash.edu.au    |
+ |                       Australia.  E-mail   billm@vaxc.cc.monash.edu.au    |
  |                                                                           |
  |                                                                           |
  +---------------------------------------------------------------------------*/
@@ -21,7 +21,7 @@
 #include "status_w.h"
 
 
-int compare(FPU_REG *b)
+int compare(FPU_REG const *b)
 {
   int diff;
 
diff --git a/drivers/FPU-emu/reg_constant.c b/drivers/FPU-emu/reg_constant.c
index 1f63051..b2aa574 100644
--- a/drivers/FPU-emu/reg_constant.c
+++ b/drivers/FPU-emu/reg_constant.c
@@ -5,7 +5,7 @@
  |                                                                           |
  | Copyright (C) 1992,1993                                                   |
  |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
- |                       Australia.  E-mail apm233m@vaxc.cc.monash.edu.au    |
+ |                       Australia.  E-mail   billm@vaxc.cc.monash.edu.au    |
  |                                                                           |
  |                                                                           |
  +---------------------------------------------------------------------------*/
@@ -16,47 +16,47 @@
 #include "reg_constant.h"
 
 
-FPU_REG CONST_1    = { SIGN_POS, TW_Valid, EXP_BIAS,
+FPU_REG const CONST_1    = { SIGN_POS, TW_Valid, EXP_BIAS,
 			    0x00000000, 0x80000000 };
-FPU_REG CONST_2    = { SIGN_POS, TW_Valid, EXP_BIAS+1,
+FPU_REG const CONST_2    = { SIGN_POS, TW_Valid, EXP_BIAS+1,
 			    0x00000000, 0x80000000 };
-FPU_REG CONST_HALF = { SIGN_POS, TW_Valid, EXP_BIAS-1,
+FPU_REG const CONST_HALF = { SIGN_POS, TW_Valid, EXP_BIAS-1,
 			    0x00000000, 0x80000000 };
-FPU_REG CONST_L2T  = { SIGN_POS, TW_Valid, EXP_BIAS+1,
+FPU_REG const CONST_L2T  = { SIGN_POS, TW_Valid, EXP_BIAS+1,
 			    0xcd1b8afe, 0xd49a784b };
-FPU_REG CONST_L2E  = { SIGN_POS, TW_Valid, EXP_BIAS,
+FPU_REG const CONST_L2E  = { SIGN_POS, TW_Valid, EXP_BIAS,
 			    0x5c17f0bc, 0xb8aa3b29 };
-FPU_REG CONST_PI   = { SIGN_POS, TW_Valid, EXP_BIAS+1,
+FPU_REG const CONST_PI   = { SIGN_POS, TW_Valid, EXP_BIAS+1,
 			    0x2168c235, 0xc90fdaa2 };
-FPU_REG CONST_PI2  = { SIGN_POS, TW_Valid, EXP_BIAS,
+FPU_REG const CONST_PI2  = { SIGN_POS, TW_Valid, EXP_BIAS,
 			    0x2168c235, 0xc90fdaa2 };
-FPU_REG CONST_PI4  = { SIGN_POS, TW_Valid, EXP_BIAS-1,
+FPU_REG const CONST_PI4  = { SIGN_POS, TW_Valid, EXP_BIAS-1,
 			    0x2168c235, 0xc90fdaa2 };
-FPU_REG CONST_LG2  = { SIGN_POS, TW_Valid, EXP_BIAS-2,
+FPU_REG const CONST_LG2  = { SIGN_POS, TW_Valid, EXP_BIAS-2,
 			    0xfbcff799, 0x9a209a84 };
-FPU_REG CONST_LN2  = { SIGN_POS, TW_Valid, EXP_BIAS-1,
+FPU_REG const CONST_LN2  = { SIGN_POS, TW_Valid, EXP_BIAS-1,
 			    0xd1cf79ac, 0xb17217f7 };
 
 /* Extra bits to take pi/2 to more than 128 bits precision. */
-FPU_REG CONST_PI2extra = { SIGN_NEG, TW_Valid, EXP_BIAS-66,
+FPU_REG const CONST_PI2extra = { SIGN_NEG, TW_Valid, EXP_BIAS-66,
 			    0xfc8f8cbb, 0xece675d1 };
 
 /* Only the sign (and tag) is used in internal zeroes */
-FPU_REG CONST_Z    = { SIGN_POS, TW_Zero, EXP_UNDER, 0x0, 0x0 };
+FPU_REG const CONST_Z    = { SIGN_POS, TW_Zero, EXP_UNDER, 0x0, 0x0 };
 
 /* Only the sign and significand (and tag) are used in internal NaNs */
 /* The 80486 never generates one of these 
-FPU_REG CONST_SNAN = { SIGN_POS, TW_NaN, EXP_OVER, 0x00000001, 0x80000000 };
+FPU_REG const CONST_SNAN = { SIGN_POS, TW_NaN, EXP_OVER, 0x00000001, 0x80000000 };
  */
 /* This is the real indefinite QNaN */
-FPU_REG CONST_QNaN = { SIGN_NEG, TW_NaN, EXP_OVER, 0x00000000, 0xC0000000 };
+FPU_REG const CONST_QNaN = { SIGN_NEG, TW_NaN, EXP_OVER, 0x00000000, 0xC0000000 };
 
 /* Only the sign (and tag) is used in internal infinities */
-FPU_REG CONST_INF  = { SIGN_POS, TW_Infinity, EXP_OVER, 0x00000000, 0x80000000 };
+FPU_REG const CONST_INF  = { SIGN_POS, TW_Infinity, EXP_OVER, 0x00000000, 0x80000000 };
 
 
 
-static void fld_const(FPU_REG *c)
+static void fld_const(FPU_REG const *c)
 {
   FPU_REG *st_new_ptr;
 
diff --git a/drivers/FPU-emu/reg_constant.h b/drivers/FPU-emu/reg_constant.h
index 23ba06d..b7db97e 100644
--- a/drivers/FPU-emu/reg_constant.h
+++ b/drivers/FPU-emu/reg_constant.h
@@ -2,7 +2,7 @@
  |  reg_constant.h                                                           |
  |                                                                           |
  | Copyright (C) 1992    W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
- |                       Australia.  E-mail apm233m@vaxc.cc.monash.edu.au    |
+ |                       Australia.  E-mail   billm@vaxc.cc.monash.edu.au    |
  |                                                                           |
  +---------------------------------------------------------------------------*/
 
@@ -11,21 +11,21 @@
 
 #include "fpu_emu.h"
 
-extern FPU_REG CONST_1;
-extern FPU_REG CONST_2;
-extern FPU_REG CONST_HALF;
-extern FPU_REG CONST_L2T;
-extern FPU_REG CONST_L2E;
-extern FPU_REG CONST_PI;
-extern FPU_REG CONST_PI2;
-extern FPU_REG CONST_PI2extra;
-extern FPU_REG CONST_PI4;
-extern FPU_REG CONST_LG2;
-extern FPU_REG CONST_LN2;
-extern FPU_REG CONST_Z;
-extern FPU_REG CONST_PINF;
-extern FPU_REG CONST_INF;
-extern FPU_REG CONST_MINF;
-extern FPU_REG CONST_QNaN;
+extern FPU_REG const CONST_1;
+extern FPU_REG const CONST_2;
+extern FPU_REG const CONST_HALF;
+extern FPU_REG const CONST_L2T;
+extern FPU_REG const CONST_L2E;
+extern FPU_REG const CONST_PI;
+extern FPU_REG const CONST_PI2;
+extern FPU_REG const CONST_PI2extra;
+extern FPU_REG const CONST_PI4;
+extern FPU_REG const CONST_LG2;
+extern FPU_REG const CONST_LN2;
+extern FPU_REG const CONST_Z;
+extern FPU_REG const CONST_PINF;
+extern FPU_REG const CONST_INF;
+extern FPU_REG const CONST_MINF;
+extern FPU_REG const CONST_QNaN;
 
 #endif _REG_CONSTANT_H_
diff --git a/drivers/FPU-emu/reg_div.S b/drivers/FPU-emu/reg_div.S
index 24acaec..558c594 100644
--- a/drivers/FPU-emu/reg_div.S
+++ b/drivers/FPU-emu/reg_div.S
@@ -6,7 +6,7 @@
  |                                                                           |
  | Copyright (C) 1992,1993                                                   |
  |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
- |                       Australia.  E-mail apm233m@vaxc.cc.monash.edu.au    |
+ |                       Australia.  E-mail   billm@vaxc.cc.monash.edu.au    |
  |                                                                           |
  | Call from C as:                                                           |
  |   void reg_div(FPU_REG *a, FPU_REG *b, FPU_REG *dest,                     |
@@ -17,6 +17,7 @@
 #include "exception.h"
 #include "fpu_asm.h"
 
+
 .text
 	.align 2
 
@@ -24,6 +25,9 @@
 _reg_div:
 	pushl	%ebp
 	movl	%esp,%ebp
+#ifdef REENTRANT_FPU
+	subl	$28,%esp	/* Needed by divide_kernel */
+#endif REENTRANT_FPU
 
 	pushl	%esi
 	pushl	%edi
@@ -45,7 +49,7 @@
 
 	call	_denormal_operand
 	orl	%eax,%eax
-	jnz	FPU_Arith_exit
+	jnz	fpu_Arith_exit
 
 xL_arg1_not_denormal:
 	cmpl	EXP_UNDER,EXP(%ebx)
@@ -53,7 +57,7 @@
 
 	call	_denormal_operand
 	orl	%eax,%eax
-	jnz	FPU_Arith_exit
+	jnz	fpu_Arith_exit
 
 xL_arg2_not_denormal:
 #endif DENORM_OPERAND
@@ -86,7 +90,6 @@
 L_arg1_NaN:
 L_arg2_NaN:
 	pushl	%edi			/* Destination */
-/*	pushl	%ebx */
 	pushl	%esi
 	pushl	%ebx			/* Ordering is important here */
 	call	_real_2op_NaN
@@ -125,7 +128,7 @@
 
 	call	_denormal_operand
 	orl	%eax,%eax
-	jnz	FPU_Arith_exit
+	jnz	fpu_Arith_exit
 #endif DENORM_OPERAND
 
 	jmp	L_copy_arg1		/* Answer is Inf */
@@ -164,7 +167,7 @@
 
 	call	_denormal_operand
 	orl	%eax,%eax
-	jnz	FPU_Arith_exit
+	jnz	fpu_Arith_exit
 #endif DENORM_OPERAND
 
 	jmp	L_return_zero		/* Answer is zero */
@@ -184,7 +187,7 @@
 
 	call	_denormal_operand
 	orl	%eax,%eax
-	jnz	FPU_Arith_exit
+	jnz	fpu_Arith_exit
 #endif DENORM_OPERAND
 
 L_copy_arg1:
@@ -211,7 +214,11 @@
 	xorl	%eax,%eax		/* Valid result */
 
 LDiv_exit:
+#ifdef REENTRANT_FPU
+	leal	-40(%ebp),%esp
+#else
 	leal	-12(%ebp),%esp
+#endif REENTRANT_FPU
 
 	popl	%ebx
 	popl	%edi
diff --git a/drivers/FPU-emu/reg_ld_str.c b/drivers/FPU-emu/reg_ld_str.c
index d07c7bf..c9d7495 100644
--- a/drivers/FPU-emu/reg_ld_str.c
+++ b/drivers/FPU-emu/reg_ld_str.c
@@ -5,7 +5,7 @@
  |                                                                           |
  | Copyright (C) 1992,1993                                                   |
  |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
- |                       Australia.  E-mail apm233m@vaxc.cc.monash.edu.au    |
+ |                       Australia.  E-mail   billm@vaxc.cc.monash.edu.au    |
  |                                                                           |
  |                                                                           |
  +---------------------------------------------------------------------------*/
diff --git a/drivers/FPU-emu/reg_mul.c b/drivers/FPU-emu/reg_mul.c
index a7d48ad..cd21beb 100644
--- a/drivers/FPU-emu/reg_mul.c
+++ b/drivers/FPU-emu/reg_mul.c
@@ -5,7 +5,7 @@
  |                                                                           |
  | Copyright (C) 1992,1993                                                   |
  |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
- |                       Australia.  E-mail apm233m@vaxc.cc.monash.edu.au    |
+ |                       Australia.  E-mail   billm@vaxc.cc.monash.edu.au    |
  |                                                                           |
  |                                                                           |
  +---------------------------------------------------------------------------*/
@@ -21,7 +21,8 @@
 
 
 /* This routine must be called with non-empty source registers */
-int reg_mul(FPU_REG *a, FPU_REG *b, FPU_REG *dest, unsigned int control_w)
+int reg_mul(FPU_REG const *a, FPU_REG const *b,
+	    FPU_REG *dest, unsigned int control_w)
 {
   char saved_sign = dest->sign;
   char sign = (a->sign ^ b->sign);
diff --git a/drivers/FPU-emu/reg_norm.S b/drivers/FPU-emu/reg_norm.S
index f63d74a..8ce60a2 100644
--- a/drivers/FPU-emu/reg_norm.S
+++ b/drivers/FPU-emu/reg_norm.S
@@ -3,7 +3,7 @@
  |                                                                           |
  | Copyright (C) 1992,1993                                                   |
  |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
- |                       Australia.  E-mail apm233m@vaxc.cc.monash.edu.au    |
+ |                       Australia.  E-mail   billm@vaxc.cc.monash.edu.au    |
  |                                                                           |
  | Normalize the value in a FPU_REG.                                         |
  |                                                                           |
@@ -39,7 +39,6 @@
 	orl	%eax,%eax
 	jz	L_zero		/* The contents are zero */
 
-/* L_shift_32: */
 	movl	%eax,%edx
 	xorl	%eax,%eax
 	subl	$32,EXP(%ebx)	/* This can cause an underflow */
@@ -109,7 +108,6 @@
 	orl	%eax,%eax
 	jz	L_zero		/* The contents are zero */
 
-/* L_nuo_shift_32: */
 	movl	%eax,%edx
 	xorl	%eax,%eax
 	subl	$32,EXP(%ebx)	/* This can cause an underflow */
diff --git a/drivers/FPU-emu/reg_round.S b/drivers/FPU-emu/reg_round.S
index 77a8a3a..32f2b2e 100644
--- a/drivers/FPU-emu/reg_round.S
+++ b/drivers/FPU-emu/reg_round.S
@@ -6,11 +6,11 @@
  |                                                                           |
  | Copyright (C) 1993                                                        |
  |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
- |                       Australia.  E-mail apm233m@vaxc.cc.monash.edu.au    |
+ |                       Australia.  E-mail   billm@vaxc.cc.monash.edu.au    |
  |                                                                           |
  | This code has four possible entry points.                                 |
  | The following must be entered by a jmp intruction:                        |
- |   FPU_round, FPU_round_sqrt, and FPU_Arith_exit.                          |
+ |   fpu_reg_round, fpu_reg_round_sqrt, and fpu_Arith_exit.                  |
  |                                                                           |
  | The _round_reg entry point is intended to be used by C code.              |
  | From C, call as:                                                          |
@@ -24,14 +24,14 @@
 /*---------------------------------------------------------------------------+
  | Four entry points.                                                        |
  |                                                                           |
- | Needed by both the FPU_round and FPU_round_sqrt entry points:             |
+ | Needed by both the fpu_reg_round and fpu_reg_round_sqrt entry points:     |
  |  %eax:%ebx  64 bit significand                                            |
  |  %edx       32 bit extension of the significand                           |
  |  %edi       pointer to an FPU_REG for the result to be stored             |
  |  stack      calling function must have set up a C stack frame and         |
  |             pushed %esi, %edi, and %ebx                                   |
  |                                                                           |
- | Needed just for the FPU_round_sqrt entry point:                           |
+ | Needed just for the fpu_reg_round_sqrt entry point:                       |
  |  %cx  A control word in the same format as the FPU control word.          |
  | Otherwise, PARAM4 must give such a value.                                 |
  |                                                                           |
@@ -81,18 +81,30 @@
 #define	DENORMAL	$1
 #define	UNMASKED_UNDERFLOW $2
 
+
+#ifdef REENTRANT_FPU
+/*	Make the code re-entrant by putting
+	local storage on the stack: */
+#define FPU_bits_lost	(%esp)
+#define FPU_denormal	1(%esp)
+
+#else
+/*	Not re-entrant, so we can gain speed by putting
+	local storage in a static area: */
 .data
 	.align 2,0
 FPU_bits_lost:
 	.byte	0
 FPU_denormal:
 	.byte	0
+#endif REENTRANT_FPU
+
 
 .text
 	.align 2,144
-.globl FPU_round
-.globl FPU_round_sqrt
-.globl FPU_Arith_exit
+.globl fpu_reg_round
+.globl fpu_reg_round_sqrt
+.globl fpu_Arith_exit
 .globl _round_reg
 
 /* Entry point when called from C */
@@ -108,19 +120,21 @@
 	movl	SIGL(%edi),%ebx
 	movl	PARAM2,%edx
 	movl	PARAM3,%ecx
-	jmp	FPU_round_sqrt
+	jmp	fpu_reg_round_sqrt
 
-FPU_round:		/* Normal entry point */
+fpu_reg_round:			/* Normal entry point */
 	movl	PARAM4,%ecx
 
-FPU_round_sqrt:		/* Entry point from wm_sqrt.S */
+fpu_reg_round_sqrt:		/* Entry point from wm_sqrt.S */
+
+#ifdef REENTRANT_FPU
+	pushl	%ebx		/* adjust the stack pointer */
+#endif REENTRANT_FPU
 
 #ifdef PARANOID
-/*
- * Cannot use this here yet
- *	orl	%eax,%eax
- *	jns	L_entry_bugged
- */
+/* Cannot use this here yet */
+/*	orl	%eax,%eax */
+/*	jns	L_entry_bugged */
 #endif PARANOID
 
 	cmpl	EXP_UNDER,EXP(%edi)
@@ -218,7 +232,7 @@
 	andl	$0x000000ff,%ecx
 	orl	%ebx,%ecx
 	orl	%edx,%ecx
-	jz	LRe_normalise			/* No truncation needed */
+	jz	LRe_normalise		/* No truncation needed */
 
 LDo_truncate_24:
 	andl	$0xffffff00,%eax	/* Truncate to 24 bits */
@@ -392,7 +406,12 @@
 	cmpl	EXP_OVER,EXP(%edi)
 	jge	L_overflow
 
-FPU_Arith_exit:
+fpu_reg_round_exit:
+#ifdef REENTRANT_FPU
+	popl	%ebx		/* adjust the stack pointer */
+#endif REENTRANT_FPU
+
+fpu_Arith_exit:
 	popl	%ebx
 	popl	%edi
 	popl	%esi
@@ -427,8 +446,8 @@
  * have to be undone later...
  */
 xMake_denorm:
-	/* The action to be taken depends upon whether the underflow */
-	/* exception is masked */
+	/* The action to be taken depends upon whether the underflow
+	   exception is masked */
 	testb	CW_Underflow,%cl		/* Underflow mask. */
 	jz	xUnmasked_underflow		/* Do not make a denormal. */
 
@@ -601,7 +620,7 @@
 	push	%edi
 	call	_arith_overflow
 	pop	%edi
-	jmp	FPU_Arith_exit
+	jmp	fpu_reg_round_exit
 
 
 xSignal_underflow:
@@ -643,5 +662,5 @@
 	popl	%ebx
 L_exception_exit:
 	mov	$1,%eax
-	jmp	FPU_Arith_exit
+	jmp	fpu_reg_round_exit
 #endif PARANOID
diff --git a/drivers/FPU-emu/reg_u_add.S b/drivers/FPU-emu/reg_u_add.S
index 5c42e8a..4410f8f 100644
--- a/drivers/FPU-emu/reg_u_add.S
+++ b/drivers/FPU-emu/reg_u_add.S
@@ -7,7 +7,7 @@
  |                                                                           |
  | Copyright (C) 1992,1993                                                   |
  |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
- |                       Australia.  E-mail apm233m@vaxc.cc.monash.edu.au    |
+ |                       Australia.  E-mail   billm@vaxc.cc.monash.edu.au    |
  |                                                                           |
  | Call from C as:                                                           |
  |   void reg_u_add(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *answ,             |
@@ -34,7 +34,6 @@
 _reg_u_add:
 	pushl	%ebp
 	movl	%esp,%ebp
-/*	subl	$16,%esp */
 	pushl	%esi
 	pushl	%edi
 	pushl	%ebx
@@ -48,7 +47,7 @@
 
 	call	_denormal_operand
 	orl	%eax,%eax
-	jnz	FPU_Arith_exit
+	jnz	fpu_Arith_exit
 
 xOp1_not_denorm:
 	cmpl	EXP_UNDER,EXP(%edi)
@@ -56,15 +55,13 @@
 
 	call	_denormal_operand
 	orl	%eax,%eax
-	jnz	FPU_Arith_exit
+	jnz	fpu_Arith_exit
 
 xOp2_not_denorm:
 #endif DENORM_OPERAND
 
-/*	xorl	%ecx,%ecx */
 	movl	EXP(%esi),%ecx
 	subl	EXP(%edi),%ecx		/* exp1 - exp2 */
-/*	jnc	L_arg1_larger */
 	jge	L_arg1_larger
 
 	/* num1 is smaller */
@@ -82,12 +79,12 @@
 
 L_accum_loaded:
 	movl	PARAM3,%edi		/* destination */
-/*	movb	SIGN(%esi),%dl */
-/*	movb	%dl,SIGN(%edi)	*/	/* Copy the sign from the first arg */
+/*	movb	SIGN(%esi),%dl
+	movb	%dl,SIGN(%edi) */	/* Copy the sign from the first arg */
 
 
 	movl	EXP(%esi),%edx
-	movl	%edx,EXP(%edi)	/* Copy exponent to destination */
+	movl	%edx,EXP(%edi)		/* Copy exponent to destination */
 
 	xorl	%edx,%edx		/* clear the extension */
 
@@ -170,7 +167,7 @@
 	incl	EXP(%edi)
 
 L_round_the_result:
-	jmp	FPU_round	/* Round the result */
+	jmp	fpu_reg_round	/* Round the result */
 
 
 
diff --git a/drivers/FPU-emu/reg_u_div.S b/drivers/FPU-emu/reg_u_div.S
index 49b1328..0098324 100644
--- a/drivers/FPU-emu/reg_u_div.S
+++ b/drivers/FPU-emu/reg_u_div.S
@@ -6,7 +6,7 @@
  |                                                                           |
  | Copyright (C) 1992,1993                                                   |
  |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
- |                       Australia.  E-mail apm233m@vaxc.cc.monash.edu.au    |
+ |                       Australia.  E-mail   billm@vaxc.cc.monash.edu.au    |
  |                                                                           |
  |                                                                           |
  +---------------------------------------------------------------------------*/
@@ -29,27 +29,43 @@
 /* #define	dSIGH(x)	4(x) */
 
 
+#ifdef REENTRANT_FPU
+/*
+	Local storage on the stack:
+	Result:		FPU_accum_3:FPU_accum_2:FPU_accum_1:FPU_accum_0
+	Overflow flag:	ovfl_flag
+ */
+#define FPU_accum_3	-4(%ebp)
+#define FPU_accum_2	-8(%ebp)
+#define FPU_accum_1	-12(%ebp)
+#define FPU_accum_0	-16(%ebp)
+#define FPU_result_1	-20(%ebp)
+#define FPU_result_2	-24(%ebp)
+#define FPU_ovfl_flag	-28(%ebp)
+
+#else
 .data
 /*
-	Local storage:
-	Result:		accum_3:accum_2:accum_1:accum_0
+	Local storage in a static area:
+	Result:		FPU_accum_3:FPU_accum_2:FPU_accum_1:FPU_accum_0
 	Overflow flag:	ovfl_flag
  */
 	.align 2,0
-accum_3:
+FPU_accum_3:
 	.long	0
-accum_2:
+FPU_accum_2:
 	.long	0
-accum_1:
+FPU_accum_1:
 	.long	0
-accum_0:
+FPU_accum_0:
 	.long	0
-result_1:
+FPU_result_1:
 	.long	0
-result_2:
+FPU_result_2:
 	.long	0
-ovfl_flag:
+FPU_ovfl_flag:
 	.byte	0
+#endif REENTRANT_FPU
 
 
 .text
@@ -62,6 +78,9 @@
 _reg_u_div:
 	pushl	%ebp
 	movl	%esp,%ebp
+#ifdef REENTRANT_FPU
+	subl	$28,%esp
+#endif REENTRANT_FPU
 
 	pushl	%esi
 	pushl	%edi
@@ -78,7 +97,7 @@
 
 	call	_denormal_operand
 	orl	%eax,%eax
-	jnz	FPU_Arith_exit
+	jnz	fpu_Arith_exit
 
 xOp1_not_denorm:
 	movl	EXP(%ebx),%eax
@@ -87,7 +106,7 @@
 
 	call	_denormal_operand
 	orl	%eax,%eax
-	jnz	FPU_Arith_exit
+	jnz	fpu_Arith_exit
 
 xOp2_not_denorm:
 #endif DENORM_OPERAND
@@ -110,7 +129,7 @@
 	movl	SIGL(%esi),%eax	/* Dividend */
 
 	cmpl	%ecx,%edx
-	setaeb	ovfl_flag	/* Keep a record */
+	setaeb	FPU_ovfl_flag	/* Keep a record */
 	jb	L_no_adjust
 
 	subl	%ecx,%edx	/* Prevent the overflow */
@@ -118,18 +137,18 @@
 L_no_adjust:
 	/* Divide the 64 bit number by the 32 bit denominator */
 	divl	%ecx
-	movl	%eax,result_2
+	movl	%eax,FPU_result_2
 
 	/* Work on the remainder of the first division */
 	xorl	%eax,%eax
 	divl	%ecx
-	movl	%eax,result_1
+	movl	%eax,FPU_result_1
 
 	/* Work on the remainder of the 64 bit division */
 	xorl	%eax,%eax
 	divl	%ecx
 
-	testb	$255,ovfl_flag	/* was the num > denom ? */
+	testb	$255,FPU_ovfl_flag	/* was the num > denom ? */
 	je	L_no_overflow
 
 	/* Do the shifting here */
@@ -138,8 +157,8 @@
 
 	/* shift the mantissa right one bit */
 	stc			/* To set the ms bit */
-	rcrl	result_2
-	rcrl	result_1
+	rcrl	FPU_result_2
+	rcrl	FPU_result_1
 	rcrl	%eax
 
 L_no_overflow:
@@ -167,21 +186,21 @@
 L_Full_Division:
 	/* Save extended dividend in local register */
 	movl	SIGL(%esi),%eax
-	movl	%eax,accum_2
+	movl	%eax,FPU_accum_2
 	movl	SIGH(%esi),%eax
-	movl	%eax,accum_3
+	movl	%eax,FPU_accum_3
 	xorl	%eax,%eax
-	movl	%eax,accum_1	/* zero the extension */
-	movl	%eax,accum_0	/* zero the extension */
+	movl	%eax,FPU_accum_1	/* zero the extension */
+	movl	%eax,FPU_accum_0	/* zero the extension */
 
 	movl	SIGL(%esi),%eax	/* Get the current num */
 	movl	SIGH(%esi),%edx
 
 /*----------------------------------------------------------------------*/
-/* Initialization done */
-/* Do the first 32 bits */
+/* Initialization done.
+   Do the first 32 bits. */
 
-	movb	$0,ovfl_flag
+	movb	$0,FPU_ovfl_flag
 	cmpl	SIGH(%ebx),%edx	/* Test for imminent overflow */
 	jb	LLess_than_1
 	ja	LGreater_than_1
@@ -191,16 +210,16 @@
 
 LGreater_than_1:
 /* The dividend is greater or equal, would cause overflow */
-	setaeb	ovfl_flag		/* Keep a record */
+	setaeb	FPU_ovfl_flag		/* Keep a record */
 
 	subl	SIGL(%ebx),%eax
 	sbbl	SIGH(%ebx),%edx	/* Prevent the overflow */
-	movl	%eax,accum_2
-	movl	%edx,accum_3
+	movl	%eax,FPU_accum_2
+	movl	%edx,FPU_accum_3
 
 LLess_than_1:
 /* At this point, we have a dividend < divisor, with a record of
-   adjustment in ovfl_flag */
+   adjustment in FPU_ovfl_flag */
 
 	/* We will divide by a number which is too large */
 	movl	SIGH(%ebx),%ecx
@@ -217,19 +236,19 @@
 				   denom ms dw */
 
 LFirst_div_done:
-	movl	%eax,result_2	/* Put the result in the answer */
+	movl	%eax,FPU_result_2	/* Put the result in the answer */
 
 	mull	SIGH(%ebx)	/* mul by the ms dw of the denom */
 
-	subl	%eax,accum_2	/* Subtract from the num local reg */
-	sbbl	%edx,accum_3
+	subl	%eax,FPU_accum_2	/* Subtract from the num local reg */
+	sbbl	%edx,FPU_accum_3
 
-	movl	result_2,%eax	/* Get the result back */
+	movl	FPU_result_2,%eax	/* Get the result back */
 	mull	SIGL(%ebx)	/* now mul the ls dw of the denom */
 
-	subl	%eax,accum_1	/* Subtract from the num local reg */
-	sbbl	%edx,accum_2
-	sbbl	$0,accum_3
+	subl	%eax,FPU_accum_1	/* Subtract from the num local reg */
+	sbbl	%edx,FPU_accum_2
+	sbbl	$0,FPU_accum_3
 	je	LDo_2nd_32_bits		/* Must check for non-zero result here */
 
 #ifdef PARANOID
@@ -237,25 +256,25 @@
 #endif PARANOID
 
 	/* need to subtract another once of the denom */
-	incl	result_2	/* Correct the answer */
+	incl	FPU_result_2	/* Correct the answer */
 
 	movl	SIGL(%ebx),%eax
 	movl	SIGH(%ebx),%edx
-	subl	%eax,accum_1	/* Subtract from the num local reg */
-	sbbl	%edx,accum_2
+	subl	%eax,FPU_accum_1	/* Subtract from the num local reg */
+	sbbl	%edx,FPU_accum_2
 
 #ifdef PARANOID
-	sbbl	$0,accum_3
+	sbbl	$0,FPU_accum_3
 	jne	L_bugged_1	/* Must check for non-zero result here */
 #endif PARANOID
 
 /*----------------------------------------------------------------------*/
 /* Half of the main problem is done, there is just a reduced numerator
-   to handle now */
-/* Work with the second 32 bits, accum_0 not used from now on */
+   to handle now.
+   Work with the second 32 bits, FPU_accum_0 not used from now on */
 LDo_2nd_32_bits:
-	movl	accum_2,%edx	/* get the reduced num */
-	movl	accum_1,%eax
+	movl	FPU_accum_2,%edx	/* get the reduced num */
+	movl	FPU_accum_1,%eax
 
 	/* need to check for possible subsequent overflow */
 	cmpl	SIGH(%ebx),%edx
@@ -270,10 +289,10 @@
 	/* prevent overflow */
 	subl	SIGL(%ebx),%eax
 	sbbl	SIGH(%ebx),%edx
-	movl	%edx,accum_2
-	movl	%eax,accum_1
+	movl	%edx,FPU_accum_2
+	movl	%eax,FPU_accum_1
 
-	incl	result_2	/* Reflect the subtraction in the answer */
+	incl	FPU_result_2	/* Reflect the subtraction in the answer */
 
 #ifdef PARANOID
 	je	L_bugged_2	/* Can't bump the result to 1.0 */
@@ -291,23 +310,23 @@
 	divl	%ecx		/* Divide the numerator by the denom ms dw */
 
 LSecond_div_done:
-	movl	%eax,result_1	/* Put the result in the answer */
+	movl	%eax,FPU_result_1	/* Put the result in the answer */
 
 	mull	SIGH(%ebx)	/* mul by the ms dw of the denom */
 
-	subl	%eax,accum_1	/* Subtract from the num local reg */
-	sbbl	%edx,accum_2
+	subl	%eax,FPU_accum_1	/* Subtract from the num local reg */
+	sbbl	%edx,FPU_accum_2
 
 #ifdef PARANOID
 	jc	L_bugged_2
 #endif PARANOID
 
-	movl	result_1,%eax	/* Get the result back */
+	movl	FPU_result_1,%eax	/* Get the result back */
 	mull	SIGL(%ebx)	/* now mul the ls dw of the denom */
 
-	subl	%eax,accum_0	/* Subtract from the num local reg */
-	sbbl	%edx,accum_1	/* Subtract from the num local reg */
-	sbbl	$0,accum_2
+	subl	%eax,FPU_accum_0	/* Subtract from the num local reg */
+	sbbl	%edx,FPU_accum_1	/* Subtract from the num local reg */
+	sbbl	$0,FPU_accum_2
 
 #ifdef PARANOID
 	jc	L_bugged_2
@@ -316,24 +335,24 @@
 	jz	LDo_3rd_32_bits
 
 #ifdef PARANOID
-	cmpl	$1,accum_2
+	cmpl	$1,FPU_accum_2
 	jne	L_bugged_2
 #endif PARANOID
 
 	/* need to subtract another once of the denom */
 	movl	SIGL(%ebx),%eax
 	movl	SIGH(%ebx),%edx
-	subl	%eax,accum_0	/* Subtract from the num local reg */
-	sbbl	%edx,accum_1
-	sbbl	$0,accum_2
+	subl	%eax,FPU_accum_0	/* Subtract from the num local reg */
+	sbbl	%edx,FPU_accum_1
+	sbbl	$0,FPU_accum_2
 
 #ifdef PARANOID
 	jc	L_bugged_2
 	jne	L_bugged_2
 #endif PARANOID
 
-	addl	$1,result_1	/* Correct the answer */
-	adcl	$0,result_2
+	addl	$1,FPU_result_1	/* Correct the answer */
+	adcl	$0,FPU_result_2
 
 #ifdef PARANOID
 	jc	L_bugged_2	/* Must check for non-zero result here */
@@ -341,11 +360,11 @@
 
 /*----------------------------------------------------------------------*/
 /* The division is essentially finished here, we just need to perform
-   tidying operations. */
-/* deal with the 3rd 32 bits */
+   tidying operations.
+   Deal with the 3rd 32 bits */
 LDo_3rd_32_bits:
-	movl	accum_1,%edx		/* get the reduced num */
-	movl	accum_0,%eax
+	movl	FPU_accum_1,%edx		/* get the reduced num */
+	movl	FPU_accum_0,%eax
 
 	/* need to check for possible subsequent overflow */
 	cmpl	SIGH(%ebx),%edx	/* denom */
@@ -359,16 +378,16 @@
 	/* prevent overflow */
 	subl	SIGL(%ebx),%eax
 	sbbl	SIGH(%ebx),%edx
-	movl	%edx,accum_1
-	movl	%eax,accum_0
+	movl	%edx,FPU_accum_1
+	movl	%eax,FPU_accum_0
 
-	addl	$1,result_1	/* Reflect the subtraction in the answer */
-	adcl	$0,result_2
+	addl	$1,FPU_result_1	/* Reflect the subtraction in the answer */
+	adcl	$0,FPU_result_2
 	jne	LRound_prep
 	jnc	LRound_prep
 
 	/* This is a tricky spot, there is an overflow of the answer */
-	movb	$255,ovfl_flag		/* Overflow -> 1.000 */
+	movb	$255,FPU_ovfl_flag		/* Overflow -> 1.000 */
 
 LRound_prep:
 /*
@@ -376,8 +395,8 @@
  * To test for rounding, we just need to compare 2*accum with the
  * denom.
  */
-	movl	accum_0,%ecx
-	movl	accum_1,%edx
+	movl	FPU_accum_0,%ecx
+	movl	FPU_accum_1,%edx
 	movl	%ecx,%eax
 	orl	%edx,%eax
 	jz	LRound_ovfl		/* The accumulator contains zero. */
@@ -407,15 +426,15 @@
 LRound_ovfl:
 /* We are now ready to deal with rounding, but first we must get
    the bits properly aligned */
-	testb	$255,ovfl_flag	/* was the num > denom ? */
+	testb	$255,FPU_ovfl_flag	/* was the num > denom ? */
 	je	LRound_precision
 
 	incl	EXP(%edi)
 
 	/* shift the mantissa right one bit */
 	stc			/* Will set the ms bit */
-	rcrl	result_2
-	rcrl	result_1
+	rcrl	FPU_result_2
+	rcrl	FPU_result_1
 	rcrl	%eax
 
 /* Round the result as required */
@@ -423,9 +442,9 @@
 	decl	EXP(%edi)	/* binary point between 1st & 2nd bits */
 
 	movl	%eax,%edx
-	movl	result_1,%ebx
-	movl	result_2,%eax
-	jmp	FPU_round
+	movl	FPU_result_1,%ebx
+	movl	FPU_result_2,%eax
+	jmp	fpu_reg_round
 
 
 #ifdef PARANOID
diff --git a/drivers/FPU-emu/reg_u_mul.S b/drivers/FPU-emu/reg_u_mul.S
index 8824176..d041bf3 100644
--- a/drivers/FPU-emu/reg_u_mul.S
+++ b/drivers/FPU-emu/reg_u_mul.S
@@ -6,7 +6,7 @@
  |                                                                           |
  | Copyright (C) 1992,1993                                                   |
  |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
- |                       Australia.  E-mail apm233m@vaxc.cc.monash.edu.au    |
+ |                       Australia.  E-mail   billm@vaxc.cc.monash.edu.au    |
  |                                                                           |
  |                                                                           |
  +---------------------------------------------------------------------------*/
@@ -26,12 +26,21 @@
 #include "control_w.h"
 
 
+
+#ifdef REENTRANT_FPU
+/*  Local storage on the stack: */
+#define FPU_accum_0	-4(%ebp)	/* ms word */
+#define FPU_accum_1	-8(%ebp)
+
+#else
+/*  Local storage in a static area: */
 .data
-	.align 2,0
-accum_0:
+	.align 4,0
+FPU_accum_0:
 	.long	0
-accum_1:
+FPU_accum_1:
 	.long	0
+#endif REENTRANT_FPU
 
 
 .text
@@ -41,6 +50,10 @@
 _reg_u_mul:
 	pushl	%ebp
 	movl	%esp,%ebp
+#ifdef REENTRANT_FPU
+	subl	$8,%esp
+#endif REENTRANT_FPU
+
 	pushl	%esi
 	pushl	%edi
 	pushl	%ebx
@@ -62,7 +75,7 @@
 
 	call	_denormal_operand
 	orl	%eax,%eax
-	jnz	FPU_Arith_exit
+	jnz	fpu_Arith_exit
 
 xOp1_not_denorm:
 	movl	EXP(%edi),%eax
@@ -71,7 +84,7 @@
 
 	call	_denormal_operand
 	orl	%eax,%eax
-	jnz	FPU_Arith_exit
+	jnz	fpu_Arith_exit
 
 xOp2_not_denorm:
 #endif DENORM_OPERAND
@@ -81,18 +94,18 @@
 
 	movl	SIGL(%esi),%eax
 	mull	SIGL(%edi)
-	movl	%eax,accum_0
-	movl	%edx,accum_1
+	movl	%eax,FPU_accum_0
+	movl	%edx,FPU_accum_1
 
 	movl	SIGL(%esi),%eax
 	mull	SIGH(%edi)
-	addl	%eax,accum_1
+	addl	%eax,FPU_accum_1
 	adcl	%edx,%ebx
 /*	adcl	$0,%ecx		// overflow here is not possible */
 
 	movl	SIGH(%esi),%eax
 	mull	SIGL(%edi)
-	addl	%eax,accum_1
+	addl	%eax,FPU_accum_1
 	adcl	%edx,%ebx
 	adcl	$0,%ecx
 
@@ -104,6 +117,7 @@
 	movl	EXP(%esi),%eax	/* Compute the exponent */
 	addl	EXP(%edi),%eax
 	subl	EXP_BIAS-1,%eax
+
 /*  Have now finished with the sources */
 	movl	PARAM3,%edi	/* Point to the destination */
 	movl	%eax,EXP(%edi)
@@ -113,15 +127,15 @@
 	jnz	LResult_Normalised
 
 	/* Normalize by shifting left one bit */
-	shll	$1,accum_0
-	rcll	$1,accum_1
+	shll	$1,FPU_accum_0
+	rcll	$1,FPU_accum_1
 	rcll	$1,%ebx
 	rcll	$1,%ecx
 	decl	EXP(%edi)
 
 LResult_Normalised:
-	movl	accum_0,%eax
-	movl	accum_1,%edx
+	movl	FPU_accum_0,%eax
+	movl	FPU_accum_1,%edx
 	orl	%eax,%eax
 	jz	L_extent_zero
 
@@ -129,7 +143,7 @@
 
 L_extent_zero:
 	movl	%ecx,%eax
-	jmp	FPU_round
+	jmp	fpu_reg_round
 
 
 #ifdef PARANOID
diff --git a/drivers/FPU-emu/reg_u_sub.S b/drivers/FPU-emu/reg_u_sub.S
index a7b5d89..fbec17d 100644
--- a/drivers/FPU-emu/reg_u_sub.S
+++ b/drivers/FPU-emu/reg_u_sub.S
@@ -6,7 +6,7 @@
  |                                                                           |
  | Copyright (C) 1992,1993                                                   |
  |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
- |                       Australia.  E-mail apm233m@vaxc.cc.monash.edu.au    |
+ |                       Australia.  E-mail   billm@vaxc.cc.monash.edu.au    |
  |                                                                           |
  | Call from C as:                                                           |
  |   void reg_u_sub(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *answ,             |
@@ -48,7 +48,7 @@
 
 	call	_denormal_operand
 	orl	%eax,%eax
-	jnz	FPU_Arith_exit
+	jnz	fpu_Arith_exit
 
 xOp1_not_denorm:
 	cmpl	EXP_UNDER,EXP(%edi)
@@ -56,7 +56,7 @@
 
 	call	_denormal_operand
 	orl	%eax,%eax
-	jnz	FPU_Arith_exit
+	jnz	fpu_Arith_exit
 
 xOp2_not_denorm:
 #endif DENORM_OPERAND
@@ -85,8 +85,8 @@
 	movl	PARAM3,%edi	/* destination */
 	movl	EXP(%esi),%edx
 	movl	%edx,EXP(%edi)	/* Copy exponent to destination */
-/*	movb	SIGN(%esi),%dl */
-/*	movb	%dl,SIGN(%edi)	*/ /* Copy the sign from the first arg */
+/*	movb	SIGN(%esi),%dl
+	movb	%dl,SIGN(%edi) */	/* Copy the sign from the first arg */
 
 	xorl	%edx,%edx	/* register extension */
 
@@ -214,7 +214,7 @@
 	/* Shift left 64 bits */
 	subl	$64,EXP(%edi)
 	xchg	%edx,%eax
-	jmp	FPU_round
+	jmp	fpu_reg_round
 
 L_must_be_zero:
 #ifdef PARANOID
@@ -246,7 +246,7 @@
 	subl	%ecx,EXP(%edi)	/* Can get underflow here */
 
 L_round:
-	jmp	FPU_round	/* Round the result */
+	jmp	fpu_reg_round	/* Round the result */
 
 
 #ifdef PARANOID
diff --git a/drivers/FPU-emu/status_w.h b/drivers/FPU-emu/status_w.h
index 87521ff..96607d0 100644
--- a/drivers/FPU-emu/status_w.h
+++ b/drivers/FPU-emu/status_w.h
@@ -3,7 +3,7 @@
  |                                                                           |
  | Copyright (C) 1992,1993                                                   |
  |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
- |                       Australia.  E-mail apm233m@vaxc.cc.monash.edu.au    |
+ |                       Australia.  E-mail   billm@vaxc.cc.monash.edu.au    |
  |                                                                           |
  +---------------------------------------------------------------------------*/
 
diff --git a/drivers/FPU-emu/version.h b/drivers/FPU-emu/version.h
index ce22bab..587f364 100644
--- a/drivers/FPU-emu/version.h
+++ b/drivers/FPU-emu/version.h
@@ -4,7 +4,7 @@
  |                                                                           |
  | Copyright (C) 1992,1993                                                   |
  |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
- |                       Australia.  E-mail apm233m@vaxc.cc.monash.edu.au    |
+ |                       Australia.  E-mail   billm@vaxc.cc.monash.edu.au    |
  |                                                                           |
  |                                                                           |
  +---------------------------------------------------------------------------*/
diff --git a/drivers/FPU-emu/wm_shrx.S b/drivers/FPU-emu/wm_shrx.S
index 59badea..bef0e19 100644
--- a/drivers/FPU-emu/wm_shrx.S
+++ b/drivers/FPU-emu/wm_shrx.S
@@ -5,7 +5,7 @@
  | 64 bit right shift functions                                              |
  |                                                                           |
  | Copyright (C) 1992    W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
- |                       Australia.  E-mail apm233m@vaxc.cc.monash.edu.au    |
+ |                       Australia.  E-mail   billm@vaxc.cc.monash.edu.au    |
  |                                                                           |
  | Call from C as:                                                           |
  |   unsigned shrx(void *arg1, unsigned arg2)                                |
diff --git a/drivers/FPU-emu/wm_sqrt.S b/drivers/FPU-emu/wm_sqrt.S
index bc53aa5..7f8b6c6 100644
--- a/drivers/FPU-emu/wm_sqrt.S
+++ b/drivers/FPU-emu/wm_sqrt.S
@@ -6,7 +6,7 @@
  |                                                                           |
  | Copyright (C) 1992,1993                                                   |
  |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
- |                       Australia.  E-mail apm233m@vaxc.cc.monash.edu.au    |
+ |                       Australia.  E-mail   billm@vaxc.cc.monash.edu.au    |
  |                                                                           |
  | Call from C as:                                                           |
  |   void wm_sqrt(FPU_REG *n, unsigned int control_word)                     |
@@ -29,19 +29,12 @@
 #include "fpu_asm.h"
 
 
-.data
-/*
-	Local storage:
- */
-	.align 4,0
-accum_3:
-	.long	0		/* ms word */
-accum_2:
-	.long	0
-accum_1:
-	.long	0
-accum_0:
-	.long	0
+#ifdef REENTRANT_FPU
+/*	Local storage on the stack: */
+#define FPU_accum_3	-4(%ebp)	/* ms word */
+#define FPU_accum_2	-8(%ebp)
+#define FPU_accum_1	-12(%ebp)
+#define FPU_accum_0	-16(%ebp)
 
 /*
  * The de-normalised argument:
@@ -49,21 +42,47 @@
  *        b b b b b b b ... b b b   b b b .... b b b   b 0 0 0 ... 0
  *           ^ binary point here
  */
-fsqrt_arg_2:
+#define FPU_fsqrt_arg_2	-20(%ebp)	/* ms word */
+#define FPU_fsqrt_arg_1	-24(%ebp)
+#define FPU_fsqrt_arg_0	-28(%ebp)	/* ls word, at most the ms bit is set */
+
+#else
+/*	Local storage in a static area: */
+.data
+	.align 4,0
+FPU_accum_3:
 	.long	0		/* ms word */
-fsqrt_arg_1:
+FPU_accum_2:
 	.long	0
-fsqrt_arg_0:
+FPU_accum_1:
+	.long	0
+FPU_accum_0:
+	.long	0
+
+/* The de-normalised argument:
+                    sq_2                  sq_1              sq_0
+          b b b b b b b ... b b b   b b b .... b b b   b 0 0 0 ... 0
+             ^ binary point here
+ */
+FPU_fsqrt_arg_2:
+	.long	0		/* ms word */
+FPU_fsqrt_arg_1:
+	.long	0
+FPU_fsqrt_arg_0:
 	.long	0		/* ls word, at most the ms bit is set */
+#endif REENTRANT_FPU
+
 
 .text
 	.align 2,144
 
 .globl _wm_sqrt
-
 _wm_sqrt:
 	pushl	%ebp
 	movl	%esp,%ebp
+#ifdef REENTRANT_FPU
+	subl	$28,%esp
+#endif REENTRANT_FPU
 	pushl	%esi
 	pushl	%edi
 	pushl	%ebx
@@ -84,12 +103,12 @@
 	rcrl	$1,%edx
 
 sqrt_arg_ge_2:
-/* From here on, n is never accessed directly again until it is */
-/* replaced by the answer. */
+/* From here on, n is never accessed directly again until it is
+   replaced by the answer. */
 
-	movl	%eax,fsqrt_arg_2		/* ms word of n */
-	movl	%ecx,fsqrt_arg_1
-	movl	%edx,fsqrt_arg_0
+	movl	%eax,FPU_fsqrt_arg_2		/* ms word of n */
+	movl	%ecx,FPU_fsqrt_arg_1
+	movl	%edx,FPU_fsqrt_arg_0
 
 /* Make a linear first estimate */
 	shrl	$1,%eax
@@ -108,7 +127,7 @@
 /* We have now computed (approx)   (2 + x) / 3, which forms the basis
    for a few iterations of Newton's method */
 
-	movl	fsqrt_arg_2,%ecx	/* ms word */
+	movl	FPU_fsqrt_arg_2,%ecx	/* ms word */
 
 /*
  * From our initial estimate, three iterations are enough to get us
@@ -148,14 +167,14 @@
 	mull	%esi
 /* guess^2 now in %edx:%eax */
 
-	movl	fsqrt_arg_1,%ecx
+	movl	FPU_fsqrt_arg_1,%ecx
 	subl	%ecx,%eax
-	movl	fsqrt_arg_2,%ecx	/* ms word of normalized n */
+	movl	FPU_fsqrt_arg_2,%ecx	/* ms word of normalized n */
 	sbbl	%ecx,%edx
 	jnc	sqrt_stage_2_positive
 
-/* subtraction gives a negative result */
-/* negate the result before division */
+/* Subtraction gives a negative result,
+   negate the result before division. */
 	notl	%edx
 	notl	%eax
 	addl	$1,%eax
@@ -192,7 +211,7 @@
 
 #ifdef PARANOID
 /* It should be possible to get here only if the arg is ffff....ffff */
-	cmp	$0xffffffff,fsqrt_arg_1
+	cmp	$0xffffffff,FPU_fsqrt_arg_1
 	jnz	sqrt_stage_2_error
 #endif PARANOID
 
@@ -212,50 +231,50 @@
 
 sqrt_stage_2_done:
 
-/* Now the square root has been computed to better than 60 bits */
+/* Now the square root has been computed to better than 60 bits. */
 
-/* Find the square of the guess */
+/* Find the square of the guess. */
 	movl	%edi,%eax		/* ls word of guess */
 	mull	%edi
-	movl	%edx,accum_1
+	movl	%edx,FPU_accum_1
 
 	movl	%esi,%eax
 	mull	%esi
-	movl	%edx,accum_3
-	movl	%eax,accum_2
+	movl	%edx,FPU_accum_3
+	movl	%eax,FPU_accum_2
 
 	movl	%edi,%eax
 	mull	%esi
-	addl	%eax,accum_1
-	adcl	%edx,accum_2
-	adcl	$0,accum_3
+	addl	%eax,FPU_accum_1
+	adcl	%edx,FPU_accum_2
+	adcl	$0,FPU_accum_3
 
 /*	movl	%esi,%eax */
 /*	mull	%edi */
-	addl	%eax,accum_1
-	adcl	%edx,accum_2
-	adcl	$0,accum_3
+	addl	%eax,FPU_accum_1
+	adcl	%edx,FPU_accum_2
+	adcl	$0,FPU_accum_3
 
-/* guess^2 now in accum_3:accum_2:accum_1 */
+/* guess^2 now in FPU_accum_3:FPU_accum_2:FPU_accum_1 */
 
-	movl	fsqrt_arg_0,%eax		/* get normalized n */
-	subl	%eax,accum_1
-	movl	fsqrt_arg_1,%eax
-	sbbl	%eax,accum_2
-	movl	fsqrt_arg_2,%eax		/* ms word of normalized n */
-	sbbl	%eax,accum_3
+	movl	FPU_fsqrt_arg_0,%eax		/* get normalized n */
+	subl	%eax,FPU_accum_1
+	movl	FPU_fsqrt_arg_1,%eax
+	sbbl	%eax,FPU_accum_2
+	movl	FPU_fsqrt_arg_2,%eax		/* ms word of normalized n */
+	sbbl	%eax,FPU_accum_3
 	jnc	sqrt_stage_3_positive
 
-/* subtraction gives a negative result */
-/* negate the result before division */
-	notl	accum_1
-	notl	accum_2
-	notl	accum_3
-	addl	$1,accum_1
-	adcl	$0,accum_2
+/* Subtraction gives a negative result,
+   negate the result before division */
+	notl	FPU_accum_1
+	notl	FPU_accum_2
+	notl	FPU_accum_3
+	addl	$1,FPU_accum_1
+	adcl	$0,FPU_accum_2
 
 #ifdef PARANOID
-	adcl	$0,accum_3	/* This must be zero */
+	adcl	$0,FPU_accum_3	/* This must be zero */
 	jz	sqrt_stage_3_no_error
 
 sqrt_stage_3_error:
@@ -265,8 +284,8 @@
 sqrt_stage_3_no_error:
 #endif PARANOID
 
-	movl	accum_2,%edx
-	movl	accum_1,%eax
+	movl	FPU_accum_2,%edx
+	movl	FPU_accum_1,%eax
 	divl	%esi
 	movl	%eax,%ecx
 
@@ -284,8 +303,8 @@
 	jmp	sqrt_stage_3_finished
 
 sqrt_stage_3_positive:
-	movl	accum_2,%edx
-	movl	accum_1,%eax
+	movl	FPU_accum_2,%edx
+	movl	FPU_accum_1,%eax
 	divl	%esi
 	movl	%eax,%ecx
 
@@ -333,7 +352,7 @@
 	movl	PARAM1,%edi
 	movl	EXP_BIAS,EXP(%edi)	/* Result is in  [1.0 .. 2.0) */
 	movl	PARAM2,%ecx
-	jmp	FPU_round_sqrt
+	jmp	fpu_reg_round_sqrt
 
 
 sqrt_near_exact_x:
@@ -398,8 +417,8 @@
 
 
 sqrt_get_more_precision:
-/* This case is almost the same as the above, except we start */
-/* with an extra bit of precision in the estimate. */
+/* This case is almost the same as the above, except we start
+   with an extra bit of precision in the estimate. */
 	stc			/* The extra bit. */
 	rcll	$1,%edi		/* Shift the estimate left one bit */
 	rcll	$1,%esi
diff --git a/drivers/Makefile b/drivers/Makefile
index fdb28d2..a30e4a7 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -33,14 +33,10 @@
 all: driversubdirs
 
 driversubdirs: dummy
-	@for i in $(SUBDIRS); do (cd $$i && echo $$i && $(MAKE)) || exit; done
-
-clean:
-	rm -f core *.o *.a *.s
-	for i in $(SUBDIRS); do (cd $$i && $(MAKE) clean); done
+	set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i; done
 
 dep:
-	for i in $(SUBDIRS); do (cd $$i && $(MAKE) dep) || exit; done
+	set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i dep; done
 
 dummy:
 
diff --git a/drivers/block/Makefile b/drivers/block/Makefile
index ab80be1..253de65 100644
--- a/drivers/block/Makefile
+++ b/drivers/block/Makefile
@@ -51,10 +51,6 @@
 	$(AR) rcs block.a $(OBJS)
 	sync
 
-clean: 
-	rm -f core *.o *.a *.s
-	for i in $(ALL_SUBDIRS); do (cd $$i && $(MAKE) clean); done
-
 dep:
 	$(CPP) -M $(SRCS) > .depend
 
diff --git a/drivers/block/blk.h b/drivers/block/blk.h
index 0f5cb8f..970ba4d 100644
--- a/drivers/block/blk.h
+++ b/drivers/block/blk.h
@@ -1,6 +1,7 @@
 #ifndef _BLK_H
 #define _BLK_H
 
+#include <linux/major.h>
 #include <linux/sched.h>
 #include <linux/locks.h>
 #include <linux/genhd.h>
@@ -15,7 +16,7 @@
  * buffers when they are in the queue. 64 seems to be too many (easily
  * long pauses in reading when heavy writing/syncing is going on)
  */
-#define NR_REQUEST	32
+#define NR_REQUEST	64
 
 /*
  * Ok, this is an expanded form so that we can use the same
@@ -71,7 +72,6 @@
 
 extern struct sec_size * blk_sec[MAX_BLKDEV];
 extern struct blk_dev_struct blk_dev[MAX_BLKDEV];
-extern struct request request[NR_REQUEST];
 extern struct wait_queue * wait_for_request;
 extern void resetup_one_dev(struct gendisk *dev, int drive);
 
@@ -104,7 +104,8 @@
  * supported are hard-disks and floppies.
  */
 
-#if (MAJOR_NR == 1)
+#if (MAJOR_NR == MEM_MAJOR)
+
 /* ram disk */
 #define DEVICE_NAME "ramdisk"
 #define DEVICE_REQUEST do_rd_request
@@ -112,8 +113,8 @@
 #define DEVICE_ON(device) 
 #define DEVICE_OFF(device)
 
-#elif (MAJOR_NR == 2)
-/* floppy */
+#elif (MAJOR_NR == FLOPPY_MAJOR)
+
 static void floppy_on(unsigned int nr);
 static void floppy_off(unsigned int nr);
 
@@ -124,7 +125,8 @@
 #define DEVICE_ON(device) floppy_on(DEVICE_NR(device))
 #define DEVICE_OFF(device) floppy_off(DEVICE_NR(device))
 
-#elif (MAJOR_NR == 3)
+#elif (MAJOR_NR == HD_MAJOR)
+
 /* harddisk: timeout is 6 seconds.. */
 #define DEVICE_NAME "harddisk"
 #define DEVICE_INTR do_hd
@@ -135,8 +137,8 @@
 #define DEVICE_ON(device)
 #define DEVICE_OFF(device)
 
-#elif (MAJOR_NR == 8)
-/* scsi disk */
+#elif (MAJOR_NR == SCSI_DISK_MAJOR)
+
 #define DEVICE_NAME "scsidisk"
 #define DEVICE_INTR do_sd  
 #define TIMEOUT_VALUE 200
@@ -145,17 +147,16 @@
 #define DEVICE_ON(device)
 #define DEVICE_OFF(device)
 
-#elif (MAJOR_NR == 9)
-/* scsi tape */
+#elif (MAJOR_NR == SCSI_TAPE_MAJOR)
+
 #define DEVICE_NAME "scsitape"
 #define DEVICE_INTR do_st  
-#define DEVICE_REQUEST do_st_request
 #define DEVICE_NR(device) (MINOR(device))
 #define DEVICE_ON(device)
 #define DEVICE_OFF(device)
 
-#elif (MAJOR_NR == 11)
-/* scsi CD-ROM */
+#elif (MAJOR_NR == SCSI_CDROM_MAJOR)
+
 #define DEVICE_NAME "CD-ROM"
 #define DEVICE_INTR do_sr
 #define DEVICE_REQUEST do_sr_request
@@ -163,24 +164,24 @@
 #define DEVICE_ON(device)
 #define DEVICE_OFF(device)
 
-#elif (MAJOR_NR == 13)
-/* xt hard disk */
+#elif (MAJOR_NR == XT_DISK_MAJOR)
+
 #define DEVICE_NAME "xt disk"
 #define DEVICE_REQUEST do_xd_request
 #define DEVICE_NR(device) (MINOR(device) >> 6)
 #define DEVICE_ON(device)
 #define DEVICE_OFF(device)
 
-#elif (MAJOR_NR == 15)
-/* CDU31A CD-ROM */
+#elif (MAJOR_NR == CDU31A_CDROM_MAJOR)
+
 #define DEVICE_NAME "CDU31A"
 #define DEVICE_REQUEST do_cdu31a_request
 #define DEVICE_NR(device) (MINOR(device))
 #define DEVICE_ON(device)
 #define DEVICE_OFF(device)
 
-#elif (MAJOR_NR == 23)
-/* MITSUMI CD-ROM */
+#elif (MAJOR_NR == MITSUMI_CDROM_MAJOR)
+
 #define DEVICE_NAME "Mitsumi CD-ROM"
 /* #define DEVICE_INTR do_mcd */
 #define DEVICE_REQUEST do_mcd_request
@@ -189,12 +190,12 @@
 #define DEVICE_OFF(device)
 
 #else
-/* unknown blk device */
+
 #error "unknown blk device"
 
 #endif
 
-#if (MAJOR_NR != 9)
+#if (MAJOR_NR != SCSI_TAPE_MAJOR)
 
 #ifndef CURRENT
 #define CURRENT (blk_dev[MAJOR_NR].current_request)
@@ -227,8 +228,10 @@
 #endif
 static void (DEVICE_REQUEST)(void);
 
-/* SCSI devices have their own version */
-#if (MAJOR_NR != 8 && MAJOR_NR != 9 && MAJOR_NR != 11)
+/* end_request() - SCSI devices have their own version */
+
+#if ! SCSI_MAJOR(MAJOR_NR)
+
 static void end_request(int uptodate)
 {
 	struct request * req;
@@ -239,7 +242,8 @@
 	req->errors = 0;
 	if (!uptodate) {
 		printk(DEVICE_NAME " I/O error\n");
-		printk("dev %04x, sector %d\n",req->dev,req->sector);
+		printk("dev %04lX, sector %lu\n",
+		       (unsigned long)req->dev, req->sector);
 		req->nr_sectors--;
 		req->nr_sectors &= ~SECTOR_MASK;
 		req->sector += (BLOCK_SIZE / 512);
diff --git a/drivers/block/cdu31a.c b/drivers/block/cdu31a.c
index 64d90fc..4a56d16 100644
--- a/drivers/block/cdu31a.c
+++ b/drivers/block/cdu31a.c
@@ -68,6 +68,7 @@
 #include <linux/kernel.h>
 #include <linux/hdreg.h>
 #include <linux/genhd.h>
+#include <linux/ioport.h>
 
 #include <asm/system.h>
 #include <asm/io.h>
@@ -76,7 +77,7 @@
 #include <linux/cdrom.h>
 #include <linux/cdu31a.h>
 
-#define MAJOR_NR 15
+#define MAJOR_NR CDU31A_CDROM_MAJOR
 #include "blk.h"
 
 
@@ -616,6 +617,9 @@
        && (num_retries < MAX_CDU31A_RETRIES))
    {
       num_retries++;
+      current->state = TASK_INTERRUPTIBLE;
+      current->timeout = jiffies + 10; /* Wait .1 seconds on retries */
+      schedule();
       goto retry_data_operation;
    }
 
@@ -693,6 +697,9 @@
        && (num_retries < MAX_CDU31A_RETRIES))
    {
       num_retries++;
+      current->state = TASK_INTERRUPTIBLE;
+      current->timeout = jiffies + 10; /* Wait .1 seconds on retries */
+      schedule();
       goto retry_cd_operation;
    }
 
@@ -1129,8 +1136,8 @@
 static int
 scd_ioctl(struct inode *inode,
           struct file  *file,
-          unsigned int cmd,
-          unsigned int arg)
+          unsigned int  cmd,
+          unsigned long arg)
 {
    unsigned int dev;
    unsigned char res_reg[2];
@@ -1449,10 +1456,14 @@
 {
    unsigned char res_reg[2];
    unsigned int res_size;
+   int num_spin_ups;
 
 
    if (!sony_spun_up)
    {
+      num_spin_ups = 0;
+
+respinup_on_open:
       do_sony_cd_cmd(SONY_SPIN_UP_CMD, NULL, 0, res_reg, &res_size);
 
       /* The drive sometimes returns error 0.  I don't know why, but ignore
@@ -1475,6 +1486,15 @@
             goto drive_spinning;
          }
 
+         /* If the drive says it is not spun up (even though we just did it!)
+            then retry the operation at least a few times. */
+         if (   (res_reg[1] == SONY_NOT_SPIN_ERR)
+             && (num_spin_ups < MAX_CDU31A_RETRIES))
+         {
+            num_spin_ups++;
+            goto respinup_on_open;
+         }
+
          printk("Sony CDROM error 0x%2.2x (scd_open, read toc)\n", res_reg[1]);
          do_sony_cd_cmd(SONY_SPIN_DOWN_CMD, NULL, 0, res_reg, &res_size);
          
@@ -1539,7 +1559,8 @@
    scd_ioctl,              /* ioctl */
    NULL,                   /* mmap */
    scd_open,               /* open */
-   scd_release             /* release */
+   scd_release,            /* release */
+   NULL                    /* fsync */
 };
 
 
@@ -1641,12 +1662,17 @@
    while (   (cdu31a_addresses[i] != 0)
           && (!drive_found))
    {
+      if (check_region(cdu31a_addresses[i], 4)) {
+	  i++;
+	  continue;
+      }
       get_drive_configuration(cdu31a_addresses[i],
                                drive_config.exec_status,
                                &res_size);
       if ((res_size > 2) && ((drive_config.exec_status[0] & 0x20) == 0x00))
       {
          drive_found = 1;
+	 snarf_region(cdu31a_addresses[i], 4);
 
          if (register_blkdev(MAJOR_NR,"cdu31a",&scd_fops))
          {
diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c
index 493571e..37eb05d 100644
--- a/drivers/block/floppy.c
+++ b/drivers/block/floppy.c
@@ -81,7 +81,7 @@
 #include <asm/io.h>
 #include <asm/segment.h>
 
-#define MAJOR_NR 2
+#define MAJOR_NR FLOPPY_MAJOR
 #include "blk.h"
 
 static unsigned int changed_floppies = 0, fake_change = 0;
@@ -393,17 +393,19 @@
 {
 	unsigned int mask = 1 << (bh->b_dev & 0x03);
 
-	if (MAJOR(bh->b_dev) != 2) {
+	if (MAJOR(bh->b_dev) != MAJOR_NR) {
 		printk("floppy_changed: not a floppy\n");
 		return 0;
 	}
 	if (fake_change & mask) {
+		buffer_track = -1;
 		fake_change &= ~mask;
 /* omitting the next line breaks formatting in a horrible way ... */
 		changed_floppies &= ~mask;
 		return 1;
 	}
 	if (changed_floppies & mask) {
+		buffer_track = -1;
 		changed_floppies &= ~mask;
 		recalibrate = 1;
 		return 1;
@@ -453,7 +455,7 @@
 	if (read_track) {
 /* mark buffer-track bad, in case all this fails.. */
 		buffer_drive = buffer_track = -1;
-		count = floppy->sect*2*512;
+		count = floppy->sect*floppy->head*512;
 		addr = (long) floppy_track_buffer;
 	} else if (addr >= LAST_DMA_ADDR) {
 		addr = (long) tmp_floppy_area;
@@ -1166,6 +1168,7 @@
 			sti();
 			okay = format_status == FORMAT_OKAY;
 			format_status = FORMAT_NONE;
+			floppy_off(drive & 3);
 			wake_up(&format_done);
 			return okay ? 0 : -EIO;
 		case FDFLUSH:
diff --git a/drivers/block/hd.c b/drivers/block/hd.c
index 5651176..b4dd66a 100644
--- a/drivers/block/hd.c
+++ b/drivers/block/hd.c
@@ -17,8 +17,6 @@
  */
 
 
-#define HD_IRQ 14
-
 #include <linux/errno.h>
 #include <linux/signal.h>
 #include <linux/sched.h>
@@ -34,9 +32,11 @@
 #include <asm/io.h>
 #include <asm/segment.h>
 
-#define MAJOR_NR 3
+#define MAJOR_NR HD_MAJOR
 #include "blk.h"
 
+#define HD_IRQ 14
+
 static int revalidate_hddisk(int, int);
 
 static inline unsigned char CMOS_READ(unsigned char addr)
@@ -121,6 +121,7 @@
 	hd_info[hdind].wpcom = 0;
 	hd_info[hdind].lzone = ints[1];
 	hd_info[hdind].ctl = (ints[2] > 8 ? 8 : 0);
+	NR_HD = hdind+1;
 }
 
 static int win_result(void)
@@ -642,20 +643,20 @@
 static void hd_geninit(void)
 {
 	int drive, i;
-#ifndef HD_TYPE
 	extern struct drive_info drive_info;
-	void *BIOS = (void *) &drive_info;
+	unsigned char *BIOS = (unsigned char *) &drive_info;
 	int cmos_disks;
-	   
-	for (drive=0 ; drive<2 ; drive++) {
-		hd_info[drive].cyl = *(unsigned short *) BIOS;
-		hd_info[drive].head = *(unsigned char *) (2+BIOS);
-		hd_info[drive].wpcom = *(unsigned short *) (5+BIOS);
-		hd_info[drive].ctl = *(unsigned char *) (8+BIOS);
-		hd_info[drive].lzone = *(unsigned short *) (12+BIOS);
-		hd_info[drive].sect = *(unsigned char *) (14+BIOS);
-		BIOS += 16;
-	}
+
+	if (!NR_HD) {	   
+		for (drive=0 ; drive<2 ; drive++) {
+			hd_info[drive].cyl = *(unsigned short *) BIOS;
+			hd_info[drive].head = *(2+BIOS);
+			hd_info[drive].wpcom = *(unsigned short *) (5+BIOS);
+			hd_info[drive].ctl = *(8+BIOS);
+			hd_info[drive].lzone = *(unsigned short *) (12+BIOS);
+			hd_info[drive].sect = *(14+BIOS);
+			BIOS += 16;
+		}
 
 	/*
 		We querry CMOS about hard disks : it could be that 
@@ -679,14 +680,12 @@
 		
 	*/
 
-	if ((cmos_disks = CMOS_READ(0x12)) & 0xf0)
-		if (cmos_disks & 0x0f)
-			NR_HD = 2;
-		else
-			NR_HD = 1;
-	else
-		NR_HD = 0;
-#endif
+		if ((cmos_disks = CMOS_READ(0x12)) & 0xf0)
+			if (cmos_disks & 0x0f)
+				NR_HD = 2;
+			else
+				NR_HD = 1;
+	}
 	i = NR_HD;
 	while (i-- > 0) {
 		hd[i<<6].nr_sects = 0;
diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c
index 7ffcd76..1473621 100644
--- a/drivers/block/ll_rw_blk.c
+++ b/drivers/block/ll_rw_blk.c
@@ -22,7 +22,7 @@
  * The request-struct contains all necessary data
  * to load a nr of sectors into memory
  */
-struct request request[NR_REQUEST];
+static struct request all_requests[NR_REQUEST];
 
 /*
  * used to wait on when there are no free requests
@@ -69,6 +69,51 @@
  */
 int * blksize_size[MAX_BLKDEV] = { NULL, NULL, };
 
+/*
+ * look for a free request in the first N entries.
+ * NOTE: interrupts must be disabled on the way in, and will still
+ *       be disabled on the way out.
+ */
+static inline struct request * get_request(int n, int dev)
+{
+	static struct request *prev_found = NULL, *prev_limit = NULL;
+	register struct request *req, *limit;
+
+	if (n <= 0)
+		panic("get_request(%d): impossible!\n", n);
+
+	limit = all_requests + n;
+	if (limit != prev_limit) {
+		prev_limit = limit;
+		prev_found = all_requests;
+	}
+	req = prev_found;
+	for (;;) {
+		req = ((req > all_requests) ? req : limit) - 1;
+		if (req->dev < 0)
+			break;
+		if (req == prev_found)
+			return NULL;
+	}
+	prev_found = req;
+	req->dev = dev;
+	return req;
+}
+
+/*
+ * wait until a free request in the first N entries is available.
+ * NOTE: interrupts must be disabled on the way in, and will still
+ *       be disabled on the way out.
+ */
+static inline struct request * get_request_wait(int n, int dev)
+{
+	register struct request *req;
+
+	while ((req = get_request(n, dev)) == NULL)
+		sleep_on(&wait_for_request);
+	return req;
+}
+
 /* RO fail safe mechanism */
 
 static long ro_bits[MAX_BLKDEV][8];
@@ -122,11 +167,9 @@
 	req->next = tmp->next;
 	tmp->next = req;
 
-/* Scsi devices are treated differently */
-	if(MAJOR(req->dev) == 8 || 
-	   MAJOR(req->dev) == 9 ||
-	   MAJOR(req->dev) == 11)
-	  (dev->request_fn)();
+/* for SCSI devices, call request_fn unconditionally */
+	if (scsi_major(MAJOR(req->dev)))
+		(dev->request_fn)();
 
 	sti();
 }
@@ -135,7 +178,7 @@
 {
 	unsigned int sector, count;
 	struct request * req;
-	int rw_ahead;
+	int rw_ahead, max_req;
 
 /* WRITEA/READA is special case - it is not really needed, so if the */
 /* buffer is locked, we just forget about it, else it's a normal read */
@@ -164,33 +207,50 @@
 		unlock_buffer(bh);
 		return;
 	}
-/* The scsi disk drivers completely remove the request from the queue when
-   they start processing an entry.  For this reason it is safe to continue
-   to add links to the top entry for scsi devices */
+
+/* we don't allow the write-requests to fill up the queue completely:
+ * we want some room for reads: they take precedence. The last third
+ * of the requests are only for reads.
+ */
+	max_req = (rw == READ) ? NR_REQUEST : ((NR_REQUEST*2)/3);
+
+/* big loop: look for a free request. */
 
 repeat:
 	cli();
-	if ((major == 3 ||  major == 8 || major == 11)&& (req = blk_dev[major].current_request)) {
-	        if(major == 3) req = req->next;
+
+/* The scsi disk drivers completely remove the request from the queue when
+ * they start processing an entry.  For this reason it is safe to continue
+ * to add links to the top entry for scsi devices.
+ */
+	if ((major == HD_MAJOR
+	     || major == SCSI_DISK_MAJOR
+	     || major == SCSI_CDROM_MAJOR)
+	    && (req = blk_dev[major].current_request))
+	{
+	        if (major == HD_MAJOR)
+			req = req->next;
 		while (req) {
 			if (req->dev == bh->b_dev &&
 			    !req->waiting &&
 			    req->cmd == rw &&
 			    req->sector + req->nr_sectors == sector &&
-			    req->nr_sectors < 254) {
+			    req->nr_sectors < 254)
+			{
 				req->bhtail->b_reqnext = bh;
 				req->bhtail = bh;
 				req->nr_sectors += count;
 				bh->b_dirt = 0;
 				sti();
 				return;
-			      }
-			else if ( req->dev == bh->b_dev &&
+			}
+
+			if (req->dev == bh->b_dev &&
 			    !req->waiting &&
 			    req->cmd == rw &&
 			    req->sector - count == sector &&
 			    req->nr_sectors < 254)
-			    	{
+			{
 			    	req->nr_sectors += count;
 			    	bh->b_reqnext = req->bh;
 			    	req->buffer = bh->b_data;
@@ -200,36 +260,31 @@
 			    	req->bh = bh;
 			    	sti();
 			    	return;
-			    }    
-			req = req->next;
-		      }
-	      }
-/* we don't allow the write-requests to fill up the queue completely:
- * we want some room for reads: they take precedence. The last third
- * of the requests are only for reads.
- */
-	if (rw == READ)
-		req = request+NR_REQUEST;
-	else
-		req = request+(NR_REQUEST/2);
-/* find an empty request */
-	while (--req >= request)
-		if (req->dev < 0)
-			goto found;
-/* if none found, sleep on new requests: check for rw_ahead */
-	if (rw_ahead) {
-		sti();
-		unlock_buffer(bh);
-		return;
-	}
-	sleep_on(&wait_for_request);
-	sti();
-	goto repeat;
+			}    
 
-found:
-/* fill up the request-info, and add it to the queue */
-	req->dev = bh->b_dev;
+			req = req->next;
+		}
+	}
+
+/* find an unused request. */
+	req = get_request(max_req, bh->b_dev);
+
+/* if no request available: if rw_ahead, forget it; otherwise try again. */
+	if (! req) {
+		if (rw_ahead) {
+			sti();
+			unlock_buffer(bh);
+			return;
+		}
+		sleep_on(&wait_for_request);
+		sti();
+		goto repeat;
+	}
+
+/* we found a request. */
 	sti();
+
+/* fill up the request-info, and add it to the queue */
 	req->cmd = rw;
 	req->errors = 0;
 	req->sector = sector;
@@ -258,19 +313,10 @@
 		printk("Can't page to read-only device 0x%X\n",dev);
 		return;
 	}
-repeat:
 	cli();
-	req = request+NR_REQUEST;
-	while (--req >= request)
-		if (req->dev<0)
-			break;
-	if (req < request) {
-		sleep_on(&wait_for_request);
-		goto repeat;
-	}
-/* fill up the request-info, and add it to the queue */
-	req->dev = dev;
+	req = get_request_wait(NR_REQUEST, dev);
 	sti();
+/* fill up the request-info, and add it to the queue */
 	req->cmd = rw;
 	req->errors = 0;
 	req->sector = page<<3;
@@ -292,77 +338,86 @@
 void ll_rw_block(int rw, int nr, struct buffer_head * bh[])
 {
 	unsigned int major;
-
 	struct request plug;
 	int plugged;
 	int correct_size;
 	struct blk_dev_struct * dev;
-	int i, j;
+	int i;
 
 	/* Make sure that the first block contains something reasonable */
-	while(!bh[0]){
-	  bh++;
-	  nr--;
-	  if (nr <= 0) return;
+	while (!*bh) {
+		bh++;
+		if (--nr <= 0)
+			return;
 	};
 
-	if ((major=MAJOR(bh[0]->b_dev)) >= MAX_BLKDEV ||
-	!(blk_dev[major].request_fn)) {
-		printk("ll_rw_block: Trying to read nonexistent block-device %04x (%d)\n",bh[0]->b_dev,bh[0]->b_blocknr);
-		for (i=0;i<nr; i++)
-		  if (bh[i]) bh[i]->b_dirt = bh[i]->b_uptodate = 0;
-		return;
+	dev = NULL;
+	if ((major = MAJOR(bh[0]->b_dev)) < MAX_BLKDEV)
+		dev = blk_dev + major;
+	if (!dev || !dev->request_fn) {
+		printk(
+	"ll_rw_block: Trying to read nonexistent block-device %04lX (%ld)\n",
+		       (unsigned long) bh[0]->b_dev, bh[0]->b_blocknr);
+		goto sorry;
 	}
 
-	for(j=0;j<nr; j++){
-	  if(!bh[j]) continue;
-	  /* Determine correct block size for this device */
-	  correct_size = BLOCK_SIZE;
-	  if(blksize_size[major] && blksize_size[major][MINOR(bh[j]->b_dev)])
-	    correct_size = blksize_size[major][MINOR(bh[j]->b_dev)];
-	  
-	  if(bh[j]->b_size != correct_size) {
-	    
-	    printk("ll_rw_block: only %d-char blocks implemented (%d)\n",
-		   correct_size, bh[j]->b_size);
-	    
-	    for (i=0;i<nr; i++)
-	      if (bh[i]) bh[i]->b_dirt = bh[i]->b_uptodate = 0;
-	    return;
-	  }
-	};
+	/* Determine correct block size for this device.  */
+	correct_size = BLOCK_SIZE;
+	if (blksize_size[major]) {
+		i = blksize_size[major][MINOR(bh[0]->b_dev)];
+		if (i)
+			correct_size = i;
+	}
+
+	/* Verify requested block sizees.  */
+	for (i = 0; i < nr; i++) {
+		if (bh[i] && bh[i]->b_size != correct_size) {
+			printk(
+			"ll_rw_block: only %d-char blocks implemented (%lu)\n",
+			       correct_size, bh[i]->b_size);
+			goto sorry;
+		}
+	}
 
 	if ((rw == WRITE || rw == WRITEA) && is_read_only(bh[0]->b_dev)) {
 		printk("Can't write to read-only device 0x%X\n",bh[0]->b_dev);
-		for (i=0;i<nr; i++)
-		  if (bh[i]) bh[i]->b_dirt = bh[i]->b_uptodate = 0;
-		return;
+		goto sorry;
 	}
-/* If there are no pending requests for this device, then we insert a dummy
-   request for that device.  This will prevent the request from starting until
-   we have shoved all of the blocks into the queue, and then we let it rip */
+
+	/* If there are no pending requests for this device, then we insert
+	   a dummy request for that device.  This will prevent the request
+	   from starting until we have shoved all of the blocks into the
+	   queue, and then we let it rip.  */
 
 	plugged = 0;
 	cli();
-	if (!blk_dev[major].current_request && nr > 1) {
-	  blk_dev[major].current_request = &plug;
-	  plug.dev = -1;
-	  plug.next = NULL;
-	  plugged = 1;
-	};
-	sti();
-	for (i=0;i<nr; i++)
-	  if (bh[i]) {
-	    bh[i]->b_req = 1;
-	    make_request(major, rw, bh[i]);
+	if (!dev->current_request && nr > 1) {
+		dev->current_request = &plug;
+		plug.dev = -1;
+		plug.next = NULL;
+		plugged = 1;
 	}
-	if(plugged){
-	  cli();
-	  blk_dev[major].current_request = plug.next;
-	  dev = major+blk_dev;
-	  (dev->request_fn)();
-	  sti();
-	};
+	sti();
+	for (i = 0; i < nr; i++) {
+		if (bh[i]) {
+			bh[i]->b_req = 1;
+			make_request(major, rw, bh[i]);
+		}
+	}
+	if (plugged) {
+		cli();
+		dev->current_request = plug.next;
+		(dev->request_fn)();
+		sti();
+	}
+	return;
+
+      sorry:
+	for (i = 0; i < nr; i++) {
+		if (bh[i])
+			bh[i]->b_dirt = bh[i]->b_uptodate = 0;
+	}
+	return;
 }
 
 void ll_rw_swap_file(int rw, int dev, unsigned int *b, int nb, char *buf)
@@ -390,17 +445,8 @@
 
 	for (i=0; i<nb; i++, buf += buffersize)
 	{
-repeat:
 		cli();
-		req = request+NR_REQUEST;
-		while (--req >= request)
-			if (req->dev<0)
-				break;
-		if (req < request) {
-			sleep_on(&wait_for_request);
-			goto repeat;
-		}
-		req->dev = dev;
+		req = get_request_wait(NR_REQUEST, dev);
 		sti();
 		req->cmd = rw;
 		req->errors = 0;
@@ -419,11 +465,12 @@
 
 long blk_dev_init(long mem_start, long mem_end)
 {
-	int i;
+	struct request * req;
 
-	for (i=0 ; i<NR_REQUEST ; i++) {
-		request[i].dev = -1;
-		request[i].next = NULL;
+	req = all_requests + NR_REQUEST;
+	while (--req >= all_requests) {
+		req->dev = -1;
+		req->next = NULL;
 	}
 	memset(ro_bits,0,sizeof(ro_bits));
 #ifdef CONFIG_BLK_DEV_HD
diff --git a/drivers/block/mcd.c b/drivers/block/mcd.c
index e6a6206..50e9c31 100644
--- a/drivers/block/mcd.c
+++ b/drivers/block/mcd.c
@@ -44,8 +44,9 @@
 #include <asm/io.h>
 #include <asm/segment.h>
 
-#define MAJOR_NR 23
+#define MAJOR_NR MITSUMI_CDROM_MAJOR
 #include "blk.h"
+
 #include <linux/mcd.h>
 
 #if 0
diff --git a/drivers/block/ramdisk.c b/drivers/block/ramdisk.c
index 2fd4343..4904409 100644
--- a/drivers/block/ramdisk.c
+++ b/drivers/block/ramdisk.c
@@ -17,13 +17,11 @@
 #include <asm/system.h>
 #include <asm/segment.h>
 
-#define MAJOR_RAMDISK	1		/* should be in <linux/major.h>	*/
-#define MAJOR_FLOPPY	2		/* should be in <linux/major.h>	*/
-#define MINOR_RAMDISK	1
-
-#define MAJOR_NR	MAJOR_RAMDISK	/* weird hack- FvK */
+#define MAJOR_NR  MEM_MAJOR
 #include "blk.h"
 
+#define RAMDISK_MINOR	1
+
 
 char	*rd_start;
 int	rd_length = 0;
@@ -39,7 +37,7 @@
 	addr = rd_start + (CURRENT->sector << 9);
 	len = CURRENT->current_nr_sectors << 9;
 
-	if ((MINOR(CURRENT->dev) != MINOR_RAMDISK) ||
+	if ((MINOR(CURRENT->dev) != RAMDISK_MINOR) ||
 	    (addr+len > rd_start+rd_length)) {
 		end_request(0);
 		goto repeat;
@@ -79,11 +77,11 @@
 	int	i;
 	char	*cp;
 
-	if (register_blkdev(MAJOR_RAMDISK,"rd",&rd_fops)) {
-		printk("RAMDISK: Unable to get major %d.\n", MAJOR_RAMDISK);
+	if (register_blkdev(MEM_MAJOR,"rd",&rd_fops)) {
+		printk("RAMDISK: Unable to get major %d.\n", MEM_MAJOR);
 		return 0;
 	}
-	blk_dev[MAJOR_RAMDISK].request_fn = DEVICE_REQUEST;
+	blk_dev[MEM_MAJOR].request_fn = DEVICE_REQUEST;
 	rd_start = (char *) mem_start;
 	rd_length = length;
 	cp = rd_start;
@@ -116,7 +114,7 @@
 					rd_length, (int) rd_start);
 
 	/* If we are doing a diskette boot, we might have to pre-load it. */
-	if (MAJOR(ROOT_DEV) != MAJOR_FLOPPY) return;
+	if (MAJOR(ROOT_DEV) != FLOPPY_MAJOR) return;
 
 	/*
 	 * Check for a super block on the diskette.
@@ -174,7 +172,7 @@
 		printk("\ndone\n");
 
 		/* We loaded the file system image.  Prepare for mounting it. */
-		ROOT_DEV = ((MAJOR_RAMDISK << 8) | MINOR_RAMDISK);
+		ROOT_DEV = ((MEM_MAJOR << 8) | RAMDISK_MINOR);
 		return;
 	}
 }
diff --git a/drivers/block/xd.c b/drivers/block/xd.c
index a2fe529..07a4a42 100644
--- a/drivers/block/xd.c
+++ b/drivers/block/xd.c
@@ -23,7 +23,7 @@
 #include <asm/segment.h>
 #include <asm/dma.h>
 
-#define MAJOR_NR 13
+#define MAJOR_NR XT_DISK_MAJOR
 #include "blk.h"
 
 XD_INFO xd_info[XD_MAXDRIVES];
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index 52651bb..b72485c 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -72,14 +72,7 @@
 
 char.a: $(OBJS)
 	$(AR) rcs char.a $(OBJS)
-	sync
-
-defkeymap.c: defkeymap.map
-	./loadkeys defkeymap.map
-	./mktable	> defkeymap.c
-
-clean: 
-	rm -f core *.o *.a *.s
+	sync	
 
 dep:
 	$(CPP) -M $(SRCS) > .depend
diff --git a/drivers/char/busmouse.c b/drivers/char/busmouse.c
index 79703b4..6e3792c 100644
--- a/drivers/char/busmouse.c
+++ b/drivers/char/busmouse.c
@@ -2,6 +2,10 @@
  * Logitech Bus Mouse Driver for Linux
  * by James Banks
  *
+ * Mods by Matthew Dillon
+ *   calls verify_area()
+ *   tracks better when X is busy or paging
+ *
  * Heavily modified by David Giller
  *   changed from queue- to counter- driven
  *   hacked out a (probably incorrect) mouse_select
@@ -59,83 +63,143 @@
 	if (dx != 0 || dy != 0 || buttons != mouse.buttons) {
 	  mouse.buttons = buttons;
 	  mouse.dx += dx;
-	  mouse.dy += dy;
+	  mouse.dy -= dy;
 	  mouse.ready = 1;
 	  wake_up_interruptible(&mouse.wait);
+
+	  /*
+	   * keep dx/dy reasonable, but still able to track when X (or
+	   * whatever) must page or is busy (i.e. long waits between
+	   * reads)
+	   */
+	  if (mouse.dx < -2048)
+	      mouse.dx = -2048;
+	  if (mouse.dx >  2048)
+	      mouse.dx =  2048;
+
+	  if (mouse.dy < -2048)
+	      mouse.dy = -2048;
+	  if (mouse.dy >  2048)
+	      mouse.dy =  2048;
 	}
 	MSE_INT_ON();
 }
 
-static void release_mouse(struct inode * inode, struct file * file)
+/*
+ * close access to the mouse (can deal with multiple
+ * opens if allowed in the future)
+ */
+
+static void close_mouse(struct inode * inode, struct file * file)
 {
-	MSE_INT_OFF();
-	mouse.active = 0;
-	mouse.ready = 0;
-	free_irq(mouse_irq);
+	if (--mouse.active == 0) {
+	    MSE_INT_OFF();
+	    free_irq(mouse_irq);
+	}
 }
 
+/*
+ * open access to the mouse, currently only one open is
+ * allowed.
+ */
+
 static int open_mouse(struct inode * inode, struct file * file)
 {
 	if (!mouse.present)
 		return -EINVAL;
 	if (mouse.active)
 		return -EBUSY;
-	mouse.active = 1;
 	mouse.ready = 0;
 	mouse.dx = 0;
 	mouse.dy = 0;
 	mouse.buttons = 0x87;
-	if (request_irq(mouse_irq, mouse_interrupt)) {
-		mouse.active = 0;
+	if (request_irq(mouse_irq, mouse_interrupt))
 		return -EBUSY;
-	}
+	mouse.active = 1;
 	MSE_INT_ON();
 	return 0;
 }
 
+/*
+ * writes are disallowed
+ */
 
 static int write_mouse(struct inode * inode, struct file * file, char * buffer, int count)
 {
 	return -EINVAL;
 }
 
+/*
+ * read mouse data.  Currently never blocks.
+ */
+
 static int read_mouse(struct inode * inode, struct file * file, char * buffer, int count)
 {
-	int i;
+	int r;
+	int dx;
+	int dy;
+	unsigned char buttons; 
 
 	if (count < 3)
 		return -EINVAL;
+	if ((r = verify_area(VERIFY_WRITE, buffer, count)))
+		return r;
 	if (!mouse.ready)
 		return -EAGAIN;
+
+	/*
+	 * Obtain the current mouse parameters and limit as appropriate for
+	 * the return data format.  Interrupts are only disabled while 
+	 * obtaining the parameters, NOT during the puts_fs_byte() calls,
+	 * so paging in put_fs_byte() does not effect mouse tracking.
+	 */
+
 	MSE_INT_OFF();
-	put_fs_byte(mouse.buttons | 0x80, buffer);
-	if (mouse.dx < -127)
-		mouse.dx = -127;
-	if (mouse.dx > 127)
-		mouse.dx =  127;
-	put_fs_byte((char)mouse.dx, buffer + 1);
-	if (mouse.dy < -127)
-		mouse.dy = -127;
-	if (mouse.dy > 127)
-		mouse.dy =  127;
-	put_fs_byte((char) -mouse.dy, buffer + 2);
-	for (i = 3; i < count; i++)
-		put_fs_byte(0x00, buffer + i);
-	mouse.dx = 0;
-	mouse.dy = 0;
+	dx = mouse.dx;
+	dy = mouse.dy;
+	if (dx < -127)
+	    dx = -127;
+	if (dx > 127)
+	    dx = 127;
+	if (dy < -127)
+	    dy = -127;
+	if (dy > 127)
+	    dy = 127;
+	buttons = mouse.buttons;
+	mouse.dx -= dx;
+	mouse.dy -= dy;
 	mouse.ready = 0;
 	MSE_INT_ON();
-	return i;
+
+	put_fs_byte(buttons | 0x80, buffer);
+	put_fs_byte((char)dx, buffer + 1);
+	put_fs_byte((char)dy, buffer + 2);
+	for (r = 3; r < count; r++)
+	    put_fs_byte(0x00, buffer + r);
+	return r;
 }
 
+/*
+ * select for mouse input, must disable the mouse interrupt while checking
+ * mouse.ready/select_wait() to avoid race condition (though in reality
+ * such a condition is not fatal to the proper operation of the mouse since
+ * multiple interrupts generally occur).
+ */
+
 static int mouse_select(struct inode *inode, struct file *file, int sel_type, select_table * wait)
 {
-	if (sel_type != SEL_IN)
-		return 0;
-	if (mouse.ready)
-		return 1;
-	select_wait(&mouse.wait, wait);
-	return 0;
+    int r = 0;
+
+    if (sel_type == SEL_IN) {
+    	MSE_INT_OFF();
+    	if (mouse.ready) {
+    	    r = 1;
+    	} else {
+	    select_wait(&mouse.wait, wait);
+    	}
+    	MSE_INT_ON();
+    }
+    return(r);
 }
 
 struct file_operations bus_mouse_fops = {
@@ -147,7 +211,7 @@
 	NULL, 		/* mouse_ioctl */
 	NULL,		/* mouse_mmap */
 	open_mouse,
-	release_mouse,
+	close_mouse,
 };
 
 unsigned long bus_mouse_init(unsigned long kmem_start)
diff --git a/drivers/char/console.c b/drivers/char/console.c
index cfe6b66..3e2b0da 100644
--- a/drivers/char/console.c
+++ b/drivers/char/console.c
@@ -62,7 +62,7 @@
 static void clear_selection(void);
 
 /* Variables for selection control. */
-#define SEL_BUFFER_SIZE 2048
+#define SEL_BUFFER_SIZE TTY_BUF_SIZE
 static int sel_cons;
 static int sel_start = -1;
 static int sel_end;
@@ -73,7 +73,6 @@
 
 extern void vt_init(void);
 extern void register_console(void (*proc)(const char *));
-extern void compute_shiftstate(void);
 
 unsigned long	video_num_columns;		/* Number of text columns	*/
 unsigned long	video_num_lines;		/* Number of test lines		*/
@@ -225,9 +224,9 @@
 	"\040\255\233\234\376\235\174\025\376\376\246\256\252\055\376\376"
 	"\370\361\375\376\376\346\024\371\376\376\247\257\254\253\376\250"
 	"\376\376\376\376\216\217\222\200\376\220\376\376\376\376\376\376"
-	"\376\245\376\376\376\376\231\376\350\376\376\376\232\376\376\341"
+	"\376\245\376\376\376\376\231\376\235\376\376\376\232\376\376\341"
 	"\205\240\203\376\204\206\221\207\212\202\210\211\215\241\214\213"
-	"\376\244\225\242\223\376\224\366\355\227\243\226\201\376\376\230",
+	"\376\244\225\242\223\376\224\366\233\227\243\226\201\376\376\230",
 /* vt100 graphics */
 (unsigned char *)
 	"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
@@ -244,9 +243,9 @@
 	"\376\245\376\376\376\376\231\376\376\376\376\376\232\376\376\341"
 	"\205\240\203\376\204\206\221\207\212\202\210\211\215\241\214\213"
 	"\376\244\225\242\223\376\224\366\376\227\243\226\201\376\376\230",
-/* IBM graphics: minimal translations (CR, LF, LL, SO, SI and ESC) */
+/* IBM graphics: minimal translations (BS, CR, LF, LL, SO, SI and ESC) */
 (unsigned char *)
-	"\000\001\002\003\004\005\006\007\010\011\000\013\000\000\000\000"
+	"\000\001\002\003\004\005\006\007\000\011\000\013\000\000\000\000"
 	"\020\021\022\023\024\025\026\027\030\031\032\000\034\035\036\037"
 	"\040\041\042\043\044\045\046\047\050\051\052\053\054\055\056\057"
 	"\060\061\062\063\064\065\066\067\070\071\072\073\074\075\076\077"
@@ -311,16 +310,17 @@
 
 static inline void __set_origin(unsigned short offset)
 {
+	unsigned long flags;
 #ifdef CONFIG_SELECTION
 	clear_selection();
 #endif /* CONFIG_SELECTION */
-	cli();
+	save_flags(flags); cli();
 	__origin = offset;
 	outb_p(12, video_port_reg);
 	outb_p(offset >> 8, video_port_val);
 	outb_p(13, video_port_reg);
 	outb_p(offset, video_port_val);
-	sti();
+	restore_flags(flags);
 }
 
 void scrollback(int lines)
@@ -365,11 +365,13 @@
 
 static inline void set_cursor(int currcons)
 {
+	unsigned long flags;
+
 	if (currcons != fg_console || console_blanked || vcmode == KD_GRAPHICS)
 		return;
 	if (__real_origin != __origin)
 		set_origin(__real_origin);
-	cli();
+	save_flags(flags); cli();
 	if (deccm) {
 		outb_p(14, video_port_reg);
 		outb_p(0xff&((pos-video_mem_base)>>9), video_port_val);
@@ -377,7 +379,7 @@
 		outb_p(0xff&((pos-video_mem_base)>>1), video_port_val);
 	} else
 		hide_cursor(currcons);
-	sti();
+	restore_flags(flags);
 }
 
 static void scrup(int currcons, unsigned int t, unsigned int b)
@@ -597,7 +599,8 @@
 		video_erase_char = (color << 8) | ' ';
 }
 
-static void default_attr(int currcons) {
+static void default_attr(int currcons)
+{
 	intensity = 1;
 	underline = 0;
 	reverse = 0;
@@ -1436,7 +1439,7 @@
 	gotoxy(currcons,orig_x,orig_y);
 	update_screen(fg_console);
 	printable = 1;
-	printk("Console: %s %s %dx%d, %d virtual consoles\n",
+	printk("Console: %s %s %ldx%ld, %d virtual consoles\n",
 		can_do_color?"colour":"mono",
 		display_desc,
 		video_num_columns,video_num_lines,
@@ -1512,7 +1515,6 @@
 	set_origin(fg_console);
 	set_cursor(new_console);
 	set_leds();
-	compute_shiftstate();
 	lock = 0;
 }
 
@@ -1553,7 +1555,7 @@
 
 #ifdef CONFIG_SELECTION
 /* correction factor for when screen is hardware-scrolled */
-#define	hwscroll_offset ((__real_origin - __origin) << 1)
+#define	hwscroll_offset (currcons == fg_console ? ((__real_origin - __origin) << 1) : 0)
 
 /* set reverse video on characters s-e of console with selection. */
 static void highlight(const int currcons, const int s, const int e)
diff --git a/drivers/char/defkeymap.c b/drivers/char/defkeymap.c
index 0596fab..3193e1f 100644
--- a/drivers/char/defkeymap.c
+++ b/drivers/char/defkeymap.c
@@ -20,7 +20,7 @@
 	0x010b,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
 	0x030e,	0x0702,	0x030d,	0x001c,	0x0701,	0x0205,	0x0114,	0x0603,	
 	0x0118,	0x0601,	0x0602,	0x0117,	0x0600,	0x0119,	0x0115,	0x0116,	
-	0x0122,	0x010c,	0x010d,	0x0120,	0x0121,	0x0110,	0x0311,	0x0200,	
+	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
 	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
 	}, {
 	0x0200,	0x001b,	0x0021,	0x0040,	0x0023,	0x0024,	0x0025,	0x005e,	
@@ -37,41 +37,41 @@
 	0x010b,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
 	0x030e,	0x0702,	0x030d,	0x0200,	0x0701,	0x0205,	0x0114,	0x0603,	
 	0x020b,	0x0601,	0x0602,	0x0117,	0x0600,	0x020a,	0x0115,	0x0116,	
-	0x0122,	0x010c,	0x010d,	0x0120,	0x0121,	0x0110,	0x0311,	0x0200,	
+	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
 	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
 	}, {
-	0x0200,	0x001b,	0x0031,	0x0040,	0x0033,	0x0024,	0x0035,	0x0036,	
-	0x007b,	0x005b,	0x005d,	0x007d,	0x005c,	0x003d,	0x007f,	0x0009,	
-	0x0071,	0x0077,	0x0065,	0x0072,	0x0074,	0x0079,	0x0075,	0x0069,	
-	0x006f,	0x0070,	0x005b,	0x007e,	0x0201,	0x0702,	0x0061,	0x0073,	
-	0x0064,	0x0066,	0x0067,	0x0068,	0x006a,	0x006b,	0x006c,	0x003b,	
-	0x0027,	0x0060,	0x0700,	0x005c,	0x007a,	0x0078,	0x0063,	0x0076,	
-	0x0062,	0x006e,	0x006d,	0x002c,	0x002e,	0x002f,	0x0700,	0x030c,	
-	0x0703,	0x0020,	0x0207,	0x050c,	0x050d,	0x050e,	0x050f,	0x0510,	
+	0x0200,	0x0200,	0x0200,	0x0040,	0x0200,	0x0024,	0x0200,	0x0200,	
+	0x007b,	0x005b,	0x005d,	0x007d,	0x005c,	0x0200,	0x0200,	0x0200,	
+	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
+	0x0200,	0x0200,	0x0200,	0x007e,	0x0201,	0x0702,	0x0200,	0x0200,	
+	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
+	0x0200,	0x0200,	0x0700,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
+	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0700,	0x030c,	
+	0x0703,	0x0200,	0x0207,	0x050c,	0x050d,	0x050e,	0x050f,	0x0510,	
 	0x0511,	0x0512,	0x0513,	0x0514,	0x0515,	0x0208,	0x0202,	0x0307,	
 	0x0308,	0x0309,	0x030b,	0x0304,	0x0305,	0x0306,	0x030a,	0x0301,	
 	0x0302,	0x0303,	0x0300,	0x0310,	0x0206,	0x0200,	0x007c,	0x0516,	
 	0x0517,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
-	0x030e,	0x0702,	0x030d,	0x001c,	0x0701,	0x0205,	0x0114,	0x0603,	
-	0x0118,	0x0601,	0x0602,	0x0117,	0x0600,	0x0119,	0x0115,	0x0116,	
-	0x0122,	0x010c,	0x010d,	0x0120,	0x0121,	0x0110,	0x0311,	0x0200,	
-	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
-	}, {
-	0x0200,	0x001b,	0x0021,	0x0040,	0x0023,	0x0024,	0x0025,	0x005e,	
-	0x0026,	0x002a,	0x0028,	0x0029,	0x005f,	0x002b,	0x007f,	0x0009,	
-	0x0051,	0x0057,	0x0045,	0x0052,	0x0054,	0x0059,	0x0055,	0x0049,	
-	0x004f,	0x0050,	0x007b,	0x007d,	0x0201,	0x0702,	0x0041,	0x0053,	
-	0x0044,	0x0046,	0x0047,	0x0048,	0x004a,	0x004b,	0x004c,	0x003a,	
-	0x0022,	0x007e,	0x0700,	0x007c,	0x005a,	0x0058,	0x0043,	0x0056,	
-	0x0042,	0x004e,	0x004d,	0x003c,	0x003e,	0x003f,	0x0700,	0x030c,	
-	0x0703,	0x0020,	0x0207,	0x010a,	0x010b,	0x010c,	0x010d,	0x010e,	
-	0x010f,	0x0110,	0x0111,	0x0112,	0x0113,	0x0208,	0x0203,	0x0307,	
-	0x0308,	0x0309,	0x030b,	0x0304,	0x0305,	0x0306,	0x030a,	0x0301,	
-	0x0302,	0x0303,	0x0300,	0x0310,	0x0206,	0x0200,	0x003e,	0x010a,	
-	0x010b,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
 	0x030e,	0x0702,	0x030d,	0x0200,	0x0701,	0x0205,	0x0114,	0x0603,	
 	0x0118,	0x0601,	0x0602,	0x0117,	0x0600,	0x0119,	0x0115,	0x0116,	
-	0x0122,	0x010c,	0x010d,	0x0120,	0x0121,	0x0110,	0x0311,	0x0200,	
+	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
+	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
+	}, {
+	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
+	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
+	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
+	0x0200,	0x0200,	0x0200,	0x0200,	0x0201,	0x0702,	0x0200,	0x0200,	
+	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
+	0x0200,	0x0200,	0x0700,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
+	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0700,	0x030c,	
+	0x0703,	0x0200,	0x0207,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
+	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0208,	0x0200,	0x0307,	
+	0x0308,	0x0309,	0x030b,	0x0304,	0x0305,	0x0306,	0x030a,	0x0301,	
+	0x0302,	0x0303,	0x0300,	0x0310,	0x0206,	0x0200,	0x0200,	0x0200,	
+	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
+	0x030e,	0x0702,	0x030d,	0x0200,	0x0701,	0x0205,	0x0114,	0x0603,	
+	0x0118,	0x0601,	0x0602,	0x0117,	0x0600,	0x0119,	0x0115,	0x0116,	
+	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
 	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
 	}, {
 	0x0200,	0x0200,	0x0200,	0x0000,	0x001b,	0x001c,	0x001d,	0x001e,	
@@ -80,7 +80,7 @@
 	0x000f,	0x0010,	0x001b,	0x001d,	0x0201,	0x0702,	0x0001,	0x0013,	
 	0x0004,	0x0006,	0x0007,	0x0008,	0x000a,	0x000b,	0x000c,	0x0200,	
 	0x0007,	0x0000,	0x0700,	0x001c,	0x001a,	0x0018,	0x0003,	0x0016,	
-	0x0002,	0x000e,	0x000d,	0x0200,	0x020e,	0x007f,	0x0700,	0x030c,	
+	0x0002,	0x000e,	0x000d,	0x0200,	0x0200,	0x007f,	0x0700,	0x030c,	
 	0x0703,	0x0000,	0x0207,	0x0100,	0x0101,	0x0102,	0x0103,	0x0104,	
 	0x0105,	0x0106,	0x0107,	0x0108,	0x0109,	0x0208,	0x0204,	0x0307,	
 	0x0308,	0x0309,	0x030b,	0x0304,	0x0305,	0x0306,	0x030a,	0x0301,	
@@ -88,16 +88,16 @@
 	0x010b,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
 	0x030e,	0x0702,	0x030d,	0x001c,	0x0701,	0x0205,	0x0114,	0x0603,	
 	0x0118,	0x0601,	0x0602,	0x0117,	0x0600,	0x0119,	0x0115,	0x0116,	
-	0x0122,	0x010c,	0x010d,	0x0120,	0x0121,	0x0110,	0x0311,	0x0200,	
+	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
 	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
 	}, {
-	0x0200,	0x0200,	0x0200,	0x0000,	0x0200,	0x0200,	0x0200,	0x0200,	
-	0x0200,	0x0200,	0x0200,	0x0200,	0x001f,	0x0200,	0x0200,	0x0200,	
-	0x0011,	0x0017,	0x0005,	0x0012,	0x0014,	0x0019,	0x0015,	0x0009,	
-	0x000f,	0x0010,	0x0200,	0x0200,	0x0201,	0x0702,	0x0001,	0x0013,	
-	0x0004,	0x0006,	0x0007,	0x0008,	0x000a,	0x000b,	0x000c,	0x0200,	
-	0x0200,	0x0200,	0x0700,	0x0200,	0x001a,	0x0018,	0x0003,	0x0016,	
-	0x0002,	0x000e,	0x000d,	0x0200,	0x0200,	0x0200,	0x0700,	0x030c,	
+	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
+	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
+	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
+	0x0200,	0x0200,	0x0200,	0x0200,	0x0201,	0x0702,	0x0200,	0x0200,	
+	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
+	0x0200,	0x0200,	0x0700,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
+	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0700,	0x030c,	
 	0x0703,	0x0200,	0x0207,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
 	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0208,	0x0200,	0x0307,	
 	0x0308,	0x0309,	0x030b,	0x0304,	0x0305,	0x0306,	0x030a,	0x0301,	
@@ -105,16 +105,16 @@
 	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
 	0x030e,	0x0702,	0x030d,	0x0200,	0x0701,	0x0205,	0x0114,	0x0603,	
 	0x0118,	0x0601,	0x0602,	0x0117,	0x0600,	0x0119,	0x0115,	0x0116,	
-	0x0122,	0x010c,	0x010d,	0x0120,	0x0121,	0x0110,	0x0311,	0x0200,	
+	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
 	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
 	}, {
 	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
 	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
-	0x0011,	0x0017,	0x0005,	0x0012,	0x0014,	0x0019,	0x0015,	0x0009,	
-	0x000f,	0x0010,	0x0200,	0x0200,	0x0201,	0x0702,	0x0001,	0x0013,	
-	0x0004,	0x0006,	0x0007,	0x0008,	0x000a,	0x000b,	0x000c,	0x0200,	
-	0x0200,	0x0200,	0x0700,	0x0200,	0x001a,	0x0018,	0x0003,	0x0016,	
-	0x0002,	0x000e,	0x000d,	0x0200,	0x0200,	0x0200,	0x0700,	0x030c,	
+	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
+	0x0200,	0x0200,	0x0200,	0x0200,	0x0201,	0x0702,	0x0200,	0x0200,	
+	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
+	0x0200,	0x0200,	0x0700,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
+	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0700,	0x030c,	
 	0x0703,	0x0200,	0x0207,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
 	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0208,	0x0200,	0x0307,	
 	0x0308,	0x0309,	0x030b,	0x0304,	0x0305,	0x0306,	0x030a,	0x0301,	
@@ -122,16 +122,16 @@
 	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
 	0x030e,	0x0702,	0x030d,	0x0200,	0x0701,	0x0205,	0x0114,	0x0603,	
 	0x0118,	0x0601,	0x0602,	0x0117,	0x0600,	0x0119,	0x0115,	0x020c,	
-	0x0122,	0x010c,	0x010d,	0x0120,	0x0121,	0x0110,	0x0311,	0x0200,	
+	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
 	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
 	}, {
 	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
 	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
-	0x0011,	0x0017,	0x0005,	0x0012,	0x0014,	0x0019,	0x0015,	0x0009,	
-	0x000f,	0x0010,	0x0200,	0x0200,	0x0201,	0x0702,	0x0001,	0x0013,	
-	0x0004,	0x0006,	0x0007,	0x0008,	0x000a,	0x000b,	0x000c,	0x0200,	
-	0x0200,	0x0200,	0x0700,	0x0200,	0x001a,	0x0018,	0x0003,	0x0016,	
-	0x0002,	0x000e,	0x000d,	0x0200,	0x0200,	0x0200,	0x0700,	0x030c,	
+	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
+	0x0200,	0x0200,	0x0200,	0x0200,	0x0201,	0x0702,	0x0200,	0x0200,	
+	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
+	0x0200,	0x0200,	0x0700,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
+	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0700,	0x030c,	
 	0x0703,	0x0200,	0x0207,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
 	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0208,	0x0200,	0x0307,	
 	0x0308,	0x0309,	0x030b,	0x0304,	0x0305,	0x0306,	0x030a,	0x0301,	
@@ -139,7 +139,7 @@
 	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
 	0x030e,	0x0702,	0x030d,	0x0200,	0x0701,	0x0205,	0x0114,	0x0603,	
 	0x0118,	0x0601,	0x0602,	0x0117,	0x0600,	0x0119,	0x0115,	0x0116,	
-	0x0122,	0x010c,	0x010d,	0x0120,	0x0121,	0x0110,	0x0311,	0x0200,	
+	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
 	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
 	}, {
 	0x0200,	0x081b,	0x0831,	0x0832,	0x0833,	0x0834,	0x0835,	0x0836,	
@@ -156,16 +156,16 @@
 	0x050b,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
 	0x030e,	0x0702,	0x030d,	0x001c,	0x0701,	0x0205,	0x0114,	0x0603,	
 	0x0118,	0x0601,	0x0602,	0x0117,	0x0600,	0x0119,	0x0115,	0x0116,	
-	0x0122,	0x010c,	0x010d,	0x0120,	0x0121,	0x0110,	0x0311,	0x0200,	
+	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
 	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
 	}, {
 	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
 	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
-	0x0851,	0x0857,	0x0845,	0x0852,	0x0854,	0x0859,	0x0855,	0x0849,	
-	0x084f,	0x0850,	0x0200,	0x0200,	0x0201,	0x0702,	0x0841,	0x0853,	
-	0x0844,	0x0846,	0x0847,	0x0848,	0x084a,	0x084b,	0x084c,	0x0200,	
-	0x0200,	0x0200,	0x0700,	0x0200,	0x085a,	0x0858,	0x0843,	0x0856,	
-	0x0842,	0x084e,	0x084d,	0x0200,	0x0200,	0x0200,	0x0700,	0x030c,	
+	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
+	0x0200,	0x0200,	0x0200,	0x0200,	0x0201,	0x0702,	0x0200,	0x0200,	
+	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
+	0x0200,	0x0200,	0x0700,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
+	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0700,	0x030c,	
 	0x0703,	0x0200,	0x0207,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
 	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0208,	0x0200,	0x0307,	
 	0x0308,	0x0309,	0x030b,	0x0304,	0x0305,	0x0306,	0x030a,	0x0301,	
@@ -173,16 +173,16 @@
 	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
 	0x030e,	0x0702,	0x030d,	0x0200,	0x0701,	0x0205,	0x0114,	0x0603,	
 	0x0118,	0x0601,	0x0602,	0x0117,	0x0600,	0x0119,	0x0115,	0x0116,	
-	0x0122,	0x010c,	0x010d,	0x0120,	0x0121,	0x0110,	0x0311,	0x0200,	
+	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
 	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
 	}, {
 	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
 	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
-	0x0871,	0x0877,	0x0865,	0x0872,	0x0874,	0x0879,	0x0875,	0x0869,	
-	0x086f,	0x0870,	0x0200,	0x0200,	0x0201,	0x0702,	0x0861,	0x0873,	
-	0x0864,	0x0866,	0x0867,	0x0868,	0x086a,	0x086b,	0x086c,	0x0200,	
-	0x0200,	0x0200,	0x0700,	0x0200,	0x087a,	0x0878,	0x0863,	0x0876,	
-	0x0862,	0x086e,	0x086d,	0x0200,	0x0200,	0x0200,	0x0700,	0x030c,	
+	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
+	0x0200,	0x0200,	0x0200,	0x0200,	0x0201,	0x0702,	0x0200,	0x0200,	
+	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
+	0x0200,	0x0200,	0x0700,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
+	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0700,	0x030c,	
 	0x0703,	0x0200,	0x0207,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
 	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0208,	0x0200,	0x0307,	
 	0x0308,	0x0309,	0x030b,	0x0304,	0x0305,	0x0306,	0x030a,	0x0301,	
@@ -190,16 +190,16 @@
 	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
 	0x030e,	0x0702,	0x030d,	0x0200,	0x0701,	0x0205,	0x0114,	0x0603,	
 	0x0118,	0x0601,	0x0602,	0x0117,	0x0600,	0x0119,	0x0115,	0x0116,	
-	0x0122,	0x010c,	0x010d,	0x0120,	0x0121,	0x0110,	0x0311,	0x0200,	
+	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
 	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
 	}, {
 	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
 	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
-	0x0851,	0x0857,	0x0845,	0x0852,	0x0854,	0x0859,	0x0855,	0x0849,	
-	0x084f,	0x0850,	0x0200,	0x0200,	0x0201,	0x0702,	0x0841,	0x0853,	
-	0x0844,	0x0846,	0x0847,	0x0848,	0x084a,	0x084b,	0x084c,	0x0200,	
-	0x0200,	0x0200,	0x0700,	0x0200,	0x085a,	0x0858,	0x0843,	0x0856,	
-	0x0842,	0x084e,	0x084d,	0x0200,	0x0200,	0x0200,	0x0700,	0x030c,	
+	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
+	0x0200,	0x0200,	0x0200,	0x0200,	0x0201,	0x0702,	0x0200,	0x0200,	
+	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
+	0x0200,	0x0200,	0x0700,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
+	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0700,	0x030c,	
 	0x0703,	0x0200,	0x0207,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
 	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0208,	0x0200,	0x0307,	
 	0x0308,	0x0309,	0x030b,	0x0304,	0x0305,	0x0306,	0x030a,	0x0301,	
@@ -207,16 +207,16 @@
 	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
 	0x030e,	0x0702,	0x030d,	0x0200,	0x0701,	0x0205,	0x0114,	0x0603,	
 	0x0118,	0x0601,	0x0602,	0x0117,	0x0600,	0x0119,	0x0115,	0x0116,	
-	0x0122,	0x010c,	0x010d,	0x0120,	0x0121,	0x0110,	0x0311,	0x0200,	
+	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
 	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
 	}, {
 	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
 	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
-	0x0811,	0x0817,	0x0805,	0x0812,	0x0814,	0x0819,	0x0815,	0x0809,	
-	0x080f,	0x0810,	0x0200,	0x0200,	0x0201,	0x0702,	0x0801,	0x0813,	
-	0x0804,	0x0806,	0x0807,	0x0808,	0x080a,	0x080b,	0x080c,	0x0200,	
-	0x0200,	0x0200,	0x0700,	0x0200,	0x081a,	0x0818,	0x0803,	0x0816,	
-	0x0802,	0x080e,	0x080d,	0x0200,	0x0200,	0x0200,	0x0700,	0x030c,	
+	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
+	0x0200,	0x0200,	0x0200,	0x0200,	0x0201,	0x0702,	0x0200,	0x0200,	
+	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
+	0x0200,	0x0200,	0x0700,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
+	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0700,	0x030c,	
 	0x0703,	0x0200,	0x0207,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
 	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0208,	0x0200,	0x0307,	
 	0x0308,	0x0309,	0x030b,	0x0304,	0x0305,	0x0306,	0x030a,	0x0301,	
@@ -224,16 +224,16 @@
 	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
 	0x030e,	0x0702,	0x030d,	0x0200,	0x0701,	0x0205,	0x0114,	0x0603,	
 	0x0118,	0x0601,	0x0602,	0x0117,	0x0600,	0x0119,	0x0115,	0x020c,	
-	0x0122,	0x010c,	0x010d,	0x0120,	0x0121,	0x0110,	0x0311,	0x0200,	
+	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
 	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
 	}, {
 	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
 	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
-	0x0811,	0x0817,	0x0805,	0x0812,	0x0814,	0x0819,	0x0815,	0x0809,	
-	0x080f,	0x0810,	0x0200,	0x0200,	0x0201,	0x0702,	0x0801,	0x0813,	
-	0x0804,	0x0806,	0x0807,	0x0808,	0x080a,	0x080b,	0x080c,	0x0200,	
-	0x0200,	0x0200,	0x0700,	0x0200,	0x081a,	0x0818,	0x0803,	0x0816,	
-	0x0802,	0x080e,	0x080d,	0x0200,	0x0200,	0x0200,	0x0700,	0x030c,	
+	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
+	0x0200,	0x0200,	0x0200,	0x0200,	0x0201,	0x0702,	0x0200,	0x0200,	
+	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
+	0x0200,	0x0200,	0x0700,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
+	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0700,	0x030c,	
 	0x0703,	0x0200,	0x0207,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
 	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0208,	0x0200,	0x0307,	
 	0x0308,	0x0309,	0x030b,	0x0304,	0x0305,	0x0306,	0x030a,	0x0301,	
@@ -241,16 +241,16 @@
 	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
 	0x030e,	0x0702,	0x030d,	0x0200,	0x0701,	0x0205,	0x0114,	0x0603,	
 	0x0118,	0x0601,	0x0602,	0x0117,	0x0600,	0x0119,	0x0115,	0x0116,	
-	0x0122,	0x010c,	0x010d,	0x0120,	0x0121,	0x0110,	0x0311,	0x0200,	
+	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
 	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
 	}, {
 	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
 	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
-	0x0811,	0x0817,	0x0805,	0x0812,	0x0814,	0x0819,	0x0815,	0x0809,	
-	0x080f,	0x0810,	0x0200,	0x0200,	0x0201,	0x0702,	0x0801,	0x0813,	
-	0x0804,	0x0806,	0x0807,	0x0808,	0x080a,	0x080b,	0x080c,	0x0200,	
-	0x0200,	0x0200,	0x0700,	0x0200,	0x081a,	0x0818,	0x0803,	0x0816,	
-	0x0802,	0x080e,	0x080d,	0x0200,	0x0200,	0x0200,	0x0700,	0x030c,	
+	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
+	0x0200,	0x0200,	0x0200,	0x0200,	0x0201,	0x0702,	0x0200,	0x0200,	
+	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
+	0x0200,	0x0200,	0x0700,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
+	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0700,	0x030c,	
 	0x0703,	0x0200,	0x0207,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
 	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0208,	0x0200,	0x0307,	
 	0x0308,	0x0309,	0x030b,	0x0304,	0x0305,	0x0306,	0x030a,	0x0301,	
@@ -258,16 +258,16 @@
 	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
 	0x030e,	0x0702,	0x030d,	0x0200,	0x0701,	0x0205,	0x0114,	0x0603,	
 	0x0118,	0x0601,	0x0602,	0x0117,	0x0600,	0x0119,	0x0115,	0x0116,	
-	0x0122,	0x010c,	0x010d,	0x0120,	0x0121,	0x0110,	0x0311,	0x0200,	
+	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
 	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
 	}, {
 	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
 	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
-	0x0811,	0x0817,	0x0805,	0x0812,	0x0814,	0x0819,	0x0815,	0x0809,	
-	0x080f,	0x0810,	0x0200,	0x0200,	0x0201,	0x0702,	0x0801,	0x0813,	
-	0x0804,	0x0806,	0x0807,	0x0808,	0x080a,	0x080b,	0x080c,	0x0200,	
-	0x0200,	0x0200,	0x0700,	0x0200,	0x081a,	0x0818,	0x0803,	0x0816,	
-	0x0802,	0x080e,	0x080d,	0x0200,	0x0200,	0x0200,	0x0700,	0x030c,	
+	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
+	0x0200,	0x0200,	0x0200,	0x0200,	0x0201,	0x0702,	0x0200,	0x0200,	
+	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
+	0x0200,	0x0200,	0x0700,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
+	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0700,	0x030c,	
 	0x0703,	0x0200,	0x0207,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
 	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0208,	0x0200,	0x0307,	
 	0x0308,	0x0309,	0x030b,	0x0304,	0x0305,	0x0306,	0x030a,	0x0301,	
@@ -275,7 +275,7 @@
 	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
 	0x030e,	0x0702,	0x030d,	0x0200,	0x0701,	0x0205,	0x0114,	0x0603,	
 	0x0118,	0x0601,	0x0602,	0x0117,	0x0600,	0x0119,	0x0115,	0x0116,	
-	0x0122,	0x010c,	0x010d,	0x0120,	0x0121,	0x0110,	0x0311,	0x0200,	
+	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
 	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	0x0200,	
 	}, 
 };
@@ -313,9 +313,6 @@
 	0, 
 	0, 
 	0, 
-	0, 
-	0, 
-	'\033', '[', 'M', 0, 
 };
 
 char *func_table[NR_FUNC] = {
@@ -351,7 +348,4 @@
 	func_buf + 148,
 	func_buf + 149,
 	func_buf + 150,
-	func_buf + 151,
-	func_buf + 152,
-	func_buf + 153,
 };
diff --git a/drivers/char/defkeymap.map b/drivers/char/defkeymap.map
index bb4c368..cf43e69 100644
--- a/drivers/char/defkeymap.map
+++ b/drivers/char/defkeymap.map
@@ -5,7 +5,6 @@
 	alt     keycode   2 = Meta_one        
 keycode   3 = two              at               at              
 	control keycode   3 = nul             
-	shift control keycode 3 = nul
 	alt     keycode   3 = Meta_two        
 keycode   4 = three            numbersign      
 	control keycode   4 = Escape          
@@ -31,7 +30,6 @@
 	alt     keycode  11 = Meta_zero       
 keycode  12 = minus            underscore       backslash       
 	control keycode  12 = Control_underscore
-	shift control keycode 12 = Control_underscore
 	alt     keycode  12 = Meta_minus      
 keycode  13 = equal            plus            
 	alt     keycode  13 = Meta_equal      
@@ -56,7 +54,7 @@
 	control keycode  27 = Control_bracketright
 	alt     keycode  27 = Meta_bracketright
 keycode  28 = Return          
-	alt     keycode  28 = Meta_Control_m
+	alt     keycode  28 = 0x080d          
 keycode  29 = Control         
 keycode  30 = a               
 keycode  31 = s               
@@ -89,7 +87,6 @@
 keycode  51 = comma            less            
 	alt     keycode  51 = Meta_comma      
 keycode  52 = period           greater         
-	control keycode  52 = Dead_Key_Next
 	alt     keycode  52 = Meta_period     
 keycode  53 = slash            question        
 	control keycode  53 = Delete          
@@ -199,13 +196,13 @@
 keycode 111 = Remove          
 	altgr   control keycode 111 = Boot            
 	control alt     keycode 111 = Boot            
-keycode 112 = Macro
-keycode 113 = F13
-keycode 114 = F14
-keycode 115 = Help
-keycode 116 = Do
-keycode 117 = F17
-keycode 118 = KP_MinPlus
+keycode 112 =
+keycode 113 =
+keycode 114 =
+keycode 115 =
+keycode 116 =
+keycode 117 =
+keycode 118 =
 keycode 119 =
 keycode 120 =
 keycode 121 =
@@ -247,6 +244,3 @@
 string F24 = ""
 string F25 = ""
 string F26 = ""
-string Macro = "\033[M"
-string Help = ""
-string Do = ""
diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c
index 7fcc884..0b1ae66 100644
--- a/drivers/char/keyboard.c
+++ b/drivers/char/keyboard.c
@@ -7,8 +7,8 @@
  * the assembly version by Linus (with diacriticals added)
  *
  * Some additional features added by Christoph Niemann (ChN), March 1993
+ *
  * Loadable keymaps by Risto Kankkunen, May 1993
- * Diacriticals redone & other small changes, aeb@cwi.nl, June 1993
  */
 
 #define KEYBOARD_IRQ 1
@@ -25,8 +25,6 @@
 
 #include <asm/bitops.h>
 
-#define SIZE(x) (sizeof(x)/sizeof((x)[0]))
-
 #ifndef KBD_DEFFLAGS
 
 #ifdef CONFIG_KBD_META
@@ -66,11 +64,8 @@
 
 unsigned char kbd_read_mask = 0x01;	/* modified by psaux.c */
 
-/*
- * global state includes the following, and various static variables
- * in this module: prev_scancode, shift_state, diacr, npadch,
- *   dead_key_next, last_console
- */
+unsigned long kbd_dead_keys = 0;
+unsigned long kbd_prev_dead_keys = 0;
 
 /* shift state counters.. */
 static unsigned char k_down[NR_SHIFT] = {0, };
@@ -79,10 +74,6 @@
 
 static int want_console = -1;
 static int last_console = 0;		/* last used VC */
-static int dead_key_next = 0;
-static int shift_state = 0;
-static int npadch = -1;		        /* -1 or number assembled on pad */
-static unsigned char diacr = 0;
 static char rep = 0;			/* flag telling character repeat */
 struct kbd_struct kbd_table[NR_CONSOLES];
 static struct kbd_struct * kbd = kbd_table;
@@ -112,17 +103,25 @@
 
 /* maximum values each key_handler can handle */
 const int max_vals[] = {
-	255, NR_FUNC - 1, 14, 17, 4, 255, 3, NR_SHIFT,
+	255, NR_FUNC - 1, 13, 16, 4, 255, 3, NR_SHIFT,
 	255, 9, 3
 };
 
-const int NR_TYPES = SIZE(max_vals);
+const int NR_TYPES = (sizeof(max_vals) / sizeof(int));
+
+#define E0_BASE 96
+
+static int shift_state = 0;
+static int diacr = -1;
+static int npadch = 0;
 
 static void put_queue(int);
-static unsigned char handle_diacr(unsigned char);
+static unsigned int handle_diacr(unsigned int);
 
 static struct pt_regs * pt_regs;
 
+static inline void translate(unsigned char scancode);
+
 static inline void kb_wait(void)
 {
 	int i;
@@ -132,65 +131,22 @@
 			break;
 }
 
-/*
- * Translation of escaped scancodes to keysyms.
- * This should be user-settable.
- */
-#define E0_BASE 96
-
-#define E0_KPENTER (E0_BASE+0)
-#define E0_RCTRL   (E0_BASE+1)
-#define E0_KPSLASH (E0_BASE+2)
-#define E0_PRSCR   (E0_BASE+3)
-#define E0_RALT    (E0_BASE+4)
-#define E0_BREAK   (E0_BASE+5)  /* (control-pause) */
-#define E0_HOME    (E0_BASE+6)
-#define E0_UP      (E0_BASE+7)
-#define E0_PGUP    (E0_BASE+8)
-#define E0_LEFT    (E0_BASE+9)
-#define E0_RIGHT   (E0_BASE+10)
-#define E0_END     (E0_BASE+11)
-#define E0_DOWN    (E0_BASE+12)
-#define E0_PGDN    (E0_BASE+13)
-#define E0_INS     (E0_BASE+14)
-#define E0_DEL     (E0_BASE+15)
-/* BTC */
-#define E0_MACRO   (E0_BASE+16)
-/* LK450 */
-#define E0_F13     (E0_BASE+17)
-#define E0_F14     (E0_BASE+18)
-#define E0_HELP    (E0_BASE+19)
-#define E0_DO      (E0_BASE+20)
-#define E0_F17     (E0_BASE+21)
-#define E0_KPMINPLUS (E0_BASE+22)
-
-static unsigned char e0_keys[128] = {
-  0, 0, 0, 0, 0, 0, 0, 0,			      /* 0x00-0x07 */
-  0, 0, 0, 0, 0, 0, 0, 0,			      /* 0x08-0x0f */
-  0, 0, 0, 0, 0, 0, 0, 0,			      /* 0x10-0x17 */
-  0, 0, 0, 0, E0_KPENTER, E0_RCTRL, 0, 0,	      /* 0x18-0x1f */
-  0, 0, 0, 0, 0, 0, 0, 0,			      /* 0x20-0x27 */
-  0, 0, 0, 0, 0, 0, 0, 0,			      /* 0x28-0x2f */
-  0, 0, 0, 0, 0, E0_KPSLASH, 0, E0_PRSCR,	      /* 0x30-0x37 */
-  E0_RALT, 0, 0, 0, 0, E0_F13, E0_F14, E0_HELP,	      /* 0x38-0x3f */
-  E0_DO, E0_F17, 0, 0, 0, 0, E0_BREAK, E0_HOME,	      /* 0x40-0x47 */
-  E0_UP, E0_PGUP, 0, E0_LEFT, 0, E0_RIGHT, E0_KPMINPLUS, E0_END,  /* 0x48-0x4f */
-  E0_DOWN, E0_PGDN, E0_INS, E0_DEL, 0, 0, 0, 0,	      /* 0x50-0x57 */
-  0, 0, 0, 0, 0, 0, 0, 0,			      /* 0x58-0x5f */
-  0, 0, 0, 0, 0, 0, 0, 0,			      /* 0x60-0x67 */
-  0, 0, 0, 0, 0, 0, 0, E0_MACRO,		      /* 0x68-0x6f */
-  0, 0, 0, 0, 0, 0, 0, 0,			      /* 0x70-0x77 */
-  0, 0, 0, 0, 0, 0, 0, 0			      /* 0x78-0x7f */
-};
+static inline void send_cmd(unsigned char c)
+{
+	kb_wait();
+	outb(c,0x64);
+}
 
 static void keyboard_interrupt(int int_pt_regs)
 {
 	unsigned char scancode;
-	static unsigned char prev_scancode = 0; /* remember E0, E1 */
-	char up_flag;
-	char raw_mode;
 
 	pt_regs = (struct pt_regs *) int_pt_regs;
+	kbd_prev_dead_keys |= kbd_dead_keys;
+	if (!kbd_dead_keys)
+		kbd_prev_dead_keys = 0;
+	kbd_dead_keys = 0;
+	send_cmd(0xAD);		/* disable keyboard */
 	kb_wait();
 	if ((inb_p(0x64) & kbd_read_mask) != 0x01)
 		goto end_kbd_intr;
@@ -205,85 +161,109 @@
 	}
 	tty = TTY_TABLE(0);
 	kbd = kbd_table + fg_console;
-	if ((raw_mode = vc_kbd_flag(kbd,VC_RAW))) {
+	if (vc_kbd_flag(kbd,VC_RAW)) {
+		memset(k_down, 0, sizeof(k_down));
+		memset(key_down, 0, sizeof(key_down));
+		shift_state = 0;
 		put_queue(scancode);
-		/* we do not return yet, because we want to maintain
-		   the key_down array, so that we have the correct
-		   values when finishing RAW mode or when changing VT's */
-	}
-	if (scancode == 0xe0 || scancode == 0xe1) {
-		prev_scancode = scancode;
 		goto end_kbd_intr;
-	}
+	} else
+		translate(scancode);
+end_kbd_intr:
+	send_cmd(0xAE);		/* enable keyboard */
+	return;
+}
 
+static inline void translate(unsigned char scancode)
+{
+	char break_flag;
+     	static unsigned char e0_keys[] = {
+		0x1c,	/* keypad enter */
+		0x1d,	/* right control */
+		0x35,	/* keypad slash */
+		0x37,	/* print screen */
+		0x38,	/* right alt */
+		0x46,	/* break (control-pause) */
+		0x47,	/* editpad home */
+		0x48,	/* editpad up */
+		0x49,	/* editpad pgup */
+		0x4b,	/* editpad left */
+		0x4d,	/* editpad right */
+		0x4f,	/* editpad end */
+		0x50,	/* editpad dn */
+		0x51,	/* editpad pgdn */
+		0x52,	/* editpad ins */
+		0x53,	/* editpad del */
+#ifdef LK450
+		0x3d,	/* f13 */
+		0x3e,	/* f14 */
+		0x3f,	/* help */
+		0x40,	/* do */
+		0x41,	/* f17 */
+		0x4e	/* keypad minus/plus */
+#endif
+#ifdef BTC
+		0x6f    /* macro */
+#endif
+	};
+
+	if (scancode == 0xe0) {
+		set_kbd_dead(KGD_E0);
+		return;
+	}
+	if (scancode == 0xe1) {
+		set_kbd_dead(KGD_E1);
+		return;
+	}
 	/*
-	 *  Convert scancode to keysym, using prev_scancode.
+	 *  The keyboard maintains its own internal caps lock and num lock
+	 *  statuses. In caps lock mode E0 AA precedes make code and E0 2A
+	 *  follows break code. In num lock mode, E0 2A precedes make
+	 *  code and E0 AA follows break code. We do our own book-keeping,
+	 *  so we will just ignore these.
 	 */
-	up_flag = scancode > 0x7f;
+	if (kbd_dead(KGD_E0) && (scancode == 0x2a || scancode == 0xaa ||
+				 scancode == 0x36 || scancode == 0xb6))
+		return;
+
+	/* map two byte scancodes into one byte id's */
+
+	break_flag = scancode > 0x7f;
 	scancode &= 0x7f;
 
-	if (prev_scancode == 0xe0) {
-	  prev_scancode = 0;
-  	  /*
-	   *  The keyboard maintains its own internal caps lock and num lock
-	   *  statuses. In caps lock mode E0 AA precedes make code and E0 2A
-	   *  follows break code. In num lock mode, E0 2A precedes make
-	   *  code and E0 AA follows break code. We do our own book-keeping,
-	   *  so we will just ignore these.
-	   */
-	  /*
-	   *  For my keyboard there is no caps lock mode, but there are
-	   *  both Shift-L and Shift-R modes. The former mode generates
-	   *  E0 2A / E0 AA pairs, the latter E0 B6 / E0 36 pairs.
-	   *  So, we should also ignore the latter. - aeb@cwi.nl
-	   */
-	  if (scancode == 0x2a || scancode == 0x36)
-	    goto end_kbd_intr;
-
-	  if (e0_keys[scancode])
-	    scancode = e0_keys[scancode];
-	  else if (!raw_mode) {
-	    printk("keyboard: unknown scancode e0 %02x\n", scancode);
-	    goto end_kbd_intr;
-	  }
-	} else if (scancode >= E0_BASE && !raw_mode) {
-	  printk("keyboard: scancode (%02x) not in range 00 - %2x\n",
-		 scancode, E0_BASE - 1);
-	  goto end_kbd_intr;
+	if (kbd_dead(KGD_E0)) {
+		int i;
+		for (i = 0; i < sizeof(e0_keys); i++)
+			if (scancode == e0_keys[i]) {
+				scancode = E0_BASE + i;
+				i = -1;
+				break;
+			}
+		if (i != -1) {
+#if 0
+			printk("keyboard: unknown scancode e0 %02x\n", scancode);
+#endif
+			return;
+		}
+	} else if (scancode >= E0_BASE) {
+#if 0
+		printk("keyboard: scancode (%02x) not in range 00 - %2x\n", scancode, E0_BASE - 1);
+#endif
+		return;
 	}
 
-	/*
-	 * At this point the variable `scancode' contains the keysym.
-	 * We keep track of the up/down status of the key, and
-	 * return the keysym if in MEDIUMRAW mode.
-	 * Note that the present code requires the application to keep
-	 * track of the up/down status as well - it would probably be
-	 * better to   put_queue(scancode + (up_flag ? 0200 : 0))  .
-	 */
-
-	if (up_flag) {
+	rep = 0;
+	if (break_flag)
 		clear_bit(scancode, key_down);
-		rep = 0;
-	} else
+	else
 		rep = set_bit(scancode, key_down);
 
-	if (raw_mode)
-	        goto end_kbd_intr;
-
 	if (vc_kbd_flag(kbd, VC_MEDIUMRAW)) {
 		put_queue(scancode);
-		goto end_kbd_intr;
+		return;
 	}
 
 	/*
-	 * Small change in philosophy: earlier we defined repetition by
-	 *	 rep = scancode == prev_keysym;
-	 *	 prev_keysym = scancode;
-	 * but now by the fact that the depressed key was down already.
-	 * Does this ever make a difference?
-	 */
-
-	/*
 	 *  Repeat a key only if the input buffers are empty or the
 	 *  characters get echoed locally. This makes key repeat usable
 	 *  with slow applications and under heavy loads.
@@ -295,10 +275,8 @@
 		u_short key_code;
 
 		key_code = key_map[shift_state][scancode];
-		(*key_handler[key_code >> 8])(key_code & 0xff, up_flag);
+		(*key_handler[key_code >> 8])(key_code & 0xff, break_flag);
 	}
-
-end_kbd_intr:
 }
 
 static void put_queue(int ch)
@@ -372,13 +350,13 @@
 	if (!pt_regs)
 		return;
 	printk("\n");
-	printk("EIP: %04x:%08x",0xffff & pt_regs->cs,pt_regs->eip);
+	printk("EIP: %04x:%08lx",0xffff & pt_regs->cs,pt_regs->eip);
 	if (pt_regs->cs & 3)
-		printk(" ESP: %04x:%08x",0xffff & pt_regs->ss,pt_regs->esp);
-	printk(" EFLAGS: %08x\n",pt_regs->eflags);
-	printk("EAX: %08x EBX: %08x ECX: %08x EDX: %08x\n",
+		printk(" ESP: %04x:%08lx",0xffff & pt_regs->ss,pt_regs->esp);
+	printk(" EFLAGS: %08lx\n",pt_regs->eflags);
+	printk("EAX: %08lx EBX: %08lx ECX: %08lx EDX: %08lx\n",
 		pt_regs->orig_eax,pt_regs->ebx,pt_regs->ecx,pt_regs->edx);
-	printk("ESI: %08x EDI: %08x EBP: %08x",
+	printk("ESI: %08lx EDI: %08lx EBP: %08lx",
 		pt_regs->esi, pt_regs->edi, pt_regs->ebp);
 	printk(" DS: %04x ES: %04x FS: %04x GS: %04x\n",
 		0xffff & pt_regs->ds,0xffff & pt_regs->es,
@@ -393,7 +371,7 @@
 		/* pressing srcoll lock 2nd time sends ^Q, ChN */
 		put_queue(START_CHAR(tty));
 	else
-		/* pressing scroll lock 1st time sends ^S, ChN */
+		/* pressing srcoll lock 1st time sends ^S, ChN */
 		put_queue(STOP_CHAR(tty));
 	chg_vc_kbd_flag(kbd,VC_SCROLLOCK);
 }
@@ -442,10 +420,6 @@
 	ctrl_alt_del();
 }
 
-static void dead_next(void)
-{
-        dead_key_next = 1;
-}
 
 static void do_spec(unsigned char value, char up_flag)
 {
@@ -454,12 +428,12 @@
 		NULL,		enter,		show_ptregs,	show_mem,
 		show_state,	send_intr,	lastcons, 	caps_toggle,
 		num,		hold,		scrll_forw,	scrll_back,
-		boot_it,	caps_on,        dead_next
+		boot_it,	caps_on
 	};
 
-	if (up_flag)
+	if (value >= sizeof(fn_table)/sizeof(fnp))
 		return;
-	if (value >= SIZE(fn_table))
+	if (up_flag)
 		return;
 	if (!fn_table[value])
 		return;
@@ -471,14 +445,7 @@
 	if (up_flag)
 		return;		/* no action, if this is a key release */
 
-        if (diacr)
-                value = handle_diacr(value);
-
-        if (dead_key_next) {
-                dead_key_next = 0;
-                diacr = value;
-                return;
-        }
+	value = handle_diacr(value);
 
 	/* kludge... but works for ISO 8859-1 */
 	if (vc_kbd_flag(kbd,VC_CAPSLOCK))
@@ -490,13 +457,8 @@
 	put_queue(value);
 }
 
-#define A_GRAVE  '`'
-#define A_ACUTE  '\''
-#define A_CFLEX  '^'
-#define A_TILDE  '~'
-#define A_DIAER  '"'
 static unsigned char ret_diacr[] =
-        {A_GRAVE, A_ACUTE, A_CFLEX, A_TILDE, A_DIAER };
+	{'`', '\'', '^', '~', '"' };		/* Must not end with 0 */
 
 /* If a dead key pressed twice, output a character corresponding to it,	*/
 /* otherwise just remember the dead key.				*/
@@ -506,12 +468,11 @@
 	if (up_flag)
 		return;
 
-        value = ret_diacr[value];
-        if (diacr == value) {   /* pressed twice */
-                diacr = 0;
-                put_queue(value);
-                return;
-        }
+	if (diacr == value) {	/* pressed twice */
+		diacr = -1;
+		put_queue(ret_diacr[value]);
+		return;
+	}
 	diacr = value;
 }
 
@@ -519,59 +480,40 @@
 /* if space if pressed, return a character corresponding the pending	*/
 /* dead key, otherwise try to combine the two.				*/
 
-unsigned char handle_diacr(unsigned char ch)
+unsigned int handle_diacr(unsigned int ch)
 {
-        static struct {
-          unsigned char diacr, base, result;
-        } accent_table[] = {
-          {A_GRAVE, 'A', '\300'},       {A_GRAVE, 'a', '\340'},
-          {A_ACUTE, 'A', '\301'},       {A_ACUTE, 'a', '\341'},
-          {A_CFLEX, 'A', '\302'},       {A_CFLEX, 'a', '\342'},
-          {A_TILDE, 'A', '\303'},       {A_TILDE, 'a', '\343'},
-          {A_DIAER, 'A', '\304'},       {A_DIAER, 'a', '\344'},
-          {'O',     'A', '\305'},       {'o',     'a', '\345'},
-          {'0',     'A', '\305'},       {'0',     'a', '\345'},
-          {'A',     'A', '\305'},       {'a',     'a', '\345'},
-          {'A',     'E', '\306'},       {'a',     'e', '\346'},
-          {',',     'C', '\307'},       {',',     'c', '\347'},
-          {A_GRAVE, 'E', '\310'},       {A_GRAVE, 'e', '\350'},
-          {A_ACUTE, 'E', '\311'},       {A_ACUTE, 'e', '\351'},
-          {A_CFLEX, 'E', '\312'},       {A_CFLEX, 'e', '\352'},
-          {A_DIAER, 'E', '\313'},       {A_DIAER, 'e', '\353'},
-          {A_GRAVE, 'I', '\314'},       {A_GRAVE, 'i', '\354'},
-          {A_ACUTE, 'I', '\315'},       {A_ACUTE, 'i', '\355'},
-          {A_CFLEX, 'I', '\316'},       {A_CFLEX, 'i', '\356'},
-          {A_DIAER, 'I', '\317'},       {A_DIAER, 'i', '\357'},
-          {'-',     'D', '\320'},       {'-',     'd', '\360'}, /* eth */
-          {A_TILDE, 'N', '\321'},       {A_TILDE, 'n', '\361'},
-          {A_GRAVE, 'O', '\322'},       {A_GRAVE, 'o', '\362'},
-          {A_ACUTE, 'O', '\323'},       {A_ACUTE, 'o', '\363'},
-          {A_CFLEX, 'O', '\324'},       {A_CFLEX, 'o', '\364'},
-          {A_TILDE, 'O', '\325'},       {A_TILDE, 'o', '\365'},
-          {A_DIAER, 'O', '\326'},       {A_DIAER, 'o', '\366'},
-          {'/',     'O', '\330'},       {'/',     'o', '\370'},
-          {A_GRAVE, 'U', '\331'},       {A_GRAVE, 'u', '\371'},
-          {A_ACUTE, 'U', '\332'},       {A_ACUTE, 'u', '\372'},
-          {A_CFLEX, 'U', '\333'},       {A_CFLEX, 'u', '\373'},
-          {A_DIAER, 'U', '\334'},       {A_DIAER, 'u', '\374'},
-          {A_ACUTE, 'Y', '\335'},       {A_ACUTE, 'y', '\375'},
-          {'T',     'H', '\336'},       {'t',     'h', '\376'}, /* thorn */
-          {'s',     's', '\337'},       {A_DIAER, 'y', '\377'},
-          {'s',     'z', '\337'},       {'i',     'j', '\377'}
-        };
-        int d = diacr;
-        int i;
+	static unsigned char accent_table[5][64] = {
+	" \300BCD\310FGH\314JKLMN\322PQRST\331VWXYZ[\\]^_"
+	"`\340bcd\350fgh\354jklmn\362pqrst\371vwxyz{|}~",   /* accent grave */
 
-        diacr = 0;
-        if (ch == ' ')
-                return d;
+	" \301BCD\311FGH\315JKLMN\323PQRST\332VWX\335Z[\\]^_"
+	"`\341bcd\351fgh\355jklmn\363pqrst\372vwx\375z{|}~", /* accent acute */
 
-        for (i = 0; i < SIZE(accent_table); i++)
-          if(accent_table[i].diacr == d && accent_table[i].base == ch)
-            return accent_table[i].result;
+	" \302BCD\312FGH\316JKLMN\324PQRST\333VWXYZ[\\]^_"
+	"`\342bcd\352fgh\356jklmn\364pqrst\373vwxyz{|}~",   /* circumflex */
 
-        put_queue(d);
-        return ch;
+	" \303BCDEFGHIJKLM\321\325PQRSTUVWXYZ[\\]^_"
+	"`\343bcdefghijklm\361\365pqrstuvwxyz{|}~",	    /* tilde */
+
+	" \304BCD\313FGH\317JKLMN\326PQRST\334VWXYZ[\\]^_"
+	"`\344bcd\353fgh\357jklmn\366pqrst\374vwx\377z{|}~" /* dieresis */
+	};
+	int d = diacr, e;
+
+	if (diacr == -1)
+		return ch;
+
+	diacr = -1;
+	if (ch == ' ')
+		return ret_diacr[d];
+
+	if (ch >= 64 && ch <= 122) {
+		e = accent_table[d][ch - 64];
+		if (e != ch)
+			return e;
+	}
+	put_queue(ret_diacr[d]);
+	return ch;
 }
 
 static void do_cons(unsigned char value, char up_flag)
@@ -585,16 +527,13 @@
 {
 	if (up_flag)
 		return;
-	if (value < SIZE(func_table))
-	        puts_queue(func_table[value]);
-	else
-	        printk("do_fn called with value=%d\n", value);
+	puts_queue(func_table[value]);
 }
 
 static void do_pad(unsigned char value, char up_flag)
 {
-	static char *pad_chars = "0123456789+-*/\015,.?";
-	static char *app_map = "pqrstuvwxylSRQMnn?";
+	static char *pad_chars = "0123456789+-*/\015,.";
+	static char *app_map = "pqrstuvwxylSRQMnn";
 
 	if (up_flag)
 		return;		/* no action, if this is a key release */
@@ -671,8 +610,6 @@
 	}
 
 	if (up_flag) {
-	        /* handle the case that two shift or control
-		   keys are depressed simultaneously */
 		if (k_down[value])
 			k_down[value]--;
 	} else
@@ -684,37 +621,12 @@
 		shift_state &= ~ (1 << value);
 
 	/* kludge */
-	if (up_flag && shift_state != old_state && npadch != -1) {
+	if (up_flag && shift_state != old_state && npadch != 0) {
 		put_queue(npadch);
-		npadch = -1;
+		npadch = 0;
 	}
 }
 
-/* called after returning from RAW mode or when changing consoles -
-   recompute k_down[] and shift_state from key_down[] */
-void compute_shiftstate(void)
-{
-        int i, j, k, sym, val;
-
-        shift_state = 0;
-	for(i=0; i < SIZE(k_down); i++)
-	  k_down[i] = 0;
-
-	for(i=0; i < SIZE(key_down); i++)
-	  if(key_down[i]) {	/* skip this word if not a single bit on */
-	    k = (i<<5);
-	    for(j=0; j<32; j++,k++)
-	      if(test_bit(k, key_down)) {
-		sym = key_map[0][k];
-		if(KTYP(sym) == KT_SHIFT) {
-		  val = KVAL(sym);
-		  k_down[val]++;
-		  shift_state |= (1<<val);
-	        }
-	      }
-	  }
-}
-
 static void do_meta(unsigned char value, char up_flag)
 {
 	if (up_flag)
@@ -732,10 +644,7 @@
 	if (up_flag)
 		return;
 
-	if (npadch == -1)
-	        npadch = value;
-	else
-	        npadch = (npadch * 10 + value) % 1000;
+	npadch = (npadch * 10 + value) % 1000;
 }
 
 /* done stupidly to avoid coding in any dependencies of
diff --git a/drivers/char/lp.c b/drivers/char/lp.c
index ce0d63d..ec40297 100644
--- a/drivers/char/lp.c
+++ b/drivers/char/lp.c
@@ -8,6 +8,7 @@
 
 #include <linux/errno.h>
 #include <linux/kernel.h>
+#include <linux/major.h>
 #include <linux/sched.h>
 #include <linux/lp.h>
 #include <linux/malloc.h>
@@ -432,8 +433,8 @@
 	unsigned int testvalue = 0;
 	int count = 0;
 
-	if (register_chrdev(6,"lp",&lp_fops)) {
-		printk("unable to get major 6 for line printer\n");
+	if (register_chrdev(LP_MAJOR,"lp",&lp_fops)) {
+		printk("unable to get major %d for line printer\n", LP_MAJOR);
 		return kmem_start;
 	}
 	/* take on all known port values */
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index 7dbcaa2..f30d39f 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -9,6 +9,7 @@
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
+#include <linux/major.h>
 #include <linux/tty.h>
 #include <linux/mouse.h>
 #include <linux/tpqic02.h>
@@ -110,6 +111,20 @@
 	return 0;
 }
 
+static int read_kmem(struct inode *inode, struct file *file, char *buf, int count)
+{
+	int read1, read2;
+
+	read1 = read_mem(inode, file, buf, count);
+	if (read1 < 0)
+		return read1;
+	read2 = vread(buf + read1, (char *) file->f_pos, count - read1);
+	if (read2 < 0)
+		return read2;
+	file->f_pos += read2;
+	return read1 + read2;
+}
+
 static int read_port(struct inode * inode,struct file * file,char * buf, int count)
 {
 	unsigned int i = file->f_pos;
@@ -224,7 +239,6 @@
 	return file->f_pos;
 }
 
-#define read_kmem	read_mem
 #define write_kmem	write_mem
 #define mmap_kmem	mmap_mem
 #define zero_lseek	null_lseek
@@ -351,13 +365,13 @@
 
 long chr_dev_init(long mem_start, long mem_end)
 {
-	if (register_chrdev(1,"mem",&memory_fops))
-		printk("unable to get major 1 for memory devs\n");
+	if (register_chrdev(MEM_MAJOR,"mem",&memory_fops))
+		printk("unable to get major %d for memory devs\n", MEM_MAJOR);
 	mem_start = tty_init(mem_start);
 #ifdef CONFIG_PRINTER
 	mem_start = lp_init(mem_start);
 #endif
-#if defined (CONFIG_BUSMOUSE) || defined (CONFIG_QUICKPORT_MOUSE) || \
+#if defined (CONFIG_BUSMOUSE) || defined (CONFIG_82C710_MOUSE) || \
     defined (CONFIG_PSMOUSE) || defined (CONFIG_MS_BUSMOUSE) || \
     defined (CONFIG_ATIXL_BUSMOUSE)
 	mem_start = mouse_init(mem_start);
diff --git a/drivers/char/mouse.c b/drivers/char/mouse.c
index 3ea9c47..debc6ea 100644
--- a/drivers/char/mouse.c
+++ b/drivers/char/mouse.c
@@ -19,6 +19,7 @@
 #include <linux/mouse.h>
 #include <linux/config.h>
 #include <linux/kernel.h>
+#include <linux/major.h>
 
 /*
  * note that you can remove any or all of the drivers by undefining
@@ -91,7 +92,8 @@
 #ifdef CONFIG_ATIXL_BUSMOUSE
  	kmem_start = atixl_busmouse_init(kmem_start);
 #endif
-	if (register_chrdev(10,"mouse",&mouse_fops))
-		printk("unable to get major 10 for mouse devices\n");
+	if (register_chrdev(MOUSE_MAJOR,"mouse",&mouse_fops))
+		printk("unable to get major %d for mouse devices\n",
+		       MOUSE_MAJOR);
 	return kmem_start;
 }
diff --git a/drivers/char/msbusmouse.c b/drivers/char/msbusmouse.c
index 0fd252d..8a5bef4 100644
--- a/drivers/char/msbusmouse.c
+++ b/drivers/char/msbusmouse.c
@@ -62,7 +62,7 @@
 	outb(MS_MSE_COMMAND_MODE, MS_MSE_CONTROL_PORT);
 	outb((inb(MS_MSE_DATA_PORT) & 0xdf), MS_MSE_DATA_PORT);
 
-	if (dx != 0 || dy != 0 || buttons != mouse.buttons) {
+	if (dx != 0 || dy != 0 || buttons != mouse.buttons || ((~buttons) & 0x07)) {
 		mouse.buttons = buttons;
 		mouse.dx += dx;
 		mouse.dy += dy;
diff --git a/drivers/char/psaux.c b/drivers/char/psaux.c
index e313633..487b16d 100644
--- a/drivers/char/psaux.c
+++ b/drivers/char/psaux.c
@@ -14,6 +14,11 @@
  *
  * Modified by Johan Myreen (jem@cs.hut.fi) 04Aug93
  *   to include support for QuickPort mouse.
+ *
+ * Changed references to "QuickPort" with "82C710" since "QuickPort"
+ * is not what this driver is all about -- QuickPort is just a
+ * connector type, and this driver is for the mouse port on the Chips
+ * & Technologies 82C710 interface chip. 15Nov93 jem@cs.hut.fi
  */
 
 /* Uncomment the following line if your mouse needs initialization. */
@@ -67,7 +72,7 @@
 #define AUX_IRQ		12
 #define AUX_BUF_SIZE	2048
 
-/* QuickPort definitions */
+/* 82C710 definitions */
 
 #define QP_DATA         0x310		/* Data Port I/O Address */
 #define QP_STATUS       0x311		/* Status Port I/O Address */
@@ -99,7 +104,7 @@
 static int aux_present = 0;
 static int poll_aux_status(void);
 
-#ifdef CONFIG_QUICKPORT_MOUSE
+#ifdef CONFIG_82C710_MOUSE
 static int qp_present = 0;
 static int qp_busy = 0;
 static int qp_data = QP_DATA;
@@ -203,11 +208,11 @@
 }
 
 /*
- * Interrupt handler for the QuickPort. A character
+ * Interrupt handler for the 82C710 mouse port. A character
  * is waiting in the 82C710.
  */
 
-#ifdef CONFIG_QUICKPORT_MOUSE
+#ifdef CONFIG_82C710_MOUSE
 static void qp_interrupt(int cpl)
 {
 	int head = queue->head;
@@ -236,17 +241,17 @@
 	aux_busy = 0;
 }
 
-#ifdef CONFIG_QUICKPORT_MOUSE
+#ifdef CONFIG_82C710_MOUSE
 static void release_qp(struct inode * inode, struct file * file)
 {
 	unsigned char status;
 
 	if (!poll_qp_status())
-	        printk("Warning: QuickPort device busy in release_qp()\n");
+	        printk("Warning: Mouse device busy in release_qp()\n");
 	status = inb_p(qp_status);
 	outb_p(status & ~(QP_ENABLE|QP_INTS_ON), qp_status);
 	if (!poll_qp_status())
-	        printk("Warning: QuickPort device busy in release_qp()\n");
+	        printk("Warning: Mouse device busy in release_qp()\n");
 	free_irq(QP_IRQ);
 	qp_busy = 0;
 }
@@ -280,7 +285,7 @@
 	return 0;
 }
 
-#ifdef CONFIG_QUICKPORT_MOUSE
+#ifdef CONFIG_82C710_MOUSE
 /*
  * Install interrupt handler.
  * Enable the device, enable interrupts. Set qp_busy
@@ -313,7 +318,7 @@
 	outb_p(status, qp_status);              /* Enable interrupts */
 
 	while (!poll_qp_status()) {
-	        printk("Error: QuickPort device busy in open_qp()\n");
+	        printk("Error: Mouse device busy in open_qp()\n");
 		return -EBUSY;
         }
 
@@ -344,9 +349,9 @@
 }
 
 
-#ifdef CONFIG_QUICKPORT_MOUSE
+#ifdef CONFIG_82C710_MOUSE
 /*
- * Write to the QuickPort device.
+ * Write to the 82C710 mouse device.
  */
 
 static int write_qp(struct inode * inode, struct file * file, char * buffer, int count)
@@ -428,19 +433,19 @@
 
 
 /*
- * Initialize driver. First check for QuickPort device; if found
- * forget about the Aux port and use the QuickPort functions.
+ * Initialize driver. First check for a 82C710 chip; if found
+ * forget about the Aux port and use the *_qp functions.
  */
 
 unsigned long psaux_init(unsigned long kmem_start)
 {
         int qp_found = 0;
 
-#ifdef CONFIG_QUICKPORT_MOUSE
-	printk("Probing QuickPort device.\n");
-        if (qp_found = probe_qp()) {
-	        printk("QuickPort pointing device detected -- driver installed.\n");
-/*		printk("QuickPort address = %x (should be 0x310)\n", qp_data); */
+#ifdef CONFIG_82C710_MOUSE
+	printk("Probing 82C710 mouse port device.\n");
+        if ((qp_found = probe_qp())) {
+	        printk("82C710 type pointing device detected -- driver installed.\n");
+/*		printk("82C710 address = %x (should be 0x310)\n", qp_data); */
 		qp_present = 1;
 		psaux_fops.write = write_qp;
 		psaux_fops.open = open_qp;
@@ -492,7 +497,7 @@
 	return !(retries==MAX_RETRIES);
 }
 
-#ifdef CONFIG_QUICKPORT_MOUSE
+#ifdef CONFIG_82C710_MOUSE
 /*
  * Wait for device to send output char and flush any input char.
  */
@@ -526,7 +531,7 @@
 }
 
 /*
- * See if we can find a QuickPort device. Read mouse address.
+ * See if we can find a 82C710 device. Read mouse address.
  */
 
 static int probe_qp(void)
diff --git a/drivers/char/pty.c b/drivers/char/pty.c
index 4cbecab..f3ee83b 100644
--- a/drivers/char/pty.c
+++ b/drivers/char/pty.c
@@ -74,7 +74,7 @@
 
 /*
  * This routine gets called when tty_write has put something into
- * the write_queue. It copies the input to the output-queue of it's
+ * the write_queue. It copies the input to the output-queue of its
  * slave.
  */
 static void pty_write(struct tty_struct * tty)
diff --git a/drivers/char/serial.c b/drivers/char/serial.c
index 9ad20f9..d2b6286 100644
--- a/drivers/char/serial.c
+++ b/drivers/char/serial.c
@@ -41,7 +41,7 @@
  *		Enables automatic IRQ detection.  I've put in some
  * 		fixes to this which should make this work much more
  * 		cleanly than it used to in 0.98pl2-6.  It should be
- * 		much less vulnerable to false IRQ's now.
+ * 		much less vulnerable to false IRQs now.
  * 
  * CONFIG_AST_FOURPORT
  *		Enables support for the AST Fourport serial port.
diff --git a/drivers/char/tpqic02.c b/drivers/char/tpqic02.c
index 5283f42..45e6958 100644
--- a/drivers/char/tpqic02.c
+++ b/drivers/char/tpqic02.c
@@ -154,25 +154,26 @@
 
 #define REALLY_SLOW_IO		/* it sure is ... */
 
-#include <asm/dma.h>
 #include <linux/sched.h>
 #include <linux/timer.h>
 #include <linux/fs.h>
 #include <linux/kernel.h>
-#include <asm/system.h>
-#include <asm/io.h>
-#include <asm/segment.h>
-
+#include <linux/major.h>
 #include <linux/errno.h>
 #include <linux/mtio.h>
 #include <linux/fcntl.h>
 #include <linux/delay.h>
-
 #include <linux/tpqic02.h>
 
+#include <asm/dma.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/segment.h>
+
 /* check existence of required configuration parameters */
-#if !defined(TAPE_QIC02_MAJOR) || !defined(TAPE_QIC02_PORT) || \
-    !defined(TAPE_QIC02_IRQ) || !defined(TAPE_QIC02_DMA)
+#if !defined(TAPE_QIC02_PORT) || \
+    !defined(TAPE_QIC02_IRQ) || \
+    !defined(TAPE_QIC02_DMA)
 #error tape_qic02 configuration error
 #endif
 
@@ -220,7 +221,7 @@
 static volatile unsigned dma_mode = 0;		/* !=0 also means DMA in use */
 static 		flag need_rewind = YES;
 
-static dev_t current_tape_dev = (TAPE_QIC02_MAJOR)<<8;
+static dev_t current_tape_dev = QIC02_TAPE_MAJOR << 8;
 static int extra_blocks_left = BLOCKS_BEYOND_EW;
 
 
@@ -560,7 +561,9 @@
 	ioctl_status.mt_fileno = ioctl_status.mt_blkno = 0;
 
 	outb_p(ctlbits & ~QIC_CTL_RESET, QIC_CTL_PORT);	/* de-assert reset */
-	status_dead = ((inb_p(QIC_STAT_PORT) & QIC_STAT_RESETMASK) != QIC_STAT_RESETVAL);
+	/* KLUDGE FOR G++ BUG */
+	{ int stat = inb_p(QIC_STAT_PORT);
+	  status_dead = ((stat & QIC_STAT_RESETMASK) != QIC_STAT_RESETVAL); }
 	/* if successful, inb(STAT) returned RESETVAL */
 	if (status_dead)
 		printk(TPQIC_NAME ": reset failed!\n");
@@ -2341,7 +2344,7 @@
 
 	/* check iocmd first */
 
-	if (dev_maj != TAPE_QIC02_MAJOR) {
+	if (dev_maj != QIC02_TAPE_MAJOR) {
 		printk(TPQIC_NAME ": Oops! Wrong device?\n");
 		/* A panic() would be appropriate here */
 		return -ENODEV;
@@ -2582,8 +2585,9 @@
 #endif
 
 	/* If we got this far, install driver functions */
-	if (register_chrdev(TAPE_QIC02_MAJOR, TPQIC_NAME, &tape_qic02_fops)) {
-		printk(TPQIC_NAME ": Unable to get chrdev major %d\n", TAPE_QIC02_MAJOR);
+	if (register_chrdev(QIC02_TAPE_MAJOR, TPQIC_NAME, &tape_qic02_fops)) {
+		printk(TPQIC_NAME ": Unable to get chrdev major %d\n",
+		       QIC02_TAPE_MAJOR);
 		return kmem_start;
 	}
 
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index 160eb64..9a4478b 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -35,6 +35,7 @@
  */
 
 #include <linux/types.h>
+#include <linux/major.h>
 #include <linux/errno.h>
 #include <linux/signal.h>
 #include <linux/fcntl.h>
@@ -996,7 +997,7 @@
 	struct tty_struct * tty;
 
 	dev = file->f_rdev;
-	if (MAJOR(dev) != 4) {
+	if (MAJOR(dev) != TTY_MAJOR) {
 		printk("tty_read: bad pseudo-major nr #%d\n", MAJOR(dev));
 		return -EINVAL;
 	}
@@ -1030,8 +1031,8 @@
 
 	dev = file->f_rdev;
 	is_console = (inode->i_rdev == 0x0400);
-	if (MAJOR(dev) != 4) {
-		printk("tty_write: pseudo-major != 4\n");
+	if (MAJOR(dev) != TTY_MAJOR) {
+		printk("tty_write: pseudo-major != TTY_MAJOR\n");
 		return -EINVAL;
 	}
 	dev = MINOR(dev);
@@ -1292,13 +1293,13 @@
 	minor = MINOR(inode->i_rdev);
 	major = MAJOR(inode->i_rdev);
 	noctty = filp->f_flags & O_NOCTTY;
-	if (major == 5) {
+	if (major == TTYAUX_MAJOR) {
 		if (!minor) {
-			major = 4;
+			major = TTY_MAJOR;
 			minor = current->tty;
 		}
 		noctty = 1;
-	} else if (major == 4) {
+	} else if (major == TTY_MAJOR) {
 		if (!minor) {
 			minor = fg_console + 1;
 			noctty = 1;
@@ -1361,8 +1362,8 @@
 	int dev;
 
 	dev = filp->f_rdev;
-	if (MAJOR(dev) != 4) {
-		printk("tty_release: tty pseudo-major != 4\n");
+	if (MAJOR(dev) != TTY_MAJOR) {
+		printk("tty_release: tty pseudo-major != TTY_MAJOR\n");
 		return;
 	}
 	dev = MINOR(filp->f_rdev);
@@ -1379,8 +1380,8 @@
 	struct tty_struct * tty;
 
 	dev = filp->f_rdev;
-	if (MAJOR(dev) != 4) {
-		printk("tty_select: tty pseudo-major != 4\n");
+	if (MAJOR(dev) != TTY_MAJOR) {
+		printk("tty_select: tty pseudo-major != TTY_MAJOR\n");
 		return 0;
 	}
 	dev = MINOR(filp->f_rdev);
@@ -1646,10 +1647,10 @@
 
 	if (sizeof(struct tty_struct) > PAGE_SIZE)
 		panic("size of tty structure > PAGE_SIZE!");
-	if (register_chrdev(4,"tty",&tty_fops))
-		panic("unable to get major 4 for tty device");
-	if (register_chrdev(5,"tty",&tty_fops))
-		panic("unable to get major 5 for tty device");
+	if (register_chrdev(TTY_MAJOR,"tty",&tty_fops))
+		panic("unable to get major %d for tty device", TTY_MAJOR);
+	if (register_chrdev(TTYAUX_MAJOR,"tty",&tty_fops))
+		panic("unable to get major %d for tty device", TTYAUX_MAJOR);
 	for (i=0 ; i< MAX_TTYS ; i++) {
 		tty_table[i] =  0;
 		tty_termios[i] = 0;
diff --git a/drivers/char/tty_ioctl.c b/drivers/char/tty_ioctl.c
index df5d35d..a819573 100644
--- a/drivers/char/tty_ioctl.c
+++ b/drivers/char/tty_ioctl.c
@@ -14,6 +14,7 @@
 #include <linux/sched.h>
 #include <linux/config.h>
 #include <linux/kernel.h>
+#include <linux/major.h>
 #include <linux/tty.h>
 #include <linux/fcntl.h>
 
@@ -419,8 +420,8 @@
 	int termios_dev;
 	int retval;
 
-	if (MAJOR(file->f_rdev) != 4) {
-		printk("tty_ioctl: tty pseudo-major != 4\n");
+	if (MAJOR(file->f_rdev) != TTY_MAJOR) {
+		printk("tty_ioctl: tty pseudo-major != TTY_MAJOR\n");
 		return -EINVAL;
 	}
 	dev = MINOR(file->f_rdev);
diff --git a/drivers/char/vt.c b/drivers/char/vt.c
index deb1662..d1069be 100644
--- a/drivers/char/vt.c
+++ b/drivers/char/vt.c
@@ -33,11 +33,10 @@
  * to the current console is done by the main ioctl code.
  */
 
-struct vt_cons vt_cons[NR_CONSOLES];
+struct vt_struct vt_cons[NR_CONSOLES];
 
 asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on);
 
-extern void compute_shiftstate(void);
 extern void change_console(unsigned int new_console);
 extern void complete_change_console(unsigned int new_console);
 extern int vt_waitactive(void);
@@ -213,7 +212,6 @@
 		} else if (arg == K_XLATE) {
 			clr_vc_kbd_flag(kbd, VC_RAW);
 			clr_vc_kbd_flag(kbd, VC_MEDIUMRAW);
-			compute_shiftstate();
 		} else if (arg == K_MEDIUMRAW) {
 			clr_vc_kbd_flag(kbd, VC_RAW);
 			set_vc_kbd_flag(kbd, VC_MEDIUMRAW);
@@ -273,7 +271,7 @@
 
 	case KDGKBSENT:
 	{
-		const struct kbsentry *a = (struct kbsentry *)arg;
+		struct kbsentry *a = (struct kbsentry *)arg;
 		char *p;
 		u_char *q;
 
diff --git a/drivers/char/vt_kern.h b/drivers/char/vt_kern.h
index 6341140..978119a 100644
--- a/drivers/char/vt_kern.h
+++ b/drivers/char/vt_kern.h
@@ -8,7 +8,7 @@
 
 #include <linux/vt.h>
 
-extern struct vt_cons {
+extern struct vt_struct {
 	unsigned char	vc_mode;		/* KD_TEXT, ... */
 	unsigned char	vc_kbdraw;
 	unsigned char	vc_kbde0;
diff --git a/drivers/net/3c503.c b/drivers/net/3c503.c
index e310156..bf86c6f 100644
--- a/drivers/net/3c503.c
+++ b/drivers/net/3c503.c
@@ -1,4 +1,4 @@
-/* el2.c: A shared-memory NS8390 ethernet driver for linux. */
+/* 3c503.c: A shared-memory NS8390 ethernet driver for linux. */
 /*
     Written 1992,1993 by Donald Becker.
 
@@ -16,7 +16,7 @@
 */
 
 static char *version =
-    "el2.c:v0.99.13 8/30/93 Donald Becker (becker@super.org)\n";
+    "3c503.c:v0.99.13 8/30/93 Donald Becker (becker@super.org)\n";
 
 #include <linux/config.h>
 #include <linux/kernel.h>
diff --git a/drivers/net/3c507.c b/drivers/net/3c507.c
new file mode 100644
index 0000000..64c4532
--- /dev/null
+++ b/drivers/net/3c507.c
@@ -0,0 +1,899 @@
+/* 3c507.c: An EtherLink16 device driver for Linux. */
+/*
+	Written 1993 by Donald Becker.
+	Copyright 1993 United States Government as represented by the Director,
+	National Security Agency.  This software may only be used and distributed
+	according to the terms of the GNU Public License as modified by SRC,
+	incorported herein by reference.
+
+	The author may be reached as becker@super.org or
+	C/O Supercomputing Research Ctr., 17100 Science Dr., Bowie MD 20715
+
+	Thanks go to jennings@Montrouge.SMR.slb.com ( Patrick Jennings)
+	and jrs@world.std.com (Rick Sladkey) for testing and bugfixes.
+
+	Things remaining to do:
+	Verify that the tx and rx buffers don't have fencepost errors.
+	Move the theory of operation and memory map documentation.
+	The statistics need to be updated correctly.
+*/
+
+static char *version =
+	"3c507.c:v0.03 10/27/93 Donald Becker (becker@super.org)\n";
+
+#include <linux/config.h>
+
+/*
+  Sources:
+	This driver wouldn't have been written with the availability of the
+	Crynwr driver source code.	It provided a known-working implementation
+	that filled in the gaping holes of the Intel documention.  Three cheers
+	for Russ Nelson.
+
+	Intel Microcommunications Databook, Vol. 1, 1990. It provides just enough
+	info that the casual reader might think that it documents the i82586.
+*/
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/in.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <errno.h>
+#include <memory.h>
+
+#include "dev.h"
+#include "iow.h"
+#include "eth.h"
+#include "skbuff.h"
+#include "arp.h"
+
+#ifndef HAVE_ALLOC_SKB
+#define alloc_skb(size, priority) (struct sk_buff *) kmalloc(size,priority)
+#define kfree_skbmem(addr, size) kfree_s(addr,size);
+#else
+#include <linux/malloc.h>
+#endif
+
+/* use 0 for production, 1 for verification, 2..7 for debug */
+#ifndef NET_DEBUG
+#define NET_DEBUG 1
+#endif
+static unsigned int net_debug = NET_DEBUG;
+
+/*
+  			Details of the i82586.
+
+   You'll really need the databook to understand the details of this part,
+   but the outline is that the i82586 has two seperate processing units.
+   Both are started from a list of three configuration tables, of which only
+   the last, the System Control Block (SCB), is used after reset-time.  The SCB
+   has the following fileds:
+		Status word
+		Command word
+		Tx/Command block addr.
+		Rx block addr.
+   The command word accepts the following controls for the Tx and Rx units:
+  */
+
+#define	 CUC_START	 0x0100
+#define	 CUC_RESUME	 0x0200
+#define	 CUC_SUSPEND 0x0300
+#define	 RX_START	 0x0010
+#define	 RX_RESUME	 0x0020
+#define	 RX_SUSPEND	 0x0030
+
+/* The Rx unit uses a list of frame descriptors and a list of data buffer
+   descriptors.  We use full-sized (1518 byte) data buffers, so there is
+   a one-to-one pairing of frame descriptors to buffer descriptors.
+
+   The Tx ("command") unit executes a list of commands that look like:
+		Status word		Written by the 82586 when the command is done.
+		Command word	Command in lower 3 bits, post-command action in upper 3
+		Link word		The address of the next command.
+		Parameters		(as needed).
+
+	Some definitions related to the Command Word are:
+ */
+#define CMD_EOL		0x8000			/* The last command of the list, stop. */
+#define CMD_SUSP	0x4000			/* Suspend after doing cmd. */
+#define CMD_INTR	0x2000			/* Interrupt after doing cmd. */
+
+enum commands {
+	CmdNOp = 0, CmdSASetup = 1, CmdConfigure = 2, CmdMulticastList = 3,
+	CmdTx = 4, CmdTDR = 5, CmdDump = 6, CmdDiagnose = 7};
+
+/* Information that need to be kept for each board. */
+struct net_local {
+	struct enet_statistics stats;
+	int last_restart;
+	ushort rx_head;
+	ushort rx_tail;
+	ushort tx_head;
+	ushort tx_cmd_link;
+	ushort tx_reap;
+};
+
+/*
+  		Details of the EtherLink16 Implementation
+  The 3c507 is a generic shared-memory i82586 implementation.
+  The host can map 16K, 32K, 48K, or 64K of the 64K memory into
+  0x0[CD][08]0000, or all 64K into 0xF[02468]0000.
+  */
+
+/* Offsets from the base I/O address. */
+#define	SA_DATA		0	/* Station address data, or 3Com signature. */
+#define MISC_CTRL	6	/* Switch the SA_DATA banks, and bus config bits. */
+#define RESET_IRQ	10	/* Reset the latched IRQ line. */
+#define SIGNAL_CA	11	/* Frob the 82586 Channel Attention line. */
+#define ROM_CONFIG	13
+#define MEM_CONFIG	14
+#define IRQ_CONFIG	15
+
+/* The ID port is used at boot-time to locate the ethercard. */
+#define ID_PORT		0x100
+
+/* Offsets to registers in the mailbox (SCB). */
+#define iSCB_STATUS	0x8
+#define iSCB_CMD		0xA
+#define iSCB_CBL		0xC	/* Command BLock offset. */
+#define iSCB_RFA		0xE	/* Rx Frame Area offset. */
+
+/*
+  What follows in 'init_words[]' is the "program" that is downloaded to the
+  82586 memory.	 It's mostly tables and command blocks, and starts at the
+  reset address 0xfffff6.  This is designed to be similar to the EtherExpress,
+  thus the unusual location of the SCB at 0x0008.
+
+  Even with the additional "don't care" values, doing it this way takes less
+  program space than initializing the individual tables, and I feel it's much
+  cleaner.
+
+  The databook is particularly useless for the first two structures, I had
+  to use the Crynwr driver as an example.
+
+   The memory setup is as follows:
+   */
+
+#define CONFIG_CMD	0x0018
+#define SET_SA_CMD	0x0024
+#define SA_OFFSET	0x002A
+#define IDLELOOP	0x30
+#define TDR_CMD		0x38
+#define TDR_TIME	0x3C
+#define DUMP_CMD	0x40
+#define DIAG_CMD	0x48
+#define SET_MC_CMD	0x4E
+#define DUMP_DATA	0x56	/* A 170 byte buffer for dump and Set-MC into. */
+
+#define TX_BUF_START	0x0100
+#define NUM_TX_BUFS 	4
+#define TX_BUF_SIZE 	(1518+14+20+16) /* packet+header+TBD */
+
+#define RX_BUF_START	0x2000
+#define RX_BUF_SIZE 	(1518+14+18)	/* packet+header+RBD */
+#define RX_BUF_END		(dev->mem_end - dev->mem_start)
+
+/*
+  That's it: only 86 bytes to set up the beast, including every extra
+  command available.  The 170 byte buffer at DUMP_DATA is shared between the
+  Dump command (called only by the diagnostic program) and the SetMulticastList
+  command. 
+
+  To complete the memory setup you only have to write the station address at
+  SA_OFFSET and create the Tx & Rx buffer lists.
+
+  The Tx command chain and buffer list is setup as follows:
+  A Tx command table, with the data buffer pointing to...
+  A Tx data buffer descriptor.  The packet is in a single buffer, rather than
+     chaining together several smaller buffers.
+  A NoOp command, which initially points to itself,
+  And the packet data.
+
+  A transmit is done by filling in the Tx command table and data buffer,
+  re-writing the NoOp command, and finally changing the offset of the last
+  command to point to the current Tx command.  When the Tx command is finished,
+  it jumps to the NoOp, when it loops until the next Tx command changes the
+  "link offset" in the NoOp.  This way the 82586 never has to go through the
+  slow restart sequence.
+
+  The Rx buffer list is set up in the obvious ring structure.  We have enough
+  memory (and low enough interrupt latency) that we can avoid the complicated
+  Rx buffer linked lists by alway associating a full-size Rx data buffer with
+  each Rx data frame.
+
+  I current use four transmit buffers starting at TX_BUF_START (0x0100), and
+  use the rest of memory, from RX_BUF_START to RX_BUF_END, for Rx buffers.
+
+  */
+
+short init_words[] = {
+	0x0000,					/* Set bus size to 16 bits. */
+	0x0000,0x0000,			/* Set control mailbox (SCB) addr. */
+	0,0,					/* pad to 0x000000. */
+	0x0001,					/* Status word that's cleared when init is done. */
+	0x0008,0,0,				/* SCB offset, (skip, skip) */
+
+	0,0xf000|RX_START|CUC_START,	/* SCB status and cmd. */
+	CONFIG_CMD,				/* Command list pointer, points to Configure. */
+	RX_BUF_START,				/* Rx block list. */
+	0,0,0,0,				/* Error count: CRC, align, buffer, overrun. */
+
+	/* 0x0018: Configure command.  Change to put MAC data with packet. */
+	0, CmdConfigure,		/* Status, command.		*/
+	SET_SA_CMD,				/* Next command is Set Station Addr. */
+	0x0804,					/* "4" bytes of config data, 8 byte FIFO. */
+	0x2e40,					/* Magic values, including MAC data location. */
+	0,						/* Unused pad word. */
+
+	/* 0x0024: Setup station address command. */
+	0, CmdSASetup,
+	SET_MC_CMD,				/* Next command. */
+	0xaa00,0xb000,0x0bad,	/* Station address (to be filled in) */
+
+	/* 0x0030: NOP, looping back to itself.	 Point to first Tx buffer to Tx. */
+	0, CmdNOp, IDLELOOP, 0 /* pad */,
+
+	/* 0x0038: A unused Time-Domain Reflectometer command. */
+	0, CmdTDR, IDLELOOP, 0,
+
+	/* 0x0040: An unused Dump State command. */
+	0, CmdDump, IDLELOOP, DUMP_DATA,
+
+	/* 0x0048: An unused Diagnose command. */
+	0, CmdDiagnose, IDLELOOP,
+
+	/* 0x004E: An empty set-multicast-list command. */
+	0, CmdMulticastList, IDLELOOP, 0,
+};
+
+/* Index to functions, as function prototypes. */
+
+extern int el16_probe(struct device *dev);	/* Called from Space.c */
+
+static int	el16_probe1(struct device *dev, short ioaddr);
+static int	el16_open(struct device *dev);
+static int	el16_send_packet(struct sk_buff *skb, struct device *dev);
+static void	el16_interrupt(int reg_ptr);
+static void el16_rx(struct device *dev);
+static int	el16_close(struct device *dev);
+static struct enet_statistics *el16_get_stats(struct device *dev);
+
+static void hardware_send_packet(struct device *dev, void *buf, short length);
+void init_82586_mem(struct device *dev);
+
+
+/* Check for a network adaptor of this type, and return '0' iff one exists.
+   If dev->base_addr == 0, probe all likely locations.
+   If dev->base_addr == 1, always return failure.
+   If dev->base_addr == 2, (detachable devices only) alloate space for the
+   device and return success.
+   */
+int
+el16_probe(struct device *dev)
+{
+	/* Don't probe all settable addresses, 0x[23][0-F]0, just common ones. */
+	int *port, ports[] = {0x300, 0x320, 0x340, 0x280, 0};
+	int base_addr = dev->base_addr;
+	ushort lrs_state = 0xff, i;
+
+	if (base_addr > 0x1ff)	/* Check a single specified location. */
+		return el16_probe1(dev, base_addr);
+	else if (base_addr > 0)
+		return ENXIO;		/* Don't probe at all. */
+
+	/* Send the ID sequence to the ID_PORT to enable the board. */
+	outb(0x00, ID_PORT);
+	for(i = 0; i < 255; i++) {
+		outb(lrs_state, ID_PORT);
+		lrs_state <<= 1;
+		if (lrs_state & 0x100)
+			lrs_state ^= 0xe7;
+	}
+	outb(0x00, ID_PORT);
+
+	for (port = &ports[0]; *port; port++) {
+		short ioaddr = *port;
+#if 0
+		/* This is my original code. */
+		if (inb(ioaddr) == '*' && inb(ioaddr+1) == '3'
+			&& inb(ioaddr+2) == 'C' && inb(ioaddr+3) == 'O'
+			&& el16_probe1(dev, *port) == 0)
+			return 0;
+#else
+	/* This is code from jennings@Montrouge.SMR.slb.com, done so that
+	   the string can be printed out. */
+		char res[5];
+		res[0] = inb(ioaddr); res[1] = inb(ioaddr+1);
+		res[2] = inb(ioaddr+2); res[3] = inb(ioaddr+3);
+		res[4] = 0;
+		if (res[0] == '*' && res[1] == '3'
+			&& res[2] == 'C' && res[3] == 'O'
+			&& el16_probe1(dev, *port) == 0)
+		  return 0;
+#endif
+	}
+
+	return ENODEV;			/* ENODEV would be more accurate. */
+}
+
+int el16_probe1(struct device *dev, short ioaddr)
+{
+	int i, irq, irqval;
+
+	printk("%s: 3c507 at %#x,", dev->name, ioaddr);
+
+	/* We should make a few more checks here, like the first three octets of
+	   the S.A. for the manufactor's code. */ 
+
+	irq = inb(ioaddr + IRQ_CONFIG) & 0x0f;
+
+	irqval = request_irq(irq, &el16_interrupt);
+	if (irqval) {
+		printk ("unable to get IRQ %d (irqval=%d).\n", irq, irqval);
+		return EAGAIN;
+	}
+	
+	/* We've committed to using the board, and can start filling in *dev. */
+	snarf_region(ioaddr, 16);
+	dev->base_addr = ioaddr;
+
+	outb(0x01, ioaddr + MISC_CTRL);
+	for (i = 0; i < 6; i++) {
+		dev->dev_addr[i] = inb(ioaddr + i);
+		printk(" %02x", dev->dev_addr[i]);
+	}
+
+	if ((dev->mem_start & 0xf) > 0)
+		net_debug = dev->mem_start & 7;
+
+#ifdef MEM_BASE
+	dev->mem_start = MEM_BASE;
+	dev->mem_end = dev->mem_start + 0x10000;
+#else
+	{
+		int base;
+		int size;
+		char mem_config = inb(ioaddr + MEM_CONFIG);
+		if (mem_config & 0x20) {
+			size = 64*1024;
+			base = 0xf00000 + (mem_config & 0x08 ? 0x080000
+							   : ((mem_config & 3) << 17));
+		} else {
+			size = ((mem_config & 3) + 1) << 14;
+			base = 0x0c0000 + ( (mem_config & 0x18) << 12);
+		}
+		if (size != 0x10000)
+			printk("%s: Warning, this version probably only works with 64K of"
+				   "shared memory.\n", dev->name);
+		dev->mem_start = base;
+		dev->mem_end = base + size;
+	}
+#endif
+
+	dev->if_port = (inb(ioaddr + ROM_CONFIG) & 0x80) ? 1 : 0;
+	dev->irq = inb(ioaddr + IRQ_CONFIG) & 0x0f;
+
+	printk(", IRQ %d, %sternal xcvr, memory %#x-%#x.\n", dev->irq,
+		   dev->if_port ? "ex" : "in", dev->mem_start, dev->mem_end-1);
+
+	if (net_debug)
+		printk(version);
+
+	/* Initialize the device structure. */
+	dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL);
+	memset(dev->priv, 0, sizeof(struct net_local));
+
+	dev->open		= el16_open;
+	dev->stop		= el16_close;
+	dev->hard_start_xmit = el16_send_packet;
+	dev->get_stats	= el16_get_stats;
+
+	/* Fill in the fields of the device structure with ethernet-generic values.
+	   This should be in a common file instead of per-driver.  */
+	for (i = 0; i < DEV_NUMBUFFS; i++)
+		dev->buffs[i] = NULL;
+
+	dev->hard_header	= eth_header;
+	dev->add_arp	= eth_add_arp;
+	dev->queue_xmit = dev_queue_xmit;
+	dev->rebuild_header = eth_rebuild_header;
+	dev->type_trans = eth_type_trans;
+
+	dev->type		= ARPHRD_ETHER;
+	dev->hard_header_len = ETH_HLEN;
+	dev->mtu		= 1500; /* eth_mtu */
+	dev->addr_len	= ETH_ALEN;
+	for (i = 0; i < ETH_ALEN; i++) {
+		dev->broadcast[i]=0xff;
+	}
+
+	/* New-style flags. */
+	dev->flags		= IFF_BROADCAST;
+	dev->family		= AF_INET;
+	dev->pa_addr	= 0;
+	dev->pa_brdaddr = 0;
+	dev->pa_mask	= 0;
+	dev->pa_alen	= sizeof(unsigned long);
+
+	return 0;
+}
+
+
+
+static int
+el16_open(struct device *dev)
+{
+	irq2dev_map[dev->irq] = dev;
+
+	/* Initialize the 82586 memory and start it. */
+	init_82586_mem(dev);
+
+	dev->tbusy = 0;
+	dev->interrupt = 0;
+	dev->start = 1;
+	return 0;
+}
+
+static int
+el16_send_packet(struct sk_buff *skb, struct device *dev)
+{
+	struct net_local *lp = (struct net_local *)dev->priv;
+	int ioaddr = dev->base_addr;
+	short *shmem = (short*)dev->mem_start;
+
+	if (dev->tbusy) {
+		/* If we get here, some higher level has decided we are broken.
+		   There should really be a "kick me" function call instead. */
+		int tickssofar = jiffies - dev->trans_start;
+		if (tickssofar < 5)
+			return 1;
+		if (net_debug > 1)
+			printk("%s: transmit timed out, %s?  ", dev->name,
+				   shmem[iSCB_STATUS>>1] & 0x8000 ? "IRQ conflict" :
+				   "network cable problem");
+		/* Try to restart the adaptor. */
+		if (lp->last_restart == lp->stats.tx_packets) {
+			if (net_debug > 1) printk("Resetting board.\n");
+			/* Completely reset the adaptor. */
+			init_82586_mem(dev);
+		} else {
+			/* Issue the channel attention signal and hope it "gets better". */
+			if (net_debug > 1) printk("Kicking board.\n");
+			shmem[iSCB_CMD>>1] = 0xf000|CUC_START|RX_START;
+			outb(0, ioaddr + SIGNAL_CA);			/* Issue channel-attn. */
+			lp->last_restart = lp->stats.tx_packets;
+		}
+		dev->tbusy=0;
+		dev->trans_start = jiffies;
+	}
+
+	/* If some higher layer thinks we've missed an tx-done interrupt
+	   we are passed NULL. Caution: dev_tint() handles the cli()/sti()
+	   itself. */
+	if (skb == NULL) {
+		dev_tint(dev);
+		return 0;
+	}
+
+	/* For ethernet, fill in the header.  This should really be done by a
+	   higher level, rather than duplicated for each ethernet adaptor. */
+	if (!skb->arp  &&  dev->rebuild_header(skb+1, dev)) {
+		skb->dev = dev;
+		arp_queue (skb);
+		return 0;
+	}
+	skb->arp=1;
+
+	/* Block a timer-based transmit from overlapping. */
+	if (set_bit(0, (void*)&dev->tbusy) != 0)
+		printk("%s: Transmitter access conflict.\n", dev->name);
+	else {
+		short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
+		unsigned char *buf = (void *)(skb+1);
+
+		/* Disable the 82586's input to the interrupt line. */
+		outb(0x80, ioaddr + MISC_CTRL);
+		hardware_send_packet(dev, buf, length);
+		dev->trans_start = jiffies;
+		/* Enable the 82586 interrupt input. */
+		outb(0x84, ioaddr + MISC_CTRL);
+	}
+
+	if (skb->free)
+		kfree_skb (skb, FREE_WRITE);
+
+	/* You might need to clean up and record Tx statistics here. */
+
+	return 0;
+}
+
+/*	The typical workload of the driver:
+	Handle the network interface interrupts. */
+static void
+el16_interrupt(int reg_ptr)
+{
+	int irq = -(((struct pt_regs *)reg_ptr)->orig_eax+2);
+	struct device *dev = (struct device *)(irq2dev_map[irq]);
+	struct net_local *lp;
+	int ioaddr, status, boguscount = 0;
+	ushort ack_cmd = 0;
+	ushort *shmem;
+	
+	if (dev == NULL) {
+		printk ("net_interrupt(): irq %d for unknown device.\n", irq);
+		return;
+	}
+	dev->interrupt = 1;
+	
+	ioaddr = dev->base_addr;
+	lp = (struct net_local *)dev->priv;
+	shmem = ((ushort*)dev->mem_start);
+	
+	status = shmem[iSCB_STATUS>>1];
+	
+    if (net_debug > 4) {
+		printk("%s: 3c507 interrupt, status %4.4x.\n", dev->name, status);
+    }
+
+	/* Disable the 82586's input to the interrupt line. */
+	outb(0x80, ioaddr + MISC_CTRL);
+
+	/* Reap the Tx packet buffers. */
+	while (lp->tx_reap != lp->tx_head) {
+	  unsigned short tx_status = shmem[lp->tx_reap>>1];
+
+	  if (tx_status == 0) {
+		if (net_debug > 5)  printk("Couldn't reap %#x.\n", lp->tx_reap);
+		break;
+	  }
+	  if (tx_status & 0x2000) {
+		lp->stats.tx_packets++;
+		lp->stats.collisions += tx_status & 0xf;
+		dev->tbusy = 0;
+		mark_bh(INET_BH);		/* Inform upper layers. */
+	  } else {
+		lp->stats.tx_errors++;
+		if (tx_status & 0x0600)  lp->stats.tx_carrier_errors++;
+		if (tx_status & 0x0100)  lp->stats.tx_fifo_errors++;
+		if (!(tx_status & 0x0040))  lp->stats.tx_heartbeat_errors++;
+		if (tx_status & 0x0020)  lp->stats.tx_aborted_errors++;
+	  }
+	  if (net_debug > 5)
+		  printk("Reaped %x, Tx status %04x.\n" , lp->tx_reap, tx_status);
+	  lp->tx_reap += TX_BUF_SIZE;
+	  if (lp->tx_reap > RX_BUF_START - TX_BUF_SIZE)
+		lp->tx_reap = TX_BUF_START;
+	  if (++boguscount > 4)
+		break;
+	}
+
+	if (status & 0x4000) { /* Packet received. */
+		if (net_debug > 5)
+			printk("Received packet, rx_head %04x.\n", lp->rx_head);
+		el16_rx(dev);
+	}
+
+	/* Acknowledge the interrupt sources. */
+	ack_cmd = status & 0xf000;
+
+	if ((status & 0x0700) != 0x0200 && dev->start) {
+		if (net_debug)
+			printk("%s: Command unit stopped, status %04x, restarting.\n",
+				   dev->name, status);
+		/* If this ever occurs we should really re-write the idle loop, reset
+		   the Tx list, and do a complete restart of the command unit.
+		   For now we rely on the Tx timeout if the resume doesn't work. */
+		ack_cmd |= CUC_RESUME;
+	}
+
+	if ((status & 0x0070) != 0x0040  &&  dev->start) {
+	  static void init_rx_bufs(struct device *);
+		/* The Rx unit is not ready, it must be hung.  Restart the receiver by
+		   initializing the rx buffers, and issuing an Rx start command. */
+		if (net_debug)
+			printk("%s: Rx unit stopped, status %04x, restarting.\n",
+				   dev->name, status);
+		init_rx_bufs(dev);
+		shmem[iSCB_RFA >> 1] = RX_BUF_START;
+		ack_cmd |= RX_START;
+	}
+
+	shmem[iSCB_CMD>>1] = ack_cmd;
+	outb(0, ioaddr + SIGNAL_CA);			/* Issue channel-attn. */
+
+	/* Clear the latched interrupt. */
+	outb(0, ioaddr + RESET_IRQ);
+
+	/* Enable the 82586's interrupt input. */
+	outb(0x84, ioaddr + MISC_CTRL);
+
+	return;
+}
+
+static int
+el16_close(struct device *dev)
+{
+	int ioaddr = dev->base_addr;
+	ushort *shmem = (short*)dev->mem_start;
+
+	dev->tbusy = 1;
+	dev->start = 0;
+
+	/* Flush the Tx and disable Rx. */
+	shmem[iSCB_CMD >> 1] = RX_SUSPEND | CUC_SUSPEND;
+	outb(0, ioaddr + SIGNAL_CA);
+
+	/* Disable the 82586's input to the interrupt line. */
+	outb(0x80, ioaddr + MISC_CTRL);
+
+	/* We always physically use the IRQ line, so we don't do free_irq().
+	   We do remove ourselves from the map. */
+
+	irq2dev_map[dev->irq] = 0;
+
+	/* Update the statistics here. */
+
+	return 0;
+}
+
+/* Get the current statistics.	This may be called with the card open or
+   closed. */
+static struct enet_statistics *
+el16_get_stats(struct device *dev)
+{
+	struct net_local *lp = (struct net_local *)dev->priv;
+
+	/* ToDo: decide if there are any useful statistics from the SCB. */
+
+	return &lp->stats;
+}
+
+/* Initialize the Rx-block list. */
+static void
+init_rx_bufs(struct device *dev)
+{
+	struct net_local *lp = (struct net_local *)dev->priv;
+	unsigned short *write_ptr;
+
+	int cur_rxbuf = lp->rx_head = RX_BUF_START;
+	
+	/* Initialize each Rx frame + data buffer. */
+	do {	/* While there is room for one more. */
+
+	  write_ptr = (unsigned short *)(dev->mem_start + cur_rxbuf);
+
+		*write_ptr++ = 0x0000; 				/* Status */
+		*write_ptr++ = 0x0000;				/* Command */
+		*write_ptr++ = cur_rxbuf + RX_BUF_SIZE; /* Link */
+		*write_ptr++ = cur_rxbuf + 22;		/* Buffer offset */
+		*write_ptr++ = 0x0000; 				/* Pad for dest addr. */
+		*write_ptr++ = 0x0000;
+		*write_ptr++ = 0x0000;
+		*write_ptr++ = 0x0000; 				/* Pad for source addr. */
+		*write_ptr++ = 0x0000;
+		*write_ptr++ = 0x0000;
+		*write_ptr++ = 0x0000;				/* Pad for protocol. */
+		
+		*write_ptr++ = 0x0000;				/* Buffer: Actual count */
+		*write_ptr++ = -1;					/* Buffer: Next (none). */
+		*write_ptr++ = cur_rxbuf + 0x20;		/* Buffer: Address low */
+		*write_ptr++ = 0x0000;
+		/* Finally, the number of bytes in the buffer. */
+		*write_ptr++ = 0x8000 + RX_BUF_SIZE-0x20;
+		
+		lp->rx_tail = cur_rxbuf;
+		cur_rxbuf += RX_BUF_SIZE;
+	} while (cur_rxbuf <= RX_BUF_END - RX_BUF_SIZE);
+	
+	/* Terminate the list by setting the EOL bit, and wrap the pointer to make
+	   the list a ring. */
+	write_ptr = (unsigned short *)
+	  (dev->mem_start + lp->rx_tail + 2);
+	*write_ptr++ = 0xC000;					/* Command, mark as last. */
+	*write_ptr++ = lp->rx_head;				/* Link */
+
+}
+
+void
+init_82586_mem(struct device *dev)
+{
+	struct net_local *lp = (struct net_local *)dev->priv;
+	short ioaddr = dev->base_addr;
+	ushort *shmem = (short*)dev->mem_start;
+
+	/* Enable loopback to protect the wire while starting up,
+	   and hold the 586 in reset during the memory initialization. */
+	outb(0x20, ioaddr + MISC_CTRL);
+
+	/* Write the words at 0xfff6 (address-aliased to 0xfffff6). */
+#ifdef old
+	memcpy((void*)dev->mem_start+0xfff6, init_words, 10);
+#else
+	memcpy((void*)dev->mem_end-10, init_words, 10);
+#endif
+	/* Write the words at 0x0000. */
+	memcpy((char*)dev->mem_start, init_words + 5, sizeof(init_words) - 10);
+
+	/* Fill in the station address. */
+	memcpy((char*)dev->mem_start+SA_OFFSET, dev->dev_addr,
+		   sizeof(dev->dev_addr));
+
+	/* The Tx-block list is written as needed.  We just set up the values. */
+	lp->tx_cmd_link = IDLELOOP + 4;
+	lp->tx_head = lp->tx_reap = TX_BUF_START;
+
+	init_rx_bufs(dev);
+
+	/* Start the 586 by releasing the reset line, but leave loopback. */
+	outb(0xA0, ioaddr + MISC_CTRL);
+
+	/* This was time consuming to track down: you need to give two channel
+	   attention signals to reliably start up the i82586. */
+	outb(0, ioaddr + SIGNAL_CA);
+
+	{
+		int boguscnt = 50;
+		while (shmem[iSCB_STATUS>>1] == 0)
+			if (--boguscnt == 0) {
+				printk("%s: i82586 initialization timed out with status %04x,"
+					   "cmd %04x.\n", dev->name,
+					   shmem[iSCB_STATUS>>1], shmem[iSCB_CMD>>1]);
+				break;
+			}
+		/* Issue channel-attn -- the 82586 won't start. */
+		outb(0, ioaddr + SIGNAL_CA);
+	}
+
+	/* Disable loopback and enable interrupts. */
+	outb(0x84, ioaddr + MISC_CTRL);
+	if (net_debug > 4)
+		printk("%s: Initialized 82586, status %04x.\n", dev->name,
+			   shmem[iSCB_STATUS>>1]);
+	return;
+}
+
+static void
+hardware_send_packet(struct device *dev, void *buf, short length)
+{
+	struct net_local *lp = (struct net_local *)dev->priv;
+	short ioaddr = dev->base_addr;
+	ushort tx_block = lp->tx_head;
+	ushort *write_ptr =	  (ushort *)(dev->mem_start + tx_block);
+
+	/* Set the write pointer to the Tx block, and put out the header. */
+	*write_ptr++ = 0x0000;				/* Tx status */
+	*write_ptr++ = CMD_INTR|CmdTx;		/* Tx command */
+	*write_ptr++ = tx_block+16;			/* Next command is a NoOp. */
+	*write_ptr++ = tx_block+8;			/* Data Buffer offset. */
+
+	/* Output the data buffer descriptor. */
+	*write_ptr++ = length | 0x8000;		/* Byte count parameter. */
+	*write_ptr++ = -1;					/* No next data buffer. */
+	*write_ptr++ = tx_block+22;			/* Buffer follows the NoOp command. */
+	*write_ptr++ = 0x0000;				/* Buffer address high bits (always zero). */
+
+	/* Output the Loop-back NoOp command. */
+	*write_ptr++ = 0x0000;				/* Tx status */
+	*write_ptr++ = CmdNOp;				/* Tx command */
+	*write_ptr++ = tx_block+16;			/* Next is myself. */
+
+	/* Output the packet at the write pointer. */
+	memcpy(write_ptr, buf, length);
+
+	/* Set the old command link pointing to this send packet. */
+	*(ushort*)(dev->mem_start + lp->tx_cmd_link) = tx_block;
+	lp->tx_cmd_link = tx_block + 20;
+
+	/* Set the next free tx region. */
+	lp->tx_head = tx_block + TX_BUF_SIZE;
+	if (lp->tx_head > RX_BUF_START - TX_BUF_SIZE)
+		lp->tx_head = TX_BUF_START;
+
+    if (net_debug > 4) {
+		printk("%s: 3c507 @%x send length = %d, tx_block %3x, next %3x.\n",
+			   dev->name, ioaddr, length, tx_block, lp->tx_head);
+    }
+
+	if (lp->tx_head != lp->tx_reap)
+		dev->tbusy = 0;
+}
+
+static void
+el16_rx(struct device *dev)
+{
+	struct net_local *lp = (struct net_local *)dev->priv;
+	short *shmem = (short*)dev->mem_start;
+	ushort rx_head = lp->rx_head;
+	ushort rx_tail = lp->rx_tail;
+	ushort boguscount = 10;
+	short frame_status;
+
+	while ((frame_status = shmem[rx_head>>1]) < 0) {   /* Command complete */
+		ushort *read_frame =  (short *)(dev->mem_start + rx_head);
+		ushort rfd_cmd = read_frame[1];
+		ushort next_rx_frame = read_frame[2];
+		ushort data_buffer_addr = read_frame[3];
+		ushort *data_frame = (short *)(dev->mem_start + data_buffer_addr);
+		ushort pkt_len = data_frame[0];
+
+		if (rfd_cmd != 0 || data_buffer_addr != rx_head + 22
+			|| pkt_len & 0xC000 != 0xC000) {
+			printk("%s: Rx frame at %#x corrupted, status %04x cmd %04x"
+				   "next %04x data-buf @%04x %04x.\n", dev->name, rx_head,
+				   frame_status, rfd_cmd, next_rx_frame, data_buffer_addr,
+				   pkt_len);
+		} else if ((frame_status & 0x2000) == 0) {
+			/* Frame Rxed, but with error. */
+			lp->stats.rx_errors++;
+			if (frame_status & 0x0800) lp->stats.rx_crc_errors++;
+			if (frame_status & 0x0400) lp->stats.rx_frame_errors++;
+			if (frame_status & 0x0200) lp->stats.rx_fifo_errors++;
+			if (frame_status & 0x0100) lp->stats.rx_over_errors++;
+			if (frame_status & 0x0080) lp->stats.rx_length_errors++;
+		} else {
+			/* Malloc up new buffer. */
+			int sksize;
+			struct sk_buff *skb;
+
+			pkt_len &= 0x3fff;
+			sksize = sizeof(struct sk_buff) + pkt_len;
+			skb = alloc_skb(sksize, GFP_ATOMIC);
+			if (skb == NULL) {
+				printk("%s: Memory squeeze, dropping packet.\n", dev->name);
+				lp->stats.rx_dropped++;
+				break;
+			}
+			skb->mem_len = sksize;
+			skb->mem_addr = skb;
+			skb->len = pkt_len;
+			skb->dev = dev;
+
+			/* 'skb+1' points to the start of sk_buff data area. */
+			memcpy((unsigned char *) (skb + 1), data_frame + 5, pkt_len);
+		
+#ifdef HAVE_NETIF_RX
+			netif_rx(skb);
+#else
+			skb->lock = 0;
+			if (dev_rint((unsigned char*)skb, pkt_len, IN_SKBUFF, dev) != 0) {
+				kfree_skbmem(skb, sksize);
+				lp->stats.rx_dropped++;
+				break;
+			}
+#endif
+			lp->stats.rx_packets++;
+		}
+
+		/* Clear the status word and set End-of-List on the rx frame. */
+		read_frame[0] = 0;
+		read_frame[1] = 0xC000;
+		/* Clear the end-of-list on the prev. RFD. */
+		*(short*)(dev->mem_start + rx_tail + 2) = 0x0000;
+
+		rx_tail = rx_head;
+		rx_head = next_rx_frame;
+		if (--boguscount == 0)
+			break;
+	}
+
+	lp->rx_head = rx_head;
+	lp->rx_tail = rx_tail;
+}
+
+/*
+ * Local variables:
+ *  compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -I/usr/src/linux/drivers/net -Wall -Wstrict-prototypes -O6 -m486 -c 3c507.c"
+ *  version-control: t
+ *  kept-new-versions: 5
+ *  tab-width: 4
+ * End:
+ */
+
diff --git a/drivers/net/3c509.c b/drivers/net/3c509.c
index 5fb51f3..f0898d2 100644
--- a/drivers/net/3c509.c
+++ b/drivers/net/3c509.c
@@ -1,19 +1,19 @@
 /* 3c509.c: A 3c509 EtherLink3 ethernet driver for linux. */
 /*
-    Written 1993 by Donald Becker.
+	Written 1993 by Donald Becker.
 
-    Copyright 1993 United States Government as represented by the
-    Director, National Security Agency.  This software may be used and
-    distributed according to the terms of the GNU Public License,
-    incorporated herein by reference.
-    
-    This driver is for the 3Com EtherLinkIII series.
+	Copyright 1993 United States Government as represented by the
+	Director, National Security Agency.	 This software may be used and
+	distributed according to the terms of the GNU Public License,
+	incorporated herein by reference.
+	
+	This driver is for the 3Com EtherLinkIII series.
 
-    The author may be reached as becker@super.org or
-    C/O Supercomputing Research Ctr., 17100 Science Dr., Bowie MD 20715
+	The author may be reached as becker@super.org or
+	C/O Supercomputing Research Ctr., 17100 Science Dr., Bowie MD 20715
 */
 
-static char *version = "3c509.c:pl14 10/18/93 becker@super.org\n";
+static char *version = "3c509.c:pl13t 11/24/93 becker@super.org\n";
 
 #include <linux/config.h>
 #include <linux/kernel.h>
@@ -45,7 +45,6 @@
 
 #ifndef HAVE_ALLOC_SKB
 #define alloc_skb(size, priority) (struct sk_buff *) kmalloc(size,priority)
-#define kfree_skb(buff,size) kfree_s(buff,size)
 #endif
 
 
@@ -63,25 +62,26 @@
 #define EL3_CMD 0x0e
 #define EL3_STATUS 0x0e
 #define ID_PORT 0x100
-#define  EEPROM_READ 0x80
+#define	 EEPROM_READ 0x80
 
 #define EL3WINDOW(win_num) outw(0x0800+(win_num), ioaddr + EL3_CMD)
 
+/* Register window 1 offsets, the window used in normal operation. */
+#define TX_FIFO		0x00
+#define RX_FIFO		0x00
+#define RX_STATUS 	0x08
+#define TX_STATUS 	0x0B
+#define TX_FREE		0x0C		/* Remaining free bytes in Tx buffer. */
 
-/* Register window 1 offsets, used in normal operation. */
-#define TX_FREE 0x0C
-#define TX_STATUS 0x0B
-#define TX_FIFO 0x00
-#define RX_STATUS 0x08
-#define RX_FIFO 0x00
-
-#define WN4_MEDIA	0x0A
+#define WN4_MEDIA	0x0A		/* Window 4: Various transceiver/media bits. */
+#define  MEDIA_TP	0x00C0		/* Enable link beat and jabber for 10baseT. */
 
 struct el3_private {
-    struct enet_statistics stats;
+	struct enet_statistics stats;
 };
 
-static int read_eeprom(int index);
+static ushort id_read_eeprom(int index);
+static ushort read_eeprom(short ioaddr, int index);
 static int el3_open(struct device *dev);
 static int el3_start_xmit(struct sk_buff *skb, struct device *dev);
 static void el3_interrupt(int reg_ptr);
@@ -97,143 +97,198 @@
 
 int el3_probe(struct device *dev)
 {
-    short lrs_state = 0xff, i;
-    short ioaddr, irq;
-    short *phys_addr = (short *)dev->dev_addr;
-    static int current_tag = 0;
+	short lrs_state = 0xff, i;
+	ushort ioaddr, irq, if_port;
+	short *phys_addr = (short *)dev->dev_addr;
+	static int current_tag = 0;
 
-    /* Send the ID sequence to the ID_PORT. */
-    outb(0x00, ID_PORT);
-    outb(0x00, ID_PORT);
-    for(i = 0; i < 255; i++) {
-	outb(lrs_state, ID_PORT);
-	lrs_state <<= 1;
-	lrs_state = lrs_state & 0x100 ? lrs_state ^ 0xcf : lrs_state;
-    }
+	/* First check for a board on the EISA bus.	 This first check should
+	   really be in init/main.c, along with a MCA check. */
+	if (strncmp((char*)0x0FFFD9, "EISA", 4) == 0) {
+		for (ioaddr = 0x1000; ioaddr < 0x9000; ioaddr += 0x1000) {
+			if (inw(ioaddr) != 0x6d50)
+				continue;
 
-    /* For the first probe, clear all board's tag registers. */
-    if (current_tag == 0)
-	outb(0xd0, ID_PORT);
-    else		/* Otherwise kill off already-found boards. */
-	outb(0xd8, ID_PORT);
+			irq = inw(ioaddr + 8) >> 12;
+			if_port = inw(ioaddr + 6)>>14;
+			for (i = 0; i < 3; i++)
+				phys_addr[i] = htons(read_eeprom(ioaddr, i));
 
-    if (read_eeprom(7) != 0x6d50) {
-	return -ENODEV;
-    }
+			/* Restore the "Manufacturer ID" to the EEPROM read register. */
+			/* The manual says to restore "Product ID" (reg. 3). !???! */
+			read_eeprom(ioaddr, 7);
 
-    /* Read in EEPROM data, which does contention-select.
-       Only the lowest address board will stay "on-line".
-       3Com got the byte order backwards. */
-    for (i = 0; i < 3; i++) {
-	phys_addr[i] = htons(read_eeprom(i));
-    }
+			/* Was the EISA code an add-on hack?  Nahhhhh... */
+			goto found;
+		}
+	}
 
-    {
-	unsigned short iobase = read_eeprom(8);
-	dev->if_port = iobase >> 14;
-	ioaddr = 0x200 + ((iobase & 0x1f) << 4);
-    }
-    irq = read_eeprom(9) >> 12;
+#ifdef CONFIG_MCA
+	if (MCA_bus) {
+		mca_adaptor_select_mode(1);
+		for (i = 0; i < 8; i++)
+			if ((mca_adaptor_id(i) | 1) == 0x627c) {
+				ioaddr = mca_pos_base_addr(i);
+				irq = inw(ioaddr + 8) >> 12;
+				if_port = inw(ioaddr + 6)>>14;
+				for (i = 0; i < 3; i++)
+					phys_addr[i] = htons(read_eeprom(ioaddr, i));
 
-    /* The current Space.c structure makes it difficult to have more
-       than one adaptor initialized.  Send me email if you have a need for
-       multiple adaptors, and we'll work out something.  -becker@super.org */
-    if (dev->base_addr != 0
-	&&  dev->base_addr != (unsigned short)ioaddr) {
-	return -ENODEV;
-    }
+				mca_adaptor_select_mode(0);
+				goto found;
+			}
+		mca_adaptor_select_mode(0);
 
-    /* Set the adaptor tag so that the next card can be found. */
-    outb(0xd0 + ++current_tag, ID_PORT);
+	}
+#endif	  
 
-    /* Activate the adaptor at the EEPROM location. */
-    outb(0xff, ID_PORT);
+	/* Send the ID sequence to the ID_PORT. */
+	outb(0x00, ID_PORT);
+	outb(0x00, ID_PORT);
+	for(i = 0; i < 255; i++) {
+		outb(lrs_state, ID_PORT);
+		lrs_state <<= 1;
+		lrs_state = lrs_state & 0x100 ? lrs_state ^ 0xcf : lrs_state;
+	}
 
-    EL3WINDOW(0);
-    if (inw(ioaddr) != 0x6d50)
-	return -ENODEV;
+	/* For the first probe, clear all board's tag registers. */
+	if (current_tag == 0)
+		outb(0xd0, ID_PORT);
+	else				/* Otherwise kill off already-found boards. */
+		outb(0xd8, ID_PORT);
 
-    dev->base_addr = ioaddr;
-    dev->irq = irq;
-    snarf_region(dev->base_addr, 16);
+	if (id_read_eeprom(7) != 0x6d50) {
+		return -ENODEV;
+	}
 
-    {
-	char *if_names[] = {"10baseT", "AUI", "undefined", "BNC"};
-	printk("%s: 3c509 at %#3.3x  tag %d, %s port, address ",
-	       dev->name, dev->base_addr, current_tag, if_names[dev->if_port]);
-    }
+	/* Read in EEPROM data, which does contention-select.
+	   Only the lowest address board will stay "on-line".
+	   3Com got the byte order backwards. */
+	for (i = 0; i < 3; i++) {
+		phys_addr[i] = htons(id_read_eeprom(i));
+	}
 
-    /* Read in the station address. */
-    for (i = 0; i < 6; i++)
-	printk(" %2.2x", dev->dev_addr[i]);
-    printk(", IRQ %d.\n", dev->irq);
+	{
+		unsigned short iobase = id_read_eeprom(8);
+		if_port = iobase >> 14;
+		ioaddr = 0x200 + ((iobase & 0x1f) << 4);
+	}
+	irq = id_read_eeprom(9) >> 12;
 
-    /* Make up a EL3-specific-data structure. */
-    dev->priv = kmalloc(sizeof(struct el3_private), GFP_KERNEL);
-    memset(dev->priv, 0, sizeof(struct el3_private));
+	/* The current Space.c structure makes it difficult to have more
+	   than one adaptor initialized.  Send me email if you have a need for
+	   multiple adaptors, and we'll work out something.	 -becker@super.org */
+	if (dev->base_addr != 0
+		&&	dev->base_addr != (unsigned short)ioaddr) {
+		return -ENODEV;
+	}
 
-    if (el3_debug > 0)
-	printk(version);
+	/* Set the adaptor tag so that the next card can be found. */
+	outb(0xd0 + ++current_tag, ID_PORT);
 
-    /* The EL3-specific entries in the device structure. */
-    dev->open = &el3_open;
-    dev->hard_start_xmit = &el3_start_xmit;
-    dev->stop = &el3_close;
-    dev->get_stats = &el3_get_stats;
+	/* Activate the adaptor at the EEPROM location. */
+	outb(0xff, ID_PORT);
+
+	EL3WINDOW(0);
+	if (inw(ioaddr) != 0x6d50)
+		return -ENODEV;
+
+ found:
+	dev->base_addr = ioaddr;
+	dev->irq = irq;
+	dev->if_port = if_port;
+	snarf_region(dev->base_addr, 16);
+
+	{
+		char *if_names[] = {"10baseT", "AUI", "undefined", "BNC"};
+		printk("%s: 3c509 at %#3.3x	 tag %d, %s port, address ",
+			   dev->name, dev->base_addr, current_tag, if_names[dev->if_port]);
+	}
+
+	/* Read in the station address. */
+	for (i = 0; i < 6; i++)
+		printk(" %2.2x", dev->dev_addr[i]);
+	printk(", IRQ %d.\n", dev->irq);
+
+	/* Make up a EL3-specific-data structure. */
+	dev->priv = kmalloc(sizeof(struct el3_private), GFP_KERNEL);
+	memset(dev->priv, 0, sizeof(struct el3_private));
+
+	if (el3_debug > 0)
+		printk(version);
+
+	/* The EL3-specific entries in the device structure. */
+	dev->open = &el3_open;
+	dev->hard_start_xmit = &el3_start_xmit;
+	dev->stop = &el3_close;
+	dev->get_stats = &el3_get_stats;
 #ifdef HAVE_MULTICAST
-	dev->set_multicast_list = &set_multicast_list;
+		dev->set_multicast_list = &set_multicast_list;
 #endif
 
-    /* Fill in the generic fields of the device structure. */
-    for (i = 0; i < DEV_NUMBUFFS; i++)
-	dev->buffs[i] = NULL;
+	/* Fill in the generic fields of the device structure. */
+	for (i = 0; i < DEV_NUMBUFFS; i++)
+		dev->buffs[i] = NULL;
 
-    dev->hard_header	= eth_header;
-    dev->add_arp	= eth_add_arp;
-    dev->queue_xmit	= dev_queue_xmit;
-    dev->rebuild_header	= eth_rebuild_header;
-    dev->type_trans	= eth_type_trans;
+	dev->hard_header	= eth_header;
+	dev->add_arp		= eth_add_arp;
+	dev->queue_xmit		= dev_queue_xmit;
+	dev->rebuild_header = eth_rebuild_header;
+	dev->type_trans		= eth_type_trans;
 
-    dev->type		= ARPHRD_ETHER;
-    dev->hard_header_len = ETH_HLEN;
-    dev->mtu		= 1500; /* eth_mtu */
-    dev->addr_len	= ETH_ALEN;
-    for (i = 0; i < ETH_ALEN; i++) {
-	dev->broadcast[i]=0xff;
-    }
+	dev->type			= ARPHRD_ETHER;
+	dev->hard_header_len = ETH_HLEN;
+	dev->mtu			= 1500; /* eth_mtu */
+	dev->addr_len		= ETH_ALEN;
+	for (i = 0; i < ETH_ALEN; i++) {
+		dev->broadcast[i]=0xff;
+	}
 
-    /* New-style flags. */
-    dev->flags		= IFF_BROADCAST;
-    dev->family		= AF_INET;
-    dev->pa_addr	= 0;
-    dev->pa_brdaddr	= 0;
-    dev->pa_mask	= 0;
-    dev->pa_alen	= sizeof(unsigned long);
+	/* New-style flags. */
+	dev->flags			= IFF_BROADCAST;
+	dev->family			= AF_INET;
+	dev->pa_addr		= 0;
+	dev->pa_brdaddr		= 0;
+	dev->pa_mask		= 0;
+	dev->pa_alen		= sizeof(unsigned long);
 
-    return 0;
+	return 0;
 }
 
-
-static int
-read_eeprom(int index)
+/* Read a word from the EEPROM using the regular EEPROM access register.
+   Assume that we are in register window zero.
+ */
+static ushort read_eeprom(short ioaddr, int index)
 {
-    int timer, bit, word = 0;
-    
-    /* Issue read command, and pause for at least 162 us. for it to complete.
-       Assume extra-fast 16Mhz bus. */
-    outb(EEPROM_READ + index, ID_PORT);
+	int timer;
 
-    /* This should really be done by looking at one of the timer channels. */
-    for (timer = 0; timer < 162*4 + 400; timer++)
-	SLOW_DOWN_IO;
+	outw(EEPROM_READ + index, ioaddr + 10);
+	/* Pause for at least 162 us. for the read to take place. */
+	for (timer = 0; timer < 162*4 + 400; timer++)
+		SLOW_DOWN_IO;
+	return inw(ioaddr + 12);
+}
 
-    for (bit = 15; bit >= 0; bit--)
-	word = (word << 1) + (inb(ID_PORT) & 0x01);
+/* Read a word from the EEPROM when in the ISA ID probe state. */
+static ushort id_read_eeprom(int index)
+{
+	int timer, bit, word = 0;
 	
-    if (el3_debug > 3)
-	printk("  3c509 EEPROM word %d %#4.4x.\n", index, word);
+	/* Issue read command, and pause for at least 162 us. for it to complete.
+	   Assume extra-fast 16Mhz bus. */
+	outb(EEPROM_READ + index, ID_PORT);
 
-    return word;
+	/* This should really be done by looking at one of the timer channels. */
+	for (timer = 0; timer < 162*4 + 400; timer++)
+		SLOW_DOWN_IO;
+
+	for (bit = 15; bit >= 0; bit--)
+		word = (word << 1) + (inb(ID_PORT) & 0x01);
+		
+	if (el3_debug > 3)
+		printk("  3c509 EEPROM word %d %#4.4x.\n", index, word);
+
+	return word;
 }
 
 
@@ -241,398 +296,408 @@
 static int
 el3_open(struct device *dev)
 {
-    int ioaddr = dev->base_addr;
-    int i;
+	int ioaddr = dev->base_addr;
+	int i;
 
-    if (request_irq(dev->irq, &el3_interrupt)) {
-	return -EAGAIN;
-    }
+	if (request_irq(dev->irq, &el3_interrupt)) {
+		return -EAGAIN;
+	}
 
-    EL3WINDOW(0);
-    if (el3_debug > 3)
-	printk("%s: Opening, IRQ %d  status@%x %4.4x.\n", dev->name,
-	       dev->irq, ioaddr + EL3_STATUS, inw(ioaddr + EL3_STATUS));
+	EL3WINDOW(0);
+	if (el3_debug > 3)
+		printk("%s: Opening, IRQ %d	 status@%x %4.4x.\n", dev->name,
+			   dev->irq, ioaddr + EL3_STATUS, inw(ioaddr + EL3_STATUS));
 
-    /* Activate board: this is probably unnecessary. */
-    outw(0x0001, ioaddr + 4);
+	/* Activate board: this is probably unnecessary. */
+	outw(0x0001, ioaddr + 4);
 
-    irq2dev_map[dev->irq] = dev;
+	irq2dev_map[dev->irq] = dev;
 
-    /* Set the IRQ line. */
-    outw((dev->irq << 12) | 0x0f00, ioaddr + 8);
+	/* Set the IRQ line. */
+	outw((dev->irq << 12) | 0x0f00, ioaddr + 8);
 
-    /* Set the station address in window 2 each time opened. */
-    EL3WINDOW(2);
+	/* Set the station address in window 2 each time opened. */
+	EL3WINDOW(2);
 
-    for (i = 0; i < 6; i++)
-	outb(dev->dev_addr[i], ioaddr + i);
+	for (i = 0; i < 6; i++)
+		outb(dev->dev_addr[i], ioaddr + i);
 
-    if (dev->if_port == 3)
-	/* Start the thinnet transceiver. We should really wait 50ms...*/
-	outw(0x1000, ioaddr + EL3_CMD);
-    else if (dev->if_port == 0) {
-	/* 10baseT interface, enabled link beat and jabber check. */
-	EL3WINDOW(4);
-	outw(inw(ioaddr + WN4_MEDIA) | 0x00C0, ioaddr + WN4_MEDIA);
-    }
+	if (dev->if_port == 3)
+		/* Start the thinnet transceiver. We should really wait 50ms...*/
+		outw(0x1000, ioaddr + EL3_CMD);
+	else if (dev->if_port == 0) {
+		/* 10baseT interface, enabled link beat and jabber check. */
+		EL3WINDOW(4);
+		outw(inw(ioaddr + WN4_MEDIA) | MEDIA_TP, ioaddr + WN4_MEDIA);
+	}
 
-    /* Switch to register set 1 for normal use. */
-    EL3WINDOW(1);
+	/* Switch to register set 1 for normal use. */
+	EL3WINDOW(1);
 
-    outw(0x8005, ioaddr + EL3_CMD); /* Accept b-case and phys addr only. */
-    outw(0xA800, ioaddr + EL3_CMD); /* Turn on statistics. */
-    outw(0x2000, ioaddr + EL3_CMD); /* Enable the receiver. */
-    outw(0x4800, ioaddr + EL3_CMD); /* Enable transmitter. */
-    outw(0x78ff, ioaddr + EL3_CMD); /* Allow all status bits to be seen. */
-    dev->interrupt = 0;
-    dev->tbusy = 0;
-    dev->start = 1;
-    outw(0x7098, ioaddr + EL3_CMD); /* Set interrupt mask. */
+	outw(0x8005, ioaddr + EL3_CMD); /* Accept b-case and phys addr only. */
+	outw(0xA800, ioaddr + EL3_CMD); /* Turn on statistics. */
+	outw(0x2000, ioaddr + EL3_CMD); /* Enable the receiver. */
+	outw(0x4800, ioaddr + EL3_CMD); /* Enable transmitter. */
+	outw(0x78ff, ioaddr + EL3_CMD); /* Allow all status bits to be seen. */
+	dev->interrupt = 0;
+	dev->tbusy = 0;
+	dev->start = 1;
+	outw(0x7098, ioaddr + EL3_CMD); /* Set interrupt mask. */
 
-    if (el3_debug > 3)
-	printk("%s: Opened 3c509  IRQ %d  status %4.4x.\n",
-	       dev->name, dev->irq, inw(ioaddr + EL3_STATUS));
+	if (el3_debug > 3)
+		printk("%s: Opened 3c509  IRQ %d  status %4.4x.\n",
+			   dev->name, dev->irq, inw(ioaddr + EL3_STATUS));
 
-    return 0;			/* Always succeed */
+	return 0;					/* Always succeed */
 }
 
 static int
 el3_start_xmit(struct sk_buff *skb, struct device *dev)
 {
-    struct el3_private *lp = (struct el3_private *)dev->priv;
-    int ioaddr = dev->base_addr;
+	struct el3_private *lp = (struct el3_private *)dev->priv;
+	int ioaddr = dev->base_addr;
 
-    /* Transmitter timeout, serious problems. */
-    if (dev->tbusy) {
-	int tickssofar = jiffies - dev->trans_start;
-	if (tickssofar < 10)
-	    return 1;
-	printk("%s: transmit timed out, tx_status %2.2x status %4.4x.\n",
-	       dev->name, inb(ioaddr + TX_STATUS), inw(ioaddr + EL3_STATUS));
-	dev->trans_start = jiffies;
-	/* Issue TX_RESET and TX_START commands. */
-	outw(0x5800, ioaddr + EL3_CMD);	/* TX_RESET */
-	outw(0x4800, ioaddr + EL3_CMD);	/* TX_START */
-	dev->tbusy = 0;
-    }
-
-    if (skb == NULL) {
-	dev_tint(dev);
-	return 0;
-    }
-
-    /* Fill in the ethernet header. */
-    if (!skb->arp  &&  dev->rebuild_header(skb+1, dev)) {
-	skb->dev = dev;
-	arp_queue (skb);
-	return 0;
-    }
-    skb->arp=1;
-
-    if (skb->len <= 0)
-	return 0;
-
-    if (el3_debug > 4) {
-	printk("%s: el3_start_xmit(lenght = %d) called, status %4.4x.\n",
-	       dev->name, skb->len, inw(ioaddr + EL3_STATUS));
-    }
-
-    if (inw(ioaddr + EL3_STATUS) & 0x0001) { /* IRQ line active, missed one. */
-      printk("%s: Missed interrupt, status %4.4x  Tx %2.2x Rx %4.4x.\n",
-	     dev->name, inw(ioaddr + EL3_STATUS), inb(ioaddr + TX_STATUS),
-	     inw(ioaddr + RX_STATUS));
-      outw(0x7800, ioaddr + EL3_CMD); /* Fake interrupt trigger. */
-      outw(0x6899, ioaddr + EL3_CMD); /* Ack IRQ */
-      outw(0x78ff, ioaddr + EL3_CMD); /* Allow all status bits to be seen. */
-    }
-
-    /* Avoid timer-based retransmission conflicts. */
-    if (set_bit(0, (void*)&dev->tbusy) != 0)
-	printk("%s: Transmitter access conflict.\n", dev->name);
-    else {
-	/* Put out the doubleword header... */
-	outw(skb->len, ioaddr + TX_FIFO);
-	outw(0x00, ioaddr + TX_FIFO);
-	/* ... and the packet rounded to a doubleword. */
-	port_write_l(ioaddr + TX_FIFO, (void *)(skb+1), (skb->len + 3) >> 2);
-    
-	dev->trans_start = jiffies;
-	if (inw(ioaddr + TX_FREE) > 1536) {
-	    dev->tbusy=0;
-	} else
-	    /* Interrupt us when the FIFO has room for max-sized packet. */
-	    outw(0x9000 + 1536, ioaddr + EL3_CMD);
-    }
-
-    if (skb->free)
-	kfree_skb (skb, FREE_WRITE);
-
-    /* Clear the Tx status stack. */
-    {
-	short tx_status;
-	int i = 4;
-
-	while (--i > 0  &&  (tx_status = inb(ioaddr + TX_STATUS)) > 0) {
-	    if (el3_debug > 5)
-		printk("        Tx status %4.4x.\n", tx_status);
-	    if (tx_status & 0x38) lp->stats.tx_aborted_errors++;
-	    if (tx_status & 0x30) outw(0x5800, ioaddr + EL3_CMD);
-	    if (tx_status & 0x3C) outw(0x4800, ioaddr + EL3_CMD);
-	    outb(0x00, ioaddr + TX_STATUS); /* Pop the status stack. */
+	/* Transmitter timeout, serious problems. */
+	if (dev->tbusy) {
+		int tickssofar = jiffies - dev->trans_start;
+		if (tickssofar < 10)
+			return 1;
+		printk("%s: transmit timed out, tx_status %2.2x status %4.4x.\n",
+			   dev->name, inb(ioaddr + TX_STATUS), inw(ioaddr + EL3_STATUS));
+		dev->trans_start = jiffies;
+		/* Issue TX_RESET and TX_START commands. */
+		outw(0x5800, ioaddr + EL3_CMD); /* TX_RESET */
+		outw(0x4800, ioaddr + EL3_CMD); /* TX_START */
+		dev->tbusy = 0;
 	}
-    }
-    return 0;
+
+	if (skb == NULL) {
+		dev_tint(dev);
+		return 0;
+	}
+
+	/* Fill in the ethernet header. */
+	if (!skb->arp  &&  dev->rebuild_header(skb+1, dev)) {
+		skb->dev = dev;
+		arp_queue (skb);
+		return 0;
+	}
+	skb->arp=1;
+
+	if (skb->len <= 0)
+		return 0;
+
+	if (el3_debug > 4) {
+		printk("%s: el3_start_xmit(lenght = %d) called, status %4.4x.\n",
+			   dev->name, skb->len, inw(ioaddr + EL3_STATUS));
+	}
+#ifndef final_version
+	{	/* Error-checking code, delete for 1.00. */
+		ushort status = inw(ioaddr + EL3_STATUS);
+		if (status & 0x0001 		/* IRQ line active, missed one. */
+			&& inw(ioaddr + EL3_STATUS) & 1) { 			/* Make sure. */
+			printk("%s: Missed interrupt, status then %04x now %04x"
+				   "  Tx %2.2x Rx %4.4x.\n", dev->name, status,
+				   inw(ioaddr + EL3_STATUS), inb(ioaddr + TX_STATUS),
+				   inw(ioaddr + RX_STATUS));
+			outw(0x7800, ioaddr + EL3_CMD); /* Fake interrupt trigger. */
+			outw(0x6899, ioaddr + EL3_CMD); /* Ack IRQ */
+			outw(0x78ff, ioaddr + EL3_CMD); /* Set all status bits visible. */
+		}
+	}
+#endif
+
+	/* Avoid timer-based retransmission conflicts. */
+	if (set_bit(0, (void*)&dev->tbusy) != 0)
+		printk("%s: Transmitter access conflict.\n", dev->name);
+	else {
+		/* Put out the doubleword header... */
+		outw(skb->len, ioaddr + TX_FIFO);
+		outw(0x00, ioaddr + TX_FIFO);
+		/* ... and the packet rounded to a doubleword. */
+		port_write_l(ioaddr + TX_FIFO, (void *)(skb+1), (skb->len + 3) >> 2);
+	
+		dev->trans_start = jiffies;
+		if (inw(ioaddr + TX_FREE) > 1536) {
+			dev->tbusy=0;
+		} else
+			/* Interrupt us when the FIFO has room for max-sized packet. */
+			outw(0x9000 + 1536, ioaddr + EL3_CMD);
+	}
+
+	if (skb->free)
+		kfree_skb (skb, FREE_WRITE);
+
+	/* Clear the Tx status stack. */
+	{
+		short tx_status;
+		int i = 4;
+
+		while (--i > 0	&&	(tx_status = inb(ioaddr + TX_STATUS)) > 0) {
+			if (el3_debug > 5)
+				printk("		Tx status %4.4x.\n", tx_status);
+			if (tx_status & 0x38) lp->stats.tx_aborted_errors++;
+			if (tx_status & 0x30) outw(0x5800, ioaddr + EL3_CMD);
+			if (tx_status & 0x3C) outw(0x4800, ioaddr + EL3_CMD);
+			outb(0x00, ioaddr + TX_STATUS); /* Pop the status stack. */
+		}
+	}
+	return 0;
 }
 
 /* The EL3 interrupt handler. */
 static void
 el3_interrupt(int reg_ptr)
 {
-    int irq = -(((struct pt_regs *)reg_ptr)->orig_eax+2);
-    struct device *dev = (struct device *)(irq2dev_map[irq]);
-    int ioaddr, status;
-    int i = 0;
+	int irq = -(((struct pt_regs *)reg_ptr)->orig_eax+2);
+	struct device *dev = (struct device *)(irq2dev_map[irq]);
+	int ioaddr, status;
+	int i = 0;
 
-    if (dev == NULL) {
-	printk ("el3_interrupt(): irq %d for unknown device.\n", irq);
-	return;
-    }
-
-    if (dev->interrupt)
-	printk("%s: Re-entering the interrupt handler.\n", dev->name);
-    dev->interrupt = 1;
-
-    ioaddr = dev->base_addr;
-    status = inw(ioaddr + EL3_STATUS);
-
-    if (el3_debug > 4)
-	printk("%s: interrupt, status %4.4x.\n", dev->name, status);
-    
-    while ((status = inw(ioaddr + EL3_STATUS)) & 0x01) {
-
-	if (status & 0x10)
-	    el3_rx(dev);
-
-	if (status & 0x08) {
-	    if (el3_debug > 5)
-		printk("    TX room bit was handled.\n");
-	    /* There's room in the FIFO for a full-sized packet. */
-	    outw(0x6808, ioaddr + EL3_CMD); /* Ack IRQ */
-	    dev->tbusy = 0;
-	    mark_bh(INET_BH);
+	if (dev == NULL) {
+		printk ("el3_interrupt(): irq %d for unknown device.\n", irq);
+		return;
 	}
-	if (status & 0x80)		/* Statistics full. */
-	    update_stats(ioaddr, dev);
+
+	if (dev->interrupt)
+		printk("%s: Re-entering the interrupt handler.\n", dev->name);
+	dev->interrupt = 1;
+
+	ioaddr = dev->base_addr;
+	status = inw(ioaddr + EL3_STATUS);
+
+	if (el3_debug > 4)
+		printk("%s: interrupt, status %4.4x.\n", dev->name, status);
 	
-	if (++i > 10) {
-	    printk("%s: Infinite loop in interrupt, status %4.4x.\n",
-		   dev->name, status);
-	    break;
-	}
-	/* Clear the other interrupts we have handled. */
-	outw(0x6899, ioaddr + EL3_CMD); /* Ack IRQ */
-    }
+	while ((status = inw(ioaddr + EL3_STATUS)) & 0x01) {
 
-    if (el3_debug > 4) {
-	printk("%s: exiting interrupt, status %4.4x.\n", dev->name,
-	       inw(ioaddr + EL3_STATUS));
-    }
-    
-    dev->interrupt = 0;
-    return;
+		if (status & 0x10)
+			el3_rx(dev);
+
+		if (status & 0x08) {
+			if (el3_debug > 5)
+				printk("	TX room bit was handled.\n");
+			/* There's room in the FIFO for a full-sized packet. */
+			outw(0x6808, ioaddr + EL3_CMD); /* Ack IRQ */
+			dev->tbusy = 0;
+			mark_bh(INET_BH);
+		}
+		if (status & 0x80)				/* Statistics full. */
+			update_stats(ioaddr, dev);
+		
+		if (++i > 10) {
+			printk("%s: Infinite loop in interrupt, status %4.4x.\n",
+				   dev->name, status);
+			break;
+		}
+		/* Clear the other interrupts we have handled. */
+		outw(0x6899, ioaddr + EL3_CMD); /* Ack IRQ */
+	}
+
+	if (el3_debug > 4) {
+		printk("%s: exiting interrupt, status %4.4x.\n", dev->name,
+			   inw(ioaddr + EL3_STATUS));
+	}
+	
+	dev->interrupt = 0;
+	return;
 }
 
 
 static struct enet_statistics *
 el3_get_stats(struct device *dev)
 {
-    struct el3_private *lp = (struct el3_private *)dev->priv;
+	struct el3_private *lp = (struct el3_private *)dev->priv;
 
-    sti();
-    update_stats(dev->base_addr, dev);
-    cli();
-    return &lp->stats;
+	sti();
+	update_stats(dev->base_addr, dev);
+	cli();
+	return &lp->stats;
 }
 
-/* Update statistics.  We change to register window 6, so this
-   should be run single-threaded if the device is active. This
-   is expected to be a rare operation, and not worth a special
-   window-state variable. */
+/*  Update statistics.  We change to register window 6, so this should be run
+	single-threaded if the device is active. This is expected to be a rare
+	operation, and it's simpler for the rest of the driver to assume that
+	window 1 is always valid rather than use a special window-state variable.
+	*/
 static void update_stats(int ioaddr, struct device *dev)
 {
-    struct el3_private *lp = (struct el3_private *)dev->priv;
+	struct el3_private *lp = (struct el3_private *)dev->priv;
 
-    if (el3_debug > 5)
-	printk("   Updating the statistics.\n");
-    /* Turn off statistics updates while reading. */
-    outw(0xB000, ioaddr + EL3_CMD);
-    /* Switch to the stats window, and read everything. */
-    EL3WINDOW(6);
-    lp->stats.tx_carrier_errors	+= inb(ioaddr + 0);
-    lp->stats.tx_heartbeat_errors	+= inb(ioaddr + 1);
-    /* Multiple collisions. */	   inb(ioaddr + 2);
-    lp->stats.collisions		+= inb(ioaddr + 3);
-    lp->stats.tx_window_errors	+= inb(ioaddr + 4);
-    lp->stats.rx_fifo_errors	+= inb(ioaddr + 5);
-    lp->stats.tx_packets		+= inb(ioaddr + 6);
-    lp->stats.rx_packets		+= inb(ioaddr + 7);
-    /* Tx deferrals */		   inb(ioaddr + 8);
-    inw(ioaddr + 10);	/* Total Rx and Tx octets. */
-    inw(ioaddr + 12);
+	if (el3_debug > 5)
+		printk("   Updating the statistics.\n");
+	/* Turn off statistics updates while reading. */
+	outw(0xB000, ioaddr + EL3_CMD);
+	/* Switch to the stats window, and read everything. */
+	EL3WINDOW(6);
+	lp->stats.tx_carrier_errors 	+= inb(ioaddr + 0);
+	lp->stats.tx_heartbeat_errors	+= inb(ioaddr + 1);
+	/* Multiple collisions. */	   	inb(ioaddr + 2);
+	lp->stats.collisions			+= inb(ioaddr + 3);
+	lp->stats.tx_window_errors		+= inb(ioaddr + 4);
+	lp->stats.rx_fifo_errors		+= inb(ioaddr + 5);
+	lp->stats.tx_packets			+= inb(ioaddr + 6);
+	lp->stats.rx_packets			+= inb(ioaddr + 7);
+	/* Tx deferrals */				inb(ioaddr + 8);
+	inw(ioaddr + 10);	/* Total Rx and Tx octets. */
+	inw(ioaddr + 12);
 
-    /* Back to window 1, and turn statistics back on. */
-    EL3WINDOW(1);
-    outw(0xA800, ioaddr + EL3_CMD);
-    return;
+	/* Back to window 1, and turn statistics back on. */
+	EL3WINDOW(1);
+	outw(0xA800, ioaddr + EL3_CMD);
+	return;
 }
 
 static int
 el3_rx(struct device *dev)
 {
-    struct el3_private *lp = (struct el3_private *)dev->priv;
-    int ioaddr = dev->base_addr;
-    short rx_status;
+	struct el3_private *lp = (struct el3_private *)dev->priv;
+	int ioaddr = dev->base_addr;
+	short rx_status;
 
-    if (el3_debug > 5)
-	printk("       In rx_packet(), status %4.4x, rx_status %4.4x.\n",
-	       inw(ioaddr+EL3_STATUS), inw(ioaddr+RX_STATUS));
-    while ((rx_status = inw(ioaddr + RX_STATUS)) > 0) {
-	if (rx_status & 0x4000) { /* Error, update stats. */
-	    short error = rx_status & 0x3C00;
-	    lp->stats.rx_errors++;
-	    switch (error) {
-	    case 0x2000:	lp->stats.rx_over_errors++; break;
-	    case 0x2C00:	lp->stats.rx_length_errors++; break;
-	    case 0x3400:	lp->stats.rx_crc_errors++; break;
-	    case 0x2400:	lp->stats.rx_length_errors++; break;
-	    case 0x3000:	lp->stats.rx_frame_errors++; break;
-	    case 0x0800:	lp->stats.rx_frame_errors++; break;
-	    }
-	}
-	if ( (! (rx_status & 0x4000))
-	    || ! (rx_status & 0x2000)) { /* Dribble bits are OK. */
-	    short pkt_len = rx_status & 0x7ff;
-	    int sksize = sizeof(struct sk_buff) + pkt_len + 3;
-	    struct sk_buff *skb;
+	if (el3_debug > 5)
+		printk("	   In rx_packet(), status %4.4x, rx_status %4.4x.\n",
+			   inw(ioaddr+EL3_STATUS), inw(ioaddr+RX_STATUS));
+	while ((rx_status = inw(ioaddr + RX_STATUS)) > 0) {
+		if (rx_status & 0x4000) { /* Error, update stats. */
+			short error = rx_status & 0x3C00;
+			lp->stats.rx_errors++;
+			switch (error) {
+			case 0x2000:		lp->stats.rx_over_errors++; break;
+			case 0x2C00:		lp->stats.rx_length_errors++; break;
+			case 0x3400:		lp->stats.rx_crc_errors++; break;
+			case 0x2400:		lp->stats.rx_length_errors++; break;
+			case 0x3000:		lp->stats.rx_frame_errors++; break;
+			case 0x0800:		lp->stats.rx_frame_errors++; break;
+			}
+		}
+		if ( (! (rx_status & 0x4000))
+			|| ! (rx_status & 0x2000)) { /* Dribble bits are OK. */
+			short pkt_len = rx_status & 0x7ff;
+			int sksize = sizeof(struct sk_buff) + pkt_len + 3;
+			struct sk_buff *skb;
 
-	    skb = alloc_skb(sksize, GFP_ATOMIC);
-	    if (el3_debug > 4)
-		printk("       Receiving packet size %d status %4.4x.\n",
-		       pkt_len, rx_status);
-	    if (skb != NULL) {
-		skb->mem_len = sksize;
-		skb->mem_addr = skb;
-		skb->len = pkt_len;
-		skb->dev = dev;
+			skb = alloc_skb(sksize, GFP_ATOMIC);
+			if (el3_debug > 4)
+				printk("	   Receiving packet size %d status %4.4x.\n",
+					   pkt_len, rx_status);
+			if (skb != NULL) {
+				skb->mem_len = sksize;
+				skb->mem_addr = skb;
+				skb->len = pkt_len;
+				skb->dev = dev;
 
-		/* 'skb+1' points to the start of sk_buff data area. */
-		port_read_l(ioaddr+RX_FIFO, (void *)(skb+1),
-			    (pkt_len + 3) >> 2);
+				/* 'skb+1' points to the start of sk_buff data area. */
+				port_read_l(ioaddr+RX_FIFO, (void *)(skb+1),
+							(pkt_len + 3) >> 2);
 
 #ifdef HAVE_NETIF_RX
-		netif_rx(skb);
-		outw(0x4000, ioaddr + EL3_CMD); /* Rx discard */
-		continue;
+				netif_rx(skb);
+				outw(0x4000, ioaddr + EL3_CMD); /* Rx discard */
+				continue;
 #else
-		skb->lock = 0;
-		if (dev_rint((unsigned char *)skb, pkt_len,
-			     IN_SKBUFF,dev)== 0){
-		    if (el3_debug > 6)
-			printk("     dev_rint() happy, status %4.4x.\n",
-			inb(ioaddr + EL3_STATUS));
-		    outw(0x4000, ioaddr + EL3_CMD); /* Rx discard */
-		    while (inw(ioaddr + EL3_STATUS) & 0x1000)
-		      printk("  Waiting for 3c509 to discard packet, status %x.\n",
-			     inw(ioaddr + EL3_STATUS) );
-		    if (el3_debug > 6)
-			printk("     discarded packet, status %4.4x.\n",
-			inb(ioaddr + EL3_STATUS));
-		    continue;
-		} else {
-		    printk("%s: receive buffers full.\n", dev->name);
-		    kfree_skbmem(skb, sksize);
-		}
+				skb->lock = 0;
+				if (dev_rint((unsigned char *)skb, pkt_len,
+							 IN_SKBUFF,dev)== 0){
+					if (el3_debug > 6)
+						printk("	 dev_rint() happy, status %4.4x.\n",
+						inb(ioaddr + EL3_STATUS));
+					outw(0x4000, ioaddr + EL3_CMD); /* Rx discard */
+					while (inw(ioaddr + EL3_STATUS) & 0x1000)
+					  printk("	Waiting for 3c509 to discard packet, status %x.\n",
+							 inw(ioaddr + EL3_STATUS) );
+					if (el3_debug > 6)
+						printk("	 discarded packet, status %4.4x.\n",
+						inb(ioaddr + EL3_STATUS));
+					continue;
+				} else {
+					printk("%s: receive buffers full.\n", dev->name);
+					kfree_s(skb, sksize);
+				}
 #endif
-	    } else if (el3_debug)
-		printk("%s: Couldn't allocate a sk_buff of size %d.\n",
-		       dev->name, sksize);
+			} else if (el3_debug)
+				printk("%s: Couldn't allocate a sk_buff of size %d.\n",
+					   dev->name, sksize);
+		}
+		lp->stats.rx_dropped++;
+		outw(0x4000, ioaddr + EL3_CMD); /* Rx discard */
+		while (inw(ioaddr + EL3_STATUS) & 0x1000)
+		  printk("	Waiting for 3c509 to discard packet, status %x.\n",
+				 inw(ioaddr + EL3_STATUS) );
 	}
-	lp->stats.rx_dropped++;
-	outw(0x4000, ioaddr + EL3_CMD); /* Rx discard */
-	while (inw(ioaddr + EL3_STATUS) & 0x1000)
-	  printk("  Waiting for 3c509 to discard packet, status %x.\n",
-		 inw(ioaddr + EL3_STATUS) );
-    }
 
-    if (el3_debug > 5)
-	printk("       Exiting rx_packet(), status %4.4x, rx_status %4.4x.\n",
-	       inw(ioaddr+EL3_STATUS), inw(ioaddr+8));
+	if (el3_debug > 5)
+		printk("	   Exiting rx_packet(), status %4.4x, rx_status %4.4x.\n",
+			   inw(ioaddr+EL3_STATUS), inw(ioaddr+8));
 
-    return 0;
+	return 0;
 }
 
 #ifdef HAVE_MULTICAST
 /* Set or clear the multicast filter for this adaptor.
-   num_addrs == -1	Promiscuous mode, receive all packets
-   num_addrs == 0	Normal mode, clear multicast list
-   num_addrs > 0	Multicast mode, receive normal and MC packets, and do
-			best-effort filtering.
+   num_addrs == -1		Promiscuous mode, receive all packets
+   num_addrs == 0		Normal mode, clear multicast list
+   num_addrs > 0		Multicast mode, receive normal and MC packets, and do
+						best-effort filtering.
  */
 static void
 set_multicast_list(struct device *dev, int num_addrs, void *addrs)
 {
-    short ioaddr = dev->base_addr;
-    if (num_addrs > 0) {
-    	outw(0x8007, ioaddr + EL3_CMD);
-    } else if (num_addrs < 0) {
-	outw(0x8008, ioaddr + EL3_CMD);
-    } else
-	outw(0x8005, ioaddr + EL3_CMD);
+	short ioaddr = dev->base_addr;
+	if (num_addrs > 0) {
+		outw(0x8007, ioaddr + EL3_CMD);
+	} else if (num_addrs < 0) {
+		outw(0x8008, ioaddr + EL3_CMD);
+	} else
+		outw(0x8005, ioaddr + EL3_CMD);
 }
 #endif
 
 static int
 el3_close(struct device *dev)
 {
-    int ioaddr = dev->base_addr;
+	int ioaddr = dev->base_addr;
 
-    if (el3_debug > 2)
-	printk("%s: Shutting down ethercard.\n", dev->name);
+	if (el3_debug > 2)
+		printk("%s: Shutting down ethercard.\n", dev->name);
 
-    dev->tbusy = 1;
-    dev->start = 0;
+	dev->tbusy = 1;
+	dev->start = 0;
 
-    /* Turn off statistics.  We update lp->stats below. */
-    outw(0xB000, ioaddr + EL3_CMD);
+	/* Turn off statistics.	 We update lp->stats below. */
+	outw(0xB000, ioaddr + EL3_CMD);
 
-    /* Disable the receiver and transmitter. */
-    outw(0x1800, ioaddr + EL3_CMD);
-    outw(0x5000, ioaddr + EL3_CMD);
+	/* Disable the receiver and transmitter. */
+	outw(0x1800, ioaddr + EL3_CMD);
+	outw(0x5000, ioaddr + EL3_CMD);
 
-    if (dev->if_port == 3)
-	/* Turn off thinnet power. */
-	outw(0xb800, ioaddr + EL3_CMD);
-    else if (dev->if_port == 0) {
-	/* Disable link beat and jabber, if_port may change ere next open(). */
-	EL3WINDOW(4);
-	outw(inw(ioaddr + WN4_MEDIA) & ~ 0x00C0, ioaddr + WN4_MEDIA);
-    }
+	if (dev->if_port == 3)
+		/* Turn off thinnet power. */
+		outw(0xb800, ioaddr + EL3_CMD);
+	else if (dev->if_port == 0) {
+		/* Disable link beat and jabber, if_port may change ere next open(). */
+		EL3WINDOW(4);
+		outw(inw(ioaddr + WN4_MEDIA) & ~MEDIA_TP, ioaddr + WN4_MEDIA);
+	}
 
-    free_irq(dev->irq);
-    /* Switching back to window 0 disables the IRQ. */
-    EL3WINDOW(0);
-    /* But we explicitly zero the IRQ line select anyway. */
-    outw(0x0f00, ioaddr + 8);
+	free_irq(dev->irq);
+	/* Switching back to window 0 disables the IRQ. */
+	EL3WINDOW(0);
+	/* But we explicitly zero the IRQ line select anyway. */
+	outw(0x0f00, ioaddr + 8);
 
 
-    irq2dev_map[dev->irq] = 0;
+	irq2dev_map[dev->irq] = 0;
 
-    update_stats(ioaddr, dev);
-    return 0;
+	update_stats(ioaddr, dev);
+	return 0;
 }
 
 /*
  * Local variables:
- *  compile-command: "gcc -D__KERNEL__ -Wall -O6 -x c++ -c 3c509.c"
+ *  compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c 3c509.c"
+ *  version-control: t
+ *  kept-new-versions: 5
+ *  tab-width: 4
  * End:
  */
diff --git a/drivers/net/CONFIG b/drivers/net/CONFIG
index 2ec4be3..c17d07f 100644
--- a/drivers/net/CONFIG
+++ b/drivers/net/CONFIG
@@ -43,5 +43,5 @@
 HP_OPTS		=
 PLIP_OPTS	=
 SLIP_OPTS	= -DSL_DUMP -DSL_COMPRESSED
-DL_OPTS		= # -DD_LINK_IO=0x378 -DD_LINK_IRQ=7 -UD_LINK_DEBUG
+DL_OPTS		= -DD_LINK_IO=0x378 -DD_LINK_IRQ=7 -UD_LINK_DEBUG
 AT_OPTS		= # -DLANCE_DMA=5
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index c473451..c535be7 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -1,23 +1,13 @@
-# File: net/drv/Makefile
+# File: drivers/net/Makefile
 #
 # Makefile for the Linux network (ethercard) device drivers.
 #
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
-#
-# Note 2! The CFLAGS definition is now in the main makefile...
 
+# This will go away in some future future: hidden configuration files
+# are difficult for users to deal with.
 include CONFIG
 
-.c.s:
-	$(CC) $(CFLAGS) -S -o $*.s $<
-.s.o:
-	$(AS) -o $*.o $<
-.c.o:
-	$(CC) $(CFLAGS) -c -o $*.o $<
-
-NETDRV_OBJS := Space.o auto_irq.o
+NETDRV_OBJS := net.a(Space.o) net.a(auto_irq.o) net.a(net_init.o)
 CFLAGS := $(CFLAGS) -I../../net/inet
 CPP := $(CPP) -I../../net/inet
 
@@ -27,101 +17,122 @@
 Space.o: Space.c /usr/include/linux/autoconf.h
 	$(CC) $(CFLAGS) $(OPTS) $(DL_OPTS) -c $< -o $@
 
+net_init.o: /usr/include/linux/autoconf.h
+
 ifdef CONFIG_WD80x3
-NETDRV_OBJS := $(NETDRV_OBJS) wd.o
+NETDRV_OBJS := $(NETDRV_OBJS) net.a(wd.o)
 CONFIG_8390 = CONFIG_8390
 wd.o:	wd.c CONFIG
-	$(CC) $(CPPFLAGS) $(CFLAGS) $(WD_OPTS) -c wd.c
+	$(CC) $(CPPFLAGS) $(CFLAGS) $(WD_OPTS) -c $<
 endif
 
 ifdef CONFIG_EL2
-NETDRV_OBJS := $(NETDRV_OBJS) 3c503.o
+NETDRV_OBJS := $(NETDRV_OBJS) net.a(3c503.o)
 CONFIG_8390 = CONFIG_8390
 3c503.o:	3c503.c CONFIG
-	$(CC) $(CPPFLAGS) $(CFLAGS) $(EL2_OPTS) -c 3c503.c
+	$(CC) $(CPPFLAGS) $(CFLAGS) $(EL2_OPTS) -c $<
 endif
 
 ifdef CONFIG_NE2000
-NETDRV_OBJS := $(NETDRV_OBJS) ne.o
+NETDRV_OBJS := $(NETDRV_OBJS) net.a(ne.o)
 CONFIG_8390 = CONFIG_8390
 ne.o:	ne.c CONFIG
-	$(CC) $(CPPFLAGS) $(CFLAGS) $(NE_OPTS) -c ne.c
+	$(CC) $(CPPFLAGS) $(CFLAGS) $(NE_OPTS) -c $<
 endif
 
 ifdef CONFIG_HPLAN
-NETDRV_OBJS := $(NETDRV_OBJS) hp.o
+NETDRV_OBJS := $(NETDRV_OBJS) net.a(hp.o)
 CONFIG_8390 = CONFIG_8390
 hp.o:	hp.c CONFIG
-	$(CC) $(CPPFLAGS) $(CFLAGS) $(HP_OPTS) -c hp.c
+	$(CC) $(CPPFLAGS) $(CFLAGS) $(HP_OPTS) -c $<
 endif
 
 ifdef CONFIG_ULTRA
-NETDRV_OBJS := $(NETDRV_OBJS) smc-ultra.o
+NETDRV_OBJS := $(NETDRV_OBJS) net.a(smc-ultra.o)
+CONFIG_8390 = CONFIG_8390
+endif
+
+ifdef CONFIG_E2100
+NETDRV_OBJS := $(NETDRV_OBJS) net.a(e2100.o)
+CONFIG_8390 = CONFIG_8390
+endif
+
+ifdef CONFIG_PLIP
+NETDRV_OBJS := $(NETDRV_OBJS) net.a(plip.o)
+plip.o:	plip.c CONFIG
+	$(CC) $(CPPFLAGS) $(CFLAGS) $(PLIP_OPTS) -c $<
+endif
+
+ifdef CONFIG_PPP
+NETDRV_OBJS := $(NETDRV_OBJS) net.a(ppp.o) net.a(slhc.o)
+endif
+
+ifdef CONFIG_SLIP
+NETDRV_OBJS := $(NETDRV_OBJS) net.a(slip.o) net.a(slhc.o)
+slip.o:	slip.c CONFIG
+	$(CC) $(CPPFLAGS) $(CFLAGS) $(SLIP_OPTS) -c $<
+endif
+
+ifdef CONFIG_DE600
+NETDRV_OBJS := $(NETDRV_OBJS) net.a(d_link.o)
+d_link.o: d_link.c CONFIG
+	$(CC) $(CPPFLAGS) $(CFLAGS) $(DL_OPTS) -c $<
+endif
+
+ifdef CONFIG_AT1500
+NETDRV_OBJS := $(NETDRV_OBJS) net.a(lance.o)
+endif
+ifdef CONFIG_LANCE
+NETDRV_OBJS := $(NETDRV_OBJS) net.a(lance.o)
+endif
+ifdef CONFIG_AT1700
+NETDRV_OBJS := $(NETDRV_OBJS) net.a(at1700.o)
+endif
+ifdef CONFIG_EL1
+NETDRV_OBJS := $(NETDRV_OBJS) net.a(3c501.o)
+endif
+ifdef CONFIG_EL16
+NETDRV_OBJS := $(NETDRV_OBJS) net.a(3c507.o)
+endif
+ifdef CONFIG_EL3
+NETDRV_OBJS := $(NETDRV_OBJS) net.a(3c509.o)
+endif
+ifdef CONFIG_EEXPRESS
+NETDRV_OBJS := $(NETDRV_OBJS) net.a(eexpress.o)
+endif
+ifdef CONFIG_ZNET
+NETDRV_OBJS := $(NETDRV_OBJS) net.a(znet.o)
+endif
+ifdef CONFIG_DEPCA
+NETDRV_OBJS := $(NETDRV_OBJS) net.a(depca.o)
+endif
+ifdef CONFIG_ATP
+NETDRV_OBJS := $(NETDRV_OBJS) net.a(atp.o)
+endif
+ifdef CONFIG_NI52
+NETDRV_OBJS := $(NETDRV_OBJS) net.a(ni52.o)
+endif
+ifdef CONFIG_NI65
+NETDRV_OBJS := $(NETDRV_OBJS) net.a(ni65.o)
+endif
+ifdef CONFIG_ELPLUS
+NETDRV_OBJS := $(NETDRV_OBJS) net.a(3c505.o)
+endif
+ifdef CONFIG_AC3200
+NETDRV_OBJS := $(NETDRV_OBJS) net.a(ac3200.o)
 CONFIG_8390 = CONFIG_8390
 endif
 
 ifdef CONFIG_8390
-NETDRV_OBJS := $(NETDRV_OBJS) 8390.o
-endif
-
-ifdef CONFIG_PLIP
-NETDRV_OBJS := $(NETDRV_OBJS) plip.o
-plip.o:	plip.c CONFIG
-	$(CC) $(CPPFLAGS) $(CFLAGS) $(PLIP_OPTS) -c plip.c
-endif
-
-ifdef CONFIG_SLIP
-NETDRV_OBJS := $(NETDRV_OBJS) slip.o slhc.o
-slip.o:	slip.c CONFIG
-	$(CC) $(CPPFLAGS) $(CFLAGS) $(SLIP_OPTS) -c slip.c
-endif
-
-ifdef CONFIG_DE600
-NETDRV_OBJS := $(NETDRV_OBJS) d_link.o
-d_link.o: d_link.c CONFIG
-	$(CC) $(CPPFLAGS) $(CFLAGS) $(DL_OPTS) -c d_link.c
-endif
-
-ifdef CONFIG_AT1500
-NETDRV_OBJS := $(NETDRV_OBJS) lance.o
-endif
-
-ifdef CONFIG_EL3
-NETDRV_OBJS := $(NETDRV_OBJS) 3c509.o
-endif
-
-ifdef CONFIG_ZNET
-NETDRV_OBJS := $(NETDRV_OBJS) znet.o
-endif
-ifdef CONFIG_EEXPRESS
-NETDRV_OBJS := $(NETDRV_OBJS) eexpress.o
-endif
-ifdef CONFIG_EL1
-NETDRV_OBJS := $(NETDRV_OBJS) 3c501.o
-endif
-ifdef CONFIG_EL16
-NETDRV_OBJS := $(NETDRV_OBJS) 3c507.o
-endif
-ifdef CONFIG_DEPCA
-NETDRV_OBJS := $(NETDRV_OBJS) depca.o
-endif
-ifdef CONFIG_ATP
-NETDRV_OBJS := $(NETDRV_OBJS) atlantec.o
-endif
-ifdef CONFIG_NI52
-NETDRV_OBJS := $(NETDRV_OBJS) ni52.o
-endif
-ifdef CONFIG_NI65
-NETDRV_OBJS := $(NETDRV_OBJS) ni65.o
+NETDRV_OBJS := $(NETDRV_OBJS) net.a(8390.o)
 endif
 
 ifdef CONFIG_IP_DEFRAG
-NETDRV_OBJS := $(NETDRV_OBJS) ip-frag.o
+NETDRV_OBJS := $(NETDRV_OBJS) net.a(ip-frag.o)
 endif
 
 net.a: $(NETDRV_OBJS)
-	rm -f $@
-	$(AR) rcs $@ $^
+	ranlib net.a
 
 clean:
 	rm -f core *.o *.a *.s
@@ -130,11 +141,10 @@
 	$(CPP) -M *.c > .depend
 
 tar:
-	tar -cvf /dev/f1 .
 
-#
+
 # include a dependency file if one exists
-#
+
 ifeq (.depend,$(wildcard .depend))
 include .depend
 endif
diff --git a/drivers/net/Space.c b/drivers/net/Space.c
index 64d8bb4..6cc4cf6 100644
--- a/drivers/net/Space.c
+++ b/drivers/net/Space.c
@@ -45,10 +45,18 @@
 extern int znet_probe(struct device *);
 extern int express_probe(struct device *);
 extern int el3_probe(struct device *);
-extern int atp_probe(struct device *);
 extern int at1500_probe(struct device *);
+extern int at1700_probe(struct device *);
 extern int depca_probe(struct device *);
 extern int el1_probe(struct device *);
+extern int el16_probe(struct device *);
+extern int elplus_probe(struct device *);
+extern int ac3200_probe(struct device *);
+extern int e2100_probe(struct device *);
+
+/* Detachable devices ("pocket adaptors" and special PCMCIA drivers). */
+extern int atp_init(struct device *);
+extern int d_link_init(struct device *);
 
 static int
 ethif_probe(struct device *dev)
@@ -65,7 +73,7 @@
 #if defined(CONFIG_WD80x3) || defined(WD80x3)
 	&& wd_probe(dev)
 #endif
-#if defined(CONFIG_EL2) || defined(EL2)
+#if defined(CONFIG_EL2) || defined(EL2)	/* 3c503 */
 	&& el2_probe(dev)
 #endif
 #if defined(CONFIG_NE2000) || defined(NE2000)
@@ -77,24 +85,36 @@
 #ifdef CONFIG_AT1500
 	&& at1500_probe(dev)
 #endif
-#ifdef CONFIG_EL3
+#ifdef CONFIG_AT1700
+	&& at1700_probe(dev)
+#endif
+#ifdef CONFIG_EL3		/* 3c509 */
 	&& el3_probe(dev)
 #endif
-#ifdef CONFIG_ZNET
+#ifdef CONFIG_ZNET		/* Zenith Z-Note and some IBM Thinkpads. */
 	&& znet_probe(dev)
 #endif
-#ifdef CONFIG_EEXPRESS
+#ifdef CONFIG_EEXPRESS		/* Intel EtherExpress */
 	&& express_probe(dev)
 #endif
-#ifdef CONFIG_ATP		/* AT-LAN-TEC (RealTek) pocket adaptor. */
-	&& atp_probe(dev)
-#endif
-#ifdef CONFIG_DEPCA
+#ifdef CONFIG_DEPCA		/* DEC DEPCA */
 	&& depca_probe(dev)
 #endif
-#ifdef CONFIG_EL1
+#ifdef CONFIG_EL1		/* 3c501 */
 	&& el1_probe(dev)
 #endif
+#ifdef CONFIG_EL16		/* 3c507 */
+	&& el16_probe(dev)
+#endif
+#ifdef CONFIG_ELPLUS		/* 3c505 */
+	&& elplus_probe(dev)
+#endif
+#ifdef CONFIG_AC3200		/* Ansel Communications EISA 3200. */
+	&& ac3200_probe(dev)
+#endif
+#ifdef CONFIG_E2100		/* Cabletron E21xx series. */
+	&& e2100_probe(dev)
+#endif
 	&& 1 ) {
 	return 1;	/* -ENODEV or -EAGAIN would be more accurate. */
     }
@@ -102,26 +122,22 @@
 }
 
 
-/* This remains seperate because it requires the addr and IRQ to be
-   set. */
+/* This remains seperate because it requires the addr and IRQ to be set. */
 #if defined(D_LINK) || defined(CONFIG_DE600)
-    extern int d_link_init(struct device *);
-    static struct device d_link_dev = {
-	"dl0",
-	0,
-	0,
-	0,
-	0,
-	D_LINK_IO,
-	D_LINK_IRQ,
-	0, 0, 0,
-	NEXT_DEV,
-	d_link_init
-    };
+static struct device d_link_dev = {
+    "dl0", 0, 0, 0, 0, D_LINK_IO, D_LINK_IRQ, 0, 0, 0, NEXT_DEV, d_link_init };
 #   undef NEXT_DEV
 #   define NEXT_DEV	(&d_link_dev)
 #endif
 
+/* Run-time ATtachable (Pocket) devices have a different (not "eth#") name. */
+#ifdef CONFIG_ATP		/* AT-LAN-TEC (RealTek) pocket adaptor. */
+static struct device atp_dev = {
+    "atp0", 0, 0, 0, 0, 0, 0, 0, 0, 0, NEXT_DEV, atp_init, /* ... */ };
+#   undef NEXT_DEV
+#   define NEXT_DEV	(&atp_dev)
+#endif
+
 /* The first device defaults to I/O base '0', which means autoprobe. */
 #ifdef EI8390
 # define ETH0_ADDR EI8390
@@ -214,7 +230,20 @@
 #   undef	NEXT_DEV
 #   define	NEXT_DEV	(&slip0_dev)
 #endif	/* SLIP */
-
+  
+#if defined(CONFIG_PPP)
+extern int ppp_init(struct device *);
+static struct device ppp3_dev = {
+    "ppp3", 0x0, 0x0, 0x0, 0x0, 3, 0, 0, 0, 0, NEXT_DEV,  ppp_init, };
+static struct device ppp2_dev = {
+    "ppp2", 0x0, 0x0, 0x0, 0x0, 2, 0, 0, 0, 0, &ppp3_dev, ppp_init, };
+static struct device ppp1_dev = {
+    "ppp1", 0x0, 0x0, 0x0, 0x0, 1, 0, 0, 0, 0, &ppp2_dev, ppp_init, };
+static struct device ppp0_dev = {
+    "ppp0", 0x0, 0x0, 0x0, 0x0, 0, 0, 0, 0, 0, &ppp1_dev, ppp_init, };
+#undef NEXT_DEV
+#define NEXT_DEV (&ppp0_dev)
+#endif   /* PPP */
 
 #ifdef LOOPBACK
     extern int loopback_init(struct device *dev);
diff --git a/drivers/net/at1700.c b/drivers/net/at1700.c
new file mode 100644
index 0000000..fe619c8
--- /dev/null
+++ b/drivers/net/at1700.c
@@ -0,0 +1,661 @@
+/* at1700.c: A network device driver for  the Allied Telesis AT1700.
+
+   Written 1993 by Donald Becker.  This is a alpha test limited release.
+   This version may only be used and distributed according to the terms of the
+   GNU Public License, incorporated herein by reference.
+
+   The author may be reached as becker@super.org or
+   C/O Supercomputing Research Ctr., 17100 Science Dr., Bowie MD 20715
+
+   This is a device driver for the Allied Telesis AT1700, which is a
+   straight-foward Fujitsu MB86965 implementation.
+*/
+
+static char *version =
+	"at1700.c:v0.03 11/16/93  Donald Becker (becker@super.org)\n";
+
+#include <linux/config.h>
+
+/*
+  Sources:
+    The Fujitsu MB86695 datasheet.
+*/
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/in.h>
+#include <linux/malloc.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <errno.h>
+#include <memory.h>
+
+#include "dev.h"
+#include "iow.h"
+#include "eth.h"
+#include "skbuff.h"
+#include "arp.h"
+
+#ifndef HAVE_AUTOIRQ
+/* From auto_irq.c, in ioport.h for later versions. */
+extern void autoirq_setup(int waittime);
+extern int autoirq_report(int waittime);
+/* The map from IRQ number (as passed to the interrupt handler) to
+   'struct device'. */
+extern struct device *irq2dev_map[16];
+#endif
+
+#ifndef HAVE_ALLOC_SKB
+#define alloc_skb(size, priority) (struct sk_buff *) kmalloc(size,priority)
+#define kfree_skbmem(addr, size) kfree_s(addr,size);
+#endif
+
+/* use 0 for production, 1 for verification, >2 for debug */
+#ifndef NET_DEBUG
+#define NET_DEBUG 2
+#endif
+static unsigned int net_debug = NET_DEBUG;
+
+typedef unsigned char uchar;
+
+/* Information that need to be kept for each board. */
+struct net_local {
+	struct enet_statistics stats;
+	long open_time;				/* Useless example local info. */
+	uint tx_started:1;			/* Number of packet on the Tx queue. */
+	uchar tx_queue;				/* Number of packet on the Tx queue. */
+	ushort tx_queue_len;		/* Current length of the Tx queue. */
+};
+
+
+/* Offsets from the base address. */
+#define STATUS			0
+#define TX_STATUS		0
+#define RX_STATUS		1
+#define TX_INTR			2		/* Bit-mapped interrupt enable registers. */
+#define RX_INTR			3
+#define TX_MODE			4
+#define RX_MODE			5
+#define CONFIG_0		6		/* Misc. configuration settings. */
+#define CONFIG_1		7
+/* Run-time register bank 2 definitions. */
+#define DATAPORT		8		/* Word-wide DMA or programmed-I/O dataport. */
+#define TX_START		10
+#define MODE13			13
+#define EEPROM_Ctrl 	16
+#define EEPROM_Data 	17
+
+/*  EEPROM_Ctrl bits. */
+#define EE_SHIFT_CLK	0x40	/* EEPROM shift clock, in reg. 16. */
+#define EE_CS			0x20	/* EEPROM chip select, in reg. 16. */
+#define EE_DATA_WRITE	0x80	/* EEPROM chip data in, in reg. 17. */
+#define EE_DATA_READ	0x80	/* EEPROM chip data out, in reg. 17. */
+
+/* Delay between EEPROM clock transitions. */
+#define eeprom_delay()	do { int _i = 40; while (--_i > 0) { __SLOW_DOWN_IO; }} while (0)
+
+/* The EEPROM commands include the alway-set leading bit. */
+#define EE_WRITE_CMD	(5 << 6)
+#define EE_READ_CMD		(6 << 6)
+#define EE_ERASE_CMD	(7 << 6)
+
+
+/* Index to functions, as function prototypes. */
+
+extern int at1700_probe(struct device *dev);
+
+static int at1700_probe1(struct device *dev, short ioaddr);
+static int read_eeprom(int ioaddr, int location);
+static int net_open(struct device *dev);
+static int	net_send_packet(struct sk_buff *skb, struct device *dev);
+static void net_interrupt(int reg_ptr);
+static void net_rx(struct device *dev);
+static int net_close(struct device *dev);
+static struct enet_statistics *net_get_stats(struct device *dev);
+#ifdef HAVE_MULTICAST
+static void set_multicast_list(struct device *dev, int num_addrs, void *addrs);
+#endif
+
+
+/* Check for a network adaptor of this type, and return '0' iff one exists.
+   If dev->base_addr == 0, probe all likely locations.
+   If dev->base_addr == 1, always return failure.
+   If dev->base_addr == 2, alloate space for the device and return success
+   (detachable devices only).
+   */
+int
+at1700_probe(struct device *dev)
+{
+	short ports[] = {0x300, 0x280, 0x380, 0x320, 0x340, 0x260, 0x2a0, 0x240, 0};
+	short *port, base_addr = dev->base_addr;
+
+	if (base_addr > 0x1ff)		/* Check a single specified location. */
+		return at1700_probe1(dev, base_addr);
+	else if (base_addr > 0)		/* Don't probe at all. */
+		return ENXIO;
+
+	for (port = &ports[0]; *port; port++) {
+		int ioaddr = *port;
+#ifdef HAVE_PORTRESERVE
+		if (check_region(ioaddr, 32))
+			continue;
+#endif
+		if (inw(ioaddr) != 0x0000)
+			continue;
+		if (at1700_probe1(dev, ioaddr) == 0)
+			return 0;
+	}
+
+	return ENODEV;			/* ENODEV would be more accurate. */
+}
+
+int at1700_probe1(struct device *dev, short ioaddr)
+{
+	unsigned short signature[4]         = {0x0000, 0xffff, 0x41f6, 0xefb6};
+	unsigned short signature_invalid[4] = {0x0000, 0xffff, 0x00f0, 0x2f00};
+	char irqmap[4] = {3, 4, 5, 9};
+	unsigned short *station_address = (unsigned short *)dev->dev_addr;
+	unsigned int i, irq;
+
+	/* Resetting the chip doesn't reset the ISA interface, so don't bother.
+	   That means we have to be careful with the register values we probe for.
+	   */
+	for (i = 0; i < 4; i++)
+		if ((inw(ioaddr + 2*i) | signature_invalid[i]) != signature[i]) {
+			if (net_debug > 1)
+				printk("AT1700 signature match failed at %d (%04x vs. %04x)\n",
+					   i, inw(ioaddr + 2*i), signature[i]);
+			return -ENODEV;
+		}
+#ifdef HAVE_PORTRESERVE
+	/* Grab the region so that we can find another board if the IRQ request
+	   fails. */
+	snarf_region(ioaddr, 32);
+#endif
+
+	irq = irqmap[ read_eeprom(ioaddr, 0) >> 14 ];
+
+	/* Snarf the interrupt vector now. */
+	if (request_irq(irq, &net_interrupt)) {
+		printk ("AT1700 found at %#3x, but it's unusable due to a conflict on"
+				"IRQ %d.\n", ioaddr, irq);
+		return EAGAIN;
+	}
+
+	printk("%s: AT1700 found at %#3x, IRQ %d, address ", dev->name,
+		   ioaddr, irq);
+
+	dev->base_addr = ioaddr;
+	dev->irq = irq;
+	irq2dev_map[irq] = dev;
+
+	for(i = 0; i < 3; i++) {
+		unsigned short eeprom_val = read_eeprom(ioaddr, 4+i);
+		printk("%04x", eeprom_val);
+		station_address[i] = ntohs(eeprom_val);
+	}
+
+	/* The EEPROM word 12 bit 0x0400 means use regular 100 ohm 10baseT signals,
+	   rather than 150 ohm shielded twisted pair compansation.
+	   0x0000 == auto-sense the interface
+	   0x0800 == use TP interface
+	   0x1800 == use coax interface
+	   */
+	{
+		char *porttype[] = {"auto-sense", "10baseT", "auto-sense", "10base2"};
+		ushort setup_value = read_eeprom(ioaddr, 12);
+
+		dev->if_port = setup_value >> 8;
+		printk(" %s interface (%04x).\n", porttype[(dev->if_port>>3) & 3],
+			   setup_value);
+	}
+
+	/* Set the station address in bank zero. */
+	outb(0xe0, ioaddr + 7);
+	for (i = 0; i < 6; i++)
+		outb(dev->dev_addr[i], ioaddr + 8 + i);
+
+	/* Switch to bank 1 and set the multicast table to accept none. */
+	outb(0xe4, ioaddr + 7);
+	for (i = 0; i < 8; i++)
+		outb(0x00, ioaddr + 8 + i);
+
+	/* Set the configuration register 0 to 32K 100ns. byte-wide memory, 16 bit
+	   bus access, two 4K Tx queues, and disabled Tx and Rx. */
+	outb(0xda, ioaddr + CONFIG_0);
+
+	/* Switch to bank 2 and lock our I/O address. */
+	outb(0xe8, ioaddr + 7);
+	outb(dev->if_port, MODE13);
+
+	/* Power-down the chip.  Aren't we green! */
+	outb(0x00, ioaddr + CONFIG_1);
+
+	if (net_debug)
+		printk(version);
+
+	/* Initialize the device structure. */
+	dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL);
+	memset(dev->priv, 0, sizeof(struct net_local));
+
+	dev->open		= net_open;
+	dev->stop		= net_close;
+	dev->hard_start_xmit = net_send_packet;
+	dev->get_stats	= net_get_stats;
+#ifdef HAVE_MULTICAST
+	dev->set_multicast_list = &set_multicast_list;
+#endif
+
+	/* Fill in the fields of the device structure with ethernet-generic values.
+	   This should be in a common file instead of per-driver.  */
+	for (i = 0; i < DEV_NUMBUFFS; i++)
+		dev->buffs[i] = NULL;
+
+	dev->hard_header	= eth_header;
+	dev->add_arp		= eth_add_arp;
+	dev->queue_xmit		= dev_queue_xmit;
+	dev->rebuild_header	= eth_rebuild_header;
+	dev->type_trans		= eth_type_trans;
+
+	dev->type		= ARPHRD_ETHER;
+	dev->hard_header_len = ETH_HLEN;
+	dev->mtu		= 1500; /* eth_mtu */
+	dev->addr_len	= ETH_ALEN;
+	for (i = 0; i < ETH_ALEN; i++) {
+		dev->broadcast[i]=0xff;
+	}
+
+	/* New-style flags. */
+	dev->flags		= IFF_BROADCAST;
+	dev->family		= AF_INET;
+	dev->pa_addr	= 0;
+	dev->pa_brdaddr	= 0;
+	dev->pa_mask	= 0;
+	dev->pa_alen	= sizeof(unsigned long);
+
+	return 0;
+}
+
+static int read_eeprom(int ioaddr, int location)
+{
+	int i;
+	unsigned short retval = 0;
+	short ee_addr = ioaddr + EEPROM_Ctrl;
+	short ee_daddr = ioaddr + EEPROM_Data;
+	int read_cmd = location | EE_READ_CMD;
+	short ctrl_val = EE_CS;
+	
+	outb(ctrl_val, ee_addr);
+	
+	/* Shift the read command bits out. */
+	for (i = 9; i >= 0; i--) {
+		short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0;
+		outb(dataval, ee_daddr);
+		outb(EE_CS | EE_SHIFT_CLK, ee_addr);	/* EEPROM clock tick. */
+		eeprom_delay();
+		outb(EE_CS, ee_addr);	/* Finish EEPROM a clock tick. */
+		eeprom_delay();
+	}
+	outb(EE_CS, ee_addr);
+	
+	for (i = 16; i > 0; i--) {
+		outb(EE_CS | EE_SHIFT_CLK, ee_addr);
+		eeprom_delay();
+		retval = (retval << 1) | ((inb(ee_daddr) & EE_DATA_READ) ? 1 : 0);
+		outb(EE_CS, ee_addr);
+		eeprom_delay();
+	}
+
+	/* Terminate the EEPROM access. */
+	ctrl_val &= ~EE_CS;
+	outb(ctrl_val | EE_SHIFT_CLK, ee_addr);
+	eeprom_delay();
+	outb(ctrl_val, ee_addr);
+	eeprom_delay();
+	return retval;
+}
+
+
+
+static int net_open(struct device *dev)
+{
+	struct net_local *lp = (struct net_local *)dev->priv;
+	int ioaddr = dev->base_addr;
+	int i;
+
+	/* Powerup the chip, initialize config register 1, and select bank 0. */
+	outb(0xe0, ioaddr + CONFIG_1);
+
+	/* Set the station address in bank zero. */
+	for (i = 0; i < 6; i++)
+		outb(dev->dev_addr[i], ioaddr + 8 + i);
+
+	/* Switch to bank 1 and set the multicast table to accept none. */
+	outb(0xe4, ioaddr + 7);
+	for (i = 0; i < 8; i++)
+		outb(0x00, ioaddr + 8 + i);
+
+	/* Set the configuration register 0 to 32K 100ns. byte-wide memory, 16 bit
+	   bus access, and two 4K Tx queues. */
+	outb(0xda, ioaddr + CONFIG_0);
+
+	/* Same config 0, except enable the Rx and Tx. */
+	outb(0x5a, ioaddr + CONFIG_0);
+	/* Switch to register bank 2 for the run-time registers. */
+	outb(0xe8, ioaddr + CONFIG_1);
+
+	/* Turn on Rx interrupts, leave Tx interrupts off until packet Tx. */
+	outb(0x00, ioaddr + TX_INTR);
+	outb(0x81, ioaddr + RX_INTR);
+
+	lp->open_time = jiffies;
+
+	dev->tbusy = 0;
+	dev->interrupt = 0;
+	dev->start = 1;
+
+	return 0;
+}
+
+static int
+net_send_packet(struct sk_buff *skb, struct device *dev)
+{
+	struct net_local *lp = (struct net_local *)dev->priv;
+	int ioaddr = dev->base_addr;
+
+	if (dev->tbusy) {
+		/* If we get here, some higher level has decided we are broken.
+		   There should really be a "kick me" function call instead. */
+		int tickssofar = jiffies - dev->trans_start;
+		if (tickssofar < 10)
+			return 1;
+		printk("%s: transmit timed out with status %04x, %s?\n", dev->name,
+			   inw(ioaddr + STATUS), inb(ioaddr + TX_STATUS) & 0x80
+			   ? "IRQ conflict" : "network cable problem");
+		printk("%s: timeout registers: %04x %04x %04x %04x %04x %04x %04x %04x.\n",
+			   dev->name, inw(ioaddr + 0), inw(ioaddr + 2), inw(ioaddr + 4),
+			   inw(ioaddr + 6), inw(ioaddr + 8), inw(ioaddr + 10),
+			   inw(ioaddr + 12), inw(ioaddr + 14));
+		lp->stats.tx_errors++;
+		/* ToDo: We should try to restart the adaptor... */
+		outw(0xffff, ioaddr + 24);
+		outw(0xffff, ioaddr + TX_STATUS);
+		outw(0xe85a, ioaddr + CONFIG_0);
+		outw(0x8100, ioaddr + TX_INTR);
+		dev->tbusy=0;
+		dev->trans_start = jiffies;
+	}
+
+	/* If some higher layer thinks we've missed an tx-done interrupt
+	   we are passed NULL. Caution: dev_tint() handles the cli()/sti()
+	   itself. */
+	if (skb == NULL) {
+		dev_tint(dev);
+		return 0;
+	}
+
+	/* For ethernet, fill in the header.  This should really be done by a
+	   higher level, rather than duplicated for each ethernet adaptor. */
+	if (!skb->arp  &&  dev->rebuild_header(skb+1, dev)) {
+		skb->dev = dev;
+		arp_queue (skb);
+		return 0;
+	}
+	skb->arp=1;
+
+	/* Block a timer-based transmit from overlapping.  This could better be
+	   done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
+	if (set_bit(0, (void*)&dev->tbusy) != 0)
+		printk("%s: Transmitter access conflict.\n", dev->name);
+	else {
+		short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
+		unsigned char *buf = (void *)(skb+1);
+
+		if (net_debug > 4)
+			printk("%s: Transmitting a packet of length %d.\n", dev->name,
+				   skb->len);
+
+		/* Turn off the possible Tx interrupts. */
+		outb(0x00, ioaddr + TX_INTR);
+		
+		outw(length, ioaddr + DATAPORT);
+		port_write(ioaddr + DATAPORT, buf, (length + 1) >> 1);
+
+		lp->tx_queue++;
+		lp->tx_queue_len += length + 2;
+
+		if (lp->tx_started == 0) {
+			/* If the Tx is idle, always trigger a transmit. */
+			outb(0x80 | lp->tx_queue, ioaddr + TX_START);
+			lp->tx_queue = 0;
+			lp->tx_queue_len = 0;
+			dev->trans_start = jiffies;
+			lp->tx_started = 1;
+		} else if (lp->tx_queue_len < 4096 - 1502)	/* Room for one more packet? */
+			dev->tbusy = 0;
+
+		/* Turn on Tx interrupts back on. */
+		outb(0x82, ioaddr + TX_INTR);
+	}
+	if (skb->free)
+		kfree_skb (skb, FREE_WRITE);
+
+	return 0;
+}
+
+/* The typical workload of the driver:
+   Handle the network interface interrupts. */
+static void
+net_interrupt(int reg_ptr)
+{
+	int irq = -(((struct pt_regs *)reg_ptr)->orig_eax+2);
+	struct device *dev = (struct device *)(irq2dev_map[irq]);
+	struct net_local *lp;
+	int ioaddr, status;
+
+	if (dev == NULL) {
+		printk ("at1700_interrupt(): irq %d for unknown device.\n", irq);
+		return;
+	}
+	dev->interrupt = 1;
+
+	ioaddr = dev->base_addr;
+	lp = (struct net_local *)dev->priv;
+	status = inw(ioaddr + TX_STATUS);
+	outw(status, ioaddr + TX_STATUS);
+
+	if (net_debug > 4)
+		printk("%s: Interrupt with status %04x.\n", dev->name, status);
+	if (status & 0xff00
+		||  (inb(ioaddr + RX_MODE) & 0x40) == 0) {			/* Got a packet(s). */
+		net_rx(dev);
+	}
+	if (status & 0x00ff) {
+		if (status & 0x80) {
+			lp->stats.tx_packets++;
+			if (lp->tx_queue) {
+				outb(0x80 | lp->tx_queue, ioaddr + TX_START);
+				lp->tx_queue = 0;
+				lp->tx_queue_len = 0;
+				dev->trans_start = jiffies;
+				dev->tbusy = 0;
+				mark_bh(INET_BH);	/* Inform upper layers. */
+			} else {
+				lp->tx_started = 0;
+				/* Turn on Tx interrupts off. */
+				outb(0x00, ioaddr + TX_INTR);
+				dev->tbusy = 0;
+			}
+		}
+	}
+
+	return;
+}
+
+/* We have a good packet(s), get it/them out of the buffers. */
+static void
+net_rx(struct device *dev)
+{
+	struct net_local *lp = (struct net_local *)dev->priv;
+	int ioaddr = dev->base_addr;
+	int boguscount = 5;
+
+	while ((inb(ioaddr + RX_MODE) & 0x40) == 0) {
+		ushort status = inw(ioaddr + DATAPORT);
+
+		if (net_debug > 4)
+			printk("%s: Rxing packet mode %02x status %04x.\n",
+				   dev->name, inb(ioaddr + RX_MODE), status);
+#ifndef final_version
+		if (status == 0) {
+			outb(0x05, ioaddr + 14);
+			break;
+		}
+#endif
+
+		if ((status & 0xF0) != 0x20) {	/* There was an error. */
+			lp->stats.rx_errors++;
+			if (status & 0x08) lp->stats.rx_length_errors++;
+			if (status & 0x04) lp->stats.rx_frame_errors++;
+			if (status & 0x02) lp->stats.rx_crc_errors++;
+			if (status & 0x01) lp->stats.rx_over_errors++;
+		} else {
+			ushort pkt_len = inw(ioaddr + DATAPORT);
+			/* Malloc up new buffer. */
+			int sksize = sizeof(struct sk_buff) + pkt_len;
+			struct sk_buff *skb;
+
+			if (pkt_len > 1550) {
+				printk("%s: The AT1700 claimed a very large packet, size %d.\n",
+					   dev->name, pkt_len);
+				outb(0x05, ioaddr + 14);
+				lp->stats.rx_errors++;
+				break;
+			}
+			skb = alloc_skb(sksize, GFP_ATOMIC);
+			if (skb == NULL) {
+				printk("%s: Memory squeeze, dropping packet (len %d).\n",
+					   dev->name, pkt_len);
+				outb(0x05, ioaddr + 14);
+				lp->stats.rx_dropped++;
+				break;
+			}
+			skb->mem_len = sksize;
+			skb->mem_addr = skb;
+			skb->len = pkt_len;
+			skb->dev = dev;
+
+			/* 'skb+1' points to the start of sk_buff data area. */
+			port_read(ioaddr + DATAPORT, (void *)(skb+1), (pkt_len + 1) >> 1);
+
+			if (net_debug > 5) {
+				int i;
+				printk("%s: Rxed packet of length %d: ", dev->name, pkt_len);
+				for (i = 0; i < 14; i++)
+					printk(" %02x", ((unsigned char*)(skb + 1))[i]);
+				printk(".\n");
+			}
+
+#ifdef HAVE_NETIF_RX
+			netif_rx(skb);
+#else
+			skb->lock = 0;
+			if (dev_rint((unsigned char*)skb, pkt_len, IN_SKBUFF, dev) != 0) {
+				kfree_s(skb, sksize);
+				lp->stats.rx_dropped++;
+				break;
+			}
+#endif
+			lp->stats.rx_packets++;
+		}
+		if (--boguscount <= 0)
+			break;
+	}
+
+	/* If any worth-while packets have been received, dev_rint()
+	   has done a mark_bh(INET_BH) for us and will work on them
+	   when we get to the bottom-half routine. */
+	{
+		int i;
+		for (i = 0; i < 20; i++) {
+			if ((inb(ioaddr + RX_MODE) & 0x40) == 0x40)
+				break;
+			outb(0x05, ioaddr + 14);
+		}
+
+		if (net_debug > 5)
+			printk("%s: Exint Rx packet with mode %02x after %d ticks.\n", 
+				   dev->name, inb(ioaddr + RX_MODE), i);
+	}
+	return;
+}
+
+/* The inverse routine to net_open(). */
+static int net_close(struct device *dev)
+{
+	struct net_local *lp = (struct net_local *)dev->priv;
+	int ioaddr = dev->base_addr;
+
+	lp->open_time = 0;
+
+	dev->tbusy = 1;
+	dev->start = 0;
+
+	/* Set configuration register 0 to disable Tx and Rx. */
+	outb(0xda, ioaddr + CONFIG_0);
+
+	/* Update the statistics -- ToDo. */
+
+	/* Power-down the chip.  Green, green, green! */
+	outb(0x00, ioaddr + CONFIG_1);
+
+	return 0;
+}
+
+/* Get the current statistics.	This may be called with the card open or
+   closed. */
+static struct enet_statistics *
+net_get_stats(struct device *dev)
+{
+	struct net_local *lp = (struct net_local *)dev->priv;
+
+	cli();
+	/* ToDo: Update the statistics from the device registers. */
+	sti();
+
+	return &lp->stats;
+}
+
+#ifdef HAVE_MULTICAST
+/* Set or clear the multicast filter for this adaptor.
+   num_addrs == -1	Promiscuous mode, receive all packets
+   num_addrs == 0	Normal mode, clear multicast list
+   num_addrs > 0	Multicast mode, receive normal and MC packets, and do
+			best-effort filtering.
+ */
+static void
+set_multicast_list(struct device *dev, int num_addrs, void *addrs)
+{
+	short ioaddr = dev->base_addr;
+	if (num_addrs) {
+		outw(3, ioaddr + RX_MODE);	/* Enable promiscuous mode */
+	} else
+		outw(2, ioaddr + RX_MODE);	/* Disable promiscuous, use normal mode */
+}
+#endif
+
+/*
+ * Local variables:
+ *  compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c at1700.c"
+ *  version-control: t
+ *  kept-new-versions: 5
+ *  tab-width: 4
+ * End:
+ */
diff --git a/drivers/net/auto_irq.c b/drivers/net/auto_irq.c
index e3be4cb..6fa11e1 100644
--- a/drivers/net/auto_irq.c
+++ b/drivers/net/auto_irq.c
@@ -73,13 +73,15 @@
     irqs_used |= ~irq_handled;
 
     /* Hang out at least <waittime> jiffies waiting for bogus IRQ hits. */
-    while (timeout >= jiffies)
+    while (timeout > jiffies)
 	;
 
     for (i = 0, mask = 0x01; i < 16; i++, mask <<= 1) {
 	if (irq_bitmap & irq_handled & mask) {
 	    irq_handled &= ~mask;
+#ifdef notdef
 	    printk(" Spurious interrupt on IRQ %d\n", i);
+#endif
 	    free_irq(i);
 	}
     }
@@ -92,7 +94,7 @@
     int timeout = jiffies+waittime;
 
     /* Hang out at least <waittime> jiffies waiting for the IRQ. */
-    while (timeout >= jiffies)
+    while (timeout > jiffies)
 	if (irq_number)
 	    break;
 
diff --git a/drivers/net/eexpress.c b/drivers/net/eexpress.c
index 53c61bb..41c2480 100644
--- a/drivers/net/eexpress.c
+++ b/drivers/net/eexpress.c
@@ -19,7 +19,7 @@
 */
 
 static char *version =
-	"eexpress.c:v0.04 10/18/93 Donald Becker (becker@super.org)\n";
+	"eexpress.c:v0.06 10/27/93 Donald Becker (becker@super.org)\n";
 
 #include <linux/config.h>
 
@@ -42,7 +42,6 @@
 #include <linux/ptrace.h>
 #include <linux/ioport.h>
 #include <linux/in.h>
-#include <linux/malloc.h>
 #include <asm/system.h>
 #include <asm/bitops.h>
 #include <asm/io.h>
@@ -58,7 +57,9 @@
 
 #ifndef HAVE_ALLOC_SKB
 #define alloc_skb(size, priority) (struct sk_buff *) kmalloc(size,priority)
-#define kfree_skbmem(buff, size) kfree_s(buff,size)
+#else
+/* This isn't quite right, but it's the best version define I can find right now. */
+#include <linux/malloc.h>
 #endif
 
 /* use 0 for production, 1 for verification, 2..7 for debug */
@@ -233,7 +234,7 @@
 
   */
 
-short init_words[] = {
+static short init_words[] = {
 	0x0000,					/* Set bus size to 16 bits. */
 	0x0000,0x0000,			/* Set control mailbox (SCB) addr. */
 	0,0,					/* pad to 0x000000. */
@@ -311,7 +312,7 @@
 express_probe(struct device *dev)
 {
 	/* Don't probe all settable addresses, 0x[23][0-7]0, just common ones. */
-	int *port, ports[] = {0x300, 0x320, 0x340, 0x280, 0};
+	int *port, ports[] = {0x300, 0x270, 0x320, 0x340, 0};
 	int base_addr = dev->base_addr;
 
 	if (base_addr > 0x1ff)	/* Check a single specified location. */
@@ -364,8 +365,6 @@
 	snarf_region(ioaddr, 16);
 	dev->base_addr = ioaddr;
 
-	outb(ASIC_RESET, ioaddr + EEPROM_Ctrl);
-
 	for (i = 0; i < 6; i++) {
 		dev->dev_addr[i] = ((unsigned char*)station_addr)[5-i];
 		printk(" %02x", dev->dev_addr[i]);
@@ -388,6 +387,9 @@
 		outb(0x00, ioaddr + SET_IRQ);
 	}
 
+	/* It's now OK to leave the board in reset, pending the open(). */
+	outb(ASIC_RESET, ioaddr + EEPROM_Ctrl);
+
 	if ((dev->mem_start & 0xf) > 0)
 		net_debug = dev->mem_start & 7;
 
@@ -447,12 +449,14 @@
 
 	if (dev->irq == 0  ||  irqrmap[dev->irq] == 0)
 		return -ENXIO;
-	if (request_irq(dev->irq, &eexp_interrupt)) {
+
+	if (irq2dev_map[dev->irq] != 0
+		/* This is always true, but avoid the false IRQ. */
+		|| (irq2dev_map[dev->irq] = dev) == 0
+		|| request_irq(dev->irq, &eexp_interrupt)) {
 		return -EAGAIN;
 	}
 
-	irq2dev_map[dev->irq] = dev;
-
 	/* Initialize the 82586 memory and start it. */
 	init_82586_mem(dev);
 
@@ -964,7 +968,7 @@
 #else
 			skb->lock = 0;
 			if (dev_rint((unsigned char*)skb, pkt_len, IN_SKBUFF, dev) != 0) {
-				kfree_skbmem(skb, sksize);
+				kfree_s(skb, sksize);
 				lp->stats.rx_dropped++;
 				break;
 			}
diff --git a/drivers/net/el2.c b/drivers/net/el2.c
deleted file mode 100644
index 4ff9e31..0000000
--- a/drivers/net/el2.c
+++ /dev/null
@@ -1,443 +0,0 @@
-/* el2.c: A shared-memory NS8390 ethernet driver for linux. */
-/*
-    Written 1992,1993 by Donald Becker.
-
-    Copyright 1993 United States Government as represented by the
-    Director, National Security Agency.  This software may be used and
-    distributed according to the terms of the GNU Public License,
-    incorporated herein by reference.
-
-    This driver should work with the 3c503 and 3c503/16.  It should be used
-    in shared memory mode for best performance, although it may also work
-    in programmed-I/O mode.
-
-    The Author may be reached as becker@super.org or
-    C/O Supercomputing Research Ctr., 17100 Science Dr., Bowie MD 20715
-*/
-
-static char *version =
-    "el2.c:v0.99.13 8/30/93 Donald Becker (becker@super.org)\n";
-
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/errno.h>
-#include <asm/io.h>
-#include <asm/system.h>
-
-#include "dev.h"
-
-#include "8390.h"
-#include "el2reg.h"
-
-int el2_probe(struct device *dev);
-int el2_pio_autoprobe(struct device *dev);
-int el2probe1(int ioaddr, struct device *dev);
-
-static int el2_open(struct device *dev);
-static int el2_close(struct device *dev);
-static void el2_reset_8390(struct device *dev);
-static void el2_init_card(struct device *dev);
-static void el2_block_output(struct device *dev, int count,
-			     const unsigned char *buf, const start_page);
-static int el2_block_input(struct device *dev, int count, char *buf,
-			   int ring_offset);
-
-
-/* This routine probes for a memory-mapped 3c503 board by looking for
-   the "location register" at the end of the jumpered boot PROM space.
-   This works even if a PROM isn't there.
-
-   If the ethercard isn't found there is an optional probe for
-   ethercard jumpered to programmed-I/O mode.
-   */
-
-static int ports[] = {0x300,0x310,0x330,0x350,0x250,0x280,0x2a0,0x2e0,0};
-
-int
-el2_probe(struct device *dev)
-{
-    int *addr, addrs[] = { 0xddffe, 0xd9ffe, 0xcdffe, 0xc9ffe, 0};
-    short ioaddr = dev->base_addr;
-
-    if (ioaddr < 0)
-	return ENXIO;		/* Don't probe at all. */
-    if (ioaddr > 0)
-	return ! el2probe1(ioaddr, dev);
-
-    for (addr = addrs; *addr; addr++) {
-	int i;
-	unsigned int base_bits = *(unsigned char *)*addr;
-	/* Find first set bit. */
-	for(i = 7; i >= 0; i--, base_bits >>= 1)
-	    if (base_bits & 0x1)
-		break;
-	if (base_bits != 1)
-	    continue;
-#ifdef HAVE_PORTRESERVE
-	if (check_region(ports[i], 16))
-	    continue;
-#endif
-	if (el2probe1(ports[i], dev))
-	    return 0;
-    }
-#ifndef no_probe_nonshared_memory
-    return el2_pio_autoprobe(dev);
-#else
-    return ENODEV;
-#endif
-}
-
-/*  Try all of the locations that aren't obviously empty.  This touches
-    a lot of locations, and is much riskier than the code above. */
-int
-el2_pio_autoprobe(struct device *dev)
-{
-    int i;
-    for (i = 0; i < 8; i++) {
-#ifdef HAVE_PORTRESERVE
-	if (check_region(ports[i], 16))
-	    continue;
-#endif
-	/* Reset and/or avoid any lurking NE2000 */
-	if (inb_p(ports[i] + 0x408) == 0xff)
-	    continue;
-	if (inb(ports[i] + 0x403) == (0x80 >> i) /* Preliminary check */
-	    && el2probe1(ports[i], dev))
-	    return 0;
-    }
-    return ENODEV;
-}
-
-/* Probe for the Etherlink II card at I/O port base IOADDR,
-   returning non-zero on sucess.  If found, set the station
-   address and memory parameters in DEVICE. */
-int
-el2probe1(int ioaddr, struct device *dev)
-{
-    int i, iobase_reg, membase_reg, saved_406;
-    unsigned char *station_addr = dev->dev_addr;
-
-    /* We verify that it's a 3C503 board by checking the first three octets
-       of its ethernet address. */
-    printk("3c503 probe at %#3x:", ioaddr);
-    iobase_reg = inb(ioaddr+0x403);
-    membase_reg = inb(ioaddr+0x404);
-    /* Verify ASIC register that should be 0 or have a single bit set. */
-    if (   (iobase_reg  & (iobase_reg - 1))
-	|| (membase_reg & (membase_reg - 1))) {
-	printk("  not found.\n");
-	return 0;
-    }
-    saved_406 = inb_p(ioaddr + 0x406);
-    outb_p(ECNTRL_RESET|ECNTRL_THIN, ioaddr + 0x406); /* Reset it... */
-    outb_p(ECNTRL_THIN, ioaddr + 0x406);
-    /* Map the station addr PROM into the lower I/O ports. */
-    outb(ECNTRL_SAPROM|ECNTRL_THIN, ioaddr + 0x406);
-    for (i = 0; i < ETHER_ADDR_LEN; i++) {
-	printk(" %2.2X", (station_addr[i] = inb(ioaddr + i)));
-    }
-    if ( station_addr[0] != 0x02
-	|| station_addr[1] != 0x60
-	|| station_addr[2] != 0x8c) {
-	printk("  3C503 not found.\n");
-	/* Restore the register we frobbed. */
-	outb(saved_406, ioaddr + 0x406);
-	return 0;
-    }
-
-#ifdef HAVE_PORTRESERVE
-    snarf_region(ioaddr, 16);
-#endif
-    ethdev_init(dev);
-
-    /* Map the 8390 back into the window. */
-    outb(ECNTRL_THIN, ioaddr + 0x406);
-    dev->base_addr = ioaddr;
-    /* Probe for, turn on and clear the board's shared memory. */
-    if (ei_debug > 2) printk(" memory jumpers %2.2x ", membase_reg);
-    outb(EGACFR_NORM, ioaddr + 0x405);	/* Enable RAM */
-
-    /* This should be probed for (or set via an ioctl()) at run-time.
-       Right now we use a sleazy hack to pass in the interface number
-       at boot-time via the low bits of the mem_end field.  That value is
-       unused, and the low bits would be discarded even if it was used. */
-#if defined(EI8390_THICK) || defined(EL2_AUI)
-    ei_status.interface_num = 1;
-#else
-    ei_status.interface_num = dev->mem_end & 0xf;
-#endif
-
-    if ((membase_reg & 0xf0) == 0) {
-	dev->mem_start = 0;
-    } else {
-	dev->mem_start = ((membase_reg & 0xc0) ? 0xD8000 : 0xC8000) +
-	    ((membase_reg & 0xA0) ? 0x4000 : 0);
-
-#define EL2_MEMSIZE (EL2SM_STOP_PG - EL2SM_START_PG)*256
-#ifdef EL2MEMTEST
-	/* This has never found an error, but someone might care. */
-	{			/* Check the card's memory. */
-	    int *mem_base = (int *)dev->mem_start;
-	    int memtest_value = 0xbbadf00d;
-	    mem_base[0] = 0xba5eba5e;
-	    for (i = 1; i < EL2_MEMSIZE/sizeof(mem_base[0]); i++) {
-		mem_base[i] = memtest_value;
-		if (mem_base[0] != 0xba5eba5e
-		    || mem_base[i] != memtest_value) {
-		    printk(" memory failure or memory address conflict.\n");
-		    dev->mem_start = 0;
-		    break;
-		}
-		memtest_value += 0x55555555;
-		mem_base[i] = 0;
-	    }
-	}
-#endif  /* EL2MEMTEST */
-	/* Divide the on-board memory into a single maximum-sized transmit
-	   (double-sized for ping-pong transmit) buffer at the base, and
-	   use the rest as a receive ring. */
-	dev->mem_end = dev->rmem_end = dev->mem_start + EL2_MEMSIZE;
-	dev->rmem_start = TX_PAGES*256 + dev->mem_start;
-    }
-    if (ei_debug > 2)
-	printk("\n3c503: memory params start=%#5x rstart=%#5x end=%#5x rend=%#5x.\n",
-	       dev->mem_start, dev->rmem_start, dev->mem_end, dev->rmem_end);
-
-    /* Finish setting the board's parameters. */
-    ei_status.name = "3C503";
-    ei_status.tx_start_page = EL2SM_START_PG;
-    ei_status.rx_start_page = EL2SM_START_PG + TX_PAGES;
-    ei_status.stop_page = EL2SM_STOP_PG;
-    ei_status.reset_8390 = &el2_reset_8390;
-    ei_status.block_input = &el2_block_input;
-    ei_status.block_output = &el2_block_output;
-
-    if (dev->irq == 2)
-	dev->irq = 9;
-    else if (dev->irq > 5 && dev->irq != 9) {
-	printk("\n3c503: configured interrupt %d invalid, using autoIRQ.\n",
-	       dev->irq);
-	dev->irq = 0;
-    }
-
-    ei_status.saved_irq = dev->irq;
-
-    dev->start = 0;
-    dev->open = &el2_open;
-    dev->stop = &el2_close;
-    el2_init_card(dev);
-
-    if (dev->mem_start)
-	printk("\n%s: %s with shared memory at %#6x-%#6x,\n",
-	       dev->name, ei_status.name, dev->mem_start, dev->mem_end-1);
-    else
-	printk("\n%s: %s using programmed I/O (REJUMPER for SHARED MEMORY).\n",
-	       dev->name, ei_status.name);
-    if (ei_debug > 1)
-	printk(version);
-
-    return ioaddr;
-}
-
-static int
-el2_open(struct device *dev)
-{
-
-    if (dev->irq < 2) {
-	int irqlist[] = {5, 2, 3, 4, 0};
-	int *irqp = irqlist;
-
-	outb(EGACFR_NORM, E33G_GACFR);	/* Enable RAM and interrupts. */
-	do {
-	    if (request_irq (*irqp, NULL) != -EBUSY) {
-		/* Twinkle the interrupt, and check if it's seen. */
-		autoirq_setup(0);
-		outb_p(0x04 << *irqp, E33G_IDCFR);
-		outb_p(0x00, E33G_IDCFR);
-		if (*irqp == autoirq_report(0)	 /* It's a good IRQ line! */
-		    && request_irq (dev->irq = *irqp, &ei_interrupt) == 0)
-		    break;
-	    }
-	} while (*++irqp);
-	if (*irqp == 0) {
-	    outb(EGACFR_IRQOFF, E33G_GACFR);	/* disable interrupts. */
-	    return -EAGAIN;
-	}
-    } else {
-	if (request_irq(dev->irq, &ei_interrupt)) {
-	    return -EAGAIN;
-	}
-    }
-    return ei_open(dev);
-}
-
-static int
-el2_close(struct device *dev)
-{
-    free_irq(dev->irq);
-    dev->irq = ei_status.saved_irq;
-    irq2dev_map[dev->irq] = NULL;
-    outb(EGACFR_IRQOFF, E33G_GACFR);	/* disable interrupts. */
-
-    NS8390_init(dev, 0);
-
-    return 0;
-}
-
-/* This is called whenever we have a unrecoverable failure:
-       transmit timeout
-       Bad ring buffer packet header
- */
-static void
-el2_reset_8390(struct device *dev)
-{
-    if (ei_debug > 1) {
-	printk("%s: Resetting the 3c503 board...", dev->name);
-	printk("%#x=%#02x %#x=%#02x %#x=%#02x...", E33G_IDCFR, inb(E33G_IDCFR),
-	       E33G_CNTRL, inb(E33G_CNTRL), E33G_GACFR, inb(E33G_GACFR));
-    }
-    outb_p(ECNTRL_RESET|ECNTRL_THIN, E33G_CNTRL);
-    ei_status.txing = 0;
-    outb_p(ei_status.interface_num==0 ? ECNTRL_THIN : ECNTRL_AUI, E33G_CNTRL);
-    el2_init_card(dev);
-    if (ei_debug > 1) printk("done\n");
-}
-
-/* Initialize the 3c503 GA registers after a reset. */
-static void
-el2_init_card(struct device *dev)
-{
-    /* Unmap the station PROM and select the DIX or BNC connector. */
-    outb_p(ei_status.interface_num==0 ? ECNTRL_THIN : ECNTRL_AUI, E33G_CNTRL);
-
-    /* Set ASIC copy of rx's first and last+1 buffer pages */
-    /* These must be the same as in the 8390. */
-    outb(ei_status.rx_start_page, E33G_STARTPG);
-    outb(ei_status.stop_page,  E33G_STOPPG);
-
-    /* Point the vector pointer registers somewhere ?harmless?. */
-    outb(0xff, E33G_VP2);	/* Point at the ROM restart location 0xffff0 */
-    outb(0xff, E33G_VP1);
-    outb(0x00, E33G_VP0);
-    /* Turn off all interrupts until we're opened. */
-    outb_p(0x00,  dev->base_addr + EN0_IMR);
-    /* Enable IRQs iff started. */
-    outb(EGACFR_NORM, E33G_GACFR);
-
-    /* Set the interrupt line. */
-    outb_p((0x04 << (dev->irq == 9 ? 2 : dev->irq)), E33G_IDCFR);
-    outb_p(8, E33G_DRQCNT);		/* Set burst size to 8 */
-    outb_p(0x20, E33G_DMAAH);	/* Put a valid addr in the GA DMA */
-    outb_p(0x00, E33G_DMAAL);
-    return;			/* We always succeed */
-}
-
-/* Either use the shared memory (if enabled on the board) or put the packet
-   out through the ASIC FIFO.  The latter is probably much slower. */
-static void
-el2_block_output(struct device *dev, int count,
-		 const unsigned char *buf, const start_page)
-{
-    int i;				/* Buffer index */
-    int boguscount = 0;		/* timeout counter */
-
-    /* This should really be set with during an open(). */
-    outb(EGACFR_NORM, E33G_GACFR);	/* Enable RAM and interrupts. */
-
-    if (dev->mem_start) {	/* Shared memory transfer */
-	void *dest_addr = (void *)(dev->mem_start +
-	    ((start_page - ei_status.tx_start_page) << 8));
-	memcpy(dest_addr, buf, count);
-	if (ei_debug > 2  &&  memcmp(dest_addr, buf, count))
-	    printk("%s: 3c503 send_packet() bad memory copy @ %#5x.\n",
-		   dev->name, (int) dest_addr);
-	else if (ei_debug > 4)
-	    printk("%s: 3c503 send_packet() good memory copy @ %#5x.\n",
-		   dev->name, (int) dest_addr);
-	return;
-    }
-    /* No shared memory, put the packet out the slow way. */
-    /* Set up then start the internal memory transfer to Tx Start Page */
-    outb(0x00, E33G_DMAAL);
-    outb_p(start_page, E33G_DMAAH);
-    outb_p((ei_status.interface_num ? ECNTRL_AUI : ECNTRL_THIN ) | ECNTRL_OUTPUT
-	   | ECNTRL_START, E33G_CNTRL);
-
-    /* This is the byte copy loop: it should probably be tuned for
-       for speed once everything is working.  I think it is possible
-       to output 8 bytes between each check of the status bit. */
-    for(i = 0; i < count; i++) {
-	if (i % 8 == 0)
-	    while ((inb(E33G_STATUS) & ESTAT_DPRDY) == 0)
-		if (++boguscount > (i<<3) + 32) {
-		    printk("%s: FIFO blocked in el2_block_output (at %d of %d, bc=%d).\n",
-			   dev->name, i, count, boguscount);
-		    return;
-		}
-	outb(buf[i], E33G_FIFOH);
-    }
-    outb_p(ei_status.interface_num==0 ? ECNTRL_THIN : ECNTRL_AUI, E33G_CNTRL);
-    return;
-}
-
-/* Returns the new ring pointer. */
-static int
-el2_block_input(struct device *dev, int count, char *buf, int ring_offset)
-{
-    int boguscount = 0;
-    int end_of_ring = dev->rmem_end;
-    unsigned int i;
-
-    /* Maybe enable shared memory just be to be safe... nahh.*/
-    if (dev->mem_start) {	/* Use the shared memory. */
-	ring_offset -= (EL2SM_START_PG<<8);
-	if (dev->mem_start + ring_offset + count > end_of_ring) {
-	    /* We must wrap the input move. */
-	    int semi_count = end_of_ring - (dev->mem_start + ring_offset);
-	    if (ei_debug > 4)
-		printk("%s: 3c503 block_input() @ %#5x+%x=%5x.\n",
-		       dev->name, dev->mem_start, ring_offset,
-		       dev->mem_start + ring_offset);
-	    memcpy(buf, (char *)dev->mem_start + ring_offset, semi_count);
-	    count -= semi_count;
-	    memcpy(buf + semi_count, (char *)dev->rmem_start, count);
-	    return dev->rmem_start + count;
-	}
-	if (ei_debug > 4)
-	    printk("%s: 3c503 block_input() @ %#5x+%x=%5x.\n",
-		   dev->name, dev->mem_start, ring_offset,
-		   dev->mem_start + ring_offset);
-	memcpy(buf, (char *)dev->mem_start + ring_offset, count);
-	return ring_offset + count;
-    }
-    /* No shared memory, use programmed I/O. */
-    outb(ring_offset & 0xff, E33G_DMAAL);
-    outb_p((ring_offset >> 8) & 0xff, E33G_DMAAH);
-    outb_p((ei_status.interface_num == 0 ? ECNTRL_THIN : ECNTRL_AUI) | ECNTRL_INPUT
-	   | ECNTRL_START, E33G_CNTRL);
-
-    /* This is the byte copy loop: it should probably be tuned for
-       for speed once everything is working. */
-    for(i = 0; i < count; i++) {
-	if (i % 8 == 0)
-	    while ((inb(E33G_STATUS) & ESTAT_DPRDY) == 0)
-		if (++boguscount > (i<<3) + 32) {
-		    printk("%s: FIFO blocked in el2_block_input() (at %d of %d, bc=%d).\n",
-			   dev->name, i, count, boguscount);
-		    boguscount = 0;
-		    break;
-		}
-	buf[i] = inb_p(E33G_FIFOH);
-    }
-    outb_p(ei_status.interface_num == 0 ? ECNTRL_THIN : ECNTRL_AUI, E33G_CNTRL);
-    return 0;
-}
-
-/*
- * Local variables:
- *  compile-command: "gcc -DKERNEL -Wall -O6 -fomit-frame-pointer -I/usr/src/linux/net/tcp -c 3c503.c"
- *  version-control: t
- *  kept-new-versions: 5
- * End:
- */
diff --git a/drivers/net/el2reg.h b/drivers/net/el2reg.h
deleted file mode 100644
index a1c8575..0000000
--- a/drivers/net/el2reg.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/* Definitions for the 3Com 3c503 Etherlink 2. */
-/* This file is distributed under the GPL.
-   Some of these names and comments are from the Crynwr packet drivers. */
-
-#define EL2H (dev->base_addr + 0x400)
-#define EL2L (dev->base_addr)
-
-/* Shared memory management parameters */
-
-#define EL2SM_START_PG	(0x20)	/* First page of TX buffer */
-#define EL2SM_STOP_PG	(0x40)	/* Last page +1 of RX ring */
-
-/* 3Com 3c503 ASIC registers */
-#define E33G_STARTPG	(EL2H+0)       /* Start page, must match EN0_STARTPG */
-#define E33G_STOPPG	(EL2H+1)	/* Stop  page, must match EN0_STOPPG */
-#define E33G_DRQCNT	(EL2H+2)	/* DMA burst count */
-#define E33G_IOBASE	(EL2H+3)	/* Read of I/O base jumpers. */
-	/* (non-useful, but it also appears at the end of EPROM space) */
-#define E33G_ROMBASE	(EL2H+4)	/* Read of memory base jumpers. */
-#define E33G_GACFR	(EL2H+5)	/* Config/setup bits for the ASIC GA */
-#define E33G_CNTRL	(EL2H+6)	/* Board's main control register */
-#define E33G_STATUS	(EL2H+7)	/* Status on completions. */
-#define E33G_IDCFR	(EL2H+8)	/* Interrupt/DMA config register */
-				/* (Which IRQ to assert, DMA chan to use) */
-#define E33G_DMAAH	(EL2H+9)	/* High byte of DMA address reg */
-#define E33G_DMAAL	(EL2H+10)	/* Low byte of DMA address reg */
-/* "Vector pointer" - if this address matches a read, the EPROM (rather than
-   shared RAM) is mapped into memory space. */
-#define E33G_VP2	(EL2H+11)
-#define E33G_VP1	(EL2H+12)
-#define E33G_VP0	(EL2H+13)
-#define E33G_FIFOH	(EL2H+14)	/* FIFO for programmed I/O moves */
-#define E33G_FIFOL	(EL2H+15)	/* ... low byte of above. */
-
-/* Bits in E33G_CNTRL register: */
-
-#define ECNTRL_RESET	(0x01)	/* Software reset of the ASIC and 8390 */
-#define ECNTRL_THIN	(0x02)	/* Onboard xcvr enable, AUI disable */
-#define ECNTRL_AUI	(0x00)	/* Onboard xcvr disable, AUI enable */
-#define ECNTRL_SAPROM	(0x04)	/* Map the station address prom */
-#define ECNTRL_DBLBFR	(0x20)	/* FIFO configuration bit */
-#define ECNTRL_OUTPUT	(0x40)	/* PC-to-3C503 direction if 1 */
-#define ECNTRL_INPUT	(0x00)	/* 3C503-to-PC direction if 0 */
-#define ECNTRL_START	(0x80)	/* Start the DMA logic */
-
-/* Bits in E33G_STATUS register: */
-
-#define ESTAT_DPRDY	(0x80)	/* Data port (of FIFO) ready */
-#define ESTAT_UFLW	(0x40)	/* Tried to read FIFO when it was empty */
-#define ESTAT_OFLW	(0x20)	/* Tried to write FIFO when it was full */
-#define ESTAT_DTC	(0x10)	/* Terminal Count from PC bus DMA logic */
-#define ESTAT_DIP	(0x08)	/* DMA In Progress */
-
-/* Bits in E33G_GACFR register: */
-
-#define EGACFR_NORM	(0x49)	/* Enable 8K shared mem, no DMA TC int */
-#define EGACFR_IRQOFF	(0xc9)	/* Above, and disable 8390 IRQ line */
-
-/* End of 3C503 parameter definitions */
diff --git a/drivers/net/lance.c b/drivers/net/lance.c
index 3022808..b80ecbd 100644
--- a/drivers/net/lance.c
+++ b/drivers/net/lance.c
@@ -14,7 +14,7 @@
     C/O Supercomputing Research Ctr., 17100 Science Dr., Bowie MD 20715
 */
 
-static char *version = "lance.c:v0.13f 10/18/93 becker@super.org\n";
+static char *version = "lance.c:v0.13s 11/15/93 becker@super.org\n";
 
 #include <linux/config.h>
 #include <linux/kernel.h>
@@ -24,6 +24,7 @@
 #include <linux/errno.h>
 #include <linux/ioport.h>
 #include <linux/malloc.h>
+#include <linux/interrupt.h>
 #include <asm/bitops.h>
 #include <asm/io.h>
 #include <asm/dma.h>
@@ -34,6 +35,19 @@
 #include "skbuff.h"
 #include "arp.h"
 
+#ifndef HAVE_PORTRESERVE
+#define check_region(addr, size)	0
+#define snarf_region(addr, size)	do ; while(0)
+#endif
+
+#ifndef HAVE_ALLOC_SKB
+#define alloc_skb(size, priority) (struct sk_buff *) kmalloc(size,priority)
+#define kfree_skbmem(buff, size) kfree_s(buff,size)
+#endif
+
+struct device *init_etherdev(struct device *dev, int sizeof_private,
+			     unsigned long *mem_startp);
+
 #ifdef LANCE_DEBUG
 int lance_debug = LANCE_DEBUG;
 #else
@@ -44,21 +58,106 @@
 #define LANCE_DMA	5
 #endif
 
-/* Set the number of Tx and Rx buffers. */
-#ifndef LANCE_BUFFER_LOG_SZ
-#define RING_SIZE	16
-#define RING_MOD_MASK	0x0f
-#define RING_LEN_BITS	0x80000000
-#else
-#define RING_SIZE	(1 << (LANCE_BUFFERS_LOG_SZ))
-#define RING_MOD_MASK	(RING_SIZE - 1)
-#define RING_LEN_BITS	(LANCE_BUFFER_LOG_SZ << 13)
+/*
+  		Theory of Operation
+
+I. Board Compatibility
+
+This device driver is designed for the AMD 79C960, the "PCnet-ISA
+single-chip ethernet controller for ISA".  This chip is used in a wide
+variety of boards from vendors such as Allied Telesis, HP, Kingston,
+and Boca.  This driver is also intended to work with older AMD 7990
+designs, such as the NE1500 and NE2100.  For convenience, I use the name
+LANCE to refer to either AMD chip.
+
+II. Board-specific settings
+
+The driver is designed to work the boards that use the faster
+bus-master mode, rather than in shared memory mode.  (Only older designs
+have on-board buffer memory needed to support the slower shared memory mode.)
+
+Most boards have jumpered settings for the I/O base, IRQ line, and DMA channel.
+This driver probes the likely base addresses, {0x300, 0x320, 0x340, 0x360}.
+After the board is found it generates an DMA-timeout interrupt and uses
+autoIRQ to find the IRQ line.  The DMA channel defaults to LANCE_DMA, or it
+can be set with the low bits of the otherwise-unused dev->mem_start value.
+
+The HP-J2405A board is an exception: with this board it's easy to read the
+EEPROM-set values for the base, IRQ, and DMA.  Of course you must already
+_know_ the base address, but that entry is for changing the EEPROM.
+
+III. Driver operation
+
+IIIa. Ring buffers
+The LANCE uses ring buffers of Tx and Rx descriptors.  Each entry describes
+the base and length of the data buffer, along with status bits.  The length
+of these buffers is set by LANCE_LOG_{RX,TX}_BUFFERS, which is log_2() of
+the buffer length (rather than being directly the buffer length) for
+implementation ease.  The current values are 2 (Tx) and 4 (Rx), which leads to
+ring sizes of 4 (Tx) and 16 (Rx).  Increasing the number of ring entries
+needlessly uses extra space and reduces the chance that an upper layer will
+be able to reorder queued Tx packets based on priority.  Decreasing the number
+of entries makes it more difficult to achieve back-to-back packet transmission
+and increases the chance that Rx ring will overflow.  (Consider the worst case
+of receiving back-to-back minimum-sized packets.)
+
+The LANCE has the capability to "chain" both Rx and Tx buffers, but this driver
+statically allocates full-sized (slightly oversized -- PKT_BUF_SZ) buffers to
+avoid the administrative overhead. For the Rx side this avoids dynamically
+allocating full-sized buffers "just in case", at the expense of a
+memory-to-memory data copy for each packet received.  For most systems this
+is an good tradeoff: the Rx buffer will always be in low memory, the copy
+is inexpensive, and it primes the cache for later packet processing.  For Tx
+the buffers are only used when needed as low-memory bounce buffers.
+
+IIIB. 16M memory limitations.
+For the ISA bus master mode all structures used directly by the LANCE,
+the initialization block, Rx and Tx rings, and data buffers, must be
+accessable from the ISA bus, i.e. in the lower 16M of real memory.
+This is a problem for current Linux kernels on >16M machines. The network
+devices are initialized after memory initialization, and the kernel doles out
+memory from the top of memory downward.  The current solution is to have a
+special network initialization routine that's called before memory
+initialization; this will eventually be generalized for all network devices.
+As mentioned before, low-memory "bounce-buffers" are used when needed.
+
+IIIC. Synchronization
+The driver runs as two independent, single-threaded flows of control.  One
+is the send-packet routine, which enforces single-threaded use by the
+dev->tbusy flag.  The other thread is the interrupt handler, which is single
+threaded by the hardware and other software.
+
+The send packet thread has partial control over the Tx ring and 'dev->tbusy'
+flag.  It sets the tbusy flag whenever it's queuing a Tx packet. If the next
+queue slot is empty, it clears the tbusy flag when finished otherwise it sets
+the 'lp->tx_full' flag.
+
+The interrupt handler has exclusive control over the Rx ring and records stats
+from the Tx ring.  (The Tx-done interrupt can't be selectively turned off, so
+we can't avoid the interrupt overhead by having the Tx routine reap the Tx
+stats.)  After reaping the stats, it marks the queue entry as empty by setting
+the 'base' to zero.  Iff the 'lp->tx_full' flag is set, it clears both the
+tx_full and tbusy flags.
+
+*/
+
+/* Set the number of Tx and Rx buffers, using Log_2(# buffers).
+   Reasonable default values are 4 Tx buffers, and 16 Rx buffers.
+   That translates to 2 (4 == 2^^2) and 4 (16 == 2^^4). */
+#ifndef LANCE_LOG_TX_BUFFERS
+#define LANCE_LOG_TX_BUFFERS 2
+#define LANCE_LOG_RX_BUFFERS 4
 #endif
 
-#ifndef HAVE_ALLOC_SKB
-#define alloc_skb(size, priority) (struct sk_buff *) kmalloc(size,priority)
-#define kfree_skbmem(buff, size) kfree_s(buff,size)
-#endif
+#define TX_RING_SIZE		(1 << (LANCE_LOG_TX_BUFFERS))
+#define TX_RING_MOD_MASK	(TX_RING_SIZE - 1)
+#define TX_RING_LEN_BITS	((LANCE_LOG_TX_BUFFERS) << 29)
+
+#define RX_RING_SIZE		(1 << (LANCE_LOG_RX_BUFFERS))
+#define RX_RING_MOD_MASK	(RX_RING_SIZE - 1)
+#define RX_RING_LEN_BITS	((LANCE_LOG_RX_BUFFERS) << 29)
+
+#define PKT_BUF_SZ	1544
 
 /* Offsets from base I/O address. */
 #define LANCE_DATA 0x10
@@ -81,7 +180,7 @@
 };
 
 /* The LANCE initialization block, described in databook. */
-struct lance_init {
+struct lance_init_block {
     unsigned short mode;	/* Pre-set mode (reg. 15) */
     unsigned char phys_addr[6];	/* Physical ethernet address */
     unsigned filter[2];		/* Multicast filter (unused). */
@@ -93,10 +192,12 @@
 struct lance_private {
     char devname[8];
     /* These must aligned on 8-byte boundaries. */
-    struct lance_rx_head rx_ring[RING_SIZE];
-    struct lance_tx_head tx_ring[RING_SIZE];
-    struct lance_init	init_block;
-    long dma_buffs;		/* Address of Rx and Tx buffers. */
+    struct lance_rx_head rx_ring[RX_RING_SIZE];
+    struct lance_tx_head tx_ring[TX_RING_SIZE];
+    struct lance_init_block	init_block;
+    long rx_buffs;		/* Address of Rx and Tx buffers. */
+    /* Tx low-memory "bounce buffer" address. */
+    char (*tx_bounce_buffs)[PKT_BUF_SZ];
     int	cur_rx, cur_tx;		/* The next free ring entry */
     int dirty_rx, dirty_tx;	/* The ring entries to be free()ed. */
     int dma;
@@ -105,18 +206,7 @@
     int pad0, pad1;		/* Used for alignment */
 };
 
-/* We need a ethercard low-memory allocation scheme for for bus-master or
-   DMA ethercards if they are to work >16M memory systems. This is a
-   temporary solution to the lack of one, but it limits us to a single
-   AT1500 and <16M. Bummer. */
-
-#define PKT_BUF_SZ	1544
-
-#ifndef MEM_START_ALLOC
-static char rx_buffs[PKT_BUF_SZ][RING_SIZE];
-#endif
-
-static int lance_probe1(struct device *dev, short ioaddr);
+static unsigned long lance_probe1(short ioaddr, unsigned long mem_start);
 static int lance_open(struct device *dev);
 static void lance_init_ring(struct device *dev);
 static int lance_start_xmit(struct sk_buff *skb, struct device *dev);
@@ -130,41 +220,27 @@
 
 
 
-int at1500_probe(struct device *dev)
+unsigned long lance_init(unsigned long mem_start, unsigned long mem_end)
 {
     int *port, ports[] = {0x300, 0x320, 0x340, 0x360, 0};
-    int base_addr = dev->base_addr;
 
-    if (base_addr > 0x1ff)		/* Check a single specified location. */
-		return lance_probe1(dev, base_addr);
-    else if (base_addr > 0)		/* Don't probe at all. */
-		return ENXIO;
-
-    /* First probe for the ethercard ID, 0x57, and then look for a LANCE
-       chip. */
-    
+    printk("lance_init(%#x, %#x).\n", mem_start, mem_end);
     for (port = &ports[0]; *port; port++) {
 	int ioaddr = *port;
 
-#ifdef HAVE_PORTRESERVE
-	if (check_region(ioaddr, LANCE_TOTAL_SIZE))
-	    continue;
-#endif
-	if (inb(ioaddr + 14) != 0x57
-	    || inb(ioaddr + 15) != 0x57)
-	    continue;
-
-	if (lance_probe1(dev, ioaddr) == 0)
-	    return 0;
+	if (   check_region(ioaddr, LANCE_TOTAL_SIZE) == 0
+	    && inb(ioaddr + 14) == 0x57
+	    && inb(ioaddr + 15) == 0x57) {
+	    mem_start = lance_probe1(ioaddr, mem_start);
+	}
     }
 
-    dev->base_addr = base_addr;
-    return ENODEV;			/* ENODEV would be more accurate. */
+    return mem_start;
 }
 
-static int
-lance_probe1(struct device *dev, short ioaddr)
+static unsigned long lance_probe1(short ioaddr, unsigned long mem_start)
 {
+    struct device *dev;
     struct lance_private *lp;
     int hpJ2405A = 0;
     int i, reset_val;
@@ -182,7 +258,11 @@
 
     outw(0x0000, ioaddr+LANCE_ADDR); /* Switch to window 0 */
     if (inw(ioaddr+LANCE_DATA) != 0x0004)
-	return ENXIO;
+	return mem_start;
+
+    dev = init_etherdev(0, sizeof(struct lance_private)
+			+ PKT_BUF_SZ*(RX_RING_SIZE + TX_RING_SIZE),
+			&mem_start);
 
     printk("%s: LANCE at %#3x,", dev->name, ioaddr);
 
@@ -192,43 +272,27 @@
 	printk(" %2.2x", dev->dev_addr[i] = inb(ioaddr + i));
 
     dev->base_addr = ioaddr;
-#ifdef HAVE_PORTRESERVE
     snarf_region(ioaddr, LANCE_TOTAL_SIZE);
-#endif
 
-    /* Make up a LANCE-specific-data structure. */
-#ifdef MEM_START_ALLOC
-    dev->priv = (void *)((mem_start + 7) & ~7);
-    mem_start += (long)dev->priv + sizeof(struct lance_private);
+    /* Make certain the data structures used by the LANCE are aligned. */
+    dev->priv = (void *)(((int)dev->priv + 7) & ~7);
     lp = (struct lance_private *)dev->priv;
-    lp->dma_buffs = mem_start;
-    mem_start += PKT_BUF_SZ * RING_SIZE;
-#else    
-    dev->priv = kmalloc(sizeof(struct lance_private), GFP_KERNEL);
-    /* Align on 8-byte boundary. */
-    dev->priv = (void *)(((int)dev->priv + 7) & ~0x07);
-
-    if ((int)dev->priv & 0xff000000  ||  (int) rx_buffs & 0xff000000) {
-	printk(" disabled (buff %#x > 16M).\n", (int)rx_buffs);
-	return -ENOMEM;
-    }
-    memset(dev->priv, 0, sizeof(struct lance_private));
-    lp = (struct lance_private *)dev->priv;
-    lp->dma_buffs = (long)rx_buffs;
-#endif
+    lp->rx_buffs = (long)dev->priv + sizeof(struct lance_private);
+    lp->tx_bounce_buffs = (char (*)[PKT_BUF_SZ])
+			   (lp->rx_buffs + PKT_BUF_SZ*RX_RING_SIZE);
 
 #ifndef final_version
     /* This should never happen. */
     if ((int)(lp->rx_ring) & 0x07) {
 	printk(" **ERROR** LANCE Rx and Tx rings not on even boundary.\n");
-	return -ENXIO;
+	return mem_start;
     }
 #endif
 
     outw(88, ioaddr+LANCE_ADDR);
     lp->old_lance = (inw(ioaddr+LANCE_DATA) != 0x3003);
 
-#ifdef notdef
+#if defined(notdef)
     printk(lp->old_lance ? " original LANCE (%04x)" : " PCnet-ISA LANCE (%04x)",
 	   inw(ioaddr+LANCE_DATA));
 #endif
@@ -238,8 +302,8 @@
 	lp->init_block.phys_addr[i] = dev->dev_addr[i];
     lp->init_block.filter[0] = 0x00000000;
     lp->init_block.filter[1] = 0x00000000;
-    lp->init_block.rx_ring = (int)lp->rx_ring | RING_LEN_BITS;
-    lp->init_block.tx_ring = (int)lp->tx_ring | RING_LEN_BITS;
+    lp->init_block.rx_ring = (int)lp->rx_ring | RX_RING_LEN_BITS;
+    lp->init_block.tx_ring = (int)lp->tx_ring | TX_RING_LEN_BITS;
 
     outw(0x0001, ioaddr+LANCE_ADDR);
     outw((short) (int) &lp->init_block, ioaddr+LANCE_DATA);
@@ -256,11 +320,15 @@
 	printk(" HP J2405A IRQ %d DMA %d.\n", dev->irq, dev->dma);
     } else {
 	/* The DMA channel may be passed in on this parameter. */
-	dev->dma = dev->mem_start & 0x07;
+	if (dev->mem_start & 0x07)
+	    dev->dma = dev->mem_start & 0x07;
+	else if (dev->dma == 0)
+	    dev->dma = LANCE_DMA;
 
 	/* To auto-IRQ we enable the initialization-done and DMA err,
 	   interrupts. For now we will always get a DMA error. */
 	if (dev->irq < 2) {
+
 	    autoirq_setup(0);
 
 	    /* Trigger an initialization just for the interrupt. */
@@ -271,7 +339,7 @@
 		printk(", probed IRQ %d, fixed at DMA %d.\n", dev->irq, dev->dma);
 	    else {
 		printk(", failed to detect IRQ line.\n");
-		return -EAGAIN;
+		return mem_start;
 	    }
 	} else
 	    printk(" assigned IRQ %d DMA %d.\n", dev->irq, dev->dma);
@@ -296,35 +364,7 @@
     dev->set_multicast_list = &set_multicast_list;
 #endif
 
-    dev->mem_start = 0;
-
-    /* Fill in the generic field of the device structure. */
-    for (i = 0; i < DEV_NUMBUFFS; i++)
-	dev->buffs[i] = NULL;
-
-    dev->hard_header	= eth_header;
-    dev->add_arp	= eth_add_arp;
-    dev->queue_xmit	= dev_queue_xmit;
-    dev->rebuild_header	= eth_rebuild_header;
-    dev->type_trans	= eth_type_trans;
-
-    dev->type		= ARPHRD_ETHER;
-    dev->hard_header_len = ETH_HLEN;
-    dev->mtu		= 1500; /* eth_mtu */
-    dev->addr_len	= ETH_ALEN;
-    for (i = 0; i < dev->addr_len; i++) {
-	dev->broadcast[i]=0xff;
-    }
-
-    /* New-style flags. */
-    dev->flags		= IFF_BROADCAST;
-    dev->family		= AF_INET;
-    dev->pa_addr	= 0;
-    dev->pa_brdaddr	= 0;
-    dev->pa_mask	= 0;
-    dev->pa_alen	= sizeof(unsigned long);
-
-    return 0;
+    return mem_start;
 }
 
 
@@ -339,9 +379,7 @@
 	return -EAGAIN;
     }
 
-    lp->dma = dev->dma ? dev->dma : LANCE_DMA;
-
-    if (request_dma(lp->dma)) {
+    if (request_dma(dev->dma)) {
 	free_irq(dev->irq);
 	return -EAGAIN;
     }
@@ -351,8 +389,8 @@
     inw(ioaddr+LANCE_RESET);
 
     /* The DMA controller is used as a no-operation slave, "cascade mode". */
-    enable_dma(lp->dma);
-    set_dma_mode(lp->dma, DMA_MODE_CASCADE);
+    enable_dma(dev->dma);
+    set_dma_mode(dev->dma, DMA_MODE_CASCADE);
 
     /* Un-Reset the LANCE, needed only for the NE2100. */
     if (lp->old_lance)
@@ -366,7 +404,7 @@
 
     if (lance_debug > 1)
 	printk("%s: lance_open() irq %d dma %d tx/rx rings %#x/%#x init %#x.\n",
-	       dev->name, dev->irq, lp->dma, (int) lp->tx_ring, (int) lp->rx_ring,
+	       dev->name, dev->irq, dev->dma, (int) lp->tx_ring, (int) lp->rx_ring,
 	       (int) &lp->init_block);
 
     lance_init_ring(dev);
@@ -408,9 +446,13 @@
     lp->cur_rx = lp->cur_tx = 0;
     lp->dirty_rx = lp->dirty_tx = 0;
 
-    for (i = 0; i < RING_SIZE; i++) {
-	lp->rx_ring[i].base = (lp->dma_buffs + i*PKT_BUF_SZ) | 0x80000000;
+    for (i = 0; i < RX_RING_SIZE; i++) {
+	lp->rx_ring[i].base = (lp->rx_buffs + i*PKT_BUF_SZ) | 0x80000000;
 	lp->rx_ring[i].buf_length = -PKT_BUF_SZ;
+    }
+    /* The Tx buffer address is filled in as needed, but we do need to clear
+       the upper ownership bit. */
+    for (i = 0; i < TX_RING_SIZE; i++) {
 	lp->tx_ring[i].base = 0;
     }
 
@@ -419,8 +461,8 @@
 	lp->init_block.phys_addr[i] = dev->dev_addr[i];
     lp->init_block.filter[0] = 0x00000000;
     lp->init_block.filter[1] = 0x00000000;
-    lp->init_block.rx_ring = (int)lp->rx_ring | RING_LEN_BITS;
-    lp->init_block.tx_ring = (int)lp->tx_ring | RING_LEN_BITS;
+    lp->init_block.rx_ring = (int)lp->rx_ring | RX_RING_LEN_BITS;
+    lp->init_block.tx_ring = (int)lp->tx_ring | TX_RING_LEN_BITS;
 }
 
 static int
@@ -428,18 +470,36 @@
 {
     struct lance_private *lp = (struct lance_private *)dev->priv;
     int ioaddr = dev->base_addr;
+    int entry;
 
     /* Transmitter timeout, serious problems. */
     if (dev->tbusy) {
 	int tickssofar = jiffies - dev->trans_start;
-	if (tickssofar < 5)
+	if (tickssofar < 10)
 	    return 1;
 	outw(0, ioaddr+LANCE_ADDR);
 	printk("%s: transmit timed out, status %4.4x, resetting.\n",
 	       dev->name, inw(ioaddr+LANCE_DATA));
-
+	outw(0x0001, ioaddr+LANCE_DATA);
+	lp->stats.tx_errors++;
+#ifndef final_version
+	{
+	    int i;
+	    printk(" Ring data dump: dirty_tx %d cur_tx %d cur_rx %d.",
+		   lp->dirty_tx, lp->cur_tx, lp->cur_rx);
+	    for (i = 0 ; i < RX_RING_SIZE; i++)
+		printk("%s %08x %04x %04x", i & 0x3 ? "" : "\n ",
+		       lp->rx_ring[i].base, -lp->rx_ring[i].buf_length,
+		       lp->rx_ring[i].msg_length);
+	    for (i = 0 ; i < TX_RING_SIZE; i++)
+		printk(" %s%08x %04x %04x", i & 0x3 ? "" : "\n ",
+		       lp->tx_ring[i].base, -lp->tx_ring[i].length,
+		       lp->tx_ring[i].misc);
+	    printk("\n");
+	}
+#endif
 	lance_init_ring(dev);
-	outw(0x43, ioaddr+LANCE_DATA);
+	outw(0x0043, ioaddr+LANCE_DATA);
 
 	dev->tbusy=0;
 	dev->trans_start = jiffies;
@@ -475,49 +535,47 @@
     if (set_bit(0, (void*)&dev->tbusy) != 0)
 	printk("%s: Transmitter access conflict.\n", dev->name);
 
-    /* This code is broken for >16M RAM systems.
-       There are two ways to fix it:
-           Keep around several static low-memory buffers, and deal with
-	   the book-keeping (bad for small systems).
-	   Make static Tx buffers that are optionally used.
-	   (Even worse.)
-     */
-    {				/* Fill in a Tx ring entry */
-	int entry = lp->cur_tx++;
+    /* Fill in a Tx ring entry */
 
-	entry &= RING_MOD_MASK;		/* Ring buffer. */
-	/* Caution: the write order is important here. */
-	lp->tx_ring[entry].length = -skb->len;
+    /* Mask to ring buffer boundary. */
+    entry = lp->cur_tx & TX_RING_MOD_MASK;
 
-	/* This shouldn't be necessary... */
+    /* Caution: the write order is important here, set the base address
+       with the "ownership" bits last. */
+
+    /* The old LANCE chips doesn't automatically pad buffers to min. size. */
+    if (lp->old_lance) {
 	lp->tx_ring[entry].length =
 	    -(ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN);
+    } else
+	lp->tx_ring[entry].length = -skb->len;
 
-	lp->tx_ring[entry].misc = 0x0000;
+    lp->tx_ring[entry].misc = 0x0000;
+
+    /* If any part of this buffer is >16M we must copy it to a low-memory
+       buffer. */
+    if ((int)(skb+1) + skb->len > 0x01000000) {
+	if (lance_debug > 5)
+	    printk("%s: bouncing a high-memory packet (%#x).\n",
+		   dev->name, (int)(skb+1));
+	memcpy(&lp->tx_bounce_buffs[entry], skb+1, skb->len);
+	lp->tx_ring[entry].base =
+	    (int)(lp->tx_bounce_buffs + entry) | 0x83000000;
+	if (skb->free)
+	    kfree_skb (skb, FREE_WRITE);
+    } else
 	lp->tx_ring[entry].base = (int)(skb+1) | 0x83000000;
 
-	/* Trigger an immediate send poll. */
-	outw(0x0000, ioaddr+LANCE_ADDR);
-	outw(0x0048, ioaddr+LANCE_DATA);
+    lp->cur_tx++;
 
-	if (lance_debug > 4) {
-	    unsigned char *pkt =
-		(unsigned char *)(lp->tx_ring[entry].base & 0x00ffffff);
+    /* Trigger an immediate send poll. */
+    outw(0x0000, ioaddr+LANCE_ADDR);
+    outw(0x0048, ioaddr+LANCE_DATA);
 
-	    printk("%s: tx ring[%d], %#x, sk_buf %#x len %d.\n",
-		   dev->name, entry, (int) &lp->tx_ring[entry],
-		   lp->tx_ring[entry].base, -lp->tx_ring[entry].length);
-	    printk("%s:  Tx %2.2x %2.2x %2.2x ... %2.2x  %2.2x %2.2x %2.2x...%2.2x len %2.2x %2.2x  %2.2x %2.2x.\n",
-		   dev->name, pkt[0], pkt[1], pkt[2], pkt[5], pkt[6],
-		   pkt[7], pkt[8], pkt[11], pkt[12], pkt[13],
-		   pkt[14], pkt[15]);
-	}
+    dev->trans_start = jiffies;
 
-	dev->trans_start = jiffies;
-
-	if (lp->tx_ring[(entry+1) & RING_MOD_MASK].base >= 0)
-	    dev->tbusy=0;
-    }
+    if (lp->tx_ring[(entry+1) & TX_RING_MOD_MASK].base == 0)
+	dev->tbusy=0;
 
     return 0;
 }
@@ -557,41 +615,65 @@
 	lance_rx(dev);
 
     if (csr0 & 0x0200) {	/* Tx-done interrupt */
-	int dirty_tx = lp->dirty_tx & RING_MOD_MASK;
+	int dirty_tx = lp->dirty_tx;
 
-	if (lance_debug > 5)
-	    printk("%s: Cleaning tx ring, dirty %d clean %d.\n",
-		   dev->name, dirty_tx, (lp->cur_tx & RING_MOD_MASK));
+	if (dirty_tx == lp->cur_tx - TX_RING_SIZE
+	    && dev->tbusy) {
+	    /* The ring is full, clear tbusy. */
+	    dev->tbusy = 0;
+	    mark_bh(INET_BH);
+	}
 
-	/* This code is broken for >16M RAM systems. */
-	while (dirty_tx != (lp->cur_tx & RING_MOD_MASK)
-	       && lp->tx_ring[dirty_tx].base > 0) {
-	    struct sk_buff *skb =
-		(struct sk_buff *)(lp->tx_ring[dirty_tx].base & 0x00ffffff);
-	    unsigned short *tmdp = (unsigned short *)(&lp->tx_ring[dirty_tx]);
-	    int status = lp->tx_ring[dirty_tx].base >> 24;
+	while (dirty_tx < lp->cur_tx) {
+	    int entry = dirty_tx & TX_RING_MOD_MASK;
+	    int status = lp->tx_ring[entry].base;
+	    void *databuff;
+	    
+	    if (status < 0)
+		break;		/* It still hasn't been Txed */
 
-	    if (status & 0x40) { /* There was an major error, log it. */
-		int err_status = lp->tx_ring[dirty_tx].misc;
+	    lp->tx_ring[entry].base = 0;
+	    databuff = (void*)(status & 0x00ffffff);
+
+	    if (status & 0x40000000) { /* There was an major error, log it. */
+		int err_status = lp->tx_ring[entry].misc;
 		lp->stats.tx_errors++;
 		if (err_status & 0x0400) lp->stats.tx_aborted_errors++;
 		if (err_status & 0x0800) lp->stats.tx_carrier_errors++;
 		if (err_status & 0x1000) lp->stats.tx_window_errors++;
 		if (err_status & 0x4000) lp->stats.tx_fifo_errors++;
 		/* We should re-init() after the FIFO error. */
-	    } else if (status & 0x18)
+	    } else if (status & 0x18000000)
 		lp->stats.collisions++;
 	    else
 		lp->stats.tx_packets++;
-	    if (lance_debug > 5)
-		printk("%s: Tx done entry %d, %4.4x %4.4x %4.4x %4.4x.\n",
-		       dev->name, dirty_tx,
-		       tmdp[0], tmdp[1], tmdp[2], tmdp[3]);
-	    if ((skb-1)->free)
-		kfree_skb (skb-1, FREE_WRITE);
-	    dirty_tx = ++lp->dirty_tx & RING_MOD_MASK;
+
+	    /* We don't free the skb if it's a data-only copy in the bounce
+	       buffer.  The address checks here are sorted -- the first test
+	       should always works.  */
+	    if (databuff >= (void*)(&lp->tx_bounce_buffs[TX_RING_SIZE])
+		|| databuff < (void*)(lp->tx_bounce_buffs)) {
+		struct sk_buff *skb = ((struct sk_buff *)databuff) - 1;
+		if (skb->free)
+		    kfree_skb(skb, FREE_WRITE);
+	    }
+	    dirty_tx++;
 	}
-	/* mark_bh(INET_BH); */
+
+	lp->dirty_tx = dirty_tx;
+
+#ifndef final_version
+	if (lp->cur_tx - dirty_tx >= TX_RING_SIZE) {
+	    printk("out-of-sync dirty pointer, %d vs. %d.\n",
+		   dirty_tx, lp->cur_tx);
+	    lp->dirty_tx += TX_RING_SIZE;
+	}
+#endif
+    }
+
+    if (csr0 & 0x8000) {
+	if (csr0 & 0x4000) lp->stats.tx_errors++;
+	if (csr0 & 0x1000) lp->stats.rx_errors++;
     }
 
     /* Clear the interrupts we've handled. */
@@ -611,7 +693,7 @@
 lance_rx(struct device *dev)
 {
     struct lance_private *lp = (struct lance_private *)dev->priv;
-    int entry = lp->cur_rx & RING_MOD_MASK;
+    int entry = lp->cur_rx & RX_RING_MOD_MASK;
 	
     /* If we own the next entry, it's a new packet. Send it up. */
     while (lp->rx_ring[entry].base >= 0) {
@@ -656,14 +738,12 @@
 	}
 
 	lp->rx_ring[entry].base |= 0x80000000;
-	entry = (entry+1) & RING_MOD_MASK;
+	entry = (++lp->cur_rx) & RX_RING_MOD_MASK;
     }
 
     /* We should check that at least two ring entries are free.  If not,
        we should free one and mark stats->rx_dropped++. */
 
-    lp->cur_rx = entry;
-
     return 0;
 }
 
@@ -689,10 +769,10 @@
        memory if we don't. */
     outw(0x0004, ioaddr+LANCE_DATA);
 
-    disable_dma(lp->dma);
+    disable_dma(dev->dma);
 
     free_irq(dev->irq);
-    free_dma(lp->dma);
+    free_dma(dev->dma);
 
     irq2dev_map[dev->irq] = 0;
 
diff --git a/drivers/net/ne.c b/drivers/net/ne.c
index 86cfec2..95d4231 100644
--- a/drivers/net/ne.c
+++ b/drivers/net/ne.c
@@ -17,7 +17,7 @@
 /* Routines for the NatSemi-based designs (NE[12]000). */
 
 static char *version =
-    "ne.c:v0.99-13 8/30/93 Donald Becker (becker@super.org)\n";
+    "ne.c:v0.99-13s 11/17/93 Donald Becker (becker@super.org)\n";
 
 #include <linux/config.h>
 #include <linux/kernel.h>
@@ -132,7 +132,7 @@
        We can't reliably read the SAPROM address without this.
        (I learned the hard way!). */
     {
-	struct {char value, offset; } program_seq[] = {
+	struct {unsigned char value, offset; } program_seq[] = {
 	    {E8390_NODMA+E8390_PAGE0+E8390_STOP, E8390_CMD}, /* Select page 0*/
 	    {0x48,	EN0_DCFG},	/* Set byte-wide (0x48) access. */
 	    {0x00,	EN0_RCNTLO},	/* Clear the count regs. */
@@ -141,7 +141,7 @@
 	    {0xFF,	EN0_ISR},
 	    {E8390_RXOFF, EN0_RXCR},	/* 0x20  Set to monitor */
 	    {E8390_TXOFF, EN0_TXCR},	/* 0x02  and loopback mode. */
-    	    {32,		EN0_RCNTLO},
+	    {32,	EN0_RCNTLO},
 	    {0x00,	EN0_RCNTHI},
 	    {0x00,	EN0_RSARLO},	/* DMA starting at 0x0000. */
 	    {0x00,	EN0_RSARHI},
@@ -190,7 +190,7 @@
 	    start_page = NESM_START_PG;
 	    stop_page = NESM_STOP_PG;
 	} else {
-	    name = dlink ? "DE100" : "D-Link";
+	    name = dlink ? "DE100" : "NE1000";
 	    start_page = NE1SM_START_PG;
 	    stop_page = NE1SM_STOP_PG;
 	}
diff --git a/drivers/net/net_init.c b/drivers/net/net_init.c
new file mode 100644
index 0000000..4c15147
--- /dev/null
+++ b/drivers/net/net_init.c
@@ -0,0 +1,163 @@
+/* netdrv_init.c: Initialization for network devices. */
+/*
+	Written 1993 by Donald Becker.
+	Copyright 1993 United States Government as represented by the Director,
+	National Security Agency.  This software may only be used and distributed
+	according to the terms of the GNU Public License as modified by SRC,
+	incorported herein by reference.
+
+	The author may be reached as becker@super.org or
+	C/O Supercomputing Research Ctr., 17100 Science Dr., Bowie MD 20715
+
+	This file contains the initialization for the "pl14+" style ethernet
+	drivers.  It should eventually replace most of drivers/net/Space.c.
+	It's primary advantage is that it's able to allocate low-memory buffers.
+	A secondary advantage is that the dangerous NE*000 netcards can reserve
+	their I/O port region before the SCSI probes start.
+*/
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/malloc.h>
+#include <linux/if_ether.h>
+#include <memory.h>
+#include "dev.h"
+#include "eth.h"
+
+/* The network devices currently exist only in the socket namespace, so these
+   entries are unused.  The only ones that make sense are
+    open	start the ethercard
+    close	stop  the ethercard
+    ioctl	To get statistics, perhaps set the interface port (AUI, BNC, etc.)
+   One can also imagine getting raw packets using
+    read & write
+   but this is probably better handled by a raw packet socket.
+
+   Given that almost all of these functions are handled in the current
+   socket-based scheme, putting ethercard devices in /dev/ seems pointless.
+*/
+
+/* The next device number/name to assign: "eth0", "eth1", etc. */
+static int next_ethdev_number = 0;
+
+#ifdef NET_MAJOR_NUM
+static struct file_operations netcard_fops = {
+	NULL,		/* lseek */
+	NULL,		/* read */
+	NULL,		/* write */
+	NULL,		/* readdir */
+	NULL,		/* select */
+	NULL,		/* ioctl */
+	NULL,		/* mmap */
+	NULL,		/* open */
+	NULL,		/* release */
+	NULL		/* fsync */
+};
+#endif
+
+unsigned long lance_init(unsigned long mem_start, unsigned long mem_end);
+
+/*
+  net_dev_init() is our network device initialization routine.
+  It's called from init/main.c with the start and end of free memory,
+  and returns the new start of free memory.
+  */
+
+unsigned long net_dev_init (unsigned long mem_start, unsigned long mem_end)
+{
+
+#ifdef NET_MAJOR_NUM
+	if (register_chrdev(NET_MAJOR_NUM, "network",&netcard_fops))
+		printk("WARNING: Unable to get major %d for the network devices.\n",
+			   NET_MAJOR_NUM);
+#endif
+
+#if defined(CONFIG_LANCE)			/* Note this is _not_ CONFIG_AT1500. */
+	mem_start = lance_init(mem_start, mem_end);
+#endif
+
+	return mem_start;
+}
+
+/* Fill in the fields of the device structure with ethernet-generic values.
+
+   If no device structure is passed, a new one is constructed, complete with
+   a SIZEOF_PRIVATE private data area.
+
+   If an empty string area is passed as dev->name, or a new structure is made,
+   a new name string is constructed.  The passed string area should be 8 bytes
+   long.
+ */
+
+struct device *init_etherdev(struct device *dev, int sizeof_private,
+							 unsigned long *mem_startp)
+{
+	int i;
+	int new_device = 0;
+
+	if (dev == NULL) {
+		int alloc_size = sizeof(struct device) + sizeof("eth%d ")
+			+ sizeof_private;
+		if (mem_startp && *mem_startp ) {
+			dev = (struct device *)*mem_startp;
+			*mem_startp += alloc_size;
+		} else
+			dev = (struct device *)kmalloc(alloc_size, GFP_KERNEL);
+		memset(dev, 0, sizeof(alloc_size));
+		dev->name = (char *)(dev + 1);
+		if (sizeof_private)
+			dev->priv = dev->name + sizeof("eth%d ");
+		new_device = 1;
+	}
+
+	if (dev->name  &&  dev->name[0] == '\0')
+		sprintf(dev->name, "eth%d", next_ethdev_number++);
+
+	for (i = 0; i < DEV_NUMBUFFS; i++)
+		dev->buffs[i] = NULL;
+	
+	dev->hard_header	= eth_header;
+	dev->add_arp		= eth_add_arp;
+	dev->queue_xmit		= dev_queue_xmit;
+	dev->rebuild_header	= eth_rebuild_header;
+	dev->type_trans		= eth_type_trans;
+	
+	dev->type			= ARPHRD_ETHER;
+	dev->hard_header_len = ETH_HLEN;
+	dev->mtu			= 1500; /* eth_mtu */
+	dev->addr_len		= ETH_ALEN;
+	for (i = 0; i < ETH_ALEN; i++) {
+		dev->broadcast[i]=0xff;
+	}
+	
+	/* New-style flags. */
+	dev->flags			= IFF_BROADCAST;
+	dev->family			= AF_INET;
+	dev->pa_addr		= 0;
+	dev->pa_brdaddr		= 0;
+	dev->pa_mask		= 0;
+	dev->pa_alen		= sizeof(unsigned long);
+	
+	if (new_device) {
+		/* Append the device to the device queue. */
+		struct device **old_devp = &dev_base;
+		while ((*old_devp)->next)
+			old_devp = & (*old_devp)->next;
+		(*old_devp)->next = dev;
+		dev->next = 0;
+	}
+	return dev;
+}
+
+
+/*
+ * Local variables:
+ *  compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c net_init.c"
+ *  version-control: t
+ *  kept-new-versions: 5
+ *  tab-width: 4
+ * End:
+ */
diff --git a/drivers/net/skeleton.c b/drivers/net/skeleton.c
index b6440d8..48d64a8 100644
--- a/drivers/net/skeleton.c
+++ b/drivers/net/skeleton.c
@@ -4,7 +4,7 @@
 	Copyright 1993 United States Government as represented by the Director,
 	National Security Agency.  This software may only be used and distributed
 	according to the terms of the GNU Public License as modified by SRC,
-	incorported herein by reference.
+	incorporated herein by reference.
 
 	The author may be reached as becker@super.org or
 	C/O Supercomputing Research Ctr., 17100 Science Dr., Bowie MD 20715
@@ -19,7 +19,7 @@
 */
 
 static char *version =
-	"skeleton.c:v0.04 10/17/93 Donald Becker (becker@super.org)\n";
+	"skeleton.c:v0.05 11/16/93 Donald Becker (becker@super.org)\n";
 
 /* Always include 'config.h' first in case the user wants to turn on
    or override something. */
@@ -49,12 +49,12 @@
 #include <linux/ioport.h>
 #include <linux/in.h>
 #include <linux/malloc.h>
+#include <linux/string.h>
 #include <asm/system.h>
 #include <asm/bitops.h>
 #include <asm/io.h>
 #include <asm/dma.h>
 #include <errno.h>
-#include <memory.h>
 
 #include "dev.h"
 #include "iow.h"
@@ -73,7 +73,12 @@
 
 #ifndef HAVE_ALLOC_SKB
 #define alloc_skb(size, priority) (struct sk_buff *) kmalloc(size,priority)
-#define kfree_skbmem(buff, size) kfree_s(buff, size);
+#define kfree_skbmem(addr, size) kfree_s(addr,size);
+#endif
+
+#ifndef HAVE_PORTRESERVE
+#define check_region(ioaddr, size) 		0
+#define	snarf_region(ioaddr, size);		do ; while (0)
 #endif
 
 /* use 0 for production, 1 for verification, >2 for debug */
@@ -88,6 +93,14 @@
 	long open_time;				/* Useless example local info. */
 };
 
+/* The number of low I/O ports used by the ethercard. */
+#define ETHERCARD_TOTAL_SIZE	16
+
+/* The station (ethernet) address prefix, used for IDing the board. */
+#define SA_ADDR0 0x00
+#define SA_ADDR1 0x42
+#define SA_ADDR2 0x65
+
 /* Index to functions, as function prototypes. */
 
 extern int netcard_probe(struct device *dev);
@@ -128,10 +141,8 @@
 
 	for (port = &ports[0]; *port; port++) {
 		int ioaddr = *port;
-#ifdef HAVE_PORTRESERVE
-		if (check_region(ioaddr, 1 /* ETHERCARD_TOTAL_SIZE */))
+		if (check_region(ioaddr, ETHERCARD_TOTAL_SIZE))
 			continue;
-#endif
 		if (inb(ioaddr) != 0x57)
 			continue;
 		dev->base_addr = ioaddr;
@@ -140,7 +151,7 @@
 	}
 
 	dev->base_addr = base_addr;
-	return ENODEV;			/* ENODEV would be more accurate. */
+	return ENODEV;
 }
 
 int netcard_probe1(struct device *dev, short ioaddr)
@@ -153,7 +164,8 @@
 		station_addr[i] = inb(ioaddr + i);
 	}
 	/* Check the first three octets of the S.A. for the manufactor's code. */ 
-	if (station_addr[0] != 0x42	 ||	 station_addr[1] != 0x42 || station_addr[2] != 0x42) {
+	if (station_addr[0] != SA_ADDR0
+		||	 station_addr[1] != SA_ADDR1 || station_addr[2] != SA_ADDR2) {
 		return ENODEV;
 	}
 
@@ -188,10 +200,8 @@
 	 }
 #endif	/* jumpered interrupt */
 
-#ifdef HAVE_PORTRESERVE
 	/* Grab the region so we can find another board if autoIRQ fails. */
-	snarf_region(ioaddr, 16);
-#endif
+	snarf_region(ioaddr, ETHERCARD_TOTAL_SIZE);
 
 	if (net_debug)
 		printk(version);
@@ -219,21 +229,21 @@
 	dev->rebuild_header	= eth_rebuild_header;
 	dev->type_trans		= eth_type_trans;
 
-	dev->type		= ARPHRD_ETHER;
+	dev->type			= ARPHRD_ETHER;
 	dev->hard_header_len = ETH_HLEN;
-	dev->mtu		= 1500; /* eth_mtu */
-	dev->addr_len	= ETH_ALEN;
+	dev->mtu			= 1500; /* eth_mtu */
+	dev->addr_len		= ETH_ALEN;
 	for (i = 0; i < ETH_ALEN; i++) {
 		dev->broadcast[i]=0xff;
 	}
 
 	/* New-style flags. */
-	dev->flags		= IFF_BROADCAST;
-	dev->family		= AF_INET;
-	dev->pa_addr	= 0;
-	dev->pa_brdaddr	= 0;
-	dev->pa_mask	= 0;
-	dev->pa_alen	= sizeof(unsigned long);
+	dev->flags			= IFF_BROADCAST;
+	dev->family			= AF_INET;
+	dev->pa_addr		= 0;
+	dev->pa_brdaddr		= 0;
+	dev->pa_mask		= 0;
+	dev->pa_alen		= sizeof(unsigned long);
 
 	return 0;
 }
@@ -422,7 +432,7 @@
 #else
 			skb->lock = 0;
 			if (dev_rint((unsigned char*)skb, pkt_len, IN_SKBUFF, dev) != 0) {
-				kfree_skbmem(skb, sksize);
+				kfree_s(skb, sksize);
 				lp->stats.rx_dropped++;
 				break;
 			}
diff --git a/drivers/net/slip.c b/drivers/net/slip.c
index 85a14ad..0c3720f 100644
--- a/drivers/net/slip.c
+++ b/drivers/net/slip.c
@@ -14,6 +14,9 @@
  *		Alan Cox	: 	Found cause of overrun. ifconfig sl0 mtu upwards.
  *					Driver now spots this and grows/shrinks its buffers(hack!).
  *					Memory leak if you run out of memory setting up a slip driver fixed.
+ *		Matt Dillon	:	Printable slip (borrowed from NET2E)
+ *	Pauline Middelink	:	Slip driver fixes.
+ *		Alan Cox	:	Honours the old SL_COMPRESSED flag
  */
 #include <asm/segment.h>
 #include <asm/system.h>
@@ -77,7 +80,7 @@
 
   ip = (struct iphdr *) ptr;
   th = (struct tcphdr *) (ptr + ip->ihl * 4);
-  printk("\r%s -> %s seq %x ack %x len %d\n",
+  printk("\r%s -> %s seq %lx ack %lx len %d\n",
 	 in_ntoa(ip->saddr), in_ntoa(ip->daddr), 
 	 ntohl(th->seq), ntohl(th->ack_seq), ntohs(ip->tot_len));
   return;
@@ -125,6 +128,12 @@
   sl->inuse		= 0;
   sl->sending		= 0;
   sl->escape		= 0;
+  sl->flags		= 0;
+#ifdef SL_COMPRESSED
+  sl->mode		= SL_MODE_CSLIP;	/* Default */
+#else
+  sl->mode		= SL_MODE_SLIP;		/* Default for non compressors */
+#endif  
 
   sl->line		= dev->base_addr;
   sl->tty		= NULL;
@@ -180,6 +189,7 @@
 		return(sl);
 	}
   }
+  restore_flags(flags);
   return(NULL);
 }
 
@@ -335,7 +345,7 @@
   int count;
 
   count = sl->rcount;
-  if (1) {
+  if (sl->mode & SL_MODE_CSLIP) {
     if ((c = sl->rbuff[0]) & SL_TYPE_COMPRESSED_TCP) {
       /* make sure we've reserved enough space for uncompress to use */
       save_flags(flags);
@@ -397,7 +407,6 @@
 sl_encaps(struct slip *sl, unsigned char *icp, int len)
 {
   unsigned char *bp, *p;
-  unsigned char c;
   int count;
 
   DPRINTF((DBG_SLIP, "SLIP: sl_encaps(0x%X, %d) called\n", icp, len));
@@ -408,17 +417,17 @@
   if(sl->mtu != sl->dev->mtu)	/* Someone has been ifconfigging */
   	sl_changedmtu(sl);
   
-  if(len>=sl->mtu)		/* Sigh, shouldn't occur BUT ... */
+  if(len>sl->mtu)		/* Sigh, shouldn't occur BUT ... */
   {
-  	len=sl->mtu-1;
+  	len=sl->mtu;
   	printk("slip: truncating oversized transmit packet!\n");
   }
 
   p = icp;
-#ifdef SL_COMPRESSED
-  len = slhc_compress(sl->slcomp, p, len, sl->cbuff, &p, 1);
-#endif
-  
+  if(sl->mode & SL_MODE_CSLIP)
+	  len = slhc_compress(sl->slcomp, p, len, sl->cbuff, &p, 1);
+
+#ifdef OLD  
   /*
    * Send an initial END character to flush out any
    * data that may have accumulated in the receiver
@@ -450,8 +459,14 @@
 			count++;
 	}
   }
-  *bp++ = END;
+  *bp++ = END;  
   count++;
+#else
+  if(sl->mode & SL_MODE_SLIP6)
+  	count=slip_esc6(p, (unsigned char *)sl->xbuff,len);
+  else
+  	count=slip_esc(p, (unsigned char *)sl->xbuff,len);
+#endif  	  
   sl->spacket++;
   bp = sl->xbuff;
 
@@ -640,10 +655,10 @@
 slip_recv(struct tty_struct *tty)
 {
   unsigned char buff[128];
-  unsigned char *p, c;
+  unsigned char *p;
   struct slip *sl;
-  int count;
-
+  int count, error=0;
+  
   DPRINTF((DBG_SLIP, "SLIP: slip_recv(%d) called\n", tty->line));
   if ((sl = sl_find(tty)) == NULL) return;	/* not connected */
 
@@ -653,9 +668,15 @@
   /* Suck the bytes out of the TTY queues. */
   do {
 	count = tty_read_raw_data(tty, buff, 128);
-	if (count <= 0) break;
-
+	if (count <= 0)
+	{
+		count= - count;
+		if(count)
+			error=1;
+		break;
+	}
 	p = buff;
+#ifdef OLD	
 	while (count--) {
 		c = *p++;
 		if (sl->escape) {
@@ -676,7 +697,14 @@
 			} else	sl_enqueue(sl, c);
 		}
 	}
+#else
+	if(sl->mode & SL_MODE_SLIP6)
+		slip_unesc6(sl,buff,count,error);
+	else
+		slip_unesc(sl,buff,count,error);
+#endif		
   } while(1);
+  
 }
 
 
@@ -741,12 +769,181 @@
 					tty->line, sl->dev->name));
 }
 
+ 
+ /************************************************************************
+  *			STANDARD SLIP ENCAPSULATION			*
+  ************************************************************************
+  *
+  */
+ 
+ int
+ slip_esc(unsigned char *s, unsigned char *d, int len)
+ {
+     int count = 0;
+ 
+     /*
+      * Send an initial END character to flush out any
+      * data that may have accumulated in the receiver
+      * due to line noise.
+      */
+ 
+     d[count++] = END;
+ 
+     /*
+      * For each byte in the packet, send the appropriate
+      * character sequence, according to the SLIP protocol.
+      */
+ 
+     while(len-- > 0) {
+     	switch(*s) {
+     	case END:
+     	    d[count++] = ESC;
+     	    d[count++] = ESC_END;
+ 	    break;
+ 	case ESC:
+     	    d[count++] = ESC;
+     	    d[count++] = ESC_ESC;
+ 	    break;
+ 	default:
+ 	    d[count++] = *s;
+ 	}
+ 	++s;
+     }
+     d[count++] = END;
+     return(count);
+ }
+ 
+ void
+ slip_unesc(struct slip *sl, unsigned char *s, int count, int error)
+ {
+     int i;
+ 
+     for (i = 0; i < count; ++i, ++s) {
+ 	switch(*s) {
+ 	case ESC:
+ 	    sl->flags |= SLF_ESCAPE;
+ 	    break;
+ 	case ESC_ESC:
+ 	    if (sl->flags & SLF_ESCAPE)
+ 	    	sl_enqueue(sl, ESC);
+ 	    else
+ 	        sl_enqueue(sl, *s);
+	    sl->flags &= ~SLF_ESCAPE;
+ 	    break;
+	case ESC_END:
+ 	    if (sl->flags & SLF_ESCAPE)
+	    	sl_enqueue(sl, END);
+	    else
+ 	        sl_enqueue(sl, *s);
+	    sl->flags &= ~SLF_ESCAPE;
+	    break;
+	case END:
+ 	    if (sl->rcount > 2) 
+ 	    	sl_bump(sl);
+ 	    sl_dequeue(sl, sl->rcount);
+ 	    sl->rcount = 0;
+ 	    sl->flags &= ~(SLF_ESCAPE | SLF_ERROR);
+ 	    break;
+ 	default:
+ 	    sl_enqueue(sl, *s);
+ 	    sl->flags &= ~SLF_ESCAPE;
+ 	}
+     }
+     if (error)
+     	sl->flags |= SLF_ERROR;
+ }
+ 
+ /************************************************************************
+  *			 6 BIT SLIP ENCAPSULATION			*
+  ************************************************************************
+  *
+  */
+ 
+ int
+ slip_esc6(unsigned char *s, unsigned char *d, int len)
+ {
+     int count = 0;
+     int i;
+     unsigned short v = 0;
+     short bits = 0;
+ 
+     /*
+      * Send an initial END character to flush out any
+      * data that may have accumulated in the receiver
+      * due to line noise.
+      */
+ 
+     d[count++] = 0x70;
+ 
+     /*
+      * Encode the packet into printable ascii characters
+      */
+ 
+     for (i = 0; i < len; ++i) {
+     	v = (v << 8) | s[i];
+     	bits += 8;
+     	while (bits >= 6) {
+     	    unsigned char c;
+ 
+     	    bits -= 6;
+     	    c = 0x30 + ((v >> bits) & 0x3F);
+     	    d[count++] = c;
+ 	}
+     }
+     if (bits) {
+     	unsigned char c;
+ 
+     	c = 0x30 + ((v << (6 - bits)) & 0x3F);
+     	d[count++] = c;
+     }
+     d[count++] = 0x70;
+     return(count);
+ }
+ 
+ void
+ slip_unesc6(struct slip *sl, unsigned char *s, int count, int error)
+ {
+     int i;
+     unsigned char c;
+ 
+     for (i = 0; i < count; ++i, ++s) {
+     	if (*s == 0x70) {
+ 	    if (sl->rcount > 8) {	/* XXX must be 2 for compressed slip */
+ #ifdef NOTDEF
+ 	        printk("rbuff %02x %02x %02x %02x\n",
+ 	            sl->rbuff[0],
+ 	            sl->rbuff[1],
+ 	            sl->rbuff[2],
+ 	            sl->rbuff[3]
+ 	        );
+ #endif
+ 	    	sl_bump(sl);
+ 	    }
+ 	    sl_dequeue(sl, sl->rcount);
+ 	    sl->rcount = 0;
+ 	    sl->flags &= ~(SLF_ESCAPE | SLF_ERROR); /* SLF_ESCAPE not used */
+ 	    sl->xbits = 0;
+ 	} else if (*s >= 0x30 && *s < 0x70) {
+ 	    sl->xdata = (sl->xdata << 6) | ((*s - 0x30) & 0x3F);
+ 	    sl->xbits += 6;
+ 	    if (sl->xbits >= 8) {
+ 	    	sl->xbits -= 8;
+ 	    	c = (unsigned char)(sl->xdata >> sl->xbits);
+ 		sl_enqueue(sl, c);
+ 	    }
+ 
+ 	}
+     }
+     if (error)
+     	sl->flags |= SLF_ERROR;
+ }
 
 /* Perform I/O control on an active SLIP channel. */
 static int
 slip_ioctl(struct tty_struct *tty, void *file, int cmd, void *arg)
 {
   struct slip *sl;
+  int err;
 
   /* First make sure we're connected. */
   if ((sl = sl_find(tty)) == NULL) {
@@ -757,9 +954,19 @@
   DPRINTF((DBG_SLIP, "SLIP: ioctl(%d, 0x%X, 0x%X)\n", tty->line, cmd, arg));
   switch(cmd) {
 	case SIOCGIFNAME:
-		verify_area(VERIFY_WRITE, arg, 16);
+		err=verify_area(VERIFY_WRITE, arg, 16);
+		if(err)
+			return -err;
 		memcpy_tofs(arg, sl->dev->name, strlen(sl->dev->name) + 1);
 		return(0);
+	case SIOCGIFENCAP:
+		err=verify_area(VERIFY_WRITE,arg,sizeof(long));
+		put_fs_long(sl->mode,(long *)arg);
+		return(0);
+	case SIOCSIFENCAP:
+		err=verify_area(VERIFY_READ,arg,sizeof(long));
+		sl->mode=get_fs_long((long *)arg);
+		return(0);
 	default:
 		return(-EINVAL);
   }
diff --git a/drivers/net/slip.h b/drivers/net/slip.h
index cd81d60..6c779ab 100644
--- a/drivers/net/slip.h
+++ b/drivers/net/slip.h
@@ -8,6 +8,7 @@
  *
  * Fixes:
  *		Alan Cox	: 	Added slip mtu field.
+ *		Matt Dillon	:	Printable slip (borrowed from net2e)
  *
  * Author:	Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
  */
@@ -56,10 +57,25 @@
   unsigned long		errors;		/* error count			*/
   
   int			mtu;		/* Our mtu (to spot changes!)   */
+  unsigned char		flags;		/* Flag values/ mode etc	*/
+#define SLF_ESCAPE	2
+#define SLF_ERROR	4
+#define SLF_COMP	16
+#define SLF_EXPN	32
+  unsigned char		mode;		/* SLIP mode			*/
+#define SL_MODE_SLIP	0
+#define SL_MODE_CSLIP	1
+#define SL_MODE_SLIP6	2		/* Matt Dillon's printable slip */
+#define SL_MODE_CSLIP6	(SL_MODE_SLIP|SL_MODE_CSLIP)
+  int			xdata,xbits;	/* 6 bit slip controls 		*/
 };
 
 
 extern int	slip_init(struct device *dev);
+extern int	slip_esc(unsigned char *s, unsigned char *d, int len);
+extern int	slip_esc6(unsigned char *s, unsigned char *d, int len);
+extern void	slip_unesc(struct slip *sl, unsigned char *s, int count, int error);
+extern void 	slip_unesc6(struct slip *sl, unsigned char *s, int count, int error);
 
 
 #endif	/* _LINUX_SLIP.H */
diff --git a/drivers/net/smc-ultra.c b/drivers/net/smc-ultra.c
index 2947f96..726e1c8 100644
--- a/drivers/net/smc-ultra.c
+++ b/drivers/net/smc-ultra.c
@@ -14,19 +14,25 @@
 */
 
 static char *version =
-    "smc-ultra.c:v0.02 10/8/93 Donald Becker (becker@super.org)\n";
+    "smc-ultra.c:v0.03 11/21/93 Donald Becker (becker@super.org)\n";
 
 #include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/errno.h>
+#include <linux/string.h>
 #include <asm/io.h>
 #include <asm/system.h>
-#include <memory.h>
 
 #include "dev.h"
 #include "8390.h"
 
+/* Compatibility definitions for earlier kernel versions. */
+#ifndef HAVE_PORTRESERVE
+#define check_region(ioaddr, size)              0
+#define snarf_region(ioaddr, size);             do ; while (0)
+#endif
+
 int ultraprobe(int ioaddr, struct device *dev);
 int ultraprobe1(int ioaddr, struct device *dev);
 
@@ -53,19 +59,17 @@
 
 int ultra_probe(struct device *dev)
 {
-    int *port, ports[] = {0x300, 0x280, 0x380, 0x240, 0};
-    short ioaddr = dev->base_addr;
+    int *port, ports[] = {0x200, 0x220, 0x240, 0x280, 0x300, 0x380, 0};
+    unsigned short ioaddr = dev->base_addr;
 
-    if (ioaddr < 0)
-	return ENXIO;		/* Don't probe at all. */
-    if (ioaddr > 0x100)
+    if (ioaddr > 0x1ff)
 	return ! ultraprobe1(ioaddr, dev);
+    else if (ioaddr > 0)
+	return ENXIO;		/* Don't probe at all. */
 
     for (port = &ports[0]; *port; port++) {
-#ifdef HAVE_PORTRESERVE
 	if (check_region(*port, 32))
 	    continue;
-#endif
 	if ((inb(*port + 7) & 0xF0) == 0x20
 	    && ultraprobe1(*port, dev) == 0)
 	    return 0;
@@ -81,7 +85,14 @@
   int checksum = 0;
   char *model_name;
   int num_pages;
+  unsigned char reg1, eeprom_irq = 0;
 
+  /* Second probe check: at most one bit can be set in register 1. */
+  reg1 = inb(ioaddr + 1);
+  if (reg1 & (reg1 - 1))
+      return ENODEV;
+
+  /* Select the station address register set. */
   outb(0x7f & inb(ioaddr + 4), ioaddr + 4);
 
   for (i = 0; i < 8; i++)
@@ -93,37 +104,30 @@
   for (i = 0; i < 6; i++)
       printk(" %2.2X", station_addr[i] = inb(ioaddr + 8 + i));
 
+  /* Switch from the station address to the alternate register set. */
   outb(0x80 | inb(ioaddr + 4), ioaddr + 4);
 
   model_name = "SMC Ultra";
 
   if (dev->irq < 2) {
+      unsigned char irqmap[] = {0, 9, 3, 5, 7, 10, 11, 15};
+      int irqreg = inb(ioaddr + 0xd);
       int irq;
-      /* Datasheet doesn't specify the IRQ line mapping -> always autoIRQ. */
 
-      outb(0x05, ioaddr + 6);
-      autoirq_setup(0);
+      /* The IRQ bits are split. */
+      irq = irqmap[((irqreg & 0x40) >> 4) + ((irqreg & 0x0c) >> 2)];
 
-      /* Trigger an interrupt, then release. */
-      outb_p(0x09, ioaddr + 6);
-      outb(0x00, ioaddr + 6);
-
-      irq = autoirq_report(1);
-      if (irq)
-	  printk(", using IRQ %d", irq);
-      else {
+      if (irq == 0) {
 	  printk(", failed to detect IRQ line.\n");
 	  return -EAGAIN;
       }
       dev->irq = irq;
-  } else
-      printk(" assigned IRQ %d.\n", dev->irq);
+      eeprom_irq = 1;
+  }
 
 
   /* OK, were are certain this is going to work.  Setup the device. */
-#ifdef HAVE_PORTRESERVE
   snarf_region(ioaddr, 32);
-#endif
 
   /* The 8390 isn't at the base address, so fake the offset */
   dev->base_addr = ioaddr+ULTRA_NIC_OFFSET;
@@ -149,7 +153,8 @@
   dev->mem_end = dev->rmem_end
       = dev->mem_start + (ei_status.stop_page - START_PG)*256;
 
-  printk(", shared memory at %#x-%#x.\n", dev->mem_start, dev->mem_end-1);
+  printk(",%s IRQ %d memory %#x-%#x.\n", eeprom_irq ? "" : "assigned ",
+	 dev->irq, dev->mem_start, dev->mem_end-1);
   if (ei_debug > 0)
       printk(version);
 
diff --git a/drivers/net/wd.c b/drivers/net/wd.c
index ea1244e..f88ec98 100644
--- a/drivers/net/wd.c
+++ b/drivers/net/wd.c
@@ -1,236 +1,254 @@
 /* wd.c: A WD80x3 ethernet driver for linux. */
 /*
-    Written 1993 by Donald Becker.
-    Copyright 1993 United States Government as represented by the
-    Director, National Security Agency.  This software may be used and
-    distributed according to the terms of the GNU Public License,
-    incorporated herein by reference.
-    
-    This is a driver for WD8003 and WD8013 "compatible" ethercards.
+	Written 1993 by Donald Becker.
+	Copyright 1993 United States Government as represented by the
+	Director, National Security Agency.	 This software may be used and
+	distributed according to the terms of the GNU Public License,
+	incorporated herein by reference.
+	
+	This is a driver for WD8003 and WD8013 "compatible" ethercards.
 
-    The Author may be reached as becker@super.org or
-    C/O Supercomputing Research Ctr., 17100 Science Dr., Bowie MD 20715
+	The Author may be reached as becker@super.org or
+	C/O Supercomputing Research Ctr., 17100 Science Dr., Bowie MD 20715
 
-    Thanks to Russ Nelson (nelson@crnwyr.com) for loaning me a WD8013.
+	Thanks to Russ Nelson (nelson@crnwyr.com) for loaning me a WD8013.
 */
 
 static char *version =
-    "wd.c:v0.99-14 10/13/93 Donald Becker (becker@super.org)\n";
+	"wd.c:v0.99-14 11/21/93 Donald Becker (becker@super.org)\n";
 
 #include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/errno.h>
+#include <linux/string.h>
 #include <asm/io.h>
 #include <asm/system.h>
-#include <memory.h>
 
 #include "dev.h"
 #include "8390.h"
 
-int wdprobe(int ioaddr, struct device *dev);
+/* Compatibility definitions for earlier kernel versions. */
+#ifndef HAVE_PORTRESERVE
+#define check_region(ioaddr, size)              0
+#define snarf_region(ioaddr, size);             do ; while (0)
+#endif
+
+int wd_probe(struct device *dev);
 int wdprobe1(int ioaddr, struct device *dev);
 
 static int wd_open(struct device *dev);
 static void wd_reset_8390(struct device *dev);
 static int wd_block_input(struct device *dev, int count,
-			  char *buf, int ring_offset);
+						  char *buf, int ring_offset);
 static void wd_block_output(struct device *dev, int count,
-			    const unsigned char *buf, const start_page);
+							const unsigned char *buf, const start_page);
 static int wd_close_card(struct device *dev);
 
 
-#define WD_START_PG	0x00	/* First page of TX buffer */
+#define WD_START_PG		0x00	/* First page of TX buffer */
 #define WD03_STOP_PG	0x20	/* Last page +1 of RX ring */
 #define WD13_STOP_PG	0x40	/* Last page +1 of RX ring */
 
-#define WD_CMDREG	0	/* Offset to ASIC command register. */
-#define  WD_RESET	0x80	/* Board reset, in WD_CMDREG. */
-#define  WD_MEMENB	0x40	/* Enable the shared memory. */
-#define WD_CMDREG5	5	/* Offset to 16-bit-only ASIC register 5. */
-#define  ISA16		0x80	/* Enable 16 bit access from the ISA bus. */
-#define  NIC16		0x40	/* Enable 16 bit access from the 8390. */
-#define WD_NIC_OFFSET	16	/* Offset to the 8390 NIC from the base_addr. */
+#define WD_CMDREG		0		/* Offset to ASIC command register. */
+#define	 WD_RESET		0x80	/* Board reset, in WD_CMDREG. */
+#define	 WD_MEMENB		0x40	/* Enable the shared memory. */
+#define WD_CMDREG5		5		/* Offset to 16-bit-only ASIC register 5. */
+#define	 ISA16			0x80	/* Enable 16 bit access from the ISA bus. */
+#define	 NIC16			0x40	/* Enable 16 bit access from the 8390. */
+#define WD_NIC_OFFSET	16		/* Offset to the 8390 NIC from the base_addr. */
 
-/*  Probe for the WD8003 and WD8013.  These cards have the station
-    address PROM at I/O ports <base>+8 to <base>+13, with a checksum
-    following. A Soundblaster can have the same checksum as an WDethercard,
-    so we have an extra exclusionary check for it.
+/*	Probe for the WD8003 and WD8013.  These cards have the station
+	address PROM at I/O ports <base>+8 to <base>+13, with a checksum
+	following. A Soundblaster can have the same checksum as an WDethercard,
+	so we have an extra exclusionary check for it.
 
-    The wdprobe1() routine initializes the card and fills the
-    station address field. */
+	The wdprobe1() routine initializes the card and fills the
+	station address field. */
 
 int wd_probe(struct device *dev)
 {
-    int *port, ports[] = {0x300, 0x280, 0x380, 0x240, 0};
-    short ioaddr = dev->base_addr;
+	int *port, ports[] = {0x300, 0x280, 0x380, 0x240, 0};
+	short ioaddr = dev->base_addr;
 
-    if (ioaddr < 0)
-	return ENXIO;		/* Don't probe at all. */
-    if (ioaddr > 0x100)
-	return ! wdprobe1(ioaddr, dev);
+	if (ioaddr < 0)
+		return ENXIO;			/* Don't probe at all. */
+	if (ioaddr > 0x100)
+		return ! wdprobe1(ioaddr, dev);
 
-    for (port = &ports[0]; *port; port++) {
-#ifdef HAVE_PORTRESERVE
-	if (check_region(*port, 32))
-	    continue;
-#endif
-	if (inb(*port + 8) != 0xff
-	    && inb(*port + 9) != 0xff /* Extra check to avoid soundcard. */
-	    && wdprobe1(*port, dev))
-	    return 0;
-    }
-    dev->base_addr = ioaddr;
-    return ENODEV;
+	for (port = &ports[0]; *port; port++) {
+		if (check_region(*port, 32))
+			continue;
+		if (inb(*port + 8) != 0xff
+			&& inb(*port + 9) != 0xff /* Extra check to avoid soundcard. */
+			&& wdprobe1(*port, dev))
+			return 0;
+	}
+	dev->base_addr = ioaddr;
+	return ENODEV;
 }
 
 int wdprobe1(int ioaddr, struct device *dev)
 {
-  int i;
-  unsigned char *station_addr = dev->dev_addr;
-  int checksum = 0;
-  int ancient = 0;		/* An old card without config registers. */
-  int word16 = 0;		/* 0 = 8 bit, 1 = 16 bit */
-  char *model_name;
-
-  for (i = 0; i < 8; i++)
-      checksum += inb(ioaddr + 8 + i);
-  if ((checksum & 0xff) != 0xFF)
-      return 0;
-  
-  printk("%s: WD80x3 at %#3x, ", dev->name, ioaddr);
-  for (i = 0; i < 6; i++)
-      printk(" %2.2X", station_addr[i] = inb(ioaddr + 8 + i));
-
-  /* The following PureData probe code was contributed by
-     Mike Jagdis <jaggy@purplet.demon.co.uk>. Puredata does software
-     configuration differently from others so we have to check for them.
-     This detects an 8 bit, 16 bit or dumb (Toshiba, jumpered) card.
-     */
-  if (inb(ioaddr+0) == 'P' && inb(ioaddr+1) == 'D') {
-      unsigned char reg5 = inb(ioaddr+5);
-
-      switch (inb(ioaddr+2)) {
-      case 0x03: word16 = 0; model_name = "PDI8023-8";  break;
-      case 0x05: word16 = 0; model_name = "PDUC8023";   break;
-      case 0x0a: word16 = 1; model_name = "PDI8023-16"; break;
-	  /* Either 0x01 (dumb) or they've released a new version. */
-      default:   word16 = 0; model_name = "PDI8023";    break;
-      }
-      dev->mem_start = ((reg5 & 0x1c) + 0xc0) << 12;
-      dev->irq = (reg5 & 0xe0) == 0xe0 ? 10 : (reg5 >> 5) + 1;
-  } else {				/* End of PureData probe */
-      /* This method of checking for a 16-bit board is borrowed from the
-	 we.c driver.  A simpler method is just to look in ASIC reg. 0x03.
-	 I'm comparing the two method in alpha test to make certain they
-	 return the same result. */
-      /* Check for the old 8 bit board - it has register 0/8 aliasing.
-	 Do NOT check i>=6 here -- it hangs the old 8003 boards! */
-      for (i = 0; i < 6; i++)
-	  if (inb(ioaddr+i) != inb(ioaddr+8+i))
-	      break;
-      if (i >= 6) {
-	  ancient = 1;
-	  model_name = "WD8003-old";
-	  word16 = 0;
-      } else {
-	  int tmp = inb(ioaddr+1); /* fiddle with 16bit bit */
-	  outb( tmp ^ 0x01, ioaddr+1 ); /* attempt to clear 16bit bit */
-	  if (((inb( ioaddr+1) & 0x01) == 0x01) /* A 16 bit card */
-	      && (tmp & 0x01) == 0x01   ) {		/* In a 16 slot. */
-	      int asic_reg5 = inb(ioaddr+WD_CMDREG5);
-	      /* Magic to set ASIC to word-wide mode. */
-	      outb( NIC16 | (asic_reg5&0x1f), ioaddr+WD_CMDREG5);
-	      outb(tmp, ioaddr+1);
-	      model_name = "WD8013";
-	      word16 = 1; 	/* We have a 16bit board here! */
-	  } else {
-	      model_name = "WD8003";
-	      word16 = 0;
-	  }
-	  outb(tmp, ioaddr+1);		/* Restore original reg1 value. */
-      }
+	int i;
+	unsigned char *station_addr = dev->dev_addr;
+	int checksum = 0;
+	int ancient = 0;			/* An old card without config registers. */
+	int word16 = 0;				/* 0 = 8 bit, 1 = 16 bit */
+	char *model_name;
+	
+	for (i = 0; i < 8; i++)
+		checksum += inb(ioaddr + 8 + i);
+	if ((checksum & 0xff) != 0xFF)
+		return 0;
+	
+	printk("%s: WD80x3 at %#3x, ", dev->name, ioaddr);
+	for (i = 0; i < 6; i++)
+		printk(" %2.2X", station_addr[i] = inb(ioaddr + 8 + i));
+	
+	/* The following PureData probe code was contributed by
+	   Mike Jagdis <jaggy@purplet.demon.co.uk>. Puredata does software
+	   configuration differently from others so we have to check for them.
+	   This detects an 8 bit, 16 bit or dumb (Toshiba, jumpered) card.
+	   */
+	if (inb(ioaddr+0) == 'P' && inb(ioaddr+1) == 'D') {
+		unsigned char reg5 = inb(ioaddr+5);
+		
+		switch (inb(ioaddr+2)) {
+		case 0x03: word16 = 0; model_name = "PDI8023-8";	break;
+		case 0x05: word16 = 0; model_name = "PDUC8023";	break;
+		case 0x0a: word16 = 1; model_name = "PDI8023-16"; break;
+			/* Either 0x01 (dumb) or they've released a new version. */
+		default:	 word16 = 0; model_name = "PDI8023";	break;
+		}
+		dev->mem_start = ((reg5 & 0x1c) + 0xc0) << 12;
+		dev->irq = (reg5 & 0xe0) == 0xe0 ? 10 : (reg5 >> 5) + 1;
+	} else {								/* End of PureData probe */
+		/* This method of checking for a 16-bit board is borrowed from the
+		   we.c driver.  A simpler method is just to look in ASIC reg. 0x03.
+		   I'm comparing the two method in alpha test to make certain they
+		   return the same result. */
+		/* Check for the old 8 bit board - it has register 0/8 aliasing.
+		   Do NOT check i>=6 here -- it hangs the old 8003 boards! */
+		for (i = 0; i < 6; i++)
+			if (inb(ioaddr+i) != inb(ioaddr+8+i))
+				break;
+		if (i >= 6) {
+			ancient = 1;
+			model_name = "WD8003-old";
+			word16 = 0;
+		} else {
+			int tmp = inb(ioaddr+1); /* fiddle with 16bit bit */
+			outb( tmp ^ 0x01, ioaddr+1 ); /* attempt to clear 16bit bit */
+			if (((inb( ioaddr+1) & 0x01) == 0x01) /* A 16 bit card */
+				&& (tmp & 0x01) == 0x01	) {				/* In a 16 slot. */
+				int asic_reg5 = inb(ioaddr+WD_CMDREG5);
+				/* Magic to set ASIC to word-wide mode. */
+				outb( NIC16 | (asic_reg5&0x1f), ioaddr+WD_CMDREG5);
+				outb(tmp, ioaddr+1);
+				model_name = "WD8013";
+				word16 = 1;		/* We have a 16bit board here! */
+			} else {
+				model_name = "WD8003";
+				word16 = 0;
+			}
+			outb(tmp, ioaddr+1);			/* Restore original reg1 value. */
+		}
 #ifndef final_version
-      if ( !ancient && (inb(ioaddr+1) & 0x01) != (word16 & 0x01))
-	  printk("\nWD80?3: Bus width conflict, %d (probe) != %d (reg report).",
-		 word16 ? 16 : 8, (inb(ioaddr+1) & 0x01) ? 16 : 8);
+		if ( !ancient && (inb(ioaddr+1) & 0x01) != (word16 & 0x01))
+			printk("\nWD80?3: Bus width conflict, %d (probe) != %d (reg report).",
+				   word16 ? 16 : 8, (inb(ioaddr+1) & 0x01) ? 16 : 8);
 #endif
-  }
-
+	}
+	
 #if defined(WD_SHMEM) && WD_SHMEM > 0x80000
-  /* Allow a compile-time override.  */
-  dev->mem_start = WD_SHMEM;
+	/* Allow a compile-time override.	 */
+	dev->mem_start = WD_SHMEM;
 #else
-  if (dev->mem_start == 0) {
-      /* Sanity and old 8003 check */
-      int reg0 = inb(ioaddr);
-      if (reg0 == 0xff || reg0 == 0) {
-	  /* Future plan: this could check a few likely locations first. */
-	  dev->mem_start = 0xd0000;
-	  printk(" assigning address %#x", dev->mem_start);
-      } else {
-	  int high_addr_bits = inb(ioaddr+WD_CMDREG5) & 0x1f;
-	  /* Some boards don't have the register 5 -- it returns 0xff. */
-	  if (high_addr_bits == 0x1f || word16 == 0)
-	      high_addr_bits = 0x01;
-	  dev->mem_start = ((reg0&0x3f) << 13) + (high_addr_bits << 19);
-      }
-  }
+	if (dev->mem_start == 0) {
+		/* Sanity and old 8003 check */
+		int reg0 = inb(ioaddr);
+		if (reg0 == 0xff || reg0 == 0) {
+			/* Future plan: this could check a few likely locations first. */
+			dev->mem_start = 0xd0000;
+			printk(" assigning address %#lx", dev->mem_start);
+		} else {
+			int high_addr_bits = inb(ioaddr+WD_CMDREG5) & 0x1f;
+			/* Some boards don't have the register 5 -- it returns 0xff. */
+			if (high_addr_bits == 0x1f || word16 == 0)
+				high_addr_bits = 0x01;
+			dev->mem_start = ((reg0&0x3f) << 13) + (high_addr_bits << 19);
+		}
+	}
 #endif
-
-  /* The 8390 isn't at the base address -- the ASIC regs are there! */
-  dev->base_addr = ioaddr+WD_NIC_OFFSET;
-
-  if (dev->irq < 2) {
-      int irqmap[] = {9,3,5,7,10,11,15,4};
-      int reg1 = inb(ioaddr+1);
-      int reg4 = inb(ioaddr+4);
-      if (ancient || reg1 == 0xff)	/* Ack!! No way to read the IRQ! */
-	  dev->irq = word16 ? 10 : 5;
-      else
-	  dev->irq = irqmap[((reg4 >> 5) & 0x03) + (reg1 & 0x04)];
-  } else if (dev->irq == 2)	/* Fixup bogosity: IRQ2 is really IRQ9 */
-      dev->irq = 9;
-
-  /* Snarf the interrupt now.  There's no point in waiting since we cannot
-     share and the board will usually be enabled. */
-  { int irqval = irqaction (dev->irq, &ei_sigaction);
-    if (irqval) {
-	printk (" unable to get IRQ %d (irqval=%d).\n", dev->irq, irqval);
-	return 0;
-    }
-  }
-
-  /* OK, were are certain this is going to work.  Setup the device. */
-#ifdef HAVE_PORTRESERVE
-  snarf_region(ioaddr, 32);
-#endif
-  ethdev_init(dev);
-
-  ei_status.name = model_name;
-  ei_status.word16 = word16;
-  ei_status.tx_start_page = WD_START_PG;
-  ei_status.rx_start_page = WD_START_PG + TX_PAGES;
-  ei_status.stop_page = word16 ? WD13_STOP_PG : WD03_STOP_PG;
-
-  /* Don't map in the shared memory until the board is actually opened. */
-  dev->rmem_start = dev->mem_start + TX_PAGES*256;
-  dev->mem_end = dev->rmem_end
-      = dev->mem_start + (ei_status.stop_page - WD_START_PG)*256;
-
-  printk(" %s, IRQ %d, shared memory at %#x-%#x.\n",
-	 model_name, dev->irq, dev->mem_start, dev->mem_end-1);
-  if (ei_debug > 0)
-      printk(version);
-
-  ei_status.reset_8390 = &wd_reset_8390;
-  ei_status.block_input = &wd_block_input;
-  ei_status.block_output = &wd_block_output;
-  dev->open = &wd_open;
-  dev->stop = &wd_close_card;
-  NS8390_init(dev, 0);
-
-  return dev->base_addr;
+	
+	/* The 8390 isn't at the base address -- the ASIC regs are there! */
+	dev->base_addr = ioaddr+WD_NIC_OFFSET;
+	
+	if (dev->irq < 2) {
+		int irqmap[] = {9,3,5,7,10,11,15,4};
+		int reg1 = inb(ioaddr+1);
+		int reg4 = inb(ioaddr+4);
+		if (ancient || reg1 == 0xff) {	/* Ack!! No way to read the IRQ! */
+			short nic_addr = ioaddr+WD_NIC_OFFSET;
+			
+			/* We have an old-style ethercard that doesn't report its IRQ
+			   line.  Do autoirq to find the IRQ line. Note that this IS NOT
+			   a reliable way to trigger an interrupt. */
+			outb_p(E8390_NODMA + E8390_STOP, nic_addr);
+			outb(0x00, nic_addr+EN0_IMR);	/* Disable all intrs. */
+			autoirq_setup(0);
+			outb_p(0xff, nic_addr + EN0_IMR);	/* Enable all interrupts. */
+			outb_p(0x00, nic_addr + EN0_RCNTLO);
+			outb_p(0x00, nic_addr + EN0_RCNTHI);
+			outb(E8390_RREAD+E8390_START, nic_addr); /* Trigger it... */
+			dev->irq = autoirq_report(2);
+			outb_p(0x00, nic_addr+EN0_IMR);	/* Mask all intrs. again. */
+			
+			if (ei_debug > 2)
+				printk(" autoirq is %d", dev->irq);
+			if (dev->irq < 2)
+				dev->irq = word16 ? 10 : 5;
+		} else
+			dev->irq = irqmap[((reg4 >> 5) & 0x03) + (reg1 & 0x04)];
+	} else if (dev->irq == 2)		/* Fixup bogosity: IRQ2 is really IRQ9 */
+		dev->irq = 9;
+	
+	/* Snarf the interrupt now.  There's no point in waiting since we cannot
+	   share and the board will usually be enabled. */
+	if (irqaction (dev->irq, &ei_sigaction)) {
+		printk (" unable to get IRQ %d.\n", dev->irq);
+		return 0;
+	}
+	
+	/* OK, were are certain this is going to work.  Setup the device. */
+	snarf_region(ioaddr, 32);
+	ethdev_init(dev);
+	
+	ei_status.name = model_name;
+	ei_status.word16 = word16;
+	ei_status.tx_start_page = WD_START_PG;
+	ei_status.rx_start_page = WD_START_PG + TX_PAGES;
+	ei_status.stop_page = word16 ? WD13_STOP_PG : WD03_STOP_PG;
+	
+	/* Don't map in the shared memory until the board is actually opened. */
+	dev->rmem_start = dev->mem_start + TX_PAGES*256;
+	dev->mem_end = dev->rmem_end
+		= dev->mem_start + (ei_status.stop_page - WD_START_PG)*256;
+	
+	printk(" %s, IRQ %d, shared memory at %#lx-%#lx.\n",
+		   model_name, dev->irq, dev->mem_start, dev->mem_end-1);
+	if (ei_debug > 0)
+		printk(version);
+	
+	ei_status.reset_8390 = &wd_reset_8390;
+	ei_status.block_input = &wd_block_input;
+	ei_status.block_output = &wd_block_output;
+	dev->open = &wd_open;
+	dev->stop = &wd_close_card;
+	NS8390_init(dev, 0);
+	
+	return dev->base_addr;
 }
 
 static int
@@ -239,12 +257,12 @@
   int ioaddr = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */
 
   /* Map in the shared memory. Always set register 0 last to remain
-     compatible with very old boards. */
+	 compatible with very old boards. */
   ei_status.reg0 = ((dev->mem_start>>13) & 0x3f) | WD_MEMENB;
   ei_status.reg5 = ((dev->mem_start>>19) & 0x1f) | NIC16;
 
   if (ei_status.word16)
-      outb(ei_status.reg5, ioaddr+WD_CMDREG5);
+	  outb(ei_status.reg5, ioaddr+WD_CMDREG5);
   outb(ei_status.reg0, ioaddr); /* WD_CMDREG */
 
   return ei_open(dev);
@@ -253,19 +271,19 @@
 static void
 wd_reset_8390(struct device *dev)
 {
-    int wd_cmd_port = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */
+	int wd_cmd_port = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */
 
-    outb(WD_RESET, wd_cmd_port);
-    if (ei_debug > 1) printk("resetting the WD80x3 t=%d...", jiffies);
-    ei_status.txing = 0;
+	outb(WD_RESET, wd_cmd_port);
+	if (ei_debug > 1) printk("resetting the WD80x3 t=%lu...", jiffies);
+	ei_status.txing = 0;
 
-    /* Set up the ASIC registers, just in case something changed them. */
-    outb((((dev->mem_start>>13) & 0x3f)|WD_MEMENB), wd_cmd_port);
-    if (ei_status.word16)
-	outb(NIC16 | ((dev->mem_start>>19) & 0x1f), wd_cmd_port+WD_CMDREG5);
+	/* Set up the ASIC registers, just in case something changed them. */
+	outb((((dev->mem_start>>13) & 0x3f)|WD_MEMENB), wd_cmd_port);
+	if (ei_status.word16)
+		outb(NIC16 | ((dev->mem_start>>19) & 0x1f), wd_cmd_port+WD_CMDREG5);
 
-    if (ei_debug > 1) printk("reset done\n");
-    return;
+	if (ei_debug > 1) printk("reset done\n");
+	return;
 }
 
 /* Block input and output are easy on shared memory ethercards, and trivial
@@ -276,76 +294,76 @@
 static int
 wd_block_input(struct device *dev, int count, char *buf, int ring_offset)
 {
-    int wd_cmdreg = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */
-    void *xfer_start = (void *)(dev->mem_start + ring_offset
-				- (WD_START_PG<<8));
+	int wd_cmdreg = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */
+	long xfer_start = dev->mem_start + ring_offset - (WD_START_PG<<8);
 
-    /* We'll always get a 4 byte header read first. */
-    if (count == 4) {
+	/* We'll always get a 4 byte header read followed by a packet read, so
+	   we enable 16 bit mode before the header, and disable after the body. */
+	if (count == 4) {
+		if (ei_status.word16)
+			outb(ISA16 | ei_status.reg5, wd_cmdreg+WD_CMDREG5);
+		((int*)buf)[0] = ((int*)xfer_start)[0];
+		return 0;
+	}
+
+	if (xfer_start + count > dev->rmem_end) {
+		/* We must wrap the input move. */
+		int semi_count = dev->rmem_end - xfer_start;
+		memcpy(buf, (char *)xfer_start, semi_count);
+		count -= semi_count;
+		memcpy(buf + semi_count, (char *)dev->rmem_start, count);
+	} else
+		memcpy(buf, (char *)xfer_start, count);
+
+	/* Turn off 16 bit access so that reboot works.	 ISA brain-damage */
 	if (ei_status.word16)
-	    outb(ISA16 | ei_status.reg5, wd_cmdreg+WD_CMDREG5);
-	((int*)buf)[0] = ((int*)xfer_start)[0];
+		outb(ei_status.reg5, wd_cmdreg+WD_CMDREG5);
+
 	return 0;
-    }
-
-    if (xfer_start + count > (void*) dev->rmem_end) {
-	/* We must wrap the input move. */
-	int semi_count = (void*)dev->rmem_end - xfer_start;
-	memcpy(buf, xfer_start, semi_count);
-	count -= semi_count;
-	memcpy(buf + semi_count, (char *)dev->rmem_start, count);
-    } else
-	memcpy(buf, xfer_start, count);
-
-    /* Turn off 16 bit access so that reboot works.  ISA brain-damage */
-    if (ei_status.word16)
-	outb(ei_status.reg5, wd_cmdreg+WD_CMDREG5);
-
-    return 0;
 }
 
 static void
 wd_block_output(struct device *dev, int count, const unsigned char *buf,
-		int start_page)
+				int start_page)
 {
-    int wd_cmdreg = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */
-    unsigned char *shmem
-	= (unsigned char *)dev->mem_start + ((start_page - WD_START_PG)<<8);
+	int wd_cmdreg = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */
+	long shmem = dev->mem_start + ((start_page - WD_START_PG)<<8);
 
 
-    if (ei_status.word16) {
-	/* Turn on and off 16 bit access so that reboot works. */
-	outb(ISA16 | ei_status.reg5, wd_cmdreg+WD_CMDREG5);
-	memcpy(shmem, buf, count);
-	outb(ei_status.reg5, wd_cmdreg+WD_CMDREG5);
-    } else
-	memcpy(shmem, buf, count);
+	if (ei_status.word16) {
+		/* Turn on and off 16 bit access so that reboot works. */
+		outb(ISA16 | ei_status.reg5, wd_cmdreg+WD_CMDREG5);
+		memcpy((char *)shmem, buf, count);
+		outb(ei_status.reg5, wd_cmdreg+WD_CMDREG5);
+	} else
+		memcpy((char *)shmem, buf, count);
 }
 
 
 static int
 wd_close_card(struct device *dev)
 {
-    int wd_cmdreg = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */
+	int wd_cmdreg = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */
 
-    if (ei_debug > 1)
-	printk("%s: Shutting down ethercard.\n", dev->name);
-    NS8390_init(dev, 0);
+	if (ei_debug > 1)
+		printk("%s: Shutting down ethercard.\n", dev->name);
+	NS8390_init(dev, 0);
 
-    /* Change from 16-bit to 8-bit shared memory so reboot works. */
-    outb(ei_status.reg5, wd_cmdreg + WD_CMDREG5 );
+	/* Change from 16-bit to 8-bit shared memory so reboot works. */
+	outb(ei_status.reg5, wd_cmdreg + WD_CMDREG5 );
 
-    /* And disable the shared memory. */
-    outb(ei_status.reg0 & ~WD_MEMENB, wd_cmdreg);
+	/* And disable the shared memory. */
+	outb(ei_status.reg0 & ~WD_MEMENB, wd_cmdreg);
 
-    return 0;
+	return 0;
 }
 
 
 /*
  * Local variables:
- *  compile-command: "gcc -D__KERNEL__ -Wall -O6 -I/usr/src/linux/net/tcp -c wd.c"
+ *  compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c wd.c"
  *  version-control: t
+ *  tab-width: 4
  *  kept-new-versions: 5
  * End:
  */
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index 2144533..76e3dc2 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -128,10 +128,6 @@
 endif
 
 
-clean:
-	rm -f core *.o *.a *.s
-
-
 #
 # include a dependency file if one exists
 #
diff --git a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c
index caa0c5a..8b27142 100644
--- a/drivers/scsi/NCR5380.c
+++ b/drivers/scsi/NCR5380.c
@@ -2117,29 +2117,28 @@
 
 
 /* 
- * Function : int NCR5380_reset (void)
+ * Function : int NCR5380_reset (struct Scsi_Cmnd *)
  * 
  * Purpose : reset the SCSI bus.
  *
  * Returns : 0
- *
- * XXX we really need to add some sort of a per instance field here so that 
- * we only do a SCSI bus reset on the host adapter for which the reset command
- * was called.
  */ 
 
 #ifndef NCR5380_reset
 static
 #endif
-int NCR5380_reset (void) {
+int NCR5380_reset (Scsi_Cmnd * SCpnt) {
     NCR5380_local_declare();
     struct Scsi_Host *instance;
     cli();
-    for (instance = first_instance; instance; instance = instance->next) {
-	NCR5380_setup(instance);
-	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST);
-	udelay(1);
-	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
-    }
+
+    instance = SCpnt->host;
+    NCR5380_setup(instance);
+    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST);
+    udelay(1);
+    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+
+    sti();
+    if (SCpnt) SCpnt->flags |= NEEDS_JUMPSTART;
     return 0;
 }
diff --git a/drivers/scsi/NCR5380.h b/drivers/scsi/NCR5380.h
index c230a50..bedf225 100644
--- a/drivers/scsi/NCR5380.h
+++ b/drivers/scsi/NCR5380.h
@@ -236,7 +236,7 @@
 #ifndef NCR5380_reset
 static
 #endif
-int NCR5380_reset (void);
+int NCR5380_reset (Scsi_Cmnd *);
 #ifndef NCR5380_queue_command
 static 
 #endif
diff --git a/drivers/scsi/aha152x.c b/drivers/scsi/aha152x.c
index eedefdb..1f90af8 100644
--- a/drivers/scsi/aha152x.c
+++ b/drivers/scsi/aha152x.c
@@ -20,10 +20,17 @@
  * General Public License for more details.
  
  *
- * $Id: aha152x.c,v 0.97 1993/10/09 18:53:53 root Exp $
+ * $Id: aha152x.c,v 0.99 1993/10/24 16:19:59 root Exp root $
  *
 
  * $Log: aha152x.c,v $
+ * Revision 0.99  1993/10/24  16:19:59  root
+ * - fixed DATA IN (rare read errors gone)
+ *
+ * Revision 0.98  1993/10/17  12:54:44  root
+ * - fixed some recent fixes (shame on me)
+ * - moved initialization of scratch area to aha152x_queue
+ *
  * Revision 0.97  1993/10/09  18:53:53  root
  * - DATA IN fixed. Rarely left data in the fifo.
  *
@@ -204,13 +211,16 @@
 
 #endif
 
-#define DEBUG_BIOSPARAM         /* warn when biosparam is invoked */
 #define DEBUG_RESET             /* resets should be rare */
 #define DEBUG_ABORT             /* aborts too */
 
 /* END OF DEFINES */
 
-char *aha152x_id = "Adaptec 152x SCSI driver; $Revision: 0.97 $\n";
+/* some additional "phases" for getphase() */
+#define P_BUSFREE  1
+#define P_PARITY   2
+
+char *aha152x_id = "Adaptec 152x SCSI driver; $Revision: 0.99 $\n";
 
 static int port_base      = 0;
 static int this_host      = 0;
@@ -401,9 +411,8 @@
  * return value is a valid phase or an error code.
  *
  * errorcodes:
- *   1 BUS FREE phase detected
- *   2 RESET IN detected
- *   3 parity error in DATA phase
+ *   P_BUSFREE   BUS FREE phase detected
+ *   P_PARITY    parity error in DATA phase
  */
 static int getphase(void)
 {
@@ -416,7 +425,7 @@
           while( !( ( sstat1 = GETPORT( SSTAT1 ) ) & (BUSFREE|SCSIRSTI|REQINIT ) ) )
             ;
           if( sstat1 & BUSFREE )
-            return 1;
+            return P_BUSFREE;
           if( sstat1 & SCSIRSTI )
             {
               /* IBM drive responds with RSTI to RSTO */
@@ -433,18 +442,12 @@
       if( TESTHI( SSTAT1, SCSIPERR ) )
         {
           if( (phase & (CDO|MSGO))==0 )                         /* DATA phase */
-            {
-              return 3;
-            }
+            return P_PARITY;
 
-          SETPORT( SCSISIG, phase );
           make_acklow();
         }
       else
-        {
-          SETPORT( SCSISIG, phase );
-          return phase;
-        }
+        return phase;
     }
 }
 
@@ -660,7 +663,7 @@
   do_pause(5);
   CLRBITS(SCSISEQ, SCSIRSTO );
 
-  aha152x_reset();
+  aha152x_reset(NULL);
 
   printk("aha152x: vital data: PORTBASE=0x%03x, IRQ=%d, SCSI ID=%d, reconnect=%s, parity=enabled\n",
          port_base, interrupt_level, this_host, can_disconnect ? "enabled" : "disabled" );
@@ -719,15 +722,41 @@
   disp_ports();
 #endif
 
+  SCpnt->scsi_done =       done;
+
+  /* setup scratch area
+     SCp.ptr              : buffer pointer
+     SCp.this_residual    : buffer length
+     SCp.buffer           : next buffer
+     SCp.buffers_residual : left buffers in list
+     SCp.phase            : current state of the command */
+  SCpnt->SCp.phase = not_issued;
+  if (SCpnt->use_sg)
+    {
+      SCpnt->SCp.buffer           = (struct scatterlist *)SCpnt->request_buffer;
+      SCpnt->SCp.ptr              = SCpnt->SCp.buffer->address;
+      SCpnt->SCp.this_residual    = SCpnt->SCp.buffer->length;
+      SCpnt->SCp.buffers_residual = SCpnt->use_sg - 1;
+    }
+  else
+    {
+      SCpnt->SCp.ptr              = (char *)SCpnt->request_buffer;
+      SCpnt->SCp.this_residual    = SCpnt->request_bufflen;
+      SCpnt->SCp.buffer           = NULL;
+      SCpnt->SCp.buffers_residual = 0;
+    }
+          
+  SCpnt->SCp.Status              = CHECK_CONDITION;
+  SCpnt->SCp.Message             = 0;
+  SCpnt->SCp.have_data_in        = 0;
+  SCpnt->SCp.sent_command        = 0;
+
   /* Turn led on, when this is the first command. */
   cli();
   commands++;
   if(commands==1)
     SETPORT( PORTA, 1 );
 
-  SCpnt->scsi_done =       done;
-  SCpnt->SCp.phase = not_issued;
-
 #if defined(DEBUG_QUEUES)
   printk("i+ (%d), ", commands );
 #endif
@@ -868,7 +897,7 @@
 
   SETPORT(BRSTCNTRL, 0xf1);
 
-  /* clear channel 0 and transfer count */
+  /* clear SCSI fifo and transfer count */
   SETPORT(SXFRCTL0, CH1|CLRCH1|CLRSTCNT);
   SETPORT(SXFRCTL0, CH1);
 
@@ -881,7 +910,7 @@
  *  Reset registers, reset a hanging bus and
  *  kill active and disconnected commands
  */
-int aha152x_reset(void)
+int aha152x_reset(Scsi_Cmnd * __unused)
 {
   Scsi_Cmnd *ptr;
 
@@ -1111,7 +1140,7 @@
 
       SETPORT( SXFRCTL0, CH1);
 
-      identify_msg = GETPORT(SCSIBUS);
+      identify_msg = GETPORT(SCSIDAT);
 
       if(!(identify_msg & IDENTIFY_BASE))
         {
@@ -1123,8 +1152,6 @@
       make_acklow();
       getphase();
 
-      SETPORT(SCSISIG, P_MSGI);
-
 #if defined(DEBUG_QUEUES)
       printk("identify=%02x, lun=%d, ", identify_msg, identify_msg & 0x3f );
 #endif
@@ -1169,35 +1196,9 @@
           sti();
 
 #if defined(DEBUG_INTR) || defined(DEBUG_SELECTION) || defined(DEBUG_PHASES)
-          printk("issuing command, ");
+          printk("issueing command, ");
 #endif
-
-          /* setup SCSI pointers
-             SCp.ptr              : buffer pointer
-             SCp.this_residual    : buffer length
-             SCp.buffer           : next buffer
-             SCp.buffers_residual : left buffers in list */
-          if (current_SC->use_sg)
-            {
-              current_SC->SCp.buffer =
-                (struct scatterlist *)current_SC->request_buffer;
-              current_SC->SCp.ptr              = current_SC->SCp.buffer->address;
-              current_SC->SCp.this_residual    = current_SC->SCp.buffer->length;
-              current_SC->SCp.buffers_residual = current_SC->use_sg - 1;
-            }
-          else
-            {
-              current_SC->SCp.ptr              = (char *)current_SC->request_buffer;
-              current_SC->SCp.this_residual    = current_SC->request_bufflen;
-              current_SC->SCp.buffer           = NULL;
-              current_SC->SCp.buffers_residual = 0;
-            }
-          
-          current_SC->SCp.Status              = CHECK_CONDITION;
-          current_SC->SCp.Message             = 0;
-          current_SC->SCp.have_data_in        = 0;
-          current_SC->SCp.sent_command        = 0;
-          current_SC->SCp.phase               = in_selection;
+          current_SC->SCp.phase = in_selection;
 
   #if defined(DEBUG_INTR) || defined(DEBUG_SELECTION) || defined(DEBUG_PHASES)
           printk("selecting %d, ", current_SC->target); 
@@ -1331,6 +1332,8 @@
 
   /* enable interrupt, when target leaves current phase */
   phase = getphase();
+  if(!(phase & ~P_MASK))                                      /* "real" phase */
+    SETPORT(SCSISIG, phase);
   SETPORT(SSTAT1, CLRPHASECHG);
   current_SC->SCp.phase =
     (current_SC->SCp.phase & ~((P_MASK|1)<<16)) | (phase << 16 );
@@ -1355,7 +1358,8 @@
           }
         else
           /* If we didn't identify yet, do it. Otherwise there's nothing to do,
-             but reject (perhaps one could do as NOP as well) */
+             but reject (probably we got an message before, that we have to
+             reject (SDTR, WDTR, etc.) */
           if( !(current_SC->SCp.phase & sent_ident))
             {
               message=IDENTIFY(can_disconnect,current_SC->lun);
@@ -1372,23 +1376,25 @@
 #endif
             }
           
-        CLRSETBITS( SXFRCTL0, ENDMA, SPIOEN);
+        CLRBITS( SXFRCTL0, ENDMA);
 
-        SETPORT( SIMODE0, ENSPIORDY );
-        SETPORT( SIMODE1, ENPHASEMIS );
+        SETPORT( SIMODE0, 0 );
+        SETPORT( SIMODE1, ENPHASEMIS|ENREQINIT );
 
         /* wait for data latch to become ready or a phase change */
         while( TESTLO( DMASTAT, INTSTAT ) )
           ;
 
-        if( TESTLO( SSTAT0, SPIORDY ) )
-          aha152x_panic("couldn't send message");
+        if( TESTHI( SSTAT1, PHASEMIS ) )
+          aha152x_panic("unable to send message");
 
         /* Leave MESSAGE OUT after transfer */
         SETPORT( SSTAT1, CLRATNO);
 
         SETPORT( SCSIDAT, message );
-        CLRBITS( SXFRCTL0, SPIOEN);
+
+        make_acklow();
+        getphase();
 
         if(message==IDENTIFY(can_disconnect,current_SC->lun))
           current_SC->SCp.phase |= sent_ident;
@@ -1418,27 +1424,19 @@
 #endif
       if( !(current_SC->SCp.sent_command) )
         {
-          if(GETPORT(FIFOSTAT))
-            {
-              int i;
+          if(GETPORT(FIFOSTAT) || GETPORT(SSTAT2) & (SFULL|SFCNT))
+            printk("aha152x: P_CMD: %d(%d) bytes left in FIFO, resetting\n",
+                   GETPORT(FIFOSTAT), GETPORT(SSTAT2) & (SFULL|SFCNT));
 
-              printk("aha152x: %d bytes left in FIFO, resetting\n",
-                     GETPORT(FIFOSTAT));
-              disp_ports();
-              printk("contents ( ");
-              SETPORT( SXFRCTL0, CH1|SPIOEN );
-              for(i=0; i<GETPORT(FIFOSTAT); i++)
-                printk("%02x ", GETPORT(SCSIDAT));
-              SETPORT( SXFRCTL0, CH1 );
-              printk(")\n");
-            }
-
+          /* reset fifo and enable writes */
           SETPORT(DMACNTRL0, WRITE_READ|RSTFIFO);
           SETPORT(DMACNTRL0, ENDMA|WRITE_READ);
 
+          /* clear transfer count and scsi fifo */
           SETPORT(SXFRCTL0, CH1|CLRSTCNT|CLRCH1 );
           SETPORT(SXFRCTL0, SCSIEN|DMAEN|CH1);
-   
+  
+          /* missing phase raises INTSTAT */
           SETPORT( SIMODE0, 0 );
           SETPORT( SIMODE1, ENPHASEMIS );
   
@@ -1497,10 +1495,10 @@
 
       SETPORT( SIMODE0, 0);
       SETPORT( SIMODE1, ENBUSFREE);
-
+  
       while( phase == P_MSGI ) 
         {
-          current_SC->SCp.Message = GETPORT( SCSIBUS );
+          current_SC->SCp.Message = GETPORT( SCSIDAT );
           switch(current_SC->SCp.Message)
             {
             case DISCONNECT:
@@ -1512,7 +1510,7 @@
               if(!can_disconnect)
                 aha152x_panic("target was not allowed to disconnect");
               break;
-            
+        
             case COMMAND_COMPLETE:
 #if defined(DEBUG_MSGI) || defined(DEBUG_PHASES)
               printk("inbound message ( COMMAND COMPLETE ), ");
@@ -1521,7 +1519,7 @@
               break;
 
             case MESSAGE_REJECT:
-#if defined(DEBUG_MSGI)
+#if defined(DEBUG_MSGI) || defined(DEBUG_TIMING)
               printk("inbound message ( MESSAGE REJECT ), ");
 #endif
               break;
@@ -1532,8 +1530,6 @@
 #endif
               break;
 
-/* my IBM drive responds to the first command with an extended message.
-   I just ignore it... */
             case EXTENDED_MESSAGE:
               { 
                 int           i, code;
@@ -1544,48 +1540,61 @@
                 make_acklow();
                 if(getphase()!=P_MSGI)
                   break;
-
+  
                 i=GETPORT(SCSIDAT);
 
 #if defined(DEBUG_MSGI)
                 printk("length (%d), ", i);
 #endif
 
-                make_acklow();
-                if(getphase()!=P_MSGI)
-                  break;
-
 #if defined(DEBUG_MSGI)
                 printk("code ( ");
 #endif
 
+                make_acklow();
+                if(getphase()!=P_MSGI)
+                  break;
+
                 code = GETPORT(SCSIDAT);
 
-#if defined(DEBUG_MSGI)
                 switch( code )
                   {
                   case 0x00:
+#if defined(DEBUG_MSGI)
                     printk("MODIFY DATA POINTER ");
+#endif
+                    SETPORT(SCSISIG, P_MSGI|ATNO);
                     break;
                   case 0x01:
+#if defined(DEBUG_MSGI)
                     printk("SYNCHRONOUS DATA TRANSFER REQUEST ");
+#endif
+                    SETPORT(SCSISIG, P_MSGI|ATNO);
                     break;
                   case 0x02:
+#if defined(DEBUG_MSGI)
                     printk("EXTENDED IDENTIFY ");
+#endif
                     break;
                   case 0x03:
+#if defined(DEBUG_MSGI)
                     printk("WIDE DATA TRANSFER REQUEST ");
+#endif
+                    SETPORT(SCSISIG, P_MSGI|ATNO);
                     break;
                   default:
+#if defined(DEBUG_MSGI)
                     if( code & 0x80 )
                       printk("reserved (%d) ", code );
                     else
                       printk("vendor specific (%d) ", code);
+#endif
+                    SETPORT(SCSISIG, P_MSGI|ATNO);
                     break;
                   }
+#if defined(DEBUG_MSGI)
                 printk(" ), data ( ");
 #endif
-
                 while( --i && (make_acklow(), getphase()==P_MSGI))
                   {
 #if defined(DEBUG_MSGI)
@@ -1597,20 +1606,27 @@
 #if defined(DEBUG_MSGI)
                 printk(" ), ");
 #endif
+                /* We reject all extended messages. To do this
+                   we just enter MSGO by asserting ATN. Since
+                   we have already identified a REJECT message
+                   will be sent. */
+                SETPORT(SCSISIG, P_MSGI|ATNO);
               }
               break;
        
             default:
               printk("unsupported inbound message %x, ", current_SC->SCp.Message);
               break;
- 
+
             }
 
           make_acklow();
           phase=getphase();
         } 
 
-      SETPORT( SCSISIG, P_MSGI );
+      /* clear SCSI fifo on BUSFREE */
+      if(phase==P_BUSFREE)
+        SETPORT(SXFRCTL0, CH1|CLRCH1);
 
       if(current_SC->SCp.phase & disconnected)
         {
@@ -1630,17 +1646,16 @@
           SETBITS( DMACNTRL0, INTEN );
           return;
         }
-
       break;
 
     case P_STATUS:                                         /* STATUS IN phase */
 #if defined(DEBUG_STATUS) || defined(DEBUG_INTR) || defined(DEBUG_PHASES)
       printk("STATUS, ");
 #endif
-      SETPORT( SXFRCTL0, CH1|SPIOEN);
+      SETPORT( SXFRCTL0, CH1);
 
-      SETPORT( SIMODE0, ENSPIORDY );
-      SETPORT( SIMODE1, ENPHASEMIS );
+      SETPORT( SIMODE0, 0 );
+      SETPORT( SIMODE1, ENPHASEMIS|ENREQINIT );
 
       SETBITS( SXFRCTL0, SCSIEN );
 #if defined(DEBUG_STATUS)
@@ -1652,10 +1667,15 @@
       while( TESTLO( DMASTAT, INTSTAT ) )
         ;
 
+#if 0
       if(TESTLO( SSTAT0, SPIORDY ) )
         aha152x_panic("passing STATUS phase");
+#endif
 
       current_SC->SCp.Status = GETPORT( SCSIDAT );
+      make_acklow();
+      getphase();
+
 #if defined(DEBUG_STATUS)
       printk("inbound status ");
       print_status( current_SC->SCp.Status );
@@ -1665,7 +1685,9 @@
       while( TESTHI( SXFRCTL0, SCSIEN ) )
         ;
         
+#if 0
       CLRBITS( SXFRCTL0, SPIOEN);
+#endif
       break;
 
     case P_DATAI:                                            /* DATA IN phase */
@@ -1676,16 +1698,19 @@
         printk("DATA IN, ");
 #endif
 
+        if(GETPORT(FIFOSTAT) || GETPORT(SSTAT2) & (SFULL|SFCNT))
+          printk("aha152x: P_DATAI: %d(%d) bytes left in FIFO, resetting\n",
+                 GETPORT(FIFOSTAT), GETPORT(SSTAT2) & (SFULL|SFCNT));
+
+        /* reset host fifo */
+        SETPORT(DMACNTRL0, RSTFIFO);
+        SETPORT(DMACNTRL0, RSTFIFO|ENDMA);
+
+        SETPORT(SXFRCTL0, CH1|SCSIEN|DMAEN );
+
         SETPORT( SIMODE0, 0 );
         SETPORT( SIMODE1, ENPHASEMIS|ENBUSFREE );
 
-        SETPORT(SXFRCTL0, CH1|CLRSTCNT|CLRCH1 );
-        CLRSETBITS(SXFRCTL0, CLRSTCNT, SCSIEN|DMAEN|CH1);
-
-        SETBITS(DMACNTRL0, RSTFIFO);
-        CLRSETBITS(DMACNTRL0, WRITE_READ, ENDMA);
-
-
         /* done is set when the FIFO is empty after the target left DATA IN */
         done=0;
       
@@ -1719,19 +1744,6 @@
             printk("fifodata=%d, ", fifodata);
 #endif
 
-            /* I don't know yet why, but rarely I get empty
-               buffers here, so I've to advance to the next buffer
-               before I enter the loop */
-            if(!current_SC->SCp.this_residual &&
-                current_SC->SCp.buffers_residual)
-              {
-                /* advance to next buffer */
-                current_SC->SCp.buffers_residual--;
-                current_SC->SCp.buffer++;
-                current_SC->SCp.ptr           = current_SC->SCp.buffer->address;
-                current_SC->SCp.this_residual = current_SC->SCp.buffer->length;
-              }
-
             while( fifodata && current_SC->SCp.this_residual )
               {
                 data_count=fifodata;
@@ -1795,8 +1807,10 @@
                messages) get transfered in the data phase, so I assume 1
                additional byte is ok */
             if(fifodata>1)
-              printk("aha152x: more data than expected (%d bytes)\n",
-                     GETPORT(FIFOSTAT));
+              {
+                printk("aha152x: more data than expected (%d bytes)\n",
+                       GETPORT(FIFOSTAT));
+              }
 
 #if defined(DEBUG_DATAI)
             if(!fifodata)
@@ -1812,7 +1826,6 @@
                  current_SC->SCp.buffers_residual, 
                  current_SC->SCp.this_residual);
 #endif
-
         /* transfer can be considered ended, when SCSIEN reads back zero */
         CLRBITS(SXFRCTL0, SCSIEN|DMAEN);
         while( TESTHI( SXFRCTL0, SCSIEN ) )
@@ -1840,9 +1853,9 @@
                current_SC->SCp.buffers_residual );
 #endif
 
-        if(GETPORT(FIFOSTAT))
+        if(GETPORT(FIFOSTAT) || GETPORT(SSTAT2) & (SFULL|SFCNT) )
           {
-            printk("%d left in FIFO, ", GETPORT(FIFOSTAT));
+            printk("%d(%d) left in FIFO, ", GETPORT(FIFOSTAT), GETPORT(SSTAT2) & (SFULL|SFCNT) );
             aha152x_panic("FIFO should be empty");
           }
 
@@ -1921,16 +1934,7 @@
                (perhaps disconnect) */
 
             /* data in fifos has to be resend */
-            data_count = GETPORT(SSTAT2);
-            if( (data_count & SFCNT) == 0)
-              data_count = (data_count & SEMPTY) ? 0 : 8 ;
-            else
-              data_count &= SFCNT;
-
-#if defined(DEBUG_DATAO)
-            printk("\ntarget left DATA OUT, fifo=%d, scsififo=%d, ",
-                   GETPORT(FIFOSTAT), data_count ) ;
-#endif
+            data_count = GETPORT(SSTAT2) & (SFULL|SFCNT);
 
             data_count += GETPORT(FIFOSTAT) ;
             current_SC->SCp.ptr           -= data_count;
@@ -1942,7 +1946,7 @@
                    data_count );
 #endif
             SETPORT(DMACNTRL0, WRITE_READ|RSTFIFO);
-            CLRBITS(SXFRCTL0, SCSIEN|DMAEN);
+            CLRBITS(SXFRCTL0, SCSIEN|DMAEN );
             CLRBITS(DMACNTRL0, ENDMA);
           }
         else
@@ -1977,7 +1981,7 @@
       }
       break;
 
-    case 1:                                                        /* BUSFREE */
+    case P_BUSFREE:                                                /* BUSFREE */
 #if defined(DEBUG_RACE)
       leave_driver("(BUSFREE) intr");
 #endif
@@ -1990,7 +1994,7 @@
       return;
       break;
 
-    case 3:                                     /* parity error in DATA phase */
+    case P_PARITY:                              /* parity error in DATA phase */
 #if defined(DEBUG_RACE)
       leave_driver("(DID_PARITY) intr");
 #endif
@@ -2004,9 +2008,7 @@
       break;
 
     default:
-#if defined(DEBUG_INTR)
-      printk("unexpected phase, ");
-#endif
+      printk("aha152x: unexpected phase\n");
       break;
     }
 
@@ -2192,14 +2194,7 @@
   if( s & SOFFSET)  printk("SOFFSET ");
   if( s & SEMPTY)   printk("SEMPTY ");
   if( s & SFULL)    printk("SFULL ");
-  printk("); ");
-
-
-  if(s & SFCNT)
-    s &= SFCNT;
-  else
-    s = (s & SEMPTY) ? 0 : 8;
-  printk("SFCNT ( %d ); ", s );
+  printk("); SFCNT ( %d ); ", s & (SFULL|SFCNT) );
 
 #if 0
   printk("SSTAT4 ( ");
diff --git a/drivers/scsi/aha152x.h b/drivers/scsi/aha152x.h
index e693988..7996f81 100644
--- a/drivers/scsi/aha152x.h
+++ b/drivers/scsi/aha152x.h
@@ -15,7 +15,7 @@
 int        aha152x_command(Scsi_Cmnd *);
 int        aha152x_queue(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
 int        aha152x_abort(Scsi_Cmnd *, int);
-int        aha152x_reset(void);
+int        aha152x_reset(Scsi_Cmnd *);
 int        aha152x_biosparam(int, int, int*);
 
 /* number of queueable commands
diff --git a/drivers/scsi/aha1542.c b/drivers/scsi/aha1542.c
index c905002..f31d73d 100644
--- a/drivers/scsi/aha1542.c
+++ b/drivers/scsi/aha1542.c
@@ -173,6 +173,7 @@
 
 static int aha1542_test_port(int bse, struct Scsi_Host * shpnt)
 {
+    int i;
     volatile int debug = 0;
     
     /* Quick and dirty test for presence of the card. */
@@ -183,6 +184,9 @@
     /*  DEB(printk("aha1542_test_port called \n")); */
     
     outb(SRST|IRST/*|SCRST*/, CONTROL(bse));
+
+    i = jiffies + 2;
+    while (i>jiffies); /* Wait a little bit for things to settle down. */
     
     debug = 1;
     /* Expect INIT and IDLE, any of the others are bad */
@@ -294,7 +298,10 @@
 	sti();
 	/* Hmm, no mail.  Must have read it the last time around */
 	if (number_serviced) return;
-	printk("aha1542.c: interrupt received, but no mail.\n");
+	/* Virtually all of the time, this turns out to be the problem */
+	printk("aha1542.c: Unsupported BIOS options enabled."
+		"  Please turn off.\n");
+/*	printk("aha1542.c: interrupt received, but no mail.\n"); */
 	return;
       };
 
@@ -486,7 +493,7 @@
 	   (((int)sgpnt[i].address) & 1) || (sgpnt[i].length & 1)){
 	  unsigned char * ptr;
 	  printk("Bad segment list supplied to aha1542.c (%d, %d)\n",SCpnt->use_sg,i);
-	  for(i=0;i<SCpnt->use_sg++;i++){
+	  for(i=0;i<SCpnt->use_sg;i++){
 	    printk("%d: %x %x %d\n",i,(unsigned int) sgpnt[i].address, (unsigned int) sgpnt[i].alt_address,
 		   sgpnt[i].length);
 	  };
@@ -735,7 +742,7 @@
 		    DEB(aha1542_stat());
 		    
 		    DEB(printk("aha1542_detect: enable interrupt channel %d\n", irq_level));
-		    
+		    cli();
 		    if (request_irq(irq_level,aha1542_intr_handle)) {
 			    printk("Unable to allocate IRQ for adaptec controller.\n");
 			    goto unregister;
@@ -753,7 +760,6 @@
 				    outb(dma_chan - 4, DMA_MASK_REG);
 			    }
 		    }
-		    
 		    aha_host[irq_level - 9] = shpnt;
 		    shpnt->io_port = base_io;
 		    shpnt->dma_channel = dma_chan;
@@ -761,6 +767,7 @@
 		    HOSTDATA(shpnt)->aha1542_last_mbi_used  = (2*AHA1542_MAILBOXES - 1);
 		    HOSTDATA(shpnt)->aha1542_last_mbo_used  = (AHA1542_MAILBOXES - 1);
 		    memset(HOSTDATA(shpnt)->SCint, 0, sizeof(HOSTDATA(shpnt)->SCint));
+		    sti();
 #if 0
 		    DEB(printk(" *** READ CAPACITY ***\n"));
 		    
@@ -829,9 +836,14 @@
     return 0;
 }
 
-int aha1542_reset(void)
+/* We do not implement a reset function here, but the upper level code assumes
+   that it will get some kind of response for the command in SCpnt.  We must
+   oblige, or the command will hang the scsi system */
+
+int aha1542_reset(Scsi_Cmnd * SCpnt)
 {
     DEB(printk("aha1542_reset called\n"));
+    if(SCpnt) SCpnt->flags |= NEEDS_JUMPSTART;
     return 0;
 }
 
diff --git a/drivers/scsi/aha1542.h b/drivers/scsi/aha1542.h
index 4992ffe..f906107 100644
--- a/drivers/scsi/aha1542.h
+++ b/drivers/scsi/aha1542.h
@@ -130,11 +130,12 @@
 int aha1542_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
 int aha1542_abort(Scsi_Cmnd *, int);
 const char *aha1542_info(void);
-int aha1542_reset(void);
+int aha1542_reset(Scsi_Cmnd *);
 int aha1542_biosparam(int, int, int*);
 
 #define AHA1542_MAILBOXES 8
 #define AHA1542_SCATTER 16
+#define AHA1542_CMDLUN 1
 
 #ifndef NULL
 	#define NULL 0
@@ -147,6 +148,7 @@
 		aha1542_reset,				\
 	        NULL,		                        \
 		aha1542_biosparam,                      \
-		AHA1542_MAILBOXES, 7, AHA1542_SCATTER, 1, 0, 1}
+		AHA1542_MAILBOXES, 7, AHA1542_SCATTER, AHA1542_CMDLUN \
+		  , 0, 1}
 
 #endif
diff --git a/drivers/scsi/aha1740.c b/drivers/scsi/aha1740.c
index 5ddc028..2cd1a31 100644
--- a/drivers/scsi/aha1740.c
+++ b/drivers/scsi/aha1740.c
@@ -415,7 +415,7 @@
     return internal_done_errcode;
 }
 
-/* Query the board for it's irq_level.  Nothing else matters
+/* Query the board for its irq_level.  Nothing else matters
    in enhanced mode on an EISA bus. */
 
 void aha1740_getconfig(void)
@@ -467,10 +467,10 @@
 }
 
 /* Note:  They following two functions do not apply very well to the Adaptec,
-which basically manages it's own affairs quite well without our interference,
+which basically manages its own affairs quite well without our interference,
 so I haven't put anything into them.  I can faintly imagine someone with a
 *very* badly behaved SCSI target (perhaps an old tape?) wanting the abort(),
-but it hasn't happened yet, and doing aborts brings the Adaptec to it's
+but it hasn't happened yet, and doing aborts brings the Adaptec to its
 knees.  I cannot (at this moment in time) think of any reason to reset the
 card once it's running.  So there. */
 
@@ -480,9 +480,14 @@
     return 0;
 }
 
-int aha1740_reset(void)
+/* We do not implement a reset function here, but the upper level code assumes
+   that it will get some kind of response for the command in SCpnt.  We must
+   oblige, or the command will hang the scsi system */
+
+int aha1740_reset(Scsi_Cmnd * SCpnt)
 {
     DEB(printk("aha1740_reset called\n"));
+    if (SCpnt) SCpnt->flags |= NEEDS_JUMPSTART;
     return 0;
 }
 
diff --git a/drivers/scsi/aha1740.h b/drivers/scsi/aha1740.h
index ec25861..a4bb888 100644
--- a/drivers/scsi/aha1740.h
+++ b/drivers/scsi/aha1740.h
@@ -157,7 +157,7 @@
 int aha1740_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
 int aha1740_abort(Scsi_Cmnd *, int);
 const char *aha1740_info(void);
-int aha1740_reset(void);
+int aha1740_reset(Scsi_Cmnd *);
 int aha1740_biosparam(int, int, int*);
 
 #define AHA1740_ECBS 32
diff --git a/drivers/scsi/fdomain.c b/drivers/scsi/fdomain.c
index 6364c67..b82f031 100644
--- a/drivers/scsi/fdomain.c
+++ b/drivers/scsi/fdomain.c
@@ -1,10 +1,10 @@
 /* fdomain.c -- Future Domain TMC-16x0 driver
  * Created: Sun May  3 18:53:19 1992 by faith@cs.unc.edu
- * Revised: Sun Oct 10 20:15:47 1993 by faith@cs.unc.edu
+ * Revised: Sun Oct 31 19:53:49 1993 by faith@cs.unc.edu
  * Author: Rickard E. Faith, faith@cs.unc.edu
  * Copyright 1992, 1993 Rickard E. Faith
  *
- * $Id: fdomain.c,v 5.3 1993/10/11 00:16:12 root Exp $
+ * $Id: fdomain.c,v 5.6 1993/11/01 02:40:32 root Exp $
 
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the
@@ -144,7 +144,7 @@
 #include <linux/string.h>
 #include <linux/ioport.h>
 
-#define VERSION          "$Revision: 5.3 $"
+#define VERSION          "$Revision: 5.6 $"
 
 /* START OF USER DEFINABLE OPTIONS */
 
@@ -412,13 +412,12 @@
       if (inb( port + MSB_ID_Code ) != 0x60) return 0;
       chip = tmc18c50;
    }
-   
+
    /* We have a valid MCA ID for a TMC-1660/TMC-1680 Future Domain board.
-      Now, check to be sure the bios_base matches these ports.
-      If someone was unlucky enough to have purchased more than one
-      Future Domain board, then they will have to modify this code, as
-      we only detect one board here.  [The one with the lowest bios_base.]
-    */
+      Now, check to be sure the bios_base matches these ports.  If someone
+      was unlucky enough to have purchased more than one Future Domain
+      board, then they will have to modify this code, as we only detect one
+      board here.  [The one with the lowest bios_base.]  */
 
    options = inb( port + Configuration1 );
 
@@ -426,7 +425,9 @@
    printk( " Options = %x\n", options );
 #endif
 
-   if (addresses[ (options & 0xc0) >> 6 ] != bios_base) return 0;
+				/* Check for board with lowest bios_base. */
+   if (addresses[ (options & 0xc0) >> 6 ] != bios_base)
+	 return 0;
    interrupt_level = ints[ (options & 0x0e) >> 1 ];
 
    return 1;
@@ -440,7 +441,8 @@
    for (i = 0; i < 255; i++) {
       outb( i, port_base + Write_Loopback );
       result = inb( port_base + Read_Loopback );
-      if (i != result) return 1;
+      if (i != result)
+	    return 1;
    }
    return 0;
 }
@@ -503,7 +505,8 @@
 #endif
 
       for (flag = 0, i = 0; !flag && i < PORT_COUNT; i++) {
-	 if (port_base == ports[i]) ++flag;
+	 if (port_base == ports[i])
+	       ++flag;
       }
 
       if (flag)
@@ -571,7 +574,7 @@
    Write_FIFO_port       = port_base + Write_FIFO;
    Write_SCSI_Data_port  = port_base + Write_SCSI_Data;
 
-   fdomain_16x0_reset();
+   fdomain_16x0_reset( NULL );
 
    if (fdomain_test_loopback()) {
 #if DEBUG_DETECT
@@ -633,8 +636,7 @@
       higher level SCSI routines when I first wrote this driver.  Now,
       however, correct scan routines are part of scsi.c and these routines
       are no longer needed.  However, this code is still good for
-      debugging.
-    */
+      debugging.  */
 
    SCinit.request_buffer  = SCinit.buffer = buf;
    SCinit.request_bufflen = SCinit.bufflen = sizeof(buf)-1;
@@ -644,7 +646,8 @@
    printk( "Future Domain detection routine scanning for devices:\n" );
    for (i = 0; i < 8; i++) {
       SCinit.target = i;
-      if (i == 6) continue;	/* The host adapter is at SCSI ID 6 */
+      if (i == scsi_hosts[this_host].this_id) /* Skip host adapter */
+	    continue;
       memcpy(SCinit.cmnd, do_request_sense, sizeof(do_request_sense));
       retcode = fdomain_16x0_command(&SCinit);
       if (!retcode) {
@@ -721,7 +724,8 @@
    timeout = jiffies + 50;	              /* 500 mS */
    while (jiffies < timeout) {
       status = inb( TMC_Status_port );        /* Read adapter status */
-      if (status & 0x02) return 0;	      /* Arbitration complete */
+      if (status & 0x02)		      /* Arbitration complete */
+	    return 0;	
    }
 
    /* Make bus idle */
@@ -731,8 +735,7 @@
    printk( "Arbitration failed, status = %x\n", status );
 #endif
 #if ERRORS_ONLY
-   printk( "Future Domain: Arbitration failed, status = %x",
-	   status );
+   printk( "Future Domain: Arbitration failed, status = %x", status );
 #endif
    return 1;
 }
@@ -777,7 +780,8 @@
       outb( 0x00, Interrupt_Cntl_port );
       fdomain_make_bus_idle();
       current_SC->result = error;
-      if (current_SC->scsi_done) current_SC->scsi_done( current_SC );
+      if (current_SC->scsi_done)
+	    current_SC->scsi_done( current_SC );
       else panic( "Future Domain: current_SC->scsi_done() == NULL" );
    } else {
       panic( "Future Domain: my_done() called outside of command\n" );
@@ -805,31 +809,20 @@
 #endif
       return;
    }
+
+   /* Abort calls my_done, so we do nothing here. */
+   if (current_SC->SCp.phase & aborted) {
+#if DEBUG_ABORT
+      printk( "Interrupt after abort, ignoring\n" );
+#endif
+      /*
+      return; */
+   }
+
 #if DEBUG_RACE
    ++in_interrupt_flag;
 #endif
 
-   if (current_SC->SCp.phase & aborted) {
-#if EVERY_ACCESS
-      if (current_SC->SCp.phase & (in_other | disconnect))
-	    printk( "aborted (%s) = %d, ",
-		    current_SC->SCp.phase & in_other
-		    ? "in_other" : "disconnect",
-		    current_SC->result );
-      else
-	    printk( "aborted = %d, ",
-		    current_SC->result );
-#endif
-      /* Force retry for timeouts after selection complete */
-      if (current_SC->SCp.phase & (in_other | disconnect)) {
-	 fdomain_16x0_reset();
-	 my_done( DID_RESET << 16 );
-      } else {
-	 my_done( current_SC->result << 16 );
-      }
-      return;
-   }
-
    if (current_SC->SCp.phase & in_arbitration) {
       status = inb( TMC_Status_port );        /* Read adapter status */
       if (!(status & 0x02)) {
@@ -888,28 +881,12 @@
       switch (status & 0x0e) {
        
       case 0x08:		/* COMMAND OUT */
-#if 0
-	 if (!current_SC->SCp.sent_command) {
-	    int i;
-	    
-	    current_SC->SCp.sent_command = COMMAND_SIZE( current_SC->cmnd[0] );
-	    
-	    for (i = 0; i < COMMAND_SIZE( current_SC->cmnd[0] ); i++) {
-	       outb( current_SC->cmnd[i], Write_SCSI_Data_port );
-#if EVERY_ACCESS
-	       printk( "CMD = %x,", current_SC->cmnd[i] );
-#endif
-	    }
-	 }
-#else
 	 outb( current_SC->cmnd[current_SC->SCp.sent_command++],
 	       Write_SCSI_Data_port );
 #if EVERY_ACCESS
 	 printk( "CMD = %x,",
 		 current_SC->cmnd[ current_SC->SCp.sent_command - 1] );
 #endif
-	 
-#endif
 	 break;
       case 0x00:		/* DATA OUT -- tmc18c50 only */
 	 if (chip != tmc1800 && !current_SC->SCp.have_data_in) {
@@ -1203,6 +1180,9 @@
 					  + 13));
 
 	    if (!(key == UNIT_ATTENTION && (code == 0x29 || !code))
+		&& !(key == NOT_READY
+		     && code == 0x04
+		     && (!qualifier || qualifier == 0x02 || qualifier == 0x01))
 		&& !(key == ILLEGAL_REQUEST && (code == 0x25
 						|| code == 0x24
 						|| !code)))
@@ -1349,7 +1329,8 @@
    isr = inb( 0xa0 ) << 8;
    outb( 0x0b, 0x20 );
    isr += inb( 0x20 );
-   
+
+				/* Print out interesting information */
    printk( "IMR = 0x%04x", imr );
    if (imr & (1 << interrupt_level))
 	 printk( " (masked)" );
@@ -1357,10 +1338,12 @@
 
    printk( "SCSI Status      = 0x%02x\n", inb( SCSI_Status_port ) );
    printk( "TMC Status       = 0x%02x", inb( TMC_Status_port ) );
-   if (inb( TMC_Status_port & 1)) printk( " (interrupt)" );
+   if (inb( TMC_Status_port & 1))
+	 printk( " (interrupt)" );
    printk( "\n" );
    printk( "Interrupt Status = 0x%02x", inb( Interrupt_Status_port ) );
-   if (inb( Interrupt_Status_port ) & 0x08) printk( " (enabled)" );
+   if (inb( Interrupt_Status_port ) & 0x08)
+	 printk( " (enabled)" );
    printk( "\n" );
    if (chip == tmc18c50) {
       printk( "FIFO Status      = 0x%02x\n", inb( port_base + FIFO_Status ) );
@@ -1411,7 +1394,7 @@
    return 0;
 }
 
-int fdomain_16x0_reset( void )
+int fdomain_16x0_reset( Scsi_Cmnd *SCpnt )
 {
 #if DEBUG_RESET
    static int called_once = 0;
@@ -1432,6 +1415,14 @@
    do_pause( 115 );
    outb( 0, SCSI_Mode_Cntl_port );
    outb( PARITY_MASK, TMC_Cntl_port );
+
+   /* Unless this is the very first call (i.e., SCPnt == NULL), everything
+      is probably hosed at this point.  We will, however, try to keep
+      things going by informing the high-level code that we need help. */
+
+   if (SCpnt)
+	 SCpnt->flags |= NEEDS_JUMPSTART;
+   
    return 0;
 }
 
diff --git a/drivers/scsi/fdomain.h b/drivers/scsi/fdomain.h
index d913e92..3374232 100644
--- a/drivers/scsi/fdomain.h
+++ b/drivers/scsi/fdomain.h
@@ -4,7 +4,7 @@
  * Author: Rickard E. Faith, faith@cs.unc.edu
  * Copyright 1992, 1993 Rickard E. Faith
  *
- * $Id: fdomain.h,v 5.1 1993/10/10 13:33:11 root Exp $
+ * $Id: fdomain.h,v 5.2 1993/10/24 16:40:41 root Exp $
 
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the
@@ -25,7 +25,7 @@
 int        fdomain_16x0_command( Scsi_Cmnd * );
 int        fdomain_16x0_abort( Scsi_Cmnd *, int );
 const char *fdomain_16x0_info( void );
-int        fdomain_16x0_reset( void ); 
+int        fdomain_16x0_reset( Scsi_Cmnd * ); 
 int        fdomain_16x0_queue( Scsi_Cmnd *, void (*done)(Scsi_Cmnd *) );
 int        fdomain_16x0_biosparam( int, int, int * );
 
diff --git a/drivers/scsi/g_NCR5380.h b/drivers/scsi/g_NCR5380.h
index cb55068..88a536f 100644
--- a/drivers/scsi/g_NCR5380.h
+++ b/drivers/scsi/g_NCR5380.h
@@ -37,7 +37,7 @@
 int generic_NCR5380_detect(int);
 const char *generic_NCR5380_info(void);
 int generic_NCR5380_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
-int generic_NCR5380_reset(void);
+int generic_NCR5380_reset(Scsi_Cmnd *);
 
 
 #ifndef NULL
diff --git a/drivers/scsi/hosts.h b/drivers/scsi/hosts.h
index 69e67b8..3780d72 100644
--- a/drivers/scsi/hosts.h
+++ b/drivers/scsi/hosts.h
@@ -21,6 +21,14 @@
 */
 
 
+/* A jumpstart is often required when the reset() function is called -
+   many host adapters cannot do this cleanly, so they do nothing at all.
+   To get the command going again, these routines set this bit in the flags
+   so that a scsi_request_sense() is executed, and the command starts running
+   again */
+
+#define NEEDS_JUMPSTART 0x20
+
 #define SG_NONE 0
 #define SG_ALL 0xff
 
@@ -114,9 +122,15 @@
 	/*
 		The reset function will reset the SCSI bus.  Any executing 
 		commands should fail with a DID_RESET in the host byte.
+		The Scsi_Cmnd  is passed so that the reset routine can figure
+		out which host adapter should be reset, and also which command
+		within the command block was responsible for the reset in
+		the first place.  Some hosts do not implement a reset function,
+		and these hosts must call scsi_request_sense(SCpnt) to keep
+		the command alive.
 	*/ 
 
-	int (* reset)(void);
+	int (* reset)(Scsi_Cmnd *);
 	/*
 		This function is used to select synchronous communications,
 		which will result in a higher data throughput.  Not implemented
diff --git a/drivers/scsi/pas16.h b/drivers/scsi/pas16.h
index d3b9bb0..1ebacb8 100644
--- a/drivers/scsi/pas16.h
+++ b/drivers/scsi/pas16.h
@@ -119,7 +119,7 @@
 int pas16_detect(int);
 const char *pas16_info(void);
 int pas16_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
-int pas16_reset(void);
+int pas16_reset(Scsi_Cmnd *);
 
 #ifndef NULL
 #define NULL 0
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index ada400a..9bf092a 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -85,6 +85,7 @@
 #define WAS_SENSE	0x04
 #define IS_RESETTING	0x08
 #define ASKED_FOR_SENSE 0x10
+/* #define NEEDS_JUMPSTART 0x20  defined in hosts.h */
 
 /*
  *	This is the number  of clock ticks we should wait before we time out 
@@ -698,6 +699,9 @@
 	int clock;
 #endif
 
+	if ((unsigned long) &SCpnt < current->kernel_stack_page)
+	  panic("Kernel stack overflow.");
+
 	host = SCpnt->host;
 
 /*
@@ -881,13 +885,14 @@
 	SCpnt->flags |= (WAS_RESET | IS_RESETTING);
 	scsi_reset(SCpnt);
 	
-#if 0
 #ifdef DEBUG
 	printk("performing request sense\n");
 #endif
 	
-	scsi_request_sense (SCpnt);
-#endif
+	if(SCpnt->flags & NEEDS_JUMPSTART) {
+	  SCpnt->flags &= ~NEEDS_JUMPSTART;
+	  scsi_request_sense (SCpnt);
+	};
 }
 	
 	
@@ -1344,14 +1349,14 @@
 				  SCpnt1 = SCpnt1->next;
 				};
 
-				temp = host->hostt->reset();			
+				temp = host->hostt->reset(SCpnt);	
 				}				
 			else
 				{
 				host->host_busy++;
 	
 				sti();
-				temp = host->hostt->reset();
+				temp = host->hostt->reset(SCpnt);
 				host->last_reset = jiffies;
 				host->host_busy--;
 				}
diff --git a/drivers/scsi/scsi.h b/drivers/scsi/scsi.h
index 45a6c5c..08a2035 100644
--- a/drivers/scsi/scsi.h
+++ b/drivers/scsi/scsi.h
@@ -446,7 +446,7 @@
 extern unsigned long sg_init1(unsigned long, unsigned long);
 extern void sg_attach(Scsi_Device *);
 
-#if defined(MAJOR_NR) && (MAJOR_NR != 9)
+#if defined(MAJOR_NR) && (MAJOR_NR != SCSI_TAPE_MAJOR)
 static void end_scsi_request(Scsi_Cmnd * SCpnt, int uptodate, int sectors)
 {
 	struct request * req;
@@ -456,8 +456,8 @@
 	req = &SCpnt->request;
 	req->errors = 0;
 	if (!uptodate) {
-		printk(DEVICE_NAME " I/O error\n");
-		printk("dev %04x, sector %d\n",req->dev,req->sector);
+		printk(DEVICE_NAME " I/O error: dev %04x, sector %lu\n",
+		       req->dev,req->sector);
 	}
 
 	do {
diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
index ffda507..4fe973e 100644
--- a/drivers/scsi/scsi_debug.c
+++ b/drivers/scsi/scsi_debug.c
@@ -18,6 +18,7 @@
 
 #include <asm/system.h>
 #include <asm/io.h>
+
 #include "../block/blk.h"
 #include "scsi.h"
 #include "hosts.h"
@@ -25,8 +26,7 @@
 /* Number of real scsi disks that will be detected ahead of time */
 static int NR_REAL=-1;
 
-#define NR_BLK_DEV	12
-#define MAJOR_NR 8
+#define MAJOR_NR SCSI_DISK_MAJOR
 #define START_PARTITION 4
 #define SCSI_DEBUG_TIMER 20
 /* Number of jiffies to wait before completing a command */
@@ -487,7 +487,7 @@
   return 0;
 }
 
-int scsi_debug_reset(void)
+int scsi_debug_reset(Scsi_Cmnd * SCpnt)
 {
     int i;
     void (*my_done)(Scsi_Cmnd *);
diff --git a/drivers/scsi/scsi_debug.h b/drivers/scsi/scsi_debug.h
index 263fda3..725b37e 100644
--- a/drivers/scsi/scsi_debug.h
+++ b/drivers/scsi/scsi_debug.h
@@ -8,7 +8,7 @@
 int scsi_debug_abort(Scsi_Cmnd *, int);
 int scsi_debug_biosparam(int, int*);
 char *scsi_debug_info(void);
-int scsi_debug_reset(void);
+int scsi_debug_reset(Scsi_Cmnd *);
 
 #ifndef NULL
 	#define NULL 0
diff --git a/drivers/scsi/scsi_ioctl.c b/drivers/scsi/scsi_ioctl.c
index 64835f6..a5ea183 100644
--- a/drivers/scsi/scsi_ioctl.c
+++ b/drivers/scsi/scsi_ioctl.c
@@ -177,8 +177,7 @@
 	
 	SCpnt = allocate_device(NULL, dev->index, 1);
 
-	scsi_do_cmd(SCpnt,  cmd,  buf,  ((outlen > MAX_BUF) ? 
-			MAX_BUF : outlen),  scsi_ioctl_done,  MAX_TIMEOUT, 
+	scsi_do_cmd(SCpnt,  cmd,  buf, needed,  scsi_ioctl_done,  MAX_TIMEOUT, 
 			MAX_RETRIES);
 
 	if (SCpnt->request.dev != 0xfffe){
@@ -187,10 +186,20 @@
 	  while (SCpnt->request.dev != 0xfffe) schedule();
 	};
 
-	result = verify_area(VERIFY_WRITE, cmd_in, (outlen > MAX_BUF) ? MAX_BUF  : outlen);
-	if (result)
-		return result;
-	memcpy_tofs ((void *) cmd_in,  buf,  (outlen > MAX_BUF) ? MAX_BUF  : outlen);
+
+	/* If there was an error condition, pass the info back to the user. */
+	if(SCpnt->result) {
+	  result = verify_area(VERIFY_WRITE, cmd_in, sizeof(SCpnt->sense_buffer));
+	  if (result)
+	    return result;
+	  memcpy_tofs((void *) cmd_in,  SCpnt->sense_buffer, sizeof(SCpnt->sense_buffer));
+	} else {
+
+	  result = verify_area(VERIFY_WRITE, cmd_in, (outlen > MAX_BUF) ? MAX_BUF  : outlen);
+	  if (result)
+	    return result;
+	  memcpy_tofs ((void *) cmd_in,  buf,  (outlen > MAX_BUF) ? MAX_BUF  : outlen);
+	};
 	result = SCpnt->result;
 	SCpnt->request.dev = -1;  /* Mark as not busy */
 	if (buf) scsi_free(buf, needed);
@@ -249,6 +258,7 @@
 		case SCSI_IOCTL_PROBE_HOST:
 			return ioctl_probe(dev->host, arg);
 		case SCSI_IOCTL_SEND_COMMAND:
+			if(!suser())  return -EACCES;
 			return ioctl_command((Scsi_Device *) dev, arg);
 		case SCSI_IOCTL_DOORLOCK:
 			if (!dev->removable || !dev->lockable) return 0;
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index 712cea6..7bb847a 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -17,9 +17,7 @@
 #include <linux/errno.h>
 #include <asm/system.h>
 
-
-#define MAJOR_NR 8
-
+#define MAJOR_NR SCSI_DISK_MAJOR
 #include "../block/blk.h"
 #include "scsi.h"
 #include "hosts.h"
@@ -204,9 +202,8 @@
   The SCpnt->request.nr_sectors field is always done in 512 byte sectors,
   even if this really isn't the case.
 */
-	    printk("sd.c: linked page request. (%x %x)",
+	    panic("sd.c: linked page request (%lx %x)",
 		  SCpnt->request.sector, this_count);
-	    panic("Aiiiiiiiiiiiieeeeeeeee");
 	  }
       }
     end_scsi_request(SCpnt, 1, this_count);
@@ -262,13 +259,15 @@
 
 	  if ((SCpnt->sense_buffer[0] & 0x7f) == 0x70) {
 	    if ((SCpnt->sense_buffer[2] & 0xf) == UNIT_ATTENTION) {
+	      if(rscsi_disks[DEVICE_NR(SCpnt->request.dev)].device->removable) {
 	      /* detected disc change.  set a bit and quietly refuse	*/
 	      /* further access.					*/
 	      
-	      rscsi_disks[DEVICE_NR(SCpnt->request.dev)].device->changed = 1;
-	      end_scsi_request(SCpnt, 0, this_count);
-	      requeue_sd_request(SCpnt);
-	      return;
+		rscsi_disks[DEVICE_NR(SCpnt->request.dev)].device->changed = 1;
+		end_scsi_request(SCpnt, 0, this_count);
+		requeue_sd_request(SCpnt);
+		return;
+	      }
 	    }
 	  }
 	  
@@ -705,6 +704,7 @@
 	 SCpnt->sense_buffer[2] == NOT_READY) {
 	int time1;
 	if(!spintime){
+	  printk( "sd%d: Spinning up disk...", i );
 	  cmd[0] = START_STOP;
 	  cmd[1] = (rscsi_disks[i].device->lun << 5) & 0xe0;
 	  cmd[1] |= 1;  /* Return immediately */
@@ -726,8 +726,15 @@
 
 	time1 = jiffies;
 	while(jiffies < time1 + 100); /* Wait 1 second for next try */
+	printk( "." );
       };
-    } while(the_result && spintime && spintime+1500 < jiffies);
+    } while(the_result && spintime && spintime+5000 > jiffies);
+    if (spintime) {
+       if (the_result)
+           printk( "not responding...\n" );
+       else
+           printk( "ready\n" );
+    }
   };  /* current == task[0] */
 
 
diff --git a/drivers/scsi/seagate.c b/drivers/scsi/seagate.c
index d5fb319..32baed7 100644
--- a/drivers/scsi/seagate.c
+++ b/drivers/scsi/seagate.c
@@ -34,7 +34,7 @@
  *
  * -DARBITRATE will cause the host adapter to arbitrate for the 
  *	bus for better SCSI-II compatability, rather than just 
- *	waiting for BUS FREE and then doing it's thing.  Should
+ *	waiting for BUS FREE and then doing its thing.  Should
  *	let us do one command per Lun when I integrate my 
  *	reorganization changes into the distribution sources.
  *
@@ -884,7 +884,7 @@
 			if (STATUS & STAT_BSY) {
 				printk("scsi%d : BST asserted after we've been aborted.\n",
 					hostno);
-				seagate_st0x_reset();
+				seagate_st0x_reset(NULL);
 				return retcode(DID_RESET);
 			}
 			return retcode(st0x_aborted);
@@ -1478,7 +1478,7 @@
 #ifdef notyet
 	if (st0x_aborted) {
 		if (STATUS & STAT_BSY) {	
-			seagate_st0x_reset();
+			seagate_st0x_reset(NULL);
 			st0x_aborted = DID_RESET;
 		} 
 		abort_confirm = 1;
@@ -1560,7 +1560,7 @@
 	the seagate_st0x_reset function resets the SCSI bus
 */
 	
-int seagate_st0x_reset (void)
+int seagate_st0x_reset (Scsi_Cmnd * SCpnt)
 	{
 	unsigned clock;
 	/*
@@ -1590,6 +1590,7 @@
 #ifdef DEBUG
 	printk("SCSI bus reset.\n");
 #endif
+	if(SCpnt) SCpnt->flags |= NEEDS_JUMPSTART;
 	return 0;
 	}
 
diff --git a/drivers/scsi/seagate.h b/drivers/scsi/seagate.h
index 0be87ab..fff3e39 100644
--- a/drivers/scsi/seagate.h
+++ b/drivers/scsi/seagate.h
@@ -18,7 +18,7 @@
 
 int seagate_st0x_abort(Scsi_Cmnd *, int);
 const char *seagate_st0x_info(void);
-int seagate_st0x_reset(void); 
+int seagate_st0x_reset(Scsi_Cmnd *); 
 
 #ifndef NULL
 	#define NULL 0
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index 7509699..39e11d4 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -24,8 +24,6 @@
 #include "scsi_ioctl.h"
 #include "sg.h"
 
-#define MAJOR_NR 21
-
 int NR_SG=0;
 int MAX_SG=0;
 
@@ -296,9 +294,10 @@
 /* Driver initialization */
 unsigned long sg_init(unsigned long mem_start, unsigned long mem_end)
  {
-  if (register_chrdev(MAJOR_NR,"sg",&sg_fops)) 
+  if (register_chrdev(SCSI_GENERIC_MAJOR,"sg",&sg_fops)) 
    {
-    printk("Unable to get major %d for Generic SCSI device\n",MAJOR_NR);
+    printk("Unable to get major %d for generic SCSI device\n",
+	   SCSI_GENERIC_MAJOR);
     return mem_start;
    }
   if (NR_SG == 0) return mem_start;
diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c
index b86e30d..59a0cd2 100644
--- a/drivers/scsi/sr.c
+++ b/drivers/scsi/sr.c
@@ -20,8 +20,7 @@
 #include <linux/errno.h>
 #include <asm/system.h>
 
-#define MAJOR_NR 11
-
+#define MAJOR_NR SCSI_CDROM_MAJOR
 #include "../block/blk.h"
 #include "scsi.h"
 #include "hosts.h"
@@ -127,7 +126,7 @@
 			int offset;
 			offset = (SCpnt->request.sector % 4) << 9;
 			memcpy((char *)SCpnt->request.buffer, 
-			       SCpnt->buffer + offset, 
+			       (char *)SCpnt->buffer + offset, 
 			       this_count << 9);
 			/* Even though we are not using scatter-gather, we look
 			   ahead and see if there is a linked request for the
@@ -139,7 +138,7 @@
 			   SCpnt->request.bh->b_reqnext &&
 			   SCpnt->request.bh->b_reqnext->b_size == 1024) {
 			  memcpy((char *)SCpnt->request.bh->b_reqnext->b_data, 
-				 SCpnt->buffer + 1024, 
+				 (char *)SCpnt->buffer + 1024, 
 				 1024);
 			  this_count += 2;
 			};
@@ -173,11 +172,8 @@
 			{	 
 			SCpnt->request.errors = 0;
 			if (!SCpnt->request.bh)
-			  {
-			    printk("sr.c: linked page request. (%x %x)",
+			    panic("sr.c: linked page request (%lx %x)",
 				  SCpnt->request.sector, this_count);
-			    panic("Aiiiiiiiiiiiieeeeeeeee");
-			  }
 			}
 
 		  end_scsi_request(SCpnt, 1, this_count);  /* All done */
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
index 06e8148..a138655 100644
--- a/drivers/scsi/st.c
+++ b/drivers/scsi/st.c
@@ -47,7 +47,7 @@
 #include <asm/segment.h>
 #include <asm/system.h>
 
-#define MAJOR_NR 9
+#define MAJOR_NR SCSI_TAPE_MAJOR
 #include "../block/blk.h"
 #include "scsi.h"
 #include "scsi_ioctl.h"
diff --git a/drivers/scsi/t128.h b/drivers/scsi/t128.h
index 39e1ba2..453118a 100644
--- a/drivers/scsi/t128.h
+++ b/drivers/scsi/t128.h
@@ -96,7 +96,7 @@
 int t128_detect(int);
 const char *t128_info(void);
 int t128_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
-int t128_reset(void);
+int t128_reset(Scsi_Cmnd *);
 
 #ifndef NULL
 #define NULL 0
diff --git a/drivers/scsi/ultrastor.c b/drivers/scsi/ultrastor.c
index 9b03cf5..d59398b 100644
--- a/drivers/scsi/ultrastor.c
+++ b/drivers/scsi/ultrastor.c
@@ -926,7 +926,7 @@
 
 }
 
-int ultrastor_reset(void)
+int ultrastor_reset(Scsi_Cmnd * SCpnt)
 {
     int flags;
     register int i;
@@ -934,7 +934,11 @@
     printk("US14F: reset: called\n");
 #endif
 
-    if(config.slot) return 0;  /* Do not attempt a reset for the 24f */
+    if(config.slot) {
+      if (SCpnt) SCpnt->flags |= NEEDS_JUMPSTART;
+      return 0;  /* Do not attempt a reset for the 24f */
+    };
+
     save_flags(flags);
     cli();
 
@@ -1011,7 +1015,7 @@
 	printk("Ux4F interrupt: bad MSCP address %x\n", (unsigned int) mscp);
 	/* A command has been lost.  Reset and report an error
 	   for all commands.  */
-	ultrastor_reset();
+	ultrastor_reset(NULL);
 	return;
     }
 #endif
diff --git a/drivers/scsi/ultrastor.h b/drivers/scsi/ultrastor.h
index dbbaa7c..0731227 100644
--- a/drivers/scsi/ultrastor.h
+++ b/drivers/scsi/ultrastor.h
@@ -17,7 +17,7 @@
 const char *ultrastor_info(void);
 int ultrastor_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
 int ultrastor_abort(Scsi_Cmnd *, int);
-int ultrastor_reset(void);
+int ultrastor_reset(Scsi_Cmnd *);
 int ultrastor_biosparam(int, int, int *);
 
 #define ULTRASTOR_14F_MAX_SG 16
diff --git a/drivers/scsi/wd7000.c b/drivers/scsi/wd7000.c
index bc21559..059dbfb 100644
--- a/drivers/scsi/wd7000.c
+++ b/drivers/scsi/wd7000.c
@@ -592,11 +592,16 @@
 }
 
 
-int wd7000_reset(void)
+/* We do not implement a reset function here, but the upper level code assumes
+   that it will get some kind of response for the command in SCpnt.  We must
+   oblige, or the command will hang the scsi system */
+
+int wd7000_reset(Scsi_Cmnd * SCpnt)
 {
 #ifdef DEBUG
     printk("wd7000_reset\n");
 #endif
+    if (SCpnt) SCpnt->flags |= NEEDS_JUMPSTART;
     return 0;
 }
 
diff --git a/drivers/scsi/wd7000.h b/drivers/scsi/wd7000.h
index bc27c61..ab8b2a5 100644
--- a/drivers/scsi/wd7000.h
+++ b/drivers/scsi/wd7000.h
@@ -172,7 +172,7 @@
 int wd7000_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
 int wd7000_abort(Scsi_Cmnd *, int);
 const char *wd7000_info(void);
-int wd7000_reset(void);
+int wd7000_reset(Scsi_Cmnd *);
 int wd7000_biosparam(int, int, int*);
 
 #ifndef NULL
diff --git a/drivers/sound/.blurb b/drivers/sound/.blurb
new file mode 100644
index 0000000..1b2fa63
--- /dev/null
+++ b/drivers/sound/.blurb
@@ -0,0 +1,8 @@
+NOTE!	This driver version is not compatible with the version 1.0c.
+	This means you have to use the latest version of the snd-util
+	package. The earlier ones (from 1.0) will not work. If you have
+	other programs using ioctl calls of the driver, they must be
+	recompiled. Most of them will not work without some source
+	modifications.
+
+		Hannu
diff --git a/drivers/sound/.indent.pro b/drivers/sound/.indent.pro
new file mode 100644
index 0000000..f10c3dd
--- /dev/null
+++ b/drivers/sound/.indent.pro
@@ -0,0 +1,11 @@
+-bad 
+-bap 
+-fca
+-fc1 
+-cdb 
+-sc 
+-bl 
+-psl 
+-di16
+-lp
+-ip5
diff --git a/drivers/sound/COPYING b/drivers/sound/COPYING
new file mode 100644
index 0000000..d1509c5
--- /dev/null
+++ b/drivers/sound/COPYING
@@ -0,0 +1,25 @@
+/*
+ * Copyright by Hannu Savolainen 1993
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
diff --git a/drivers/sound/Makefile b/drivers/sound/Makefile
index 85e5ccd..76d1857 100644
--- a/drivers/sound/Makefile
+++ b/drivers/sound/Makefile
@@ -1,14 +1,13 @@
-# Makefile for the stub version of Linux sound card driver
-#
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
+# Makefile for the Linux sound card driver
 #
 # Note 2! The CFLAGS definitions are now inherited from the
 # parent makes. (hopefully)
 #
 #
 
+VERSION		= 2.0
+USRINCDIR	= /usr/include
+
 .c.s:
 	$(CC) $(CFLAGS) -S $<
 .s.o:
@@ -16,31 +15,47 @@
 .c.o:
 	$(CC) $(CFLAGS) -c $<
 
-OBJS	= sound_stub.o
+OBJS   = soundcard.o dsp.o audio.o dmabuf.o sb_dsp.o dev_table.o \
+	 opl3.o sequencer.o midibuf.o sb_card.o pas2_card.o adlib_card.o \
+	 pas2_pcm.o pas2_mixer.o pas2_midi.o gus_card.o gus_wave.o mpu401.o \
+	 gus_midi.o gus_vol.o patmgr.o
+
+all:	local.h sound.a
 
 sound.a: $(OBJS) 
+	-rm -f sound.a
 	$(AR) rcs sound.a $(OBJS)
 	sync
 
-clean:
-	rm -f core *.o *.a
+indent:
+	for n in *.c;do echo indent $$n;indent $$n;done
 
-config:
-	-@if [ -n "$(CONFIG_SOUND)" ] ;then make notice; fi
+local.h:
+	rm -f configure
+	$(MAKE) config
+	$(MAKE) dep
 
-notice:
-	@echo
-	@echo
-	@echo "WARNING!	You have attempted to compile the sound driver"
-	@echo "		to your kernel. The driver is not included in"
-	@echo "		the kernel distribution. You have to install"
-	@echo "		the sound driver and to run "make config" again."
-	@echo "		Otherwise the sound driver will not be included"
-	@echo
-	@echo "		The sound driver is available at nic.funet.fi"
-	@echo "		in directory pub/OS/Linux/xtra/snd-kit. It "
-	@echo "		should be also at the other Linux ftp sites."
-	@echo
+config: configure
+	@./configure > local.h
+	@echo \#define SOUND_VERSION_STRING \"$(VERSION)\" >> local.h
+	@echo \#define SOUND_CONFIG_DATE \"`date`\" >> local.h
+	@echo \#define SOUND_CONFIG_BY \"`whoami`\" >> local.h
+	@echo \#define SOUND_CONFIG_HOST \"`hostname`\" >> local.h
+	@echo \#define SOUND_CONFIG_DOMAIN \"`domainname`\" >> local.h
+
+clrconf:
+	rm -f local.h .depend os.h soundcard.c
+
+configure: configure.c
+	$(HOSTCC) -o configure configure.c
+	@cat .blurb
 
 dep:
-	@touch .depend
+	$(CPP) -M *.c > .depend
+
+#
+# include a dependency file if one exists
+#
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
diff --git a/drivers/sound/Readme b/drivers/sound/Readme
new file mode 100644
index 0000000..1357cc3
--- /dev/null
+++ b/drivers/sound/Readme
@@ -0,0 +1,272 @@
+Release notes for the Linux Sound Driver 2.1
+-----------------------------------------------
+
+This version is just version 2.0 with some kind of SB16
+support. The SB16 works now in 8 bit mono mode up to speed
+44100 Hz. Stereo recording and playback is not supported with
+the SB16 yet. Also the 16 bit mode is missing.
+
+You will need the snd-util-2.0.tar.gz and snd-data-0.1.tar.Z
+packages to use this driver. They should be in the same
+ftp site or BBS from where you got this driver. For
+example at nic.funet.fi:pub/OS/Linux/*.
+
+If you are looking for the installation instructions, please
+look at linux/Readme.
+
+Welcome to use the Gravis UltraSound driver for Linux. This
+driver still supports the same cards than version 1.0c 
+(SoundBlaster, SB Pro, Pro Audio Spectrum 16 and AdLib). 
+In addition there is rather limited support for MPU-401
+(and compatible) midi cards. Also the OPL-3 synthesizer
+of the SB Pro and PAS16 cards is now supported in the 4 OP
+modes.
+Most of the features of the /dev/sequencer device file are
+available just for GUS owners. 
+
+The SoundBlaster 16 and SB 16 ASP cards are not supported.
+They could work in mono mode with speeds < 22 kHz. 
+The OPL-3 chicp of the SB 16 should work but it doesn't.
+
+NOTE!	There are separate driver for CD-ROMS supported by
+	some soundcards. The driver for CDU31A (Fusion 16) is
+	called cdu31a-0.6.diff.z. It will be contained in the
+	Linux version 0.99.12. The driver for the CD-ROM of SB Pro
+	is sbpcd0.4.tar.gz (these were the latest versions when I wrote
+	this). These files should be at least at sunsite.unc.edu.
+	Also the SCSI interface of the PAS16 should be supported by
+	Linux 0.99.13k and later.
+
+	There is also a driver for joystick. Look for file joystick-0.5.tar.gz
+	(sunsite).
+
+
+Compatibility with the earlier versions
+---------------------------------------
+
+IMPORTANT!!!!!!!!!!!!!!!!!!!!!!
+
+This version is not binary or source compatible with the version 1.0c.
+
+The ioctl() interface has changed completely since version 1.0c. All
+programs using this driver must be at least recompiled. 
+The snd-util-2.0 package contains some utilities for this version.
+
+The version 1.0c and earlier used a 'nonportable' ioctl calling scheme
+where the input argument was passed by value and the output value was
+returned as the functional return. For example setting the speed of
+/dev/dsp were done as the following:
+
+	int actual_speed;
+	actual_speed = ioctl(fd, SOUND_PCM_WRITE_RATE, 44100);
+
+After version 1.99.0 this must be done as the following:
+
+	int actual_speed = 44100;
+	ioctl(fd, SOUND_PCM_WRITE_RATE, &actual_speed);
+
+If you have an application written for the version 1.0, you should search
+for the strings SNDCTL_ and SOUND_ and to check the parameters. 
+The following ioctl calls have changed:
+
+	SNDCTL_SEQ_GETOUTCOUNT
+	SNDCTL_SEQ_GETINCOUNT
+	SNDCTL_SEQ_TESTMIDI
+	SNDCTL_DSP_SPEED
+	SNDCTL_DSP_STEREO
+	SNDCTL_DSP_GETBLKSIZE
+	SNDCTL_DSP_SAMPLESIZE
+	SOUND_PCM_WRITE_CHANNELS
+	SOUND_PCM_WRITE_FILTER
+	SOUND_PCM_READ_RATE
+	SOUND_PCM_READ_CHANNELS
+	SOUND_PCM_READ_BITS
+	SOUND_PCM_READ_FILTER
+	SOUND_PCM_WRITE_BITS
+	SOUND_PCM_WRITE_RATE
+	SOUND_MIXER_READ_*	(several ones)
+	SOUND_MIXER_WRITE_*	(several ones)
+
+Since the this version will support more than one synthesizer devices
+at the same time, the ioctl(SNDCTL_FM_LOAD_INSTR) is obsolete. In addition
+there is some new fields which must be initialized. Look at the sbiset.c in
+the snd-util-2.0 package for further info.
+
+This version is almost 100% compatible with the alpha test version (1.99.9). The
+difference is in the installation procedure.
+
+Using the driver under other environments than Linux
+----------------------------------------------------
+
+**** There is some ISC stuff in this driver. Please stay away ****
+This stuff is here just because I want to be in sync with the porters. This
+ports don't work yet.
+The ISC port is by Andy Warner (andy@harris.nl). 
+
+There FreeBSD port is by 
+There is a FreeBSD port by Jim Lowe (james@blatz.cs.uwm.edu) in the directory
+freebsd. (Based on my 386bsd port which was in the previous release (1.99.9).
+It's should work but it requires still some testing. It should work
+with the NetBSD 0.9 also but propably not with the 386bsd 0.1.
+There has been some problems with GUS in SCO and NetBSD.
+In addition I'm preparing a SCO port myself. Yet again, these ports
+are little incomplete and untested. It could be possible to get them to work
+with finite amount of hacking but be careful. 
+
+New features
+------------
+
+There is also some changes which make this version more usable than
+the version 1.0c.
+
+- /dev/dsp and /dev/audio
+
+The DMA buffering is now little bit more intelligent than earlier. The
+buffer size is selected run-time so that a buffer holds data for 0.5 to
+1.0 seconds of recording or playback. This makes recording more comfortable
+than with version 1.0. With the previous version there was sometimes more
+than 10 seconds of delay before the driver returned the first input byte.
+
+There is also support for more than one digitized voice devices. The device
+files /dev/dsp1 and /dev/audio1 (minor 19 and 20) are available with PAS16. 
+The /dev/dsp (/dev/audio) is connected to the PCM circuit of the PAS16 itself 
+and the /dev/dsp1 (/dev/audio1) to the SB emulation of PAS16 card. Two
+dsp/audio devices are available also if you have combination of SB and GUS.
+With GUS and PAS16 you will have even three dsp/audio devices. These devices
+can be used independently and can be active at the same time (3 channels
+at the same time propably don't work).
+
+The dsp/audio support of PAS16 should be much cleaner now since the
+constant clicking sound between the DMA blocks (about once per second) has
+been eliminated.
+
+The stereo playback of GUS doesn't work perfectly. There is lot of 
+clicking in the output.
+
+- /dev/mixer
+
+No changes.
+
+There is no mixer for the GUS yet.
+
+- /dev/sequencer
+
+This part has the most changes. Mostly to support the rich
+features of the Gravis UltraSound. There is also the support
+for the OPL-3 synthesizer chip.
+
+- /dev/sndstat
+
+This is a new devicefile for debugging purposes. A better place for
+it is in the /proc -directory but I was just too lazy to implement it
+properly. The /dev/sndstat (major 14, minor 6) is a file which returns
+info about the current configuration (see the example below). If you
+send me a error/problem report, please include a printout from this 
+device to your message (cat /dev/sndstat).
+
+Note!	This device file is currently present only in the Linux version
+	of this driver.
+
+------ cut here --- cat /dev/sndstat example --------
+Sound Driver:1.99.7 (Fri Jul 9 17:01:47 GMT 1993 root@lucifer.savolai.fi)
+Config options: 0x00000d4b
+
+Major number: 14
+HW config: 
+Type 4: Gravis Ultrasound  at 0x210 irq 15 drq 6
+Type 3: ProAudioSpectrum  at 0x388 irq 10 drq 3
+Type 2: SoundBlaster  at 0x220 irq 7 drq 1
+Type 1: AdLib  at 0x388 irq 0 drq 0
+
+PCM devices:
+00: Gravis UltraSound
+01: Pro Audio Spectrum
+02: SoundBlaster 2.0
+
+Synth devices:
+00: Gravis UltraSound
+01: Yamaha OPL-3
+
+Midi devices:
+00: Gravis UltraSound
+01: Pro Audio Spectrum
+
+Mixer(s) installed
+------ cut here ---- End of Example -----------
+
+
+Known bugs
+----------
+
+- There was clicking during stereo playback to /dev/dsp with GUS.
+  * Fixed in 1.99.9 *
+- It's not possible to open /dev/dsp (or /dev/audio) while the 
+  /dev/sequencer is open for output and GUS is the only soundcard
+  installed. It's possible if /dev/dsp is opened before /dev/sequencer
+  but at this time the GUS is not available for access via /dev/sequencer.
+  This is a limitation of the driver.
+- MPU-401 driver hangs the computer on boot if there is no MPU-401 installed.
+  It uses by default the I/O port 0x330 whic is used by Adaptec 1542 SCSI
+  adapter.
+- The /dev/sequencer playback to GUS sounds sometimes rather weird. Hitting
+  ^C and playing again should solve this problem. This is propably caused by
+  incompatibilities between GUS and certain VLB motherboards. Try to avoid
+  switching between VTs while patches are being loaded to the GUS.
+- There was some problems with GUS and Mitsumi CD in version 1.99.8. Fixed
+  in 1.99.9.
+- /dev/audio sounded like stereo with GUS. Fixed in 1.99.9.
+- There is a skeleton of the patch manager support. It don't work in
+  this version. 
+
+
+Future development
+------------------
+
+- The SB16 card should be fully supported some day. The SDK for it is
+  not available yet so it's not possible to implement the 16 bit mode yet.
+- Since this driver is no longer just the Linux Sound Driver, it's time
+  to give it a new name. I have planned to use name VoxWare.
+- I'm writing a Hacker's guide to the VoxWare sound driver. Should
+  be ready within this year (alpha version).
+- Completion of the ISC, SCO and BSD ports. Port to SVR4.2.
+- I'm interested to implement/include support for new soundcards and 
+  operating systems. 
+
+  Hint for the soundcard and OS manufacturers:
+  I'm collecting soundcards (high end ones) and SDKs for them. In
+  addition I'm collecting PC operating systems. I will be happy if
+  somebody sends me such items. In addition such kind of donation
+  makes it easier to change the VoxWare driver to support your
+  soundcard or operating system. However, please contact me before
+  sending anything.
+
+I will propably release some fix versions within this and next year. At
+least when the non-Linux versions get ready. The next major release (3.0)
+will be quite complete rewrite and released after about a year (end of 94 or
+beginning of 95).
+
+
+Contributors
+------------
+
+This driver contains code by several contributors. In addition several other
+persons have given usefull suggestions. The following is a list of major
+contributors. (I could have forgotten some names.)
+
+	Craig Metz	1/2 of the PAS16 Mixer and PCM support
+	Rob Hooft	Volume computation algorithm for the FM synth.
+	Mika Liljeberg	uLaw encoding and decoding routines
+	Greg Lee	Volume computation algorithm for the GUS and
+			lot's of valuable suggestions.
+	Andy Warner	ISC port
+	Jim Lowe	FreeBSD port
+
+Regards,
+
+Hannu Savolainen
+hsavolai@cs.helsinki.fi
+
+Snail mail:	Hannu Savolainen
+		Pallaksentie 4 A 2
+		00970 Helsinki
+		Finland
diff --git a/drivers/sound/adlib_card.c b/drivers/sound/adlib_card.c
new file mode 100644
index 0000000..29e521e
--- /dev/null
+++ b/drivers/sound/adlib_card.c
@@ -0,0 +1,52 @@
+
+/*
+ * linux/kernel/chr_drv/sound/adlib_card.c
+ * 
+ * Detection routine for the AdLib card.
+ * 
+ * Copyright by Hannu Savolainen 1993
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer. 2.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * 
+ */
+
+#include "sound_config.h"
+
+#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_YM3812)
+
+long
+attach_adlib_card (long mem_start, struct address_info *hw_config)
+{
+
+  if (opl3_detect (FM_MONO))
+    {
+      mem_start = opl3_init (mem_start);
+    }
+  return mem_start;
+}
+
+int
+probe_adlib (struct address_info *hw_config)
+{
+  return opl3_detect (FM_MONO);
+}
+
+#endif
diff --git a/drivers/sound/audio.c b/drivers/sound/audio.c
new file mode 100644
index 0000000..775e6ab
--- /dev/null
+++ b/drivers/sound/audio.c
@@ -0,0 +1,298 @@
+/*
+ * linux/kernel/chr_drv/sound/audio.c
+ * 
+ * Device file manager for /dev/audio
+ * 
+ * Copyright by Hannu Savolainen 1993
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer. 2.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * 
+ */
+
+#include "sound_config.h"
+
+#ifdef CONFIGURE_SOUNDCARD
+#ifndef EXCLUDE_AUDIO
+
+#include "ulaw.h"
+
+#define ON		1
+#define OFF		0
+
+static int      wr_buff_no[MAX_DSP_DEV];	/* != -1, if there is a
+						 * incomplete output block */
+static int      wr_buff_size[MAX_DSP_DEV], wr_buff_ptr[MAX_DSP_DEV];
+static char    *wr_dma_buf[MAX_DSP_DEV];
+
+int
+audio_open (int dev, struct fileinfo *file)
+{
+  int             mode;
+  int             ret;
+
+  dev = dev >> 4;
+  mode = file->mode & O_ACCMODE;
+
+  if ((ret = DMAbuf_open (dev, mode)) < 0)
+    return ret;
+
+  wr_buff_no[dev] = -1;
+  return ret;
+}
+
+void
+audio_release (int dev, struct fileinfo *file)
+{
+  int             mode;
+
+  dev = dev >> 4;
+  mode = file->mode & O_ACCMODE;
+
+  if (wr_buff_no[dev] >= 0)
+    {
+      DMAbuf_start_output (dev, wr_buff_no[dev], wr_buff_ptr[dev]);
+
+      wr_buff_no[dev] = -1;
+    }
+
+  DMAbuf_release (dev, mode);
+}
+
+#ifdef NO_INLINE_ASM
+static void
+translate_bytes (const unsigned char *table, unsigned char *buff, unsigned long n)
+{
+  unsigned long   i;
+
+  for (i = 0; i < n; ++i)
+    buff[i] = table[buff[i]];
+}
+
+#else
+extern inline void
+translate_bytes (const void *table, void *buff, unsigned long n)
+{
+  __asm__ ("cld\n"
+	   "1:\tlodsb\n\t"
+	   "xlatb\n\t"
+	   "stosb\n\t"
+	   "loop 1b\n\t":
+	   :"b" ((long) table), "c" (n), "D" ((long) buff), "S" ((long) buff)
+	   :"bx", "cx", "di", "si", "ax");
+}
+
+#endif
+
+int
+audio_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
+{
+  int             c, p, l;
+  int             err;
+
+  dev = dev >> 4;
+
+  p = 0;
+  c = count;
+
+  if (!count)			/* Flush output */
+    {
+      if (wr_buff_no[dev] >= 0)
+	{
+	  DMAbuf_start_output (dev, wr_buff_no[dev], wr_buff_ptr[dev]);
+
+	  wr_buff_no[dev] = -1;
+	}
+      return 0;
+    }
+
+  while (c)
+    {				/* Perform output blocking */
+      if (wr_buff_no[dev] < 0)	/* There is no incomplete buffers */
+	{
+	  if ((wr_buff_no[dev] = DMAbuf_getwrbuffer (dev, &wr_dma_buf[dev], &wr_buff_size[dev])) < 0)
+	    return wr_buff_no[dev];
+	  wr_buff_ptr[dev] = 0;
+	}
+
+      l = c;
+      if (l > (wr_buff_size[dev] - wr_buff_ptr[dev]))
+	l = (wr_buff_size[dev] - wr_buff_ptr[dev]);
+
+      COPY_FROM_USER (&wr_dma_buf[dev][wr_buff_ptr[dev]], buf, p, l);
+
+      /* Insert local processing here */
+
+#ifdef linux
+      /* This just allows interrupts while the conversion is running */
+      __asm__ ("sti");
+#endif
+      translate_bytes (ulaw_dsp, &wr_dma_buf[dev][wr_buff_ptr[dev]], l);
+
+      c -= l;
+      p += l;
+      wr_buff_ptr[dev] += l;
+
+      if (wr_buff_ptr[dev] >= wr_buff_size[dev])
+	{
+	  if ((err = DMAbuf_start_output (dev, wr_buff_no[dev], wr_buff_ptr[dev])) < 0)
+	    return err;
+
+	  wr_buff_no[dev] = -1;
+	}
+
+    }
+
+  return count;
+}
+
+int
+audio_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
+{
+  int             c, p, l;
+  char           *dmabuf;
+  int             buff_no;
+
+  dev = dev >> 4;
+  p = 0;
+  c = count;
+
+  while (c)
+    {
+      if ((buff_no = DMAbuf_getrdbuffer (dev, &dmabuf, &l)) < 0)
+	return buff_no;
+
+      if (l > c)
+	l = c;
+
+      /* Insert any local processing here. */
+#ifdef linux
+      /* This just allows interrupts while the conversion is running */
+      __asm__ ("sti");
+#endif
+
+      translate_bytes (dsp_ulaw, dmabuf, l);
+
+      COPY_TO_USER (buf, p, dmabuf, l);
+
+      DMAbuf_rmchars (dev, buff_no, l);
+
+      p += l;
+      c -= l;
+    }
+
+  return count - c;
+}
+
+int
+audio_ioctl (int dev, struct fileinfo *file,
+	     unsigned int cmd, unsigned int arg)
+{
+  dev = dev >> 4;
+
+  switch (cmd)
+    {
+    case SNDCTL_DSP_SYNC:
+      if (wr_buff_no[dev] >= 0)
+	{
+	  DMAbuf_start_output (dev, wr_buff_no[dev], wr_buff_ptr[dev]);
+
+	  wr_buff_no[dev] = -1;
+	}
+      return DMAbuf_ioctl (dev, cmd, arg, 0);
+      break;
+
+    case SNDCTL_DSP_POST:
+      if (wr_buff_no[dev] >= 0)
+	{
+	  DMAbuf_start_output (dev, wr_buff_no[dev], wr_buff_ptr[dev]);
+
+	  wr_buff_no[dev] = -1;
+	}
+      return 0;
+      break;
+
+    case SNDCTL_DSP_RESET:
+      wr_buff_no[dev] = -1;
+      return DMAbuf_ioctl (dev, cmd, arg, 0);
+      break;
+
+    default:
+#if 1
+      return RET_ERROR (EIO);
+#else
+      return DMAbuf_ioctl (dev, cmd, arg, 0);
+#endif
+    }
+}
+
+long
+audio_init (long mem_start)
+{
+  return mem_start;
+}
+
+#else
+/* Stub versions */
+
+int
+audio_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
+{
+  return RET_ERROR (EIO);
+}
+
+int
+audio_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
+{
+  return RET_ERROR (EIO);
+}
+
+int
+audio_open (int dev, struct fileinfo *file)
+  {
+    return RET_ERROR (ENXIO);
+  }
+
+void
+audio_release (int dev, struct fileinfo *file)
+  {
+  };
+int
+audio_ioctl (int dev, struct fileinfo *file,
+	     unsigned int cmd, unsigned int arg)
+{
+  return RET_ERROR (EIO);
+}
+
+int
+audio_lseek (int dev, struct fileinfo *file, off_t offset, int orig)
+{
+  return RET_ERROR (EIO);
+}
+
+long
+audio_init (long mem_start)
+{
+  return mem_start;
+}
+
+#endif
+
+#endif
diff --git a/drivers/sound/configure.c b/drivers/sound/configure.c
new file mode 100644
index 0000000..e27bf75
--- /dev/null
+++ b/drivers/sound/configure.c
@@ -0,0 +1,500 @@
+/*
+ * sound/configure.c	- Configuration program for the Linux Sound Driver
+ * 
+ * Copyright by Hannu Savolainen 1993
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer. 2.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * 
+ */
+
+#include <stdio.h>
+
+#define B(x)	(1 << (x))
+
+/*
+ * Option numbers
+ */
+
+#define OPT_PAS		0
+#define OPT_SB		1
+#define OPT_ADLIB	2
+#define OPT_LAST_MUTUAL	2
+
+#define OPT_GUS		3
+#define OPT_MPU401	4
+
+#define OPT_HIGHLEVEL   5
+#define OPT_SBPRO	5
+#define OPT_AUDIO	6
+#define OPT_MIDI_AUTO	7
+#define OPT_MIDI	8
+#define OPT_YM3812_AUTO	9	/* Select this automaticly if user selects
+				 * MIDI or AdLib driver */
+#define OPT_YM3812	10	/* Select this if the previous one was not
+				 * selected */
+#define OPT_SEQUENCER	11
+#define OPT_CHIP_MIDI   12	/* New support added at UW - Milwauklee UW -
+				 * Milwauklee */
+#define OPT_LAST	11
+
+#define ANY_DEVS (B(OPT_AUDIO)|B(OPT_MIDI)|B(OPT_SEQUENCER)|B(OPT_GUS)|B(OPT_MPU401))
+
+typedef struct
+  {
+    unsigned long   conditions;
+    unsigned long   exclusive_options;
+    char            macro[20];
+    int             verify;
+    int             alias;
+  }
+
+hw_entry;
+
+
+/*
+ * The rule table for the driver options. The first field defines a set of
+ * options which must be selected before this entry can be selected. The
+ * second field is a set of options which are not allowed with this one. If
+ * the fourth field is zero, the option is selected without asking
+ * confirmation from the user.
+ * 
+ * With this version of the rule table it is possible to select just one type of
+ * hardware.
+ * 
+ * NOTE!	Keep the following table and the questions array in sync with the
+ * option numbering!
+ */
+
+hw_entry        hw_table[] =
+{
+/* 0 */
+  {0, 0, "PAS", 1, 0},
+  {0, 0, "SB", 1, 0},
+  {0, B (OPT_PAS) | B (OPT_SB), "ADLIB", 1, 0},
+
+/* 3 */
+  {0, 0, "GUS", 1, 0},
+  {0, 0, "MPU401", 1, 0},
+  {B (OPT_SB), B (OPT_PAS), "SBPRO", 1, 0},
+  {B (OPT_SB) | B (OPT_PAS) | B (OPT_GUS), 0, "AUDIO", 1, 0},
+  {B (OPT_MPU401), 0, "MIDI_AUTO", 0, OPT_MIDI},
+  {B (OPT_SB) | B (OPT_PAS) | B (OPT_MPU401) | B (OPT_GUS), 0, "MIDI", 1, 0},
+  {B (OPT_ADLIB), 0, "YM3812_AUTO", 0, OPT_YM3812},
+  {B (OPT_SB) | B (OPT_PAS) | B (OPT_ADLIB), B (OPT_YM3812_AUTO), "YM3812", 1, 0},
+/* 10 */
+  {B (OPT_MIDI) | B (OPT_YM3812) | B (OPT_YM3812_AUTO) | B (OPT_GUS), 0, "SEQUENCER", 0, 0},
+  {0, 0, "CHIP_MIDI", 1, 0}
+};
+
+char           *questions[] =
+{
+  "ProAudioSpectrum 16 support",
+  "SoundBlaster support",
+  "AdLib support",
+  "Gravis Ultrasound support",
+  "MPU-401 support",
+
+  "SoundBlaster Pro support (mixer)",
+  "digitized voice support",
+  "This should not be asked",
+  "MIDI interface support",
+  "This should not be asked",
+  "Internal synthesizer (FM/GUS) support",
+  "/dev/sequencer support",
+  "MIDI on CHIP support"
+};
+
+unsigned long   selected_options = 0;
+
+int
+can_select_option (int nr)
+{
+  switch (nr)
+    {
+    case 0:
+      fprintf (stderr, "The SoundBlaster, AdLib and ProAudioSpectrum\n"
+	       "cards cannot be installed at the same time\n");
+      fprintf (stderr, "\nSelect at most one of them:\n");
+      fprintf (stderr, "	- ProAudioSpectrum 16\n");
+      fprintf (stderr, "	- SoundBlaster / SB Pro\n");
+      fprintf (stderr, "          (Could be selected with PAS16 also\n"
+	       "	  since there is a SB emulation on it)\n");
+      fprintf (stderr, "	- AdLib\n");
+      fprintf (stderr, "\nDon't enable SoundBlaster if you have GUS at 0x220!\n\n");
+      break;
+
+    case OPT_LAST_MUTUAL + 1:
+      fprintf (stderr, "\nThe following cards should work with any other cards.\n"
+	       "CAUTION! Don't enable MPU-401 if you don't have it.\n");
+      break;
+
+    case OPT_HIGHLEVEL:
+      fprintf (stderr, "\nSelect one or more of the following options\n");
+      break;
+
+
+    }
+
+  if (hw_table[nr].conditions)
+    if (!(hw_table[nr].conditions & selected_options))
+      return 0;
+
+  if (hw_table[nr].exclusive_options)
+    if (hw_table[nr].exclusive_options & selected_options)
+      return 0;
+
+  return 1;
+}
+
+int
+think_positively (void)
+{
+  char            answ[512];
+  int             len;
+
+  if ((len = read (0, &answ, sizeof (answ))) < 1)
+    {
+      fprintf (stderr, "\n\nERROR! Cannot read stdin\n");
+
+      perror ("stdin");
+      printf ("#undef CONFIGURE_SOUNDCARD\n");
+      printf ("#undef KERNEL_SOUNDCARD\n");
+      exit (-1);
+    }
+
+  if (len < 2)			/* There is an additional LF at the end */
+    return 0;
+
+  answ[len - 1] = 0;
+
+  if (!strcmp (answ, "y") || !strcmp (answ, "Y"))
+    return 1;
+
+  return 0;
+}
+
+int
+ask_value (char *format, int default_answer)
+{
+  char            answ[512];
+  int             len, num;
+
+play_it_again_Sam:
+
+  if ((len = read (0, &answ, sizeof (answ))) < 1)
+    {
+      fprintf (stderr, "\n\nERROR! Cannot read stdin\n");
+
+      perror ("stdin");
+      printf ("#undef CONFIGURE_SOUNDCARD\n");
+      printf ("#undef KERNEL_SOUNDCARD\n");
+      exit (-1);
+    }
+
+  if (len < 2)			/* There is an additional LF at the end */
+    return default_answer;
+
+  answ[len - 1] = 0;
+
+  if (sscanf (answ, format, &num) != 1)
+    {
+      fprintf (stderr, "Illegal format. Try again: ");
+      goto play_it_again_Sam;
+    }
+
+  return num;
+}
+
+int
+main (int argc, char *argv[])
+{
+  int             i, num, def_size, full_driver = 1;
+  char            answ[10];
+
+  printf ("/*\tGenerated by configure. Don't edit!!!!\t*/\n\n");
+
+  fprintf (stderr, "\nConfiguring the sound support\n\n");
+
+  fprintf (stderr, "Do you want to include full version of the sound driver (n/y) ? ");
+
+  if (think_positively ())
+    {
+      selected_options = 0xffffffff & ~B (OPT_MPU401);
+      fprintf (stderr, "Note! MPU-401 driver was not enabled\n");
+      full_driver = 1;
+    }
+  else
+    {
+      fprintf (stderr, "Do you want to DISABLE the Sound Driver (n/y) ?");
+      if (think_positively ())
+	{
+	  printf ("#undef CONFIGURE_SOUNDCARD\n");
+	  printf ("#undef KERNEL_SOUNDCARD\n");
+	  exit (0);
+	}
+      /* Partial driver */
+
+      full_driver = 0;
+
+      for (i = 0; i <= OPT_LAST; i++)
+	if (can_select_option (i))
+	  {
+	    if (!(selected_options & B (i)))	/* Not selected yet */
+	      if (!hw_table[i].verify)
+		{
+		  if (hw_table[i].alias)
+		    selected_options |= B (hw_table[i].alias);
+		  else
+		    selected_options |= B (i);
+		}
+	      else
+		{
+		  fprintf (stderr, "  %s (n/y) ? ", questions[i]);
+		  if (think_positively ())
+		    if (hw_table[i].alias)
+		      selected_options |= B (hw_table[i].alias);
+		    else
+		      selected_options |= B (i);
+		}
+	  }
+    }
+
+  if (!(selected_options & ANY_DEVS))
+    {
+      printf ("#undef CONFIGURE_SOUNDCARD\n");
+      printf ("#undef KERNEL_SOUNDCARD\n");
+      fprintf (stderr, "\n*** This combination is useless. Sound driver disabled!!! ***\n\n");
+      exit (0);
+    }
+  else
+    printf ("#define KERNEL_SOUNDCARD\n");
+
+  for (i = 0; i <= OPT_LAST; i++)
+    if (!hw_table[i].alias)
+      if (selected_options & B (i))
+	printf ("#undef  EXCLUDE_%s\n", hw_table[i].macro);
+      else
+	printf ("#define EXCLUDE_%s\n", hw_table[i].macro);
+
+
+  printf ("#define EXCLUDE_PRO_MIDI\n");
+  printf ("#define EXCLUDE_CHIP_MIDI\n");
+
+  /*
+   * IRQ and DMA settings
+   */
+  printf ("\n");
+
+#ifdef linux
+  if (selected_options & B (OPT_SB) && selected_options & (B (OPT_AUDIO) | B (OPT_MIDI)))
+    {
+      fprintf (stderr, "\nIRQ number for SoundBlaster?\n"
+	       "The IRQ adress is defined by the jumpers on your card and\n"
+	       "7 is the factory default. Valid values are 9, 5, 7 and 10.\n"
+	       "Enter the value: ");
+
+      num = ask_value ("%d", 7);
+      if (num != 9 && num != 5 && num != 7 && num != 10)
+	{
+
+	  fprintf (stderr, "*** Illegal input! ***\n");
+	  num = 7;
+	}
+      fprintf (stderr, "SoundBlaster IRQ set to %d\n", num);
+      printf ("#define SBC_IRQ %d\n", num);
+
+      if (selected_options & B (OPT_SBPRO))
+	{
+
+	  fprintf (stderr, "\nDMA channel for SoundBlaster?\n"
+		   "For SB 1.0, 1.5 and 2.0 this MUST be 1\n"
+		   "SB Pro supports DMA channels 0, 1 and 3 (jumper)\n"
+		   "The default value is 1\n"
+		   "Enter the value: ");
+
+	  num = ask_value ("%d", 1);
+	  if (num < 0 || num > 7 || num == 4)
+	    {
+
+	      fprintf (stderr, "*** Illegal input! ***\n");
+	      num = 1;
+	    }
+	  fprintf (stderr, "SoundBlaster DMA set to %d\n", num);
+	  printf ("#define SBC_DMA %d\n", num);
+	}
+    }
+
+  if (selected_options & B (OPT_PAS))
+    {
+      if (selected_options & (B (OPT_AUDIO) | B (OPT_MIDI)))
+	{
+	  fprintf (stderr, "\nIRQ number for ProAudioSpectrum?\n"
+		   "The recommended value is the IRQ used under DOS.\n"
+		   "Please refer to the ProAudioSpectrum User's Guide.\n"
+		   "The default value is 10.\n"
+		   "Enter the value: ");
+
+	  num = ask_value ("%d", 10);
+	  if (num == 6 || num < 3 || num > 15 || num == 2)	/* Illegal */
+	    {
+
+	      fprintf (stderr, "*** Illegal input! ***\n");
+	      num = 10;
+	    }
+	  fprintf (stderr, "ProAudioSpectrum IRQ set to %d\n", num);
+	  printf ("#define PAS_IRQ %d\n", num);
+	}
+
+      if (selected_options & B (OPT_AUDIO))
+	{
+	  fprintf (stderr, "\nDMA number for ProAudioSpectrum?\n"
+		   "The recommended value is the DMA channel under DOS.\n"
+		   "Please refer to the ProAudioSpectrum User's Guide.\n"
+		   "The default value is 3\n"
+		   "Enter the value: ");
+
+	  num = ask_value ("%d", 3);
+	  if (num == 4 || num < 0 || num > 7)
+	    {
+
+	      fprintf (stderr, "*** Illegal input! ***\n");
+	      num = 3;
+	    }
+	  fprintf (stderr, "\nProAudioSpectrum DMA set to %d\n", num);
+	  printf ("#define PAS_DMA %d\n", num);
+	}
+    }
+
+  if (selected_options & B (OPT_GUS))
+    {
+      fprintf (stderr, "\nI/O base for Gravis Ultrasound?\n"
+	       "Valid choises are 210, 220, 230, 240, 250 or 260\n"
+	       "The factory default is 220\n"
+	       "Enter the GUS I/O base: ");
+
+      num = ask_value ("%x", 0x220);
+      if ((num > 0x260) || ((num & 0xf0f) != 0x200) || ((num & 0x0f0) > 0x060))
+	{
+
+	  fprintf (stderr, "*** Illegal input! ***\n");
+	  num = 0x220;
+	}
+
+      if ((selected_options & B (OPT_SB)) && (num == 0x220))
+	{
+	  fprintf (stderr, "FATAL ERROR!!!!!!!!!!!!!!\n"
+		   "\t0x220 cannot be used if SoundBlaster is enabled.\n"
+		   "\tRun the config again.\n");
+	  printf ("#undef CONFIGURE_SOUNDCARD\n");
+	  printf ("#undef KERNEL_SOUNDCARD\n");
+	  exit (-1);
+	}
+      fprintf (stderr, "GUS I/O base set to %03x\n", num);
+      printf ("#define GUS_BASE 0x%03x\n", num);
+
+      fprintf (stderr, "\nIRQ number for Gravis UltraSound?\n"
+	       "The recommended value is the IRQ used under DOS.\n"
+	       "Please refer to the Gravis Ultrasound User's Guide.\n"
+	       "The default value is 15.\n"
+	       "Enter the value: ");
+
+      num = ask_value ("%d", 15);
+      if (num == 6 || num < 3 || num > 15 || num == 2)	/* Invalid */
+	{
+
+	  fprintf (stderr, "*** Illegal input! ***\n");
+	  num = 15;
+	}
+      fprintf (stderr, "Gravis UltraSound IRQ set to %d\n", num);
+      printf ("#define GUS_IRQ %d\n", num);
+
+      fprintf (stderr, "\nDMA number for Gravis UltraSound?\n"
+	       "The recommended value is the DMA channel under DOS.\n"
+	       "Please refer to the Gravis Ultrasound User's Guide.\n"
+	       "The default value is 6\n"
+	       "Enter the value: ");
+
+      num = ask_value ("%d", 6);
+      if (num == 4 || num < 0 || num > 7)
+	{
+	  fprintf (stderr, "*** Illegal input! ***\n");
+	  num = 6;
+	}
+      fprintf (stderr, "\nGravis UltraSound DMA set to %d\n", num);
+      printf ("#define GUS_DMA %d\n", num);
+    }
+
+  if (selected_options & B (OPT_MPU401))
+    {
+      fprintf (stderr, "\nI/O base for MPU-401?\n"
+	       "The factory default is 330\n"
+	       "Enter the MPU-401 I/O base: ");
+
+      num = ask_value ("%x", 0x330);
+      fprintf (stderr, "MPU-401 I/O base set to %03x\n", num);
+      printf ("#define MPU_BASE 0x%03x\n", num);
+
+      fprintf (stderr, "\nIRQ number for MPU-401?\n"
+	       "Valid numbers are: 3, 4, 5, 7 and 9.\n"
+	       "The default value is 5.\n"
+	       "Enter the value: ");
+
+      num = ask_value ("%d", 5);
+      if (num == 6 || num < 3 || num > 15)	/* Used for floppy */
+	{
+
+	  fprintf (stderr, "*** Illegal input! ***\n");
+	  num = 5;
+	}
+      fprintf (stderr, "MPU-401 IRQ set to %d\n", num);
+      printf ("#define MPU_IRQ %d\n", num);
+    }
+#endif
+
+  if (selected_options & B (OPT_AUDIO))
+    {
+      def_size = 16384;
+
+      if (selected_options & (B (OPT_SBPRO) | B (OPT_PAS)))
+	def_size = 32768;
+      if ((selected_options & B (OPT_PAS)) && !full_driver)
+	def_size = 65536;	/* PAS16 alone */
+
+      fprintf (stderr, "\nSelect the DMA buffer size (4096, 16384, 32768 or 65536 bytes)\n"
+	       "%d is recommended value for this configuration.\n"
+	       "Enter the value: ", def_size);
+
+      num = ask_value ("%d", def_size);
+      if (num != 4096 && num != 16384 && num != 32768 && num != 65536)
+	{
+
+	  fprintf (stderr, "*** Illegal input! ***\n");
+	  num = def_size;
+	}
+      fprintf (stderr, "The DMA buffer size set to %d\n", num);
+      printf ("#define DSP_BUFFSIZE %d\n", num);
+    }
+
+  printf ("#define SELECTED_SOUND_OPTIONS\t0x%08x\n", selected_options);
+  fprintf (stderr, "The sound driver is now configured.\n");
+
+  exit (0);
+}
diff --git a/drivers/sound/dev_table.c b/drivers/sound/dev_table.c
new file mode 100644
index 0000000..05083d9
--- /dev/null
+++ b/drivers/sound/dev_table.c
@@ -0,0 +1,103 @@
+/*
+ * linux/kernel/chr_drv/sound/dev_table.c
+ * 
+ * Device call tables.
+ * 
+ * Copyright by Hannu Savolainen 1993
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer. 2.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * 
+ */
+
+#define _DEV_TABLE_C_
+#include "sound_config.h"
+
+#ifdef CONFIGURE_SOUNDCARD
+
+long
+sndtable_init (long mem_start)
+{
+  int             i, n = sizeof (supported_drivers) / sizeof (struct card_info);
+
+  for (i = 0; i < (n - 1); i++)
+    if (supported_drivers[i].probe (&supported_drivers[i].config))
+      {
+#ifndef SHORT_BANNERS
+	printk ("snd%d",
+		supported_drivers[i].card_type);
+#endif
+
+	mem_start = supported_drivers[i].attach (mem_start, &supported_drivers[i].config);
+#ifndef SHORT_BANNERS
+	printk (" at 0x%3x irq %d drq %d\n",
+		supported_drivers[i].config.io_base,
+		supported_drivers[i].config.irq,
+		supported_drivers[i].config.dma);
+#endif
+      }
+  return mem_start;
+}
+
+int
+sndtable_probe (int unit, struct address_info *hw_config)
+{
+  int             i, n = sizeof (supported_drivers) / sizeof (struct card_info);
+
+  if (!unit)
+    return TRUE;
+
+  for (i = 0; i < (n - 1); i++)
+    if (supported_drivers[i].card_type == unit)
+      return supported_drivers[i].probe (hw_config);
+
+  return FALSE;
+}
+
+int
+sndtable_init_card (int unit, struct address_info *hw_config)
+{
+  int             i, n = sizeof (supported_drivers) / sizeof (struct card_info);
+
+  if (!unit)
+    {
+      if (sndtable_init (0) != 0)
+	panic ("snd: Invalid memory allocation\n");
+      return TRUE;
+    }
+
+  for (i = 0; i < (n - 1); i++)
+    if (supported_drivers[i].card_type == unit)
+      {
+	if (supported_drivers[i].attach (0, hw_config) != 0)
+	  panic ("snd#: Invalid memory allocation\n");
+	return TRUE;
+      }
+
+  return FALSE;
+}
+
+int
+sndtable_get_cardcount (void)
+{
+  return num_dspdevs + num_mixers + num_synths + num_midis;
+}
+
+#endif
diff --git a/drivers/sound/dev_table.h b/drivers/sound/dev_table.h
new file mode 100644
index 0000000..9bfd784
--- /dev/null
+++ b/drivers/sound/dev_table.h
@@ -0,0 +1,253 @@
+/*
+ *	dev_table.h
+ *
+ *	Global definitions for device call tables
+ * 
+ * Copyright by Hannu Savolainen 1993
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+
+*/
+
+#ifndef _DEV_TABLE_H_
+#define _DEV_TABLE_H_
+
+/*
+ *	NOTE! 	NOTE!	NOTE!	NOTE!
+ *
+ *	If you modify this file, please check the dev_table.c also.
+ *
+ *	NOTE! 	NOTE!	NOTE!	NOTE!
+ */
+
+struct card_info {
+	int card_type;	/*	From soundcard.c	*/
+	char *name;
+	long (*attach) (long mem_start, struct address_info *hw_config);
+	int (*probe) (struct address_info *hw_config);
+	struct address_info config;
+};
+
+/** UWM -- new  MIDI structure here.. **/
+
+struct generic_midi_info{
+        char *name;	/* Name of the MIDI device.. */
+        long (*attach) (long mem_start);
+};
+
+struct audio_operations {
+        char name[32];
+	int (*open) (int dev, int mode);
+	void (*close) (int dev);
+	void (*output_block) (int dev, unsigned long buf, int count, int intrflag);
+	void (*start_input) (int dev, unsigned long buf, int count, int intrflag);
+	int (*ioctl) (int dev, unsigned int cmd, unsigned int arg, int local);
+	int (*prepare_for_input) (int dev, int bufsize, int nbufs);
+	int (*prepare_for_output) (int dev, int bufsize, int nbufs);
+	void (*reset) (int dev);
+	void (*halt_xfer) (int dev);
+	int (*has_output_drained)(int dev);
+        void (*copy_from_user)(int dev, char *localbuf, int localoffs,
+                               snd_rw_buf *userbuf, int useroffs, int len);
+};
+
+struct mixer_operations {
+	int (*ioctl) (int dev, unsigned int cmd, unsigned int arg);
+};
+
+struct synth_operations {
+	struct synth_info *info;
+	int synth_type;
+	int synth_subtype;
+
+	int (*open) (int dev, int mode);
+	void (*close) (int dev);
+	int (*ioctl) (int dev, unsigned int cmd, unsigned int arg);
+	int (*kill_note) (int dev, int voice, int velocity);
+	int (*start_note) (int dev, int voice, int note, int velocity);
+	int (*set_instr) (int dev, int voice, int instr);
+	void (*reset) (int dev);
+	void (*hw_control) (int dev, unsigned char *event);
+	int (*load_patch) (int dev, int format, snd_rw_buf *addr,
+	     int offs, int count, int pmgr_flag);
+	void (*aftertouch) (int dev, int voice, int pressure);
+	void (*controller) (int dev, int voice, int ctrl_num, int value);
+	void (*panning) (int dev, int voice, int value);
+	int (*pmgr_interface) (int dev, struct patmgr_info *info);
+};
+
+struct midi_operations {
+	struct midi_info info;
+	int (*open) (int dev, int mode,
+		void (*inputintr)(int dev, unsigned char data),
+		void (*outputintr)(int dev)
+		);
+	void (*close) (int dev);
+	int (*ioctl) (int dev, unsigned int cmd, unsigned int arg);
+	int (*putc) (int dev, unsigned char data);
+	int (*start_read) (int dev);
+	int (*end_read) (int dev);
+	void (*kick)(int dev);
+	int (*command) (int dev, unsigned char data);
+	int (*buffer_status) (int dev);
+};
+
+/** UWM -- new structure for MIDI  **/
+
+struct generic_midi_operations {
+	struct midi_info info;
+	int (*open) (int dev, int mode);
+	void (*close) (int dev);
+	int (*write) (int dev, snd_rw_buf *data);
+	int (*read)  (int dev, snd_rw_buf *data);
+};	
+
+#ifndef ALL_EXTERNAL_TO_ME
+
+#ifdef _MIDI_TABLE_C_
+
+/** UWM **/
+       struct generic_midi_operations * generic_midi_devs[MAX_MIDI_DEV] = {NULL}; 
+       int num_generic_midis = 0, pro_midi_dev = 0; 
+
+      struct generic_midi_info midi_supported[] = {
+
+#ifndef EXCLUDE_PRO_MIDI
+        {"ProAudioSpectrum MV101",pro_midi_attach}
+#endif
+        }; 
+
+        int num_midi_drivers = 
+            sizeof (midi_supported) / sizeof(struct generic_midi_info);
+
+#endif
+
+
+#ifdef _DEV_TABLE_C_   
+	struct audio_operations * dsp_devs[MAX_DSP_DEV] = {NULL}; int num_dspdevs = 0;
+	struct mixer_operations * mixer_devs[MAX_MIXER_DEV] = {NULL}; int num_mixers = 0;
+	struct synth_operations * synth_devs[MAX_SYNTH_DEV] = {NULL}; int num_synths = 0;
+	struct midi_operations * midi_devs[MAX_MIDI_DEV] = {NULL}; int num_midis = 0;
+
+
+#   ifndef EXCLUDE_MPU401
+        int mpu401_dev = 0;
+#   endif
+
+/*
+ *	Note! The detection order is significant. Don't change it.
+ */
+
+	struct card_info supported_drivers[] = {
+#ifndef EXCLUDE_MPU401
+		{SNDCARD_MPU401,"Roland MPU-401",	attach_mpu401, probe_mpu401,
+			{MPU_BASE, MPU_IRQ, 0}},
+#endif
+
+#ifndef EXCLUDE_GUS
+		{SNDCARD_GUS,	"Gravis Ultrasound",	attach_gus_card, probe_gus,
+			{GUS_BASE, GUS_IRQ, GUS_DMA}},
+#endif
+
+#ifndef EXCLUDE_PAS
+		{SNDCARD_PAS,	"ProAudioSpectrum",	attach_pas_card, probe_pas,
+			{PAS_BASE, PAS_IRQ, PAS_DMA}},
+#endif
+
+#ifndef EXCLUDE_SB
+		{SNDCARD_SB,	"SoundBlaster",		attach_sb_card, probe_sb,
+			{SBC_BASE, SBC_IRQ, SBC_DMA}},
+#endif
+
+#ifndef EXCLUDE_YM3812
+		{SNDCARD_ADLIB,	"AdLib",		attach_adlib_card, probe_adlib,
+			{FM_MONO, 0, 0}},
+#endif
+		{0,			"*?*",			NULL}
+	};
+
+	int num_sound_drivers =
+	    sizeof(supported_drivers) / sizeof (struct card_info);
+
+
+# ifndef EXCLUDE_AUDIO 
+	int sound_buffcounts[MAX_DSP_DEV] = {0};
+	long sound_buffsizes[MAX_DSP_DEV] = {0};
+	int sound_dsp_dmachan[MAX_DSP_DEV] = {0};
+	int sound_dma_automode[MAX_DSP_DEV] = {0};
+# endif
+#else
+	extern struct audio_operations * dsp_devs[MAX_DSP_DEV]; int num_dspdevs;
+	extern struct mixer_operations * mixer_devs[MAX_MIXER_DEV]; extern int num_mixers;
+	extern struct synth_operations * synth_devs[MAX_SYNTH_DEV]; extern int num_synths;
+	extern struct midi_operations * midi_devs[MAX_MIDI_DEV]; extern int num_midis;
+#   ifndef EXCLUDE_MPU401
+        extern int mpu401_dev;
+#   endif
+
+	extern struct card_info supported_drivers[];
+	extern int num_sound_drivers;
+
+# ifndef EXCLUDE_AUDIO
+	extern int sound_buffcounts[MAX_DSP_DEV];
+	extern long sound_buffsizes[MAX_DSP_DEV];
+	extern int sound_dsp_dmachan[MAX_DSP_DEV];
+	extern int sound_dma_automode[MAX_DSP_DEV];
+# endif
+
+#endif
+
+long sndtable_init(long mem_start);
+int sndtable_get_cardcount (void);
+long CMIDI_init(long mem_start); /* */
+#endif
+
+#endif
+
+/* If external to me.... :) */
+
+#ifdef ALL_EXTERNAL_TO_ME
+
+	extern struct audio_operations * dsp_devs[MAX_DSP_DEV]; int num_dspdevs;
+        extern struct mixer_operations * mixer_devs[MAX_MIXER_DEV]; extern int num_mixers;
+        extern struct synth_operations * synth_devs[MAX_SYNTH_DEV]; extern int num_synths;
+        extern struct midi_operations * midi_devs[MAX_MIDI_DEV]; extern int num_midis;
+	extern struct generic_midi_operations *generic_midi_devs[]; 
+	extern int num_generic_midis, pro_midi_dev;
+ 
+#ifndef EXCLUDE_MPU401
+        extern int mpu401_dev;
+#endif
+
+	extern struct generic_midi_info midi_supported[];
+	extern struct card_info supported_drivers[];
+        extern int num_sound_drivers;
+	extern int num_midi_drivers;	
+#ifndef EXCLUDE_AUDIO
+        extern int sound_buffcounts[MAX_DSP_DEV];
+        extern long sound_buffsizes[MAX_DSP_DEV];
+        extern int sound_dsp_dmachan[MAX_DSP_DEV];
+        extern int sound_dma_automode[MAX_DSP_DEV];
+#endif
+
+#endif
diff --git a/drivers/sound/dma.h b/drivers/sound/dma.h
new file mode 100644
index 0000000..1590815
--- /dev/null
+++ b/drivers/sound/dma.h
@@ -0,0 +1,266 @@
+/* $Id: dma.h,v 1.7 1992/12/14 00:29:34 root Exp root $
+ * linux/include/asm/dma.h: Defines for using and allocating dma channels.
+ * Written by Hennus Bergman, 1992.
+ * High DMA channel support & info by Hannu Savolainen
+ * and John Boyd, Nov. 1992.
+ */
+
+#ifndef _ASM_DMA_H
+#define _ASM_DMA_H
+
+#include <asm/io.h>		/* need byte IO */
+
+#define deb_outb(x,y) {printk("out %02x, %02x\n", x, y);outb(x,y);}
+
+
+#ifdef HAVE_REALLY_SLOW_DMA_CONTROLLER
+#define outb	outb_p
+#endif
+
+/*
+ * NOTES about DMA transfers:
+ *
+ *  controller 1: channels 0-3, byte operations, ports 00-1F
+ *  controller 2: channels 4-7, word operations, ports C0-DF
+ *
+ *  - ALL registers are 8 bits only, regardless of transfer size
+ *  - channel 4 is not used - cascades 1 into 2.
+ *  - channels 0-3 are byte - addresses/counts are for physical bytes
+ *  - channels 5-7 are word - addresses/counts are for physical words
+ *  - transfers must not cross physical 64K (0-3) or 128K (5-7) boundaries
+ *  - transfer count loaded to registers is 1 less than actual count
+ *  - controller 2 offsets are all even (2x offsets for controller 1)
+ *  - page registers for 5-7 don't use data bit 0, represent 128K pages
+ *  - page registers for 0-3 use bit 0, represent 64K pages
+ *
+ * DMA transfers are limited to the lower 16MB of _physical_ memory.  
+ * Note that addresses loaded into registers must be _physical_ addresses,
+ * not logical addresses (which may differ if paging is active).
+ *
+ *  Address mapping for channels 0-3:
+ *
+ *   A23 ... A16 A15 ... A8  A7 ... A0    (Physical addresses)
+ *    |  ...  |   |  ... |   |  ... |
+ *    |  ...  |   |  ... |   |  ... |
+ *    |  ...  |   |  ... |   |  ... |
+ *   P7  ...  P0  A7 ... A0  A7 ... A0   
+ * |    Page    | Addr MSB | Addr LSB |   (DMA registers)
+ *
+ *  Address mapping for channels 5-7:
+ *
+ *   A23 ... A17 A16 A15 ... A9 A8 A7 ... A1 A0    (Physical addresses)
+ *    |  ...  |   \   \   ... \  \  \  ... \  \
+ *    |  ...  |    \   \   ... \  \  \  ... \  (not used)
+ *    |  ...  |     \   \   ... \  \  \  ... \
+ *   P7  ...  P1 (0) A7 A6  ... A0 A7 A6 ... A0   
+ * |      Page      |  Addr MSB   |  Addr LSB  |   (DMA registers)
+ *
+ * Again, channels 5-7 transfer _physical_ words (16 bits), so addresses
+ * and counts _must_ be word-aligned (the lowest address bit is _ignored_ at
+ * the hardware level, so odd-byte transfers aren't possible).
+ *
+ * Transfer count (_not # bytes_) is limited to 64K, represented as actual
+ * count - 1 : 64K => 0xFFFF, 1 => 0x0000.  Thus, count is always 1 or more,
+ * and up to 128K bytes may be transferred on channels 5-7 in one operation. 
+ *
+ */
+
+#define MAX_DMA_CHANNELS	8
+
+/* 8237 DMA controllers */
+#define IO_DMA1_BASE	0x00	/* 8 bit slave DMA, channels 0..3 */
+#define IO_DMA2_BASE	0xC0	/* 16 bit master DMA, ch 4(=slave input)..7 */
+
+/* DMA controller registers */
+#define DMA1_CMD_REG		0x08	/* command register (w) */
+#define DMA1_STAT_REG		0x08	/* status register (r) */
+#define DMA1_REQ_REG            0x09    /* request register (w) */
+#define DMA1_MASK_REG		0x0A	/* single-channel mask (w) */
+#define DMA1_MODE_REG		0x0B	/* mode register (w) */
+#define DMA1_CLEAR_FF_REG	0x0C	/* clear pointer flip-flop (w) */
+#define DMA1_TEMP_REG           0x0D    /* Temporary Register (r) */
+#define DMA1_RESET_REG		0x0D	/* Master Clear (w) */
+#define DMA1_CLR_MASK_REG       0x0E    /* Clear Mask */
+#define DMA1_MASK_ALL_REG       0x0F    /* all-channels mask (w) */
+
+#define DMA2_CMD_REG		0xD0	/* command register (w) */
+#define DMA2_STAT_REG		0xD0	/* status register (r) */
+#define DMA2_REQ_REG            0xD2    /* request register (w) */
+#define DMA2_MASK_REG		0xD4	/* single-channel mask (w) */
+#define DMA2_MODE_REG		0xD6	/* mode register (w) */
+#define DMA2_CLEAR_FF_REG	0xD8	/* clear pointer flip-flop (w) */
+#define DMA2_TEMP_REG           0xDA    /* Temporary Register (r) */
+#define DMA2_RESET_REG		0xDA	/* Master Clear (w) */
+#define DMA2_CLR_MASK_REG       0xDC    /* Clear Mask */
+#define DMA2_MASK_ALL_REG       0xDE    /* all-channels mask (w) */
+
+#define DMA_ADDR_0              0x00    /* DMA address registers */
+#define DMA_ADDR_1              0x02
+#define DMA_ADDR_2              0x04
+#define DMA_ADDR_3              0x06
+#define DMA_ADDR_4              0xC0
+#define DMA_ADDR_5              0xC4
+#define DMA_ADDR_6              0xC8
+#define DMA_ADDR_7              0xCC
+
+#define DMA_CNT_0               0x01    /* DMA count registers */
+#define DMA_CNT_1               0x03
+#define DMA_CNT_2               0x05
+#define DMA_CNT_3               0x07
+#define DMA_CNT_4               0xC2
+#define DMA_CNT_5               0xC6
+#define DMA_CNT_6               0xCA
+#define DMA_CNT_7               0xCE
+
+#define DMA_PAGE_0              0x87    /* DMA page registers */
+#define DMA_PAGE_1              0x83
+#define DMA_PAGE_2              0x81
+#define DMA_PAGE_3              0x82
+#define DMA_PAGE_5              0x8B
+#define DMA_PAGE_6              0x89
+#define DMA_PAGE_7              0x8A
+
+#define DMA_MODE_READ	0x44	/* I/O to memory, no autoinit, increment, single mode */
+#define DMA_MODE_WRITE	0x48	/* memory to I/O, no autoinit, increment, single mode */
+#define DMA_MODE_CASCADE 0xC0   /* pass thru DREQ->HRQ, DACK<-HLDA only */
+
+/* enable/disable a specific DMA channel */
+static __inline__ void enable_dma(unsigned int dmanr)
+{
+	if (dmanr<=3)
+		deb_outb(dmanr,  DMA1_MASK_REG)
+	else
+		deb_outb(dmanr & 3,  DMA2_MASK_REG);
+}
+
+static __inline__ void disable_dma(unsigned int dmanr)
+{
+	if (dmanr<=3)
+		deb_outb(dmanr | 4,  DMA1_MASK_REG)
+	else
+		deb_outb((dmanr & 3) | 4,  DMA2_MASK_REG);
+}
+
+/* Clear the 'DMA Pointer Flip Flop'.
+ * Write 0 for LSB/MSB, 1 for MSB/LSB access.
+ * Use this once to initialize the FF to a known state.
+ * After that, keep track of it. :-)
+ * --- In order to do that, the DMA routines below should ---
+ * --- only be used while interrupts are disabled! ---
+ */
+static __inline__ void clear_dma_ff(unsigned int dmanr)
+{
+	if (dmanr<=3)
+		deb_outb(0,  DMA1_CLEAR_FF_REG)
+	else
+		deb_outb(0,  DMA2_CLEAR_FF_REG);
+}
+
+/* set mode (above) for a specific DMA channel */
+static __inline__ void set_dma_mode(unsigned int dmanr, char mode)
+{
+	if (dmanr<=3)
+		deb_outb(mode | dmanr,  DMA1_MODE_REG)
+	else
+		deb_outb(mode | (dmanr&3),  DMA2_MODE_REG);
+}
+
+/* Set only the page register bits of the transfer address.
+ * This is used for successive transfers when we know the contents of
+ * the lower 16 bits of the DMA current address register, but a 64k boundary
+ * may have been crossed.
+ */
+static __inline__ void set_dma_page(unsigned int dmanr, char pagenr)
+{
+	switch(dmanr) {
+		case 0:
+			deb_outb(pagenr, DMA_PAGE_0);
+			break;
+		case 1:
+			deb_outb(pagenr, DMA_PAGE_1);
+			break;
+		case 2:
+			deb_outb(pagenr, DMA_PAGE_2);
+			break;
+		case 3:
+			deb_outb(pagenr, DMA_PAGE_3);
+			break;
+		case 5:
+			deb_outb(pagenr & 0xfe, DMA_PAGE_5);
+			break;
+		case 6:
+			deb_outb(pagenr & 0xfe, DMA_PAGE_6);
+			break;
+		case 7:
+			deb_outb(pagenr & 0xfe, DMA_PAGE_7);
+			break;
+	}
+}
+
+
+/* Set transfer address & page bits for specific DMA channel.
+ * Assumes dma flipflop is clear.
+ */
+static __inline__ void set_dma_addr(unsigned int dmanr, unsigned int a)
+{
+	set_dma_page(dmanr, a>>16);
+	if (dmanr <= 3)  {
+	    deb_outb( a & 0xff, ((dmanr&3)<<1) + IO_DMA1_BASE );
+            deb_outb( (a>>8) & 0xff, ((dmanr&3)<<1) + IO_DMA1_BASE )
+	}  else  {
+	    deb_outb( (a>>1) & 0xff, ((dmanr&3)<<2) + IO_DMA2_BASE );
+	    deb_outb( (a>>9) & 0xff, ((dmanr&3)<<2) + IO_DMA2_BASE );
+	}
+}
+
+
+/* Set transfer size (max 64k for DMA1..3, 128k for DMA5..7) for
+ * a specific DMA channel.
+ * You must ensure the parameters are valid.
+ * NOTE: from a manual: "the number of transfers is one more
+ * than the initial word count"! This is taken into account.
+ * Assumes dma flip-flop is clear.
+ * NOTE 2: "count" represents _bytes_ and must be even for channels 5-7.
+ */
+static __inline__ void set_dma_count(unsigned int dmanr, unsigned int count)
+{
+        count--;
+	if (dmanr <= 3)  {
+	    deb_outb( count & 0xff, ((dmanr&3)<<1) + 1 + IO_DMA1_BASE );
+	    deb_outb( (count>>8) & 0xff, ((dmanr&3)<<1) + 1 + IO_DMA1_BASE );
+        } else {
+	    deb_outb( (count>>1) & 0xff, ((dmanr&3)<<2) + 2 + IO_DMA2_BASE );
+	    deb_outb( (count>>9) & 0xff, ((dmanr&3)<<2) + 2 + IO_DMA2_BASE );
+        }
+}
+
+
+/* Get DMA residue count. After a DMA transfer, this
+ * should return zero. Reading this while a DMA transfer is
+ * still in progress will return unpredictable results.
+ * If called before the channel has been used, it may return 1.
+ * Otherwise, it returns the number of _bytes_ left to transfer.
+ *
+ * Assumes DMA flip-flop is clear.
+ */
+static __inline__ int get_dma_residue(unsigned int dmanr)
+{
+	unsigned int io_port = (dmanr<=3)? ((dmanr&3)<<1) + 1 + IO_DMA1_BASE
+					 : ((dmanr&3)<<2) + 2 + IO_DMA2_BASE;
+
+	/* using short to get 16-bit wrap around */
+	unsigned short count;
+
+	count = 1 + inb(io_port);
+	count += inb(io_port) << 8;
+	
+	return (dmanr<=3)? count : (count<<1);
+}
+
+
+/* These are in kernel/dma.c: */
+extern int request_dma(unsigned int dmanr);	/* reserve a DMA channel */
+extern void free_dma(unsigned int dmanr);	/* release it again */
+
+
+#endif /* _ASM_DMA_H */
diff --git a/drivers/sound/dmabuf.c b/drivers/sound/dmabuf.c
new file mode 100644
index 0000000..0d39eb1
--- /dev/null
+++ b/drivers/sound/dmabuf.c
@@ -0,0 +1,791 @@
+/*
+ * linux/kernel/chr_drv/sound/dmabuf.c
+ * 
+ * The DMA buffer manager for digitized voice applications
+ * 
+ * Copyright by Hannu Savolainen 1993
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer. 2.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * 
+ */
+
+#include "sound_config.h"
+
+#ifdef CONFIGURE_SOUNDCARD
+
+#include "sound_calls.h"
+
+#if !defined(EXCLUDE_AUDIO) || !defined(EXCLUDE_GUS)
+
+#define MAX_SUB_BUFFERS		16
+
+/*
+ * The DSP channel can be used either for input or output. Variable
+ * 'dma_mode' will be set when the program calls read or write first time
+ * after open. Current version doesn't support mode changes without closing
+ * and reopening the device. Support for this feature may be implemented in a
+ * future version of this driver.
+ */
+
+#define DMODE_NONE		0
+#define DMODE_OUTPUT		1
+#define DMODE_INPUT		2
+#define DMODE_INIT		3
+
+DEFINE_WAIT_QUEUES (dev_sleeper[MAX_DSP_DEV], dev_sleep_flag[MAX_DSP_DEV]);
+
+static int      dma_mode[MAX_DSP_DEV] =
+{0};				/* DMODE_INPUT, DMODE_OUTPUT or DMODE_NONE */
+
+static volatile int dmabuf_interrupted[MAX_DSP_DEV] =
+{0};
+
+/*
+ * Pointers to raw buffers
+ */
+
+char           *snd_raw_buf[MAX_DSP_DEV][DSP_BUFFCOUNT] =
+{
+  {NULL}};
+unsigned long   snd_raw_buf_phys[MAX_DSP_DEV][DSP_BUFFCOUNT];
+int             snd_raw_count[MAX_DSP_DEV];
+
+/*
+ * Device state tables
+ */
+
+static int      dev_busy[MAX_DSP_DEV];
+static int      dev_active[MAX_DSP_DEV];
+static int      dev_qlen[MAX_DSP_DEV];
+static int      dev_qhead[MAX_DSP_DEV];
+static int      dev_qtail[MAX_DSP_DEV];
+static int      dev_underrun[MAX_DSP_DEV];
+static int      bufferalloc_done[MAX_DSP_DEV] =
+{0};
+
+/*
+ * Logical buffers for each devices
+ */
+
+static int      dev_nbufs[MAX_DSP_DEV];	/* # of logical buffers ( >=
+					 * sound_buffcounts[dev] */
+static int      dev_counts[MAX_DSP_DEV][MAX_SUB_BUFFERS];
+static unsigned long dev_buf_phys[MAX_DSP_DEV][MAX_SUB_BUFFERS];
+static char    *dev_buf[MAX_DSP_DEV][MAX_SUB_BUFFERS] =
+{
+  {NULL}};
+static int      dev_buffsize[MAX_DSP_DEV];
+
+static void
+reorganize_buffers (int dev)
+{
+  /*
+   * This routine breaks the physical device buffers to logical ones.
+   */
+
+  unsigned long   i, p, n;
+  unsigned long   sr, nc, sz, bsz;
+
+  sr = dsp_devs[dev]->ioctl (dev, SOUND_PCM_READ_RATE, 0, 1);
+  nc = dsp_devs[dev]->ioctl (dev, SOUND_PCM_READ_CHANNELS, 0, 1);
+  sz = dsp_devs[dev]->ioctl (dev, SOUND_PCM_READ_BITS, 0, 1);
+
+  if (sr < 1 || nc < 1 || sz < 1)
+    {
+      printk ("SOUND: Invalid PCM parameters[%d] sr=%d, nc=%d, sz=%d\n", dev, sr, nc, sz);
+      sr = DSP_DEFAULT_SPEED;
+      nc = 1;
+      sz = 8;
+    }
+
+  sz /= 8;			/* Convert # of bits -> # of bytes */
+
+  sz = sr * nc * sz;
+
+  /*
+   * Compute a buffer size not exeeding 1 second.
+   */
+
+  bsz = sound_buffsizes[dev];
+
+  while (bsz > sz)
+    bsz >>= 1;			/* Divide by 2 */
+
+  if (sound_buffcounts[dev] == 1 && bsz == sound_buffsizes[dev])
+    bsz >>= 1;			/* Need at least 2 buffers */
+
+  dev_buffsize[dev] = bsz;
+  n = 0;
+
+  /*
+   * Now computing addresses for the logical buffers
+   */
+
+  for (i = 0; i < snd_raw_count[dev]; i++)
+    {
+      p = 0;
+
+      while ((p + bsz) <= sound_buffsizes[dev])
+	{
+	  dev_buf[dev][n] = snd_raw_buf[dev][i] + p;
+	  dev_buf_phys[dev][n] = snd_raw_buf_phys[dev][i] + p;
+	  p += bsz;
+	  n++;
+	}
+    }
+
+  dev_nbufs[dev] = n;
+
+  for (i = 0; i < dev_nbufs[dev]; i++)
+    {
+      dev_counts[dev][i] = 0;
+    }
+
+  bufferalloc_done[dev] = 1;
+}
+
+int
+DMAbuf_open (int dev, int mode)
+{
+  int             retval;
+
+  if (dev >= num_dspdevs)
+    {
+      printk ("PCM device %d not installed.\n", dev);
+      return RET_ERROR (ENXIO);
+    }
+
+  if (dev_busy[dev])
+    return RET_ERROR (EBUSY);
+
+  if (!dsp_devs[dev])
+    {
+      printk ("DSP device %d not initialized\n", dev);
+      return RET_ERROR (ENXIO);
+    }
+
+  if (snd_raw_buf[dev][0] == NULL)
+    return RET_ERROR (ENOSPC);	/* Memory allocation failed during boot */
+
+  if ((retval = dsp_devs[dev]->open (dev, mode)) < 0)
+    return retval;
+
+  RESET_WAIT_QUEUE (dev_sleeper[dev], dev_sleep_flag[dev]);
+  dev_underrun[dev] = 0;
+
+  dev_busy[dev] = 1;
+
+  reorganize_buffers (dev);
+  bufferalloc_done[dev] = 0;
+
+  dev_qlen[dev] = dev_qtail[dev] = dev_qhead[dev] = 0;
+
+  return 0;
+}
+
+static void
+dma_reset (int dev)
+{
+  dsp_devs[dev]->reset (dev);
+
+  dev_qlen[dev] = 0;
+  dev_qhead[dev] = 0;
+  dev_qtail[dev] = 0;
+  dev_active[dev] = 0;
+}
+
+static int
+dma_sync (int dev)
+{
+  unsigned long   flags;
+  unsigned long   time;
+  int             timed_out;
+
+  if (dma_mode[dev] == DMODE_OUTPUT)
+    {
+      DISABLE_INTR (flags);
+
+      timed_out = 0;
+      time = GET_TIME ();
+
+      while ((!(PROCESS_ABORTING (dev_sleeper[dev], dev_sleep_flag[dev]) ||
+		dmabuf_interrupted[dev]) && !timed_out)
+	     && dev_qlen[dev])
+	{
+	  DO_SLEEP (dev_sleeper[dev], dev_sleep_flag[dev], 10 * HZ);
+	  if ((GET_TIME () - time) > (10 * HZ))
+	    timed_out = 1;
+	}
+      RESTORE_INTR (flags);
+
+      /*
+       * Some devices such as GUS have huge amount of on board RAM for the
+       * audio data. We have to wait util the device has finished playing.