diff -u --recursive --new-file v1.1.87/linux/CREDITS linux/CREDITS
--- v1.1.87/linux/CREDITS	Mon Jan 30 08:53:05 1995
+++ linux/CREDITS	Tue Jan 31 09:39:02 1995
@@ -329,7 +329,7 @@
 D: German Support-Disks for SLS/Slackware called SLT
 D: Linux Internationalization Project
 D: DOSemu
-S: Mohlenweg 19
+S: Muehlenweg 19
 S: 34266 Niestetal
 S: Germany
 
diff -u --recursive --new-file v1.1.87/linux/Makefile linux/Makefile
--- v1.1.87/linux/Makefile	Mon Jan 30 08:53:05 1995
+++ linux/Makefile	Tue Jan 31 17:32:12 1995
@@ -1,6 +1,6 @@
 VERSION = 1
 PATCHLEVEL = 1
-SUBLEVEL = 87
+SUBLEVEL = 88
 
 ARCH = i386
 
diff -u --recursive --new-file v1.1.87/linux/README.modules linux/README.modules
--- v1.1.87/linux/README.modules	Thu Jan 26 07:49:02 1995
+++ linux/README.modules	Tue Jan 31 09:39:02 1995
@@ -18,7 +18,7 @@
 	make zImage or make zlilo
 
 In "make config", you select what you want to include in the kernel.
-You will generally select the miminal set that is needed to boot:
+You will generally select the minimal set that is needed to boot:
 
 	The filesystem of your root partition
 	A scsi driver, but see below for a list of SCSI modules!
diff -u --recursive --new-file v1.1.87/linux/arch/alpha/kernel/entry.S linux/arch/alpha/kernel/entry.S
--- v1.1.87/linux/arch/alpha/kernel/entry.S	Sun Jan 22 21:39:37 1995
+++ linux/arch/alpha/kernel/entry.S	Tue Jan 31 09:30:47 1995
@@ -68,11 +68,33 @@
 .ent	entInt
 entInt:
 	SAVE_ALL
+/* start atomic operation with respect to software interrupts */
+	lda	$0,intr_count
+	ldq	$1,0($0)
+	addq	$1,1,$1
+	stq	$1,0($0)
+/* set up the arguments to the C interrupt handler */
 	bis	$30,$30,$19
 	lda	$27,do_entInt
 	jsr	$26,($27),do_entInt
+/* ok, check if we need to do software interrupts */
+1:	lda	$0,intr_count
+	ldq	$1,0($0)
+	subq	$1,1,$1
+	bne	$1,2f		/* interrupt within interrupt: return now */
+	lda	$2,bh_active
+	ldq	$3,0($2)
+	lda	$2,bh_mask
+	ldq	$2,0($2)
+	and	$2,$3,$2
+	bne	$2,3f
+2:	stq	$1,0($0)
 	RESTORE_ALL
 	rti
+.align 5
+3:	lda	$27,do_bottom_half
+	jsr	$26,($27),do_bottom_half
+	br	$31,1b
 .end entInt
 
 .align 5
diff -u --recursive --new-file v1.1.87/linux/arch/alpha/mm/fault.c linux/arch/alpha/mm/fault.c
--- v1.1.87/linux/arch/alpha/mm/fault.c	Thu Jan 26 07:49:02 1995
+++ linux/arch/alpha/mm/fault.c	Tue Jan 31 09:30:47 1995
@@ -18,6 +18,7 @@
 
 #include <asm/system.h>
 #include <asm/segment.h>
+#include <asm/pgtable.h>
 
 extern void die_if_kernel(char *,struct pt_regs *,long);
 
diff -u --recursive --new-file v1.1.87/linux/arch/alpha/mm/init.c linux/arch/alpha/mm/init.c
--- v1.1.87/linux/arch/alpha/mm/init.c	Mon Jan 30 08:53:06 1995
+++ linux/arch/alpha/mm/init.c	Tue Jan 31 09:30:47 1995
@@ -18,6 +18,7 @@
 
 #include <asm/system.h>
 #include <asm/segment.h>
+#include <asm/pgtable.h>
 #include <asm/hwrpb.h>
 
 extern void scsi_mem_init(unsigned long);
@@ -38,10 +39,10 @@
  * ZERO_PAGE is a special page that is used for zero-initialized
  * data and COW.
  */
-pte_t * __bad_pagetable(void)
+pmd_t * __bad_pagetable(void)
 {
 	memset((void *) EMPTY_PGT, 0, PAGE_SIZE);
-	return (pte_t *) EMPTY_PGT;
+	return (pmd_t *) EMPTY_PGT;
 }
 
 pte_t __bad_page(void)
@@ -151,7 +152,7 @@
 	start_mem = PAGE_ALIGN(start_mem);
 
 	/*
-	 * Mark the pages used by the kernel as reserved,,
+	 * Mark the pages used by the kernel as reserved..
 	 */
 	tmp = KERNEL_START;
 	while (tmp < start_mem) {
diff -u --recursive --new-file v1.1.87/linux/arch/i386/boot/compressed/Makefile linux/arch/i386/boot/compressed/Makefile
--- v1.1.87/linux/arch/i386/boot/compressed/Makefile	Mon Jan 30 08:53:06 1995
+++ linux/arch/i386/boot/compressed/Makefile	Tue Jan 31 08:58:00 1995
@@ -34,7 +34,7 @@
 xtract: xtract.c
 	$(HOSTCC) $(CFLAGS) -o xtract xtract.c
 
-piggyback: xtract.c
+piggyback: piggyback.c
 	$(HOSTCC) $(CFLAGS) -o piggyback piggyback.c
 
 clean:
diff -u --recursive --new-file v1.1.87/linux/arch/i386/config.in linux/arch/i386/config.in
--- v1.1.87/linux/arch/i386/config.in	Mon Jan 30 08:53:06 1995
+++ linux/arch/i386/config.in	Tue Jan 31 14:36:23 1995
@@ -149,6 +149,7 @@
 		bool 'EtherExpress support' CONFIG_EEXPRESS n
 		bool 'NI5210 support' CONFIG_NI52 n
 		bool 'NI6510 support' CONFIG_NI65 n
+		bool 'WaveLAN support' CONFIG_WAVELAN n
 	fi
 	bool 'HP PCLAN+ (27247B and 27252A) support' CONFIG_HPLAN_PLUS n
 	bool 'HP PCLAN (27245 and other 27xxx series) support' CONFIG_HPLAN n
diff -u --recursive --new-file v1.1.87/linux/arch/i386/kernel/process.c linux/arch/i386/kernel/process.c
--- v1.1.87/linux/arch/i386/kernel/process.c	Sun Jan 22 23:03:57 1995
+++ linux/arch/i386/kernel/process.c	Mon Jan 30 13:08:04 1995
@@ -21,7 +21,9 @@
 #include <linux/a.out.h>
 
 #include <asm/segment.h>
+#include <asm/pgtable.h>
 #include <asm/system.h>
+#include <asm/io.h>
 
 asmlinkage void ret_from_sys_call(void) __asm__("ret_from_sys_call");
 
@@ -45,6 +47,41 @@
 		if (hlt_works_ok && !need_resched)
 			__asm__("hlt");
 		schedule();
+	}
+}
+
+/*
+ * This routine reboots the machine by asking the keyboard
+ * controller to pulse the reset-line low. We try that for a while,
+ * and if it doesn't work, we do some other stupid things.
+ */
+static long no_idt[2] = {0, 0};
+
+static inline void kb_wait(void)
+{
+	int i;
+
+	for (i=0; i<0x10000; i++)
+		if ((inb_p(0x64) & 0x02) == 0)
+			break;
+}
+
+void hard_reset_now(void)
+{
+	int i, j;
+
+	sti();
+/* rebooting needs to touch the page at absolute addr 0 */
+	pg0[0] = 7;
+	*((unsigned short *)0x472) = 0x1234;
+	for (;;) {
+		for (i=0; i<100; i++) {
+			kb_wait();
+			for(j = 0; j < 100000 ; j++)
+				/* nothing */;
+			outb(0xfe,0x64);	 /* pulse reset low */
+		}
+		__asm__ __volatile__("\tlidt %0": "=m" (no_idt));
 	}
 }
 
diff -u --recursive --new-file v1.1.87/linux/arch/i386/kernel/ptrace.c linux/arch/i386/kernel/ptrace.c
--- v1.1.87/linux/arch/i386/kernel/ptrace.c	Sun Jan 22 23:03:57 1995
+++ linux/arch/i386/kernel/ptrace.c	Mon Jan 30 13:08:04 1995
@@ -9,10 +9,11 @@
 #include <linux/errno.h>
 #include <linux/ptrace.h>
 #include <linux/user.h>
+#include <linux/debugreg.h>
 
 #include <asm/segment.h>
+#include <asm/pgtable.h>
 #include <asm/system.h>
-#include <linux/debugreg.h>
 
 /*
  * does not yet catch signals sent when the child dies.
diff -u --recursive --new-file v1.1.87/linux/arch/i386/kernel/vm86.c linux/arch/i386/kernel/vm86.c
--- v1.1.87/linux/arch/i386/kernel/vm86.c	Thu Jan 26 07:49:03 1995
+++ linux/arch/i386/kernel/vm86.c	Mon Jan 30 13:08:04 1995
@@ -12,6 +12,7 @@
 #include <linux/mm.h>
 
 #include <asm/segment.h>
+#include <asm/pgtable.h>
 #include <asm/io.h>
 
 /*
diff -u --recursive --new-file v1.1.87/linux/arch/i386/mm/fault.c linux/arch/i386/mm/fault.c
--- v1.1.87/linux/arch/i386/mm/fault.c	Sun Jan 22 23:03:57 1995
+++ linux/arch/i386/mm/fault.c	Mon Jan 30 13:08:04 1995
@@ -18,6 +18,7 @@
 
 #include <asm/system.h>
 #include <asm/segment.h>
+#include <asm/pgtable.h>
 
 extern void die_if_kernel(char *,struct pt_regs *,long);
 
diff -u --recursive --new-file v1.1.87/linux/arch/i386/mm/init.c linux/arch/i386/mm/init.c
--- v1.1.87/linux/arch/i386/mm/init.c	Thu Jan 26 07:49:03 1995
+++ linux/arch/i386/mm/init.c	Tue Jan 31 09:39:01 1995
@@ -18,6 +18,7 @@
 
 #include <asm/system.h>
 #include <asm/segment.h>
+#include <asm/pgtable.h>
 
 extern void scsi_mem_init(unsigned long);
 extern void sound_mem_init(void);
@@ -137,7 +138,7 @@
 		}
 		pg_table = (pte_t *) pgd_page(pg_dir[768]);
 
-		/* also map it tempoarily at 0x0000000 for init */
+		/* also map it temporarily at 0x0000000 for init */
 		pgd_set(pg_dir+768, pg_table);
 		pgd_set(pg_dir, pg_table);
 		pg_dir++;
diff -u --recursive --new-file v1.1.87/linux/arch/mips/kernel/head.S linux/arch/mips/kernel/head.S
--- v1.1.87/linux/arch/mips/kernel/head.S	Mon Jan 30 06:41:55 1995
+++ linux/arch/mips/kernel/head.S	Tue Jan 31 09:39:02 1995
@@ -436,7 +436,7 @@
 
 		.data
 /*
- * Inital mapping tables for supported Mips boards.
+ * Initial mapping tables for supported Mips boards.
  * First item is always the number of wired TLB entries,
  * following by EntryHi/EntryLo pairs and page mask.
  * Since everything must be quad-aligned (8) we insert
diff -u --recursive --new-file v1.1.87/linux/arch/mips/kernel/irq.c linux/arch/mips/kernel/irq.c
--- v1.1.87/linux/arch/mips/kernel/irq.c	Mon Jan 30 06:41:55 1995
+++ linux/arch/mips/kernel/irq.c	Tue Jan 31 09:39:02 1995
@@ -16,8 +16,8 @@
  */
 
 /*
- * The Deskstation Tyne is almost completly like an IBM compatible PC with
- * another type of microprocessor. Therefore this code is almost completly
+ * The Deskstation Tyne is almost completely like an IBM compatible PC with
+ * another type of microprocessor. Therefore this code is almost completely
  * the same. More work needs to be done to support Acer PICA and other
  * machines.
  */
diff -u --recursive --new-file v1.1.87/linux/arch/sparc/kernel/ioport.c linux/arch/sparc/kernel/ioport.c
--- v1.1.87/linux/arch/sparc/kernel/ioport.c	Thu Jan 26 07:49:03 1995
+++ linux/arch/sparc/kernel/ioport.c	Tue Jan 31 09:39:01 1995
@@ -1,6 +1,6 @@
 /* ioport.c:  I/O access on the Sparc. Work in progress.. Most of the things
  *            in this file are for the sole purpose of getting the kernel
- *	      throught the compiler. :-)
+ *	      through the compiler. :-)
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
  */
diff -u --recursive --new-file v1.1.87/linux/arch/sparc/kernel/probe.c linux/arch/sparc/kernel/probe.c
--- v1.1.87/linux/arch/sparc/kernel/probe.c	Thu Jan 26 07:49:03 1995
+++ linux/arch/sparc/kernel/probe.c	Tue Jan 31 09:39:01 1995
@@ -236,7 +236,7 @@
 void
 probe_clock(int fchild)
 {
-  /* TODO :> I just can't stomache it right now... */
+  /* TODO :> I just can't stomach it right now... */
   return;
 }
 
diff -u --recursive --new-file v1.1.87/linux/arch/sparc/mm/init.c linux/arch/sparc/mm/init.c
--- v1.1.87/linux/arch/sparc/mm/init.c	Thu Jan 26 07:49:03 1995
+++ linux/arch/sparc/mm/init.c	Tue Jan 31 09:39:01 1995
@@ -95,7 +95,7 @@
  * unmaps the bootup page table (as we're now in KSEG, so we don't need it).
  *
  * The bootup sequence put the virtual page table into high memory: that
- * means that we cah change the L1 page table by just using VL1p below.
+ * means that we can change the L1 page table by just using VL1p below.
  */
 
 unsigned long paging_init(unsigned long start_mem, unsigned long end_mem)
diff -u --recursive --new-file v1.1.87/linux/drivers/block/README.aztcd linux/drivers/block/README.aztcd
--- v1.1.87/linux/drivers/block/README.aztcd	Sun Jan 22 23:03:57 1995
+++ linux/drivers/block/README.aztcd	Tue Jan 31 09:39:01 1995
@@ -22,7 +22,7 @@
                          7. OTHER DRIVES
                          8. IF YOU DON'T SUCCEED ... DEBUGGING  
                          9. TECHNICAL HISTORY OF THE DRIVER
-                        10. ACKNOWLEDGEMENTS
+                        10. ACKNOWLEDGMENTS
                         11. PROGRAMMING ADD ONS: CDPLAY.C
                         APPENDIX: Source code of cdplay.c
 ----------------------------------------------------------------------------
@@ -51,7 +51,7 @@
 in /usr/include/linux and the source code 'aztcd.c', which normally resides in
 /usr/src/linux/drivers/block. It uses /dev/aztcd0, which must be a valid block
 device with major number 29 and reside in directory /dev. To mount a CD-ROM,
-your kernel needs to have the ISO9660-filesysytem support included.
+your kernel needs to have the ISO9660-filesystem support included.
 
 
 3. CONFIGURING YOUR KERNEL
@@ -86,7 +86,7 @@
 If your kernel is not yet configured for the AZTECH driver and the ISO9660-
 filesystem, you have to recompile your kernel: 
 
-- Edit aztcd.h to set the I/O-adress to your I/O-Base adress (AZT_BASE_ADDR), 
+- Edit aztcd.h to set the I/O-address to your I/O-Base address (AZT_BASE_ADDR), 
   the driver does not use interrupts or DMA, so if you are using an AZTECH
   CD268, an ORCHID CD-3110 or ORCHID/WEARNES CDD110 that's the only item you 
   have to set up. 
@@ -172,7 +172,7 @@
 the same as AZTECH CDA268-01A, especially they seem to use the same command 
 codes. So it was quite simple to make the AZTECH driver work with these drives. 
 
-Unfortuntately I do not have any of these drives available, so I couldn't test
+Unfortunately I do not have any of these drives available, so I couldn't test
 it myself. But I've got reports, that it works with ORCHID CDS3110 and Game-
 Wave32 sound cards and also with WEARNES CDD110 in some different combinations. 
 In some installations, it seems necessary to initialize the drive with the DOS 
@@ -195,7 +195,7 @@
     DMA:           not used
     Base Address:  something like 300, 320 ...
  You can check this, when you start the DOS driver, which came with your
- drive. By appropiately configuring the drive and the DOS driver you can
+ drive. By appropriately configuring the drive and the DOS driver you can
  check, whether your drive does operate in this mode correctly under DOS. If
  it does not operate under DOS, it won't under Linux.
  Make sure the Base Address is configured correctly in aztcd.h, also make
@@ -297,7 +297,7 @@
 The AZTECH-Driver is a rework of the Mitsumi-Driver. Four major items had to
 be reworked:
 
-a) The Mitsumi drive does issue complete status informations acknowleding
+a) The Mitsumi drive does issue complete status information acknowledging
 each command, the Aztech drive does only signal that the command was
 processed. So whenever the complete status information is needed, an extra
 ACMD_GET_STATUS command is issued. The handshake procedure for the drive
@@ -326,7 +326,7 @@
 uses a different command than for cooked mode, which I only have implemen-
 ted in the ioctl-section but not in the section which is used by the ISO9660- 
 
-The driver was developped on an AST PC with Intel 486/DX2, 8MB RAM, 340MB IDE 
+The driver was developed on an AST PC with Intel 486/DX2, 8MB RAM, 340MB IDE 
 hard disk and on an AST PC with Intel Pentium 60MHz, 16MB RAM, 520MB IDE 
 running Linux kernel version 1.0.9 from the LST 1.8 Distribution. The kernel 
 was compiled with gcc.2.5.8. My CD-ROM drive is an Aztech CDA268-01A. My
@@ -341,7 +341,7 @@
 Mitsumi driver, where I did not completely understand their code.
 
 
-10. ACKNOWLEDGEMENTS
+10. ACKNOWLEDGMENTS
 Without the help of P.Bush, Aztech, who delivered technical information
 about the Aztech Drive and without the help of E.Moenkeberg, GWDG, who did a
 great job in analyzing the command structure of various CD-ROM drives, this
@@ -360,7 +360,7 @@
 and suggested a lot of patches for them.
 
 Joseph Piskor and Peter Nugent were the first users with the ORCHID CD3110
-and also were very patient with the problems, which occured.
+and also were very patient with the problems which occurred.
 
 Anybody, who is interested in these items should have a look at 'ftp.gwdg.de',
 directory 'pub/linux/cdrom' and at 'ftp.cdrom.com', directory 'pub/cdrom'.
@@ -415,7 +415,7 @@
 
    Copyright 1994, 1995 Werner Zimmermann (zimmerma@rz.fht-esslingen.de)
 
-This programm originally was written to test the audio functions of the
+This program originally was written to test the audio functions of the
 AZTECH.CDROM-driver, but it should work with every CD-ROM drive. Before 
 using it, you should set a symlink from /dev/cdrom to your real CDROM
 device.
@@ -592,7 +592,7 @@
                             }
                           break;
               case 'a':   cmd=CDROMPLAYMSF;
-                          printf("Adress (min:sec:frame)  ");
+                          printf("Address (min:sec:frame)  ");
                           scanf("%d:%d:%d",&arg1,&arg2,&arg3);
                           msf.cdmsf_min0  =arg1;
                           msf.cdmsf_sec0  =arg2;
@@ -603,12 +603,12 @@
                           msf.cdmsf_sec1=00;
                           msf.cdmsf_frame1=00;
                           if (ioctl(handle,cmd,&msf)) 
-                           { printf("Drive error or invalid adress\n");
+                           { printf("Drive error or invalid address\n");
                            }
                           break;
 #ifdef AZT_PRIVATE_IOCTLS /*not supported by every CDROM driver*/
               case 'd':   cmd=CDROMREADMODE1;
-                          printf("Adress (min:sec:frame)  ");
+                          printf("Address (min:sec:frame)  ");
                           scanf("%d:%d:%d",&arg1,&arg2,&arg3);
                           azt.msf.cdmsf_min0  =arg1;
                           azt.msf.cdmsf_sec0  =arg2;
@@ -616,7 +616,7 @@
                           if (azt.msf.cdmsf_sec0  > 59) azt.msf.cdmsf_sec0  =59;
                           if (azt.msf.cdmsf_frame0> 74) azt.msf.cdmsf_frame0=74;
                           if (ioctl(handle,cmd,&azt.msf)) 
-                           { printf("Drive error, invalid adress or unsupported command\n");
+                           { printf("Drive error, invalid address or unsupported command\n");
                            }
                           k=0;
                           getchar();
@@ -641,7 +641,7 @@
                            } 
                           break;
               case 'w':   cmd=CDROMREADMODE2;
-                          printf("Adress (min:sec:frame)  ");
+                          printf("Address (min:sec:frame)  ");
                           scanf("%d:%d:%d",&arg1,&arg2,&arg3);
                           azt.msf.cdmsf_min0  =arg1;
                           azt.msf.cdmsf_sec0  =arg2;
@@ -649,7 +649,7 @@
                           if (azt.msf.cdmsf_sec0  > 59) azt.msf.cdmsf_sec0  =59;
                           if (azt.msf.cdmsf_frame0> 74) azt.msf.cdmsf_frame0=74;
                           if (ioctl(handle,cmd,&azt)) 
-                           { printf("Drive error, invalid adress or unsupported command\n");
+                           { printf("Drive error, invalid address or unsupported command\n");
                            }
                           k=0;
                           for (i=0;i<146;i++)
diff -u --recursive --new-file v1.1.87/linux/drivers/block/README.ide linux/drivers/block/README.ide
--- v1.1.87/linux/drivers/block/README.ide	Mon Jan 30 06:41:56 1995
+++ linux/drivers/block/README.ide	Tue Jan 31 09:39:01 1995
@@ -98,11 +98,11 @@
 
 Some Terminology
 ----------------
-IDE = Integrated Drive Electonics, meaning that each drive has a built-in
+IDE = Integrated Drive Electronics, meaning that each drive has a built-in
 controller, which is why an "IDE interface card" is not a "controller card".
 
 IDE drives are designed to attach almost directly to the ISA bus of an AT-style
-computer.  The typcial IDE interface card merely provides I/O port address
+computer.  The typical IDE interface card merely provides I/O port address
 decoding and tri-state buffers, although several newer localbus cards go much
 beyond the basics.  When purchasing a localbus IDE interface, avoid cards with
 an onboard BIOS and those which require special drivers.  Instead, look for a
@@ -119,7 +119,7 @@
 ATAPI = ATA Packet Interface, a new protocol for controlling the drives,
 similar to SCSI protocols, created at the same time as the ATA2 standard.
 ATAPI is currently used for controlling CDROM and TAPE devices, and will
-likely also soon be used for Floppy drives, removeable R/W cartridges,
+likely also soon be used for Floppy drives, removable R/W cartridges,
 and for high capacity hard disk drives.
 
 How To Use *Big* ATA/IDE drives with Linux
diff -u --recursive --new-file v1.1.87/linux/drivers/block/aztcd.c linux/drivers/block/aztcd.c
--- v1.1.87/linux/drivers/block/aztcd.c	Thu Jan 26 07:49:04 1995
+++ linux/drivers/block/aztcd.c	Tue Jan 31 09:39:01 1995
@@ -32,7 +32,7 @@
 		   frame can be read in sequence, this is also the reason for
 		3. getting 'timeout in state 4' messages, but nevertheless
 		   it works
-		W.Zimmermann, Okt. 31, 1994
+		W.Zimmermann, Oct. 31, 1994
 	V0.1    Version is ALPHA, problems #2 and #3 resolved.  
 		W.Zimmermann, Nov. 3, 1994
 	V0.2    Modification to some comments, debugging aids for partial test
@@ -67,24 +67,24 @@
 		W.Zimmermann, Nov. 18, 1994
 	V0.42   Included getAztStatus command in GetQChannelInfo() to allow
 		reading Q-channel info on audio disks, if drive is stopped, 
-		and some other bug fixes in the audio stuff, suggestet by 
+		and some other bug fixes in the audio stuff, suggested by 
 		Robby Schirmer.
 		Added more ioctls (reading data in mode 1 and mode 2).
 		Completely removed the old azt_poll() routine.
 		Detection of ORCHID CDS-3110 in aztcd_init implemented.
 		Additional debugging aids (see the readme file).
-		W.Zimmermann, Dez. 9, 1994  
-	V0.50   Autodetection of drives inplemented.
-		W.Zimmermann, Dez. 12, 1994
+		W.Zimmermann, Dec. 9, 1994  
+	V0.50   Autodetection of drives implemented.
+		W.Zimmermann, Dec. 12, 1994
 	V0.52   Prepared for including in the standard kernel, renamed most
 		variables to contain 'azt', included autoconf.h
-		W.Zimmermann, Dez. 16, 1994        
+		W.Zimmermann, Dec. 16, 1994        
 	V0.6    Version for being included in the standard Linux kernel.
 		Renamed source and header file to aztcd.c and aztcd.h
-		W.Zimmermann, Dez. 24, 1994
+		W.Zimmermann, Dec. 24, 1994
 	V0.7    Changed VERIFY_READ to VERIFY_WRITE in aztcd_ioctl, case
 		CDROMREADMODE1 and CDROMREADMODE2; bug fix in the ioctl,
-		which causes kernel crashs, when playing audio, changed 
+		which causes kernel crashes when playing audio, changed 
 		include-files (config.h instead of autoconf.h, removed
 		delay.h)
 		W.Zimmermann, Jan. 8, 1995
@@ -209,7 +209,7 @@
 
 /* Macros for the drive hardware interface handshake, these macros use
    busy waiting */
-/* Wait for OP_OK = drive answers with AFL_OP_OK after recieving a command*/
+/* Wait for OP_OK = drive answers with AFL_OP_OK after receiving a command*/
 # define OP_OK op_ok()
 void op_ok(void)
 { aztTimeOutCount=0; 
@@ -222,7 +222,7 @@
      } while (aztIndatum!=AFL_OP_OK);
 }
 
-/* Wait for PA_OK = drive answers with AFL_PA_OK after recieving parameters*/
+/* Wait for PA_OK = drive answers with AFL_PA_OK after receiving parameters*/
 # define PA_OK pa_ok()
 void pa_ok(void)
 { aztTimeOutCount=0; 
@@ -377,7 +377,7 @@
 }
 
 
-/* used in azt_poll to poll the status, expects another programm to issue a 
+/* used in azt_poll to poll the status, expects another program to issue a 
  * ACMD_GET_STATUS directly before 
  */
 static int aztStatus(void)  
@@ -637,7 +637,7 @@
 	 */
 		break;
 	case CDROMEJECT:
-	       /* all drives can atleast stop! */
+	       /* all drives can at least stop! */
 		if (aztAudioStatus == CDROM_AUDIO_PLAY) 
 		{ if (aztSendCmd(ACMD_STOP)) return -1;
 		  STEN_LOW_WAIT;
@@ -1439,7 +1439,7 @@
 }
 
 /*
- * Read the table of contents (TOC) and TOC header if neccessary
+ * Read the table of contents (TOC) and TOC header if necessary
  */
 static int aztUpdateToc()
 {
diff -u --recursive --new-file v1.1.87/linux/drivers/block/floppy.c linux/drivers/block/floppy.c
--- v1.1.87/linux/drivers/block/floppy.c	Mon Jan 30 08:53:06 1995
+++ linux/drivers/block/floppy.c	Tue Jan 31 09:30:47 1995
@@ -121,6 +121,7 @@
 #include <linux/string.h>
 #include <linux/fcntl.h>
 #include <linux/delay.h>
+#include <linux/mc146818rtc.h> /* CMOS defines */
 
 #include <asm/dma.h>
 #include <asm/irq.h>
@@ -2851,11 +2852,6 @@
 	return 0;
 #undef IOCTL_ALLOWED
 }
-
-#define CMOS_READ(addr) ({ \
-outb_p(addr,0x70); \
-inb_p(0x71); \
-})
 
 static void set_base_type(int drive,int code)
 {
diff -u --recursive --new-file v1.1.87/linux/drivers/block/hd.c linux/drivers/block/hd.c
--- v1.1.87/linux/drivers/block/hd.c	Mon Jan 16 14:18:16 1995
+++ linux/drivers/block/hd.c	Tue Jan 31 09:30:47 1995
@@ -34,6 +34,7 @@
 #include <linux/malloc.h>
 #include <linux/string.h>
 #include <linux/ioport.h>
+#include <linux/mc146818rtc.h> /* CMOS defines */
 
 #define REALLY_SLOW_IO
 #include <asm/system.h>
@@ -46,12 +47,6 @@
 #define HD_IRQ 14
 
 static int revalidate_hddisk(int, int);
-
-static inline unsigned char CMOS_READ(unsigned char addr)
-{
-	outb_p(addr,0x70);
-	return inb_p(0x71);
-}
 
 #define	HD_DELAY	0
 
diff -u --recursive --new-file v1.1.87/linux/drivers/char/ChangeLog linux/drivers/char/ChangeLog
--- v1.1.87/linux/drivers/char/ChangeLog	Mon Jan  9 07:22:01 1995
+++ linux/drivers/char/ChangeLog	Tue Jan 31 09:39:02 1995
@@ -1,3 +1,31 @@
+Thu Jan 26 09:02:49 1995  Theodore Y. Ts'o  (tytso@rt-11)
+
+	* serial.c (rs_init, set_serial_info, get_serial_info, rs_close):
+		Support close_wait and close_wait2 in the serial driver.
+		This is helpful for slow devices (like serial plotters) so
+		that their outputs don't get flushed upon device close.
+		This has to be configurable because normally we don't want
+		ports to be hung up for long periods of time during a
+		close when they are not connected to a device, or the
+		device is powered off.
+
+		The default is to wait 30 seconds after shutting down the
+		receiver (to prevent echo wars).  This is done by setting
+		close_wait=ASYNC_CLOSE_WAIT_NONE, close_wait2 = 3000.  If
+		XON/XOFF handshaking is used, then the 30 second timeout
+		should happen before the receiver is shutdown; this is
+		done by reversing the values of close_wait and
+		close_wait2.  In the case of a very slow device, the
+		timeouts for close_wait or close_wait2 should be lengthed.
+		If either value is set to 0, the kernel will wait forever
+		for all of the data to be transmitted.  
+
+Thu Jan 17 01:17:20 1995  Theodore Y. Ts'o  (tytso@rt-11)
+
+	* serial.c (startup, change_speed, rs_init): Add support to detect
+		the StarTech 16650 chip.  Treat it as a 16450 for now,
+		because of its FIFO bugs.
+
 Thu Jan  5 21:21:57 1995  <dhinds@allegro.stanford.edu>
 
 	* serial.c: (receive_char): Added counter to prevent infinite loop
diff -u --recursive --new-file v1.1.87/linux/drivers/char/keyboard.c linux/drivers/char/keyboard.c
--- v1.1.87/linux/drivers/char/keyboard.c	Mon Jan 16 14:18:18 1995
+++ linux/drivers/char/keyboard.c	Mon Jan 30 13:08:04 1995
@@ -1158,34 +1158,6 @@
 	sti();
 }
 
-long no_idt[2] = {0, 0};
-
-/*
- * This routine reboots the machine by asking the keyboard
- * controller to pulse the reset-line low. We try that for a while,
- * and if it doesn't work, we do some other stupid things.
- */
-#ifdef __i386__
-void hard_reset_now(void)
-{
-	int i, j;
-
-	sti();
-/* rebooting needs to touch the page at absolute addr 0 */
-	pg0[0] = 7;
-	*((unsigned short *)0x472) = 0x1234;
-	for (;;) {
-		for (i=0; i<100; i++) {
-			kb_wait();
-			for(j = 0; j < 100000 ; j++)
-				/* nothing */;
-			outb(0xfe,0x64);	 /* pulse reset low */
-		}
-		__asm__("\tlidt _no_idt");
-	}
-}
-#endif
-
 unsigned long kbd_init(unsigned long kmem_start)
 {
 	int i;
diff -u --recursive --new-file v1.1.87/linux/drivers/char/serial.c linux/drivers/char/serial.c
--- v1.1.87/linux/drivers/char/serial.c	Thu Jan 26 07:49:05 1995
+++ linux/drivers/char/serial.c	Tue Jan 31 09:39:02 1995
@@ -877,7 +877,15 @@
 	 * Clear the FIFO buffers and disable them
 	 * (they will be reenabled in change_speed())
 	 */
-	if (info->type == PORT_16550A) {
+	if (info->type == PORT_16650) {
+		serial_outp(info, UART_FCR, (UART_FCR_CLEAR_RCVR |
+					     UART_FCR_CLEAR_XMIT));
+#if 0
+		info->xmit_fifo_size = 32;
+#else
+		info->xmit_fifo_size = 1;
+#endif
+	} else if (info->type == PORT_16550A) {
 		serial_outp(info, UART_FCR, (UART_FCR_CLEAR_RCVR |
 					     UART_FCR_CLEAR_XMIT));
 		info->xmit_fifo_size = 16;
@@ -1148,6 +1156,18 @@
 			fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1;
 		else
 			fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_8;
+	} else if (info->type == PORT_16650) {
+		/*
+		 * On the 16650, we disable the FIFOs altogether
+		 * because of a design bug in how the implement
+		 * things.  We could support it by completely changing
+		 * how we handle the interrupt driver, but not today....
+		 *
+		 * N.B.  Because there's no way to set a FIFO trigger
+		 * at 1 char, we'd probably disable at speed below
+		 * 2400 baud anyway...
+		 */
+		fcr = 0;
 	} else
 		fcr = 0;
 	
@@ -1404,6 +1424,8 @@
 	tmp.flags = info->flags;
 	tmp.baud_base = info->baud_base;
 	tmp.close_delay = info->close_delay;
+	tmp.closing_wait = info->closing_wait;
+	tmp.closing_wait2 = info->closing_wait2;
 	tmp.custom_divisor = info->custom_divisor;
 	tmp.hub6 = info->hub6;
 	memcpy_tofs(retinfo,&tmp,sizeof(*retinfo));
@@ -1471,6 +1493,8 @@
 	info->custom_divisor = new_serial.custom_divisor;
 	info->type = new_serial.type;
 	info->close_delay = new_serial.close_delay;
+	info->closing_wait = new_serial.closing_wait;
+	info->closing_wait2 = new_serial.closing_wait2;
 
 	release_region(info->port,8);
 	if (change_port || change_irq) {
@@ -1871,6 +1895,8 @@
 		info->normal_termios = *tty->termios;
 	if (info->flags & ASYNC_CALLOUT_ACTIVE)
 		info->callout_termios = *tty->termios;
+	if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE)
+		wait_until_sent(tty, info->closing_wait);
 	/*
 	 * At this point we stop accepting input.  To do this, we
 	 * disable the receive line status interrupts, and tell the
@@ -1881,7 +1907,7 @@
 	info->read_status_mask &= ~UART_LSR_DR;
 	if (info->flags & ASYNC_INITIALIZED) {
 		serial_out(info, UART_IER, info->IER);
-		wait_until_sent(tty, 3000); /* 30 seconds timeout */
+		wait_until_sent(tty, info->closing_wait2);
 		/*
 		 * Before we drop DTR, make sure the UART transmitter
 		 * has completely drained; this is especially
@@ -2329,6 +2355,10 @@
 	if (info->flags & ASYNC_AUTO_IRQ)
 		info->irq = do_auto_irq(info);
 		
+	scratch2 = serial_in(info, UART_LCR);
+	serial_outp(info, UART_LCR, scratch2 | UART_LCR_DLAB);
+	serial_outp(info, UART_EFR, 0);	/* EFR is the same as FCR */
+	serial_outp(info, UART_LCR, scratch2);
 	serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO);
 	scratch = serial_in(info, UART_IIR) >> 6;
 	info->xmit_fifo_size = 1;
@@ -2343,8 +2373,15 @@
 			info->type = PORT_16550;
 			break;
 		case 3:
-			info->type = PORT_16550A;
-			info->xmit_fifo_size = 16;
+			serial_outp(info, UART_LCR, scratch2 | UART_LCR_DLAB);
+			if (serial_in(info, UART_EFR) == 0) {
+				info->type = PORT_16650;
+				info->xmit_fifo_size = 32;
+			} else {
+				info->type = PORT_16550A;
+				info->xmit_fifo_size = 16;
+			}
+			serial_outp(info, UART_LCR, scratch2);
 			break;
 	}
 	if (info->type == PORT_16450) {
@@ -2457,6 +2494,8 @@
 		info->type = PORT_UNKNOWN;
 		info->custom_divisor = 0;
 		info->close_delay = 50;
+		info->closing_wait = ASYNC_CLOSING_WAIT_NONE;
+		info->closing_wait2 = 3000;
 		info->x_char = 0;
 		info->event = 0;
 		info->count = 0;
@@ -2491,6 +2530,9 @@
 				break;
 			case PORT_16550A:
 				printk(" is a 16550A\n");
+				break;
+			case PORT_16650:
+				printk(" is a 16650\n");
 				break;
 			default:
 				printk("\n");
diff -u --recursive --new-file v1.1.87/linux/drivers/net/3c501.c linux/drivers/net/3c501.c
--- v1.1.87/linux/drivers/net/3c501.c	Thu Jan 26 07:49:05 1995
+++ linux/drivers/net/3c501.c	Tue Jan 31 14:33:21 1995
@@ -677,12 +677,15 @@
 void
 cleanup_module(void)
 {
-	if (MOD_IN_USE)
-		printk("3c501: device busy, remove delayed\n");
-	else
-	{
-		unregister_netdev(&dev_3c501);
-	}
+	/* No need to check MOD_IN_USE, as sys_delete_module() checks. */
+	unregister_netdev(&dev_3c501);
+
+	/* Free up the private structure, or leak memory :-)  */
+	kfree(dev_3c501.priv);
+	dev_3c501.priv = NULL;	/* gets re-allocated by el1_probe1 */
+
+	/* If we don't do this, we can't re-insmod it later. */
+	release_region(dev_3c501.base_addr, EL1_IO_EXTENT);
 }
 #endif /* MODULE */
 
diff -u --recursive --new-file v1.1.87/linux/drivers/net/Makefile linux/drivers/net/Makefile
--- v1.1.87/linux/drivers/net/Makefile	Mon Jan 30 06:41:56 1995
+++ linux/drivers/net/Makefile	Tue Jan 31 14:36:24 1995
@@ -164,6 +164,12 @@
 MODULES := $(MODULES) eexpress.o
 endif
 
+ifdef CONFIG_WAVELAN
+NETDRV_OBJS := $(NETDRV_OBJS) wavelan.o
+else
+MODULES := $(MODULES) wavelan.o
+endif
+
 ifdef CONFIG_ZNET
 NETDRV_OBJS := $(NETDRV_OBJS) znet.o
 endif
diff -u --recursive --new-file v1.1.87/linux/drivers/net/README.wavelan linux/drivers/net/README.wavelan
--- v1.1.87/linux/drivers/net/README.wavelan	Thu Jan  1 02:00:00 1970
+++ linux/drivers/net/README.wavelan	Tue Jan 31 14:36:24 1995
@@ -0,0 +1,49 @@
+#if	defined(CONFIG_WAVELAN)
+
+Tue Jan 31 10:42:35 EST 1995
+
+0. This document refers to Version 5 of the Linux WaveLAN device driver software.
+   It has been tested successfully under the 1.1.87 release of the Linux
+   kernel.  It is `beta-test' software, so caveat emptor.  Please report bugs
+   to me so that I can fix them quickly.
+
+1. At present the driver only autoprobes for a WaveLAN card at I/O address 0x390.
+   The version of the card that I use (NCR) supports four I/O addresses (selectable
+   via a pair of DIP switches).  If you want the driver to autoprobe a different
+   subset of the four valid addresses then you will need to edit
+   .../drivers/net/wavelan.c (near line 714) and change the initialisation of the
+   `iobase[]' array.  Normally, I use a LILO configuration file directive to
+   obviate the need for autoprobing entirely, a course of action I heartily
+   recommend.
+
+2. By default, the driver uses the Network ID (NWID) stored in the card's Parameter
+   Storage Area (PSA).  However, the PSA NWID can be overridden by a value passed
+   explicitly as the third numeric argument to LILO's "ether=" directive, either
+   at the LILO prompt at boot time or within LILO's configuration file.
+   For example, the following line from such a LILO configuration file would
+   auto-configure the IRQ value, set the I/O base to 0x390 and set the NWID to
+   0x4321, all on a WaveLAN card labelled "eth0":
+
+	..
+	append	="ether=0,0x390,0x4321,eth0"
+	..
+
+3. The files that comprise this software must be incorporated into the Linux
+   kernel source tree (usually rooted at /usr/src/linux).  Following that a
+   "make clean; make config; make dep; make zImage" should produce a Linux
+   kernel incorporating the WaveLAN driver, ready for installation.
+   The files:
+   	drivers/net/wavelan.[ch]
+   	drivers/net/i82586.h
+   are unique to this package and simply may be moved into place.  The
+   others are modified versions of pre-existing files and must
+   be incorporated more carefully.  However, the regions of modified code
+   within these files are small and are bracketted by the preprocessor
+   symbol CONFIG_WAVELAN, so incorporation should be straightforward.
+
+4. If you encounter any problems send me some email.
+
+Good luck,
+Bruce Janson (bruce@cs.usyd.edu.au)
+
+#endif	/* defined(CONFIG_WAVELAN) */
diff -u --recursive --new-file v1.1.87/linux/drivers/net/Space.c linux/drivers/net/Space.c
--- v1.1.87/linux/drivers/net/Space.c	Mon Jan 30 06:41:56 1995
+++ linux/drivers/net/Space.c	Tue Jan 31 14:36:24 1995
@@ -51,6 +51,9 @@
 extern int ewrk3_probe(struct device *);
 extern int de4x5_probe(struct device *);
 extern int el1_probe(struct device *);
+#if	defined(CONFIG_WAVELAN)
+extern int wavelan_probe(struct device *);
+#endif	/* defined(CONFIG_WAVELAN) */
 extern int el16_probe(struct device *);
 extern int elplus_probe(struct device *);
 extern int ac3200_probe(struct device *);
@@ -121,6 +124,9 @@
 #ifdef CONFIG_EL1		/* 3c501 */
 	&& el1_probe(dev)
 #endif
+#if	defined(CONFIG_WAVELAN)	/* WaveLAN */
+	&& wavelan_probe(dev)
+#endif	/* defined(CONFIG_WAVELAN) */
 #ifdef CONFIG_EL16		/* 3c507 */
 	&& el16_probe(dev)
 #endif
diff -u --recursive --new-file v1.1.87/linux/drivers/net/de4x5.h linux/drivers/net/de4x5.h
--- v1.1.87/linux/drivers/net/de4x5.h	Mon Jan 30 06:41:56 1995
+++ linux/drivers/net/de4x5.h	Tue Jan 31 09:39:01 1995
@@ -78,7 +78,7 @@
 ** EISA Configuration Register 2 bit definitions
 */
 #define ER2_BRS       0xc0           /* Boot ROM Size */
-#define ER2_BRA       0x3c           /* Boot ROM Adress <16:13> */
+#define ER2_BRA       0x3c           /* Boot ROM Address <16:13> */
 
 /*
 ** EISA Configuration Register 3 bit definitions
@@ -247,7 +247,7 @@
 #define OMR_BP     0x00010000       /* Back Pressure */
 #define OMR_TR     0x0000c000       /* Threshold Control Bits */
 #define OMR_ST     0x00002000       /* Start/Stop Transmission Command */
-#define OMR_FC     0x00001000       /* Force Collisio Mode */
+#define OMR_FC     0x00001000       /* Force Collision Mode */
 #define OMR_OM     0x00000c00       /* Operating Mode */
 #define OMR_FD     0x00000200       /* Full Duplex Mode */
 #define OMR_FKD    0x00000100       /* Flaky Oscillator Disable */
@@ -343,7 +343,7 @@
 /*
 ** DC21040 SIA Transmit and Receive Register (DE4X5_STRR)
 */
-#define STRR_SPP   0x00004000       /* Set Polarit Plus */
+#define STRR_SPP   0x00004000       /* Set Polarity Plus */
 #define STRR_APE   0x00002000       /* Auto Polarity Enable */
 #define STRR_LTE   0x00001000       /* Link Test Enable */
 #define STRR_SQE   0x00000800       /* Signal Quality Enable */
diff -u --recursive --new-file v1.1.87/linux/drivers/net/i82586.h linux/drivers/net/i82586.h
--- v1.1.87/linux/drivers/net/i82586.h	Thu Jan  1 02:00:00 1970
+++ linux/drivers/net/i82586.h	Tue Jan 31 14:36:24 1995
@@ -0,0 +1,410 @@
+#if	defined(CONFIG_WAVELAN)
+/*
+ * Intel 82586 IEEE 802.3 Ethernet LAN Coprocessor.
+ *
+ * See:
+ *	Intel Microcommunications 1991
+ *	p1-1 to p1-37
+ *	Intel order No. 231658
+ *	ISBN 1-55512-119-5
+ *
+ *     Unfortunately, the above chapter mentions neither
+ * the System Configuration Pointer (SCP) nor the
+ * Intermediate System Configuration Pointer (ISCP),
+ * so we probably need to look elsewhere for the
+ * whole story -- some recommend the "Intel LAN
+ * Components manual" but I have neither a copy
+ * nor a full reference.  But "elsewhere" may be
+ * in the same publication...
+ *     The description of a later device, the
+ * "82596CA High-Performance 32-Bit Local Area Network
+ * Coprocessor", (ibid. p1-38 to p1-109) does mention
+ * the SCP and ISCP and also has an i82586 compatibility
+ * mode.  Even more useful is "AP-235 An 82586 Data Link
+ * Driver" (ibid. p1-337 to p1-417).
+ */
+
+#define	I82586_MEMZ	(64 * 1024)
+
+#define	I82586_SCP_ADDR	(I82586_MEMZ - sizeof(scp_t))
+
+#define	ADDR_LEN	6
+#define	I82586NULL	0xFFFF
+
+#define	toff(t,p,f) 	(unsigned short)((void *)(&((t *)((void *)0 + (p)))->f) - (void *)0)
+
+/*
+ * System Configuration Pointer (SCP).
+ */
+typedef struct scp_t	scp_t;
+struct scp_t
+{
+	unsigned short	scp_sysbus;	/* 82586 bus width:	*/
+#define		SCP_SY_16BBUS	(0x0 << 0)	/* 16 bits */
+#define		SCP_SY_8BBUS	(0x1 << 0)	/*  8 bits. */
+	unsigned short	scp_junk[2];	/* Unused */
+	unsigned short	scp_iscpl;	/* lower 16 bits of ISCP_ADDR */
+	unsigned short	scp_iscph;	/* upper 16 bits of ISCP_ADDR */
+};
+
+/*
+ * Intermediate System Configuration Pointer (ISCP).
+ */
+typedef struct iscp_t	iscp_t;
+struct iscp_t
+{
+	unsigned short	iscp_busy;	/* set by CPU before first CA,	*/
+					/* cleared by 82586 after read.	*/
+	unsigned short	iscp_offset;	/* offset of SCB		*/
+	unsigned short	iscp_basel;	/* base of SCB			*/
+	unsigned short	iscp_baseh;	/*  "				*/
+};
+
+/*
+ * System Control Block (SCB).
+ *	The 82586 writes its status to scb_status and then
+ *	raises an interrupt to alert the CPU.
+ *	The CPU writes a command to scb_command and
+ *	then issues a Channel Attention (CA) to alert the 82586.
+ */
+typedef struct scb_t	scb_t;
+struct scb_t
+{
+	unsigned short	scb_status;	/* Status of 82586		*/
+#define		SCB_ST_INT	(0xF << 12)	/* Some of:		*/
+#define		SCB_ST_CX	(0x1 << 15)	/* Cmd completed	*/
+#define		SCB_ST_FR	(0x1 << 14)	/* Frame received	*/
+#define		SCB_ST_CNA	(0x1 << 13)	/* Cmd unit not active	*/
+#define		SCB_ST_RNR	(0x1 << 12)	/* Rcv unit not ready	*/
+#define		SCB_ST_JUNK0	(0x1 << 11)	/* 0			*/
+#define		SCB_ST_CUS	(0x7 <<  8)	/* Cmd unit status	*/
+#define			SCB_ST_CUS_IDLE	(0 << 8)	/* Idle		*/
+#define			SCB_ST_CUS_SUSP	(1 << 8)	/* Suspended	*/
+#define			SCB_ST_CUS_ACTV	(2 << 8)	/* Active	*/
+#define		SCB_ST_JUNK1	(0x1 <<  7)	/* 0			*/
+#define		SCB_ST_RUS	(0x7 <<  4)	/* Rcv unit status	*/
+#define			SCB_ST_RUS_IDLE	(0 << 4)	/* Idle		*/
+#define			SCB_ST_RUS_SUSP	(1 << 4)	/* Suspended	*/
+#define			SCB_ST_RUS_NRES	(2 << 4)	/* No resources	*/
+#define			SCB_ST_RUS_RDY	(4 << 4)	/* Ready	*/
+	unsigned short	scb_command;	/* Next command			*/
+#define		SCB_CMD_ACK_CX	(0x1 << 15)	/* Ack cmd completion	*/
+#define		SCB_CMD_ACK_FR	(0x1 << 14)	/* Ack frame received	*/
+#define		SCB_CMD_ACK_CNA	(0x1 << 13)	/* Ack CU not active	*/
+#define		SCB_CMD_ACK_RNR	(0x1 << 12)	/* Ack RU not ready	*/
+#define		SCB_CMD_JUNKX	(0x1 << 11)	/* Unused		*/
+#define		SCB_CMD_CUC	(0x7 <<  8)	/* Command Unit command	*/
+#define			SCB_CMD_CUC_NOP	(0 << 8)	/* Nop		*/
+#define			SCB_CMD_CUC_GO	(1 << 8)	/* Start cbl_offset */
+#define			SCB_CMD_CUC_RES	(2 << 8)	/* Resume execution */
+#define			SCB_CMD_CUC_SUS	(3 << 8)	/* Suspend   "	*/
+#define			SCB_CMD_CUC_ABT	(4 << 8)	/* Abort     "	*/
+#define		SCB_CMD_RESET	(0x1 <<  7)	/* Reset chip (hardware) */
+#define		SCB_CMD_RUC	(0x7 <<  4)	/* Receive Unit command	*/
+#define			SCB_CMD_RUC_NOP	(0 << 4)	/* Nop		*/
+#define			SCB_CMD_RUC_GO	(1 << 4)	/* Start rfa_offset */
+#define			SCB_CMD_RUC_RES	(2 << 4)	/* Resume reception */
+#define			SCB_CMD_RUC_SUS	(3 << 4)	/* Suspend   "	*/
+#define			SCB_CMD_RUC_ABT	(4 << 4)	/* Abort     "	*/
+	unsigned short	scb_cbl_offset;	/* Offset of first command unit	*/
+					/* Action Command		*/
+	unsigned short	scb_rfa_offset;	/* Offset of first Receive	*/
+					/* Frame Descriptor in the	*/
+					/* Receive Frame Area		*/
+	unsigned short	scb_crcerrs;	/* Properly aligned frames	*/
+					/* received with a CRC error	*/
+	unsigned short	scb_alnerrs;	/* Misaligned frames received	*/
+					/* with a CRC error		*/
+	unsigned short	scb_rscerrs;	/* Frames lost due to no space	*/
+	unsigned short	scb_ovrnerrs;	/* Frames lost due to slow bus	*/
+};
+
+#define	scboff(p,f) 	toff(scb_t, p, f)
+
+/*
+ * The eight Action Commands.
+ */
+typedef enum acmd_e	acmd_e;
+enum acmd_e
+{
+	acmd_nop	= 0,	/* Do nothing				*/
+	acmd_ia_setup	= 1,	/* Load an (ethernet) address into the	*/
+				/* 82586				*/
+	acmd_configure	= 2,	/* Update the 82586 operating parameters */
+	acmd_mc_setup	= 3,	/* Load a list of (ethernet) multicast	*/
+				/* addresses into the 82586		*/
+	acmd_transmit	= 4,	/* Transmit a frame			*/
+	acmd_tdr	= 5,	/* Perform a Time Domain Reflectometer	*/
+				/* test on the serial link		*/
+	acmd_dump	= 6,	/* Copy 82586 registers to memory	*/
+	acmd_diagnose	= 7,	/* Run an internal self test		*/
+};
+
+/*
+ * Generic Action Command header.
+ */
+typedef struct ach_t	ach_t;
+struct ach_t
+{
+	unsigned short	ac_status;		/* Command status:	*/
+#define		AC_SFLD_C	(0x1 << 15)	/* Command completed	*/
+#define		AC_SFLD_B	(0x1 << 14)	/* Busy executing	*/
+#define		AC_SFLD_OK	(0x1 << 13)	/* Completed error free	*/
+#define		AC_SFLD_A	(0x1 << 12)	/* Command aborted	*/
+#define		AC_SFLD_FAIL	(0x1 << 11)	/* Selftest failed	*/
+#define		AC_SFLD_S10	(0x1 << 10)	/* No carrier sense	*/
+						/* during transmission	*/
+#define		AC_SFLD_S9	(0x1 <<  9)	/* Tx unsuccessful:	*/
+						/* (stopped) lost CTS	*/
+#define		AC_SFLD_S8	(0x1 <<  8)	/* Tx unsuccessful:	*/
+						/* (stopped) slow DMA	*/
+#define		AC_SFLD_S7	(0x1 <<  7)	/* Tx deferred:		*/
+						/* other link traffic	*/
+#define		AC_SFLD_S6	(0x1 <<  6)	/* Heart Beat: collision */
+						/* detect after last tx	*/
+#define		AC_SFLD_S5	(0x1 <<  5)	/* Tx stopped:		*/
+						/* excessive collisions	*/
+#define		AC_SFLD_MAXCOL	(0xF <<  0)	/* Collision count  	*/
+	unsigned short	ac_command;		/* Command specifier:	*/
+#define		AC_CFLD_EL	(0x1 << 15)	/* End of command list	*/
+#define		AC_CFLD_S	(0x1 << 14)	/* Suspend on completion */
+#define		AC_CFLD_I	(0x1 << 13)	/* Interrupt on completion */
+#define		AC_CFLD_CMD	(0x7 <<  0)	/* acmd_e		*/
+	unsigned short	ac_link;		/* Next Action Command	*/
+};
+
+#define	acoff(p,f) 	toff(ach_t, p, f)
+
+/*
+ * The Nop Action Command.
+ */
+typedef struct ac_nop_t	ac_nop_t;
+struct ac_nop_t
+{
+	ach_t	nop_h;
+};
+
+/*
+ * The IA-Setup Action Command.
+ */
+typedef struct ac_ias_t	ac_ias_t;
+struct ac_ias_t
+{
+	ach_t		ias_h;
+	unsigned char	ias_addr[ADDR_LEN]; /* The (ethernet) address	*/
+};
+
+/*
+ * The Configure Action Command.
+ */
+typedef struct ac_cfg_t	ac_cfg_t;
+struct ac_cfg_t
+{
+	ach_t		cfg_h;
+	unsigned char	cfg_byte_cnt;	/* Size foll data: 4-12	*/
+#define	AC_CFG_BYTE_CNT(v)	(((v) & 0xF) << 0)
+	unsigned char	cfg_fifolim;	/* FIFO threshold	*/
+#define	AC_CFG_FIFOLIM(v)	(((v) & 0xF) << 0)
+	unsigned char	cfg_byte8;
+#define	AC_CFG_SAV_BF(v) 	(((v) & 0x1) << 7)	/* Save rxd bad frames	*/
+#define	AC_CFG_SRDY(v) 		(((v) & 0x1) << 6)	/* SRDY/ARDY pin means	*/
+							/* external sync.	*/
+	unsigned char	cfg_byte9;
+#define	AC_CFG_ELPBCK(v)	(((v) & 0x1) << 7)	/* External loopback	*/
+#define	AC_CFG_ILPBCK(v)	(((v) & 0x1) << 6)	/* Internal loopback	*/
+#define	AC_CFG_PRELEN(v)	(((v) & 0x3) << 4)	/* Preamble length	*/
+#define		AC_CFG_PLEN_2		0		/*  2 bytes	*/
+#define		AC_CFG_PLEN_4		1		/*  4 bytes	*/
+#define		AC_CFG_PLEN_8		2		/*  8 bytes	*/
+#define		AC_CFG_PLEN_16		3		/* 16 bytes	*/
+#define	AC_CFG_ALOC(v)		(((v) & 0x1) << 3)	/* Addr/len data is	*/
+							/* explicit in buffers	*/
+#define	AC_CFG_ADDRLEN(v)	(((v) & 0x7) << 0)	/* Bytes per address	*/
+	unsigned char	cfg_byte10;
+#define	AC_CFG_BOFMET(v)	(((v) & 0x1) << 7)	/* Use alternate expo.	*/
+							/* backoff method	*/
+#define	AC_CFG_ACR(v)		(((v) & 0x7) << 4)	/* Accelerated cont. res. */
+#define	AC_CFG_LINPRIO(v)	(((v) & 0x7) << 0)	/* Linear priority	*/
+	unsigned char	cfg_ifs;	/* Interframe spacing		*/
+	unsigned char	cfg_slotl;	/* Slot time (low byte)		*/
+	unsigned char	cfg_byte13;
+#define	AC_CFG_RETRYNUM(v)	(((v) & 0xF) << 4)	/* Max. collision retry	*/
+#define	AC_CFG_SLTTMHI(v)	(((v) & 0x7) << 0)	/* Slot time (high bits) */
+	unsigned char	cfg_byte14;
+#define	AC_CFG_FLGPAD(v)	(((v) & 0x1) << 7)	/* Pad with HDLC flags	*/
+#define	AC_CFG_BTSTF(v)		(((v) & 0x1) << 6)	/* Do HDLC bitstuffing	*/
+#define	AC_CFG_CRC16(v)		(((v) & 0x1) << 5)	/* 16 bit CCITT CRC	*/
+#define	AC_CFG_NCRC(v)		(((v) & 0x1) << 4)	/* Insert no CRC	*/
+#define	AC_CFG_TNCRS(v)		(((v) & 0x1) << 3)	/* Tx even if no carrier */
+#define	AC_CFG_MANCH(v)		(((v) & 0x1) << 2)	/* Manchester coding	*/
+#define	AC_CFG_BCDIS(v)		(((v) & 0x1) << 1)	/* Disable broadcast	*/
+#define	AC_CFG_PRM(v)		(((v) & 0x1) << 0)	/* Promiscuous mode	*/
+	unsigned char	cfg_byte15;
+#define	AC_CFG_ICDS(v)		(((v) & 0x1) << 7)	/* Internal collision	*/
+							/* detect source	*/
+#define	AC_CFG_CDTF(v)		(((v) & 0x7) << 4)	/* Collision detect	*/
+							/* filter in bit times	*/
+#define	AC_CFG_ICSS(v)		(((v) & 0x1) << 3)	/* Internal carrier	*/
+							/* sense source		*/
+#define	AC_CFG_CSTF(v)		(((v) & 0x7) << 0)	/* Carrier sense	*/
+							/* filter in bit times	*/
+	unsigned short	cfg_min_frm_len;
+#define	AC_CFG_MNFRM(v)		(((v) & 0xFF) << 0)	/* Min. bytes/frame (<= 255) */
+};
+
+/*
+ * The MC-Setup Action Command.
+ */
+typedef struct ac_mcs_t	ac_mcs_t;
+struct ac_mcs_t
+{
+	ach_t		mcs_h;
+	unsigned short	mcs_cnt;	/* No. of bytes of MC addresses	*/
+	unsigned short	mcs_data[3];	/* The first MC address ..	*/
+};
+
+/*
+ * The Transmit Action Command.
+ */
+typedef struct ac_tx_t	ac_tx_t;
+struct ac_tx_t
+{
+	ach_t		tx_h;
+	unsigned short	tx_tbd_offset;	/* Address of list of buffers.	*/
+#if	0
+Linux packets are passed down with the destination MAC address
+and length/type field already prepended to the data,
+so we do not need to insert it.  Consistent with this
+we must also set the AC_CFG_ALOC(..) flag during the
+ac_cfg_t action command.
+	unsigned char	tx_addr[ADDR_LEN]; /* The frame dest. address	*/
+	unsigned short	tx_length;	/* The frame length		*/
+#endif	/* 0 */
+};
+
+/*
+ * The Time Domain Reflectometer Action Command.
+ */
+typedef struct ac_tdr_t	ac_tdr_t;
+struct ac_tdr_t
+{
+	ach_t		tdr_h;
+	unsigned short	tdr_result;	/* Result.	*/
+#define		AC_TDR_LNK_OK	(0x1 << 15)	/* No link problem	*/
+#define		AC_TDR_XCVR_PRB	(0x1 << 14)	/* Txcvr cable problem	*/
+#define		AC_TDR_ET_OPN	(0x1 << 13)	/* Open on the link	*/
+#define		AC_TDR_ET_SRT	(0x1 << 12)	/* Short on the link	*/
+#define		AC_TDR_TIME	(0x7FF << 0)	/* Distance to problem	*/
+						/* site	in transmit	*/
+						/* clock cycles		*/
+};
+
+/*
+ * The Dump Action Command.
+ */
+typedef struct ac_dmp_t	ac_dmp_t;
+struct ac_dmp_t
+{
+	ach_t		dmp_h;
+	unsigned short	dmp_offset;	/* Result.	*/
+};
+
+/*
+ * Size of the result of the dump command.
+ */
+#define	DUMPBYTES	170
+
+/*
+ * The Diagnose Action Command.
+ */
+typedef struct ac_dgn_t	ac_dgn_t;
+struct ac_dgn_t
+{
+	ach_t		dgn_h;
+};
+
+/*
+ * Transmit Buffer Descriptor (TBD).
+ */
+typedef struct tbd_t	tbd_t;
+struct tbd_t
+{
+	unsigned short	tbd_status;		/* Written by the CPU	*/
+#define		TBD_STATUS_EOF	(0x1 << 15)	/* This TBD is the	*/
+						/* last for this frame	*/
+#define		TBD_STATUS_ACNT	(0x3FFF << 0)	/* Actual count of data	*/
+						/* bytes in this buffer	*/
+	unsigned short	tbd_next_bd_offset;	/* Next in list		*/
+	unsigned short	tbd_bufl;		/* Buffer address (low)	*/
+	unsigned short	tbd_bufh;		/*    "	     "	(high)	*/
+};
+
+/*
+ * Receive Buffer Descriptor (RBD).
+ */
+typedef struct rbd_t	rbd_t;
+struct rbd_t
+{
+	unsigned short	rbd_status;		/* Written by the 82586	*/
+#define		RBD_STATUS_EOF	(0x1 << 15)	/* This RBD is the	*/
+						/* last for this frame	*/
+#define		RBD_STATUS_F	(0x1 << 14)	/* ACNT field is valid	*/
+#define		RBD_STATUS_ACNT	(0x3FFF << 0)	/* Actual no. of data	*/
+						/* bytes in this buffer	*/
+	unsigned short	rbd_next_rbd_offset;	/* Next rbd in list	*/
+	unsigned short	rbd_bufl;		/* Data pointer (low)	*/
+	unsigned short	rbd_bufh;		/*  "	   "    (high)	*/
+	unsigned short	rbd_el_size;		/* EL+Data buf. size	*/
+#define		RBD_EL	(0x1 << 15)		/* This BD is the	*/
+						/* last in the list	*/
+#define		RBD_SIZE (0x3FFF << 0)		/* No. of bytes the	*/
+						/* buffer can hold	*/
+};
+
+#define	rbdoff(p,f) 	toff(rbd_t, p, f)
+
+/*
+ * Frame Descriptor (FD).
+ */
+typedef struct fd_t	fd_t;
+struct fd_t
+{
+	unsigned short	fd_status;		/* Written by the 82586	*/
+#define		FD_STATUS_C	(0x1 << 15)	/* Completed storing frame */
+#define		FD_STATUS_B	(0x1 << 14)	/* FD was consumed by RU */
+#define		FD_STATUS_OK	(0x1 << 13)	/* Frame rxd successfully */
+#define		FD_STATUS_S11	(0x1 << 11)	/* CRC error		*/
+#define		FD_STATUS_S10	(0x1 << 10)	/* Alignment error	*/
+#define		FD_STATUS_S9	(0x1 <<  9)	/* Ran out of resources	*/
+#define		FD_STATUS_S8	(0x1 <<  8)	/* Rx DMA overrun	*/
+#define		FD_STATUS_S7	(0x1 <<  7)	/* Frame too short	*/
+#define		FD_STATUS_S6	(0x1 <<  6)	/* No EOF flag		*/
+	unsigned short	fd_command;		/* Command		*/
+#define		FD_COMMAND_EL	(0x1 << 15)	/* Last FD in list	*/
+#define		FD_COMMAND_S	(0x1 << 14)	/* Suspend RU after rx	*/
+	unsigned short	fd_link_offset;		/* Next FD		*/
+	unsigned short	fd_rbd_offset;		/* First RBD (data)	*/
+						/* Prepared by CPU,	*/
+						/* updated by 82586	*/
+#if	0
+I think the rest is unused since we
+have set AC_CFG_ALOC(..).  However, just
+in case, we leave the space.
+#endif	/* 0 */
+	unsigned char	fd_dest[ADDR_LEN];	/* Destination address	*/
+						/* Written by 82586	*/
+	unsigned char	fd_src[ADDR_LEN];	/* Source address	*/
+						/* Written by 82586	*/
+	unsigned short	fd_length;		/* Frame length or type	*/
+						/* Written by 82586	*/
+};
+
+#define	fdoff(p,f) 	toff(fd_t, p, f)
+
+/*
+ * This software may only be used and distributed
+ * according to the terms of the GNU Public License.
+ *
+ * For more details, see wavelan.c.
+ */
+#endif	/* defined(CONFIG_WAVELAN) */
diff -u --recursive --new-file v1.1.87/linux/drivers/net/ppp.c linux/drivers/net/ppp.c
--- v1.1.87/linux/drivers/net/ppp.c	Mon Jan 30 06:41:57 1995
+++ linux/drivers/net/ppp.c	Tue Jan 31 09:39:02 1995
@@ -374,7 +374,7 @@
 
   /* RFC 1331, section 7.2 says the minimum value is 1500 bytes */
   if (mru < PPP_MRU)
-    mru = new_mru = PPP_MRU;
+    mru = PPP_MRU;
 
   mtu = (mtu * 2) + 20;
   mru = (mru * 2) + 20;
@@ -1409,8 +1409,8 @@
   case PPPIOCSMRU:
     error = verify_area (VERIFY_READ, (void *) l, sizeof (temp_i));
     if (error == 0) {
-      PRINTKN (3,(KERN_INFO "ppp_ioctl: set mru to %x\n", temp_i));
       temp_i = (int) get_fs_long (l);
+      PRINTKN (3,(KERN_INFO "ppp_ioctl: set mru to %d\n", temp_i));
       if (ppp->mru != temp_i)
 	ppp_changedmtu (ppp, ppp->dev->mtu, temp_i);
     }
diff -u --recursive --new-file v1.1.87/linux/drivers/net/wavelan.c linux/drivers/net/wavelan.c
--- v1.1.87/linux/drivers/net/wavelan.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/net/wavelan.c	Tue Jan 31 14:36:24 1995
@@ -0,0 +1,2338 @@
+/*
+ * AT&T GIS (nee NCR) WaveLAN card:
+ *	An Ethernet-like radio transceiver
+ *	controlled by an Intel 82586 coprocessor.
+ */
+
+#include	<linux/config.h>
+
+#if	defined(CONFIG_WAVELAN)
+#if	defined(MODULE)
+#include	<linux/module.h>
+#include	<linux/version.h>
+#endif	/* defined(MODULE) */
+
+#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/string.h>
+#include	<asm/system.h>
+#include	<asm/bitops.h>
+#include	<asm/io.h>
+#include	<asm/dma.h>
+#include	<errno.h>
+#include	<linux/netdevice.h>
+#include	<linux/etherdevice.h>
+#include	<linux/skbuff.h>
+#include	<linux/malloc.h>
+#include	<linux/timer.h>
+#define	STRUCT_CHECK	1
+#include	"i82586.h"
+#include	"wavelan.h"
+
+#ifndef WAVELAN_DEBUG
+#define WAVELAN_DEBUG			0
+#endif	/* WAVELAN_DEBUG */
+
+#define	nels(a)				(sizeof(a) / sizeof(a[0]))
+
+#define	WATCHDOG_JIFFIES		512	/* TODO: express in HZ. */
+
+typedef struct device		device;
+typedef struct enet_statistics	en_stats;
+typedef struct net_local	net_local;
+typedef struct timer_list	timer_list;
+
+struct net_local
+{
+	en_stats	stats;
+	unsigned int	tx_n_in_use;
+	unsigned char	nwid[2];
+	unsigned short	hacr;
+	unsigned short	rx_head;
+	unsigned short	rx_last;
+	unsigned short	tx_first_free;
+	unsigned short	tx_first_in_use;
+	unsigned int	nresets;
+	unsigned int	correct_nwid;
+	unsigned int	wrong_nwid;
+	unsigned int	promiscuous;
+	timer_list	watchdog;
+	device		*dev;
+	net_local	*prev;
+	net_local	*next;
+};
+
+extern int		wavelan_probe(device *);	/* See Space.c */
+
+static char		*version	= "wavelan.c:v5 31/1/95\n";
+
+/*
+ * Entry point forward declarations.
+ */
+static int		wavelan_probe1(device *, unsigned short);
+static int		wavelan_open(device *);
+static int		wavelan_send_packet(struct sk_buff *, device *);
+static void		wavelan_interrupt(int, struct pt_regs *);
+static int		wavelan_close(device *);
+static en_stats		*wavelan_get_stats(device *);
+static void		wavelan_set_multicast_list(device *, int, void *);
+
+/*
+ * Other forward declarations.
+ */
+static void		wavelan_cu_show_one(device *, net_local *, int, unsigned short);
+static void		wavelan_cu_start(device *);
+static void		wavelan_ru_start(device *);
+static void		wavelan_watchdog(unsigned long);
+#if	0
+static void		wavelan_psa_show(psa_t *);
+static void		wavelan_mmc_show(unsigned short);
+#endif	/* 0 */
+static void		wavelan_scb_show(unsigned short);
+static void		wavelan_ru_show(device *);
+static void		wavelan_cu_show(device *);
+static void		wavelan_dev_show(device *);
+static void		wavelan_local_show(device *);
+
+static unsigned int	wavelan_debug	= WAVELAN_DEBUG;
+static net_local	*first_wavelan	= (net_local *)0;
+
+static
+void
+busy_loop(int i)
+{
+	while (i-- > 0)
+		;
+}
+
+static
+unsigned long
+wavelan_splhi(void)
+{
+	unsigned long	flags;
+
+	save_flags(flags);
+	cli();
+
+	return flags;
+}
+
+static
+void
+wavelan_splx(unsigned long flags)
+{
+	restore_flags(flags);
+}
+
+static
+unsigned short
+hasr_read(unsigned short ioaddr)
+{
+	return inw(HASR(ioaddr));
+}
+
+static
+void
+hacr_write(unsigned short ioaddr, int hacr)
+{
+	outw(hacr, HACR(ioaddr));
+}
+
+static
+void
+hacr_write_slow(unsigned short ioaddr, int hacr)
+{
+	hacr_write(ioaddr, hacr);
+	/* delay might only be needed sometimes */
+	busy_loop(1000);
+}
+
+/*
+ * Set the channel attention bit.
+ */
+static
+void
+set_chan_attn(unsigned short ioaddr, unsigned short current_hacr)
+{
+	hacr_write(ioaddr, current_hacr | HACR_CA);
+}
+
+/*
+ * Reset, and then set host adaptor into default mode.
+ */
+static
+void
+wavelan_reset(unsigned short ioaddr)
+{
+	hacr_write_slow(ioaddr, HACR_RESET);
+	hacr_write(ioaddr, HACR_DEFAULT);
+}
+
+static
+void
+wavelan_16_off(unsigned short ioaddr, unsigned short hacr)
+{
+	hacr &= ~HACR_16BITS;
+
+	hacr_write(ioaddr, hacr);
+}
+
+static
+void
+wavelan_16_on(unsigned short ioaddr, unsigned short hacr)
+{
+	hacr |= HACR_16BITS;
+
+	hacr_write(ioaddr, hacr);
+}
+
+static
+void
+wavelan_ints_off(device *dev)
+{
+	unsigned short	ioaddr;
+	net_local	*lp;
+	unsigned long	x;
+
+	ioaddr = dev->base_addr;
+	lp = (net_local *)dev->priv;
+
+	x = wavelan_splhi();
+
+	lp->hacr &= ~HACR_INTRON;
+	hacr_write(ioaddr, lp->hacr);
+
+	wavelan_splx(x);
+}
+
+static
+void
+wavelan_ints_on(device *dev)
+{
+	unsigned short	ioaddr;
+	net_local	*lp;
+	unsigned long	x;
+
+	ioaddr = dev->base_addr;
+	lp = (net_local *)dev->priv;
+
+	x = wavelan_splhi();
+
+	lp->hacr |= HACR_INTRON;
+	hacr_write(ioaddr, lp->hacr);
+
+	wavelan_splx(x);
+}
+
+/*
+ * Read bytes from the PSA.
+ */
+static
+void
+psa_read(unsigned short ioaddr, unsigned short hacr, int o, unsigned char *b, int n)
+{
+	wavelan_16_off(ioaddr, hacr);
+
+	while (n-- > 0)
+	{
+		outw(o, PIOR2(ioaddr));
+		o++;
+		*b++ = inb(PIOP2(ioaddr));
+	}
+
+	wavelan_16_on(ioaddr, hacr);
+}
+
+/*
+ * Read bytes from the on-board RAM.
+ */
+static
+void
+obram_read(unsigned short ioaddr, unsigned short o, unsigned char *b, int n)
+{
+	n = (n + 1) / (sizeof(unsigned short) / sizeof(unsigned char));
+
+	outw(o, PIOR1(ioaddr));
+
+	insw(PIOP1(ioaddr), (unsigned short *)b, n);
+}
+
+/*
+ * Write bytes to the on-board RAM.
+ */
+static
+void
+obram_write(unsigned short ioaddr, unsigned short o, unsigned char *b, int n)
+{
+	n = (n + 1) / (sizeof(unsigned short) / sizeof(unsigned char));
+
+	outw(o, PIOR1(ioaddr));
+
+	outsw(PIOP1(ioaddr), (unsigned short *)b, n);
+}
+
+/*
+ * Read bytes from the MMC.
+ */
+static
+void
+mmc_read(unsigned short ioaddr, unsigned short o, unsigned char *b, int n)
+{
+	while (n-- > 0)
+	{
+		while (inw(HASR(ioaddr)) & HASR_MMC_BUSY)
+			;
+
+		outw(o << 1, MMCR(ioaddr));
+		o++;
+
+		while (inw(HASR(ioaddr)) & HASR_MMC_BUSY)
+			;
+
+		*b++ = (unsigned char)(inw(MMCR(ioaddr)) >> 8);
+	}
+}
+
+/*
+ * Write bytes to the MMC.
+ */
+static
+void
+mmc_write(unsigned short ioaddr, unsigned short o, unsigned char *b, int n)
+{
+	while (n-- > 0)
+	{
+		while (inw(HASR(ioaddr)) & HASR_MMC_BUSY)
+			;
+
+		outw((unsigned short)(((unsigned short)*b << 8) | (o << 1) | 1), MMCR(ioaddr));
+		b++;
+		o++;
+	}
+}
+
+/*
+ * Map values from the irq parameter register to irq numbers.
+ */
+static
+int
+wavelan_map_irq(unsigned short ioaddr, unsigned char irqval)
+{
+	int		irq;
+	static int	irqvals[]	=
+	{
+		   0,    0,    0, 0x01,
+		0x02, 0x04,    0, 0x08,
+		   0,    0, 0x10, 0x20,
+		0x40,    0,    0, 0x80,
+	};
+
+	for (irq = 0; irq < nels(irqvals); irq++)
+	{
+		if (irqvals[irq] == (int)irqval)
+			return irq;
+	}
+
+	return -1;
+}
+
+/*
+ * Initialize the Modem Management Controller.
+ */
+static
+void
+wavelan_mmc_init(device *dev, psa_t *psa)
+{
+	unsigned short	ioaddr;
+	net_local	*lp;
+	mmw_t		m;
+	int		configured;
+
+	ioaddr = dev->base_addr;
+	lp = (net_local *)dev->priv;
+	memset(&m, 0x00, sizeof(m));
+
+	/*
+	 *	configured = psa->psa_conf_status & 1;
+	 *
+	 * For now we use the persistent PSA
+	 * information as little as possible, thereby
+	 * allowing us to return to the same known state
+	 * during a hardware reset.
+	 */
+	configured = 0;
+	
+	/*
+	 * Set default modem control parameters.
+	 * See NCR document 407-0024326 Rev. A.
+	 */
+	m.mmw_jabber_enable = 0x01;
+	m.mmw_anten_sel = MMW_ANTEN_SEL_ALG_EN;
+	m.mmw_ifs = 0x20;
+	m.mmw_mod_delay = 0x04;
+	m.mmw_jam_time = 0x38;
+
+	m.mmw_encr_enable = 0;
+	m.mmw_des_io_invert = 0;
+	m.mmw_freeze = 0;
+	m.mmw_decay_prm = 0;
+	m.mmw_decay_updat_prm = 0;
+
+	if (configured)
+	{
+		/*
+		 * Use configuration defaults from parameter storage area.
+		 */
+		if (psa->psa_undefined & 1)
+			m.mmw_loopt_sel = 0x00;
+		else
+			m.mmw_loopt_sel = MMW_LOOPT_SEL_UNDEFINED;
+
+		m.mmw_thr_pre_set = psa->psa_thr_pre_set & 0x3F;
+		m.mmw_quality_thr = psa->psa_quality_thr & 0x0F;
+	}
+	else
+	{
+		if (lp->promiscuous)
+			m.mmw_loopt_sel = MMW_LOOPT_SEL_UNDEFINED;
+		else
+			m.mmw_loopt_sel = 0x00;
+
+		/*
+		 * 0x04 for AT,
+		 * 0x01 for MCA.
+		 */
+		if (psa->psa_comp_number & 1)
+			m.mmw_thr_pre_set = 0x01;
+		else
+			m.mmw_thr_pre_set = 0x04;
+
+		m.mmw_quality_thr = 0x03;
+	}
+
+	m.mmw_netw_id_l = lp->nwid[1];
+	m.mmw_netw_id_h = lp->nwid[0];
+
+	mmc_write(ioaddr, 0, (unsigned char *)&m, sizeof(m));
+}
+
+static
+void
+wavelan_ack(device *dev)
+{
+	unsigned short	ioaddr;
+	net_local	*lp;
+	unsigned short	scb_cs;
+	int		i;
+
+	ioaddr = dev->base_addr;
+	lp = (net_local *)dev->priv;
+
+	obram_read(ioaddr, scboff(OFFSET_SCB, scb_status), (unsigned char *)&scb_cs, sizeof(scb_cs));
+	scb_cs &= SCB_ST_INT;
+
+	if (scb_cs == 0)
+		return;
+
+	obram_write(ioaddr, scboff(OFFSET_SCB, scb_command), (unsigned char *)&scb_cs, sizeof(scb_cs));
+
+	set_chan_attn(ioaddr, lp->hacr);
+
+	for (i = 1000000; i > 0; i--)
+	{
+		obram_read(ioaddr, scboff(OFFSET_SCB, scb_command), (unsigned char *)&scb_cs, sizeof(scb_cs));
+		if (scb_cs == 0)
+			break;
+	}
+
+	if (i <= 0)
+		printk("%s: wavelan_ack(): board not accepting command.\n", dev->name);
+}
+
+/*
+ * Set channel attention bit and busy wait until command has
+ * completed, then acknowledge the command completion.
+ */
+static
+int
+wavelan_synchronous_cmd(device *dev, char *str)
+{
+	unsigned short	ioaddr;
+	net_local	*lp;
+	unsigned short	scb_cmd;
+	ach_t		cb;
+	int		i;
+
+	ioaddr = dev->base_addr;
+	lp = (net_local *)dev->priv;
+
+	scb_cmd = SCB_CMD_CUC & SCB_CMD_CUC_GO;
+	obram_write(ioaddr, scboff(OFFSET_SCB, scb_command), (unsigned char *)&scb_cmd, sizeof(scb_cmd));
+
+	set_chan_attn(ioaddr, lp->hacr);
+
+	for (i = 64000; i > 0; i--)
+	{
+		obram_read(ioaddr, OFFSET_CU, (unsigned char *)&cb, sizeof(cb));
+		if (cb.ac_status & AC_SFLD_C)
+			break;
+	}
+
+	if (i <= 0 || !(cb.ac_status & AC_SFLD_OK))
+	{
+		printk("%s: %s failed; status = 0x%x\n", dev->name, str, cb.ac_status);
+		wavelan_scb_show(ioaddr);
+		return -1;
+	}
+
+	wavelan_ack(dev);
+
+	return 0;
+}
+
+static
+int
+wavelan_hardware_reset(device *dev)
+{
+	unsigned short	ioaddr;
+	psa_t		psa;
+	net_local	*lp;
+	scp_t		scp;
+	iscp_t		iscp;
+	scb_t		scb;
+	ach_t		cb;
+	int		i;
+	ac_cfg_t	cfg;
+	ac_ias_t	ias;
+
+	ioaddr = dev->base_addr;
+	lp = (net_local *)dev->priv;
+
+	lp->nresets++;
+
+	wavelan_reset(ioaddr);
+	lp->hacr = HACR_DEFAULT;
+
+	/*
+	 * Clear the onboard RAM.
+	 */
+	{
+		unsigned char	zeroes[512];
+
+		memset(&zeroes[0], 0x00, sizeof(zeroes));
+
+		for (i = 0; i < I82586_MEMZ; i += sizeof(zeroes))
+			obram_write(ioaddr, i, &zeroes[0], sizeof(zeroes));
+	}
+
+	psa_read(ioaddr, lp->hacr, 0, (unsigned char *)&psa, sizeof(psa));
+
+	wavelan_mmc_init(dev, &psa);
+
+	/*
+	 * Construct the command unit structures:
+	 * scp, iscp, scb, cb.
+	 */
+	memset(&scp, 0x00, sizeof(scp));
+	scp.scp_sysbus = SCP_SY_16BBUS;
+	scp.scp_iscpl = OFFSET_ISCP;
+	obram_write(ioaddr, OFFSET_SCP, (unsigned char *)&scp, sizeof(scp));
+
+	memset(&iscp, 0x00, sizeof(iscp));
+	iscp.iscp_busy = 1;
+	iscp.iscp_offset = OFFSET_SCB;
+	obram_write(ioaddr, OFFSET_ISCP, (unsigned char *)&iscp, sizeof(iscp));
+
+	memset(&scb, 0x00, sizeof(scb));
+	scb.scb_command = SCB_CMD_RESET;
+	scb.scb_cbl_offset = OFFSET_CU;
+	scb.scb_rfa_offset = OFFSET_RU;
+	obram_write(ioaddr, OFFSET_SCB, (unsigned char *)&scb, sizeof(scb));
+
+	set_chan_attn(ioaddr, lp->hacr);
+
+	for (i = 1000000; i > 0; i--)
+	{
+		obram_read(ioaddr, OFFSET_ISCP, (unsigned char *)&iscp, sizeof(iscp));
+
+		if (iscp.iscp_busy == (unsigned short)0)
+			break;
+	}
+
+	if (i <= 0)
+		printk("%s: wavelan_hardware_reset(): iscp_busy timeout.\n", dev->name);
+
+	for (i = 15000; i > 0; i--)
+	{
+		obram_read(ioaddr, OFFSET_SCB, (unsigned char *)&scb, sizeof(scb));
+
+		if (scb.scb_status == (SCB_ST_CX | SCB_ST_CNA))
+			break;
+	}
+
+	if (i <= 0)
+		printk("%s: wavelan_hardware_reset(): status: expected 0x%02x, got 0x%02x.\n", dev->name, SCB_ST_CX | SCB_ST_CNA, scb.scb_status);
+
+	wavelan_ack(dev);
+
+	memset(&cb, 0x00, sizeof(cb));
+	cb.ac_command = AC_CFLD_EL | (AC_CFLD_CMD & acmd_diagnose);
+	cb.ac_link = OFFSET_CU;
+	obram_write(ioaddr, OFFSET_CU, (unsigned char *)&cb, sizeof(cb));
+
+	if (wavelan_synchronous_cmd(dev, "diag()") == -1)
+		return -1;
+
+	obram_read(ioaddr, OFFSET_CU, (unsigned char *)&cb, sizeof(cb));
+	if (cb.ac_status & AC_SFLD_FAIL)
+	{
+		printk("%s: wavelan_hardware_reset(): i82586 Self Test failed.\n", dev->name);
+		return -1;
+	}
+
+	memset(&cfg, 0x00, sizeof(cfg));
+
+#if	0
+	/*
+	 * The default board configuration.
+	 */
+	cfg.fifolim_bytecnt 	= 0x080c;
+	cfg.addrlen_mode  	= 0x2600;
+	cfg.linprio_interframe	= 0x7820;	/* IFS=120, ACS=2 */
+	cfg.slot_time      	= 0xf00c;	/* slottime=12    */
+	cfg.hardware	     	= 0x0008;	/* tx even w/o CD */
+	cfg.min_frame_len   	= 0x0040;
+#endif	/* 0 */
+
+	/*
+	 * For Linux we invert AC_CFG_ALOC(..) so as to conform
+	 * to the way that net packets reach us from above.
+	 * (See also ac_tx_t.)
+	 */
+	cfg.cfg_byte_cnt = AC_CFG_BYTE_CNT(sizeof(ac_cfg_t) - sizeof(ach_t));
+	cfg.cfg_fifolim = AC_CFG_FIFOLIM(8);
+ 	cfg.cfg_byte8 = AC_CFG_SAV_BF(0) |
+			AC_CFG_SRDY(0);
+ 	cfg.cfg_byte9 = AC_CFG_ELPBCK(0) |
+			AC_CFG_ILPBCK(0) |
+			AC_CFG_PRELEN(AC_CFG_PLEN_2) |
+			AC_CFG_ALOC(1) |
+			AC_CFG_ADDRLEN(WAVELAN_ADDR_SIZE);
+	cfg.cfg_byte10 = AC_CFG_BOFMET(0) |
+			AC_CFG_ACR(0) |
+			AC_CFG_LINPRIO(0);
+	cfg.cfg_ifs = 32;
+	cfg.cfg_slotl = 0;
+	cfg.cfg_byte13 = AC_CFG_RETRYNUM(15) |
+			AC_CFG_SLTTMHI(2);
+	cfg.cfg_byte14 = AC_CFG_FLGPAD(0) |
+			AC_CFG_BTSTF(0) |
+			AC_CFG_CRC16(0) |
+			AC_CFG_NCRC(0) |
+			AC_CFG_TNCRS(1) |
+			AC_CFG_MANCH(0) |
+			AC_CFG_BCDIS(0) |
+			AC_CFG_PRM(lp->promiscuous);
+	cfg.cfg_byte15 = AC_CFG_ICDS(0) |
+			AC_CFG_CDTF(0) |
+			AC_CFG_ICSS(0) |
+			AC_CFG_CSTF(0);
+/*
+	cfg.cfg_min_frm_len = AC_CFG_MNFRM(64);
+*/
+	cfg.cfg_min_frm_len = AC_CFG_MNFRM(8);
+
+	cfg.cfg_h.ac_command = AC_CFLD_EL | (AC_CFLD_CMD & acmd_configure);
+	cfg.cfg_h.ac_link = OFFSET_CU;
+	obram_write(ioaddr, OFFSET_CU, (unsigned char *)&cfg, sizeof(cfg));
+
+	if (wavelan_synchronous_cmd(dev, "reset()-configure") == -1)
+		return -1;
+
+	memset(&ias, 0x00, sizeof(ias));
+	ias.ias_h.ac_command = AC_CFLD_EL | (AC_CFLD_CMD & acmd_ia_setup);
+	ias.ias_h.ac_link = OFFSET_CU;
+	memcpy(&ias.ias_addr[0], (unsigned char *)&dev->dev_addr[0], sizeof(ias.ias_addr));
+	obram_write(ioaddr, OFFSET_CU, (unsigned char *)&ias, sizeof(ias));
+
+	if (wavelan_synchronous_cmd(dev, "reset()-address") == -1)
+		return -1;
+
+	wavelan_ints_on(dev);
+
+	if (wavelan_debug > 4)
+	{
+		wavelan_scb_show(ioaddr);
+		printk("%s: Initialized WaveLAN.\n", dev->name);
+	}
+
+	wavelan_ru_start(dev);
+	wavelan_cu_start(dev);
+
+	return 0;
+}
+
+#if	STRUCT_CHECK == 1
+
+static
+char	*
+wavelan_struct_check(void)
+{
+#define	SC(t,s,n)	if (sizeof(t) != s) return n
+	SC(psa_t, PSA_SIZE, "psa_t");
+	SC(mmw_t, MMW_SIZE, "mmw_t");
+	SC(mmr_t, MMR_SIZE, "mmr_t");
+	SC(ha_t, HA_SIZE, "ha_t");
+#undef	SC
+
+	return (char *)0;
+}
+
+#endif	/* STRUCT_CHECK == 1 */
+
+/*
+ * Check for a network adaptor of this type.
+ * Return '0' iff one exists.
+ * (There seem to be different interpretations of
+ * the initial value of dev->base_addr.
+ * We follow the example in drivers/net/ne.c.)
+ */
+int
+wavelan_probe(device *dev)
+{
+	int			i;
+	short			base_addr;
+	static unsigned short	iobase[]	=
+	{
+#if	0
+		Leave out 0x3C0 for now -- seems to clash
+		with some video controllers.
+		Leave out the others too -- we will always
+		use 0x390 and leave 0x300 for the Ethernet device.
+		0x300, 0x390, 0x3E0, 0x3C0,
+#endif	/* 0 */
+		0x390,
+	};
+
+#if	STRUCT_CHECK == 1
+	if (wavelan_struct_check() != (char *)0)
+	{
+		printk("%s: structure/compiler botch: \"%s\"\n", dev->name, wavelan_struct_check());
+		return ENODEV;
+	}
+#endif	/* STRUCT_CHECK == 1 */
+
+	base_addr = dev->base_addr;
+
+	if (base_addr < 0)
+		/*
+		 * Don't probe at all.
+		 */
+		return ENXIO;
+
+	if (base_addr > 0x100)
+		/*
+		 * Check a single specified location.
+		 */
+		return wavelan_probe1(dev, base_addr);
+
+	for (i = 0; i < nels(iobase); i++)
+	{
+		if (check_region(iobase[i], sizeof(ha_t)))
+			continue;
+
+		if (wavelan_probe1(dev, iobase[i]) == 0)
+			return 0;
+	}
+
+	return ENODEV;
+}
+
+static
+int
+wavelan_probe1(device *dev, unsigned short ioaddr)
+{
+	psa_t		psa;
+	int		irq;
+	int		i;
+	net_local	*lp;
+
+	wavelan_reset(ioaddr);
+
+	psa_read(ioaddr, HACR_DEFAULT, 0, (unsigned char *)&psa, sizeof(psa));
+
+	/*
+	 * Check the first three octets of the MAC address
+	 * for the manufacturer's code.
+	 */ 
+	if
+	(
+		psa.psa_univ_mac_addr[0] != SA_ADDR0
+		||
+		psa.psa_univ_mac_addr[1] != SA_ADDR1
+		||
+		psa.psa_univ_mac_addr[2] != SA_ADDR2
+	)
+		return ENODEV;
+
+	printk("%s: WaveLAN at %#x,", dev->name, ioaddr);
+
+	if ((irq = wavelan_map_irq(ioaddr, psa.psa_int_req_no)) == -1)
+	{
+		printk(" could not wavelan_map_irq(0x%x, %d).\n", ioaddr, psa.psa_int_req_no);
+		return EAGAIN;
+	}
+
+	dev->irq = irq;
+
+	request_region(ioaddr, sizeof(ha_t), "wavelan");
+	dev->base_addr = ioaddr;
+
+	/*
+	 * Apparently the third numeric argument to LILO's
+	 * `ether=' control line arrives here as `dev->mem_start'.
+	 * If it is non-zero we use it instead of the PSA NWID.
+	 */
+	if (dev->mem_start != 0)
+	{
+		psa.psa_nwid[0] = (dev->mem_start >> 8) & 0xFF;
+		psa.psa_nwid[1] = (dev->mem_start >> 0) & 0xFF;
+	}
+
+	dev->mem_start = 0x0000;
+	dev->mem_end = 0x0000;
+	dev->if_port = 0;
+
+	memcpy(&dev->dev_addr[0], &psa.psa_univ_mac_addr[0], WAVELAN_ADDR_SIZE);
+
+	for (i = 0; i < WAVELAN_ADDR_SIZE; i++)
+		printk("%s%02x", (i == 0) ? " " : ":", dev->dev_addr[i]);
+
+	printk(", IRQ %d", dev->irq);
+	printk(", nwid 0x%02x%02x", psa.psa_nwid[0], psa.psa_nwid[1]);
+
+	printk(", PC");
+	switch (psa.psa_comp_number)
+	{
+	case PSA_COMP_PC_AT_915:
+	case PSA_COMP_PC_AT_2400:
+		printk("-AT");
+		break;
+
+	case PSA_COMP_PC_MC_915:
+	case PSA_COMP_PC_MC_2400:
+		printk("-MC");
+		break;
+
+	case PSA_COMP_PCMCIA_915:
+		printk("MCIA");
+		break;
+
+	default:
+		printk("???");
+		break;
+	}
+
+	printk(", ");
+	switch (psa.psa_subband)
+	{
+	case PSA_SUBBAND_915:
+		printk("915");
+		break;
+
+	case PSA_SUBBAND_2425:
+		printk("2425");
+		break;
+
+	case PSA_SUBBAND_2460:
+		printk("2460");
+		break;
+
+	case PSA_SUBBAND_2484:
+		printk("2484");
+		break;
+
+	case PSA_SUBBAND_2430_5:
+		printk("2430.5");
+		break;
+
+	default:
+		printk("???");
+		break;
+	}
+	printk(" MHz");
+
+	printk("\n");
+
+	if (wavelan_debug)
+		printk(version);
+
+	dev->priv = kmalloc(sizeof(net_local), GFP_KERNEL);
+	memset(dev->priv, 0x00, sizeof(net_local));
+	lp = (net_local *)dev->priv;
+
+	if (first_wavelan == (net_local *)0)
+	{
+		first_wavelan = lp;
+		lp->prev = lp;
+		lp->next = lp;
+	}
+	else
+	{
+		lp->prev = first_wavelan->prev;
+		lp->next = first_wavelan;
+		first_wavelan->prev->next = lp;
+		first_wavelan->prev = lp;
+	}
+	lp->dev = dev;
+
+	lp->hacr = HACR_DEFAULT;
+
+	lp->nwid[0] = psa.psa_nwid[0];
+	lp->nwid[1] = psa.psa_nwid[1];
+
+	lp->watchdog.function = wavelan_watchdog;
+	lp->watchdog.data = (unsigned long)dev;
+
+	dev->open = wavelan_open;
+	dev->stop = wavelan_close;
+	dev->hard_start_xmit = wavelan_send_packet;
+	dev->get_stats = wavelan_get_stats;
+	dev->set_multicast_list = &wavelan_set_multicast_list;
+
+	/*
+	 * Fill in the fields of the device structure
+	 * with ethernet-generic values.
+	 */
+	ether_setup(dev);
+
+	dev->mtu = WAVELAN_MTU;
+
+	return 0;
+}
+
+/*
+ * Construct the fd and rbd structures.
+ * Start the receive unit.
+ */
+static
+void
+wavelan_ru_start(device *dev)
+{
+	unsigned short	ioaddr;
+	net_local	*lp;
+	unsigned short	scb_cs;
+	fd_t		fd;
+	rbd_t		rbd;
+	unsigned short	rx;
+	unsigned short	rx_next;
+	int		i;
+
+	ioaddr = dev->base_addr;
+	lp = (net_local *)dev->priv;
+
+	obram_read(ioaddr, scboff(OFFSET_SCB, scb_status), (unsigned char *)&scb_cs, sizeof(scb_cs));
+	if ((scb_cs & SCB_ST_RUS) == SCB_ST_RUS_RDY)
+		return;
+
+	lp->rx_head = OFFSET_RU;
+
+	for (i = 0, rx = lp->rx_head; i < NRXBLOCKS; i++, rx = rx_next)
+	{
+		rx_next = (i == NRXBLOCKS - 1) ? lp->rx_head : rx + RXBLOCKZ;
+
+		fd.fd_status = 0;
+		fd.fd_command = (i == NRXBLOCKS - 1) ? FD_COMMAND_EL : 0;
+		fd.fd_link_offset = rx_next;
+		fd.fd_rbd_offset = rx + sizeof(fd);
+		obram_write(ioaddr, rx, (unsigned char *)&fd, sizeof(fd));
+
+		rbd.rbd_status = 0;
+		rbd.rbd_next_rbd_offset = I82586NULL;
+		rbd.rbd_bufl = rx + sizeof(fd) + sizeof(rbd);
+		rbd.rbd_bufh = 0;
+		rbd.rbd_el_size = RBD_EL | (RBD_SIZE & MAXDATAZ);
+		obram_write(ioaddr, rx + sizeof(fd), (unsigned char *)&rbd, sizeof(rbd));
+
+		lp->rx_last = rx;
+	}
+
+	obram_write(ioaddr, scboff(OFFSET_SCB, scb_rfa_offset), (unsigned char *)&lp->rx_head, sizeof(lp->rx_head));
+
+	scb_cs = SCB_CMD_RUC_GO;
+	obram_write(ioaddr, scboff(OFFSET_SCB, scb_command), (unsigned char *)&scb_cs, sizeof(scb_cs));
+
+	set_chan_attn(ioaddr, lp->hacr);
+
+	for (i = 1000000; i > 0; i--)
+	{
+		obram_read(ioaddr, scboff(OFFSET_SCB, scb_command), (unsigned char *)&scb_cs, sizeof(scb_cs));
+		if (scb_cs == 0)
+			break;
+	}
+
+	if (i <= 0)
+		printk("%s: wavelan_ru_start(): board not accepting command.\n", dev->name);
+}
+
+/*
+ * Initialise the transmit blocks.
+ * Start the command unit executing the NOP
+ * self-loop of the first transmit block.
+ */
+static
+void
+wavelan_cu_start(device *dev)
+{
+	unsigned short	ioaddr;
+	net_local	*lp;
+	int		i;
+	unsigned short	txblock;
+	unsigned short	first_nop;
+	unsigned short	scb_cs;
+
+	ioaddr = dev->base_addr;
+	lp = (net_local *)dev->priv;
+
+	lp->tx_first_free = OFFSET_CU;
+	lp->tx_first_in_use = I82586NULL;
+
+	for
+	(
+		i = 0, txblock = OFFSET_CU;
+		i < NTXBLOCKS;
+		i++, txblock += TXBLOCKZ
+	)
+	{
+		ac_tx_t		tx;
+		ac_nop_t	nop;
+		tbd_t		tbd;
+		unsigned short	tx_addr;
+		unsigned short	nop_addr;
+		unsigned short	tbd_addr;
+		unsigned short	buf_addr;
+
+		tx_addr = txblock;
+		nop_addr = tx_addr + sizeof(tx);
+		tbd_addr = nop_addr + sizeof(nop);
+		buf_addr = tbd_addr + sizeof(tbd);
+
+		tx.tx_h.ac_status = 0;
+		tx.tx_h.ac_command = acmd_transmit | AC_CFLD_I;
+		tx.tx_h.ac_link = nop_addr;
+		tx.tx_tbd_offset = tbd_addr;
+		obram_write(ioaddr, tx_addr, (unsigned char *)&tx, sizeof(tx));
+
+		nop.nop_h.ac_status = 0;
+		nop.nop_h.ac_command = acmd_nop;
+		nop.nop_h.ac_link = nop_addr;
+		obram_write(ioaddr, nop_addr, (unsigned char *)&nop, sizeof(nop));
+
+		tbd.tbd_status = TBD_STATUS_EOF;
+		tbd.tbd_next_bd_offset = I82586NULL;
+		tbd.tbd_bufl = buf_addr;
+		tbd.tbd_bufh = 0;
+		obram_write(ioaddr, tbd_addr, (unsigned char *)&tbd, sizeof(tbd));
+	}
+
+	first_nop = OFFSET_CU + (NTXBLOCKS - 1) * TXBLOCKZ + sizeof(ac_tx_t);
+	obram_write(ioaddr, scboff(OFFSET_SCB, scb_cbl_offset), (unsigned char *)&first_nop, sizeof(first_nop));
+
+	scb_cs = SCB_CMD_CUC_GO;
+	obram_write(ioaddr, scboff(OFFSET_SCB, scb_command), (unsigned char *)&scb_cs, sizeof(scb_cs));
+
+	set_chan_attn(ioaddr, lp->hacr);
+
+	for (i = 1000000; i > 0; i--)
+	{
+		obram_read(ioaddr, scboff(OFFSET_SCB, scb_command), (unsigned char *)&scb_cs, sizeof(scb_cs));
+		if (scb_cs == 0)
+			break;
+	}
+
+	if (i <= 0)
+		printk("%s: wavelan_cu_start(): board not accepting command.\n", dev->name);
+
+	lp->tx_n_in_use = 0;
+	dev->tbusy = 0;
+}
+
+static
+int
+wavelan_open(device *dev)
+{
+	unsigned short	ioaddr;
+	net_local	*lp;
+
+	ioaddr = dev->base_addr;
+	lp = (net_local *)dev->priv;
+
+	if (dev->irq == 0)
+		return -ENXIO;
+
+	if
+	(
+		irq2dev_map[dev->irq] != (device *)0
+		/* This is always true, but avoid the false IRQ. */
+		||
+		(irq2dev_map[dev->irq] = dev) == (device *)0
+		||
+		request_irq(dev->irq, &wavelan_interrupt, 0, "WaveLAN") != 0
+	)
+	{
+		irq2dev_map[dev->irq] = (device *)0;
+		return -EAGAIN;
+	}
+
+	if (wavelan_hardware_reset(dev) == -1)
+	{
+		free_irq(dev->irq);
+		irq2dev_map[dev->irq] = (device *)0;
+		return -EAGAIN;
+	}
+
+	dev->interrupt = 0;
+	dev->start = 1;
+
+#if	defined(MODULE)
+	MOD_INC_USE_COUNT;
+#endif	/* defined(MODULE) */
+
+	return 0;
+}
+
+static
+void
+hardware_send_packet(device *dev, void *buf, short length)
+{
+	unsigned short	ioaddr;
+	net_local	*lp;
+	unsigned short	txblock;
+	unsigned short	txpred;
+	unsigned short	tx_addr;
+	unsigned short	nop_addr;
+	unsigned short	tbd_addr;
+	unsigned short	buf_addr;
+	ac_tx_t		tx;
+	ac_nop_t	nop;
+	tbd_t		tbd;
+	unsigned long	x;
+
+	ioaddr = dev->base_addr;
+	lp = (net_local *)dev->priv;
+
+	x = wavelan_splhi();
+
+	txblock = lp->tx_first_free;
+	txpred = txblock - TXBLOCKZ;
+	if (txpred < OFFSET_CU)
+		txpred += NTXBLOCKS * TXBLOCKZ;
+	lp->tx_first_free += TXBLOCKZ;
+	if (lp->tx_first_free >= OFFSET_CU + NTXBLOCKS * TXBLOCKZ)
+		lp->tx_first_free -= NTXBLOCKS * TXBLOCKZ;
+
+/*
+if (lp->tx_n_in_use > 0)
+	printk("%c", "0123456789abcdefghijk"[lp->tx_n_in_use]);
+*/
+
+	lp->tx_n_in_use++;
+
+	tx_addr = txblock;
+	nop_addr = tx_addr + sizeof(tx);
+	tbd_addr = nop_addr + sizeof(nop);
+	buf_addr = tbd_addr + sizeof(tbd);
+
+	/*
+	 * Transmit command.
+	 */
+	tx.tx_h.ac_status = 0;
+	obram_write(ioaddr, toff(ac_tx_t, tx_addr, tx_h.ac_status), (unsigned char *)&tx.tx_h.ac_status, sizeof(tx.tx_h.ac_status));
+
+	/*
+	 * NOP command.
+	 */
+	nop.nop_h.ac_status = 0;
+	obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_status), (unsigned char *)&nop.nop_h.ac_status, sizeof(nop.nop_h.ac_status));
+	nop.nop_h.ac_link = nop_addr;
+	obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_link), (unsigned char *)&nop.nop_h.ac_link, sizeof(nop.nop_h.ac_link));
+
+	/*
+	 * Transmit buffer descriptor. 
+	 */
+	tbd.tbd_status = TBD_STATUS_EOF | (TBD_STATUS_ACNT & length);
+	tbd.tbd_next_bd_offset = I82586NULL;
+	tbd.tbd_bufl = buf_addr;
+	tbd.tbd_bufh = 0;
+	obram_write(ioaddr, tbd_addr, (unsigned char *)&tbd, sizeof(tbd));
+
+	/*
+	 * Data.
+	 */
+	obram_write(ioaddr, buf_addr, buf, length);
+
+	/*
+	 * Overwrite the predecessor NOP link
+	 * so that it points to this txblock.
+	 */
+	nop_addr = txpred + sizeof(tx);
+	nop.nop_h.ac_status = 0;
+	obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_status), (unsigned char *)&nop.nop_h.ac_status, sizeof(nop.nop_h.ac_status));
+	nop.nop_h.ac_link = txblock;
+	obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_link), (unsigned char *)&nop.nop_h.ac_link, sizeof(nop.nop_h.ac_link));
+
+	if (lp->tx_first_in_use == I82586NULL)
+		lp->tx_first_in_use = txblock;
+
+	if (lp->tx_n_in_use < NTXBLOCKS - 1)
+		dev->tbusy = 0;
+
+	dev->trans_start = jiffies;
+
+	if (lp->watchdog.next == (timer_list *)0)
+		wavelan_watchdog((unsigned long)dev);
+
+	wavelan_splx(x);
+
+	if (wavelan_debug > 4)
+	{
+		unsigned char	*a;
+
+		a = (unsigned char *)buf;
+
+		printk
+		(
+			"%s: tx: dest %02x:%02x:%02x:%02x:%02x:%02x, length %d, tbd.tbd_bufl 0x%x.\n",
+			dev->name,
+			a[0], a[1], a[2], a[3], a[4], a[5],
+			length,
+			buf_addr
+		);
+	}
+}
+
+static
+int
+wavelan_send_packet(struct sk_buff *skb, device *dev)
+{
+	unsigned short	ioaddr;
+
+	ioaddr = dev->base_addr;
+
+	if (dev->tbusy)
+	{
+		/*
+		 * If we get here, some higher level
+		 * has decided we are broken.
+		 */
+		int	tickssofar;
+
+		tickssofar = jiffies - dev->trans_start;
+
+		/*
+		 * But for the moment, we will rely on wavelan_watchdog()
+		 * instead as it allows finer control over exactly when we
+		 * make the determination of failure.
+		 *
+		if (tickssofar < 5)
+		 */
+			return 1;
+
+		wavelan_scb_show(ioaddr);
+		wavelan_ru_show(dev);
+		wavelan_cu_show(dev);
+		wavelan_dev_show(dev);
+		wavelan_local_show(dev);
+
+		printk("%s: transmit timed out -- resetting board.\n", dev->name);
+
+		(void)wavelan_hardware_reset(dev);
+	}
+
+	/*
+	 * If some higher layer thinks we've missed
+	 * a tx-done interrupt we are passed NULL.
+	 * Caution: dev_tint() handles the cli()/sti() itself.
+	 */
+	if (skb == (struct sk_buff *)0)
+	{
+		dev_tint(dev);
+		return 0;
+	}
+
+	/*
+	 * Block a timer-based transmit from overlapping.
+	 */
+	if (set_bit(0, (void *)&dev->tbusy) == 0)
+	{
+		short		length;
+		unsigned char	*buf;
+
+		length = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN;
+		buf = skb->data;
+
+		hardware_send_packet(dev, buf, length);
+	}
+	else
+		printk("%s: Transmitter access conflict.\n", dev->name);
+
+	dev_kfree_skb(skb, FREE_WRITE);
+
+	return 0;
+}
+
+#if	0
+static
+int
+addrcmp(unsigned char *a0, unsigned char *a1)
+{
+	int	i;
+
+	for (i = 0; i < WAVELAN_ADDR_SIZE; i++)
+	{
+		if (a0[i] != a1[i])
+			return a0[i] - a1[i];
+	}
+
+	return 0;
+}
+#endif	/* 0 */
+
+/*
+ * Transfer as many packets as we can
+ * from the device RAM.
+ * Called by the interrupt handler.
+ */
+static
+void
+wavelan_receive(device *dev)
+{
+	unsigned short	ioaddr;
+	net_local	*lp;
+	int		nreaped;
+
+	ioaddr = dev->base_addr;
+	lp = (net_local *)dev->priv;
+	nreaped = 0;
+
+	for (;;)
+	{
+		fd_t		fd;
+		rbd_t		rbd;
+		ushort		pkt_len;
+		int		sksize;
+		struct sk_buff	*skb;
+
+		obram_read(ioaddr, lp->rx_head, (unsigned char *)&fd, sizeof(fd));
+
+		if ((fd.fd_status & FD_STATUS_C) != FD_STATUS_C)
+			break;
+
+		nreaped++;
+
+		if
+		(
+			(fd.fd_status & (FD_STATUS_B | FD_STATUS_OK))
+			!=
+			(FD_STATUS_B | FD_STATUS_OK)
+		)
+		{
+			/*
+			 * Not sure about this one -- it does not seem
+			 * to be an error so we will keep quiet about it.
+			if ((fd.fd_status & FD_STATUS_B) != FD_STATUS_B)
+				printk("%s: frame not consumed by RU.\n", dev->name);
+			 */
+
+			if ((fd.fd_status & FD_STATUS_OK) != FD_STATUS_OK)
+				printk("%s: frame not received successfully.\n", dev->name);
+		}
+
+		if ((fd.fd_status & (FD_STATUS_S6 | FD_STATUS_S7 | FD_STATUS_S8 | FD_STATUS_S9 | FD_STATUS_S10 | FD_STATUS_S11)) != 0)
+		{
+			lp->stats.rx_errors++;
+
+			if ((fd.fd_status & FD_STATUS_S6) != 0)
+				printk("%s: no EOF flag.\n", dev->name);
+
+			if ((fd.fd_status & FD_STATUS_S7) != 0)
+			{
+				lp->stats.rx_length_errors++;
+				printk("%s: frame too short.\n", dev->name);
+			}
+
+			if ((fd.fd_status & FD_STATUS_S8) != 0)
+			{
+				lp->stats.rx_over_errors++;
+				printk("%s: rx DMA overrun.\n", dev->name);
+			}
+
+			if ((fd.fd_status & FD_STATUS_S9) != 0)
+			{
+				lp->stats.rx_fifo_errors++;
+				printk("%s: ran out of resources.\n", dev->name);
+			}
+
+			if ((fd.fd_status & FD_STATUS_S10) != 0)
+			{
+				lp->stats.rx_frame_errors++;
+				printk("%s: alignment error.\n", dev->name);
+			}
+
+			if ((fd.fd_status & FD_STATUS_S11) != 0)
+			{
+				lp->stats.rx_crc_errors++;
+				printk("%s: CRC error.\n", dev->name);
+			}
+		}
+
+		if (fd.fd_rbd_offset == I82586NULL)
+			printk("%s: frame has no data.\n", dev->name);
+		else
+		{
+			obram_read(ioaddr, fd.fd_rbd_offset, (unsigned char *)&rbd, sizeof(rbd));
+
+			if ((rbd.rbd_status & RBD_STATUS_EOF) != RBD_STATUS_EOF)
+				printk("%s: missing EOF flag.\n", dev->name);
+
+			if ((rbd.rbd_status & RBD_STATUS_F) != RBD_STATUS_F)
+				printk("%s: missing F flag.\n", dev->name);
+
+			pkt_len = rbd.rbd_status & RBD_STATUS_ACNT;
+
+#if	0
+			{
+				unsigned char		addr[WAVELAN_ADDR_SIZE];
+				int			i;
+				static unsigned char	toweraddr[WAVELAN_ADDR_SIZE]	=
+				{
+					0x08, 0x00, 0x0e, 0x20, 0x3e, 0xd3,
+				};
+
+				obram_read(ioaddr, rbd.rbd_bufl + sizeof(addr), &addr[0], sizeof(addr));
+				if
+				(
+					/*
+					addrcmp(&addr[0], &dev->dev_addr[0]) != 0
+					&&
+					*/
+					addrcmp(&addr[0], toweraddr) != 0
+				)
+				{
+					printk("%s: foreign MAC source addr=", dev->name);
+					for (i = 0; i < WAVELAN_ADDR_SIZE; i++)
+						printk("%s%02x", (i == 0) ? "" : ":", addr[i]);
+					printk("\n");
+				}
+			}
+#endif	/* 0 */
+
+			if (wavelan_debug > 0)
+			{
+				unsigned char	addr[WAVELAN_ADDR_SIZE];
+				unsigned short	ltype;
+				int		i;
+
+#if	0
+				printk("%s: fd_dest=", dev->name);
+				for (i = 0; i < WAVELAN_ADDR_SIZE; i++)
+					printk("%s%02x", (i == 0) ? "" : ":", fd.fd_dest[i]);
+				printk("\n");
+
+				printk("%s: fd_src=", dev->name);
+				for (i = 0; i < WAVELAN_ADDR_SIZE; i++)
+					printk("%s%02x", (i == 0) ? "" : ":", fd.fd_src[i]);
+				printk("\n");
+				printk("%s: fd_length=%d\n", dev->name, fd.fd_length);
+#endif	/* 0 */
+
+				obram_read(ioaddr, rbd.rbd_bufl, &addr[0], sizeof(addr));
+				printk("%s: dest=", dev->name);
+				for (i = 0; i < WAVELAN_ADDR_SIZE; i++)
+					printk("%s%02x", (i == 0) ? "" : ":", addr[i]);
+				printk("\n");
+
+				obram_read(ioaddr, rbd.rbd_bufl + sizeof(addr), &addr[0], sizeof(addr));
+				printk("%s: src=", dev->name);
+				for (i = 0; i < WAVELAN_ADDR_SIZE; i++)
+					printk("%s%02x", (i == 0) ? "" : ":", addr[i]);
+				printk("\n");
+
+				obram_read(ioaddr, rbd.rbd_bufl + sizeof(addr) * 2, (unsigned char *)&ltype, sizeof(ltype));
+				printk("%s: ntohs(length/type)=0x%04x\n", dev->name, ntohs(ltype));
+			}
+
+			sksize = pkt_len;
+
+			if ((skb = alloc_skb(sksize, GFP_ATOMIC)) == (struct sk_buff *)0)
+			{
+				printk("%s: could not alloc_skb(%d, GFP_ATOMIC).\n", dev->name, sksize);
+				lp->stats.rx_dropped++;
+			}
+			else
+			{
+				skb->len = pkt_len;
+				skb->dev = dev;
+
+				obram_read(ioaddr, rbd.rbd_bufl, skb->data, pkt_len);
+
+				if (wavelan_debug > 5)
+				{
+					int	i;
+					int	maxi;
+
+					printk("%s: pkt_len=%d, data=\"", dev->name, pkt_len);
+
+					if ((maxi = pkt_len) > 16)
+						maxi = 16;
+				
+					for (i = 0; i < maxi; i++)
+					{
+						unsigned char	c;
+
+						c = skb->data[i];
+						if (c >= ' ' && c <= '~')
+							printk(" %c", skb->data[i]);
+						else
+							printk("%02x", skb->data[i]);
+					}
+
+					if (maxi < pkt_len)
+						printk("..");
+				
+					printk("\"\n\n");
+				}
+			
+				netif_rx(skb);
+
+				lp->stats.rx_packets++;
+			}
+		}
+
+		fd.fd_status = 0;
+		obram_write(ioaddr, fdoff(lp->rx_head, fd_status), (unsigned char *)&fd.fd_status, sizeof(fd.fd_status));
+
+		fd.fd_command = FD_COMMAND_EL;
+		obram_write(ioaddr, fdoff(lp->rx_head, fd_command), (unsigned char *)&fd.fd_command, sizeof(fd.fd_command));
+
+		fd.fd_command = 0;
+		obram_write(ioaddr, fdoff(lp->rx_last, fd_command), (unsigned char *)&fd.fd_command, sizeof(fd.fd_command));
+
+		lp->rx_last = lp->rx_head;
+		lp->rx_head = fd.fd_link_offset;
+	}
+
+/*
+	if (nreaped > 1)
+		printk("r%d", nreaped);
+*/
+}
+
+/*
+ * Command completion interrupt.
+ * Reclaim as many freed tx buffers as we can.
+ */
+static
+int
+wavelan_complete(device *dev, unsigned short ioaddr, net_local *lp)
+{
+	int	nreaped;
+
+	nreaped = 0;
+
+	for (;;)
+	{
+		unsigned short	tx_status;
+
+		if (lp->tx_first_in_use == I82586NULL)
+			break;
+
+		obram_read(ioaddr, acoff(lp->tx_first_in_use, ac_status), (unsigned char *)&tx_status, sizeof(tx_status));
+
+		if ((tx_status & AC_SFLD_C) == 0)
+			break;
+
+		nreaped++;
+
+		--lp->tx_n_in_use;
+
+/*
+if (lp->tx_n_in_use > 0)
+	printk("%c", "0123456789abcdefghijk"[lp->tx_n_in_use]);
+*/
+
+		if (lp->tx_n_in_use <= 0)
+			lp->tx_first_in_use = I82586NULL;
+		else
+		{
+			lp->tx_first_in_use += TXBLOCKZ;
+			if (lp->tx_first_in_use >= OFFSET_CU + NTXBLOCKS * TXBLOCKZ)
+				lp->tx_first_in_use -= NTXBLOCKS * TXBLOCKZ;
+		}
+
+		if (tx_status & AC_SFLD_OK)
+		{
+			int	ncollisions;
+
+			lp->stats.tx_packets++;
+			ncollisions = tx_status & AC_SFLD_MAXCOL;
+			lp->stats.collisions += ncollisions;
+			/*
+			if (ncollisions > 0)
+				printk("%s: tx completed after %d collisions.\n", dev->name, ncollisions);
+			*/
+		}
+		else
+		{
+			lp->stats.tx_errors++;
+			if (tx_status & AC_SFLD_S10)
+			{
+				lp->stats.tx_carrier_errors++;
+				if (wavelan_debug > 0)
+					printk("%s:     tx error: no CS.\n", dev->name);
+			}
+			if (tx_status & AC_SFLD_S9)
+			{
+				lp->stats.tx_carrier_errors++;
+				printk("%s:     tx error: lost CTS.\n", dev->name);
+			}
+			if (tx_status & AC_SFLD_S8)
+			{
+				lp->stats.tx_fifo_errors++;
+				printk("%s:     tx error: slow DMA.\n", dev->name);
+			}
+			if (tx_status & AC_SFLD_S6)
+			{
+				lp->stats.tx_heartbeat_errors++;
+				if (wavelan_debug > 0)
+					printk("%s:     tx error: heart beat.\n", dev->name);
+			}
+			if (tx_status & AC_SFLD_S5)
+			{
+				lp->stats.tx_aborted_errors++;
+				if (wavelan_debug > 0)
+					printk("%s:     tx error: too many collisions.\n", dev->name);
+			}
+		}
+
+		if (wavelan_debug > 5)
+			printk("%s:     tx completed, tx_status 0x%04x.\n", dev->name, tx_status);
+	}
+
+/*
+	if (nreaped > 1)
+		printk("c%d", nreaped);
+*/
+
+	/*
+	 * Inform upper layers.
+	 */
+	if (lp->tx_n_in_use < NTXBLOCKS - 1)
+	{
+		dev->tbusy = 0;
+		mark_bh(NET_BH);
+	}
+
+	return nreaped;
+}
+
+static
+void
+wavelan_watchdog(unsigned long a)
+{
+	device		*dev;
+	net_local	*lp;
+	unsigned short	ioaddr;
+	unsigned long	x;
+	unsigned int	nreaped;
+
+	x = wavelan_splhi();
+
+	dev = (device *)a;
+	ioaddr = dev->base_addr;
+	lp = (net_local *)dev->priv;
+
+	if (lp->tx_n_in_use <= 0)
+	{
+		wavelan_splx(x);
+		return;
+	}
+
+	lp->watchdog.expires = WATCHDOG_JIFFIES;
+	add_timer(&lp->watchdog);
+
+	if (jiffies - dev->trans_start < WATCHDOG_JIFFIES)
+	{
+		wavelan_splx(x);
+		return;
+	}
+
+	nreaped = wavelan_complete(dev, ioaddr, lp);
+
+	printk("%s: warning: wavelan_watchdog(): %d reaped, %d remain.\n", dev->name, nreaped, lp->tx_n_in_use);
+	/*
+	wavelan_scb_show(ioaddr);
+	wavelan_ru_show(dev);
+	wavelan_cu_show(dev);
+	wavelan_dev_show(dev);
+	wavelan_local_show(dev);
+	*/
+
+	wavelan_splx(x);
+}
+
+static
+void
+wavelan_interrupt(int irq, struct pt_regs *regs)
+{
+	device		*dev;
+	unsigned short	ioaddr;
+	net_local	*lp;
+	unsigned short	hasr;
+	unsigned short	status;
+	unsigned short	ack_cmd;
+
+	if ((dev = (device *)(irq2dev_map[irq])) == (device *)0)
+	{
+		printk("wavelan_interrupt(): irq %d for unknown device.\n", irq);
+		return;
+	}
+
+	ioaddr = dev->base_addr;
+	lp = (net_local *)dev->priv;
+
+	dev->interrupt = 1;
+
+	if ((hasr = hasr_read(ioaddr)) & HASR_MMC_INTR)
+	{
+		unsigned char	dce_status;
+
+		/*
+		 * Interrupt from the modem management controller.
+		 * This will clear it -- ignored for now.
+		 */
+		mmc_read(ioaddr, mmroff(0, mmr_dce_status), &dce_status, sizeof(dce_status));
+		if (wavelan_debug > 4)
+			printk("%s: warning: wavelan_interrupt(): unexpected mmc interrupt: status 0x%04x.\n", dev->name, dce_status);
+	}
+
+	if ((hasr & HASR_82586_INTR) == 0)
+	{
+		dev->interrupt = 0;
+		if (wavelan_debug > 4)
+			printk("%s: warning: wavelan_interrupt() but (hasr & HASR_82586_INTR) == 0.\n", dev->name);
+		return;
+	}
+
+	obram_read(ioaddr, scboff(OFFSET_SCB, scb_status), (unsigned char *)&status, sizeof(status));
+
+	/*
+	 * Acknowledge the interrupt(s).
+	 */
+	ack_cmd = status & SCB_ST_INT;
+
+	obram_write(ioaddr, scboff(OFFSET_SCB, scb_command), (unsigned char *)&ack_cmd, sizeof(ack_cmd));
+
+	set_chan_attn(ioaddr, lp->hacr);
+
+	if (wavelan_debug > 4)
+		printk("%s: interrupt, status 0x%04x.\n", dev->name, status);
+
+	if ((status & SCB_ST_CX) == SCB_ST_CX)
+	{
+		/*
+		 * Command completed.
+		 */
+		if (wavelan_debug > 5)
+			printk("%s: command completed.\n", dev->name);
+		(void)wavelan_complete(dev, ioaddr, lp);
+	}
+
+	if ((status & SCB_ST_FR) == SCB_ST_FR)
+	{
+		/*
+		 * Frame received.
+		 */
+		if (wavelan_debug > 5)
+			printk("%s: received packet.\n", dev->name);
+		wavelan_receive(dev);
+	}
+
+	if
+	(
+		(status & SCB_ST_CNA) == SCB_ST_CNA
+		||
+		(((status & SCB_ST_CUS) != SCB_ST_CUS_ACTV) && dev->start)
+	)
+	{
+		printk("%s: warning: CU inactive -- restarting.\n", dev->name);
+
+		(void)wavelan_hardware_reset(dev);
+	}
+
+	if
+	(
+		(status & SCB_ST_RNR) == SCB_ST_RNR
+		||
+		(((status & SCB_ST_RUS) != SCB_ST_RUS_RDY) && dev->start)
+	)
+	{
+		printk("%s: warning: RU not ready -- restarting.\n", dev->name);
+
+		(void)wavelan_hardware_reset(dev);
+	}
+
+	dev->interrupt = 0;
+}
+
+static
+int
+wavelan_close(device *dev)
+{
+	unsigned short	ioaddr;
+	net_local	*lp;
+	unsigned short	scb_cmd;
+
+	ioaddr = dev->base_addr;
+	lp = (net_local *)dev->priv;
+
+	dev->tbusy = 1;
+	dev->start = 0;
+
+	/*
+	 * Flush the Tx and disable Rx.
+	 */
+	scb_cmd = (SCB_CMD_CUC & SCB_CMD_CUC_SUS) | (SCB_CMD_RUC & SCB_CMD_RUC_SUS);
+	obram_write(ioaddr, scboff(OFFSET_SCB, scb_command), (unsigned char *)&scb_cmd, sizeof(scb_cmd));
+	set_chan_attn(ioaddr, lp->hacr);
+
+	wavelan_ints_off(dev);
+
+	free_irq(dev->irq);
+	irq2dev_map[dev->irq] = (device *)0;
+
+	/*
+	 * Release the ioport-region.
+	 */
+	release_region(ioaddr, sizeof(ha_t));
+
+#if	defined(MODULE)
+	MOD_DEC_USE_COUNT;
+#endif	/* defined(MODULE) */
+
+	return 0;
+}
+
+/*
+ * Get the current statistics.
+ * This may be called with the card open or closed.
+ */
+static
+en_stats	*
+wavelan_get_stats(device *dev)
+{
+	net_local	*lp;
+
+	lp = (net_local *)dev->priv;
+
+	return &lp->stats;
+}
+
+static
+void
+wavelan_set_multicast_list(device *dev, int num_addrs, void *addrs)
+{
+	net_local	*lp;
+
+	lp = (net_local *)dev->priv;
+
+	switch (num_addrs)
+	{
+	case -1:
+		/*
+		 * Promiscuous mode: receive all packets.
+		 */
+		lp->promiscuous = 1;
+		(void)wavelan_hardware_reset(dev);
+		break;
+
+	case 0:
+		/*
+		 * Normal mode: disable promiscuous mode,
+		 * clear multicast list.
+		 */
+		lp->promiscuous = 0;
+		(void)wavelan_hardware_reset(dev);
+		break;
+
+	default:
+		/*
+		 * Multicast mode: receive normal and
+		 * multicast packets and do best-effort filtering.
+		 */
+		break;
+	}
+}
+
+/*
+ * Extra WaveLAN-specific device data.
+ * "cat /proc/net/wavelan" -- see fs/proc/net.c.
+ */
+static
+int
+sprintf_stats(char *buffer, device *dev)
+{
+	net_local	*lp;
+	unsigned char	v;
+	mmr_t		m;
+
+	lp = (net_local *)dev->priv;
+
+	if (lp == (net_local *)0)
+		return sprintf(buffer, "%6s: No statistics available.\n", dev->name);
+
+	v = (unsigned char)1;
+	mmc_write(dev->base_addr, mmwoff(0, mmw_freeze), &v, sizeof(v));
+
+	mmc_read(dev->base_addr, mmroff(0, mmr_dce_status), &m.mmr_dce_status, sizeof(m.mmr_dce_status));
+	mmc_read(dev->base_addr, mmroff(0, mmr_correct_nwid_h), &m.mmr_correct_nwid_h, sizeof(m.mmr_correct_nwid_h));
+	mmc_read(dev->base_addr, mmroff(0, mmr_correct_nwid_l), &m.mmr_correct_nwid_l, sizeof(m.mmr_correct_nwid_l));
+	mmc_read(dev->base_addr, mmroff(0, mmr_wrong_nwid_h), &m.mmr_wrong_nwid_h, sizeof(m.mmr_wrong_nwid_h));
+	mmc_read(dev->base_addr, mmroff(0, mmr_wrong_nwid_l), &m.mmr_wrong_nwid_l, sizeof(m.mmr_wrong_nwid_l));
+	mmc_read(dev->base_addr, mmroff(0, mmr_signal_lvl), &m.mmr_signal_lvl, sizeof(m.mmr_signal_lvl));
+	mmc_read(dev->base_addr, mmroff(0, mmr_silence_lvl), &m.mmr_silence_lvl, sizeof(m.mmr_silence_lvl));
+	mmc_read(dev->base_addr, mmroff(0, mmr_sgnl_qual), &m.mmr_sgnl_qual, sizeof(m.mmr_sgnl_qual));
+
+	v = (unsigned char)0;
+	mmc_write(dev->base_addr, mmwoff(0, mmw_freeze), &v, sizeof(v));
+
+	lp->correct_nwid += (m.mmr_correct_nwid_h << 8) | m.mmr_correct_nwid_l;
+	lp->wrong_nwid += (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l;
+
+	return sprintf
+	(
+		buffer,
+		"%6s:   %02x %08x %08x   %02x   %02x   %02x   %02x    %u\n",
+		dev->name,
+		m.mmr_dce_status,
+		lp->correct_nwid,
+		lp->wrong_nwid,
+		m.mmr_signal_lvl,
+		m.mmr_silence_lvl,
+		m.mmr_sgnl_qual,
+		lp->tx_n_in_use,
+		lp->nresets
+	);
+}
+
+int
+wavelan_get_info(char *buffer, char **start, off_t offset, int length)
+{
+	int		len;
+	off_t		begin;
+	off_t		pos;
+	int		size;
+	unsigned long	x;
+
+	len = 0;
+	begin = 0;
+	pos = 0;
+
+	size = sprintf(buffer, "%s", "Iface |  dce    +nwid    -nwid  lvl slnc qual ntxq nrst\n");
+
+	pos += size;
+	len += size;
+	
+	x = wavelan_splhi();
+
+	if (first_wavelan != (net_local *)0)
+	{
+		net_local	*lp;
+
+		lp = first_wavelan;
+		do
+		{
+			size = sprintf_stats(buffer + len, lp->dev);
+
+			len += size;
+			pos = begin + len;
+					
+			if (pos < offset)
+			{
+				len = 0;
+				begin = pos;
+			}
+
+			if (pos > offset + length)
+				break;
+		}
+			while ((lp = lp->next) != first_wavelan);
+	}
+
+	wavelan_splx(x);
+
+	*start = buffer + (offset - begin);	/* Start of wanted data */
+	len -= (offset - begin);		/* Start slop */
+	if (len > length)
+		len = length;			/* Ending slop */
+
+	return len;
+}
+
+#if	defined(MODULE)
+char			kernel_version[]	= UTS_RELEASE;
+static struct device	dev_wavelan		=
+{
+	"       " /* "wavelan" */,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, wavelan_probe
+};
+
+int
+init_module(void)
+{
+	if (register_netdev(&dev_wavelan) != 0)
+		return -EIO;
+	return 0;
+}
+
+void
+cleanup_module(void)
+{
+	if (MOD_IN_USE)
+		printk("wavelan: device busy, remove delayed\n");
+	else
+	{
+		unregister_netdev(&dev_wavelan);
+		kfree_s(dev_wavelan.priv, sizeof(struct net_local));
+		dev_wavelan.priv = NULL;
+	}
+}
+#endif	/* defined(MODULE) */
+
+static
+void
+wavelan_cu_show_one(device *dev, net_local *lp, int i, unsigned short p)
+{
+	unsigned short	ioaddr;
+	ac_tx_t		actx;
+
+	ioaddr = dev->base_addr;
+
+	printk("%d: 0x%x:", i, p);
+
+	obram_read(ioaddr, p, (unsigned char *)&actx, sizeof(actx));
+	printk(" status=0x%x,", actx.tx_h.ac_status);
+	printk(" command=0x%x,", actx.tx_h.ac_command);
+
+/*
+	{
+		tbd_t	tbd;
+
+		obram_read(ioaddr, actx.tx_tbd_offset, (unsigned char *)&tbd, sizeof(tbd));
+		printk(" tbd_status=0x%x,", tbd.tbd_status);
+	}
+*/
+
+	printk("|");
+}
+
+#if	0
+static
+void
+wavelan_psa_show(psa_t *p)
+{
+	printk("psa:");
+
+	printk("psa_io_base_addr_1: 0x%02x,", p->psa_io_base_addr_1);
+	printk("psa_io_base_addr_2: 0x%02x,", p->psa_io_base_addr_2);
+	printk("psa_io_base_addr_3: 0x%02x,", p->psa_io_base_addr_3);
+	printk("psa_io_base_addr_4: 0x%02x,", p->psa_io_base_addr_4);
+	printk("psa_rem_boot_addr_1: 0x%02x,", p->psa_rem_boot_addr_1);
+	printk("psa_rem_boot_addr_2: 0x%02x,", p->psa_rem_boot_addr_2);
+	printk("psa_rem_boot_addr_3: 0x%02x,", p->psa_rem_boot_addr_3);
+	printk("psa_holi_params: 0x%02x,", p->psa_holi_params);
+	printk("psa_int_req_no: %d,", p->psa_int_req_no);
+	printk
+	(
+		"psa_univ_mac_addr[]: %02x:%02x:%02x:%02x:%02x:%02x,",
+		p->psa_univ_mac_addr[0],
+		p->psa_univ_mac_addr[1],
+		p->psa_univ_mac_addr[2],
+		p->psa_univ_mac_addr[3],
+		p->psa_univ_mac_addr[4],
+		p->psa_univ_mac_addr[5]
+	);
+	printk
+	(
+		"psa_local_mac_addr[]: %02x:%02x:%02x:%02x:%02x:%02x,",
+		p->psa_local_mac_addr[0],
+		p->psa_local_mac_addr[1],
+		p->psa_local_mac_addr[2],
+		p->psa_local_mac_addr[3],
+		p->psa_local_mac_addr[4],
+		p->psa_local_mac_addr[5]
+	);
+	printk("psa_univ_local_sel: %d,", p->psa_univ_local_sel);
+	printk("psa_comp_number: %d,", p->psa_comp_number);
+	printk("psa_thr_pre_set: 0x%02x,", p->psa_thr_pre_set);
+	printk("psa_feature_select/decay_prm: 0x%02x,", p->psa_feature_select);
+	printk("psa_subband/decay_update_prm: %d,", p->psa_subband);
+	printk("psa_quality_thr: 0x%02x,", p->psa_quality_thr);
+	printk("psa_mod_delay: 0x%02x,", p->psa_mod_delay);
+	printk("psa_nwid: 0x%02x%02x,", p->psa_nwid[0], p->psa_nwid[1]);
+	printk("psa_undefined: %d,", p->psa_undefined);
+	printk("psa_encryption_select: %d,", p->psa_encryption_select);
+	printk
+	(
+		"psa_encryption_key[]: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x,",
+		p->psa_encryption_key[0],
+		p->psa_encryption_key[1],
+		p->psa_encryption_key[2],
+		p->psa_encryption_key[3],
+		p->psa_encryption_key[4],
+		p->psa_encryption_key[5],
+		p->psa_encryption_key[6],
+		p->psa_encryption_key[7]
+	);
+	printk("psa_databus_width: %d,", p->psa_databus_width);
+	printk("psa_call_code/auto_squelch: 0x%02x,", p->psa_call_code);
+	printk("psa_no_of_retries: %d,", p->psa_no_of_retries);
+	printk("psa_acr: %d,", p->psa_acr);
+	printk("psa_dump_count: %d,", p->psa_dump_count);
+	printk("psa_nwid_prefix: 0x%02x,", p->psa_nwid_prefix);
+	printk("psa_conf_status: %d,", p->psa_conf_status);
+	printk("psa_crc: 0x%02x%02x,", p->psa_crc[0], p->psa_crc[1]);
+	printk("psa_crc_status: 0x%02x,", p->psa_crc_status);
+
+	printk("\n");
+}
+
+static
+void
+wavelan_mmc_show(unsigned short ioaddr)
+{
+	mmr_t	m;
+
+	mmc_read(ioaddr, 0, (unsigned char *)&m, sizeof(m));
+
+	printk("mmr:");
+	printk(" des_status: 0x%x", m.mmr_des_status);
+	printk(" des_avail: 0x%x", m.mmr_des_avail);
+	printk(" des_io_invert: 0x%x", m.mmr_des_io_invert);
+	printk
+	(
+		" dce_status: 0x%x[%s%s%s%s]",
+		m.mmr_dce_status & 0x0F,
+		(m.mmr_dce_status & MMR_DCE_STATUS_ENERG_DET) ? "energy detected," : "",
+		(m.mmr_dce_status & MMR_DCE_STATUS_LOOPT_IND) ? "loop test indicated," : "",
+		(m.mmr_dce_status & MMR_DCE_STATUS_XMTITR_IND) ? "transmitter on," : "",
+		(m.mmr_dce_status & MMR_DCE_STATUS_JBR_EXPIRED) ? "jabber timer expired," : ""
+	);
+	printk(" correct_nwid: %d", m.mmr_correct_nwid_h << 8 | m.mmr_correct_nwid_l);
+	printk(" wrong_nwid: %d", (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l);
+	printk(" thr_pre_set: 0x%x", m.mmr_thr_pre_set);
+	printk(" signal_lvl: %d", m.mmr_signal_lvl);
+	printk(" silence_lvl: %d", m.mmr_silence_lvl);
+	printk(" sgnl_qual: 0x%x", m.mmr_sgnl_qual);
+	printk(" netw_id_l: %x", m.mmr_netw_id_l);
+
+	printk("\n");
+}
+#endif	/* 0 */
+
+static
+void
+wavelan_scb_show(unsigned short ioaddr)
+{
+	scb_t	scb;
+
+	obram_read(ioaddr, OFFSET_SCB, (unsigned char *)&scb, sizeof(scb));   
+
+	printk("scb:");
+
+	printk(" status:");
+	printk
+	(
+		" stat 0x%x[%s%s%s%s]",
+		(scb.scb_status & (SCB_ST_CX | SCB_ST_FR | SCB_ST_CNA | SCB_ST_RNR)) >> 12,
+		(scb.scb_status & SCB_ST_CX) ? "cmd completion interrupt," : "",
+		(scb.scb_status & SCB_ST_FR) ? "frame received," : "",
+		(scb.scb_status & SCB_ST_CNA) ? "cmd unit not active," : "",
+		(scb.scb_status & SCB_ST_RNR) ? "rcv unit not ready," : ""
+	);
+	printk
+	(
+		" cus 0x%x[%s%s%s]",
+		(scb.scb_status & SCB_ST_CUS) >> 8,
+		((scb.scb_status & SCB_ST_CUS) == SCB_ST_CUS_IDLE) ? "idle" : "",
+		((scb.scb_status & SCB_ST_CUS) == SCB_ST_CUS_SUSP) ? "suspended" : "",
+		((scb.scb_status & SCB_ST_CUS) == SCB_ST_CUS_ACTV) ? "active" : ""
+	);
+	printk
+	(
+		" rus 0x%x[%s%s%s%s]",
+		(scb.scb_status & SCB_ST_RUS) >> 4,
+		((scb.scb_status & SCB_ST_RUS) == SCB_ST_RUS_IDLE) ? "idle" : "",
+		((scb.scb_status & SCB_ST_RUS) == SCB_ST_RUS_SUSP) ? "suspended" : "",
+		((scb.scb_status & SCB_ST_RUS) == SCB_ST_RUS_NRES) ? "no resources" : "",
+		((scb.scb_status & SCB_ST_RUS) == SCB_ST_RUS_RDY) ? "ready" : ""
+	);
+
+	printk(" command:");
+	printk
+	(
+		" ack 0x%x[%s%s%s%s]",
+		(scb.scb_command & (SCB_CMD_ACK_CX | SCB_CMD_ACK_FR | SCB_CMD_ACK_CNA | SCB_CMD_ACK_RNR)) >> 12,
+		(scb.scb_command & SCB_CMD_ACK_CX) ? "ack cmd completion," : "",
+		(scb.scb_command & SCB_CMD_ACK_FR) ? "ack frame received," : "",
+		(scb.scb_command & SCB_CMD_ACK_CNA) ? "ack CU not active," : "",
+		(scb.scb_command & SCB_CMD_ACK_RNR) ? "ack RU not ready," : ""
+	);
+	printk
+	(
+		" cuc 0x%x[%s%s%s%s%s]",
+		(scb.scb_command & SCB_CMD_CUC) >> 8,
+		((scb.scb_command & SCB_CMD_CUC) == SCB_CMD_CUC_NOP) ? "nop" : "",
+		((scb.scb_command & SCB_CMD_CUC) == SCB_CMD_CUC_GO) ? "start cbl_offset" : "",
+		((scb.scb_command & SCB_CMD_CUC) == SCB_CMD_CUC_RES) ? "resume execution" : "",
+		((scb.scb_command & SCB_CMD_CUC) == SCB_CMD_CUC_SUS) ? "suspend execution" : "",
+		((scb.scb_command & SCB_CMD_CUC) == SCB_CMD_CUC_ABT) ? "abort execution" : ""
+	);
+	printk
+	(
+		" ruc 0x%x[%s%s%s%s%s]",
+		(scb.scb_command & SCB_CMD_RUC) >> 4,
+		((scb.scb_command & SCB_CMD_RUC) == SCB_CMD_RUC_NOP) ? "nop" : "",
+		((scb.scb_command & SCB_CMD_RUC) == SCB_CMD_RUC_GO) ? "start rfa_offset" : "",
+		((scb.scb_command & SCB_CMD_RUC) == SCB_CMD_RUC_RES) ? "resume reception" : "",
+		((scb.scb_command & SCB_CMD_RUC) == SCB_CMD_RUC_SUS) ? "suspend reception" : "",
+		((scb.scb_command & SCB_CMD_RUC) == SCB_CMD_RUC_ABT) ? "abort reception" : ""
+	);
+
+	printk(" cbl_offset 0x%x", scb.scb_cbl_offset);
+	printk(" rfa_offset 0x%x", scb.scb_rfa_offset);
+
+	printk(" crcerrs %d", scb.scb_crcerrs);
+	printk(" alnerrs %d", scb.scb_alnerrs);
+	printk(" rscerrs %d", scb.scb_rscerrs);
+	printk(" ovrnerrs %d", scb.scb_ovrnerrs);
+
+	printk("\n");
+}
+
+static
+void
+wavelan_ru_show(device *dev)
+{
+	net_local	*lp;
+
+	lp = (net_local *)dev->priv;
+
+	printk("ru:");
+	/*
+	 * Not implemented yet...
+	 */
+	printk("\n");
+}
+
+static
+void
+wavelan_cu_show(device *dev)
+{
+	net_local	*lp;
+	unsigned int	i;
+	unsigned short	p;
+
+	lp = (net_local *)dev->priv;
+
+	printk("cu:");
+	printk("\n");
+
+	for (i = 0, p = lp->tx_first_in_use; i < NTXBLOCKS; i++)
+	{
+		wavelan_cu_show_one(dev, lp, i, p);
+
+		p += TXBLOCKZ;
+		if (p >= OFFSET_CU + NTXBLOCKS * TXBLOCKZ)
+			p -= NTXBLOCKS * TXBLOCKZ;
+	}
+}
+
+static
+void
+wavelan_dev_show(device *dev)
+{
+	printk("dev:");
+	printk(" start=%d,", dev->start);
+	printk(" tbusy=%d,", dev->tbusy);
+	printk(" interrupt=%d,", dev->interrupt);
+	printk(" trans_start=%ld,", dev->trans_start);
+	printk(" flags=0x%x,", dev->flags);
+	printk("\n");
+}
+
+static
+void
+wavelan_local_show(device *dev)
+{
+	net_local	*lp;
+
+	lp = (net_local *)dev->priv;
+
+	printk("local:");
+	printk(" tx_n_in_use=%d,", lp->tx_n_in_use);
+	printk(" hacr=0x%x,", lp->hacr);
+	printk(" rx_head=0x%x,", lp->rx_head);
+	printk(" rx_last=0x%x,", lp->rx_last);
+	printk(" tx_first_free=0x%x,", lp->tx_first_free);
+	printk(" tx_first_in_use=0x%x,", lp->tx_first_in_use);
+	printk("\n");
+}
+
+/*
+ * This software may only be used and distributed
+ * according to the terms of the GNU Public License.
+ *
+ * This software was developed as a component of the
+ * Linux operating system.
+ * It is based on other device drivers and information
+ * either written or supplied by:
+ *	Ajay Bakre (bakre@paul.rutgers.edu),
+ *	Donald Becker (becker@cesdis.gsfc.nasa.gov),
+ *	Loeke Brederveld (Loeke.Brederveld@Utrecht.NCR.com),
+ *	Anders Klemets (klemets@it.kth.se),
+ *	Vladimir V. Kolpakov (w@stier.koenig.ru),
+ *	Marc Meertens (Marc.Meertens@Utrecht.NCR.com),
+ *	Pauline Middelink (middelin@polyware.iaf.nl),
+ *	Robert Morris (rtm@das.harvard.edu),
+ *	Girish Welling (welling@paul.rutgers.edu),
+ *
+ * Thanks go also to:
+ *	James Ashton (jaa101@syseng.anu.edu.au),
+ *	Alan Cox (iialan@iiit.swan.ac.uk),
+ *	Allan Creighton (allanc@cs.usyd.edu.au),
+ *	Matthew Geier (matthew@cs.usyd.edu.au),
+ *	Remo di Giovanni (remo@cs.usyd.edu.au),
+ *	Mark Hagan (mhagan@wtcpost.daytonoh.NCR.COM),
+ *	Tim Nicholson (tim@cs.usyd.edu.au),
+ *	Jeff Noxon (jeff@oylpatch.sccsi.com),
+ *	Ian Parkin (ian@cs.usyd.edu.au),
+ *	John Rosenberg (johnr@cs.usyd.edu.au),
+ *	George Rossi (george@phm.gov.au),
+ *	Arthur Scott (arthur@cs.usyd.edu.au),
+ *	Peter Storey,
+ * for their assistance and advice.
+ *
+ * Please send bug reports, updates, comments to:
+ *
+ * Bruce Janson                                    Email:  bruce@cs.usyd.edu.au
+ * Basser Department of Computer Science           Phone:  +61-2-351-3423
+ * University of Sydney, N.S.W., 2006, AUSTRALIA   Fax:    +61-2-351-3838
+ */
+#endif	/* defined(CONFIG_WAVELAN) */
diff -u --recursive --new-file v1.1.87/linux/drivers/net/wavelan.h linux/drivers/net/wavelan.h
--- v1.1.87/linux/drivers/net/wavelan.h	Thu Jan  1 02:00:00 1970
+++ linux/drivers/net/wavelan.h	Tue Jan 31 14:36:24 1995
@@ -0,0 +1,254 @@
+#if	defined(CONFIG_WAVELAN)
+#define WAVELAN_ADDR_SIZE	6	/* Size of a MAC address */
+#define SA_ADDR0		0x08	/* First octet of WaveLAN MAC addresses */
+#define SA_ADDR1		0x00	/* Second octet of WaveLAN MAC addresses */
+#define SA_ADDR2		0x0E	/* Third octet of WaveLAN MAC addresses */
+#define WAVELAN_MTU		1500	/* Maximum size of WaveLAN packet */
+
+/*
+ * Parameter Storage Area (PSA).
+ */
+typedef struct psa_t	psa_t;
+struct psa_t
+{
+	unsigned char	psa_io_base_addr_1;	/* Base address 1 ??? */
+	unsigned char	psa_io_base_addr_2;	/* Base address 2 */
+	unsigned char	psa_io_base_addr_3;	/* Base address 3 */
+	unsigned char	psa_io_base_addr_4;	/* Base address 4 */
+	unsigned char	psa_rem_boot_addr_1;	/* Remote Boot Address 1 */
+	unsigned char	psa_rem_boot_addr_2;	/* Remote Boot Address 2 */
+	unsigned char	psa_rem_boot_addr_3;	/* Remote Boot Address 3 */
+	unsigned char	psa_holi_params;	/* HOst Lan Interface (HOLI) Parameters */
+	unsigned char	psa_int_req_no;		/* Interrupt Request Line */
+	unsigned char	psa_unused0[7];		/* unused */
+	unsigned char	psa_univ_mac_addr[WAVELAN_ADDR_SIZE];	/* Universal (factory) MAC Address */
+	unsigned char	psa_local_mac_addr[WAVELAN_ADDR_SIZE];	/* Local MAC Address */
+	unsigned char	psa_univ_local_sel;	/* Universal Local Selection */
+#define		PSA_UNIVERSAL	0		/* Universal (factory) */
+#define		PSA_LOCAL	1		/* Local */
+	unsigned char	psa_comp_number;	/* Compatability Number: */
+#define		PSA_COMP_PC_AT_915	0 	/* PC-AT 915 MHz	*/
+#define		PSA_COMP_PC_MC_915	1 	/* PC-MC 915 MHz	*/
+#define		PSA_COMP_PC_AT_2400	2 	/* PC-AT 2.4 GHz	*/
+#define		PSA_COMP_PC_MC_2400	3 	/* PC-MC 2.4 GHz	*/
+#define		PSA_COMP_PCMCIA_915	4 	/* PCMCIA 915 MHz	*/
+	unsigned char	psa_thr_pre_set;	/* Modem Threshold Preset */
+	unsigned char	psa_feature_select;	/* ??? */
+#if	0
+	<alias for above>
+	unsigned char	psa_decay_prm;		/* Modem Decay */
+#endif	/* 0 */
+	unsigned char	psa_subband;		/* Subband	*/
+#define		PSA_SUBBAND_915		0	/* 915 MHz	*/
+#define		PSA_SUBBAND_2425	1	/* 2425 MHz	*/
+#define		PSA_SUBBAND_2460	2	/* 2460 MHz	*/
+#define		PSA_SUBBAND_2484	3	/* 2484 MHz	*/
+#define		PSA_SUBBAND_2430_5	4	/* 2430.5 MHz	*/
+#if	0
+	<alias for above>
+	unsigned char	psa_decay_updat_prm;	/* Modem Decay Update ??? */
+#endif	/* 0 */
+	unsigned char	psa_quality_thr;	/* Modem Quality Threshold */
+	unsigned char	psa_mod_delay;		/* Modem Delay ??? */
+	unsigned char	psa_nwid[2];		/* Network ID */
+	unsigned char	psa_undefined;		/* undefined */
+	unsigned char	psa_encryption_select;	/* Encryption On Off */
+	unsigned char	psa_encryption_key[8];	/* Encryption Key */
+	unsigned char	psa_databus_width;	/* 8/16 bit bus width */
+	unsigned char	psa_call_code;		/* ??? */
+#if	0
+	<alias for above>
+	unsigned char	psa_auto_squelch;	/* Automatic Squelch level On off ??? */
+#endif	/* 0 */
+	unsigned char	psa_no_of_retries;	/* LAN Cont. No of retries */
+	unsigned char	psa_acr;		/* LAN Cont. ACR */
+	unsigned char	psa_dump_count;		/* number of Dump Commands in TFB */
+	unsigned char	psa_unused1[4];		/* unused */
+	unsigned char	psa_nwid_prefix;	/* ??? */
+	unsigned char	psa_unused2[3];		/* unused */
+	unsigned char	psa_conf_status;	/* Card Configuration Status */
+	unsigned char	psa_crc[2];		/* CRC over PSA */
+	unsigned char	psa_crc_status;		/* CRC Valid Flag */
+};
+#if	STRUCT_CHECK == 1
+#define	PSA_SIZE	64
+#endif	/* STRUCT_CHECK == 1 */
+
+/*
+ * Modem Management Controller (MMC) write structure.
+ */
+typedef struct mmw_t	mmw_t;
+struct mmw_t
+{
+	unsigned char	mmw_encr_key[8];	/* encryption key */
+	unsigned char	mmw_encr_enable;	/* enable/disable encryption */
+	unsigned char	mmw_unused0[1];		/* unused */
+	unsigned char	mmw_des_io_invert;	/* ??? */
+	unsigned char	mmw_unused1[5];		/* unused */
+	unsigned char	mmw_loopt_sel;		/* looptest selection */
+#define		MMW_LOOPT_SEL_UNDEFINED	0x40	/* undefined */
+#define		MMW_LOOPT_SEL_INT	0x20	/* activate Attention Request */
+#define		MMW_LOOPT_SEL_LS	0x10	/* looptest without collision avoidance */
+#define		MMW_LOOPT_SEL_LT3A	0x08	/* looptest 3a */
+#define		MMW_LOOPT_SEL_LT3B	0x04	/* looptest 3b */
+#define		MMW_LOOPT_SEL_LT3C	0x02	/* looptest 3c */
+#define		MMW_LOOPT_SEL_LT3D	0x01	/* looptest 3d */
+	unsigned char	mmw_jabber_enable;	/* jabber timer enable */
+	unsigned char	mmw_freeze;		/* freeze / unfreeeze signal level */
+	unsigned char	mmw_anten_sel;		/* antenna selection */
+#define		MMW_ANTEN_SEL_SEL	0x01	/* direct antenna selection */
+#define		MMW_ANTEN_SEL_ALG_EN	0x02	/* antenna selection algorithm enable */
+	unsigned char	mmw_ifs;		/* inter frame spacing */
+	unsigned char	mmw_mod_delay;	 	/* modem delay */
+	unsigned char	mmw_jam_time;		/* jamming time */
+	unsigned char	mmw_unused2[1];		/* unused */
+	unsigned char	mmw_thr_pre_set;	/* level threshold preset */
+	unsigned char	mmw_decay_prm;		/* decay parameters */
+	unsigned char	mmw_decay_updat_prm;	/* decay update parameterz */
+	unsigned char	mmw_quality_thr;	/* quality (z-quotient) threshold */
+	unsigned char	mmw_netw_id_l;		/* NWID low order byte */
+	unsigned char	mmw_netw_id_h;		/* NWID high order byte */
+};
+#if	STRUCT_CHECK == 1
+#define	MMW_SIZE	30
+#endif	/* STRUCT_CHECK == 1 */
+
+#define	mmwoff(p,f) 	(unsigned short)((void *)(&((mmw_t *)((void *)0 + (p)))->f) - (void *)0)
+
+/*
+ * Modem Management Controller (MMC) read structure.
+ */
+typedef struct mmr_t	mmr_t;
+struct mmr_t
+{
+	unsigned char	mmr_unused0[8];		/* unused */
+	unsigned char	mmr_des_status;		/* encryption status */
+	unsigned char	mmr_des_avail;		/* encryption available (0x55 read) */
+	unsigned char	mmr_des_io_invert;	/* des I/O invert register */
+	unsigned char	mmr_unused1[5];		/* unused */
+	unsigned char	mmr_dce_status;		/* DCE status */
+#define		MMR_DCE_STATUS_ENERG_DET	0x01	/* energy detected */
+#define		MMR_DCE_STATUS_LOOPT_IND	0x02	/* loop test indicated */
+#define		MMR_DCE_STATUS_XMTITR_IND	0x04	/* transmitter on */
+#define		MMR_DCE_STATUS_JBR_EXPIRED	0x08	/* jabber timer expired */
+	unsigned char	mmr_unused2[3];		/* unused */
+	unsigned char	mmr_correct_nwid_l;	/* no. of correct NWID's rxd (low) */
+	unsigned char	mmr_correct_nwid_h;	/* no. of correct NWID's rxd (high) */
+	unsigned char	mmr_wrong_nwid_l;	/* count of wrong NWID's received (low) */
+	unsigned char	mmr_wrong_nwid_h;	/* count of wrong NWID's received (high) */
+	unsigned char	mmr_thr_pre_set;	/* level threshold preset */
+	unsigned char	mmr_signal_lvl;		/* signal level */
+	unsigned char	mmr_silence_lvl;	/* silence level */
+	unsigned char	mmr_sgnl_qual;		/* signal quality */
+#define		MMR_SGNL_QUAL_0		0x01	/* signal quality 0 */
+#define		MMR_SGNL_QUAL_1		0x02	/* signal quality 1 */
+#define		MMR_SGNL_QUAL_2		0x04	/* signal quality 2 */
+#define		MMR_SGNL_QUAL_3		0x08	/* signal quality 3 */
+#define		MMR_SGNL_QUAL_S_A	0x80	/* currently selected antenna */
+	unsigned char	mmr_netw_id_l;		/* NWID low order byte ??? */
+	unsigned char	mmr_unused3[1];		/* unused */
+};
+#if	STRUCT_CHECK == 1
+#define	MMR_SIZE	30
+#endif	/* STRUCT_CHECK == 1 */
+
+#define	MMR_LEVEL_MASK	0x3F
+
+#define	mmroff(p,f) 	(unsigned short)((void *)(&((mmr_t *)((void *)0 + (p)))->f) - (void *)0)
+
+/*
+ * Host Adaptor structure.
+ * (base is board port address).
+ */
+typedef union hacs_u	hacs_u;
+union hacs_u
+{
+	unsigned short	hu_command;		/* Command register */
+#define		HACR_RESET		0x0001	/* Reset board */
+#define		HACR_CA			0x0002	/* Set Channel Attention for 82586 */
+#define		HACR_16BITS		0x0004	/* 16 bits operation (0 => 8bits) */
+#define		HACR_OUT0		0x0008	/* General purpose output pin 0 */
+						/* not used - must be 1 */
+#define		HACR_OUT1		0x0010	/* General purpose output pin 1 */
+						/* not used - must be 1 */
+#define		HACR_82586_INT_ENABLE	0x0020	/* Enable 82586 interrupts */
+#define		HACR_MMC_INT_ENABLE	0x0040	/* Enable MMC interrupts */
+#define		HACR_INTR_CLR_ENABLE	0x0080	/* Enable interrupt status read/clear */
+	unsigned short	hu_status;		/* Status Register */
+#define		HASR_82586_INTR		0x0001	/* Interrupt request from 82586 */
+#define		HASR_MMC_INTR		0x0002	/* Interrupt request from MMC */
+#define		HASR_MMC_BUSY		0x0004	/* MMC busy indication */
+#define		HASR_PSA_BUSY		0x0008	/* LAN parameter storage area busy */
+};
+
+typedef struct ha_t	ha_t;
+struct ha_t
+{
+	hacs_u		ha_cs;		/* Command and status registers */
+#define 		ha_command	ha_cs.hu_command
+#define 		ha_status	ha_cs.hu_status
+	unsigned short	ha_mmcr;	/* Modem Management Ctrl Register */
+	unsigned short	ha_pior0;	/* Program I/O Address Register Port 0 */
+	unsigned short	ha_piop0;	/* Program I/O Port 0 */
+	unsigned short	ha_pior1;	/* Program I/O Address Register Port 1 */
+	unsigned short	ha_piop1;	/* Program I/O Port 1 */
+	unsigned short	ha_pior2;	/* Program I/O Address Register Port 2 */
+	unsigned short	ha_piop2;	/* Program I/O Port 2 */
+};
+#if	STRUCT_CHECK == 1
+#define HA_SIZE		16
+#endif	/* STRUCT_CHECK == 1 */
+
+#define	hoff(p,f) 	(unsigned short)((void *)(&((ha_t *)((void *)0 + (p)))->f) - (void *)0)
+#define	HACR(p)		hoff(p, ha_command)
+#define	HASR(p)		hoff(p, ha_status)
+#define	MMCR(p)		hoff(p, ha_mmcr)
+#define	PIOR0(p)	hoff(p, ha_pior0)
+#define	PIOP0(p)	hoff(p, ha_piop0)
+#define	PIOR1(p)	hoff(p, ha_pior1)
+#define	PIOP1(p)	hoff(p, ha_piop1)
+#define	PIOR2(p)	hoff(p, ha_pior2)
+#define	PIOP2(p)	hoff(p, ha_piop2)
+
+/*
+ * Program I/O Mode Register values.
+ */
+#define STATIC_PIO		0	/* Mode 1: static mode */
+					/* RAM access ??? */
+#define AUTOINCR_PIO		1	/* Mode 2: auto increment mode */
+					/* RAM access ??? */
+#define AUTODECR_PIO		2	/* Mode 3: auto decrement mode */
+					/* RAM access ??? */
+#define PARAM_ACCESS_PIO	3	/* Mode 4: LAN parameter access mode */
+					/* Parameter access. */
+#define PIO_MASK		3	/* register mask */
+#define PIOM(cmd,piono)		((u_short)cmd << 10 << (piono * 2))
+
+#define	HACR_DEFAULT		(HACR_OUT0 | HACR_OUT1 | HACR_16BITS | PIOM(STATIC_PIO, 0) | PIOM(AUTOINCR_PIO, 1) | PIOM(PARAM_ACCESS_PIO, 2))
+#define	HACR_INTRON		(HACR_82586_INT_ENABLE | HACR_MMC_INT_ENABLE | HACR_INTR_CLR_ENABLE)
+
+#define	MAXDATAZ		(WAVELAN_ADDR_SIZE + WAVELAN_ADDR_SIZE + 2 + WAVELAN_MTU)
+
+/*
+ * Onboard 64k RAM layout.
+ * (Offsets from 0x0000.)
+ */
+#define OFFSET_RU		0x0000
+#define OFFSET_CU		0x8000
+#define OFFSET_SCB		(OFFSET_ISCP - sizeof(scb_t))
+#define OFFSET_ISCP		(OFFSET_SCP - sizeof(iscp_t))
+#define OFFSET_SCP		I82586_SCP_ADDR
+
+#define	RXBLOCKZ		(sizeof(fd_t) + sizeof(rbd_t) + MAXDATAZ)
+#define	TXBLOCKZ		(sizeof(ac_tx_t) + sizeof(ac_nop_t) + sizeof(tbd_t) + MAXDATAZ)
+
+#define	NRXBLOCKS		((OFFSET_CU - OFFSET_RU) / RXBLOCKZ)
+#define	NTXBLOCKS		((OFFSET_SCB - OFFSET_CU) / TXBLOCKZ)
+
+/*
+ * This software may only be used and distributed
+ * according to the terms of the GNU Public License.
+ *
+ * For more details, see wavelan.c.
+ */
+#endif	/* defined(CONFIG_WAVELAN) */
diff -u --recursive --new-file v1.1.87/linux/drivers/scsi/ChangeLog linux/drivers/scsi/ChangeLog
--- v1.1.87/linux/drivers/scsi/ChangeLog	Sun Jan 22 21:39:40 1995
+++ linux/drivers/scsi/ChangeLog	Tue Jan 31 09:39:01 1995
@@ -74,7 +74,7 @@
 	scsi_init_malloc to get some memory we know will be safe).
 
 	* scsi.c: Change dma freelist to be a set of pages.  This allows
-	us to dynamicly adjust the size of the list by adding more pages
+	us to dynamically adjust the size of the list by adding more pages
 	to the pagelist.  Fix scsi_malloc and scsi_free accordingly.
 
 	* scsi_module.c: Fix include.
diff -u --recursive --new-file v1.1.87/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c
--- v1.1.87/linux/drivers/scsi/scsi.c	Mon Jan 30 06:41:57 1995
+++ linux/drivers/scsi/scsi.c	Tue Jan 31 09:36:21 1995
@@ -578,14 +578,6 @@
 	}       /* for lun ends */
   shpnt->host_queue = NULL;  /* No longer needed here */
   
-  printk("scsi : detected ");
-  for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
-    if(sdtpnt->dev_noticed && sdtpnt->name)
-      printk("%d SCSI %s%s ", sdtpnt->dev_noticed, sdtpnt->name,
-	     (sdtpnt->dev_noticed != 1) ? "s" : "");
-
-  printk("total.\n");
-  
   /* Last device block does not exist.  Free memory. */
   scsi_init_free((char *) SDpnt, sizeof(Scsi_Device));
   
@@ -1955,6 +1947,11 @@
   if(scsi_loadable_module_flag) {
     retval = (unsigned long) kmalloc(size, priority);
   } else {
+    /*
+     * Keep all memory aligned on 16-byte boundaries. Some host adaptors
+     * (e.g. BusLogic BT-445S) require DMA buffers to be aligned that way.
+     */
+    size = (size + 15) & ~15;
     retval = scsi_init_memory_start;
     scsi_init_memory_start += size;
   }
@@ -1968,6 +1965,7 @@
   if((unsigned long) ptr > scsi_init_memory_start) {
     kfree(ptr);
   } else {
+    size = (size + 15) & ~15; /* Use the same alignment as scsi_init_malloc(). */
     if(((unsigned long) ptr) + size == scsi_init_memory_start)
       scsi_init_memory_start = (unsigned long) ptr;
   }
@@ -1993,7 +1991,8 @@
 
 	/* Init a few things so we can "malloc" memory. */
 	scsi_loadable_module_flag = 0;
-	scsi_init_memory_start = memory_start;
+	/* Align everything on 16-byte boundaries. */
+	scsi_init_memory_start = (memory_start + 15) & ~ 15;
 
 	timer_table[SCSI_TIMER].fn = scsi_main_timeout;
 	timer_table[SCSI_TIMER].expires = 0;
@@ -2006,6 +2005,13 @@
 	for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next)
 	  scan_scsis(shpnt);           /* scan for scsi devices */
 
+	printk("scsi : detected ");
+	for (sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
+	  if (sdtpnt->dev_noticed && sdtpnt->name)
+	    printk("%d SCSI %s%s ", sdtpnt->dev_noticed, sdtpnt->name,
+	    (sdtpnt->dev_noticed != 1) ? "s" : "");
+	printk("total.\n");
+  
 	for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
 	  if(sdtpnt->init && sdtpnt->dev_noticed) (*sdtpnt->init)();
 
@@ -2068,7 +2074,6 @@
 	dma_sectors = (dma_sectors + 15) & 0xfff0;
 	dma_free_sectors = dma_sectors;  /* This must be a multiple of 16 */
 
-	scsi_init_memory_start = (scsi_init_memory_start + 3) & 0xfffffffc;
 	dma_malloc_freelist = (unsigned char *) 
 	  scsi_init_malloc(dma_sectors >> 3, GFP_ATOMIC);
 	memset(dma_malloc_freelist, 0, dma_sectors >> 3);
@@ -2077,9 +2082,6 @@
  	  scsi_init_malloc(dma_sectors >> 1, GFP_ATOMIC);
  	memset(dma_malloc_pages, 0, dma_sectors >> 1);
  
-	/* Some host adapters require buffers to be word aligned */
-	if(scsi_init_memory_start & 1) scsi_init_memory_start++;
-	
  	for(i=0; i< dma_sectors >> 3; i++)
  	  dma_malloc_pages[i] = (unsigned char *) 
  	    scsi_init_malloc(PAGE_SIZE, GFP_ATOMIC | GFP_DMA);
diff -u --recursive --new-file v1.1.87/linux/drivers/scsi/sd.c linux/drivers/scsi/sd.c
--- v1.1.87/linux/drivers/scsi/sd.c	Thu Jan 26 07:49:06 1995
+++ linux/drivers/scsi/sd.c	Tue Jan 31 09:39:01 1995
@@ -87,7 +87,7 @@
 	  return -ENXIO;   /* No such device */
 	
 	/*
-	 * See if we are requesting a non-existant partition.
+	 * See if we are requesting a non-existent partition.
 	 */
 	if(sd_sizes[MINOR(inode->i_rdev)] == 0)
 	  return -ENXIO;
diff -u --recursive --new-file v1.1.87/linux/drivers/scsi/sr.c linux/drivers/scsi/sr.c
--- v1.1.87/linux/drivers/scsi/sr.c	Mon Jan 30 08:53:06 1995
+++ linux/drivers/scsi/sr.c	Tue Jan 31 09:39:01 1995
@@ -349,7 +349,7 @@
       min   = (unsigned long) rec[15]/16*10 + (unsigned long) rec[15]%16;
       sec   = (unsigned long) rec[16]/16*10 + (unsigned long) rec[16]%16;
       frame = (unsigned long) rec[17]/16*10 + (unsigned long) rec[17]%16;
-      /* if rec[14] is'nt 0xb0, the drive does not support multisession CD's, use zero */
+      /* if rec[14] isn't 0xb0, the drive does not support multisession CD's, use zero */
       sector = (0xb0 == rec[14]) ? min*CD_SECS*CD_FRAMES + sec*CD_FRAMES + frame : 0;
 #ifdef DEBUG
       printk("NEC: (%2x) %2li:%02li:%02li = %li\n",buf[8+14],min,sec,frame,sector);
@@ -377,7 +377,7 @@
     if (rc != 0) {
       printk("sr_photocd: ioctl error (TOSHIBA #1): 0x%x\n",rc);
       sector = 0;
-      break; /* if the first ioctl fails, we don't call the secound one */
+      break; /* if the first ioctl fails, we don't call the second one */
     }
     is_xa  = (rec[0] == 0x20);
 #ifdef DEBUG
@@ -411,7 +411,7 @@
     printk("sr_photocd: get_density: 0x%x\n",rec[4]);
 #endif
     
-    /* ...and only if nessesary a set_density */
+    /* ...and only if necessary a set_density */
     if ((rec[4] != 0x81 && is_xa) || (rec[4] != 0 && !is_xa)) {
 #ifdef DEBUG
       printk("sr_photocd: doing set_density\n");
diff -u --recursive --new-file v1.1.87/linux/fs/binfmt_elf.c linux/fs/binfmt_elf.c
--- v1.1.87/linux/fs/binfmt_elf.c	Mon Jan 30 06:41:57 1995
+++ linux/fs/binfmt_elf.c	Mon Jan 30 13:08:04 1995
@@ -33,6 +33,7 @@
 #include <linux/personality.h>
 
 #include <asm/segment.h>
+#include <asm/pgtable.h>
 
 #include <linux/config.h>
 
diff -u --recursive --new-file v1.1.87/linux/fs/exec.c linux/fs/exec.c
--- v1.1.87/linux/fs/exec.c	Mon Jan 30 06:41:57 1995
+++ linux/fs/exec.c	Mon Jan 30 13:08:04 1995
@@ -42,6 +42,7 @@
 
 #include <asm/system.h>
 #include <asm/segment.h>
+#include <asm/pgtable.h>
 
 #include <linux/config.h>
 
diff -u --recursive --new-file v1.1.87/linux/fs/msdos/msbuffer.h linux/fs/msdos/msbuffer.h
--- v1.1.87/linux/fs/msdos/msbuffer.h	Mon Jan 30 06:41:57 1995
+++ linux/fs/msdos/msbuffer.h	Tue Jan 31 09:36:21 1995
@@ -15,7 +15,7 @@
 /* These macros exist to avoid modifying all the code */
 /* They should be removed one day I guess */
 
-/* The versionning mecanism of the modules system define those macros */
+/* The versioning mechanism of the modules system define those macros */
 /* This remove some warnings */
 #ifdef brelse
 	#undef brelse
diff -u --recursive --new-file v1.1.87/linux/fs/proc/array.c linux/fs/proc/array.c
--- v1.1.87/linux/fs/proc/array.c	Thu Jan 26 07:49:08 1995
+++ linux/fs/proc/array.c	Mon Jan 30 13:08:04 1995
@@ -44,6 +44,7 @@
 #include <linux/mm.h>
 
 #include <asm/segment.h>
+#include <asm/pgtable.h>
 #include <asm/io.h>
 
 #define LOAD_INT(x) ((x) >> FSHIFT)
diff -u --recursive --new-file v1.1.87/linux/fs/proc/mem.c linux/fs/proc/mem.c
--- v1.1.87/linux/fs/proc/mem.c	Sun Jan 22 23:03:59 1995
+++ linux/fs/proc/mem.c	Mon Jan 30 13:08:04 1995
@@ -13,6 +13,7 @@
 #include <asm/page.h>
 #include <asm/segment.h>
 #include <asm/io.h>
+#include <asm/pgtable.h>
 
 /*
  * mem_write isn't really a good idea right now. It needs
diff -u --recursive --new-file v1.1.87/linux/fs/proc/net.c linux/fs/proc/net.c
--- v1.1.87/linux/fs/proc/net.c	Mon Jan 30 06:41:58 1995
+++ linux/fs/proc/net.c	Tue Jan 31 14:36:24 1995
@@ -55,6 +55,9 @@
 extern int rt_get_info(char *, char **, off_t, int);
 extern int snmp_get_info(char *, char **, off_t, int);
 extern int afinet_get_info(char *, char **, off_t, int);
+#if	defined(CONFIG_WAVELAN)
+extern int wavelan_get_info(char *, char **, off_t, int);
+#endif	/* defined(CONFIG_WAVELAN) */
 extern int ip_acct_procinfo(char *, char **, off_t, int);
 extern int ip_fw_blk_procinfo(char *, char **, off_t, int);
 extern int ip_fw_fwd_procinfo(char *, char **, off_t, int);
@@ -145,6 +148,9 @@
 #ifdef CONFIG_IP_ACCT
 	{ PROC_NET_IPACCT,	7,  "ip_acct"},
 #endif
+#if	defined(CONFIG_WAVELAN)
+	{ PROC_NET_WAVELAN,	7, "wavelan" },
+#endif	/* defined(CONFIG_WAVELAN) */
 #endif	/* CONFIG_INET */
 #ifdef CONFIG_IPX
 	{ PROC_NET_IPX_ROUTE,	9, "ipx_route" },
@@ -305,6 +311,11 @@
 				length = rarp_get_info(page,&start,file->f_pos,thistime);
 				break;
 #endif /* CONFIG_INET_RARP */				
+#if	defined(CONFIG_WAVELAN)
+			case PROC_NET_WAVELAN:
+				length = wavelan_get_info(page, &start, file->f_pos, thistime);
+				break;
+#endif	/* defined(CONFIG_WAVELAN) */
 #endif /* CONFIG_INET */
 #ifdef CONFIG_IPX
 			case PROC_NET_IPX_INTERFACE:
diff -u --recursive --new-file v1.1.87/linux/fs/umsdos/README linux/fs/umsdos/README
--- v1.1.87/linux/fs/umsdos/README	Wed Aug 10 19:26:28 1994
+++ linux/fs/umsdos/README	Tue Jan 31 09:39:02 1995
@@ -16,7 +16,7 @@
 
 There is plenty of documentation on it in the source. A formated document
 made from those comments is available from
-sunsite.unc.edu:/pub/Linux/ALPHA/umsdos
+sunsite.unc.edu:/pub/Linux/system/Filesystems/umsdos.
 
 Mostly...
 
@@ -53,9 +53,9 @@
 	$5 per directory. Add any applicable taxes.
 \end joke_section
 
-A utility umssync creates those and maintain them. It is available
-from the same directory above (sunsite) in the file umsdos_progs-0.3.tar.gz.
-A compiled version is available in umsdos-0.3a.bin.tar.gz.
+A utility umssync creates those. The kernel maintain them. It is available
+from the same directory above (sunsite) in the file umsdos_progs-0.7.tar.gz.
+A compiled version is available in umsdos_progs-0.7.bin.tar.gz.
 
 So in our example, after mounting mnt, we do
 
@@ -79,6 +79,18 @@
 Umsdos won't notice new files, but will signal removed file (it won't crash).
 Using umssync in /etc/rc will make sure the DOS directory is in sync with
 the --linux-.---.
+
+It is a good idea to put the following command in your RC file just
+after the "mount -a":
+
+	mount -a
+	/sbin/umssync -i+ -c+ -r99 /umsdos_mount_point
+
+	(You put one for each umsdos mount point in the fstab)
+
+This will insure nice operation. A umsdos.fsck is in the making,
+so you will be allowed to managed umsdos partition in the same way
+other filesystem are, using the generic fsck front end.
 
 Hope this helps!
 
diff -u --recursive --new-file v1.1.87/linux/fs/umsdos/ioctl.c linux/fs/umsdos/ioctl.c
--- v1.1.87/linux/fs/umsdos/ioctl.c	Mon Jan 30 06:41:58 1995
+++ linux/fs/umsdos/ioctl.c	Tue Jan 31 09:36:21 1995
@@ -167,7 +167,7 @@
 			}else if (cmd == UMSDOS_RENAME_DOS){
 				/* #Specification: ioctl / UMSDOS_RENAME_DOS
 					A file or directory is rename in a DOS directory
-					(not moved accross directory). The source name
+					(not moved across directory). The source name
 					is in the dos_dirent.name field and the destination
 					is in umsdos_dirent.name field.
 
diff -u --recursive --new-file v1.1.87/linux/include/asm-alpha/page.h linux/include/asm-alpha/page.h
--- v1.1.87/linux/include/asm-alpha/page.h	Mon Jan 30 08:53:06 1995
+++ linux/include/asm-alpha/page.h	Tue Jan 31 09:30:47 1995
@@ -1,43 +1,14 @@
 #ifndef _ALPHA_PAGE_H
 #define _ALPHA_PAGE_H
 
-#define CONFIG_STRICT_MM_TYPECHECKS
-
-#define invalidate_all() \
-__asm__ __volatile__( \
-	"lda $16,-2($31)\n\t" \
-	".long 51" \
-	: : :"$1", "$16", "$17", "$22","$23","$24","$25")
-
-#define invalidate() \
-__asm__ __volatile__( \
-	"lda $16,-1($31)\n\t" \
-	".long 51" \
-	: : :"$1", "$16", "$17", "$22","$23","$24","$25")
-
 /* PAGE_SHIFT determines the page size */
 #define PAGE_SHIFT	13
-#define PMD_SHIFT	23
-#define PGDIR_SHIFT	33
-
 #define PAGE_SIZE	(1UL << PAGE_SHIFT)
-#define PMD_SIZE	(1UL << PMD_SHIFT)
-#define PGDIR_SIZE	(1UL << PGDIR_SHIFT)
-
 #define PAGE_MASK	(~(PAGE_SIZE-1))
-#define PMD_MASK	(~(PMD_SIZE-1))
-#define PGDIR_MASK	(~(PGDIR_SIZE-1))
 
 #ifdef __KERNEL__
 
-#define PAGE_OFFSET 0xFFFFFC0000000000
-#define MAP_NR(addr) ((((unsigned long) (addr)) - PAGE_OFFSET) >> PAGE_SHIFT)
-#define MAP_PAGE_RESERVED (1<<31)
-
-typedef unsigned int mem_map_t;
-
-#define VMALLOC_START		0xFFFFFE0000000000
-#define VMALLOC_VMADDR(x)	((unsigned long)(x))
+#define CONFIG_STRICT_MM_TYPECHECKS
 
 #ifdef CONFIG_STRICT_MM_TYPECHECKS
 /*
@@ -77,253 +48,26 @@
 
 #endif
 
-/*
- * OSF/1 PAL-code-imposed page table bits
- */
-#define _PAGE_VALID	0x0001
-#define _PAGE_FOR	0x0002	/* used for page protection (fault on read) */
-#define _PAGE_FOW	0x0004	/* used for page protection (fault on write) */
-#define _PAGE_FOE	0x0008	/* used for page protection (fault on exec) */
-#define _PAGE_ASM	0x0010
-#define _PAGE_KRE	0x0100	/* xxx - see below on the "accessed" bit */
-#define _PAGE_URE	0x0200	/* xxx */
-#define _PAGE_KWE	0x1000	/* used to do the dirty bit in software */
-#define _PAGE_UWE	0x2000	/* used to do the dirty bit in software */
-
-/* .. and these are ours ... */
-#define _PAGE_COW	0x10000
-#define _PAGE_DIRTY	0x20000
-#define _PAGE_ACCESSED	0x40000
-
-/*
- * NOTE! The "accessed" bit isn't necessarily exact: it can be kept exactly
- * by software (use the KRE/URE/KWE/UWE bits appropritely), but I'll fake it.
- * Under Linux/AXP, the "accessed" bit just means "read", and I'll just use
- * the KRE/URE bits to watch for it. That way we don't need to overload the
- * KWE/UWE bits with both handling dirty and accessed.
- *
- * Note that the kernel uses the accessed bit just to check whether to page
- * out a page or not, so it doesn't have to be exact anyway.
- */
-
-#define __DIRTY_BITS	(_PAGE_DIRTY | _PAGE_KWE | _PAGE_UWE)
-#define __ACCESS_BITS	(_PAGE_ACCESSED | _PAGE_KRE | _PAGE_URE)
-
-#define _PFN_MASK	0xFFFFFFFF00000000
-
-#define _PAGE_TABLE	(_PAGE_VALID | __DIRTY_BITS | __ACCESS_BITS)
-#define _PAGE_CHG_MASK	(_PFN_MASK | __DIRTY_BITS | __ACCESS_BITS)
-
-/*
- * All the normal masks have the "page accessed" bits on, as any time they are used,
- * the page is accessed. They are cleared only by the page-out routines
- */
-#define PAGE_NONE	__pgprot(_PAGE_VALID | __ACCESS_BITS | _PAGE_FOR | _PAGE_FOW | _PAGE_FOE)
-#define PAGE_SHARED	__pgprot(_PAGE_VALID | __ACCESS_BITS)
-#define PAGE_COPY	__pgprot(_PAGE_VALID | __ACCESS_BITS | _PAGE_FOW | _PAGE_COW)
-#define PAGE_READONLY	__pgprot(_PAGE_VALID | __ACCESS_BITS | _PAGE_FOW)
-#define PAGE_KERNEL	__pgprot(_PAGE_VALID | _PAGE_ASM | _PAGE_KRE | _PAGE_KWE)
-
-#define _PAGE_NORMAL(x) __pgprot(_PAGE_VALID | __ACCESS_BITS | (x))
-
-#define __P000	_PAGE_NORMAL(_PAGE_COW | _PAGE_FOR | _PAGE_FOW | _PAGE_FOE)
-#define __P001	_PAGE_NORMAL(_PAGE_COW | _PAGE_FOW | _PAGE_FOE)
-#define __P010	_PAGE_NORMAL(_PAGE_COW | _PAGE_FOR | _PAGE_FOE)
-#define __P011	_PAGE_NORMAL(_PAGE_COW | _PAGE_FOE)
-#define __P100	_PAGE_NORMAL(_PAGE_COW | _PAGE_FOR | _PAGE_FOW)
-#define __P101	_PAGE_NORMAL(_PAGE_COW | _PAGE_FOW)
-#define __P110	_PAGE_NORMAL(_PAGE_COW | _PAGE_FOR)
-#define __P111	_PAGE_NORMAL(_PAGE_COW)
-
-#define __S000	_PAGE_NORMAL(_PAGE_FOR | _PAGE_FOW | _PAGE_FOE)
-#define __S001	_PAGE_NORMAL(_PAGE_FOW | _PAGE_FOE)
-#define __S010	_PAGE_NORMAL(_PAGE_FOR | _PAGE_FOE)
-#define __S011	_PAGE_NORMAL(_PAGE_FOE)
-#define __S100	_PAGE_NORMAL(_PAGE_FOR | _PAGE_FOW)
-#define __S101	_PAGE_NORMAL(_PAGE_FOW)
-#define __S110	_PAGE_NORMAL(_PAGE_FOR)
-#define __S111	_PAGE_NORMAL(0)
-
-/*
- * BAD_PAGETABLE is used when we need a bogus page-table, while
- * BAD_PAGE is used for a bogus page.
- *
- * ZERO_PAGE is a global shared page that is always zero: used
- * for zero-mapped memory areas etc..
- */
-extern pte_t __bad_page(void);
-extern pmd_t * __bad_pagetable(void);
-
-extern unsigned long __zero_page(void);
-
-#define BAD_PAGETABLE __bad_pagetable()
-#define BAD_PAGE __bad_page()
-#define ZERO_PAGE __zero_page()
+#define invalidate_all() \
+__asm__ __volatile__( \
+	"lda $16,-2($31)\n\t" \
+	".long 51" \
+	: : :"$1", "$16", "$17", "$22","$23","$24","$25")
 
-/* number of bits that fit into a memory pointer */
-#define BITS_PER_PTR			(8*sizeof(unsigned long))
+#define invalidate() \
+__asm__ __volatile__( \
+	"lda $16,-1($31)\n\t" \
+	".long 51" \
+	: : :"$1", "$16", "$17", "$22","$23","$24","$25")
 
 /* to align the pointer to the (next) page boundary */
 #define PAGE_ALIGN(addr)		(((addr)+PAGE_SIZE-1)&PAGE_MASK)
 
-/* to align the pointer to a pointer address */
-#define PTR_MASK			(~(sizeof(void*)-1))
-
-/* sizeof(void*)==1<<SIZEOF_PTR_LOG2 */
-#define SIZEOF_PTR_LOG2			3
-
-/* to find an entry in a page-table */
-#define PAGE_PTR(address)		\
-  ((unsigned long)(address)>>(PAGE_SHIFT-SIZEOF_PTR_LOG2)&PTR_MASK&~PAGE_MASK)
-
-/* This one will go away */
-#define PTRS_PER_PAGE	1024
-
-#define PTRS_PER_PTE	1024
-#define PTRS_PER_PMD	1024
-#define PTRS_PER_PGD	1024
+#define PAGE_OFFSET		0xFFFFFC0000000000
+#define MAP_NR(addr)		((((unsigned long) (addr)) - PAGE_OFFSET) >> PAGE_SHIFT)
+#define MAP_PAGE_RESERVED	(1<<31)
 
-extern unsigned long high_memory;
-
-/*
- * Conversion functions: convert a page and protection to a page entry,
- * and a page entry and page directory to the page they refer to.
- */
-extern inline pte_t mk_pte(unsigned long page, pgprot_t pgprot)
-{ pte_t pte; pte_val(pte) = ((page-PAGE_OFFSET) << (32-PAGE_SHIFT)) | pgprot_val(pgprot); return pte; }
-
-extern inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
-{ pte_val(pte) = (pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot); return pte; }
-
-extern inline void pmd_set(pmd_t * pmdp, pte_t * ptep)
-{ pmd_val(*pmdp) = _PAGE_TABLE | ((((unsigned long) ptep) - PAGE_OFFSET) << (32-PAGE_SHIFT)); }
-
-extern inline void pgd_set(pgd_t * pgdp, pmd_t * pmdp)
-{ pgd_val(*pgdp) = _PAGE_TABLE | ((((unsigned long) pmdp) - PAGE_OFFSET) << (32-PAGE_SHIFT)); }
-
-extern inline unsigned long pte_page(pte_t pte)
-{ return PAGE_OFFSET + ((pte_val(pte) & _PFN_MASK) >> (32-PAGE_SHIFT)); }
-
-extern inline pte_t * pmd_page(pmd_t pmd)
-{ return (pte_t *) (PAGE_OFFSET + ((pmd_val(pmd) & _PFN_MASK) >> (32-PAGE_SHIFT))); }
-
-extern inline pmd_t * pgd_page(pgd_t pgd)
-{ return (pmd_t *) (PAGE_OFFSET + ((pgd_val(pgd) & _PFN_MASK) >> (32-PAGE_SHIFT))); }
-
-extern inline int pte_none(pte_t pte)		{ return !pte_val(pte); }
-extern inline int pte_present(pte_t pte)	{ return pte_val(pte) & _PAGE_VALID; }
-extern inline void pte_clear(pte_t *ptep)	{ pte_val(*ptep) = 0; }
-
-extern inline int pmd_none(pmd_t pmd)		{ return !pmd_val(pmd); }
-extern inline int pmd_bad(pmd_t pmd)		{ return (pmd_val(pmd) & ~_PFN_MASK) != _PAGE_TABLE || (unsigned long) pmd_page(pmd) > high_memory; }
-extern inline int pmd_present(pmd_t pmd)	{ return pmd_val(pmd) & _PAGE_VALID; }
-extern inline void pmd_clear(pmd_t * pmdp)	{ pmd_val(*pmdp) = 0; }
-
-extern inline int pgd_none(pgd_t pgd)		{ return !pgd_val(pgd); }
-extern inline int pgd_bad(pgd_t pgd)		{ return (pgd_val(pgd) & ~_PFN_MASK) != _PAGE_TABLE || (unsigned long) pgd_page(pgd) > high_memory; }
-extern inline int pgd_present(pgd_t pgd)	{ return pgd_val(pgd) & _PAGE_VALID; }
-extern inline void pgd_clear(pgd_t * pgdp)	{ pgd_val(*pgdp) = 0; }
-
-/*
- * The following only work if pte_present() is true.
- * Undefined behaviour if not..
- */
-extern inline int pte_read(pte_t pte)		{ return !(pte_val(pte) & _PAGE_FOR); }
-extern inline int pte_write(pte_t pte)		{ return !(pte_val(pte) & _PAGE_FOW); }
-extern inline int pte_exec(pte_t pte)		{ return !(pte_val(pte) & _PAGE_FOE); }
-extern inline int pte_dirty(pte_t pte)		{ return pte_val(pte) & _PAGE_DIRTY; }
-extern inline int pte_young(pte_t pte)		{ return pte_val(pte) & _PAGE_ACCESSED; }
-extern inline int pte_cow(pte_t pte)		{ return pte_val(pte) & _PAGE_COW; }
-
-extern inline pte_t pte_wrprotect(pte_t pte)	{ pte_val(pte) |= _PAGE_FOW; return pte; }
-extern inline pte_t pte_rdprotect(pte_t pte)	{ pte_val(pte) |= _PAGE_FOR; return pte; }
-extern inline pte_t pte_exprotect(pte_t pte)	{ pte_val(pte) |= _PAGE_FOE; return pte; }
-extern inline pte_t pte_mkclean(pte_t pte)	{ pte_val(pte) &= ~(__DIRTY_BITS); return pte; }
-extern inline pte_t pte_mkold(pte_t pte)	{ pte_val(pte) &= ~(__ACCESS_BITS); return pte; }
-extern inline pte_t pte_uncow(pte_t pte)	{ pte_val(pte) &= ~_PAGE_COW; return pte; }
-extern inline pte_t pte_mkwrite(pte_t pte)	{ pte_val(pte) &= _PAGE_FOW; return pte; }
-extern inline pte_t pte_mkread(pte_t pte)	{ pte_val(pte) &= _PAGE_FOR; return pte; }
-extern inline pte_t pte_mkexec(pte_t pte)	{ pte_val(pte) &= _PAGE_FOE; return pte; }
-extern inline pte_t pte_mkdirty(pte_t pte)	{ pte_val(pte) |= __DIRTY_BITS; return pte; }
-extern inline pte_t pte_mkyoung(pte_t pte)	{ pte_val(pte) |= __ACCESS_BITS; return pte; }
-extern inline pte_t pte_mkcow(pte_t pte)	{ pte_val(pte) |= _PAGE_COW; return pte; }
-
-/* to set the page-dir */
-extern inline void SET_PAGE_DIR(struct task_struct * tsk, pgd_t * pgdir)
-{
-	tsk->tss.ptbr = ((unsigned long) pgdir - PAGE_OFFSET) >> PAGE_SHIFT;
-	if (tsk == current)
-		invalidate();
-}
-
-/* to find an entry in a page-table-directory */
-extern inline pgd_t * PAGE_DIR_OFFSET(struct task_struct * tsk, unsigned long address)
-{
-	return (pgd_t *) ((tsk->tss.ptbr << PAGE_SHIFT) + PAGE_OFFSET) +
-		((address >> 33) & (PTRS_PER_PGD - 1));
-}
-
-/* to find an entry in the second-level page-table-directory */
-extern inline pmd_t * PAGE_MIDDLE_OFFSET(pgd_t * dir, unsigned long address)
-{
-	return pgd_page(*dir) + ((address >> 23) & (PTRS_PER_PMD - 1));
-}
-
-/* to find an entry in the third-level page-table-directory */
-extern inline pte_t * PAGE_ENTRY_OFFSET(pmd_t * dir, unsigned long address)
-{
-	return pmd_page(*dir) + ((address >> 13) & (PTRS_PER_PTE - 1));
-}
-
-extern inline pte_t * pte_alloc(pmd_t *pmd, unsigned long address)
-{
-	unsigned long page;
-
-	address = (address >> 13) & (PTRS_PER_PTE - 1);
-	if (pmd_none(*pmd)) {
-		pte_t *page = (pte_t *) get_free_page(GFP_KERNEL);
-		if (pmd_none(*pmd)) {
-			if (page) {
-				pmd_set(pmd, page);
-				return page + address;
-			}
-			pmd_set(pmd, BAD_PAGETABLE);
-			return NULL;
-		}
-		free_page((unsigned long) page);
-	}
-	if (pmd_bad(*pmd)) {
-		printk("pte_alloc: bad pmd\n");
-		pmd_set(pmd, BAD_PAGETABLE);
-		return NULL;
-	}
-	return pmd_page(*pmd) + address;
-}
-
-extern inline pmd_t * pmd_alloc(pgd_t *pgd, unsigned long address)
-{
-	unsigned long page;
-
-	address = (address >> 23) & (PTRS_PER_PMD - 1);
-	if (pgd_none(*pgd)) {
-		pmd_t *page = (pmd_t *) get_free_page(GFP_KERNEL);
-		if (pgd_none(*pgd)) {
-			if (page) {
-				pgd_set(pgd, page);
-				return page + address;
-			}
-			pgd_set(pgd, BAD_PAGETABLE);
-			return NULL;
-		}
-		free_page((unsigned long) page);
-	}
-	if (pgd_bad(*pgd)) {
-		printk("pmd_alloc: bad pgd\n");
-		pgd_set(pgd, BAD_PAGETABLE);
-		return NULL;
-	}
-	return pgd_page(*pgd) + address;
-}
+typedef unsigned int mem_map_t;
 
 #endif /* __KERNEL__ */
 
diff -u --recursive --new-file v1.1.87/linux/include/asm-alpha/pgtable.h linux/include/asm-alpha/pgtable.h
--- v1.1.87/linux/include/asm-alpha/pgtable.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-alpha/pgtable.h	Tue Jan 31 09:30:47 1995
@@ -0,0 +1,349 @@
+#ifndef _ALPHA_PGTABLE_H
+#define _ALPHA_PGTABLE_H
+
+/*
+ * This file contains the functions and defines necessary to modify and use
+ * the alpha page table tree.
+ *
+ * This hopefully works with any standard alpha page-size, as defined
+ * in <asm/page.h> (currently 8192).
+ */
+
+/* PMD_SHIFT determines the size of the area a second-level page table can map */
+#define PMD_SHIFT	(PAGE_SHIFT + (PAGE_SHIFT-3))
+#define PMD_SIZE	(1UL << PMD_SHIFT)
+#define PMD_MASK	(~(PMD_SIZE-1))
+
+/* PGDIR_SHIFT determines what a third-level page table entry can map */
+#define PGDIR_SHIFT	(PAGE_SHIFT + 2*(PAGE_SHIFT-3))
+#define PGDIR_SIZE	(1UL << PGDIR_SHIFT)
+#define PGDIR_MASK	(~(PGDIR_SIZE-1))
+
+/*
+ * entries per page directory level: the alpha is three-level, with
+ * all levels having a one-page page table.
+ */
+#define PTRS_PER_PTE	(1UL << (PAGE_SHIFT-3))
+#define PTRS_PER_PMD	(1UL << (PAGE_SHIFT-3))
+#define PTRS_PER_PGD	(1UL << (PAGE_SHIFT-3))
+
+/* the no. of pointers that fit on a page: this will go away */
+#define PTRS_PER_PAGE	(1UL << (PAGE_SHIFT-3))
+
+#define VMALLOC_START		0xFFFFFE0000000000
+#define VMALLOC_VMADDR(x)	((unsigned long)(x))
+
+/*
+ * OSF/1 PAL-code-imposed page table bits
+ */
+#define _PAGE_VALID	0x0001
+#define _PAGE_FOR	0x0002	/* used for page protection (fault on read) */
+#define _PAGE_FOW	0x0004	/* used for page protection (fault on write) */
+#define _PAGE_FOE	0x0008	/* used for page protection (fault on exec) */
+#define _PAGE_ASM	0x0010
+#define _PAGE_KRE	0x0100	/* xxx - see below on the "accessed" bit */
+#define _PAGE_URE	0x0200	/* xxx */
+#define _PAGE_KWE	0x1000	/* used to do the dirty bit in software */
+#define _PAGE_UWE	0x2000	/* used to do the dirty bit in software */
+
+/* .. and these are ours ... */
+#define _PAGE_COW	0x10000
+#define _PAGE_DIRTY	0x20000
+#define _PAGE_ACCESSED	0x40000
+
+/*
+ * NOTE! The "accessed" bit isn't necessarily exact: it can be kept exactly
+ * by software (use the KRE/URE/KWE/UWE bits appropritely), but I'll fake it.
+ * Under Linux/AXP, the "accessed" bit just means "read", and I'll just use
+ * the KRE/URE bits to watch for it. That way we don't need to overload the
+ * KWE/UWE bits with both handling dirty and accessed.
+ *
+ * Note that the kernel uses the accessed bit just to check whether to page
+ * out a page or not, so it doesn't have to be exact anyway.
+ */
+
+#define __DIRTY_BITS	(_PAGE_DIRTY | _PAGE_KWE | _PAGE_UWE)
+#define __ACCESS_BITS	(_PAGE_ACCESSED | _PAGE_KRE | _PAGE_URE)
+
+#define _PFN_MASK	0xFFFFFFFF00000000
+
+#define _PAGE_TABLE	(_PAGE_VALID | __DIRTY_BITS | __ACCESS_BITS)
+#define _PAGE_CHG_MASK	(_PFN_MASK | __DIRTY_BITS | __ACCESS_BITS)
+
+/*
+ * All the normal masks have the "page accessed" bits on, as any time they are used,
+ * the page is accessed. They are cleared only by the page-out routines
+ */
+#define PAGE_NONE	__pgprot(_PAGE_VALID | __ACCESS_BITS | _PAGE_FOR | _PAGE_FOW | _PAGE_FOE)
+#define PAGE_SHARED	__pgprot(_PAGE_VALID | __ACCESS_BITS)
+#define PAGE_COPY	__pgprot(_PAGE_VALID | __ACCESS_BITS | _PAGE_FOW | _PAGE_COW)
+#define PAGE_READONLY	__pgprot(_PAGE_VALID | __ACCESS_BITS | _PAGE_FOW)
+#define PAGE_KERNEL	__pgprot(_PAGE_VALID | _PAGE_ASM | _PAGE_KRE | _PAGE_KWE)
+
+#define _PAGE_NORMAL(x) __pgprot(_PAGE_VALID | __ACCESS_BITS | (x))
+
+#define __P000	_PAGE_NORMAL(_PAGE_COW | _PAGE_FOR | _PAGE_FOW | _PAGE_FOE)
+#define __P001	_PAGE_NORMAL(_PAGE_COW | _PAGE_FOW | _PAGE_FOE)
+#define __P010	_PAGE_NORMAL(_PAGE_COW | _PAGE_FOR | _PAGE_FOE)
+#define __P011	_PAGE_NORMAL(_PAGE_COW | _PAGE_FOE)
+#define __P100	_PAGE_NORMAL(_PAGE_COW | _PAGE_FOR | _PAGE_FOW)
+#define __P101	_PAGE_NORMAL(_PAGE_COW | _PAGE_FOW)
+#define __P110	_PAGE_NORMAL(_PAGE_COW | _PAGE_FOR)
+#define __P111	_PAGE_NORMAL(_PAGE_COW)
+
+#define __S000	_PAGE_NORMAL(_PAGE_FOR | _PAGE_FOW | _PAGE_FOE)
+#define __S001	_PAGE_NORMAL(_PAGE_FOW | _PAGE_FOE)
+#define __S010	_PAGE_NORMAL(_PAGE_FOR | _PAGE_FOE)
+#define __S011	_PAGE_NORMAL(_PAGE_FOE)
+#define __S100	_PAGE_NORMAL(_PAGE_FOR | _PAGE_FOW)
+#define __S101	_PAGE_NORMAL(_PAGE_FOW)
+#define __S110	_PAGE_NORMAL(_PAGE_FOR)
+#define __S111	_PAGE_NORMAL(0)
+
+/*
+ * BAD_PAGETABLE is used when we need a bogus page-table, while
+ * BAD_PAGE is used for a bogus page.
+ *
+ * ZERO_PAGE is a global shared page that is always zero: used
+ * for zero-mapped memory areas etc..
+ */
+extern pte_t __bad_page(void);
+extern pmd_t * __bad_pagetable(void);
+
+extern unsigned long __zero_page(void);
+
+#define BAD_PAGETABLE __bad_pagetable()
+#define BAD_PAGE __bad_page()
+#define ZERO_PAGE __zero_page()
+
+/* number of bits that fit into a memory pointer */
+#define BITS_PER_PTR			(8*sizeof(unsigned long))
+
+/* to align the pointer to a pointer address */
+#define PTR_MASK			(~(sizeof(void*)-1))
+
+/* sizeof(void*)==1<<SIZEOF_PTR_LOG2 */
+#define SIZEOF_PTR_LOG2			3
+
+/* to find an entry in a page-table */
+#define PAGE_PTR(address)		\
+  ((unsigned long)(address)>>(PAGE_SHIFT-SIZEOF_PTR_LOG2)&PTR_MASK&~PAGE_MASK)
+
+extern unsigned long high_memory;
+
+/*
+ * Conversion functions: convert a page and protection to a page entry,
+ * and a page entry and page directory to the page they refer to.
+ */
+extern inline pte_t mk_pte(unsigned long page, pgprot_t pgprot)
+{ pte_t pte; pte_val(pte) = ((page-PAGE_OFFSET) << (32-PAGE_SHIFT)) | pgprot_val(pgprot); return pte; }
+
+extern inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
+{ pte_val(pte) = (pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot); return pte; }
+
+extern inline void pmd_set(pmd_t * pmdp, pte_t * ptep)
+{ pmd_val(*pmdp) = _PAGE_TABLE | ((((unsigned long) ptep) - PAGE_OFFSET) << (32-PAGE_SHIFT)); }
+
+extern inline void pgd_set(pgd_t * pgdp, pmd_t * pmdp)
+{ pgd_val(*pgdp) = _PAGE_TABLE | ((((unsigned long) pmdp) - PAGE_OFFSET) << (32-PAGE_SHIFT)); }
+
+extern inline unsigned long pte_page(pte_t pte)
+{ return PAGE_OFFSET + ((pte_val(pte) & _PFN_MASK) >> (32-PAGE_SHIFT)); }
+
+extern inline unsigned long pmd_page(pmd_t pmd)
+{ return PAGE_OFFSET + ((pmd_val(pmd) & _PFN_MASK) >> (32-PAGE_SHIFT)); }
+
+extern inline unsigned long pgd_page(pgd_t pgd)
+{ return PAGE_OFFSET + ((pgd_val(pgd) & _PFN_MASK) >> (32-PAGE_SHIFT)); }
+
+extern inline int pte_none(pte_t pte)		{ return !pte_val(pte); }
+extern inline int pte_present(pte_t pte)	{ return pte_val(pte) & _PAGE_VALID; }
+extern inline void pte_clear(pte_t *ptep)	{ pte_val(*ptep) = 0; }
+
+extern inline int pmd_none(pmd_t pmd)		{ return !pmd_val(pmd); }
+extern inline int pmd_bad(pmd_t pmd)		{ return (pmd_val(pmd) & ~_PFN_MASK) != _PAGE_TABLE || pmd_page(pmd) > high_memory; }
+extern inline int pmd_present(pmd_t pmd)	{ return pmd_val(pmd) & _PAGE_VALID; }
+extern inline void pmd_clear(pmd_t * pmdp)	{ pmd_val(*pmdp) = 0; }
+
+extern inline int pgd_none(pgd_t pgd)		{ return !pgd_val(pgd); }
+extern inline int pgd_bad(pgd_t pgd)		{ return (pgd_val(pgd) & ~_PFN_MASK) != _PAGE_TABLE || pgd_page(pgd) > high_memory; }
+extern inline int pgd_present(pgd_t pgd)	{ return pgd_val(pgd) & _PAGE_VALID; }
+extern inline void pgd_clear(pgd_t * pgdp)	{ pgd_val(*pgdp) = 0; }
+
+/*
+ * The following only work if pte_present() is true.
+ * Undefined behaviour if not..
+ */
+extern inline int pte_read(pte_t pte)		{ return !(pte_val(pte) & _PAGE_FOR); }
+extern inline int pte_write(pte_t pte)		{ return !(pte_val(pte) & _PAGE_FOW); }
+extern inline int pte_exec(pte_t pte)		{ return !(pte_val(pte) & _PAGE_FOE); }
+extern inline int pte_dirty(pte_t pte)		{ return pte_val(pte) & _PAGE_DIRTY; }
+extern inline int pte_young(pte_t pte)		{ return pte_val(pte) & _PAGE_ACCESSED; }
+extern inline int pte_cow(pte_t pte)		{ return pte_val(pte) & _PAGE_COW; }
+
+extern inline pte_t pte_wrprotect(pte_t pte)	{ pte_val(pte) |= _PAGE_FOW; return pte; }
+extern inline pte_t pte_rdprotect(pte_t pte)	{ pte_val(pte) |= _PAGE_FOR; return pte; }
+extern inline pte_t pte_exprotect(pte_t pte)	{ pte_val(pte) |= _PAGE_FOE; return pte; }
+extern inline pte_t pte_mkclean(pte_t pte)	{ pte_val(pte) &= ~(__DIRTY_BITS); return pte; }
+extern inline pte_t pte_mkold(pte_t pte)	{ pte_val(pte) &= ~(__ACCESS_BITS); return pte; }
+extern inline pte_t pte_uncow(pte_t pte)	{ pte_val(pte) &= ~_PAGE_COW; return pte; }
+extern inline pte_t pte_mkwrite(pte_t pte)	{ pte_val(pte) &= _PAGE_FOW; return pte; }
+extern inline pte_t pte_mkread(pte_t pte)	{ pte_val(pte) &= _PAGE_FOR; return pte; }
+extern inline pte_t pte_mkexec(pte_t pte)	{ pte_val(pte) &= _PAGE_FOE; return pte; }
+extern inline pte_t pte_mkdirty(pte_t pte)	{ pte_val(pte) |= __DIRTY_BITS; return pte; }
+extern inline pte_t pte_mkyoung(pte_t pte)	{ pte_val(pte) |= __ACCESS_BITS; return pte; }
+extern inline pte_t pte_mkcow(pte_t pte)	{ pte_val(pte) |= _PAGE_COW; return pte; }
+
+/* to set the page-dir */
+extern inline void SET_PAGE_DIR(struct task_struct * tsk, pgd_t * pgdir)
+{
+	tsk->tss.ptbr = ((unsigned long) pgdir - PAGE_OFFSET) >> PAGE_SHIFT;
+	if (tsk == current)
+		invalidate();
+}
+
+#define PAGE_DIR_OFFSET(tsk,address) pgd_offset((tsk),(address))
+
+/* to find an entry in a page-table-directory */
+extern inline pgd_t * pgd_offset(struct task_struct * tsk, unsigned long address)
+{
+	return (pgd_t *) ((tsk->tss.ptbr << PAGE_SHIFT) + PAGE_OFFSET) +
+		((address >> PGDIR_SHIFT) & (PTRS_PER_PGD - 1));
+}
+
+/* Find an entry in the second-level page table.. */
+extern inline pmd_t * pmd_offset(pgd_t * dir, unsigned long address)
+{
+	return (pmd_t *) pgd_page(*dir) + ((address >> PMD_SHIFT) & (PTRS_PER_PMD - 1));
+}
+
+/* Find an entry in the third-level page table.. */
+extern inline pte_t * pte_offset(pmd_t * dir, unsigned long address)
+{
+	return (pte_t *) pmd_page(*dir) + ((address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1));
+}
+
+/*              
+ * Allocate and free page tables. The xxx_kernel() versions are
+ * used to allocate a kernel page table - this turns on ASN bits
+ * if any, and marks the page tables reserved.
+ */
+extern inline void pte_free_kernel(pte_t * pte)
+{
+	mem_map[MAP_NR(pte)] = 1;
+	free_page((unsigned long) pte);
+}
+
+extern inline pte_t * pte_alloc_kernel(pmd_t *pmd, unsigned long address)
+{
+	address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
+	if (pmd_none(*pmd)) {
+		pte_t *page = (pte_t *) get_free_page(GFP_KERNEL);
+		if (pmd_none(*pmd)) {
+			if (page) {
+				pmd_set(pmd, page);
+				mem_map[MAP_NR(page)] = MAP_PAGE_RESERVED;
+				return page + address;
+			}
+			pmd_set(pmd, (pte_t *) BAD_PAGETABLE);
+			return NULL;
+		}
+		free_page((unsigned long) page);
+	}
+	if (pmd_bad(*pmd)) {
+		printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
+		pmd_set(pmd, (pte_t *) BAD_PAGETABLE);
+		return NULL;
+	}
+	return (pte_t *) pmd_page(*pmd) + address;
+}
+
+extern inline void pmd_free_kernel(pmd_t * pmd)
+{
+	mem_map[MAP_NR(pmd)] = 1;
+	free_page((unsigned long) pmd);
+}
+
+extern inline pmd_t * pmd_alloc_kernel(pgd_t *pgd, unsigned long address)
+{
+	address = (address >> PMD_SHIFT) & (PTRS_PER_PMD - 1);
+	if (pgd_none(*pgd)) {
+		pmd_t *page = (pmd_t *) get_free_page(GFP_KERNEL);
+		if (pgd_none(*pgd)) {
+			if (page) {
+				pgd_set(pgd, page);
+				mem_map[MAP_NR(page)] = MAP_PAGE_RESERVED;
+				return page + address;
+			}
+			pgd_set(pgd, BAD_PAGETABLE);
+			return NULL;
+		}
+		free_page((unsigned long) page);
+	}
+	if (pgd_bad(*pgd)) {
+		printk("Bad pgd in pmd_alloc: %08lx\n", pgd_val(*pgd));
+		pgd_set(pgd, BAD_PAGETABLE);
+		return NULL;
+	}
+	return (pmd_t *) pgd_page(*pgd) + address;
+}
+
+extern inline void pte_free(pte_t * pte)
+{
+	free_page((unsigned long) pte);
+}
+
+extern inline pte_t * pte_alloc(pmd_t *pmd, unsigned long address)
+{
+	address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
+	if (pmd_none(*pmd)) {
+		pte_t *page = (pte_t *) get_free_page(GFP_KERNEL);
+		if (pmd_none(*pmd)) {
+			if (page) {
+				pmd_set(pmd, page);
+				return page + address;
+			}
+			pmd_set(pmd, (pte_t *) BAD_PAGETABLE);
+			return NULL;
+		}
+		free_page((unsigned long) page);
+	}
+	if (pmd_bad(*pmd)) {
+		printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
+		pmd_set(pmd, (pte_t *) BAD_PAGETABLE);
+		return NULL;
+	}
+	return (pte_t *) pmd_page(*pmd) + address;
+}
+
+extern inline void pmd_free(pmd_t * pmd)
+{
+	free_page((unsigned long) pmd);
+}
+
+extern inline pmd_t * pmd_alloc(pgd_t *pgd, unsigned long address)
+{
+	address = (address >> PMD_SHIFT) & (PTRS_PER_PMD - 1);
+	if (pgd_none(*pgd)) {
+		pmd_t *page = (pmd_t *) get_free_page(GFP_KERNEL);
+		if (pgd_none(*pgd)) {
+			if (page) {
+				pgd_set(pgd, page);
+				return page + address;
+			}
+			pgd_set(pgd, BAD_PAGETABLE);
+			return NULL;
+		}
+		free_page((unsigned long) page);
+	}
+	if (pgd_bad(*pgd)) {
+		printk("Bad pgd in pmd_alloc: %08lx\n", pgd_val(*pgd));
+		pgd_set(pgd, BAD_PAGETABLE);
+		return NULL;
+	}
+	return (pmd_t *) pgd_page(*pgd) + address;
+}
+
+extern pgd_t swapper_pg_dir[1024];
+
+#endif /* _ALPHA_PGTABLE_H */
diff -u --recursive --new-file v1.1.87/linux/include/asm-i386/page.h linux/include/asm-i386/page.h
--- v1.1.87/linux/include/asm-i386/page.h	Thu Jan 26 07:49:15 1995
+++ linux/include/asm-i386/page.h	Mon Jan 30 13:08:04 1995
@@ -1,49 +1,31 @@
 #ifndef _I386_PAGE_H
 #define _I386_PAGE_H
 
-#define CONFIG_STRICT_MM_TYPECHECKS
-
-#define invalidate() \
-__asm__ __volatile__("movl %%cr3,%%eax\n\tmovl %%eax,%%cr3": : :"ax")
-
 /* PAGE_SHIFT determines the page size */
-#define PAGE_SHIFT			12
-#define PGDIR_SHIFT			22
-#define PAGE_SIZE			(1UL << PAGE_SHIFT)
-#define PGDIR_SIZE			(1UL << PGDIR_SHIFT)
+#define PAGE_SHIFT	12
+#define PAGE_SIZE	(1UL << PAGE_SHIFT)
+#define PAGE_MASK	(~(PAGE_SIZE-1))
 
 #ifdef __KERNEL__
 
-#define PAGE_OFFSET	0
-#define MAP_NR(addr) ((addr) >> PAGE_SHIFT)
-#define MAP_PAGE_RESERVED (1<<15)
-
-typedef unsigned short mem_map_t;
-
-/* Just any arbitrary offset to the start of the vmalloc VM area: the
- * current 8MB value just means that there will be a 8MB "hole" after the
- * physical memory until the kernel virtual memory starts.  That means that
- * any out-of-bounds memory accesses will hopefully be caught.
- * The vmalloc() routines leaves a hole of 4kB between each vmalloced
- * area for the same reason. ;)
- */
-#define VMALLOC_OFFSET	(8*1024*1024)
-#define VMALLOC_START ((high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
-#define VMALLOC_VMADDR(x) (TASK_SIZE + (unsigned long)(x))
+#define CONFIG_STRICT_MM_TYPECHECKS
 
 #ifdef CONFIG_STRICT_MM_TYPECHECKS
 /*
  * These are used to make use of C type-checking..
  */
 typedef struct { unsigned long pte; } pte_t;
+typedef struct { unsigned long pmd; } pmd_t;
 typedef struct { unsigned long pgd; } pgd_t;
 typedef struct { unsigned long pgprot; } pgprot_t;
 
 #define pte_val(x)	((x).pte)
+#define pmd_val(x)	((x).pmd)
 #define pgd_val(x)	((x).pgd)
 #define pgprot_val(x)	((x).pgprot)
 
 #define __pte(x)	((pte_t) { (x) } )
+#define __pmd(x)	((pmd_t) { (x) } )
 #define __pgd(x)	((pgd_t) { (x) } )
 #define __pgprot(x)	((pgprot_t) { (x) } )
 
@@ -52,171 +34,34 @@
  * .. while these make it easier on the compiler
  */
 typedef unsigned long pte_t;
+typedef unsigned long pmd_t;
 typedef unsigned long pgd_t;
 typedef unsigned long pgprot_t;
 
 #define pte_val(x)	(x)
+#define pmd_val(x)	(x)
 #define pgd_val(x)	(x)
 #define pgprot_val(x)	(x)
 
 #define __pte(x)	(x)
+#define __pmd(x)	(x)
 #define __pgd(x)	(x)
 #define __pgprot(x)	(x)
 
 #endif
 
-#define _PAGE_PRESENT	0x001
-#define _PAGE_RW	0x002
-#define _PAGE_USER	0x004
-#define _PAGE_ACCESSED	0x020
-#define _PAGE_DIRTY	0x040
-#define _PAGE_COW	0x200	/* implemented in software (one of the AVL bits) */
-
-#define _PAGE_TABLE	(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED | _PAGE_DIRTY)
-#define _PAGE_CHG_MASK	(PAGE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY)
-
-#define PAGE_NONE	__pgprot(_PAGE_PRESENT | _PAGE_ACCESSED)
-#define PAGE_SHARED	__pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED)
-#define PAGE_COPY	__pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED | _PAGE_COW)
-#define PAGE_READONLY	__pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
-#define PAGE_KERNEL	__pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED)
-
-/*
- * The i386 can't do page protection for execute, and considers that the same are read.
- * Also, write permissions imply read permissions. This is the closest we can get..
- */
-#define __P000	PAGE_NONE
-#define __P001	PAGE_READONLY
-#define __P010	PAGE_COPY
-#define __P011	PAGE_COPY
-#define __P100	PAGE_READONLY
-#define __P101	PAGE_READONLY
-#define __P110	PAGE_COPY
-#define __P111	PAGE_COPY
-
-#define __S000	PAGE_NONE
-#define __S001	PAGE_READONLY
-#define __S010	PAGE_SHARED
-#define __S011	PAGE_SHARED
-#define __S100	PAGE_READONLY
-#define __S101	PAGE_READONLY
-#define __S110	PAGE_SHARED
-#define __S111	PAGE_SHARED
-
-/*
- * Define this if things work differently on a i386 and a i486:
- * it will (on a i486) warn about kernel memory accesses that are
- * done without a 'verify_area(VERIFY_WRITE,..)'
- */
-#undef CONFIG_TEST_VERIFY_AREA
-
-/* page table for 0-4MB for everybody */
-extern unsigned long pg0[1024];
-
-/*
- * BAD_PAGETABLE is used when we need a bogus page-table, while
- * BAD_PAGE is used for a bogus page.
- *
- * ZERO_PAGE is a global shared page that is always zero: used
- * for zero-mapped memory areas etc..
- */
-extern pte_t __bad_page(void);
-extern pte_t * __bad_pagetable(void);
-
-extern unsigned long __zero_page(void);
-
-#define BAD_PAGETABLE __bad_pagetable()
-#define BAD_PAGE __bad_page()
-#define ZERO_PAGE __zero_page()
-
-/* number of bits that fit into a memory pointer */
-#define BITS_PER_PTR			(8*sizeof(unsigned long))
-
-/* to mask away the intra-page address bits */
-#define PAGE_MASK			(~(PAGE_SIZE-1))
-
-/* to mask away the intra-page address bits */
-#define PGDIR_MASK			(~(PGDIR_SIZE-1))
+#define invalidate() \
+__asm__ __volatile__("movl %%cr3,%%eax\n\tmovl %%eax,%%cr3": : :"ax")
 
 /* to align the pointer to the (next) page boundary */
-#define PAGE_ALIGN(addr)		(((addr)+PAGE_SIZE-1)&PAGE_MASK)
-
-/* to align the pointer to a pointer address */
-#define PTR_MASK			(~(sizeof(void*)-1))
+#define PAGE_ALIGN(addr)	(((addr)+PAGE_SIZE-1)&PAGE_MASK)
 
-/* sizeof(void*)==1<<SIZEOF_PTR_LOG2 */
-/* 64-bit machines, beware!  SRB. */
-#define SIZEOF_PTR_LOG2			2
-
-/* to find an entry in a page-table-directory */
-#define PAGE_DIR_OFFSET(tsk,address) \
-((((unsigned long)(address)) >> 22) + (pgd_t *) (tsk)->tss.cr3)
-
-/* to find an entry in a page-table */
-#define PAGE_PTR(address) \
-((unsigned long)(address)>>(PAGE_SHIFT-SIZEOF_PTR_LOG2)&PTR_MASK&~PAGE_MASK)
-
-/* the no. of pointers that fit on a page */
-#define PTRS_PER_PAGE			(PAGE_SIZE/sizeof(void*))
-
-/* to set the page-dir */
-#define SET_PAGE_DIR(tsk,pgdir) \
-do { \
-	(tsk)->tss.cr3 = (unsigned long) (pgdir); \
-	if ((tsk) == current) \
-		__asm__ __volatile__("movl %0,%%cr3": :"a" ((tsk)->tss.cr3)); \
-} while (0)
-
-extern unsigned long high_memory;
-
-extern inline int pte_none(pte_t pte)		{ return !pte_val(pte); }
-extern inline int pte_present(pte_t pte)	{ return pte_val(pte) & _PAGE_PRESENT; }
-extern inline void pte_clear(pte_t *ptep)	{ pte_val(*ptep) = 0; }
-
-extern inline int pgd_none(pgd_t pgd)		{ return !pgd_val(pgd); }
-extern inline int pgd_bad(pgd_t pgd)		{ return (pgd_val(pgd) & ~PAGE_MASK) != _PAGE_TABLE || pgd_val(pgd) > high_memory; }
-extern inline int pgd_present(pgd_t pgd)	{ return pgd_val(pgd) & _PAGE_PRESENT; }
-extern inline void pgd_clear(pgd_t * pgdp)	{ pgd_val(*pgdp) = 0; }
+/* This handles the memory map.. */
+#define PAGE_OFFSET		0
+#define MAP_NR(addr)		(((unsigned long)(addr)) >> PAGE_SHIFT)
+#define MAP_PAGE_RESERVED	(1<<15)
 
-/*
- * The following only work if pte_present() is true.
- * Undefined behaviour if not..
- */
-extern inline int pte_read(pte_t pte)		{ return pte_val(pte) & _PAGE_USER; }
-extern inline int pte_write(pte_t pte)		{ return pte_val(pte) & _PAGE_RW; }
-extern inline int pte_exec(pte_t pte)		{ return pte_val(pte) & _PAGE_USER; }
-extern inline int pte_dirty(pte_t pte)		{ return pte_val(pte) & _PAGE_DIRTY; }
-extern inline int pte_young(pte_t pte)		{ return pte_val(pte) & _PAGE_ACCESSED; }
-extern inline int pte_cow(pte_t pte)		{ return pte_val(pte) & _PAGE_COW; }
-
-extern inline pte_t pte_wrprotect(pte_t pte)	{ pte_val(pte) &= ~_PAGE_RW; return pte; }
-extern inline pte_t pte_rdprotect(pte_t pte)	{ pte_val(pte) &= ~_PAGE_USER; return pte; }
-extern inline pte_t pte_exprotect(pte_t pte)	{ pte_val(pte) &= ~_PAGE_USER; return pte; }
-extern inline pte_t pte_mkclean(pte_t pte)	{ pte_val(pte) &= ~_PAGE_DIRTY; return pte; }
-extern inline pte_t pte_mkold(pte_t pte)	{ pte_val(pte) &= ~_PAGE_ACCESSED; return pte; }
-extern inline pte_t pte_uncow(pte_t pte)	{ pte_val(pte) &= ~_PAGE_COW; return pte; }
-extern inline pte_t pte_mkwrite(pte_t pte)	{ pte_val(pte) |= _PAGE_RW; return pte; }
-extern inline pte_t pte_mkread(pte_t pte)	{ pte_val(pte) |= _PAGE_USER; return pte; }
-extern inline pte_t pte_mkexec(pte_t pte)	{ pte_val(pte) |= _PAGE_USER; return pte; }
-extern inline pte_t pte_mkdirty(pte_t pte)	{ pte_val(pte) |= _PAGE_DIRTY; return pte; }
-extern inline pte_t pte_mkyoung(pte_t pte)	{ pte_val(pte) |= _PAGE_ACCESSED; return pte; }
-extern inline pte_t pte_mkcow(pte_t pte)	{ pte_val(pte) |= _PAGE_COW; return pte; }
-
-/*
- * Conversion functions: convert a page and protection to a page entry,
- * and a page entry and page directory to the page they refer to.
- */
-extern inline pte_t mk_pte(unsigned long page, pgprot_t pgprot)
-{ pte_t pte; pte_val(pte) = page | pgprot_val(pgprot); return pte; }
-
-extern inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
-{ pte_val(pte) = (pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot); return pte; }
-
-extern inline unsigned long pte_page(pte_t pte)	{ return pte_val(pte) & PAGE_MASK; }
-extern inline unsigned long pgd_page(pgd_t pgd)	{ return pgd_val(pgd) & PAGE_MASK; }
-
-extern inline void pgd_set(pgd_t * pgdp, pte_t * ptep)
-{ pgd_val(*pgdp) = _PAGE_TABLE | (unsigned long) ptep; }
+typedef unsigned short mem_map_t;
 
 #endif /* __KERNEL__ */
 
diff -u --recursive --new-file v1.1.87/linux/include/asm-i386/pgtable.h linux/include/asm-i386/pgtable.h
--- v1.1.87/linux/include/asm-i386/pgtable.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-i386/pgtable.h	Tue Jan 31 09:30:48 1995
@@ -0,0 +1,305 @@
+#ifndef _I386_PGTABLE_H
+#define _I386_PGTABLE_H
+
+/*
+ * The Linux memory management assumes a three-level page table setup. On
+ * the i386, we use that, but "fold" the mid level into the top-level page
+ * table, so that we physically have the same two-level page table as the
+ * i386 mmu expects.
+ *
+ * This file contains the functions and defines necessary to modify and use
+ * the i386 page table tree.
+ */
+
+/* PMD_SHIFT determines the size of the area a second-level page table can map */
+#define PMD_SHIFT	22
+#define PMD_SIZE	(1UL << PMD_SHIFT)
+#define PMD_MASK	(~(PMD_SIZE-1))
+
+/* PGDIR_SHIFT determines what a third-level page table entry can map */
+#define PGDIR_SHIFT	22
+#define PGDIR_SIZE	(1UL << PGDIR_SHIFT)
+#define PGDIR_MASK	(~(PGDIR_SIZE-1))
+
+/*
+ * entries per page directory level: the i386 is two-level, so
+ * we don't really have any PMD directory physically.
+ */
+#define PTRS_PER_PTE	1024
+#define PTRS_PER_PMD	1
+#define PTRS_PER_PGD	1024
+
+/* the no. of pointers that fit on a page: this will go away */
+#define PTRS_PER_PAGE	(PAGE_SIZE/sizeof(void*))
+
+/* Just any arbitrary offset to the start of the vmalloc VM area: the
+ * current 8MB value just means that there will be a 8MB "hole" after the
+ * physical memory until the kernel virtual memory starts.  That means that
+ * any out-of-bounds memory accesses will hopefully be caught.
+ * The vmalloc() routines leaves a hole of 4kB between each vmalloced
+ * area for the same reason. ;)
+ */
+#define VMALLOC_OFFSET	(8*1024*1024)
+#define VMALLOC_START ((high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
+#define VMALLOC_VMADDR(x) (TASK_SIZE + (unsigned long)(x))
+
+#define _PAGE_PRESENT	0x001
+#define _PAGE_RW	0x002
+#define _PAGE_USER	0x004
+#define _PAGE_ACCESSED	0x020
+#define _PAGE_DIRTY	0x040
+#define _PAGE_COW	0x200	/* implemented in software (one of the AVL bits) */
+
+#define _PAGE_TABLE	(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED | _PAGE_DIRTY)
+#define _PAGE_CHG_MASK	(PAGE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY)
+
+#define PAGE_NONE	__pgprot(_PAGE_PRESENT | _PAGE_ACCESSED)
+#define PAGE_SHARED	__pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED)
+#define PAGE_COPY	__pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED | _PAGE_COW)
+#define PAGE_READONLY	__pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
+#define PAGE_KERNEL	__pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED)
+
+/*
+ * The i386 can't do page protection for execute, and considers that the same are read.
+ * Also, write permissions imply read permissions. This is the closest we can get..
+ */
+#define __P000	PAGE_NONE
+#define __P001	PAGE_READONLY
+#define __P010	PAGE_COPY
+#define __P011	PAGE_COPY
+#define __P100	PAGE_READONLY
+#define __P101	PAGE_READONLY
+#define __P110	PAGE_COPY
+#define __P111	PAGE_COPY
+
+#define __S000	PAGE_NONE
+#define __S001	PAGE_READONLY
+#define __S010	PAGE_SHARED
+#define __S011	PAGE_SHARED
+#define __S100	PAGE_READONLY
+#define __S101	PAGE_READONLY
+#define __S110	PAGE_SHARED
+#define __S111	PAGE_SHARED
+
+/*
+ * Define this if things work differently on a i386 and a i486:
+ * it will (on a i486) warn about kernel memory accesses that are
+ * done without a 'verify_area(VERIFY_WRITE,..)'
+ */
+#undef CONFIG_TEST_VERIFY_AREA
+
+/* page table for 0-4MB for everybody */
+extern unsigned long pg0[1024];
+
+/*
+ * BAD_PAGETABLE is used when we need a bogus page-table, while
+ * BAD_PAGE is used for a bogus page.
+ *
+ * ZERO_PAGE is a global shared page that is always zero: used
+ * for zero-mapped memory areas etc..
+ */
+extern pte_t __bad_page(void);
+extern pte_t * __bad_pagetable(void);
+
+extern unsigned long __zero_page(void);
+
+#define BAD_PAGETABLE __bad_pagetable()
+#define BAD_PAGE __bad_page()
+#define ZERO_PAGE __zero_page()
+
+/* number of bits that fit into a memory pointer */
+#define BITS_PER_PTR			(8*sizeof(unsigned long))
+
+/* to align the pointer to a pointer address */
+#define PTR_MASK			(~(sizeof(void*)-1))
+
+/* sizeof(void*)==1<<SIZEOF_PTR_LOG2 */
+/* 64-bit machines, beware!  SRB. */
+#define SIZEOF_PTR_LOG2			2
+
+/* to find an entry in a page-table */
+#define PAGE_PTR(address) \
+((unsigned long)(address)>>(PAGE_SHIFT-SIZEOF_PTR_LOG2)&PTR_MASK&~PAGE_MASK)
+
+/* to set the page-dir */
+#define SET_PAGE_DIR(tsk,pgdir) \
+do { \
+	(tsk)->tss.cr3 = (unsigned long) (pgdir); \
+	if ((tsk) == current) \
+		__asm__ __volatile__("movl %0,%%cr3": :"a" ((tsk)->tss.cr3)); \
+} while (0)
+
+extern unsigned long high_memory;
+
+extern inline int pte_none(pte_t pte)		{ return !pte_val(pte); }
+extern inline int pte_present(pte_t pte)	{ return pte_val(pte) & _PAGE_PRESENT; }
+extern inline void pte_clear(pte_t *ptep)	{ pte_val(*ptep) = 0; }
+
+extern inline int pmd_none(pmd_t pmd)		{ return !pmd_val(pmd); }
+extern inline int pmd_bad(pmd_t pmd)		{ return (pmd_val(pmd) & ~PAGE_MASK) != _PAGE_TABLE || pmd_val(pmd) > high_memory; }
+extern inline int pmd_present(pmd_t pmd)	{ return pmd_val(pmd) & _PAGE_PRESENT; }
+extern inline void pmd_clear(pmd_t * pmdp)	{ pmd_val(*pmdp) = 0; }
+
+extern inline int pgd_none(pgd_t pgd)		{ return !pgd_val(pgd); }
+extern inline int pgd_bad(pgd_t pgd)		{ return (pgd_val(pgd) & ~PAGE_MASK) != _PAGE_TABLE || pgd_val(pgd) > high_memory; }
+extern inline int pgd_present(pgd_t pgd)	{ return pgd_val(pgd) & _PAGE_PRESENT; }
+extern inline void pgd_clear(pgd_t * pgdp)	{ pgd_val(*pgdp) = 0; }
+
+/*
+ * The following only work if pte_present() is true.
+ * Undefined behaviour if not..
+ */
+extern inline int pte_read(pte_t pte)		{ return pte_val(pte) & _PAGE_USER; }
+extern inline int pte_write(pte_t pte)		{ return pte_val(pte) & _PAGE_RW; }
+extern inline int pte_exec(pte_t pte)		{ return pte_val(pte) & _PAGE_USER; }
+extern inline int pte_dirty(pte_t pte)		{ return pte_val(pte) & _PAGE_DIRTY; }
+extern inline int pte_young(pte_t pte)		{ return pte_val(pte) & _PAGE_ACCESSED; }
+extern inline int pte_cow(pte_t pte)		{ return pte_val(pte) & _PAGE_COW; }
+
+extern inline pte_t pte_wrprotect(pte_t pte)	{ pte_val(pte) &= ~_PAGE_RW; return pte; }
+extern inline pte_t pte_rdprotect(pte_t pte)	{ pte_val(pte) &= ~_PAGE_USER; return pte; }
+extern inline pte_t pte_exprotect(pte_t pte)	{ pte_val(pte) &= ~_PAGE_USER; return pte; }
+extern inline pte_t pte_mkclean(pte_t pte)	{ pte_val(pte) &= ~_PAGE_DIRTY; return pte; }
+extern inline pte_t pte_mkold(pte_t pte)	{ pte_val(pte) &= ~_PAGE_ACCESSED; return pte; }
+extern inline pte_t pte_uncow(pte_t pte)	{ pte_val(pte) &= ~_PAGE_COW; return pte; }
+extern inline pte_t pte_mkwrite(pte_t pte)	{ pte_val(pte) |= _PAGE_RW; return pte; }
+extern inline pte_t pte_mkread(pte_t pte)	{ pte_val(pte) |= _PAGE_USER; return pte; }
+extern inline pte_t pte_mkexec(pte_t pte)	{ pte_val(pte) |= _PAGE_USER; return pte; }
+extern inline pte_t pte_mkdirty(pte_t pte)	{ pte_val(pte) |= _PAGE_DIRTY; return pte; }
+extern inline pte_t pte_mkyoung(pte_t pte)	{ pte_val(pte) |= _PAGE_ACCESSED; return pte; }
+extern inline pte_t pte_mkcow(pte_t pte)	{ pte_val(pte) |= _PAGE_COW; return pte; }
+
+/*
+ * Conversion functions: convert a page and protection to a page entry,
+ * and a page entry and page directory to the page they refer to.
+ */
+extern inline pte_t mk_pte(unsigned long page, pgprot_t pgprot)
+{ pte_t pte; pte_val(pte) = page | pgprot_val(pgprot); return pte; }
+
+extern inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
+{ pte_val(pte) = (pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot); return pte; }
+
+extern inline unsigned long pte_page(pte_t pte)
+{ return pte_val(pte) & PAGE_MASK; }
+
+extern inline unsigned long pmd_page(pmd_t pmd)
+{ return pmd_val(pmd) & PAGE_MASK; }
+
+extern inline unsigned long pgd_page(pgd_t pgd)
+{ return pgd_val(pgd) & PAGE_MASK; }
+
+extern inline void pgd_set(pgd_t * pgdp, pte_t * ptep)
+{ pgd_val(*pgdp) = _PAGE_TABLE | (unsigned long) ptep; }
+
+#define PAGE_DIR_OFFSET(tsk,address) pgd_offset((tsk),(address))
+
+/* to find an entry in a page-table-directory */
+extern inline pgd_t * pgd_offset(struct task_struct * tsk, unsigned long address)
+{
+	return (pgd_t *) tsk->tss.cr3 + (address >> PGDIR_SHIFT);
+}
+
+/* Find an entry in the second-level page table.. */
+extern inline pmd_t * pmd_offset(pgd_t * dir, unsigned long address)
+{
+	return (pmd_t *) dir;
+}
+
+/* Find an entry in the third-level page table.. */ 
+extern inline pte_t * pte_offset(pmd_t * dir, unsigned long address)
+{
+	return (pte_t *) pmd_page(*dir) + ((address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1));
+}
+
+/*
+ * Allocate and free page tables. The xxx_kernel() versions are
+ * used to allocate a kernel page table - this turns on ASN bits
+ * if any, and marks the page tables reserved.
+ */
+extern inline void pte_free_kernel(pte_t * pte)
+{
+	mem_map[MAP_NR(pte)] = 1;
+	free_page((unsigned long) pte);
+}
+
+extern inline pte_t * pte_alloc_kernel(pmd_t * pmd, unsigned long address)
+{
+	address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
+	if (pmd_none(*pmd)) {
+		pte_t * page = (pte_t *) get_free_page(GFP_KERNEL);
+		if (pmd_none(*pmd)) {
+			if (page) {
+				pmd_val(*pmd) = _PAGE_TABLE | (unsigned long) page;
+				mem_map[MAP_NR(page)] = MAP_PAGE_RESERVED;
+				return page + address;
+			}
+			pmd_val(*pmd) = _PAGE_TABLE | (unsigned long) BAD_PAGETABLE;
+			return NULL;
+		}
+		free_page((unsigned long) page);
+	}
+	if (pmd_bad(*pmd)) {
+		printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
+		pmd_val(*pmd) = _PAGE_TABLE | (unsigned long) BAD_PAGETABLE;
+		return NULL;
+	}
+	return (pte_t *) pmd_page(*pmd) + address;
+}
+
+/*
+ * allocating and freeing a pmd is trivial: the 1-entry pmd is
+ * inside the pgd, so has no extra memory associated with it.
+ */
+extern inline void pmd_free_kernel(pmd_t * pmd)
+{
+}
+
+extern inline pmd_t * pmd_alloc_kernel(pgd_t * pgd, unsigned long address)
+{
+	return (pmd_t *) pgd;
+}
+
+extern inline void pte_free(pte_t * pte)
+{
+	free_page((unsigned long) pte);
+}
+
+extern inline pte_t * pte_alloc(pmd_t * pmd, unsigned long address)
+{
+	address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
+	if (pmd_none(*pmd)) {
+		pte_t * page = (pte_t *) get_free_page(GFP_KERNEL);
+		if (pmd_none(*pmd)) {
+			if (page) {
+				pmd_val(*pmd) = _PAGE_TABLE | (unsigned long) page;
+				return page + address;
+			}
+			pmd_val(*pmd) = _PAGE_TABLE | (unsigned long) BAD_PAGETABLE;
+			return NULL;
+		}
+		free_page((unsigned long) page);
+	}
+	if (pmd_bad(*pmd)) {
+		printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
+		pmd_val(*pmd) = _PAGE_TABLE | (unsigned long) BAD_PAGETABLE;
+		return NULL;
+	}
+	return (pte_t *) pmd_page(*pmd) + address;
+}
+
+/*
+ * allocating and freeing a pmd is trivial: the 1-entry pmd is
+ * inside the pgd, so has no extra memory associated with it.
+ */
+extern inline void pmd_free(pmd_t * pmd)
+{
+}
+
+extern inline pmd_t * pmd_alloc(pgd_t * pgd, unsigned long address)
+{
+	return (pmd_t *) pgd;
+}
+
+extern pgd_t swapper_pg_dir[1024];
+
+#endif /* _I386_PAGE_H */
diff -u --recursive --new-file v1.1.87/linux/include/asm-mips/page.h linux/include/asm-mips/page.h
--- v1.1.87/linux/include/asm-mips/page.h	Mon Jan 30 06:41:58 1995
+++ linux/include/asm-mips/page.h	Tue Jan 31 09:36:21 1995
@@ -50,7 +50,7 @@
 /*
  * Note that we shift the lower 32bits of each EntryLo[01] entry
  * 6 bits to the left. That way we can convert the PFN into the
- * physical address by a single 'and' operation and gain 6 aditional
+ * physical address by a single 'and' operation and gain 6 additional
  * bits for storing information which isn't present in a normal
  * MIPS page table.
  */
diff -u --recursive --new-file v1.1.87/linux/include/asm-sparc/cprefix.h linux/include/asm-sparc/cprefix.h
--- v1.1.87/linux/include/asm-sparc/cprefix.h	Thu Jan 26 07:49:15 1995
+++ linux/include/asm-sparc/cprefix.h	Tue Jan 31 09:39:00 1995
@@ -1,7 +1,7 @@
 /* cprefix.h:  This file is included by assembly source which needs
  *             to know what the c-label prefixes are. The newer versions
  *	       of cpp that come with gcc predefine such things to help
- *	       us out. The reason this stuff is neaded is to make
+ *	       us out. The reason this stuff is needed is to make
  *	       solaris compiles of the kernel work.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
diff -u --recursive --new-file v1.1.87/linux/include/linux/aztcd.h linux/include/linux/aztcd.h
--- v1.1.87/linux/include/linux/aztcd.h	Sun Jan 22 23:03:59 1995
+++ linux/include/linux/aztcd.h	Tue Jan 31 09:36:21 1995
@@ -19,7 +19,7 @@
  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  *  History:	W.Zimmermann adaption to Aztech CD268-01A Version 1.3
- *		Oktober 1994 Email: zimmerma@rz.fht-esslingen.de
+ *		October 1994 Email: zimmerma@rz.fht-esslingen.de
  */
 
 /* *** change this to set the I/O port address */
diff -u --recursive --new-file v1.1.87/linux/include/linux/ipx.h linux/include/linux/ipx.h
--- v1.1.87/linux/include/linux/ipx.h	Mon Jan 30 06:41:58 1995
+++ linux/include/linux/ipx.h	Tue Jan 31 09:36:21 1995
@@ -7,9 +7,9 @@
 struct sockaddr_ipx
 {
 	short sipx_family;
+	short sipx_port;
 	unsigned long  sipx_network;
 	unsigned char sipx_node[IPX_NODE_LEN];
-	short sipx_port;
 	unsigned char	sipx_type;
 	unsigned char	sipx_zero;	/* 16 byte fill */
 };
@@ -18,8 +18,10 @@
  *	So we can fit the extra info for SIOCSIFADDR into the address nicely
  */
  
-#define sipx_primary	sipx_port
-#define sipx_internal	sipx_zero
+#define sipx_special	sipx_port
+#define sipx_action	sipx_zero
+#define IPX_DLTITF	0
+#define IPX_CRTITF	1
 
 typedef struct ipx_route_definition
 {
@@ -32,14 +34,16 @@
 {
 	unsigned long ipx_network;
 	unsigned char ipx_device[16];
-	unsigned short ipx_dlink_type;
+	unsigned char ipx_dlink_type;
 #define IPX_FRAME_NONE		0
 #define IPX_FRAME_SNAP		1
 #define IPX_FRAME_8022		2
 #define IPX_FRAME_ETHERII	3
 #define IPX_FRAME_8023		4
-	unsigned char ipx_primary;
-	unsigned char ipx_internal;
+	unsigned char ipx_special;
+#define IPX_SPECIAL_NONE	0
+#define IPX_PRIMARY		1
+#define IPX_INTERNAL		2
 	unsigned char ipx_node[IPX_NODE_LEN];
 }	ipx_interface_definition;
 	
@@ -50,7 +54,7 @@
 }	ipx_config_data;
 
 /*
- * OLD Route Definition for backware compatibility.
+ * OLD Route Definition for backward compatibility.
  */
 
 struct ipx_route_def
diff -u --recursive --new-file v1.1.87/linux/include/linux/mc146818rtc.h linux/include/linux/mc146818rtc.h
--- v1.1.87/linux/include/linux/mc146818rtc.h	Wed Dec  1 14:44:15 1993
+++ linux/include/linux/mc146818rtc.h	Tue Jan 31 09:30:48 1995
@@ -12,13 +12,31 @@
 #define _MC146818RTC_H
 #include <asm/io.h>
 
+#define RTC_PORT(x)	(0x70 + (x))
+#define RTC_ADDR(x)	(0x80 | (x))
+#define RTC_ALWAYS_BCD	1
+
+/*
+ * The Alpha Jensen hardware for some rather strange reason puts
+ * the RTC clock at 0x170 instead of 0x70. Probably due to some
+ * misguided idea about using 0x70 for NMI stuff.
+ */
+#ifdef __alpha__
+#undef RTC_PORT
+#undef RTC_ADDR
+#undef RTC_ALWAYS_BCD
+#define RTC_PORT(x)	(0x170+(x))
+#define RTC_ADDR(x)	(x)
+#define RTC_ALWAYS_BCD	0
+#endif
+
 #define CMOS_READ(addr) ({ \
-outb_p(addr|0x80,0x70); \
-inb_p(0x71); \
+outb_p(RTC_ADDR(addr),RTC_PORT(0)); \
+inb_p(RTC_PORT(1)); \
 })
 #define CMOS_WRITE(val, addr) ({ \
-outb_p(addr|0x80,0x70); \
-outb_p(val,0x71); \
+outb_p(RTC_ADDR(addr),RTC_PORT(0)); \
+outb_p(val,RTC_PORT(1)); \
 })
 
 /**********************************************************************
diff -u --recursive --new-file v1.1.87/linux/include/linux/mm.h linux/include/linux/mm.h
--- v1.1.87/linux/include/linux/mm.h	Thu Jan 26 07:49:15 1995
+++ linux/include/linux/mm.h	Mon Jan 30 13:08:04 1995
@@ -13,8 +13,6 @@
 #define VERIFY_READ 0
 #define VERIFY_WRITE 1
 
-extern pgd_t swapper_pg_dir[1024];
-
 extern int verify_area(int, const void *, unsigned long);
 
 /*
diff -u --recursive --new-file v1.1.87/linux/include/linux/proc_fs.h linux/include/linux/proc_fs.h
--- v1.1.87/linux/include/linux/proc_fs.h	Mon Jan 30 06:41:58 1995
+++ linux/include/linux/proc_fs.h	Tue Jan 31 14:36:24 1995
@@ -74,6 +74,9 @@
 #ifdef CONFIG_IP_ACCT
 	PROC_NET_IPACCT,
 #endif
+#if	defined(CONFIG_WAVELAN)
+	PROC_NET_WAVELAN,
+#endif	/* defined(CONFIG_WAVELAN) */
 #endif
 #ifdef CONFIG_IPX
 	PROC_NET_IPX_INTERFACE,
diff -u --recursive --new-file v1.1.87/linux/include/linux/serial.h linux/include/linux/serial.h
--- v1.1.87/linux/include/linux/serial.h	Mon Dec 19 16:35:51 1994
+++ linux/include/linux/serial.h	Tue Jan 31 09:39:02 1995
@@ -22,10 +22,19 @@
 	unsigned short	close_delay;
 	char	reserved_char[2];
 	int	hub6;
-	int	reserved[5];
+	unsigned short	closing_wait; /* time to wait before rcvr shutdown */
+	unsigned short	closing_wait2; /* time to wait after rcvr shutdown */
+	int	reserved[4];
 };
 
 /*
+ * For the close wait times, 0 means wait forever for serial port to
+ * flush its output.  65535 means don't wait at all.
+ */
+#define ASYNC_CLOSING_WAIT_INF	0
+#define ASYNC_CLOSING_WAIT_NONE	65535
+
+/*
  * These are the supported serial types.
  */
 #define PORT_UNKNOWN	0
@@ -33,8 +42,9 @@
 #define PORT_16450	2
 #define PORT_16550	3
 #define PORT_16550A	4
-#define PORT_CIRRUS     5
-#define PORT_MAX	5
+#define PORT_CIRRUS     5	/* Hey!  Who put this there? */
+#define PORT_16650	6
+#define PORT_MAX	6
 
 /*
  * Definitions for async_struct (and serial_struct) flags field
@@ -96,6 +106,8 @@
 	int			custom_divisor;
 	int			x_char;	/* xon/xoff character */
 	int			close_delay;
+	unsigned short		closing_wait;
+	unsigned short		closing_wait2;
 	int			IER; 	/* Interrupt Enable Register */
 	int			MCR; 	/* Modem control register */
 	int			MCR_noint; /* MCR with interrupts off */
diff -u --recursive --new-file v1.1.87/linux/include/linux/serial_reg.h linux/include/linux/serial_reg.h
--- v1.1.87/linux/include/linux/serial_reg.h	Wed Aug 10 19:26:44 1994
+++ linux/include/linux/serial_reg.h	Tue Jan 31 09:39:02 1995
@@ -21,6 +21,8 @@
 #define UART_IER	1	/* Out: Interrupt Enable Register */
 #define UART_IIR	2	/* In:  Interrupt ID Register */
 #define UART_FCR	2	/* Out: FIFO Control Register */
+#define UART_EFR	2	/* I/O: Extended Features Register */
+				/* (DLAB=1, 16C660 only) */
 #define UART_LCR	3	/* Out: Line Control Register */
 #define UART_MCR	4	/* Out: Modem Control Register */
 #define UART_LSR	5	/* In:  Line Status Register */
@@ -29,6 +31,7 @@
 
 /*
  * These are the definitions for the FIFO Control Register
+ * (16650 only)
  */
 #define UART_FCR_ENABLE_FIFO	0x01 /* Enable the FIFO */
 #define UART_FCR_CLEAR_RCVR	0x02 /* Clear the RCVR FIFO */
@@ -39,6 +42,15 @@
 #define UART_FCR_TRIGGER_4	0x40 /* Mask for trigger set at 4 */
 #define UART_FCR_TRIGGER_8	0x80 /* Mask for trigger set at 8 */
 #define UART_FCR_TRIGGER_14	0xC0 /* Mask for trigger set at 14 */
+/* 16650 redefinitions */
+#define UART_FCR6_R_TRIGGER_8	0x00 /* Mask for receive trigger set at 1 */
+#define UART_FCR6_R_TRIGGER_16	0x40 /* Mask for receive trigger set at 4 */
+#define UART_FCR6_R_TRIGGER_24  0x80 /* Mask for receive trigger set at 8 */
+#define UART_FCR6_R_TRIGGER_28	0xC0 /* Mask for receive trigger set at 14 */
+#define UART_FCR6_T_TRIGGER_16	0x00 /* Mask for transmit trigger set at 16 */
+#define UART_FCR6_T_TRIGGER_8	0x10 /* Mask for transmit trigger set at 8 */
+#define UART_FCR6_T_TRIGGER_24  0x20 /* Mask for transmit trigger set at 24 */
+#define UART_FCR6_T_TRIGGER_30	0x30 /* Mask for transmit trigger set at 30 */
 
 /*
  * These are the definitions for the Line Control Register
@@ -108,6 +120,18 @@
 #define UART_MSR_DDSR	0x02	/* Delta DSR */
 #define UART_MSR_DCTS	0x01	/* Delta CTS */
 #define UART_MSR_ANY_DELTA 0x0F	/* Any of the delta bits! */
+
+/*
+ * These are the definitions for the Extended Features Register
+ * (StarTech 16C660 only, when DLAB=1)
+ */
+#define UART_EFR_CTS	0x80	/* CTS flow control */
+#define UART_EFR_RTS	0x40	/* RTS flow control */
+#define UART_EFR_SCD	0x20	/* Special character detect */
+#define UART_EFR_ENI	0x10	/* Enhanced Interrupt */
+/*
+ * the low four bits control software flow control
+ */
 
 #endif /* _LINUX_SERIAL_REG_H */
 
diff -u --recursive --new-file v1.1.87/linux/ipc/shm.c linux/ipc/shm.c
--- v1.1.87/linux/ipc/shm.c	Mon Jan 30 06:41:59 1995
+++ linux/ipc/shm.c	Mon Jan 30 13:08:04 1995
@@ -6,13 +6,15 @@
  */
 
 #include <linux/errno.h>
-#include <asm/segment.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/ipc.h>
 #include <linux/shm.h>
 #include <linux/stat.h>
 #include <linux/malloc.h>
+
+#include <asm/segment.h>
+#include <asm/pgtable.h>
 
 extern int ipcperms (struct ipc_perm *ipcp, short shmflg);
 extern unsigned int get_swap_page (void);
diff -u --recursive --new-file v1.1.87/linux/kernel/module.c linux/kernel/module.c
--- v1.1.87/linux/kernel/module.c	Thu Jan 26 07:49:16 1995
+++ linux/kernel/module.c	Tue Jan 31 09:36:21 1995
@@ -32,7 +32,7 @@
  *	  and ALSO from loadable modules.
  *	  The goal is to assist in modularizing the kernel even more,
  *	  and finally: reducing the number of entries in ksyms.c
- *	  since every subsystem should now be able to decide amd
+ *	  since every subsystem should now be able to decide and
  *	  control exactly what symbols it wants to export, locally!
  */
 
diff -u --recursive --new-file v1.1.87/linux/kernel/sched.c linux/kernel/sched.c
--- v1.1.87/linux/kernel/sched.c	Thu Jan 26 07:49:16 1995
+++ linux/kernel/sched.c	Mon Jan 30 13:08:05 1995
@@ -30,6 +30,7 @@
 #include <asm/system.h>
 #include <asm/io.h>
 #include <asm/segment.h>
+#include <asm/pgtable.h>
 
 #define TIMER_IRQ 0
 
diff -u --recursive --new-file v1.1.87/linux/kernel/time.c linux/kernel/time.c
--- v1.1.87/linux/kernel/time.c	Thu Jan 26 07:49:16 1995
+++ linux/kernel/time.c	Tue Jan 31 09:30:48 1995
@@ -29,8 +29,6 @@
 #include <asm/io.h>
 
 #include <linux/mc146818rtc.h>
-#define RTC_ALWAYS_BCD 1
-
 #include <linux/timex.h>
 
 /* converts date to days since 1/1/1970
diff -u --recursive --new-file v1.1.87/linux/mm/filemap.c linux/mm/filemap.c
--- v1.1.87/linux/mm/filemap.c	Sun Jan 22 23:04:00 1995
+++ linux/mm/filemap.c	Mon Jan 30 13:08:05 1995
@@ -21,6 +21,7 @@
 
 #include <asm/segment.h>
 #include <asm/system.h>
+#include <asm/pgtable.h>
 
 /*
  * Shared mappings implemented 30.11.1994. It's not fully working yet,
diff -u --recursive --new-file v1.1.87/linux/mm/memory.c linux/mm/memory.c
--- v1.1.87/linux/mm/memory.c	Thu Jan 26 07:49:16 1995
+++ linux/mm/memory.c	Mon Jan 30 13:08:05 1995
@@ -47,6 +47,7 @@
 
 #include <asm/system.h>
 #include <asm/segment.h>
+#include <asm/pgtable.h>
 
 unsigned long high_memory = 0;
 
diff -u --recursive --new-file v1.1.87/linux/mm/mmap.c linux/mm/mmap.c
--- v1.1.87/linux/mm/mmap.c	Thu Jan 26 07:49:16 1995
+++ linux/mm/mmap.c	Mon Jan 30 13:08:05 1995
@@ -15,6 +15,7 @@
 
 #include <asm/segment.h>
 #include <asm/system.h>
+#include <asm/pgtable.h>
 
 static int anon_map(struct inode *, struct file *, struct vm_area_struct *);
 
diff -u --recursive --new-file v1.1.87/linux/mm/mprotect.c linux/mm/mprotect.c
--- v1.1.87/linux/mm/mprotect.c	Thu Jan 26 07:49:16 1995
+++ linux/mm/mprotect.c	Mon Jan 30 13:08:05 1995
@@ -15,6 +15,7 @@
 
 #include <asm/segment.h>
 #include <asm/system.h>
+#include <asm/pgtable.h>
 
 static void change_protection(unsigned long start, unsigned long end, pgprot_t newprot)
 {
diff -u --recursive --new-file v1.1.87/linux/mm/swap.c linux/mm/swap.c
--- v1.1.87/linux/mm/swap.c	Mon Jan 30 06:41:59 1995
+++ linux/mm/swap.c	Mon Jan 30 13:08:05 1995
@@ -22,6 +22,7 @@
 #include <asm/dma.h>
 #include <asm/system.h> /* for cli()/sti() */
 #include <asm/bitops.h>
+#include <asm/pgtable.h>
 
 #define MAX_SWAPFILES 8
 
diff -u --recursive --new-file v1.1.87/linux/mm/vmalloc.c linux/mm/vmalloc.c
--- v1.1.87/linux/mm/vmalloc.c	Thu Jan 26 07:49:16 1995
+++ linux/mm/vmalloc.c	Tue Jan 31 09:30:48 1995
@@ -16,6 +16,7 @@
 #include <linux/mm.h>
 
 #include <asm/segment.h>
+#include <asm/pgtable.h>
 
 struct vm_struct {
 	unsigned long flags;
@@ -26,122 +27,143 @@
 
 static struct vm_struct * vmlist = NULL;
 
-static inline void set_pgdir(unsigned long dindex, pte_t * page_table)
+static inline void set_pgdir(unsigned long address, pgd_t entry)
 {
 	struct task_struct * p;
 
-	p = &init_task;
-	do {
-		pgd_set(PAGE_DIR_OFFSET(p,0) + dindex, page_table);
-		p = p->next_task;
-	} while (p != &init_task);
+	for_each_task(p)
+		*PAGE_DIR_OFFSET(p,address) = entry;
 }
 
-static inline void clear_pgdir(unsigned long dindex)
+static inline void free_area_pte(pmd_t * pmd, unsigned long address, unsigned long size)
 {
-	struct task_struct * p;
+	pte_t * pte;
+	unsigned long end;
 
-	p = &init_task;
-	do {
-		pgd_clear(PAGE_DIR_OFFSET(p,0) + dindex);
-		p = p->next_task;
-	} while (p != &init_task);
+	if (pmd_none(*pmd))
+		return;
+	if (pmd_bad(*pmd)) {
+		printk("free_area_pte: bad pmd (%08lx)\n", pmd_val(*pmd));
+		pmd_clear(pmd);
+		return;
+	}
+	pte = pte_offset(pmd, address);
+	address &= ~PMD_MASK;
+	end = address + size;
+	if (end > PMD_SIZE)
+		end = PMD_SIZE;
+	while (address < end) {
+		pte_t page = *pte;
+		pte_clear(pte);
+		address += PAGE_SIZE;
+		pte++;
+		if (pte_none(page))
+			continue;
+		if (pte_present(page)) {
+			free_page(pte_page(page));
+			continue;
+		}
+		printk("Whee.. Swapped out page in kernel page table\n");
+	}
 }
 
-static int free_area_pages(unsigned long dindex, unsigned long index, unsigned long nr)
+static inline void free_area_pmd(pgd_t * dir, unsigned long address, unsigned long size)
 {
-	pgd_t * dir;
-	pte_t * page_table;
-	unsigned long page;
+	pmd_t * pmd;
+	unsigned long end;
 
-	dir = swapper_pg_dir + dindex;
 	if (pgd_none(*dir))
-		return 0;
+		return;
 	if (pgd_bad(*dir)) {
-		printk("bad page directory entry in free_area_pages: %08lx\n", pgd_val(*dir));
+		printk("free_area_pmd: bad pgd (%08lx)\n", pgd_val(*dir));
 		pgd_clear(dir);
-		return 0;
+		return;
+	}
+	pmd = pmd_offset(dir, address);
+	address &= ~PGDIR_MASK;
+	end = address + size;
+	if (end > PGDIR_SIZE)
+		end = PGDIR_SIZE;
+	while (address < end) {
+		free_area_pte(pmd, address, end - address);
+		address = (address + PMD_SIZE) & PMD_MASK;
+		pmd++;
+	}
+}
+
+static void free_area_pages(unsigned long address, unsigned long size)
+{
+	pgd_t * dir;
+	unsigned long end = address + size;
+
+	dir = pgd_offset(&init_task, address);
+	while (address < end) {
+		free_area_pmd(dir, address, end - address);
+		address = (address + PGDIR_SIZE) & PGDIR_MASK;
+		dir++;
 	}
-	page = pgd_page(*dir);
-	page_table = index + (pte_t *) page;
-	do {
-		pte_t pte = *page_table;
-		pte_clear(page_table);
-		if (pte_present(pte))
-			free_page(pte_page(pte));
-		page_table++;
-	} while (--nr);
-	page_table = (pte_t *) page;
-	for (nr = 0 ; nr < PTRS_PER_PAGE ; nr++, page_table++)
-		if (!pte_none(*page_table))
-			return 0;
-	clear_pgdir(dindex);
-	mem_map[MAP_NR(page)] = 1;
-	free_page(page);
 	invalidate();
-	return 0;
 }
 
-static int alloc_area_pages(unsigned long dindex, unsigned long index, unsigned long nr)
+static inline int alloc_area_pte(pte_t * pte, unsigned long address, unsigned long size)
 {
-	pgd_t *dir;
-	pte_t *page_table;
+	unsigned long end;
 
-	dir = swapper_pg_dir + dindex;
-	if (pgd_none(*dir)) {
-		unsigned long page = get_free_page(GFP_KERNEL);
+	address &= ~PMD_MASK;
+	end = address + size;
+	if (end > PMD_SIZE)
+		end = PMD_SIZE;
+	while (address < end) {
+		unsigned long page;
+		if (!pte_none(*pte))
+			printk("alloc_area_pte: page already exists\n");
+		page = __get_free_page(GFP_KERNEL);
 		if (!page)
 			return -ENOMEM;
-		if (!pgd_none(*dir)) {
-			free_page(page);
-		} else {
-			mem_map[MAP_NR(page)] = MAP_PAGE_RESERVED;
-			set_pgdir(dindex, (pte_t *) page);
-		}
-	}
-	if (pgd_bad(*dir)) {
-		printk("Bad page dir entry in alloc_area_pages (%08lx)\n", pgd_val(*dir));
-		return -ENOMEM;
+		*pte = mk_pte(page, PAGE_KERNEL);
+		address += PAGE_SIZE;
+		pte++;
 	}
-	page_table = index + (pte_t *) pgd_page(*dir);
-	/*
-	 * use a tempotary page-table entry to remove a race with
-	 * vfree(): it mustn't free the page table from under us
-	 * if we sleep in get_free_page()
-	 */
-	*page_table = BAD_PAGE;
-	do {
-		unsigned long pg = get_free_page(GFP_KERNEL);
+	return 0;
+}
+
+static inline int alloc_area_pmd(pmd_t * pmd, unsigned long address, unsigned long size)
+{
+	unsigned long end;
 
-		if (!pg)
+	address &= ~PGDIR_MASK;
+	end = address + size;
+	if (end > PGDIR_SIZE)
+		end = PGDIR_SIZE;
+	while (address < end) {
+		pte_t * pte = pte_alloc_kernel(pmd, address);
+		if (!pte)
 			return -ENOMEM;
-		*page_table = mk_pte(pg, PAGE_KERNEL);
-		page_table++;
-	} while (--nr);
-	invalidate();
+		if (alloc_area_pte(pte, address, end - address))
+			return -ENOMEM;
+		address = (address + PMD_SIZE) & PMD_MASK;
+		pmd++;
+	}
 	return 0;
 }
 
-static int do_area(void * addr, unsigned long size,
-	int (*area_fn)(unsigned long,unsigned long,unsigned long))
+static int alloc_area_pages(unsigned long address, unsigned long size)
 {
-	unsigned long nr, dindex, index;
+	pgd_t * dir;
+	unsigned long end = address + size;
 
-	nr = size >> PAGE_SHIFT;
-	dindex = VMALLOC_VMADDR(addr);
-	index = (dindex >> PAGE_SHIFT) & (PTRS_PER_PAGE-1);
-	dindex = (dindex >> PGDIR_SHIFT) & (PTRS_PER_PAGE-1);
-	while (nr > 0) {
-		unsigned long i = PTRS_PER_PAGE - index;
-
-		if (i > nr)
-			i = nr;
-		nr -= i;
-		if (area_fn(dindex, index, i))
-			return -1;
-		index = 0;
-		dindex++;
+	dir = PAGE_DIR_OFFSET(&init_task, address);
+	while (address < end) {
+		pmd_t *pmd = pmd_alloc_kernel(dir, address);
+		if (!pmd)
+			return -ENOMEM;
+		if (alloc_area_pmd(pmd, address, end - address))
+			return -ENOMEM;
+		set_pgdir(address, *dir);
+		address = (address + PGDIR_SIZE) & PGDIR_MASK;
+		dir++;
 	}
+	invalidate();
 	return 0;
 }
 
@@ -158,7 +180,7 @@
 	for (p = &vmlist ; (tmp = *p) ; p = &tmp->next) {
 		if (tmp->addr == addr) {
 			*p = tmp->next;
-			do_area(tmp->addr, tmp->size, free_area_pages);
+			free_area_pages(VMALLOC_VMADDR(tmp->addr), tmp->size);
 			kfree(tmp);
 			return;
 		}
@@ -188,7 +210,7 @@
 	area->addr = addr;
 	area->next = *p;
 	*p = area;
-	if (do_area(addr, size, alloc_area_pages)) {
+	if (alloc_area_pages(VMALLOC_VMADDR(addr), size)) {
 		vfree(addr);
 		return NULL;
 	}
diff -u --recursive --new-file v1.1.87/linux/net/inet/dev.c linux/net/inet/dev.c
--- v1.1.87/linux/net/inet/dev.c	Wed Jan 11 21:14:29 1995
+++ linux/net/inet/dev.c	Mon Jan 30 13:10:06 1995
@@ -388,7 +388,12 @@
 	{
 		for (nitcount= dev_nit, ptype = ptype_base; nitcount > 0 && ptype != NULL; ptype = ptype->next) 
 		{
-			if (ptype->type == htons(ETH_P_ALL) && (ptype->dev==dev || !ptype->dev)) 
+			/* Never send packets back to the socket
+			 * they originated from - MvS (miquels@drinkel.ow.org)
+			 */
+			if (ptype->type == htons(ETH_P_ALL) &&
+			   (ptype->dev == dev || !ptype->dev) &&
+			   ((struct sock *)ptype->data != skb->sk))
 			{
 				struct sk_buff *skb2;
 				if ((skb2 = skb_clone(skb, GFP_ATOMIC)) == NULL)
diff -u --recursive --new-file v1.1.87/linux/net/inet/ipx.c linux/net/inet/ipx.c
--- v1.1.87/linux/net/inet/ipx.c	Mon Jan 30 06:41:59 1995
+++ linux/net/inet/ipx.c	Tue Jan 31 09:39:01 1995
@@ -346,7 +346,7 @@
 	/*
 	 *	We need to check if there is a primary net and if
 	 *	this is addressed to one of the *SPECIAL* sockets because
-	 *	these need to be propogated to the primary net.
+	 *	these need to be propagated to the primary net.
 	 *	The *SPECIAL* socket list contains: 0x452(SAP), 0x453(RIP) and
 	 *	0x456(Diagnostic).
 	 */
@@ -482,7 +482,7 @@
 		}
 	}
 
-	/* if the orginating net is not equal to our net; this is routed */
+	/* if the originating net is not equal to our net; this is routed */
 	if (ipx->ipx_source.net != intrfc->if_netnum) {
 		if (++(ipx->ipx_tctrl) > ipxcfg_max_hops) 
 			send_to_wire = 0;
@@ -621,6 +621,18 @@
 	return ipxitf_add_local_route(intrfc);
 }
 
+static int
+ipx_map_frame_type(unsigned char type)
+{
+	switch (type) {
+	case IPX_FRAME_ETHERII: return htons(ETH_P_IPX);
+	case IPX_FRAME_8022: return htons(ETH_P_802_2);
+	case IPX_FRAME_SNAP: return htons(ETH_P_SNAP);
+	case IPX_FRAME_8023: return htons(ETH_P_802_3);
+	}
+	return 0;
+}
+
 static int 
 ipxitf_create(ipx_interface_definition *idef)
 {
@@ -629,10 +641,10 @@
 	struct datalink_proto	*datalink = NULL;
 	ipx_interface	*intrfc;
 
-	if (idef->ipx_internal) 
+	if (idef->ipx_special == IPX_INTERNAL) 
 		return ipxitf_create_internal(idef);
 
-	if (idef->ipx_primary && (ipx_primary_net != NULL))
+	if ((idef->ipx_special == IPX_PRIMARY) && (ipx_primary_net != NULL))
 		return -EEXIST;
 
 	if ((idef->ipx_network != 0L) &&
@@ -665,9 +677,12 @@
 		return -EPROTONOSUPPORT;
 
 	dev=dev_get(idef->ipx_device);
-	if(dev==NULL)
+	if (dev==NULL) 
 		return -ENODEV;
 
+	if (!(dev->flags & IFF_UP))
+		return -ENETDOWN;
+
 	/* Check addresses are suitable */
 	if(dev->addr_len>IPX_NODE_LEN)
 		return -EINVAL;
@@ -688,7 +703,8 @@
 		intrfc->if_sklist = NULL;
 		intrfc->if_sknum = IPX_MIN_EPHEMERAL_SOCKET;
 		/* Setup primary if necessary */
-		if (idef->ipx_primary) ipx_primary_net = intrfc;
+		if ((idef->ipx_special == IPX_PRIMARY)) 
+			ipx_primary_net = intrfc;
 		intrfc->if_internal = 0;
 		intrfc->if_ipx_offset = dev->hard_header_len + datalink->header_length;
 		memset(intrfc->if_node, 0, IPX_NODE_LEN);
@@ -711,7 +727,7 @@
 	unsigned short	dlink_type = 0;
 	ipx_interface	*intrfc;
 
-	if (idef->ipx_internal) {
+	if (idef->ipx_special == IPX_INTERNAL) {
 		if (ipx_internal_net != NULL) {
 			ipxitf_down(ipx_internal_net);
 			return 0;
@@ -719,24 +735,9 @@
 		return -ENOENT;
 	}
 
-	switch (idef->ipx_dlink_type) {
-	case IPX_FRAME_ETHERII: 
-		dlink_type = htons(ETH_P_IPX);
-		break;
-	case IPX_FRAME_8022:
-		dlink_type = htons(ETH_P_802_2);
-		break;
-	case IPX_FRAME_SNAP:
-		dlink_type = htons(ETH_P_SNAP);
-		break;
-	case IPX_FRAME_8023:
-		dlink_type = htons(ETH_P_802_3);
-		break;
-	case IPX_FRAME_NONE:
-	default:
+	dlink_type = ipx_map_frame_type(idef->ipx_dlink_type);
+	if (dlink_type == 0)
 		return -EPROTONOSUPPORT;
-		break;
-	}
 
 	dev=dev_get(idef->ipx_device);
 	if(dev==NULL) return -ENODEV;
@@ -811,10 +812,10 @@
 				return -EINVAL;
 			f.ipx_network=sipx->sipx_network;
 			memcpy(f.ipx_device, ifr.ifr_name, sizeof(f.ipx_device));
+			memcpy(f.ipx_node, sipx->sipx_node, IPX_NODE_LEN);
 			f.ipx_dlink_type=sipx->sipx_type;
-			f.ipx_primary=sipx->sipx_primary;
-			f.ipx_internal=sipx->sipx_internal;
-			if(sipx->sipx_network==0)
+			f.ipx_special=sipx->sipx_special;
+			if(sipx->sipx_action==IPX_DLTITF)
 				return ipxitf_delete(&f);
 			else
 				return ipxitf_create(&f);
@@ -833,12 +834,13 @@
 			dev=dev_get(ifr.ifr_name);
 			if(!dev)
 				return -ENODEV;
-			ipxif=ipxitf_find_using_phys(dev, sipx->sipx_type);
+			ipxif=ipxitf_find_using_phys(dev, ipx_map_frame_type(sipx->sipx_type));
 			if(ipxif==NULL)
 				return -EADDRNOTAVAIL;
 			sipx->sipx_network=ipxif->if_netnum;
 			memcpy(sipx->sipx_node, ipxif->if_node, sizeof(sipx->sipx_node));
-						
+			memcpy_tofs(arg,&ifr,sizeof(ifr));
+			return 0;
 		}
 		case SIOCAIPXITFCRT:
 			err=verify_area(VERIFY_READ,arg,sizeof(char));
@@ -1054,7 +1056,7 @@
 	switch(cmd)
 	{
 		case SIOCDELRT:
-			return ipxrtr_delete(sg->sipx_network);
+			return ipxrtr_delete(st->sipx_network);
 		case SIOCADDRT:
 		{
 			struct ipx_route_definition f;
diff -u --recursive --new-file v1.1.87/linux/net/inet/psnap.c linux/net/inet/psnap.c
--- v1.1.87/linux/net/inet/psnap.c	Mon Jan 30 06:42:00 1995
+++ linux/net/inet/psnap.c	Mon Jan 30 13:10:06 1995
@@ -2,6 +2,7 @@
  *	SNAP data link layer. Derived from 802.2
  *
  *		Alan Cox <Alan.Cox@linux.org>, from the 802.2 layer by Greg Page.
+ *		Merged in additions from Greg Page's psnap.c.
  *
  *		This program is free software; you can redistribute it and/or
  *		modify it under the terms of the GNU General Public License
@@ -38,6 +39,15 @@
  
 int snap_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
 {
+	static struct packet_type psnap_packet_type = 
+	{
+		0,	
+		NULL,		/* All Devices */
+		snap_rcv,
+		NULL,
+		NULL,
+	};
+	
 	struct datalink_proto	*proto;
 
 	proto = find_snap_client(skb->h.raw);
@@ -49,7 +59,9 @@
 		 
 		skb->h.raw += 5;
 		skb->len -= 5;
-		return proto->rcvfunc(skb, dev, pt);
+		if (psnap_packet_type.type == 0)
+			psnap_packet_type.type=htons(ETH_P_SNAP);
+		return proto->rcvfunc(skb, dev, &psnap_packet_type);
 	}
 	skb->sk = NULL;
 	kfree_skb(skb, FREE_READ);
diff -u --recursive --new-file v1.1.87/linux/net/inet/tcp.c linux/net/inet/tcp.c
--- v1.1.87/linux/net/inet/tcp.c	Mon Jan 30 08:53:06 1995
+++ linux/net/inet/tcp.c	Tue Jan 31 15:44:36 1995
@@ -157,7 +157,7 @@
  *		Change the receive queue to assemble as it goes. This lets us
  *		dispose of most of tcp_sequence, half of tcp_ack and chunks of
  *		tcp_data/tcp_read as well as the window shrink crud.
- *		Seperate out duplicated code - tcp_alloc_skb, tcp_build_ack
+ *		Separate out duplicated code - tcp_alloc_skb, tcp_build_ack
  *		tcp_queue_skb seem obvious routines to extract.
  *	
  *		This program is free software; you can redistribute it and/or
@@ -582,7 +582,7 @@
 }
 
 /*
- *	A write timeout has occured. Process the after effects.
+ *	A write timeout has occurred. Process the after effects.
  */
 
 static int tcp_write_timeout(struct sock *sk)
@@ -675,8 +675,7 @@
 		/* Window probing */
 		case TIME_PROBE0:
 			tcp_send_probe0(sk);
-			if(tcp_write_timeout(sk))
-				release_sock (sk);
+			tcp_write_timeout(sk);
 			break;
 		/* Retransmitting */
 		case TIME_WRITE:
@@ -704,7 +703,6 @@
 				{
 					reset_xmit_timer (sk, TIME_WRITE, skb->when + sk->rto - jiffies);
 					restore_flags(flags);
-					release_sock (sk);
 					break;
 				}
 				restore_flags(flags);
@@ -712,10 +710,8 @@
 				 *	Retransmission
 				 */
 				sk->prot->retransmit (sk, 0);
-				if(!tcp_write_timeout(sk))
-					break;
+				tcp_write_timeout(sk);
 			}
-			release_sock (sk);
 			break;
 		}
 		/* Sending Keepalives */
@@ -730,14 +726,13 @@
 			if (sk->prot->write_wakeup)
 				  sk->prot->write_wakeup (sk);
 			sk->retransmits++;
-			if(tcp_write_timeout(sk))
-				release_sock (sk);
+			tcp_write_timeout(sk);
 			break;
 		default:
 			printk ("rexmit_timer: timer expired - reason unknown\n");
-			release_sock (sk);
 			break;
 	}
+	release_sock(sk);
 }
 
 /*
@@ -2017,7 +2012,7 @@
 	struct wait_queue wait = { current, NULL };
 	int copied = 0;
 	unsigned long peek_seq;
-	volatile unsigned long *seq;	/* So gcc doesnt overoptimise */
+	volatile unsigned long *seq;	/* So gcc doesn't overoptimise */
 	unsigned long used;
 
 	/* 
@@ -2600,8 +2595,9 @@
 	  	{
 	  		case TCPOPT_EOL:
 	  			return;
-	  		case TCPOPT_NOP:
-	  			length-=2;
+	  		case TCPOPT_NOP:	/* Ref: RFC 793 section 3.1 */
+	  			length--;
+	  			ptr--;		/* the opsize=*ptr++ above was a mistake */
 	  			continue;
 	  		
 	  		default:
