Linux 0.99.13 released

Linux 0.99pl13 has been released (for almost a week no, actually, sorry
for the delayed announcement), and can be found on nic.funet.fi in
pub/OS/Linux/PEOPLE/Linus and mirror sites.

Rough changes since pl12 (most of which have been there in various ALPHA
versions):

 - the bad memory management one-liner bug is naturally fixed.
 - compiled with plain C by default instead of C++
 - ELF binary support (Eric Youngdale)
 - Quickport mouse support (and some changes to the PS/2 mouse driver)
   by Johan Myreen and co)
 - core file name change ("core" -> "core.xxxx" where xxxx is the name
   of the program that dumped code).  Idea from ???.  Also, core-files
   now correctly truncate any existing core file before being written.
 - some mmap() fixes: better error returns, and handling of non-fixed
   maps for /dev/mem etc.
 - fixes for rename/unlink/rmdir at mount-points.
 - packet mode fixes by Charles Hedrick.  Sadly, these are likely to
   break old telnet/rlogin binaries, but it had to be done in order to
   communicate correctly with the rest of the world.
 - FPU emulator patches from Bill Metzenthen.  The fprem1 insn should be
   correct now (not that anybody seems to have seen the incorrect
   behaviour..)
 - a few fixes for SCSI (Drew and Eric)
 - signal.c changes to handle multiple segments (for Wine) correctly.
 - updated drivers from Donald Becker: 3c509 and AT1500 drivers, but
   also some other drivers have been edited, and some networking fixes.

Note that I have gotten a lot of patches that simply didn't make it: I
think I have 5-10 reasonable patches that I simply never got around to
check very carefully but that have their own reasons for existence,
ranging from sysv signal handling to quotas.  They'll probably get there
eventually, but didn't make it into pl13.

		Linus
diff --git a/CHANGES b/CHANGES
new file mode 100644
index 0000000..dde6c32
--- /dev/null
+++ b/CHANGES
@@ -0,0 +1,120 @@
+CHANGES since 0.99 patchlevel 12 and earlier:
+
+ - the bad memory management one-liner bug in pl12 is naturally fixed.
+ - compiled with plain C by default instead of C++
+ - ELF binary support (Eric Youngdale)
+ - Quickport mouse support (and some changes to the PS/2 mouse driver)
+   by Johan Myreen and co)
+ - core file name change ("core" -> "core.xxxx" where xxxx is the name
+   of the program that dumped code).  Idea from ???.  Also, core-files
+   now correctly truncate any existing core file before being written.
+ - some mmap() fixes: better error returns, and handling of non-fixed
+   maps for /dev/mem etc.
+ - one kludgy way to fix the wrong arp packets that have plagued net-2d
+   (resulting in arp packets that had the first four bytes of the
+   ethernet address as the IP address).
+ - I fixed the mount-point handling of 'rename()' and 'unlink()/rmdir()'
+   so that they should now work and/or give appropriate error messages.
+   An early version of this patch was already sent to the KERNEL
+   channel, which fixed the rename problem but not a similar bug with
+   unlink.
+ - packet mode fixes by Charles Hedrick.  Sadly, these are likely to
+   break old telnet/rlogin binaries, but it had to be done in order to
+   communicate correctly with the rest of the world.
+ - FPU emulator patches from Bill Metzenthen.  The fprem1 insn should be
+   correct now (not that anybody seems to have seen the incorrect
+   behaviour..)
+ - a few fixes for SCSI (Drew and Eric)
+ - signal.c changes to handle multiple segments (for Wine) correctly.
+ - updated drivers from Donald Becker: 3c509 and AT1500 drivers, but
+   also some other drivers have been edited, and some networking fixes.
+
+CHANGES since 0.99 patchlevel 11 and earlier:
+
+ - The memory manager cleanup has continued, and seems to be mostly
+   ready, as proven by the ease of adding mmap() over NFS with the new
+   routines.  So yes, the pl12 kernel will demand-load your binaries
+   over NFS, sharing code and clean data, as well as running shared
+   libraries over NFS.  Memory management by Eric and me, while the NFS
+   mmap code was written by Jon Tombs,
+
+ - ** IMPORTANT **: The keyboard driver has been enhanced even further,
+   and almost everything is completely re-mappable.  This means that
+   there is a new version of 'loadkeys' and 'dumpkeys' that you must use
+   with this kernel or you'll have problems.  The default keyboard is
+   still the US mapping, but if you want to create your own mappings
+   you'll have to load them with the new binaries.  Get the 'kbd.tar.gz'
+   archive from the same place you get the kernel.
+
+   The new keymappings allow things like function key string changes,
+   remapping of the control keys, and freedom to remap any of the normal
+   keyboard functions: including special features like rebooting,
+   console switching etc.  The keyboard remapping code has been done
+   mostly by Risto Kankkunen (Risto.Kankkunen@Helsinki.FI).
+
+ - updated network drivers by Donald Becker
+
+ - updated serial drivers - tytso@Athena.mit.edu
+
+ - updated 387 emulation (Bill Metzenthen).  The updated emulator code
+   has more exact trigonometric functions and improved exception
+   handling.  It now behaves very much like a real 486, with only small
+   changes (greater accuracy, slightly different denormal NaN handling
+   etc - hard to detect the differences even if you are looking for
+   them).
+
+ - network timer fixes by Florian La Roche (much cleaned up net/inet/timer.c
+   and some bad race-conditions fixed).
+
+ - Scsi code updates by Eric Youngdale and others
+
+ - Sony CDU-31A CDROM driver by Corey Minyard added to the standard
+   kernel distribution.
+
+ - The Mitsumi CDROM driver is now part of the standard kernel.  Driver
+   by Martin Harriss with patches by stud11@cc4.kuleuven.ac.be (yes, he
+   probably has a real name, but no, I haven't found it) and Jon Tombs.
+
+ - various other minor patches (preliminary ldt support etc)
+
+NOTABLE changes since patchlevel 10 or earlier:
+
+ - The memory manager has been cleaned up substantially, and mmap()
+   works for MAP_PRIVATE.  MAP_SHARED is still not supported for
+   anything else than /dev/mem, but even so it actually is usable for a
+   lot of applications.  The shared library routines have been rewritten
+   to use mmap() instead of the old hardcoded behaviour.
+
+ - The kernel is now compiled with C++ instead of plain C.  Very few
+   actual C++ features are used, but even so C++ allows for more
+   type-checking and type-safe linkage.
+
+ - The filesystem routines have been cleaned up for multiple block
+   sizes.  None of the filesystems use it yet, but people are working on
+   it.
+
+ - named pipes and normal pipes should hopefully have the right select()
+   semantics in the presense/absense of writers.
+
+ - QIC-02 tape driver by Hennus Bergman
+
+ - selection patches in the default kernel
+
+ - fixed a bug in the pty code which led to busy waiting in some
+   circumstances instead of sleeping.
+
+ - Compressed SLIP support (Charles Hedrick). See net/inet/CONFIG
+
+ - the 'clear_bit()' function was changed to return the previous setting
+   of the bit instead of the old "error-code".  This makes use of the
+   bit operations more logical.
+
+ - udelay() function for short delays (busy-waiting) added.  Used
+   currently only by the QIC driver.
+
+ - fork() and sheduler changes to make task switches happen only from
+   kernel mode to kernel mode.  Cleaner and more portable than the old
+   code which counted on being able to task-switch directly into user
+   mode.
+
+ - debugging malloc code.
diff --git a/Makefile b/Makefile
index e8a3c95..6bdc597 100644
--- a/Makefile
+++ b/Makefile
@@ -50,7 +50,7 @@
 # standard CFLAGS
 #
 
-CFLAGS = -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer -x c++
+CFLAGS = -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer # -x c++
 
 ifdef CONFIG_M486
 CFLAGS := $(CFLAGS) -m486
@@ -111,7 +111,7 @@
 
 tools/version.h: $(CONFIGURE) Makefile
 	@./makever.sh
-	@echo \#define UTS_RELEASE \"0.99.12\" > tools/version.h
+	@echo \#define UTS_RELEASE \"0.99.13\" > tools/version.h
 	@echo \#define UTS_VERSION \"\#`cat .version` `date`\" >> tools/version.h
 	@echo \#define LINUX_COMPILE_TIME \"`date +%T`\" >> tools/version.h
 	@echo \#define LINUX_COMPILE_BY \"`whoami`\" >> tools/version.h
diff --git a/README b/README
index dfd94ed..c5d27ba 100644
--- a/README
+++ b/README
@@ -1,7 +1,13 @@
 
-	Linux kernel release 0.99 patchlevel 12
+	Linux kernel release 0.99 patchlevel 13
 
-These are the release notes for linux version 0.99.12.  Read them
+[ Just to show everybody that I have no personal integrity at all, this
+release is dedicated to Martin Mueller and Sebastian Hetze just because
+they wrote the German Linux Anwenderhandbuch.  The fact that they sent
+me some of the money they made on selling it has nothing at all to do
+with the dedication.  Oh, no.  That would be crass.  ]
+
+These are the release notes for linux version 0.99.13.  Read them
 carefully, as they tell you what's new, explain how to install the
 kernel, and what to do if something goes wrong. 
 
@@ -10,104 +16,14 @@
 kernel, and I have at least one report of trouble with a 2.4.3-built
 kernel that went away when the kernel was recompiled with 2.4.5. 
 
-CHANGES since 0.99 patchlevel 11 and earlier:
-
- - The memory manager cleanup has continued, and seems to be mostly
-   ready, as proven by the ease of adding mmap() over NFS with the new
-   routines.  So yes, the pl12 kernel will demand-load your binaries
-   over NFS, sharing code and clean data, as well as running shared
-   libraries over NFS.  Memory management by Eric and me, while the NFS
-   mmap code was written by Jon Tombs,
-
- - ** IMPORTANT **: The keyboard driver has been enhanced even further,
-   and almost everything is completely re-mappable.  This means that
-   there is a new version of 'loadkeys' and 'dumpkeys' that you must use
-   with this kernel or you'll have problems.  The default keyboard is
-   still the US mapping, but if you want to create your own mappings
-   you'll have to load them with the new binaries.  Get the 'kbd.tar.gz'
-   archive from the same place you get the kernel. 
-
-   The new keymappings allow things like function key string changes,
-   remapping of the control keys, and freedom to remap any of the normal
-   keyboard functions: including special features like rebooting,
-   console switching etc.  The keyboard remapping code has been done
-   mostly by Risto Kankkunen (Risto.Kankkunen@Helsinki.FI). 
-
- - updated network drivers by Donald Becker
-
- - updated serial drivers - tytso@Athena.mit.edu
-
- - updated 387 emulation (Bill Metzenthen).  The updated emulator code
-   has more exact trigonometric functions and improved exception
-   handling.  It now behaves very much like a real 486, with only small
-   changes (greater accuracy, slightly different denormal NaN handling
-   etc - hard to detect the differences even if you are looking for
-   them). 
-
- - network timer fixes by Florian La Roche (much cleaned up net/inet/timer.c
-   and some bad race-conditions fixed).
-
- - Scsi code updates by Eric Youngdale and others
-
- - Sony CDU-31A CDROM driver by Corey Minyard added to the standard
-   kernel distribution. 
-
- - The Mitsumi CDROM driver is now part of the standard kernel.  Driver
-   by Martin Harriss with patches by stud11@cc4.kuleuven.ac.be (yes, he
-   probably has a real name, but no, I haven't found it) and Jon Tombs. 
-
- - various other minor patches (preliminary ldt support etc)
-
-NOTABLE changes since patchlevel 10 or earlier:
-
- - The memory manager has been cleaned up substantially, and mmap()
-   works for MAP_PRIVATE.  MAP_SHARED is still not supported for
-   anything else than /dev/mem, but even so it actually is usable for a
-   lot of applications.  The shared library routines have been rewritten
-   to use mmap() instead of the old hardcoded behaviour. 
-
- - The kernel is now compiled with C++ instead of plain C.  Very few
-   actual C++ features are used, but even so C++ allows for more
-   type-checking and type-safe linkage. 
-
- - The filesystem routines have been cleaned up for multiple block
-   sizes.  None of the filesystems use it yet, but people are working on
-   it. 
-
- - named pipes and normal pipes should hopefully have the right select()
-   semantics in the presense/absense of writers. 
-
- - QIC-02 tape driver by Hennus Bergman
-
- - selection patches in the default kernel
-
- - fixed a bug in the pty code which led to busy waiting in some
-   circumstances instead of sleeping. 
-
- - Compressed SLIP support (Charles Hedrick). See net/inet/CONFIG
-
- - the 'clear_bit()' function was changed to return the previous setting
-   of the bit instead of the old "error-code".  This makes use of the
-   bit operations more logical. 
-
- - udelay() function for short delays (busy-waiting) added.  Used
-   currently only by the QIC driver. 
-
- - fork() and sheduler changes to make task switches happen only from
-   kernel mode to kernel mode.  Cleaner and more portable than the old
-   code which counted on being able to task-switch directly into user
-   mode. 
-
- - debugging malloc code.
-
 INSTALLING the kernel:
 
- - if you install by patching, you need a *clean* 0.99.11 source tree,
+ - if you install by patching, you need a *clean* 0.99.12 source tree,
    which presumably exists in /usr/src/linux.  If so, to get the kernel
    patched, just do a
 
 		cd /usr/src
-		patch -p0 < linux-0.99.patch12
+		patch -p0 < linux-0.99.patch13
 
    and you should be ok.  You may want to remove the backup files (xxx~
    or xxx.orig), and make sure that there are no failed patches (xxx# or
@@ -116,7 +32,7 @@
  - If you install the full sources, do a
 
 		cd /usr/src
-		tar xvf linux-0.99.12.tar
+		tar xvf linux-0.99.13.tar
 
    to get it all put in place.
 
diff --git a/config.in b/config.in
index e122208..87788fa 100644
--- a/config.in
+++ b/config.in
@@ -13,6 +13,10 @@
 bool 'System V IPC' CONFIG_SYSVIPC y
 bool 'Use -m486 flag for 486-specific optimizations' CONFIG_M486 y
 *
+* Program binary formats
+*
+bool 'Elf executables' CONFIG_BINFMT_ELF y
+*
 * SCSI support
 *
 bool 'SCSI support?' CONFIG_SCSI n
@@ -68,7 +72,7 @@
 *
 bool 'Standard (minix) fs support' CONFIG_MINIX_FS y
 bool 'Extended fs support' CONFIG_EXT_FS n
-bool 'Second extended fs support' CONFIG_EXT2_FS n
+bool 'Second extended fs support' CONFIG_EXT2_FS y
 bool 'xiafs filesystem support' CONFIG_XIA_FS n
 bool 'msdos fs support' CONFIG_MSDOS_FS y
 bool '/proc filesystem support' CONFIG_PROC_FS y
@@ -79,8 +83,11 @@
 *
 bool 'Keyboard meta-key sends ESC-prefix' CONFIG_KBD_META y
 bool 'Keyboard Num Lock on by default' CONFIG_KBD_NUML y
-bool 'Logitech busmouse support' CONFIG_BUSMOUSE n
+bool 'Logitech busmouse support' CONFIG_BUSMOUSE y
+bool 'QuickPort mouse support' CONFIG_QUICKPORT_MOUSE y
+if [ "$CONFIG_QUICKPORT_MOUSE" = "n" ]
 bool 'PS/2 mouse (aka "auxiliary device") support' CONFIG_PSMOUSE n
+fi
 bool 'Microsoft busmouse support' CONFIG_MS_BUSMOUSE n
 bool 'ATIXL busmouse support' CONFIG_ATIXL_BUSMOUSE n
 bool 'Selection (cut and paste for virtual consoles)' CONFIG_SELECTION y
diff --git a/fs/Makefile b/fs/Makefile
index 4f3f559..c0b5c62 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -34,6 +34,9 @@
 FS_SUBDIRS := $(FS_SUBDIRS) xiafs
 endif
 
+ifdef CONFIG_BINFMT_ELF
+BINFMTS := $(BINFMTS) binfmt_elf.o
+endif
 
 .c.s:
 	$(CC) $(CFLAGS) -S $<
@@ -44,7 +47,7 @@
 
 OBJS=	open.o read_write.o inode.o devices.o file_table.o buffer.o super.o \
 	block_dev.o stat.o exec.o pipe.o namei.o fcntl.o ioctl.o \
-	select.o fifo.o locks.o filesystems.o
+	select.o fifo.o locks.o filesystems.o $(BINFMTS)
 
 all: fs.o filesystems.a
 
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
new file mode 100644
index 0000000..701cf50
--- /dev/null
+++ b/fs/binfmt_elf.c
@@ -0,0 +1,370 @@
+#include <linux/fs.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/mman.h>
+#include <linux/a.out.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/binfmts.h>
+#include <asm/segment.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/ptrace.h>
+
+asmlinkage int sys_exit(int exit_code);
+asmlinkage int sys_close(unsigned fd);
+asmlinkage int sys_open(const char *, int, int);
+
+/*
+ * These are the functions used to load ELF style executables and shared
+ * libraries.  There is no binary dependent code anywhere else.
+ */
+
+#include <linux/elf.h>
+
+int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
+{
+	struct elfhdr elf_ex;
+	struct file * file;
+  	struct exec ex;
+	struct inode *interpreter_inode;
+	int i;
+	int old_fs;
+	int error;
+	struct elf_phdr * elf_ppnt, *elf_phdata;
+	int elf_exec_fileno;
+	unsigned int elf_bss, k, elf_brk;
+	int retval;
+	char * elf_interpreter;
+	unsigned int elf_entry;
+	int status;
+	unsigned int start_code, end_code, end_data;
+	unsigned int elf_stack;
+	char passed_fileno[6];
+	
+	status = 0;
+	elf_ex = *((struct elfhdr *) bprm->buf);	  /* exec-header */
+	
+	if (elf_ex.e_ident[0] != 0x7f ||
+	    strncmp(&elf_ex.e_ident[1], "ELF",3) != 0)
+		return  -ENOEXEC;
+	
+	
+	/* First of all, some simple consistency checks */
+	if(elf_ex.e_type != ET_EXEC || 
+	   (elf_ex.e_machine != EM_386 && elf_ex.e_machine != EM_486) ||
+	   (!bprm->inode->i_op || !bprm->inode->i_op->default_file_ops ||
+	    !bprm->inode->i_op->default_file_ops->mmap)){
+		return -ENOEXEC;
+	};
+	
+	/* Now read in all of the header information */
+	
+	elf_phdata = (struct elf_phdr *) kmalloc(elf_ex.e_phentsize * 
+						 elf_ex.e_phnum, GFP_KERNEL);
+	
+	old_fs = get_fs();
+	set_fs(get_ds());
+	retval = read_exec(bprm->inode, elf_ex.e_phoff, (char *) elf_phdata,
+			   elf_ex.e_phentsize * elf_ex.e_phnum);
+	set_fs(old_fs);
+	if (retval < 0) {
+	        kfree (elf_phdata);
+		return retval;
+	}
+	
+	elf_ppnt = elf_phdata;
+	
+	elf_bss = 0;
+	elf_brk = 0;
+	
+	elf_exec_fileno = open_inode(bprm->inode, O_RDONLY);
+
+	if (elf_exec_fileno < 0) {
+	        kfree (elf_phdata);
+		return elf_exec_fileno;
+	}
+	
+	file = current->filp[elf_exec_fileno];
+	
+	elf_stack = 0xffffffff;
+	elf_interpreter = NULL;
+	start_code = 0;
+	end_code = 0;
+	end_data = 0;
+	
+	old_fs = get_fs();
+	set_fs(get_ds());
+	
+	for(i=0;i < elf_ex.e_phnum; i++){
+		if(elf_ppnt->p_type == PT_INTERP) {
+			/* This is the program interpreter used for shared libraries - 
+			   for now assume that this is an a.out format binary */
+			
+			elf_interpreter = (char *) kmalloc(elf_ppnt->p_filesz, 
+							   GFP_KERNEL);
+			
+			retval = read_exec(bprm->inode,elf_ppnt->p_offset,elf_interpreter,
+					   elf_ppnt->p_filesz);
+			printk("Using ELF interpreter %s\n", elf_interpreter);
+			if(retval >= 0)
+				retval = namei(elf_interpreter, &interpreter_inode);
+			if(retval >= 0)
+				retval = read_exec(interpreter_inode,0,bprm->buf,128);
+			
+			if(retval >= 0){
+				ex = *((struct exec *) bprm->buf);		/* exec-header */
+				
+#if 0
+				printk("Interpreter: %x %x %x\n",N_MAGIC(ex), ex.a_text,ex.a_data);
+#endif
+			};
+		};
+		elf_ppnt++;
+	};
+	
+	set_fs(old_fs);
+	
+	/* Some simple consistency checks for the interpreter */
+	if(elf_interpreter){
+		if(retval < 0) {
+			kfree(elf_interpreter);
+			kfree(elf_phdata);
+			return -ELIBACC;
+		};
+		if((N_MAGIC(ex) != OMAGIC) && (N_MAGIC(ex) != ZMAGIC)) {
+			kfree(elf_interpreter);
+			kfree(elf_phdata);
+			return -ELIBBAD;
+		};
+	}
+	
+	/* OK, we are done with that, now set up the arg stuff,
+	   and then start this sucker up */
+	
+	if (!bprm->sh_bang) {
+		char * passed_p;
+		
+		sprintf(passed_fileno, "%d", elf_exec_fileno);
+		passed_p = passed_fileno;
+		
+		if(elf_interpreter) {
+			bprm->p = copy_strings(1,&passed_p,bprm->page,bprm->p,2);
+			bprm->argc++;
+		};
+		if (!bprm->p) {
+		        if(elf_interpreter) {
+			      kfree(elf_interpreter);
+			}
+		        kfree (elf_phdata);
+			return -E2BIG;
+		}
+	}
+	
+	/* OK, This is the point of no return */
+	flush_old_exec(bprm);
+
+	current->end_data = 0;
+	current->end_code = 0;
+	current->start_mmap = ELF_START_MMAP;
+	current->mmap = NULL;
+	elf_entry = (unsigned int) elf_ex.e_entry;
+	
+	/* Do this so that we can load the interpreter, if need be.  We will
+	   change some of these later */
+	current->rss = 0;
+	bprm->p += change_ldt(0, bprm->page);
+	current->start_stack = bprm->p;
+	
+	/* Now we do a little grungy work by mmaping the ELF image into
+	   the correct location in memory.  At this point, we assume that
+	   the image should be loaded at fixed address, not at a variable
+	   address. */
+	
+	old_fs = get_fs();
+	set_fs(get_ds());
+	
+	elf_ppnt = elf_phdata;
+	for(i=0;i < elf_ex.e_phnum; i++){
+		
+		if(elf_ppnt->p_type == PT_INTERP) {
+			/* Set these up so that we are able to load the interpreter */
+			current->brk = ex.a_bss +
+				(current->end_data = ex.a_data +
+				 (current->end_code = ex.a_text));
+			elf_entry = ex.a_entry;
+			
+			/* Now load the interpreter into user address space */
+			set_fs(old_fs);
+			
+			if (N_MAGIC(ex) == OMAGIC) {
+				retval = read_exec(interpreter_inode, 32, (char *) 0, 
+						   ex.a_text+ex.a_data);
+				iput(interpreter_inode);
+			} else if (N_MAGIC(ex) == ZMAGIC || N_MAGIC(ex) == QMAGIC) {
+				retval = read_exec(interpreter_inode,
+						   N_TXTOFF(ex) ,
+						   (char *) N_TXTADDR(ex),
+						   ex.a_text+ex.a_data);
+				iput(interpreter_inode);
+			} else
+				retval = -1;
+			
+			old_fs = get_fs();
+			set_fs(get_ds());
+			
+			if(retval >= 0)
+				zeromap_page_range((ex.a_text + ex.a_data + 0xfff) & 
+						   0xfffff000, ex.a_bss, PAGE_COPY);
+			kfree(elf_interpreter);
+			
+			if(retval < 0) { 
+				kfree(elf_phdata);
+				send_sig(SIGSEGV, current, 0);
+				return 0;
+			};
+		};
+		
+		
+		if(elf_ppnt->p_type == PT_LOAD) {
+			error = do_mmap(file,
+					elf_ppnt->p_vaddr & 0xfffff000,
+					elf_ppnt->p_filesz + (elf_ppnt->p_vaddr & 0xfff),
+					PROT_READ | PROT_WRITE | PROT_EXEC,
+					MAP_FIXED | MAP_PRIVATE,
+					elf_ppnt->p_offset & 0xfffff000);
+			
+#ifdef LOW_ELF_STACK
+			if(elf_ppnt->p_vaddr & 0xfffff000 < elf_stack) 
+				elf_stack = elf_ppnt->p_vaddr & 0xfffff000;
+#endif
+			
+			k = elf_ppnt->p_vaddr;
+			if(k > start_code) start_code = k;
+			k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz;
+			if(k > elf_bss) elf_bss = k;
+			if((elf_ppnt->p_flags | PROT_WRITE) && end_code <  k)
+				end_code = k; 
+			if(end_data < k) end_data = k; 
+			k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz;
+			if(k > elf_brk) elf_brk = k;		     
+			
+			if(status == 0xffffffff) {
+				set_fs(old_fs);
+				kfree(elf_phdata);
+				send_sig(SIGSEGV, current, 0);
+				return 0;
+			};
+		};
+		elf_ppnt++;
+	};
+	set_fs(old_fs);
+	
+	kfree(elf_phdata);
+	
+	if(!elf_interpreter) sys_close(elf_exec_fileno);
+	current->elf_executable = 1;
+	current->executable = bprm->inode;
+	bprm->inode->i_count++;
+#ifdef LOW_ELF_STACK
+	current->start_stack = p = elf_stack - 4;
+#endif
+	bprm->p -= MAX_ARG_PAGES*PAGE_SIZE;
+	bprm->p = (unsigned long) create_tables((char *)bprm->p,bprm->argc,bprm->envc);
+	if(elf_interpreter) current->arg_start += strlen(passed_fileno) + 1;
+	current->start_brk = current->brk = elf_brk;
+	current->end_code = end_code;
+	current->start_code = start_code;
+	current->start_stack = bprm->p;
+	current->suid = current->euid = bprm->e_uid;
+	current->sgid = current->egid = bprm->e_gid;
+	zeromap_page_range((elf_bss + 0xfff) & 0xfffff000, elf_brk - elf_bss,
+			   PAGE_COPY);
+	regs->eip = elf_entry;		/* eip, magic happens :-) */
+	regs->esp = bprm->p;			/* stack pointer */
+	if (current->flags & PF_PTRACED)
+		send_sig(SIGTRAP, current, 0);
+	
+	return 0;
+}
+
+
+int load_elf_library(int fd){
+        struct file * file;
+	struct elfhdr elf_ex;
+	struct elf_phdr *elf_phdata  =  NULL;
+	struct  inode * inode;
+	unsigned int len;
+	int old_fs, retval;
+	unsigned int bss;
+	int error;
+	int i,j;
+	
+	len = 0;
+	file = current->filp[fd];
+	inode = file->f_inode;
+	
+	set_fs(KERNEL_DS);
+	if (file->f_op->read(inode, file, (char *) &elf_ex, sizeof(elf_ex)) != sizeof(elf_ex)) {
+		sys_close(fd);
+		return -EACCES;
+	}
+	set_fs(USER_DS);
+	
+	if (elf_ex.e_ident[0] != 0x7f ||
+	    strncmp(&elf_ex.e_ident[1], "ELF",3) != 0)
+		return -ENOEXEC;
+	
+	/* First of all, some simple consistency checks */
+	if(elf_ex.e_type != ET_EXEC || elf_ex.e_phnum > 2 ||
+	   (elf_ex.e_machine != EM_386 && elf_ex.e_machine != EM_486) ||
+	   (!inode->i_op || !inode->i_op->bmap || 
+	    !inode->i_op->default_file_ops->mmap)){
+		return -ENOEXEC;
+	};
+	
+	/* Now read in all of the header information */
+	
+	if(sizeof(struct elf_phdr) * elf_ex.e_phnum > PAGE_SIZE) 
+		return -ENOEXEC;
+	
+	elf_phdata =  (struct elf_phdr *) 
+		kmalloc(sizeof(struct elf_phdr) * elf_ex.e_phnum, GFP_KERNEL);
+	
+	old_fs = get_fs();
+	set_fs(get_ds());
+	retval = read_exec(inode, elf_ex.e_phoff, (char *) elf_phdata,
+			   sizeof(struct elf_phdr) * elf_ex.e_phnum);
+	set_fs(old_fs);
+	
+	j = 0;
+	for(i=0; i<elf_ex.e_phnum; i++)
+		if((elf_phdata + i)->p_type == PT_LOAD) j++;
+	
+	if(j != 1)  {
+		kfree(elf_phdata);
+		return -ENOEXEC;
+	};
+	
+	while(elf_phdata->p_type != PT_LOAD) elf_phdata++;
+	
+	/* Now use mmap to map the library into memory. */
+	error = do_mmap(file,
+			elf_phdata->p_vaddr & 0xfffff000,
+			elf_phdata->p_filesz + (elf_phdata->p_vaddr & 0xfff),
+			PROT_READ | PROT_WRITE | PROT_EXEC,
+			MAP_FIXED | MAP_PRIVATE,
+			elf_phdata->p_offset & 0xfffff000);
+	
+	sys_close(fd);
+	if (error != elf_phdata->p_vaddr & 0xfffff000) {
+	        kfree(elf_phdata);
+		return error;
+	}
+	len = (elf_phdata->p_filesz + elf_phdata->p_vaddr+ 0xfff) & 0xfffff000;
+	bss = elf_phdata->p_memsz + elf_phdata->p_vaddr;
+	if (bss > len)
+		zeromap_page_range(len, bss-len, PAGE_COPY);
+	kfree(elf_phdata);
+	return 0;
+}
diff --git a/fs/block_dev.c b/fs/block_dev.c
index 4fdf3a8..76bc169 100644
--- a/fs/block_dev.c
+++ b/fs/block_dev.c
@@ -168,6 +168,9 @@
 			if (*bhe) {
 				wait_on_buffer(*bhe);
 				if (!(*bhe)->b_uptodate) {	/* read error? */
+				        brelse(*bhe);
+					if (++bhe == &buflist[NBUF])
+					  bhe = buflist;
 					left = 0;
 					break;
 				}
diff --git a/fs/buffer.c b/fs/buffer.c
index dc767ac..8773875 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -160,7 +160,7 @@
 	return sync_buffers(dev, 1);
 }
 
-extern "C" int sys_sync(void)
+asmlinkage int sys_sync(void)
 {
 	sync_dev(0);
 	return 0;
@@ -171,7 +171,7 @@
 	return fsync_dev(inode->i_dev);
 }
 
-extern "C" int sys_fsync(unsigned int fd)
+asmlinkage int sys_fsync(unsigned int fd)
 {
 	struct file * file;
 	struct inode * inode;
diff --git a/fs/exec.c b/fs/exec.c
index 10c63e7..1f41a03 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -44,13 +44,13 @@
 #include <asm/segment.h>
 #include <asm/system.h>
 
-extern "C" int sys_exit(int exit_code);
-extern "C" int sys_close(unsigned fd);
-extern "C" int sys_open(const char *, int, int);
+asmlinkage int sys_exit(int exit_code);
+asmlinkage int sys_close(unsigned fd);
+asmlinkage int sys_open(const char *, int, int);
 
 extern void shm_exit (void);
 
-static int open_inode(struct inode * inode, int mode)
+int open_inode(struct inode * inode, int mode)
 {
 	int error, fd;
 	struct file *f, **fpp;
@@ -116,6 +116,7 @@
 	struct file file;
 	unsigned short fs;
 	int has_dumped = 0;
+	char corefile[6+sizeof(current->comm)];
 	register int dump_start, dump_size;
 	struct user dump;
 
@@ -128,7 +129,9 @@
 		return 0;
 	fs = get_fs();
 	set_fs(KERNEL_DS);
-	if (open_namei("core",O_CREAT | 2 | O_TRUNC,0600,&inode,NULL)) {
+	memcpy(corefile,"core.",5);
+	memcpy(corefile+5,current->comm,sizeof(current->comm));
+	if (open_namei(corefile,O_CREAT | 2 | O_TRUNC,0600,&inode,NULL)) {
 		inode = NULL;
 		goto end_coredump;
 	}
@@ -225,7 +228,7 @@
  *
  * Also note that we take the address to load from from the file itself.
  */
-extern "C" int sys_uselib(const char * library)
+asmlinkage int sys_uselib(const char * library)
 {
 	int fd, retval;
 	struct file * file;
@@ -316,7 +319,7 @@
  * it is expensive to load a segment register, we try to avoid calling
  * set_fs() unless we absolutely have to.
  */
-static unsigned long copy_strings(int argc,char ** argv,unsigned long *page,
+unsigned long copy_strings(int argc,char ** argv,unsigned long *page,
 		unsigned long p, int from_kmem)
 {
 	char *tmp, *pag = NULL;
@@ -459,7 +462,7 @@
 	current->mmap = NULL;
 	while (mpnt) {
 		mpnt1 = mpnt->vm_next;
-		if (mpnt->vm_ops->close)
+		if (mpnt->vm_ops && mpnt->vm_ops->close)
 			mpnt->vm_ops->close(mpnt);
 		kfree(mpnt);
 		mpnt = mpnt1;
@@ -649,6 +652,7 @@
 		}
 	}
 
+	bprm.sh_bang = sh_bang;
 	fmt = formats;
 	do {
 		int (*fn)(struct linux_binprm *, struct pt_regs *) = fmt->load_binary;
@@ -672,7 +676,7 @@
 /*
  * sys_execve() executes a new program.
  */
-extern "C" int sys_execve(struct pt_regs regs)
+asmlinkage int sys_execve(struct pt_regs regs)
 {
 	int error;
 	char * filename;
@@ -694,9 +698,16 @@
 			    struct pt_regs * regs);
 extern int load_aout_library(int fd);
 
+extern int load_elf_binary(struct linux_binprm *,
+			    struct pt_regs * regs);
+extern int load_elf_library(int fd);
+
 /* Here are the actual binaries that will be accepted  */
 struct linux_binfmt formats[] = {
 	{load_aout_binary, load_aout_library},
+#ifdef CONFIG_BINFMT_ELF
+	{load_elf_binary, load_elf_library},
+#endif
 	{NULL, NULL}
 };
 
@@ -713,17 +724,20 @@
 	unsigned long p = bprm->p;
 
 	ex = *((struct exec *) bprm->buf);		/* exec-header */
-	if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != OMAGIC) ||
+	if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != OMAGIC && 
+	     N_MAGIC(ex) != QMAGIC) ||
 	    ex.a_trsize || ex.a_drsize ||
 	    bprm->inode->i_size < ex.a_text+ex.a_data+ex.a_syms+N_TXTOFF(ex)) {
 		return -ENOEXEC;
 	}
-	if (N_MAGIC(ex) == ZMAGIC && N_TXTOFF(ex) &&
+
+	if (N_MAGIC(ex) == ZMAGIC &&
 	    (N_TXTOFF(ex) < bprm->inode->i_sb->s_blocksize)) {
 		printk("N_TXTOFF < BLOCK_SIZE. Please convert binary.");
 		return -ENOEXEC;
 	}
-	if (N_TXTOFF(ex) != BLOCK_SIZE && N_MAGIC(ex) != OMAGIC) {
+
+	if (N_TXTOFF(ex) != BLOCK_SIZE && N_MAGIC(ex) == ZMAGIC) {
 		printk("N_TXTOFF != BLOCK_SIZE. See a.out.h.");
 		return -ENOEXEC;
 	}
@@ -732,7 +746,10 @@
 	flush_old_exec(bprm);
 	current->start_brk = current->brk = ex.a_bss +
 		(current->end_data = ex.a_data +
-		 (current->end_code = ex.a_text));
+		 (current->end_code = N_TXTADDR(ex) + ex.a_text));
+
+	current->start_code += N_TXTADDR(ex);
+
 	current->rss = 0;
 	current->suid = current->euid = bprm->e_uid;
 	current->mmap = NULL;
@@ -751,23 +768,25 @@
 		file = current->filp[fd];
 		if (!file->f_op || !file->f_op->mmap) {
 			sys_close(fd);
-			read_exec(bprm->inode, 1024, (char *) 0, ex.a_text+ex.a_data);
+			read_exec(bprm->inode, N_TXTOFF(ex), 
+				  (char *) N_TXTADDR(ex), ex.a_text+ex.a_data);
 			goto beyond_if;
 		}
-		error = do_mmap(file, 0, ex.a_text,
+		error = do_mmap(file, N_TXTADDR(ex), ex.a_text,
 				PROT_READ | PROT_EXEC,
 				MAP_FIXED | MAP_SHARED, N_TXTOFF(ex));
-		if (error != 0) {
+
+		if (error != N_TXTADDR(ex)) {
 			sys_close(fd);
 			send_sig(SIGSEGV, current, 0);
 			return 0;
 		};
 		
-		error = do_mmap(file, ex.a_text, ex.a_data,
+ 		error = do_mmap(file, N_TXTADDR(ex) + ex.a_text, ex.a_data,
 				PROT_READ | PROT_WRITE | PROT_EXEC,
 				MAP_FIXED | MAP_PRIVATE, N_TXTOFF(ex) + ex.a_text);
 		sys_close(fd);
-		if (error != ex.a_text) {
+		if (error != N_TXTADDR(ex) + ex.a_text) {
 			send_sig(SIGSEGV, current, 0);
 			return 0;
 		};
@@ -775,7 +794,7 @@
 		bprm->inode->i_count++;
 	}
 beyond_if:
-	zeromap_page_range((ex.a_text + ex.a_data + 0xfff) & 0xfffff000,ex.a_bss, PAGE_COPY);
+	zeromap_page_range((N_TXTADDR(ex) + ex.a_text + ex.a_data + 0xfff) & 0xfffff000,ex.a_bss, PAGE_COPY);
 	p += change_ldt(ex.a_text,bprm->page);
 	p -= MAX_ARG_PAGES*PAGE_SIZE;
 	p = (unsigned long) create_tables((char *)p,bprm->argc,bprm->envc);
@@ -795,6 +814,7 @@
 	struct  inode * inode;
 	unsigned int len;
 	unsigned int bss;
+	unsigned int start_addr;
 	int error;
 	
 	file = current->filp[fd];
@@ -807,8 +827,8 @@
 	set_fs(USER_DS);
 	
 	/* We come in here for the regular a.out style of shared libraries */
-	if (N_MAGIC(ex) != ZMAGIC || ex.a_trsize ||
-	    ex.a_drsize || ex.a_entry & 0xfff ||
+	if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != QMAGIC) || ex.a_trsize ||
+	    ex.a_drsize || ((ex.a_entry & 0xfff) && N_MAGIC(ex) == ZMAGIC) ||
 	    inode->i_size < ex.a_text+ex.a_data+ex.a_syms+N_TXTOFF(ex)) {
 		return -ENOEXEC;
 	}
@@ -818,15 +838,22 @@
 		return -ENOEXEC;
 	}
 	
+	if (N_FLAGS(ex)) return -ENOEXEC;
+
+	/* For  QMAGIC, the starting address is 0x20 into the page.  We mask
+	   this off to get the starting address for the page */
+
+	start_addr =  ex.a_entry & 0xfffff000;
+
 	/* Now use mmap to map the library into memory. */
-	error = do_mmap(file, ex.a_entry, ex.a_text + ex.a_data,
+	error = do_mmap(file, start_addr, ex.a_text + ex.a_data,
 			PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_PRIVATE,
 			N_TXTOFF(ex));
-	if (error != ex.a_entry)
+	if (error != start_addr)
 		return error;
 	len = (ex.a_text + ex.a_data + 0xfff) & 0xfffff000;
 	bss = ex.a_text + ex.a_data + ex.a_bss;
 	if (bss > len)
-		zeromap_page_range(ex.a_entry + len, bss-len, PAGE_COPY);
+		zeromap_page_range(start_addr + len, bss-len, PAGE_COPY);
 	return 0;
 }
diff --git a/fs/ext/file.c b/fs/ext/file.c
index e378a05..75b6bd1 100644
--- a/fs/ext/file.c
+++ b/fs/ext/file.c
@@ -149,6 +149,9 @@
 			if (*bhe) {
 				wait_on_buffer(*bhe);
 				if (!(*bhe)->b_uptodate) {	/* read error? */
+				        brelse(*bhe);
+					if (++bhe == &buflist[NBUF])
+					  bhe = buflist;
 					left = 0;
 					break;
 				}
diff --git a/fs/ext/namei.c b/fs/ext/namei.c
index be27571..f0add8c 100644
--- a/fs/ext/namei.c
+++ b/fs/ext/namei.c
@@ -776,7 +776,7 @@
 	retval = -ENOENT;
 	if (!old_bh)
 		goto end_rename;
-	old_inode = iget(old_dir->i_sb, old_de->inode);
+	old_inode = __iget(old_dir->i_sb, old_de->inode,0); /* don't cross mnt-points */
 	if (!old_inode)
 		goto end_rename;
 	retval = -EPERM;
@@ -786,7 +786,7 @@
 		goto end_rename;
 	new_bh = ext_find_entry(new_dir,new_name,new_len,&new_de,NULL,NULL);
 	if (new_bh) {
-		new_inode = iget(new_dir->i_sb, new_de->inode);
+		new_inode = __iget(new_dir->i_sb, new_de->inode,0); /* don't cross mnt-points */
 		if (!new_inode) {
 			brelse(new_bh);
 			new_bh = NULL;
diff --git a/fs/ext2/file.c b/fs/ext2/file.c
index ee7b273..e48448c 100644
--- a/fs/ext2/file.c
+++ b/fs/ext2/file.c
@@ -155,6 +155,9 @@
 			if (*bhe) {
 				wait_on_buffer (*bhe);
 				if (!(*bhe)->b_uptodate) { /* read error? */
+				        brelse(*bhe);
+					if (++bhe == &buflist[NBUF])
+					  bhe = buflist;
 					left = 0;
 					break;
 				}
diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c
index 78006de..65f666f 100644
--- a/fs/ext2/inode.c
+++ b/fs/ext2/inode.c
@@ -351,7 +351,10 @@
 #ifdef EXT2FS_DEBUG
 		printk ("ext2_write_super: setting valid to 0\n");
 #endif
-		es->s_valid = 0;
+		if (es->s_valid) {
+			es->s_valid = 0;
+			es->s_mtime = CURRENT_TIME;
+		}
 		ext2_commit_super (sb, es);
 	}
 	sb->s_dirt = 0;
@@ -370,8 +373,10 @@
 		/* OK, we are remounting a valid rw partition rdonly, so set
 		   the rdonly flag and then mark the partition as valid
 		   again. */
-		sb->s_flags |= MS_RDONLY;
 		es->s_valid = sb->u.ext2_sb.s_was_mounted_valid;
+		es->s_mtime = CURRENT_TIME;
+		sb->u.ext2_sb.s_sbh->b_dirt = 1;
+		sb->s_dirt = 1;
 		ext2_commit_super (sb, es);
 	}
 	else {
@@ -382,6 +387,12 @@
 		if (!es->s_valid)
 			printk ("EXT2-fs warning: remounting unchecked fs, "
 				"running e2fsck is recommended\n");
+		else {
+			es->s_valid = 0;
+			es->s_mtime = CURRENT_TIME;
+			sb->u.ext2_sb.s_sbh->b_dirt = 1;
+			sb->s_dirt = 1;
+		}
 	}
 	return 0;
 }
diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c
index 49e06cc..cd0d05e 100644
--- a/fs/ext2/namei.c
+++ b/fs/ext2/namei.c
@@ -549,6 +549,8 @@
 	retval = -EPERM;
 	if (!(inode = iget (dir->i_sb, de->inode)))
 		goto end_rmdir;
+	if (inode->i_dev != dir->i_dev)
+		goto end_rmdir;
 	if (de->inode != inode->i_ino) {
 		iput(inode);
 		brelse(bh);
@@ -559,8 +561,6 @@
 	if ((dir->i_mode & S_ISVTX) && current->euid &&
 	    inode->i_uid != current->euid)
 		goto end_rmdir;
-	if (inode->i_dev != dir->i_dev)
-		goto end_rmdir;
 	if (inode == dir)	/* we may not delete ".", but "../dir" is ok */
 		goto end_rmdir;
 	if (!S_ISDIR(inode->i_mode)) {
@@ -620,6 +620,9 @@
 		goto end_unlink;
 	if (!(inode = iget (dir->i_sb, de->inode)))
 		goto end_unlink;
+	retval = -EPERM;
+	if (S_ISDIR(inode->i_mode))
+		goto end_unlink;
 	if (de->inode != inode->i_ino) {
 		iput(inode);
 		brelse(bh);
@@ -627,13 +630,10 @@
 		schedule();
 		goto repeat;
 	}
-	retval = -EPERM;
 	if ((dir->i_mode & S_ISVTX) && !suser() &&
 	    current->euid != inode->i_uid &&
 	    current->euid != dir->i_uid)
 		goto end_unlink;
-	if (S_ISDIR(inode->i_mode))
-		goto end_unlink;
 	if (!inode->i_nlink) {
 		printk ("Deleting nonexistent file (%04x:%d), %d\n",
 			inode->i_dev, inode->i_ino, inode->i_nlink);
@@ -853,7 +853,7 @@
 	retval = -ENOENT;
 	if (!old_bh)
 		goto end_rename;
-	old_inode = iget (old_dir->i_sb, old_de->inode);
+	old_inode = __iget (old_dir->i_sb, old_de->inode, 0); /* don't cross mnt-points */
 	if (!old_inode)
 		goto end_rename;
 	retval = -EPERM;
@@ -863,7 +863,7 @@
 		goto end_rename;
 	new_bh = ext2_find_entry (new_dir, new_name, new_len, &new_de);
 	if (new_bh) {
-		new_inode = iget (new_dir->i_sb, new_de->inode);
+		new_inode = __iget (new_dir->i_sb, new_de->inode, 0); /* no mntp cross */
 		if (!new_inode) {
 			brelse (new_bh);
 			new_bh = NULL;
@@ -937,6 +937,8 @@
 		new_inode->i_nlink--;
 		new_inode->i_dirt = 1;
 	}
+	old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
+	old_dir->i_dirt = 1;
 	old_bh->b_dirt = 1;
 	new_bh->b_dirt = 1;
 	if (dir_bh) {
diff --git a/fs/fcntl.c b/fs/fcntl.c
index effbd48..5a7fe10 100644
--- a/fs/fcntl.c
+++ b/fs/fcntl.c
@@ -35,7 +35,7 @@
 	return arg;
 }
 
-extern "C" int sys_dup2(unsigned int oldfd, unsigned int newfd)
+asmlinkage int sys_dup2(unsigned int oldfd, unsigned int newfd)
 {
 	if (oldfd >= NR_OPEN || !current->filp[oldfd])
 		return -EBADF;
@@ -58,12 +58,12 @@
 	return dupfd(oldfd,newfd);
 }
 
-extern "C" int sys_dup(unsigned int fildes)
+asmlinkage int sys_dup(unsigned int fildes)
 {
 	return dupfd(fildes,0);
 }
 
-extern "C" int sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg)
+asmlinkage int sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg)
 {	
 	struct file * filp;
 
diff --git a/fs/inode.c b/fs/inode.c
index fcd1825..828bb41 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -87,7 +87,7 @@
 	struct inode * inode;
 	int i;
 
-	if(!(inode = (struct inode*) get_free_page(GFP_KERNEL)))
+	if (!(inode = (struct inode*) get_free_page(GFP_KERNEL)))
 		return;
 
 	i=PAGE_SIZE / sizeof(struct inode);
@@ -417,6 +417,11 @@
 
 struct inode * iget(struct super_block * sb,int nr)
 {
+	return __iget(sb,nr,1);
+}
+
+struct inode * __iget(struct super_block * sb, int nr, int crossmntp)
+{
 	struct inode * inode, * empty;
 
 	if (!sb)
@@ -435,7 +440,7 @@
 		if (!inode->i_count)
 			nr_free_inodes--;
 		inode->i_count++;
-		if (inode->i_mount) {
+		if (crossmntp && inode->i_mount) {
 			int i;
 
 			for (i = 0 ; i<NR_SUPER ; i++)
diff --git a/fs/ioctl.c b/fs/ioctl.c
index c54c453..515203f 100644
--- a/fs/ioctl.c
+++ b/fs/ioctl.c
@@ -54,7 +54,7 @@
 }
 
 
-extern "C" int sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
+asmlinkage int sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
 {	
 	struct file * filp;
 	int on;
diff --git a/fs/isofs/file.c b/fs/isofs/file.c
index c20aef2..5fdb3e7 100644
--- a/fs/isofs/file.c
+++ b/fs/isofs/file.c
@@ -216,6 +216,9 @@
 		  if (*bhe) {/* test for valid buffer */
 		    wait_on_buffer(*bhe);
 		    if (!(*bhe)->b_uptodate) {
+		      brelse(*bhe);
+		      if (++bhe == &buflist[NBUF])
+			bhe = buflist;
 		      left = 0;
 		      break;
 		    }
diff --git a/fs/locks.c b/fs/locks.c
index 3a5e4b6..aae91cc 100644
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -22,11 +22,13 @@
 
 #define OFFSET_MAX	((off_t)0x7fffffff)	/* FIXME: move elsewhere? */
 
-static int copy_flock(struct file *filp, struct file_lock *fl, struct flock *l);
+static int copy_flock(struct file *filp, struct file_lock *fl, struct flock *l,
+                      unsigned int fd);
 static int conflict(struct file_lock *caller_fl, struct file_lock *sys_fl);
 static int overlap(struct file_lock *fl1, struct file_lock *fl2);
-static int lock_it(struct file *filp, struct file_lock *caller);
-static struct file_lock *alloc_lock(struct file_lock **pos, struct file_lock *fl);
+static int lock_it(struct file *filp, struct file_lock *caller, unsigned int fd);
+static struct file_lock *alloc_lock(struct file_lock **pos, struct file_lock *fl,
+                                    unsigned int fd);
 static void free_lock(struct file_lock **fl);
 
 static struct file_lock file_lock_table[NR_FILE_LOCKS];
@@ -64,7 +66,7 @@
 	memcpy_fromfs(&flock, l, sizeof(flock));
 	if (flock.l_type == F_UNLCK)
 		return -EINVAL;
-	if (!copy_flock(filp, &file_lock, &flock))
+	if (!copy_flock(filp, &file_lock, &flock, fd))
 		return -EINVAL;
 
 	for (fl = filp->f_inode->i_flock; fl != NULL; fl = fl->fl_next) {
@@ -106,7 +108,7 @@
 	if (error)
 		return error;
 	memcpy_fromfs(&flock, l, sizeof(flock));
-	if (!copy_flock(filp, &file_lock, &flock))
+	if (!copy_flock(filp, &file_lock, &flock, fd))
 		return -EINVAL;
 	switch (file_lock.fl_type) {
 	case F_RDLCK :
@@ -161,14 +163,15 @@
 	 * Lock doesn't conflict with any other lock ...
 	 */
 
-	return lock_it(filp, &file_lock);
+	return lock_it(filp, &file_lock, fd);
 }
 
 /*
  * This function is called when the file is closed.
  */
 
-void fcntl_remove_locks(struct task_struct *task, struct file *filp)
+void fcntl_remove_locks(struct task_struct *task, struct file *filp,
+                        unsigned int fd)
 {
 	struct file_lock *fl;
 	struct file_lock **before;
@@ -176,12 +179,12 @@
 	/* Find first lock owned by caller ... */
 
 	before = &filp->f_inode->i_flock;
-	while ((fl = *before) && task != fl->fl_owner)
+	while ((fl = *before) && task != fl->fl_owner && fd != fl->fl_fd)
 		before = &fl->fl_next;
 
-	/* The list is sorted by owner ... */
+	/* The list is sorted by owner and fd ... */
 
-	while ((fl = *before) && task == fl->fl_owner)
+	while ((fl = *before) && task == fl->fl_owner && fd == fl->fl_fd)
 		free_lock(before);
 }
 
@@ -190,7 +193,8 @@
  * Result is a boolean indicating success.
  */
 
-static int copy_flock(struct file *filp, struct file_lock *fl, struct flock *l)
+static int copy_flock(struct file *filp, struct file_lock *fl, struct flock *l,
+                      unsigned int fd)
 {
 	off_t start;
 
@@ -215,6 +219,7 @@
 	if (l->l_len == 0 || (fl->fl_end = start + l->l_len - 1) < 0)
 		fl->fl_end = OFFSET_MAX;
 	fl->fl_owner = current;
+	fl->fl_fd = fd;
 	fl->fl_wait = NULL;		/* just for cleanliness */
 	return 1;
 }
@@ -225,7 +230,8 @@
 
 static int conflict(struct file_lock *caller_fl, struct file_lock *sys_fl)
 {
-	if (caller_fl->fl_owner == sys_fl->fl_owner)
+	if (   caller_fl->fl_owner == sys_fl->fl_owner
+            && caller_fl->fl_fd == sys_fl->fl_fd)
 		return 0;
 	if (!overlap(caller_fl, sys_fl))
 		return 0;
@@ -263,7 +269,7 @@
  * To all purists: Yes, I use a few goto's. Just pass on to the next function.
  */
 
-static int lock_it(struct file *filp, struct file_lock *caller)
+static int lock_it(struct file *filp, struct file_lock *caller, unsigned int fd)
 {
 	struct file_lock *fl;
 	struct file_lock *left = 0;
@@ -276,14 +282,18 @@
 	 */
 
 	before = &filp->f_inode->i_flock;
-	while ((fl = *before) && caller->fl_owner != fl->fl_owner)
+	while (   (fl = *before)
+               && caller->fl_owner != fl->fl_owner
+               && caller->fl_fd != fl->fl_fd)
 		before = &fl->fl_next;
 
 	/*
 	 * Look up all locks of this owner.
 	 */
 
-	while ((fl = *before) && caller->fl_owner == fl->fl_owner) {
+	while (   (fl = *before)
+               && caller->fl_owner == fl->fl_owner
+               && caller->fl_fd == fl->fl_fd) {
 		/*
 		 * Detect adjacent or overlapping regions (if same lock type)
 		 */
@@ -370,7 +380,7 @@
 	if (! added) {
 		if (caller->fl_type == F_UNLCK)
 			return -EINVAL;
-		if (! (caller = alloc_lock(before, caller)))
+		if (! (caller = alloc_lock(before, caller, fd)))
 			return -ENOLCK;
 	}
 	if (right) {
@@ -380,7 +390,7 @@
 			 * have to allocate one more lock (in this case, even
 			 * F_UNLCK may fail!).
 			 */
-			if (! (left = alloc_lock(before, right))) {
+			if (! (left = alloc_lock(before, right, fd))) {
 				if (! added)
 					free_lock(before);
 				return -ENOLCK;
@@ -398,7 +408,8 @@
  */
 
 static struct file_lock *alloc_lock(struct file_lock **pos,
-				    struct file_lock *fl)
+				    struct file_lock *fl,
+                                    unsigned int     fd)
 {
 	struct file_lock *tmp;
 
@@ -417,6 +428,7 @@
 	*pos = tmp;
 
 	tmp->fl_owner = current;	/* FIXME: needed? */
+	tmp->fl_fd = fd;		/* FIXME: needed? */
 	tmp->fl_wait = NULL;
 	return tmp;
 }
diff --git a/fs/minix/file.c b/fs/minix/file.c
index e8191c1..ebcba50 100644
--- a/fs/minix/file.c
+++ b/fs/minix/file.c
@@ -143,6 +143,9 @@
 			if (*bhe) {
 				wait_on_buffer(*bhe);
 				if (!(*bhe)->b_uptodate) {	/* read error? */
+				        brelse(*bhe);
+					if (++bhe == &buflist[NBUF])
+					  bhe = buflist;
 					left = 0;
 					break;
 				}
diff --git a/fs/minix/namei.c b/fs/minix/namei.c
index dbc33c2..05a573b 100644
--- a/fs/minix/namei.c
+++ b/fs/minix/namei.c
@@ -497,6 +497,9 @@
 		goto end_unlink;
 	if (!(inode = iget(dir->i_sb, de->inode)))
 		goto end_unlink;
+	retval = -EPERM;
+	if (S_ISDIR(inode->i_mode))
+		goto end_unlink;
 	if (de->inode != inode->i_ino) {
 		iput(inode);
 		brelse(bh);
@@ -504,13 +507,10 @@
 		schedule();
 		goto repeat;
 	}
-	retval = -EPERM;
 	if ((dir->i_mode & S_ISVTX) && !suser() &&
 	    current->euid != inode->i_uid &&
 	    current->euid != dir->i_uid)
 		goto end_unlink;
-	if (S_ISDIR(inode->i_mode))
-		goto end_unlink;
 	if (!inode->i_nlink) {
 		printk("Deleting nonexistent file (%04x:%d), %d\n",
 			inode->i_dev,inode->i_ino,inode->i_nlink);
@@ -689,7 +689,7 @@
 	retval = -ENOENT;
 	if (!old_bh)
 		goto end_rename;
-	old_inode = iget(old_dir->i_sb, old_de->inode);
+	old_inode = __iget(old_dir->i_sb, old_de->inode,0); /* don't cross mnt-points */
 	if (!old_inode)
 		goto end_rename;
 	retval = -EPERM;
@@ -699,7 +699,7 @@
 		goto end_rename;
 	new_bh = minix_find_entry(new_dir,new_name,new_len,&new_de);
 	if (new_bh) {
-		new_inode = iget(new_dir->i_sb, new_de->inode);
+		new_inode = __iget(new_dir->i_sb, new_de->inode, 0);
 		if (!new_inode) {
 			brelse(new_bh);
 			new_bh = NULL;
diff --git a/fs/namei.c b/fs/namei.c
index 6c8945e..66a53b1 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -266,7 +266,7 @@
  *
  * namei for open - this is in fact almost the whole open-routine.
  *
- * Note that the low bits of "flag" aren't the same asin the open
+ * Note that the low bits of "flag" aren't the same as in the open
  * system call - they are 00 - no permissions needed
  *			  01 - read permission needed
  *			  10 - write permission needed
@@ -369,6 +369,8 @@
  				return -ETXTBSY;
  			}
 			for(mpnt = (*p)->mmap; mpnt; mpnt = mpnt->vm_next) {
+				if (mpnt->vm_page_prot & PAGE_RW)
+					continue;
 				if (inode == mpnt->vm_inode) {
 					iput(inode);
 					return -ETXTBSY;
@@ -376,6 +378,16 @@
 			}
  		}
  	}
+	if (flag & O_TRUNC) {
+	      inode->i_size = 0;
+	      if (inode->i_op && inode->i_op->truncate)
+	           inode->i_op->truncate(inode);
+	      if ((error = notify_change(NOTIFY_SIZE, inode))) {
+		   iput(inode);
+		   return error;
+	      }
+	      inode->i_dirt = 1;
+	}
 	*res_inode = inode;
 	return 0;
 }
@@ -409,7 +421,7 @@
 	return dir->i_op->mknod(dir,basename,namelen,mode,dev);
 }
 
-extern "C" int sys_mknod(const char * filename, int mode, dev_t dev)
+asmlinkage int sys_mknod(const char * filename, int mode, dev_t dev)
 {
 	int error;
 	char * tmp;
@@ -452,7 +464,7 @@
 	return dir->i_op->mkdir(dir,basename,namelen,mode);
 }
 
-extern "C" int sys_mkdir(const char * pathname, int mode)
+asmlinkage int sys_mkdir(const char * pathname, int mode)
 {
 	int error;
 	char * tmp;
@@ -493,7 +505,7 @@
 	return dir->i_op->rmdir(dir,basename,namelen);
 }
 
-extern "C" int sys_rmdir(const char * pathname)
+asmlinkage int sys_rmdir(const char * pathname)
 {
 	int error;
 	char * tmp;
@@ -534,7 +546,7 @@
 	return dir->i_op->unlink(dir,basename,namelen);
 }
 
-extern "C" int sys_unlink(const char * pathname)
+asmlinkage int sys_unlink(const char * pathname)
 {
 	int error;
 	char * tmp;
@@ -575,7 +587,7 @@
 	return dir->i_op->symlink(dir,basename,namelen,oldname);
 }
 
-extern "C" int sys_symlink(const char * oldname, const char * newname)
+asmlinkage int sys_symlink(const char * oldname, const char * newname)
 {
 	int error;
 	char * from, * to;
@@ -631,7 +643,7 @@
 	return dir->i_op->link(oldinode, dir, basename, namelen);
 }
 
-extern "C" int sys_link(const char * oldname, const char * newname)
+asmlinkage int sys_link(const char * oldname, const char * newname)
 {
 	int error;
 	char * to;
@@ -703,7 +715,7 @@
 		new_dir, new_base, new_len);
 }
 
-extern "C" int sys_rename(const char * oldname, const char * newname)
+asmlinkage int sys_rename(const char * oldname, const char * newname)
 {
 	int error;
 	char * from, * to;
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 47c46c1..b4c81fa 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -18,7 +18,7 @@
 #include <linux/errno.h>
 #include <linux/locks.h>
 
-extern int close_fp(struct file *filp);
+extern int close_fp(struct file *filp, unsigned int fd);
 
 static int nfs_notify_change(int, struct inode *);
 static void nfs_put_inode(struct inode *);
@@ -43,7 +43,8 @@
 
 void nfs_put_super(struct super_block *sb)
 {
-	close_fp(sb->u.nfs_sb.s_server.file);
+        /* No locks should be open on this, so 0 should be safe as a fd. */
+	close_fp(sb->u.nfs_sb.s_server.file, 0);
 	lock_super(sb);
 	sb->s_dev = 0;
 	unlock_super(sb);
diff --git a/fs/nfs/mmap.c b/fs/nfs/mmap.c
index 24df306..22f660c 100644
--- a/fs/nfs/mmap.c
+++ b/fs/nfs/mmap.c
@@ -54,10 +54,6 @@
 		return -EINVAL;
 	if (off & (inode->i_sb->s_blocksize - 1))
 		return -EINVAL;
-	if (len > high_memory || off > high_memory - len) /* avoid overflow */
-		return -ENXIO;
-	if (get_limit(USER_DS) != TASK_SIZE)
-		return -EINVAL;
 	if (!inode->i_sb || !S_ISREG(inode->i_mode))
 		return -EACCES;
 	if (!IS_RDONLY(inode)) {
@@ -81,10 +77,6 @@
 	mpnt->vm_ops = &nfs_file_mmap;
 	mpnt->vm_next = current->mmap;
 	current->mmap = mpnt;
-#if 0
-	printk("VFS: Loaded mmap at %08x - %08x\n",
-		mpnt->vm_start,	mpnt->vm_end);
-#endif
 	return 0;
 }
 
diff --git a/fs/open.c b/fs/open.c
index 2fb689e..6e2c4f8 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -19,14 +19,14 @@
 
 #include <asm/segment.h>
 
-extern void fcntl_remove_locks(struct task_struct *, struct file *);
+extern void fcntl_remove_locks(struct task_struct *, struct file *, unsigned int fd);
 
-extern "C" int sys_ustat(int dev, struct ustat * ubuf)
+asmlinkage int sys_ustat(int dev, struct ustat * ubuf)
 {
 	return -ENOSYS;
 }
 
-extern "C" int sys_statfs(const char * path, struct statfs * buf)
+asmlinkage int sys_statfs(const char * path, struct statfs * buf)
 {
 	struct inode * inode;
 	int error;
@@ -46,7 +46,7 @@
 	return 0;
 }
 
-extern "C" int sys_fstatfs(unsigned int fd, struct statfs * buf)
+asmlinkage int sys_fstatfs(unsigned int fd, struct statfs * buf)
 {
 	struct inode * inode;
 	struct file * file;
@@ -65,7 +65,7 @@
 	return 0;
 }
 
-extern "C" int sys_truncate(const char * path, unsigned int length)
+asmlinkage int sys_truncate(const char * path, unsigned int length)
 {
 	struct inode * inode;
 	int error;
@@ -91,7 +91,7 @@
 	return error;
 }
 
-extern "C" int sys_ftruncate(unsigned int fd, unsigned int length)
+asmlinkage int sys_ftruncate(unsigned int fd, unsigned int length)
 {
 	struct inode * inode;
 	struct file * file;
@@ -114,7 +114,7 @@
  * must be owner or have write permission.
  * Else, update from *times, must be owner or super user.
  */
-extern "C" int sys_utime(char * filename, struct utimbuf * times)
+asmlinkage int sys_utime(char * filename, struct utimbuf * times)
 {
 	struct inode * inode;
 	long actime,modtime;
@@ -155,7 +155,7 @@
  * XXX we should use the real ids for checking _all_ components of the
  * path.  Now we only use them for the final component of the path.
  */
-extern "C" int sys_access(const char * filename,int mode)
+asmlinkage int sys_access(const char * filename,int mode)
 {
 	struct inode * inode;
 	int res, i_mode;
@@ -189,7 +189,7 @@
 	return -EACCES;
 }
 
-extern "C" int sys_chdir(const char * filename)
+asmlinkage int sys_chdir(const char * filename)
 {
 	struct inode * inode;
 	int error;
@@ -210,7 +210,7 @@
 	return (0);
 }
 
-extern "C" int sys_chroot(const char * filename)
+asmlinkage int sys_chroot(const char * filename)
 {
 	struct inode * inode;
 	int error;
@@ -231,7 +231,7 @@
 	return (0);
 }
 
-extern "C" int sys_fchmod(unsigned int fd, mode_t mode)
+asmlinkage int sys_fchmod(unsigned int fd, mode_t mode)
 {
 	struct inode * inode;
 	struct file * file;
@@ -252,7 +252,7 @@
 	return notify_change(NOTIFY_MODE, inode);
 }
 
-extern "C" int sys_chmod(const char * filename, mode_t mode)
+asmlinkage int sys_chmod(const char * filename, mode_t mode)
 {
 	struct inode * inode;
 	int error;
@@ -278,7 +278,7 @@
 	return error;
 }
 
-extern "C" int sys_fchown(unsigned int fd, uid_t user, gid_t group)
+asmlinkage int sys_fchown(unsigned int fd, uid_t user, gid_t group)
 {
 	struct inode * inode;
 	struct file * file;
@@ -305,7 +305,7 @@
 	return -EPERM;
 }
 
-extern "C" int sys_chown(const char * filename, uid_t user, gid_t group)
+asmlinkage int sys_chown(const char * filename, uid_t user, gid_t group)
 {
 	struct inode * inode;
 	int error;
@@ -378,18 +378,7 @@
 		f->f_count--;
 		return error;
 	}
-	if (flag & O_TRUNC) {
-		inode->i_size = 0;
-		if (inode->i_op && inode->i_op->truncate)
-			inode->i_op->truncate(inode);
-		if ((error = notify_change(NOTIFY_SIZE, inode))) {
-			iput(inode);
-			current->filp[fd] = NULL;
-			f->f_count--;
-			return error;
-		}
-		inode->i_dirt = 1;
-	}
+
 	f->f_inode = inode;
 	f->f_pos = 0;
 	f->f_reada = 0;
@@ -409,7 +398,7 @@
 	return (fd);
 }
 
-extern "C" int sys_open(const char * filename,int flags,int mode)
+asmlinkage int sys_open(const char * filename,int flags,int mode)
 {
 	char * tmp;
 	int error;
@@ -422,12 +411,12 @@
 	return error;
 }
 
-extern "C" int sys_creat(const char * pathname, int mode)
+asmlinkage int sys_creat(const char * pathname, int mode)
 {
 	return sys_open(pathname, O_CREAT | O_WRONLY | O_TRUNC, mode);
 }
 
-int close_fp(struct file *filp)
+int close_fp(struct file *filp, unsigned int fd)
 {
 	struct inode *inode;
 
@@ -437,7 +426,7 @@
 	}
 	inode = filp->f_inode;
 	if (inode && S_ISREG(inode->i_mode))
-		fcntl_remove_locks(current, filp);
+		fcntl_remove_locks(current, filp, fd);
 	if (filp->f_count > 1) {
 		filp->f_count--;
 		return 0;
@@ -450,7 +439,7 @@
 	return 0;
 }
 
-extern "C" int sys_close(unsigned int fd)
+asmlinkage int sys_close(unsigned int fd)
 {	
 	struct file * filp;
 
@@ -460,14 +449,14 @@
 	if (!(filp = current->filp[fd]))
 		return -EBADF;
 	current->filp[fd] = NULL;
-	return (close_fp (filp));
+	return (close_fp (filp, fd));
 }
 
 /*
  * This routine simulates a hangup on the tty, to arrange that users
  * are given clean terminals at login time.
  */
-extern "C" int sys_vhangup(void)
+asmlinkage int sys_vhangup(void)
 {
 	struct tty_struct *tty;
 
diff --git a/fs/pipe.c b/fs/pipe.c
index 1f407f5..351684d 100644
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -288,7 +288,7 @@
 	NULL			/* permission */
 };
 
-extern "C" int sys_pipe(unsigned long * fildes)
+asmlinkage int sys_pipe(unsigned long * fildes)
 {
 	struct inode * inode;
 	struct file * f[2];
diff --git a/fs/proc/array.c b/fs/proc/array.c
index fe1d4e6..ba8f8c1 100644
--- a/fs/proc/array.c
+++ b/fs/proc/array.c
@@ -194,7 +194,7 @@
 	if (vsize) {
 		eip = KSTK_EIP(vsize);
 		esp = KSTK_ESP(vsize);
-		vsize = (*p)->brk + PAGE_SIZE-1;
+		vsize = (*p)->brk - (*p)->start_code + PAGE_SIZE-1;
 		if (esp)
 			vsize += TASK_SIZE - esp;
 	}
@@ -264,7 +264,7 @@
 		return 0;
 	tpag = (*p)->end_code / PAGE_SIZE;
 	if ((*p)->state != TASK_ZOMBIE) {
-	  pagedir = PAGE_DIR_OFFSET((*p)->tss.cr3,(*p)->start_code);
+	  pagedir = (unsigned long *) (*p)->tss.cr3;
 	  for (i = 0; i < 0x300; ++i) {
 	    if ((ptbl = pagedir[i]) == 0) {
 	      tpag -= PTRS_PER_PAGE;
diff --git a/fs/proc/kmsg.c b/fs/proc/kmsg.c
index bb0e51c..e577d29 100644
--- a/fs/proc/kmsg.c
+++ b/fs/proc/kmsg.c
@@ -17,7 +17,7 @@
 extern unsigned long log_size;
 extern struct wait_queue * log_wait;
 
-extern "C" int sys_syslog(int type, char * bug, int count);
+asmlinkage int sys_syslog(int type, char * bug, int count);
 
 static int kmsg_open(struct inode * inode, struct file * file)
 {
diff --git a/fs/read_write.c b/fs/read_write.c
index 32a5a0e..3ff9058 100644
--- a/fs/read_write.c
+++ b/fs/read_write.c
@@ -16,7 +16,7 @@
  * Count is not yet used: but we'll probably support reading several entries
  * at once in the future. Use count=1 in the library for future expansions.
  */
-extern "C" int sys_readdir(unsigned int fd, struct dirent * dirent, unsigned int count)
+asmlinkage int sys_readdir(unsigned int fd, struct dirent * dirent, unsigned int count)
 {
 	int error;
 	struct file * file;
@@ -34,7 +34,7 @@
 	return error;
 }
 
-extern "C" int sys_lseek(unsigned int fd, off_t offset, unsigned int origin)
+asmlinkage int sys_lseek(unsigned int fd, off_t offset, unsigned int origin)
 {
 	struct file * file;
 	int tmp = -1;
@@ -67,7 +67,7 @@
 	return file->f_pos;
 }
 
-extern "C" int sys_read(unsigned int fd,char * buf,unsigned int count)
+asmlinkage int sys_read(unsigned int fd,char * buf,unsigned int count)
 {
 	int error;
 	struct file * file;
@@ -87,7 +87,7 @@
 	return file->f_op->read(inode,file,buf,count);
 }
 
-extern "C" int sys_write(unsigned int fd,char * buf,unsigned int count)
+asmlinkage int sys_write(unsigned int fd,char * buf,unsigned int count)
 {
 	int error;
 	struct file * file;
diff --git a/fs/select.c b/fs/select.c
index 61066ef..cfa62cd 100644
--- a/fs/select.c
+++ b/fs/select.c
@@ -192,7 +192,7 @@
  * Update: ERESTARTSYS breaks at least the xview clock binary, so
  * I'm trying ERESTARTNOHAND which restart only when you want to.
  */
-extern "C" int sys_select( unsigned long *buffer )
+asmlinkage int sys_select( unsigned long *buffer )
 {
 /* Perform the select(nd, in, out, ex, tv) system call. */
 	int i;
diff --git a/fs/stat.c b/fs/stat.c
index 42033ae..d5cc98e 100644
--- a/fs/stat.c
+++ b/fs/stat.c
@@ -86,7 +86,7 @@
 	memcpy_tofs(statbuf,&tmp,sizeof(tmp));
 }
 
-extern "C" int sys_stat(char * filename, struct old_stat * statbuf)
+asmlinkage int sys_stat(char * filename, struct old_stat * statbuf)
 {
 	struct inode * inode;
 	int error;
@@ -102,7 +102,7 @@
 	return 0;
 }
 
-extern "C" int sys_newstat(char * filename, struct new_stat * statbuf)
+asmlinkage int sys_newstat(char * filename, struct new_stat * statbuf)
 {
 	struct inode * inode;
 	int error;
@@ -118,7 +118,7 @@
 	return 0;
 }
 
-extern "C" int sys_lstat(char * filename, struct old_stat * statbuf)
+asmlinkage int sys_lstat(char * filename, struct old_stat * statbuf)
 {
 	struct inode * inode;
 	int error;
@@ -134,7 +134,7 @@
 	return 0;
 }
 
-extern "C" int sys_newlstat(char * filename, struct new_stat * statbuf)
+asmlinkage int sys_newlstat(char * filename, struct new_stat * statbuf)
 {
 	struct inode * inode;
 	int error;
@@ -150,7 +150,7 @@
 	return 0;
 }
 
-extern "C" int sys_fstat(unsigned int fd, struct old_stat * statbuf)
+asmlinkage int sys_fstat(unsigned int fd, struct old_stat * statbuf)
 {
 	struct file * f;
 	struct inode * inode;
@@ -165,7 +165,7 @@
 	return 0;
 }
 
-extern "C" int sys_newfstat(unsigned int fd, struct new_stat * statbuf)
+asmlinkage int sys_newfstat(unsigned int fd, struct new_stat * statbuf)
 {
 	struct file * f;
 	struct inode * inode;
@@ -180,7 +180,7 @@
 	return 0;
 }
 
-extern "C" int sys_readlink(const char * path, char * buf, int bufsiz)
+asmlinkage int sys_readlink(const char * path, char * buf, int bufsiz)
 {
 	struct inode * inode;
 	int error;
diff --git a/fs/super.c b/fs/super.c
index fbc6c5b..cf30024 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -243,7 +243,7 @@
  * functions, they should be faked here.  -- jrs
  */
 
-extern "C" int sys_umount(char * name)
+asmlinkage int sys_umount(char * name)
 {
 	struct inode * inode;
 	dev_t dev;
@@ -390,7 +390,7 @@
  * isn't present, the flags and data info isn't used, as the syscall assumes we
  * are talking to an older version that didn't understand them.
  */
-extern "C" int sys_mount(char * dev_name, char * dir_name, char * type,
+asmlinkage int sys_mount(char * dev_name, char * dir_name, char * type,
 	unsigned long new_flags, void * data)
 {
 	struct file_system_type * fstype;
diff --git a/fs/xiafs/file.c b/fs/xiafs/file.c
index 4d02217..ad09f12 100644
--- a/fs/xiafs/file.c
+++ b/fs/xiafs/file.c
@@ -141,6 +141,9 @@
 	    if (*bhe) {
 	        wait_on_buffer(*bhe);
 		if (!(*bhe)->b_uptodate) {	/* read error? */
+		    brelse(*bhe);
+		    if (++bhe == &buflist[NBUF])
+		      bhe = buflist;
 		    left = 0;
 		    break;
 		}
diff --git a/fs/xiafs/namei.c b/fs/xiafs/namei.c
index 761d88d..2dbbf34 100644
--- a/fs/xiafs/namei.c
+++ b/fs/xiafs/namei.c
@@ -543,6 +543,9 @@
         goto end_unlink;
     if (!(inode = iget(dir->i_sb, de->d_ino)))
         goto end_unlink;
+    retval = -EPERM;
+    if (S_ISDIR(inode->i_mode))
+        goto end_unlink;
     if (de->d_ino != inode->i_ino) {
         iput(inode);
 	brelse(bh);
@@ -550,13 +553,10 @@
 	schedule();
 	goto repeat;
     }
-    retval = -EPERM;
     if ((dir->i_mode & S_ISVTX) && !suser() &&
 	    current->euid != inode->i_uid &&
 	    current->euid != dir->i_uid)
         goto end_unlink;
-    if (S_ISDIR(inode->i_mode))
-        goto end_unlink;
     if (!inode->i_nlink) {
         printk("XIA-FS: Deleting nonexistent file (%s %d)\n", WHERE_ERR);
 	inode->i_nlink=1;
@@ -720,7 +720,7 @@
     retval = -ENOENT;
     if (!old_bh)
         goto end_rename;
-    old_inode = iget(old_dir->i_sb, old_de->d_ino);
+    old_inode = __iget(old_dir->i_sb, old_de->d_ino, 0); /* don't cross mnt-points */
     if (!old_inode)
         goto end_rename;
     retval = -EPERM;
@@ -730,7 +730,7 @@
         goto end_rename;
     new_bh = xiafs_find_entry(new_dir, new_name, new_len, &new_de, NULL);
     if (new_bh) {
-        new_inode = iget(new_dir->i_sb, new_de->d_ino);
+        new_inode = __iget(new_dir->i_sb, new_de->d_ino, 0);
 	if (!new_inode) {
 	    brelse(new_bh);
 	    new_bh = NULL;
diff --git a/ibcs/emulate.c b/ibcs/emulate.c
index 5c3f582..cb4f9ec 100644
--- a/ibcs/emulate.c
+++ b/ibcs/emulate.c
@@ -20,7 +20,7 @@
 #include <asm/segment.h>
 #include <asm/system.h>
 
-extern "C" void iABI_emulate(struct pt_regs * regs)
+asmlinkage void iABI_emulate(struct pt_regs * regs)
 {
 	printk("lcall 7,xxx: eax = %08x\n",regs->eax);
 }
diff --git a/include/asm/irq.h b/include/asm/irq.h
index 64a7e92..89dbe62 100644
--- a/include/asm/irq.h
+++ b/include/asm/irq.h
@@ -8,6 +8,11 @@
  */
 
 #include <linux/segment.h>
+#include <linux/linkage.h>
+
+extern void disable_irq(unsigned int);
+extern void enable_irq(unsigned int);
+
 #define __STR(x) #x
 #define STR(x) __STR(x)
  
@@ -117,9 +122,9 @@
 #define BAD_IRQ_NAME(nr) IRQ_NAME2(bad_IRQ##nr)
 	
 #define BUILD_IRQ(chip,nr,mask) \
-extern "C" void IRQ_NAME(nr); \
-extern "C" void FAST_IRQ_NAME(nr); \
-extern "C" void BAD_IRQ_NAME(nr); \
+asmlinkage void IRQ_NAME(nr); \
+asmlinkage void FAST_IRQ_NAME(nr); \
+asmlinkage void BAD_IRQ_NAME(nr); \
 __asm__( \
 "\n.align 4\n" \
 "_IRQ" #nr "_interrupt:\n\t" \
diff --git a/include/asm/segment.h b/include/asm/segment.h
index 4e8ef17..12501a2 100644
--- a/include/asm/segment.h
+++ b/include/asm/segment.h
@@ -1,7 +1,7 @@
 #ifndef _ASM_SEGMENT_H
 #define _ASM_SEGMENT_H
 
-static inline unsigned char get_fs_byte(const char * addr)
+static inline unsigned char get_user_byte(const char * addr)
 {
 	register unsigned char _v;
 
@@ -9,15 +9,9 @@
 	return _v;
 }
 
-static inline unsigned char get_fs_byte(const unsigned char * addr)
-{
-	register unsigned char _v;
+#define get_fs_byte(addr) get_user_byte((char *)(addr))
 
-	__asm__ ("movb %%fs:%1,%0":"=q" (_v):"m" (*addr));
-	return _v;
-}
-
-static inline unsigned short get_fs_word(const short *addr)
+static inline unsigned short get_user_word(const short *addr)
 {
 	unsigned short _v;
 
@@ -25,15 +19,9 @@
 	return _v;
 }
 
-static inline unsigned short get_fs_word(const unsigned short *addr)
-{
-	unsigned short _v;
+#define get_fs_word(addr) get_user_word((short *)(addr))
 
-	__asm__ ("movw %%fs:%1,%0":"=r" (_v):"m" (*addr));
-	return _v;
-}
-
-static inline unsigned long get_fs_long(const int *addr)
+static inline unsigned long get_user_long(const int *addr)
 {
 	unsigned long _v;
 
@@ -41,69 +29,28 @@
 	return _v;
 }
 
-static inline unsigned long get_fs_long(const unsigned int *addr)
-{
-	unsigned long _v;
+#define get_fs_long(addr) get_user_long((int *)(addr))
 
-	__asm__ ("movl %%fs:%1,%0":"=r" (_v):"m" (*addr)); \
-	return _v;
-}
-
-static inline unsigned long get_fs_long(const long *addr)
-{
-	unsigned long _v;
-
-	__asm__ ("movl %%fs:%1,%0":"=r" (_v):"m" (*addr)); \
-	return _v;
-}
-
-static inline unsigned long get_fs_long(const unsigned long *addr)
-{
-	unsigned long _v;
-
-	__asm__ ("movl %%fs:%1,%0":"=r" (_v):"m" (*addr)); \
-	return _v;
-}
-
-static inline void put_fs_byte(char val,char *addr)
+static inline void put_user_byte(char val,char *addr)
 {
 __asm__ ("movb %0,%%fs:%1": /* no outputs */ :"iq" (val),"m" (*addr));
 }
 
-static inline void put_fs_byte(char val,unsigned char *addr)
-{
-__asm__ ("movb %0,%%fs:%1": /* no outputs */ :"iq" (val),"m" (*addr));
-}
+#define put_fs_byte(x,addr) put_user_byte((x),(char *)(addr))
 
-static inline void put_fs_word(short val,short * addr)
+static inline void put_user_word(short val,short * addr)
 {
 __asm__ ("movw %0,%%fs:%1": /* no outputs */ :"ir" (val),"m" (*addr));
 }
 
-static inline void put_fs_word(short val,unsigned short * addr)
-{
-__asm__ ("movw %0,%%fs:%1": /* no outputs */ :"ir" (val),"m" (*addr));
-}
+#define put_fs_word(x,addr) put_user_word((x),(short *)(addr))
 
-static inline void put_fs_long(unsigned long val,int * addr)
+static inline void put_user_long(unsigned long val,int * addr)
 {
 __asm__ ("movl %0,%%fs:%1": /* no outputs */ :"ir" (val),"m" (*addr));
 }
 
-static inline void put_fs_long(unsigned long val,unsigned int * addr)
-{
-__asm__ ("movl %0,%%fs:%1": /* no outputs */ :"ir" (val),"m" (*addr));
-}
-
-static inline void put_fs_long(unsigned long val,long * addr)
-{
-__asm__ ("movl %0,%%fs:%1": /* no outputs */ :"ir" (val),"m" (*addr));
-}
-
-static inline void put_fs_long(unsigned long val,unsigned long * addr)
-{
-__asm__ ("movl %0,%%fs:%1": /* no outputs */ :"ir" (val),"m" (*addr));
-}
+#define put_fs_long(x,addr) put_user_long((x),(int *)(addr))
 
 static inline void memcpy_tofs(void * to, const void * from, unsigned long n)
 {
diff --git a/include/linux/a.out.h b/include/linux/a.out.h
index 2c6b8c8..15071d3 100644
--- a/include/linux/a.out.h
+++ b/include/linux/a.out.h
@@ -71,24 +71,26 @@
 #define NMAGIC 0410
 /* Code indicating demand-paged executable.  */
 #define ZMAGIC 0413
+/* This indicates a demand-paged executable with the header in the text. 
+   The first page is unmapped to help trap NULL pointer references */
+#define QMAGIC 0314
 
 /* Code indicating core file.  */
 #define CMAGIC 0421
-#if !defined (N_BADMAG)
-#define N_BADMAG(x)					\
- (N_MAGIC(x) != OMAGIC && N_MAGIC(x) != NMAGIC		\
-  && N_MAGIC(x) != ZMAGIC)
-#endif
 
-#define _N_BADMAG(x)					\
- (N_MAGIC(x) != OMAGIC && N_MAGIC(x) != NMAGIC		\
-  && N_MAGIC(x) != ZMAGIC)
+#if !defined (N_BADMAG)
+#define N_BADMAG(x)	  (N_MAGIC(x) != OMAGIC		\
+			&& N_MAGIC(x) != NMAGIC		\
+  			&& N_MAGIC(x) != ZMAGIC \
+		        && N_MAGIC(x) != QMAGIC)
+#endif
 
 #define _N_HDROFF(x) (1024 - sizeof (struct exec))
 
 #if !defined (N_TXTOFF)
 #define N_TXTOFF(x) \
- (N_MAGIC(x) == ZMAGIC ? _N_HDROFF((x)) + sizeof (struct exec) : sizeof (struct exec))
+ (N_MAGIC(x) == ZMAGIC ? _N_HDROFF((x)) + sizeof (struct exec) : \
+  (N_MAGIC(x) == QMAGIC ? 0 : sizeof (struct exec)))
 #endif
 
 #if !defined (N_DATOFF)
@@ -113,7 +115,7 @@
 
 /* Address of text segment in memory after it is loaded.  */
 #if !defined (N_TXTADDR)
-#define N_TXTADDR(x) 0
+#define N_TXTADDR(x) (N_MAGIC(x) == QMAGIC ? PAGE_SIZE : 0)
 #endif
 
 /* Address of data segment in memory after it is loaded.
diff --git a/include/linux/binfmts.h b/include/linux/binfmts.h
index 35823c8..fbcb6d6 100644
--- a/include/linux/binfmts.h
+++ b/include/linux/binfmts.h
@@ -1,6 +1,8 @@
 #ifndef _LINUX_BINFMTS_H
 #define _LINUX_BINFMTS_H
 
+#include <linux/ptrace.h>
+
 /*
  * MAX_ARG_PAGES defines the number of pages allocated for arguments
  * and envelope for the new program. 32 should suffice, this gives
@@ -15,6 +17,7 @@
   char buf[128];
   unsigned long page[MAX_ARG_PAGES];
   unsigned long p;
+  int sh_bang;
   struct inode * inode;
   int e_uid, e_gid;
   int argc, envc;
@@ -31,6 +34,15 @@
 
 extern struct linux_binfmt formats[];
 
+extern int read_exec(struct inode *inode, unsigned long offset,
+	char * addr, unsigned long count);
 
+extern int open_inode(struct inode * inode, int mode);
+
+extern void flush_old_exec(struct linux_binprm * bprm);
+extern unsigned long change_ldt(unsigned long text_size,unsigned long * page);
+extern unsigned long * create_tables(char * p,int argc,int envc);
+extern unsigned long copy_strings(int argc,char ** argv,unsigned long *page,
+		unsigned long p, int from_kmem);
 
 #endif
diff --git a/include/linux/elf.h b/include/linux/elf.h
new file mode 100644
index 0000000..fbad2da
--- /dev/null
+++ b/include/linux/elf.h
@@ -0,0 +1,153 @@
+#ifndef _ELF_H
+#define _ELF_H
+
+/* THese constants are for the segment types stored in the image headers */
+#define PT_NULL    0
+#define PT_LOAD    1
+#define PT_DYNAMIC 2
+#define PT_INTERP  3
+#define PT_NOTE    4
+#define PT_SHLIB   5
+#define PT_PHDR    6
+#define PT_LOPROC  0x70000000
+#define PT_HIPROC  0x7fffffff
+
+/* These constants define the different elf file types */
+#define ET_NONE   0
+#define ET_REL    1
+#define ET_EXEC   2
+#define ET_DYN    3
+#define ET_CORE   4
+#define ET_LOPROC 5
+#define ET_HIPROC 6
+
+/* These constants define the various ELF target machines */
+#define EM_NONE  0
+#define EM_M32   1
+#define EM_SPARC 2
+#define EM_386   3
+#define EM_68K   4
+#define EM_88K   5
+#define EM_486   6   /* Perhaps disused */
+#define EM_860   7
+
+/* This is the info that is needed to parse the dynamic section of the file */
+#define DT_NULL		0
+#define DT_NEEDED	1
+#define DT_PLTRELSZ	2
+#define DT_PLTGOT	3
+#define DT_HASH		4
+#define DT_STRTAB	5
+#define DT_SYMTAB	6
+#define DT_RELA		7
+#define DT_RELASZ	8
+#define DT_RELAENT	9
+#define DT_STRSZ	10
+#define DT_SYMENT	11
+#define DT_INIT		12
+#define DT_FINI		13
+#define DT_SONAME	14
+#define DT_RPATH 	15
+#define DT_SYMBOLIC	16
+#define DT_REL	        17
+#define DT_RELSZ	18
+#define DT_RELENT	19
+#define DT_PLTREL	20
+#define DT_DEBUG	21
+#define DT_TEXTREL	22
+#define DT_JMPREL	23
+#define DT_LOPROC	0x70000000
+#define DT_HIPROC	0x7fffffff
+
+/* This info is needed when parsing the symbol table */
+#define STB_LOCAL  0
+#define STB_GLOBAL 1
+#define STB_WEAK   2
+
+#define STT_NOTYPE  0
+#define STT_OBJECT  1
+#define STT_FUNC    2
+#define STT_SECTION 3
+#define STT_FILE    4
+
+#define ELF32_ST_BIND(x) ((x) >> 4)
+#define ELF32_ST_TYPE(x) (((unsigned int) x) & 0xf)
+
+
+
+struct dynamic{
+  int d_tag;
+  union{
+    int d_val;
+    char * d_ptr;
+  } d_un;
+};
+
+/* THe following are used with relocations */
+#define ELF32_R_SYM(x) ((x) >> 8)
+#define ELF32_R_TYPE(x) ((x) & 0xff)
+
+#define R_386_NONE	0
+#define R_386_32	1
+#define R_386_PC32	2
+#define R_386_GOT32	3
+#define R_386_PLT32	4
+#define R_386_COPY	5
+#define R_386_GLOB_DAT	6
+#define R_386_JMP_SLOT	7
+#define R_386_RELATIVE	8
+#define R_386_GOTOFF	9
+#define R_386_GOTPC	10
+#define R_386_NUM	11
+
+struct Elf32_Rel{
+  unsigned int * offset;
+  int info;
+};
+
+struct Elf32_Rela{
+  unsigned int * offset;
+  int info;
+  int addend;
+};
+
+struct Elf32_Sym{
+  int st_name;
+  unsigned int st_value;
+  int st_size;
+  unsigned char st_info;
+  unsigned char st_other;
+  short int st_shndx;
+};
+
+struct elfhdr{
+  char	e_ident[16];
+  short int e_type;
+  short int e_machine;
+  int   e_version;
+  char *e_entry;  /* Entry point */
+  int   e_phoff;
+  int   e_shoff;
+  int   e_flags;
+  short int e_ehsize;
+  short int e_phentsize;
+  short int e_phnum;
+  short int e_shentsize;
+  short int e_shnum;
+  short int e_shstrndx;
+};
+
+struct elf_phdr{
+  int p_type;
+  int p_offset;
+  int p_vaddr;
+  int p_paddr;
+  int p_filesz;
+  int p_memsz;
+  int p_flags;
+  int p_align;
+};
+
+#define ELF_START_MMAP 0x80000000
+
+#endif
diff --git a/include/linux/fs.h b/include/linux/fs.h
index dada0e8..b9f03a7 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -6,6 +6,7 @@
  * structures etc.
  */
 
+#include <linux/linkage.h>
 #include <linux/limits.h>
 #include <linux/wait.h>
 #include <linux/types.h>
@@ -229,6 +230,7 @@
 struct file_lock {
 	struct file_lock *fl_next;	/* singly linked list */
 	struct task_struct *fl_owner;	/* NULL if on free list, for sanity checks */
+        unsigned int fl_fd;             /* File descriptor for this lock */
 	struct wait_queue *fl_wait;
 	char fl_type;
 	char fl_whence;
@@ -319,8 +321,8 @@
 
 #ifdef __KERNEL__
 
-extern "C" int sys_open(const char *, int, int);
-extern "C" int sys_close(unsigned int);		/* yes, it's really unsigned */
+asmlinkage int sys_open(const char *, int, int);
+asmlinkage int sys_close(unsigned int);		/* yes, it's really unsigned */
 
 extern int getname(const char * filename, char **result);
 extern void putname(char * name);
@@ -376,6 +378,7 @@
 	struct inode ** res_inode, struct inode * base);
 extern int do_mknod(const char * filename, int mode, dev_t dev);
 extern void iput(struct inode * inode);
+extern struct inode * __iget(struct super_block * sb,int nr,int crsmnt);
 extern struct inode * iget(struct super_block * sb,int nr);
 extern struct inode * get_empty_inode(void);
 extern void insert_inode_hash(struct inode *);
diff --git a/include/linux/ioport.h b/include/linux/ioport.h
new file mode 100644
index 0000000..1a2512b
--- /dev/null
+++ b/include/linux/ioport.h
@@ -0,0 +1,28 @@
+/*
+ * portio.h	Definitions of routines for detecting, reserving and
+ *		allocating system resources.
+ *
+ * Version:	0.01	8/30/93
+ *
+ * Author:	Donald Becker (becker@super.org)
+ */
+
+#ifndef _LINUX_PORTIO_H
+#define _LINUX_PORTIO_H
+
+#define HAVE_PORTRESERVE
+/*
+ * Call check_region() before probing for your hardware.
+ * Once you have found you hardware, register it with snarf_region().
+ */
+extern void reserve_setup(char *str, int *ints);
+extern int check_region(unsigned int from, unsigned int extent);
+extern void snarf_region(unsigned int from, unsigned int extent);
+
+
+#define HAVE_AUTOIRQ
+extern void *irq2dev_map[16];		/* Use only if you own the IRQ. */
+extern void autoirq_setup(int waittime);
+extern int autoirq_report(int waittime);
+
+#endif	/* _LINUX_PORTIO_H */
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index 69b1899..8d9eeb6 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -8,6 +8,7 @@
 #ifdef __KERNEL__
 
 #include <linux/config.h>
+#include <linux/linkage.h>
 
 #define INT_MAX		((int)(~0U>>1))
 #define UINT_MAX	(~0U)
@@ -20,12 +21,14 @@
 int verify_area(int type, void * addr, unsigned long count);
 
 extern void math_error(void);
-volatile void panic(const char * str);
+volatile void panic(const char * fmt, ...)
+	__attribute__ ((format (printf, 1, 2)));
 volatile void do_exit(long error_code);
 unsigned long simple_strtoul(const char *,char **,unsigned int);
 int sprintf(char * buf, const char * fmt, ...);
 
-extern "C" int printk(const char * fmt, ...);
+asmlinkage int printk(const char * fmt, ...)
+	__attribute__ ((format (printf, 1, 2)));
 
 #ifdef CONFIG_DEBUG_MALLOC
 #define kmalloc(a,b) deb_kmalloc(__FILE__,__LINE__, a,b)
diff --git a/include/linux/linkage.h b/include/linux/linkage.h
new file mode 100644
index 0000000..8f5c4d5
--- /dev/null
+++ b/include/linux/linkage.h
@@ -0,0 +1,10 @@
+#ifndef _LINUX_LINKAGE_H
+#define _LINUX_LINKAGE_H
+
+#ifdef __cplusplus
+#define asmlinkage extern "C"
+#else
+#define asmlinkage
+#endif
+
+#endif
diff --git a/include/linux/page.h b/include/linux/page.h
index 97796bd..5140a85 100644
--- a/include/linux/page.h
+++ b/include/linux/page.h
@@ -25,7 +25,7 @@
   ((unsigned long)(address)>>(PAGE_SHIFT-SIZEOF_PTR_LOG2)*2&PTR_MASK&~PAGE_MASK)))
 			/* to find an entry in a page-table */
 #define PAGE_PTR(address)		\
-  ((unsigned long)(address)>>PAGE_SHIFT-SIZEOF_PTR_LOG2&PTR_MASK&~PAGE_MASK)
+  ((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*))
 
diff --git a/include/linux/sched.h b/include/linux/sched.h
index bda86e8..0ec8bed 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -83,9 +83,10 @@
 extern void sched_init(void);
 extern void show_state(void);
 extern void trap_init(void);
-extern void panic(const char * str);
+extern void panic(const char * fmt, ...)
+	__attribute__ ((format (printf, 1, 2)));
 
-extern "C" void schedule(void);
+asmlinkage void schedule(void);
 
 #endif /* __KERNEL__ */
 
@@ -255,7 +256,7 @@
 /* min_flt */	0,0,0,0, \
 /* rlimits */   { {LONG_MAX, LONG_MAX}, {LONG_MAX, LONG_MAX},  \
 		  {LONG_MAX, LONG_MAX}, {LONG_MAX, LONG_MAX},  \
-		  {LONG_MAX, LONG_MAX}, {LONG_MAX, LONG_MAX}}, \
+		  {       0, LONG_MAX}, {LONG_MAX, LONG_MAX}}, \
 /* math */	0, \
 /* rss */	2, \
 /* comm */	"swapper", \
diff --git a/include/linux/shm.h b/include/linux/shm.h
index f61d6d6..fdcdbb2 100644
--- a/include/linux/shm.h
+++ b/include/linux/shm.h
@@ -61,13 +61,13 @@
 #define SHM_ID_MASK	((1<<_SHM_ID_BITS)-1)
 #define SHM_IDX_SHIFT	(SHM_ID_SHIFT+_SHM_ID_BITS)
 #define SHM_IDX_MASK	((1<<_SHM_IDX_BITS)-1)
-#define SHM_READ_ONLY	(1<<BITS_PER_PTR-1)
+#define SHM_READ_ONLY	(1<<(BITS_PER_PTR-1))
 
-#define SHMMAX (1<<PAGE_SHIFT+_SHM_IDX_BITS)	/* max shared seg size (bytes) */
-#define SHMMIN 1	 /* really PAGE_SIZE */	/* min shared seg size (bytes)*/
+#define SHMMAX 0x400000				/* max shared seg size (bytes) */
+#define SHMMIN 1	 /* really PAGE_SIZE */	/* min shared seg size (bytes) */
 #define SHMMNI (1<<_SHM_ID_BITS)		/* max num of segs system wide */
-#define SHMALL (1<<_SHM_IDX_BITS+_SHM_ID_BITS)	/* max shm system wide (pages) */
-#define	SHMLBA PAGE_SIZE			/* attach addr a multiple of this */
+#define SHMALL (1<<(_SHM_IDX_BITS+_SHM_ID_BITS))/* max shm system wide (pages) */
+#define	SHMLBA 0x1000				/* attach addr a multiple of this */
 #define SHMSEG SHMMNI				/* max shared segs per process */
 
 #ifdef __KERNEL__
diff --git a/include/linux/signal.h b/include/linux/signal.h
index 040a721..992933a 100644
--- a/include/linux/signal.h
+++ b/include/linux/signal.h
@@ -53,6 +53,9 @@
 */
 #define SIGPWR		30
 
+/* Arggh. Bad user source code wants this.. */
+#define SIGBUS		SIGUNUSED
+
 /*
  * sa_flags values: SA_STACK is not currently supported, but will allow the
  * usage of signal stacks by using the (now obsolete) sa_restorer field in
diff --git a/include/linux/sys.h b/include/linux/sys.h
index 7ff8045..5104bab 100644
--- a/include/linux/sys.h
+++ b/include/linux/sys.h
@@ -4,7 +4,9 @@
 
 #define sys_clone sys_fork
 
+#ifdef __cplusplus
 extern "C" {
+#endif
 
 extern int sys_setup();
 extern int sys_exit();
@@ -170,7 +172,9 @@
 sys_wait4, sys_swapoff, sys_sysinfo, sys_ipc, sys_fsync, sys_sigreturn,
 sys_clone, sys_setdomainname, sys_newuname, sys_modify_ldt};
 
+#ifdef __cplusplus
 }
+#endif
 
 /* So we don't have to do any more manual updating.... */
 int NR_syscalls = sizeof(sys_call_table)/sizeof(fn_ptr);
diff --git a/include/linux/tasks.h b/include/linux/tasks.h
index 0607d87..12facf2 100644
--- a/include/linux/tasks.h
+++ b/include/linux/tasks.h
@@ -4,6 +4,6 @@
 /*
  * This is the maximum nr of tasks - change it if you need to
  */
-#define NR_TASKS	64
+#define NR_TASKS	128
 
 #endif
diff --git a/include/linux/termios.h b/include/linux/termios.h
index 8fd2bde..741c24e 100644
--- a/include/linux/termios.h
+++ b/include/linux/termios.h
@@ -55,8 +55,8 @@
 #define TIOCPKT_FLUSHWRITE	 2
 #define TIOCPKT_STOP		 4
 #define TIOCPKT_START		 8
-#define TIOCPKT_DOSTOP		16
-#define TIOCPKT_NOSTOP		32
+#define TIOCPKT_NOSTOP		16
+#define TIOCPKT_DOSTOP		32
 
 struct winsize {
 	unsigned short ws_row;
diff --git a/include/linux/timer.h b/include/linux/timer.h
index 4cf602f..59ae295 100644
--- a/include/linux/timer.h
+++ b/include/linux/timer.h
@@ -17,6 +17,8 @@
  * 
  * HD_TIMER		harddisk timer
  *
+ * HD_TIMER2		(atdisk2 patches)
+ *
  * FLOPPY_TIMER		floppy disk timer (not used right now)
  * 
  * SCSI_TIMER		scsi.c timeout timer
@@ -44,6 +46,8 @@
 #define TAPE_QIC02_TIMER	22	/* hhb */
 #define MCD_TIMER	23
 
+#define HD_TIMER2	24
+
 struct timer_struct {
 	unsigned long expires;
 	void (*fn)(void);
diff --git a/include/linux/xd.h b/include/linux/xd.h
index 17bc3dc..f90822a 100644
--- a/include/linux/xd.h
+++ b/include/linux/xd.h
@@ -105,8 +105,6 @@
 	char *name;
 } XD_SIGNATURE;
 
-extern void resetup_one_dev (struct gendisk *dev,unsigned int drive);
-
 u_long xd_init(u_long mem_start,u_long mem_end);
 static u_char xd_detect (u_char *controller,u_char **address);
 static u_char xd_initdrives (void (*init_drive)(u_char drive));
diff --git a/init/main.c b/init/main.c
index 6d0b17b..09ff447 100644
--- a/init/main.c
+++ b/init/main.c
@@ -23,12 +23,13 @@
 #include <linux/ctype.h>
 #include <linux/delay.h>
 #include <linux/utsname.h>
+#include <linux/ioport.h>
 
 extern unsigned long * prof_buffer;
 extern unsigned long prof_len;
 extern char edata, end;
 extern char *linux_banner;
-extern "C" void lcall7(void);
+asmlinkage void lcall7(void);
 struct desc_struct default_ldt;
 
 /*
@@ -43,6 +44,7 @@
  * won't be any messing with the stack from main(), but we define
  * some others too.
  */
+#define __NR__exit __NR_exit
 static inline _syscall0(int,idle)
 static inline _syscall0(int,fork)
 static inline _syscall0(int,pause)
@@ -54,7 +56,7 @@
 static inline _syscall3(int,execve,const char *,file,char **,argv,char **,envp)
 static inline _syscall3(int,open,const char *,file,int,flag,int,mode)
 static inline _syscall1(int,close,int,fd)
-static inline _syscall1(int,exit,int,exitcode)
+static inline _syscall1(int,_exit,int,exitcode)
 static inline _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options)
 
 static inline pid_t wait(int * wait_stat)
@@ -189,6 +191,7 @@
 	char *str;
 	void (*setup_func)(char *, int *);
 } bootsetups[] = {
+	{ "reserve=", reserve_setup },
 #ifdef CONFIG_INET
 	{ "ether=", eth_setup },
 #endif
@@ -329,7 +332,7 @@
 	outb_p(0,0xf0);
 }
 
-extern "C" void start_kernel(void)
+asmlinkage void start_kernel(void)
 {
 /*
  * Interrupts are still disabled. Do necessary setups, then
@@ -466,9 +469,9 @@
 	if (!(pid=fork())) {
 		close(0);
 		if (open("/etc/rc",O_RDONLY,0))
-			exit(1);
+			_exit(1);
 		execve("/bin/sh",argv_rc,envp_rc);
-		exit(2);
+		_exit(2);
 	}
 	if (pid>0)
 		while (pid != wait(&i))
@@ -484,7 +487,7 @@
 			(void) open("/dev/tty1",O_RDWR,0);
 			(void) dup(0);
 			(void) dup(0);
-			exit(execve("/bin/sh",argv,envp));
+			_exit(execve("/bin/sh",argv,envp));
 		}
 		while (1)
 			if (pid == wait(&i))
@@ -492,5 +495,5 @@
 		printf("\n\rchild %d died with code %04x\n\r",pid,i);
 		sync();
 	}
-	exit(0);
+	_exit(0);
 }
diff --git a/ipc/shm.c b/ipc/shm.c
index 2e2c1b3..69b14ec 100644
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -338,7 +338,7 @@
 		page_table = PAGE_DIR_OFFSET(page_dir,tmp);
 		if (*page_table & PAGE_PRESENT) {
 			page_table = (ulong *) (PAGE_MASK & *page_table);
-			page_table += ((tmp >> PAGE_SHIFT) & PTRS_PER_PAGE-1);
+			page_table += ((tmp >> PAGE_SHIFT) & (PTRS_PER_PAGE-1));
 			if (*page_table) {
 				if (!remap)
 					return -EINVAL;
@@ -368,7 +368,7 @@
 	     shm_sgn += (1 << SHM_IDX_SHIFT)) { 
 		page_table = PAGE_DIR_OFFSET(page_dir,tmp);
 		page_table = (ulong *) (PAGE_MASK & *page_table);
-		page_table += (tmp >> PAGE_SHIFT) & PTRS_PER_PAGE-1;
+		page_table += (tmp >> PAGE_SHIFT) & (PTRS_PER_PAGE-1);
 		*page_table = shm_sgn;
 	}
 	return 0;
@@ -697,7 +697,7 @@
 			continue;
 		} 
 		pte = (ulong *) (PAGE_MASK & *pte);
-		pte += ((tmp >> PAGE_SHIFT) & PTRS_PER_PAGE-1);
+		pte += ((tmp >> PAGE_SHIFT) & (PTRS_PER_PAGE-1));
 		tmp = *pte;
 		if (!(tmp & PAGE_PRESENT))
 			continue;
diff --git a/ipc/util.c b/ipc/util.c
index 46dc00d..c7bebd7 100644
--- a/ipc/util.c
+++ b/ipc/util.c
@@ -13,7 +13,7 @@
 #include <linux/stat.h>
 
 void ipc_init (void);
-extern "C" int sys_ipc (uint call, int first, int second, int third, void *ptr); 
+asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr); 
 
 #ifdef CONFIG_SYSVIPC
 
@@ -67,7 +67,7 @@
 	return 0;
 }
 
-extern "C" int sys_ipc (uint call, int first, int second, int third, void *ptr) 
+asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr) 
 {
 	
 	if (call <= SEMCTL)
@@ -123,7 +123,7 @@
 
 #else /* not CONFIG_SYSVIPC */
 
-extern "C" int sys_ipc (uint call, int first, int second, int third, void *ptr) 
+asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr) 
 {
     return -ENOSYS;
 }
diff --git a/kernel/FPU-emu/errors.c b/kernel/FPU-emu/errors.c
index d7619ce..444a8af 100644
--- a/kernel/FPU-emu/errors.c
+++ b/kernel/FPU-emu/errors.c
@@ -42,7 +42,7 @@
   byte1 = get_fs_byte((unsigned char *) FPU_ORIG_EIP);
   FPU_modrm = get_fs_byte(1 + (unsigned char *) FPU_ORIG_EIP);
 
-  printk("Unimplemented FPU Opcode at eip=%p : %02x ",
+  printk("Unimplemented FPU Opcode at eip=%08x : %02x ",
 	 FPU_ORIG_EIP, byte1);
 
   if (FPU_modrm >= 0300)
@@ -86,7 +86,7 @@
 if ( partial_status & SW_Invalid )     printk("SW: invalid operation\n");
 #endif DEBUGGING
 
-  printk("At %p: %02x ", FPU_ORIG_EIP, byte1);
+  printk("At %08x: %02x ", FPU_ORIG_EIP, byte1);
   if (FPU_modrm >= 0300)
     printk("%02x (%02x+%d)\n", FPU_modrm, FPU_modrm & 0xf8, FPU_modrm & 7);
   else
@@ -312,7 +312,7 @@
 
 /* Real operation attempted on two operands, one a NaN. */
 /* Returns nz if the exception is unmasked */
-extern "C" int real_2op_NaN(FPU_REG *a, FPU_REG *b, FPU_REG *dest)
+asmlinkage int real_2op_NaN(FPU_REG *a, FPU_REG *b, FPU_REG *dest)
 {
   FPU_REG *x;
   int signalling;
@@ -326,7 +326,7 @@
 	{
 	  signalling = !(a->sigh & b->sigh & 0x40000000);
 	  /* find the "larger" */
-	  if ( *(long long *)&(a->sigl) < *(long long *)&(b->sigl) )
+	  if ( significand(a) < significand(b) )
 	    x = b;
 	}
       else
@@ -378,7 +378,7 @@
 
 /* Invalid arith operation on Valid registers */
 /* Returns nz if the exception is unmasked */
-extern "C" int arith_invalid(FPU_REG *dest)
+asmlinkage int arith_invalid(FPU_REG *dest)
 {
 
   EXCEPTION(EX_Invalid);
@@ -395,7 +395,7 @@
 
 
 /* Divide a finite number by zero */
-extern "C" int divide_by_zero(int sign, FPU_REG *dest)
+asmlinkage int divide_by_zero(int sign, FPU_REG *dest)
 {
 
   if ( control_word & CW_ZeroDiv )
@@ -430,7 +430,7 @@
 
 
 /* This may be called often, so keep it lean */
-extern "C" void set_precision_flag_up(void)
+asmlinkage void set_precision_flag_up(void)
 {
   if ( control_word & CW_Precision )
     partial_status |= (SW_Precision | SW_C1);   /* The masked response */
@@ -441,7 +441,7 @@
 
 
 /* This may be called often, so keep it lean */
-extern "C" void set_precision_flag_down(void)
+asmlinkage void set_precision_flag_down(void)
 {
   if ( control_word & CW_Precision )
     {   /* The masked response */
@@ -453,7 +453,7 @@
 }
 
 
-extern "C" int denormal_operand(void)
+asmlinkage int denormal_operand(void)
 {
   if ( control_word & CW_Denormal )
     {   /* The masked response */
@@ -468,7 +468,7 @@
 }
 
 
-extern "C" int arith_overflow(FPU_REG *dest)
+asmlinkage int arith_overflow(FPU_REG *dest)
 {
 
   if ( control_word & CW_Overflow )
@@ -502,7 +502,7 @@
 }
 
 
-extern "C" int arith_underflow(FPU_REG *dest)
+asmlinkage int arith_underflow(FPU_REG *dest)
 {
 
   if ( control_word & CW_Underflow )
diff --git a/kernel/FPU-emu/fpu_arith.c b/kernel/FPU-emu/fpu_arith.c
index b81e658..471d2c6 100644
--- a/kernel/FPU-emu/fpu_arith.c
+++ b/kernel/FPU-emu/fpu_arith.c
@@ -19,10 +19,7 @@
 void fadd__()
 {
   /* fadd st,st(i) */
-#ifdef PECULIAR_486
-  /* Default, this conveys no information, but an 80486 does it. */
   clear_C1();
-#endif PECULIAR_486
   reg_add(FPU_st0_ptr, &st(FPU_rm), FPU_st0_ptr, control_word);
 }
 
@@ -30,10 +27,7 @@
 void fmul__()
 {
   /* fmul st,st(i) */
-#ifdef PECULIAR_486
-  /* Default, this conveys no information, but an 80486 does it. */
   clear_C1();
-#endif PECULIAR_486
   reg_mul(FPU_st0_ptr, &st(FPU_rm), FPU_st0_ptr, control_word);
 }
 
@@ -42,10 +36,7 @@
 void fsub__()
 {
   /* fsub st,st(i) */
-#ifdef PECULIAR_486
-  /* Default, this conveys no information, but an 80486 does it. */
   clear_C1();
-#endif PECULIAR_486
   reg_sub(FPU_st0_ptr, &st(FPU_rm), FPU_st0_ptr, control_word);
 }
 
@@ -53,10 +44,7 @@
 void fsubr_()
 {
   /* fsubr st,st(i) */
-#ifdef PECULIAR_486
-  /* Default, this conveys no information, but an 80486 does it. */
   clear_C1();
-#endif PECULIAR_486
   reg_sub(&st(FPU_rm), FPU_st0_ptr, FPU_st0_ptr, control_word);
 }
 
@@ -64,10 +52,7 @@
 void fdiv__()
 {
   /* fdiv st,st(i) */
-#ifdef PECULIAR_486
-  /* Default, this conveys no information, but an 80486 does it. */
   clear_C1();
-#endif PECULIAR_486
   reg_div(FPU_st0_ptr, &st(FPU_rm), FPU_st0_ptr, control_word);
 }
 
@@ -75,10 +60,7 @@
 void fdivr_()
 {
   /* fdivr st,st(i) */
-#ifdef PECULIAR_486
-  /* Default, this conveys no information, but an 80486 does it. */
   clear_C1();
-#endif PECULIAR_486
   reg_div(&st(FPU_rm), FPU_st0_ptr, FPU_st0_ptr, control_word);
 }
 
@@ -87,10 +69,7 @@
 void fadd_i()
 {
   /* fadd st(i),st */
-#ifdef PECULIAR_486
-  /* Default, this conveys no information, but an 80486 does it. */
   clear_C1();
-#endif PECULIAR_486
   reg_add(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm), control_word);
 }
 
@@ -98,10 +77,7 @@
 void fmul_i()
 {
   /* fmul st(i),st */
-#ifdef PECULIAR_486
-  /* Default, this conveys no information, but an 80486 does it. */
   clear_C1();
-#endif PECULIAR_486
   reg_mul(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm), control_word);
 }
 
@@ -111,10 +87,7 @@
   /* fsubr st(i),st */
   /* This is the sense of the 80486 manual
      reg_sub(&st(FPU_rm), FPU_st0_ptr, &st(FPU_rm), control_word); */
-#ifdef PECULIAR_486
-  /* Default, this conveys no information, but an 80486 does it. */
   clear_C1();
-#endif PECULIAR_486
   reg_sub(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm), control_word);
 }
 
@@ -124,10 +97,7 @@
   /* fsub st(i),st */
   /* This is the sense of the 80486 manual
      reg_sub(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm), control_word); */
-#ifdef PECULIAR_486
-  /* Default, this conveys no information, but an 80486 does it. */
   clear_C1();
-#endif PECULIAR_486
   reg_sub(&st(FPU_rm), FPU_st0_ptr, &st(FPU_rm), control_word);
 }
 
@@ -135,10 +105,7 @@
 void fdivri()
 {
   /* fdivr st(i),st */
-#ifdef PECULIAR_486
-  /* Default, this conveys no information, but an 80486 does it. */
   clear_C1();
-#endif PECULIAR_486
   reg_div(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm), control_word);
 }
 
@@ -146,10 +113,7 @@
 void fdiv_i()
 {
   /* fdiv st(i),st */
-#ifdef PECULIAR_486
-  /* Default, this conveys no information, but an 80486 does it. */
   clear_C1();
-#endif PECULIAR_486
   reg_div(&st(FPU_rm), FPU_st0_ptr, &st(FPU_rm), control_word);
 }
 
@@ -158,10 +122,7 @@
 void faddp_()
 {
   /* faddp st(i),st */
-#ifdef PECULIAR_486
-  /* Default, this conveys no information, but an 80486 does it. */
   clear_C1();
-#endif PECULIAR_486
   if ( !reg_add(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm), control_word) )
     pop();
 }
@@ -170,10 +131,7 @@
 void fmulp_()
 {
   /* fmulp st(i),st */
-#ifdef PECULIAR_486
-  /* Default, this conveys no information, but an 80486 does it. */
   clear_C1();
-#endif PECULIAR_486
   if ( !reg_mul(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm), control_word) )
     pop();
 }
@@ -185,10 +143,7 @@
   /* fsubrp st(i),st */
   /* This is the sense of the 80486 manual
      reg_sub(&st(FPU_rm), FPU_st0_ptr, &st(FPU_rm), control_word); */
-#ifdef PECULIAR_486
-  /* Default, this conveys no information, but an 80486 does it. */
   clear_C1();
-#endif PECULIAR_486
   if ( !reg_sub(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm), control_word) )
     pop();
 }
@@ -199,10 +154,7 @@
   /* fsubp st(i),st */
   /* This is the sense of the 80486 manual
      reg_sub(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm), control_word); */
-#ifdef PECULIAR_486
-  /* Default, this conveys no information, but an 80486 does it. */
   clear_C1();
-#endif PECULIAR_486
   if ( !reg_sub(&st(FPU_rm), FPU_st0_ptr, &st(FPU_rm), control_word) )
     pop();
 }
@@ -211,10 +163,7 @@
 void fdivrp()
 {
   /* fdivrp st(i),st */
-#ifdef PECULIAR_486
-  /* Default, this conveys no information, but an 80486 does it. */
   clear_C1();
-#endif PECULIAR_486
   if ( !reg_div(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm), control_word) )
     pop();
 }
@@ -223,10 +172,7 @@
 void fdivp_()
 {
   /* fdivp st(i),st */
-#ifdef PECULIAR_486
-  /* Default, this conveys no information, but an 80486 does it. */
   clear_C1();
-#endif PECULIAR_486
   if ( !reg_div(&st(FPU_rm), FPU_st0_ptr, &st(FPU_rm), control_word) )
     pop();
 }
diff --git a/kernel/FPU-emu/fpu_aux.c b/kernel/FPU-emu/fpu_aux.c
index e9f2bd2..90301a4 100644
--- a/kernel/FPU-emu/fpu_aux.c
+++ b/kernel/FPU-emu/fpu_aux.c
@@ -139,10 +139,7 @@
       stack_underflow();
       return;
     }
-#ifdef PECULIAR_486
-  /* Default, this conveys no information, but an 80486 does it. */
   clear_C1();
-#endif PECULIAR_486
   reg_move(FPU_st0_ptr, &t);
   reg_move(sti_ptr, FPU_st0_ptr);
   reg_move(&t, sti_ptr);
diff --git a/kernel/FPU-emu/fpu_emu.h b/kernel/FPU-emu/fpu_emu.h
index a0c906a..7b871fd 100644
--- a/kernel/FPU-emu/fpu_emu.h
+++ b/kernel/FPU-emu/fpu_emu.h
@@ -58,6 +58,7 @@
 #ifndef __ASSEMBLER__
 
 #include <linux/math_emu.h>
+#include <linux/linkage.h>
 
 #ifdef PARANOID
 extern char emulating;
@@ -110,33 +111,36 @@
 		 *(long *)&((y)->exp) = *(long *)&((x)->exp); \
 		 *(long long *)&((y)->sigl) = *(long long *)&((x)->sigl); }
 
+#define significand(x) ( ((unsigned long long *)&((x)->sigl))[0] )
+
 
 /*----- Prototypes for functions written in assembler -----*/
 /* extern void reg_move(FPU_REG *a, FPU_REG *b); */
 
-extern "C" void mul64(long long *a, long long *b, long long *result);
-extern "C" void poly_div2(long long *x);
-extern "C" void poly_div4(long long *x);
-extern "C" void poly_div16(long long *x);
-extern "C" void polynomial(unsigned accum[], unsigned x[],
+asmlinkage void mul64(unsigned long long *a, unsigned long long *b,
+		      unsigned long long *result);
+asmlinkage void poly_div2(unsigned long long *x);
+asmlinkage void poly_div4(unsigned long long *x);
+asmlinkage void poly_div16(unsigned long long *x);
+asmlinkage void polynomial(unsigned accum[], unsigned x[],
 		       unsigned short terms[][4], int n);
-extern "C" void normalize(FPU_REG *x);
-extern "C" void normalize_nuo(FPU_REG *x);
-extern "C" int reg_div(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *answ,
+asmlinkage void normalize(FPU_REG *x);
+asmlinkage void normalize_nuo(FPU_REG *x);
+asmlinkage int reg_div(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *answ,
 		    unsigned int control_w);
-extern "C" int reg_u_sub(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *answ,
+asmlinkage int reg_u_sub(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *answ,
 		      unsigned int control_w);
-extern "C" int reg_u_mul(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *answ,
+asmlinkage int reg_u_mul(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *answ,
 		      unsigned int control_w);
-extern "C" int reg_u_div(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *answ,
+asmlinkage int reg_u_div(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *answ,
 		      unsigned int control_w);
-extern "C" int reg_u_add(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *answ,
+asmlinkage int reg_u_add(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *answ,
 		      unsigned int control_w);
-extern "C" int wm_sqrt(FPU_REG *n, unsigned int control_w);
-extern "C" unsigned	shrx(void *l, unsigned x);
-extern "C" unsigned	shrxs(void *v, unsigned x);
-extern "C" unsigned long div_small(unsigned long long *x, unsigned long y);
-extern "C" void round_reg(FPU_REG *arg, unsigned int extent,
+asmlinkage int wm_sqrt(FPU_REG *n, unsigned int control_w);
+asmlinkage unsigned	shrx(void *l, unsigned x);
+asmlinkage unsigned	shrxs(void *v, unsigned x);
+asmlinkage unsigned long div_small(unsigned long long *x, unsigned long y);
+asmlinkage void round_reg(FPU_REG *arg, unsigned int extent,
 		      unsigned int control_w);
 
 #ifndef MAKING_PROTO
diff --git a/kernel/FPU-emu/fpu_entry.c b/kernel/FPU-emu/fpu_entry.c
index b3e188e..6bbe3c4 100644
--- a/kernel/FPU-emu/fpu_entry.c
+++ b/kernel/FPU-emu/fpu_entry.c
@@ -155,7 +155,7 @@
 static int valid_prefix(unsigned char byte);
 
 
-extern "C" void math_emulate(long arg)
+asmlinkage void math_emulate(long arg)
 {
   unsigned char  FPU_modrm;
   unsigned short code;
@@ -183,7 +183,7 @@
       current->used_math = 1;
     }
 
-  FPU_info = (struct info *) &arg;
+  SETUP_DATA_AREA(arg);
 
   /* We cannot handle emulation in v86-mode */
   if (FPU_EFLAGS & 0x00020000)
@@ -401,20 +401,12 @@
 	      switch ( (FPU_modrm >> 3) & 7 )
 		{
 		case 0:         /* fadd */
-#ifdef PECULIAR_486
-		  /* Default, this conveys no information,
-		     but an 80486 does it. */
 		  clear_C1();
-#endif PECULIAR_486
 		  reg_add(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr,
 			  control_word);
 		  break;
 		case 1:         /* fmul */
-#ifdef PECULIAR_486
-		  /* Default, this conveys no information,
-		     but an 80486 does it. */
 		  clear_C1();
-#endif PECULIAR_486
 		  reg_mul(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr,
 			  control_word);
 		  break;
@@ -426,38 +418,22 @@
 		    pop();
 		  break;
 		case 4:         /* fsub */
-#ifdef PECULIAR_486
-		  /* Default, this conveys no information,
-		     but an 80486 does it. */
 		  clear_C1();
-#endif PECULIAR_486
 		  reg_sub(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr,
 			  control_word);
 		  break;
 		case 5:         /* fsubr */
-#ifdef PECULIAR_486
-		  /* Default, this conveys no information,
-		     but an 80486 does it. */
 		  clear_C1();
-#endif PECULIAR_486
 		  reg_sub(&FPU_loaded_data, FPU_st0_ptr, FPU_st0_ptr,
 			  control_word);
 		  break;
 		case 6:         /* fdiv */
-#ifdef PECULIAR_486
-		  /* Default, this conveys no information,
-		     but an 80486 does it. */
 		  clear_C1();
-#endif PECULIAR_486
 		  reg_div(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr,
 			  control_word);
 		  break;
 		case 7:         /* fdivr */
-#ifdef PECULIAR_486
-		  /* Default, this conveys no information,
-		     but an 80486 does it. */
 		  clear_C1();
-#endif PECULIAR_486
 		  if ( FPU_st0_tag == TW_Zero )
 		    partial_status = status1;  /* Undo any denorm tag,
 					       zero-divide has priority. */
@@ -637,7 +613,7 @@
 #include <linux/signal.h>
 #include <linux/sched.h>
 
-extern "C" void math_emulate(long arg)
+asmlinkage void math_emulate(long arg)
 {
   printk("math-emulation not enabled and no coprocessor found.\n");
   printk("killing %s.\n",current->comm);
diff --git a/kernel/FPU-emu/fpu_etc.c b/kernel/FPU-emu/fpu_etc.c
index f8aee63..7c4535f 100644
--- a/kernel/FPU-emu/fpu_etc.c
+++ b/kernel/FPU-emu/fpu_etc.c
@@ -22,10 +22,7 @@
   if ( NOT_EMPTY_0 )
     {
       FPU_st0_ptr->sign ^= SIGN_POS^SIGN_NEG;
-#ifdef PECULIAR_486
-      /* Default, this conveys no information, but an 80486 does it. */
       clear_C1();
-#endif PECULIAR_486
     }
   else
     stack_underflow();
@@ -36,10 +33,7 @@
   if ( FPU_st0_tag ^ TW_Empty )
     {
       FPU_st0_ptr->sign = SIGN_POS;
-#ifdef PECULIAR_486
-      /* Default, this conveys no information, but an 80486 does it. */
       clear_C1();
-#endif PECULIAR_486
     }
   else
     stack_underflow();
diff --git a/kernel/FPU-emu/fpu_proto.h b/kernel/FPU-emu/fpu_proto.h
index ac14a1e..b7e7032 100644
--- a/kernel/FPU-emu/fpu_proto.h
+++ b/kernel/FPU-emu/fpu_proto.h
@@ -6,15 +6,15 @@
 extern void stack_underflow_i(int i);
 extern void stack_underflow_pop(int i);
 extern int set_precision_flag(int flags);
-extern "C" void exception(int n);
-extern "C" int real_2op_NaN(FPU_REG *a, FPU_REG *b, FPU_REG *dest);
-extern "C" int arith_invalid(FPU_REG *dest);
-extern "C" int divide_by_zero(int sign, FPU_REG *dest);
-extern "C" void set_precision_flag_up(void);
-extern "C" void set_precision_flag_down(void);
-extern "C" int denormal_operand(void);
-extern "C" int arith_overflow(FPU_REG *dest);
-extern "C" int arith_underflow(FPU_REG *dest);
+asmlinkage void exception(int n);
+asmlinkage int real_2op_NaN(FPU_REG *a, FPU_REG *b, FPU_REG *dest);
+asmlinkage int arith_invalid(FPU_REG *dest);
+asmlinkage int divide_by_zero(int sign, FPU_REG *dest);
+asmlinkage void set_precision_flag_up(void);
+asmlinkage void set_precision_flag_down(void);
+asmlinkage int denormal_operand(void);
+asmlinkage int arith_overflow(FPU_REG *dest);
+asmlinkage int arith_underflow(FPU_REG *dest);
 
 /* fpu_arith.c */
 extern void fadd__(void);
@@ -50,7 +50,7 @@
 extern void fstp_i(void);
 
 /* fpu_entry.c */
-extern "C" void math_emulate(long arg);
+asmlinkage void math_emulate(long arg);
 extern void __math_abort(struct info *info, unsigned int signal);
 
 /* fpu_etc.c */
diff --git a/kernel/FPU-emu/fpu_system.h b/kernel/FPU-emu/fpu_system.h
index 080ed06..be6b0bb 100644
--- a/kernel/FPU-emu/fpu_system.h
+++ b/kernel/FPU-emu/fpu_system.h
@@ -14,6 +14,10 @@
 #include <linux/sched.h>
 #include <linux/kernel.h>
 
+/* This sets the pointer FPU_info to point to the argument part
+   of the stack frame of math_emulate() */
+#define SETUP_DATA_AREA(arg)    FPU_info = (struct info *) &arg
+
 #define I387			(current->tss.i387)
 #define FPU_info		(I387.soft.info)
 
diff --git a/kernel/FPU-emu/fpu_trig.c b/kernel/FPU-emu/fpu_trig.c
index cd49903..d20c4db 100644
--- a/kernel/FPU-emu/fpu_trig.c
+++ b/kernel/FPU-emu/fpu_trig.c
@@ -20,13 +20,14 @@
 
 static void rem_kernel(unsigned long long st0, unsigned long long *y,
 		       unsigned long long st1,
-		       long long q, int n);
+		       unsigned long long q, int n);
 
 #define BETTER_THAN_486
 
 #define FCOS  4
 #define FPTAN 1
 
+
 /* Used only by fptan, fsin, fcos, and fsincos. */
 /* This routine produces very accurate results, similar to
    using a value of pi with more than 128 bits precision. */
@@ -36,7 +37,7 @@
 static int trig_arg(FPU_REG *X, int even)
 {
   FPU_REG tmp;
-  long long q;
+  unsigned long long q;
   int old_cw = control_word, saved_status = partial_status;
 
   if ( X->exp >= EXP_BIAS + 63 )
@@ -51,12 +52,12 @@
   reg_div(X, &CONST_PI2, &tmp, PR_64_BITS | RC_CHOP | 0x3f);
   round_to_int(&tmp);  /* Fortunately, this can't overflow
 			  to 2^64 */
-  q = ((long long *)&(tmp.sigl))[0];
+  q = significand(&tmp);
   if ( q )
     {
-      rem_kernel(((unsigned long long *)&(X->sigl))[0],
-		 (unsigned long long *)&(tmp.sigl),
-		 ((unsigned long long *)&(CONST_PI2.sigl))[0],
+      rem_kernel(significand(X),
+		 &significand(&tmp),
+		 significand(&CONST_PI2),
 		 q, X->exp - CONST_PI2.exp);
       tmp.exp = CONST_PI2.exp;
       normalize(&tmp);
@@ -85,7 +86,7 @@
 	{
 	  /* This code gives the effect of having p/2 to better than
 	     128 bits precision. */
-	  ((long long *)&(tmp.sigl))[0] = q + 1;
+	  significand(&tmp) = q + 1;
 	  tmp.exp = EXP_BIAS + 63;
 	  normalize(&tmp);
 	  reg_mul(&CONST_PI2extra, &tmp, &tmp, FULL_PRECISION);
@@ -104,7 +105,7 @@
 	{
 	  /* This code gives the effect of having p/2 to better than
 	     128 bits precision. */
-	  ((long long *)&(tmp.sigl))[0] = q;
+	  significand(&tmp) = q;
 	  tmp.exp = EXP_BIAS + 63;
 	  normalize(&tmp);
 	  reg_mul(&CONST_PI2extra, &tmp, &tmp, FULL_PRECISION);
@@ -204,10 +205,7 @@
 
 static void f2xm1(void)
 {
-#ifdef PECULIAR_486
-  /* Default, this conveys no information, but an 80486 does it. */
   clear_C1();
-#endif PECULIAR_486
   switch ( FPU_st0_tag )
     {
     case TW_Valid:
@@ -363,11 +361,7 @@
 
   if ( STACK_OVERFLOW )
     {  stack_overflow(); return; }
-
-#ifdef PECULIAR_486
-  /* Default, this conveys no information, but an 80486 does it. */
   clear_C1();
-#endif PECULIAR_486
   if ( !(FPU_st0_tag ^ TW_Valid) )
     {
       long e;
@@ -432,29 +426,20 @@
 
 static void fdecstp(void)
 {
-#ifdef PECULIAR_486
-  /* Default, this conveys no information, but an 80486 does it. */
   clear_C1();
-#endif PECULIAR_486
   top--;  /* FPU_st0_ptr will be fixed in math_emulate() before the next instr */
 }
 
 static void fincstp(void)
 {
-#ifdef PECULIAR_486
-  /* Default, this conveys no information, but an 80486 does it. */
   clear_C1();
-#endif PECULIAR_486
   top++;  /* FPU_st0_ptr will be fixed in math_emulate() before the next instr */
 }
 
 
 static void fsqrt_(void)
 {
-#ifdef PECULIAR_486
-  /* Default, this conveys no information, but an 80486 does it. */
   clear_C1();
-#endif PECULIAR_486
   if ( !(FPU_st0_tag ^ TW_Valid) )
     {
       int expon;
@@ -729,7 +714,7 @@
  */
 static void rem_kernel(unsigned long long st0, unsigned long long *y,
 		       unsigned long long st1,
-		       long long q, int n)
+		       unsigned long long q, int n)
 {
   unsigned long long x;
 
@@ -790,11 +775,11 @@
 		{
 		  round_to_int(&tmp);  /* Fortunately, this can't overflow
 					  to 2^64 */
-		  q = ((long long *)&(tmp.sigl))[0];
+		  q = significand(&tmp);
 
-		  rem_kernel(((unsigned long long *)&(FPU_st0_ptr->sigl))[0],
-			     (unsigned long long *)&(tmp.sigl),
-			     ((unsigned long long *)&(st1_ptr->sigl))[0],
+		  rem_kernel(significand(FPU_st0_ptr),
+			     &significand(&tmp),
+			     significand(st1_ptr),
 			     q, expdif);
 
 		  tmp.exp = st1_ptr->exp;
@@ -808,14 +793,24 @@
 
 	      if ( (round == RC_RND) && (tmp.sigh & 0xc0000000) )
 		{
-		  /* We may need to subtract st(1) once more. */
+		  /* We may need to subtract st(1) once more,
+		     to get a result <= 1/2 of st(1). */
 		  unsigned long long x;
-		  x = ((unsigned long long *)&(st1_ptr->sigl))[0] -
-		    ((unsigned long long *)&(tmp.sigl))[0];
-		  if ( x < ((unsigned long long *)&(tmp.sigl))[0] )
+		  expdif = st1_ptr->exp - tmp.exp;
+		  if ( expdif <= 1 )
 		    {
-		      tmp.sign ^= (SIGN_POS^SIGN_NEG);
-		      ((unsigned long long *)&(tmp.sigl))[0] = x;
+		      if ( expdif == 0 )
+			x = significand(st1_ptr) - significand(&tmp);
+		      else /* expdif is 1 */
+			x = (significand(st1_ptr) << 1) - significand(&tmp);
+		      if ( (x < significand(&tmp)) ||
+			  /* or equi-distant (from 0 & st(1)) and q is odd */
+			  ((x == significand(&tmp)) && (q & 1) ) )
+			{
+			  tmp.sign ^= (SIGN_POS^SIGN_NEG);
+			  significand(&tmp) = x;
+			  q++;
+			}
 		    }
 		}
 
@@ -849,10 +844,10 @@
 
 	  round_to_int(&tmp);  /* Fortunately, this can't overflow to 2^64 */
 
-	  rem_kernel(((unsigned long long *)&(FPU_st0_ptr->sigl))[0],
-		     ((unsigned long long *)&(tmp.sigl)),
-		     ((unsigned long long *)&(st1_ptr->sigl))[0],
-		     ((long long *)&(tmp.sigl))[0],
+	  rem_kernel(significand(FPU_st0_ptr),
+		     &significand(&tmp),
+		     significand(st1_ptr),
+		     significand(&tmp),
 		     tmp.exp - EXP_BIAS
 		     ); 
 	  tmp.exp = exp_1 + expdif;
@@ -882,13 +877,15 @@
 
       control_word = old_cw;
       partial_status = saved_status;
-      normalize(&tmp);
+      normalize_nuo(&tmp);
       reg_move(&tmp, FPU_st0_ptr);
       setcc(cc);
 
-      if ( FPU_st0_ptr->tag != TW_Zero )
-	/* Use round_reg() to properly detect under/overflow etc */
-	round_reg(FPU_st0_ptr, 0, control_word);
+      /* The only condition to be looked for is underflow,
+	 and it can occur here only if underflow is unmasked. */
+      if ( (FPU_st0_ptr->exp <= EXP_UNDER) && (FPU_st0_ptr->tag != TW_Zero)
+	  && !(control_word & CW_Underflow) )
+	arith_underflow(FPU_st0_ptr);
 
       return;
     }
@@ -961,10 +958,7 @@
   FPU_REG *st1_ptr = &st(1);
   char st1_tag = st1_ptr->tag;
 
-#ifdef PECULIAR_486
-  /* Default, this conveys no information, but an 80486 does it. */
   clear_C1();
-#endif PECULIAR_486
   if ( !((FPU_st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid)) )
     {
       if ( FPU_st0_ptr->sign == SIGN_POS )
@@ -1155,10 +1149,7 @@
   char st1_tag = st1_ptr->tag;
   char st1_sign = st1_ptr->sign, st0_sign = FPU_st0_ptr->sign;
 
-#ifdef PECULIAR_486
-  /* Default, this conveys no information, but an 80486 does it. */
   clear_C1();
-#endif PECULIAR_486
   if ( !((FPU_st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid)) )
     {
       int saved_control, saved_status;
@@ -1336,10 +1327,7 @@
   FPU_REG *st1_ptr = &st(1);
   char st1_tag = st1_ptr->tag;
 
-#ifdef PECULIAR_486
-  /* Default, this conveys no information, but an 80486 does it. */
   clear_C1();
-#endif PECULIAR_486
   if ( !((FPU_st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid)) )
     {
       int saved_control, saved_status;
@@ -1560,10 +1548,7 @@
   int old_cw = control_word;
   char sign = FPU_st0_ptr->sign;
 
-#ifdef PECULIAR_486
-  /* Default, this conveys no information, but an 80486 does it. */
   clear_C1();
-#endif PECULIAR_486
   if ( !((FPU_st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid)) )
     {
       long scale;
diff --git a/kernel/FPU-emu/load_store.c b/kernel/FPU-emu/load_store.c
index 33affc0..6e4b3d9 100644
--- a/kernel/FPU-emu/load_store.c
+++ b/kernel/FPU-emu/load_store.c
@@ -84,10 +84,7 @@
 switch ( type )
   {
   case 000:       /* fld m32real */
-#ifdef PECULIAR_486
-    /* Default, this conveys no information, but an 80486 does it. */
     clear_C1();
-#endif PECULIAR_486
     reg_load_single();
     if ( (FPU_loaded_data.tag == TW_NaN) &&
 	real_2op_NaN(&FPU_loaded_data, &FPU_loaded_data, &FPU_loaded_data) )
@@ -98,18 +95,12 @@
     reg_move(&FPU_loaded_data, pop_ptr);
     break;
   case 001:      /* fild m32int */
-#ifdef PECULIAR_486
-    /* Default, this conveys no information, but an 80486 does it. */
     clear_C1();
-#endif PECULIAR_486
     reg_load_int32();
     reg_move(&FPU_loaded_data, pop_ptr);
     break;
   case 002:      /* fld m64real */
-#ifdef PECULIAR_486
-    /* Default, this conveys no information, but an 80486 does it. */
     clear_C1();
-#endif PECULIAR_486
     reg_load_double();
     if ( (FPU_loaded_data.tag == TW_NaN) &&
 	real_2op_NaN(&FPU_loaded_data, &FPU_loaded_data, &FPU_loaded_data) )
@@ -120,73 +111,46 @@
     reg_move(&FPU_loaded_data, pop_ptr);
     break;
   case 003:      /* fild m16int */
-#ifdef PECULIAR_486
-    /* Default, this conveys no information, but an 80486 does it. */
     clear_C1();
-#endif PECULIAR_486
     reg_load_int16();
     reg_move(&FPU_loaded_data, pop_ptr);
     break;
   case 010:      /* fst m32real */
-#ifdef PECULIAR_486
-    /* Default, this conveys no information, but an 80486 does it. */
     clear_C1();
-#endif PECULIAR_486
     reg_store_single();
     break;
   case 011:      /* fist m32int */
-#ifdef PECULIAR_486
-    /* Default, this conveys no information, but an 80486 does it. */
     clear_C1();
-#endif PECULIAR_486
     reg_store_int32();
     break;
   case 012:     /* fst m64real */
-#ifdef PECULIAR_486
-    /* Default, this conveys no information, but an 80486 does it. */
     clear_C1();
-#endif PECULIAR_486
     reg_store_double();
     break;
   case 013:     /* fist m16int */
-#ifdef PECULIAR_486
-    /* Default, this conveys no information, but an 80486 does it. */
     clear_C1();
-#endif PECULIAR_486
     reg_store_int16();
     break;
   case 014:     /* fstp m32real */
-#ifdef PECULIAR_486
-    /* Default, this conveys no information, but an 80486 does it. */
     clear_C1();
-#endif PECULIAR_486
     if ( reg_store_single() )
       pop_0();  /* pop only if the number was actually stored
 		 (see the 80486 manual p16-28) */
     break;
   case 015:     /* fistp m32int */
-#ifdef PECULIAR_486
-    /* Default, this conveys no information, but an 80486 does it. */
     clear_C1();
-#endif PECULIAR_486
     if ( reg_store_int32() )
       pop_0();  /* pop only if the number was actually stored
 		 (see the 80486 manual p16-28) */
     break;
   case 016:     /* fstp m64real */
-#ifdef PECULIAR_486
-    /* Default, this conveys no information, but an 80486 does it. */
     clear_C1();
-#endif PECULIAR_486
     if ( reg_store_double() )
       pop_0();  /* pop only if the number was actually stored
 		 (see the 80486 manual p16-28) */
     break;
   case 017:     /* fistp m16int */
-#ifdef PECULIAR_486
-    /* Default, this conveys no information, but an 80486 does it. */
     clear_C1();
-#endif PECULIAR_486
     if ( reg_store_int16() )
       pop_0();  /* pop only if the number was actually stored
 		 (see the 80486 manual p16-28) */
@@ -198,10 +162,7 @@
     frstor();
     break;
   case 023:     /* fbld m80dec */
-#ifdef PECULIAR_486
-    /* Default, this conveys no information, but an 80486 does it. */
     clear_C1();
-#endif PECULIAR_486
     reg_load_bcd();
     reg_move(&FPU_loaded_data, pop_ptr);
     break;
@@ -220,18 +181,12 @@
     NO_NET_INSTR_EFFECT;
     break;
   case 025:      /* fld m80real */
-#ifdef PECULIAR_486
-    /* Default, this conveys no information, but an 80486 does it. */
     clear_C1();
-#endif PECULIAR_486
     reg_load_extended();
     reg_move(&FPU_loaded_data, pop_ptr);
     break;
   case 027:      /* fild m64int */
-#ifdef PECULIAR_486
-    /* Default, this conveys no information, but an 80486 does it. */
     clear_C1();
-#endif PECULIAR_486
     reg_load_int64();
     reg_move(&FPU_loaded_data, pop_ptr);
     break;
@@ -244,10 +199,7 @@
     NO_NET_DATA_EFFECT;
     break;
   case 033:      /* fbstp m80dec */
-#ifdef PECULIAR_486
-    /* Default, this conveys no information, but an 80486 does it. */
     clear_C1();
-#endif PECULIAR_486
     if ( reg_store_bcd() )
       pop_0();  /* pop only if the number was actually stored
 		 (see the 80486 manual p16-28) */
@@ -261,10 +213,7 @@
     NO_NET_INSTR_EFFECT;
     break;
   case 035:      /* fstp m80real */
-#ifdef PECULIAR_486
-    /* Default, this conveys no information, but an 80486 does it. */
     clear_C1();
-#endif PECULIAR_486
     if ( reg_store_extended() )
       pop_0();  /* pop only if the number was actually stored
 		 (see the 80486 manual p16-28) */
@@ -278,10 +227,7 @@
     NO_NET_INSTR_EFFECT;
     break;
   case 037:      /* fistp m64int */
-#ifdef PECULIAR_486
-    /* Default, this conveys no information, but an 80486 does it. */
     clear_C1();
-#endif PECULIAR_486
     if ( reg_store_int64() )
       pop_0();  /* pop only if the number was actually stored
 		 (see the 80486 manual p16-28) */
diff --git a/kernel/FPU-emu/poly_atan.c b/kernel/FPU-emu/poly_atan.c
index e9bceee..e0a0645 100644
--- a/kernel/FPU-emu/poly_atan.c
+++ b/kernel/FPU-emu/poly_atan.c
@@ -38,10 +38,7 @@
   { 0xf1dd2dbf, 0x000a530a }
 };
 
-
-static unsigned denomterm[2] =
-{ 0xfc4bd208, 0xea2e6612 };
-
+static unsigned long long denomterm = 0xea2e6612fc4bd208LL;
 
 
 /*--- poly_atan() -----------------------------------------------------------+
@@ -53,7 +50,7 @@
   short		exponent;
   FPU_REG       odd_poly, even_poly, pos_poly, neg_poly, ratio;
   FPU_REG       argSq;
-  long long     arg_signif, argSqSq;
+  unsigned long long     arg_signif, argSqSq;
   
 
 #ifdef PARANOID
@@ -97,20 +94,20 @@
 
 	  recursions++;
 
-	  arg_signif = *(long long *)&(arg->sigl);
+	  arg_signif = significand(arg);
 	  if ( exponent < -1 )
 	    {
 	      if ( shrx(&arg_signif, -1-exponent) >= 0x80000000U )
 		arg_signif++;	/* round up */
 	    }
-	  *(long long *)&(numerator.sigl) = -arg_signif;
+	  significand(&numerator) = -arg_signif;
 	  numerator.exp = EXP_BIAS - 1;
 	  normalize(&numerator);                       /* 1 - arg */
 
-	  arg_signif = *(long long *)&(arg->sigl);
+	  arg_signif = significand(arg);
 	  if ( shrx(&arg_signif, -exponent) >= 0x80000000U )
 	    arg_signif++;	/* round up */
-	  *(long long *)&(denom.sigl) = arg_signif;
+	  significand(&denom) = arg_signif;
 	  denom.sigh |= 0x80000000;                    /* 1 + arg */
 
 	  arg->exp = numerator.exp;
@@ -120,7 +117,7 @@
 	}
     }
 
-  *(long long *)&arg_signif = *(long long *)&(arg->sigl);
+  arg_signif = significand(arg);
 
 #ifdef PARANOID
   /* This must always be true */
@@ -136,8 +133,8 @@
   
   /* Now have arg_signif with binary point at the left
      .1xxxxxxxx */
-  mul64(&arg_signif, &arg_signif, (long long *)(&argSq.sigl));
-  mul64((long long *)(&argSq.sigl), (long long *)(&argSq.sigl), &argSqSq);
+  mul64(&arg_signif, &arg_signif, &significand(&argSq));
+  mul64(&significand(&argSq), &significand(&argSq), &argSqSq);
 
   /* will be a valid positive nr with expon = 0 */
   *(short *)&(pos_poly.sign) = 0;
@@ -146,8 +143,8 @@
   /* Do the basic fixed point polynomial evaluation */
   polynomial(&pos_poly.sigl, (unsigned *)&argSqSq,
 	     (unsigned short (*)[4])oddplterms, HIPOWERop-1);
-  mul64((long long *)(&argSq.sigl), (long long *)(&pos_poly.sigl),
-	(long long *)(&pos_poly.sigl));
+  mul64(&significand(&argSq), &significand(&pos_poly),
+	&significand(&pos_poly));
 
   /* will be a valid positive nr with expon = 0 */
   *(short *)&(neg_poly.sign) = 0;
@@ -158,7 +155,7 @@
 	     (unsigned short (*)[4])oddnegterms, HIPOWERon-1);
 
   /* Subtract the mantissas */
-  *((long long *)(&pos_poly.sigl)) -= *((long long *)(&neg_poly.sigl));
+  significand(&pos_poly) -= significand(&neg_poly);
 
   reg_move(&pos_poly, &odd_poly);
   poly_add_1(&odd_poly);
@@ -166,8 +163,7 @@
   /* will be a valid positive nr with expon = 0 */
   *(short *)&(even_poly.sign) = 0;
 
-  mul64((long long *)(&argSq.sigl),
-	(long long *)(&denomterm), (long long *)(&even_poly.sigl));
+  mul64(&significand(&argSq), &denomterm, &significand(&even_poly));
 
   poly_add_1(&even_poly);
 
@@ -198,7 +194,7 @@
 shrx(&src->sigl, 1);
 
 #ifdef OBSOLETE
-if ( round ) (*(long long *)&src->sigl)++;   /* Round to even */
+if ( round ) significand(src)++;   /* Round to even */
 #endif OBSOLETE
 
 src->sigh |= 0x80000000;
diff --git a/kernel/FPU-emu/poly_div.S b/kernel/FPU-emu/poly_div.S
index 987fea9..cab7d72 100644
--- a/kernel/FPU-emu/poly_div.S
+++ b/kernel/FPU-emu/poly_div.S
@@ -8,9 +8,9 @@
  |                       Australia.  E-mail apm233m@vaxc.cc.monash.edu.au    |
  |                                                                           |
  | Call from C as:                                                           |
- |   void poly_div2(long long *x)                                            |
- |   void poly_div4(long long *x)                                            |
- |   void poly_div16(long long *x)                                           |
+ |   void poly_div2(unsigned long long *x)                                   |
+ |   void poly_div4(unsigned long long *x)                                   |
+ |   void poly_div16(unsigned long long *x)                                  |
  |                                                                           |
  +---------------------------------------------------------------------------*/
 
diff --git a/kernel/FPU-emu/poly_l2.c b/kernel/FPU-emu/poly_l2.c
index 3cca359..49085a0 100644
--- a/kernel/FPU-emu/poly_l2.c
+++ b/kernel/FPU-emu/poly_l2.c
@@ -45,7 +45,7 @@
   short		  exponent;
   char		  zero;		/* flag for an Xx == 0 */
   unsigned short  bits, shift;
-  long long       Xsq;
+  unsigned long long       Xsq;
   FPU_REG	  accum, denom, num, Xx;
 
 
@@ -79,14 +79,14 @@
 
   denom.sigl = num.sigl;
   denom.sigh = num.sigh;
-  poly_div4((long long *)&(denom.sigl));
+  poly_div4(&significand(&denom));
   denom.sigh += 0x80000000;			/* set the msb */
   Xx.exp = EXP_BIAS;  /* needed to prevent errors in div routine */
   reg_u_div(&num, &denom, &Xx, FULL_PRECISION);
 
   zero = !(Xx.sigh | Xx.sigl);
   
-  mul64((long long *)&Xx.sigl, (long long *)&Xx.sigl, &Xsq);
+  mul64(&significand(&Xx), &significand(&Xx), &Xsq);
   poly_div16(&Xsq);
 
   accum.exp = -1;		/* exponent of accum */
@@ -123,7 +123,7 @@
 	    {
 	      /* The argument is of the form 1-x */
 	      /* Use  1-1/(1-x) = x/(1-x) */
-	      *((long long *)&num.sigl) = - *((long long *)&(arg->sigl));
+	      significand(&num) = - significand(arg);
 	      normalize(&num);
 	      reg_div(&num, arg, &num, FULL_PRECISION);
 	    }
@@ -149,16 +149,16 @@
       return;
     }
 
-  mul64((long long *)&accum.sigl,
-	(long long *)&Xx.sigl, (long long *)&accum.sigl);
+  mul64(&significand(&accum),
+	&significand(&Xx), &significand(&accum));
 
-  *((long long *)(&accum.sigl)) += *((long long *)(&Xx.sigl));
+  significand(&accum) += significand(&Xx);
 
   if ( Xx.sigh > accum.sigh )
     {
       /* There was an overflow */
 
-      poly_div2((long long *)&accum.sigl);
+      poly_div2(&significand(&accum));
       accum.sigh |= 0x80000000;
       accum.exp++;
     }
@@ -179,11 +179,11 @@
 	  /* Shift to get exponent == 0 */
 	  if ( accum.exp < 0 )
 	    {
-	      poly_div2((long long *)&accum.sigl);
+	      poly_div2(&significand(&accum));
 	      accum.exp++;
 	    }
 	  /* Just negate, but throw away the sign */
-	  *((long long *)&(accum.sigl)) = - *((long long *)&(accum.sigl));
+	  significand(&accum) = - significand(&accum);
 	  if ( exponent < 0 )
 	    exponent++;
 	  else
@@ -198,11 +198,11 @@
       if ( accum.exp )
 	{
 	  accum.exp++;
-	  poly_div2((long long *)&accum.sigl);
+	  poly_div2(&significand(&accum));
 	}
       while ( shift )
 	{
-	  poly_div2((long long *)&accum.sigl);
+	  poly_div2(&significand(&accum));
 	  if ( shift & 1)
 	    accum.sigh |= 0x80000000;
 	  shift >>= 1;
@@ -227,7 +227,7 @@
 int	poly_l2p1(FPU_REG *arg, FPU_REG *result)
 {
   char		sign = 0;
-  long long     Xsq;
+  unsigned long long     Xsq;
   FPU_REG      	arg_pl1, denom, accum, local_arg, poly_arg;
 
 
@@ -263,7 +263,7 @@
   /* Get poly_arg bits aligned as required */
   shrx((unsigned *)&(poly_arg.sigl), -(poly_arg.exp - EXP_BIAS + 3));
 
-  mul64((long long *)&(poly_arg.sigl), (long long *)&(poly_arg.sigl), &Xsq);
+  mul64(&significand(&poly_arg), &significand(&poly_arg), &Xsq);
   poly_div16(&Xsq);
 
   /* Do the basic fixed point polynomial evaluation */
diff --git a/kernel/FPU-emu/poly_sin.c b/kernel/FPU-emu/poly_sin.c
index 24c58fe..5076741 100644
--- a/kernel/FPU-emu/poly_sin.c
+++ b/kernel/FPU-emu/poly_sin.c
@@ -82,13 +82,13 @@
     {
       /* shift the argument right by the required places */
       if ( shrx(&(fixed_arg.sigl), -1-exponent) >= 0x80000000U )
-	(*((long long *)(&(fixed_arg.sigl))))++;	/* round up */
+	significand(&fixed_arg)++;	/* round up */
     }
   
-  mul64((long long *)&(fixed_arg.sigl), (long long *)&(fixed_arg.sigl),
-	(long long *)&(arg_sqrd.sigl));
-  mul64((long long *)&(arg_sqrd.sigl), (long long *)&(arg_sqrd.sigl),
-	(long long *)&(arg_to_4.sigl));
+  mul64(&significand(&fixed_arg), &significand(&fixed_arg),
+	&significand(&arg_sqrd));
+  mul64(&significand(&arg_sqrd), &significand(&arg_sqrd),
+	&significand(&arg_to_4));
   
   /* will be a valid positive nr with expon = 0 */
   *(short *)&(accum.sign) = 0;
@@ -103,11 +103,11 @@
   
   /* Do the basic fixed point polynomial evaluation */
   polynomial(&(negaccum.sigl), &(arg_to_4.sigl), negterms, HIPOWER-1);
-  mul64((long long *)&(arg_sqrd.sigl), (long long *)&(negaccum.sigl),
-	(long long *)&(negaccum.sigl));
+  mul64(&significand(&arg_sqrd), &significand(&negaccum),
+	&significand(&negaccum));
 
   /* Subtract the mantissas */
-  *((long long *)(&(accum.sigl))) -= *((long long *)(&(negaccum.sigl)));
+  significand(&accum) -= significand(&negaccum);
   
   /* Convert to 64 bit signed-compatible */
   accum.exp = EXP_BIAS - 1 + accum.exp;
diff --git a/kernel/FPU-emu/poly_tan.c b/kernel/FPU-emu/poly_tan.c
index 8cb202a..4c8a41b 100644
--- a/kernel/FPU-emu/poly_tan.c
+++ b/kernel/FPU-emu/poly_tan.c
@@ -54,7 +54,7 @@
   short		exponent;
   FPU_REG       odd_poly, even_poly, pos_poly, neg_poly;
   FPU_REG       argSq;
-  long long     arg_signif, argSqSq;
+  unsigned long long     arg_signif, argSqSq;
   
 
   exponent = arg->exp - EXP_BIAS;
@@ -64,7 +64,7 @@
     { arith_invalid(y_reg); return; }  /* Need a positive number */
 #endif PARANOID
 
-  *(long long *)&arg_signif = *(long long *)&(arg->sigl);
+  arg_signif = significand(arg);
   if ( exponent < -1 )
     {
       /* shift the argument right by the required places */
@@ -72,8 +72,8 @@
 	arg_signif++;	/* round up */
     }
 
-  mul64(&arg_signif, &arg_signif, (long long *)(&argSq.sigl));
-  mul64((long long *)(&argSq.sigl), (long long *)(&argSq.sigl), &argSqSq);
+  mul64(&arg_signif, &arg_signif, &significand(&argSq));
+  mul64(&significand(&argSq), &significand(&argSq), &argSqSq);
 
   /* will be a valid positive nr with expon = 0 */
   *(short *)&(pos_poly.sign) = 0;
@@ -88,11 +88,11 @@
 
   /* Do the basic fixed point polynomial evaluation */
   polynomial(&neg_poly.sigl, (unsigned *)&argSqSq, oddnegterms, HIPOWERon-1);
-  mul64((long long *)(&argSq.sigl), (long long *)(&neg_poly.sigl),
-	(long long *)(&neg_poly.sigl));
+  mul64(&significand(&argSq), &significand(&neg_poly),
+	&significand(&neg_poly));
 
   /* Subtract the mantissas */
-  *((long long *)(&pos_poly.sigl)) -= *((long long *)(&neg_poly.sigl));
+  significand(&pos_poly) -= significand(&neg_poly);
 
   /* Convert to 64 bit signed-compatible */
   pos_poly.exp -= 1;
@@ -110,8 +110,8 @@
   
   /* Do the basic fixed point polynomial evaluation */
   polynomial(&pos_poly.sigl, (unsigned *)&argSqSq, evenplterms, HIPOWERep-1);
-  mul64((long long *)(&argSq.sigl),
-	(long long *)(&pos_poly.sigl), (long long *)(&pos_poly.sigl));
+  mul64(&significand(&argSq),
+	&significand(&pos_poly), &significand(&pos_poly));
   
   /* will be a valid positive nr with expon = 0 */
   *(short *)&(neg_poly.sign) = 0;
@@ -121,7 +121,7 @@
   polynomial(&neg_poly.sigl, (unsigned *)&argSqSq, evennegterms, HIPOWERen-1);
 
   /* Subtract the mantissas */
-  *((long long *)(&neg_poly.sigl)) -= *((long long *)(&pos_poly.sigl));
+  significand(&neg_poly) -= significand(&pos_poly);
   /* and multiply by argSq */
 
   /* Convert argSq to a valid reg number */
diff --git a/kernel/FPU-emu/reg_constant.c b/kernel/FPU-emu/reg_constant.c
index 6cda7f0..1f63051 100644
--- a/kernel/FPU-emu/reg_constant.c
+++ b/kernel/FPU-emu/reg_constant.c
@@ -67,10 +67,7 @@
     }
   push();
   reg_move(c, FPU_st0_ptr);
-#ifdef PECULIAR_486
-  /* Default, this conveys no information, but an 80486 does it. */
   clear_C1();
-#endif PECULIAR_486
 }
 
 
diff --git a/kernel/FPU-emu/reg_ld_str.c b/kernel/FPU-emu/reg_ld_str.c
index 1ddc553..d07c7bf 100644
--- a/kernel/FPU-emu/reg_ld_str.c
+++ b/kernel/FPU-emu/reg_ld_str.c
@@ -312,7 +312,7 @@
   }
 
   e = EXP_BIAS + 63;
-  *((long long *)&FPU_loaded_data.sigl) = s;
+  significand(&FPU_loaded_data) = s;
   FPU_loaded_data.exp = e;
   FPU_loaded_data.tag = TW_Valid;
   normalize_nuo(&FPU_loaded_data);
@@ -417,7 +417,7 @@
     }
   else
     {
-      *((long long *)&FPU_loaded_data.sigl) = l;
+      significand(&FPU_loaded_data) = l;
       FPU_loaded_data.exp = EXP_BIAS + 63;
       FPU_loaded_data.tag = TW_Valid;
       normalize_nuo(&FPU_loaded_data);
@@ -1033,7 +1033,7 @@
 
   reg_move(FPU_st0_ptr, &t);
   precision_loss = round_to_int(&t);
-  ll = *(unsigned long long *)(&t.sigl);
+  ll = significand(&t);
 
   /* Check for overflow, by comparing with 999999999999999999 decimal. */
   if ( (t.sigh > 0x0de0b6b3) ||
@@ -1042,14 +1042,16 @@
       EXCEPTION(EX_Invalid);
       /* This is a special case: see sec 16.2.5.1 of the 80486 book */
     invalid_operand:
-      if ( control_word & EX_Invalid )
+      if ( control_word & CW_Invalid )
 	{
 	  /* Produce the QNaN "indefinite" */
 	  RE_ENTRANT_CHECK_OFF
 	  verify_area(VERIFY_WRITE,d,10);
-	  put_fs_byte(0xff,(unsigned char *) d+7); /* This byte undefined */
-	  put_fs_byte(0xff,(unsigned char *) d+8);
-	  put_fs_byte(0xff,(unsigned char *) d+9);
+	  for ( i = 0; i < 7; i++)
+	    put_fs_byte(0, (unsigned char *) d+i); /* These bytes "undefined" */
+	  put_fs_byte(0xc0, (unsigned char *) d+7); /* This byte "undefined" */
+	  put_fs_byte(0xff, (unsigned char *) d+8);
+	  put_fs_byte(0xff, (unsigned char *) d+9);
 	  RE_ENTRANT_CHECK_ON
 	  return 1;
 	}
@@ -1058,8 +1060,8 @@
     }
   else if ( precision_loss )
     {
-      if ( set_precision_flag(precision_loss) )
-	return 0;
+      /* Precision loss doesn't stop the data transfer */
+      set_precision_flag(precision_loss);
     }
 
   verify_area(VERIFY_WRITE,d,10);
@@ -1096,7 +1098,7 @@
   if (r->tag == TW_Zero)
     {
       /* Make sure that zero is returned */
-      *(long long *)&r->sigl = 0;
+      significand(r) = 0;
       return 0;        /* o.k. */
     }
   
@@ -1118,7 +1120,7 @@
 	  || (half_or_more && (r->sigl & 1)) )	/* odd -> even */
 	{
 	  if ( very_big ) return 1;        /* overflow */
-	  (*(long long *)(&r->sigl)) ++;
+	  significand(r) ++;
 	  return PRECISION_LOST_UP;
 	}
       break;
@@ -1126,7 +1128,7 @@
       if (frac_part && r->sign)
 	{
 	  if ( very_big ) return 1;        /* overflow */
-	  (*(long long *)(&r->sigl)) ++;
+	  significand(r) ++;
 	  return PRECISION_LOST_UP;
 	}
       break;
@@ -1134,7 +1136,7 @@
       if (frac_part && !r->sign)
 	{
 	  if ( very_big ) return 1;        /* overflow */
-	  (*(long long *)(&r->sigl)) ++;
+	  significand(r) ++;
 	  return PRECISION_LOST_UP;
 	}
       break;
diff --git a/kernel/FPU-emu/status_w.h b/kernel/FPU-emu/status_w.h
index 0e23d6c..87521ff 100644
--- a/kernel/FPU-emu/status_w.h
+++ b/kernel/FPU-emu/status_w.h
@@ -10,6 +10,7 @@
 #ifndef _STATUS_H_
 #define _STATUS_H_
 
+#include "fpu_emu.h"    /* for definition of PECULIAR_486 */
 
 #ifdef __ASSEMBLER__
 #define	Const__(x)	$##x
@@ -51,8 +52,13 @@
   partial_status &= ~(SW_C0|SW_C1|SW_C2|SW_C3); \
   partial_status |= (cc) & (SW_C0|SW_C1|SW_C2|SW_C3); })
 
-/* Clear the SW_C1 bit, "other bits undefined" */
-#define clear_C1()  { partial_status &= ~SW_C1; }
+#ifdef PECULIAR_486
+   /* Default, this conveys no information, but an 80486 does it. */
+   /* Clear the SW_C1 bit, "other bits undefined". */
+#  define clear_C1()  { partial_status &= ~SW_C1; }
+# else
+#  define clear_C1()
+#endif PECULIAR_486
 
 #endif __ASSEMBLER__
 
diff --git a/kernel/FPU-emu/version.h b/kernel/FPU-emu/version.h
index fd562ce..ce22bab 100644
--- a/kernel/FPU-emu/version.h
+++ b/kernel/FPU-emu/version.h
@@ -9,5 +9,5 @@
  |                                                                           |
  +---------------------------------------------------------------------------*/
 
-#define FPU_VERSION "wm-FPU-emu version BETA 1.5"
+#define FPU_VERSION "wm-FPU-emu version BETA 1.6"
 
diff --git a/kernel/blk_drv/blk.h b/kernel/blk_drv/blk.h
index 2e4f158..0f5cb8f 100644
--- a/kernel/blk_drv/blk.h
+++ b/kernel/blk_drv/blk.h
@@ -3,6 +3,7 @@
 
 #include <linux/sched.h>
 #include <linux/locks.h>
+#include <linux/genhd.h>
 
 /*
  * NR_REQUEST is the number of entries in the request-queue.
diff --git a/kernel/blk_drv/genhd.c b/kernel/blk_drv/genhd.c
index 840e858..1681d2b 100644
--- a/kernel/blk_drv/genhd.c
+++ b/kernel/blk_drv/genhd.c
@@ -194,7 +194,7 @@
 }
 	
 /* This may be used only once, enforced by 'static int callable' */
-extern "C" int sys_setup(void * BIOS)
+asmlinkage int sys_setup(void * BIOS)
 {
 	static int callable = 1;
 	struct gendisk *p;
diff --git a/kernel/blk_drv/hd.c b/kernel/blk_drv/hd.c
index d1d2258..9858b32 100644
--- a/kernel/blk_drv/hd.c
+++ b/kernel/blk_drv/hd.c
@@ -559,7 +559,7 @@
 		case BLKFLSBUF:
 			if(!suser())  return -EACCES;
 			if(!inode->i_rdev) return -EINVAL;
-			sync_dev(inode->i_rdev);
+			fsync_dev(inode->i_rdev);
 			invalidate_buffers(inode->i_rdev);
 			return 0;
 
diff --git a/kernel/blk_drv/ramdisk.c b/kernel/blk_drv/ramdisk.c
index 3f50ea0..49b1302 100644
--- a/kernel/blk_drv/ramdisk.c
+++ b/kernel/blk_drv/ramdisk.c
@@ -37,7 +37,8 @@
 repeat:
 	INIT_REQUEST;
 	addr = rd_start + (CURRENT->sector << 9);
-	len = CURRENT->nr_sectors << 9;
+	len = CURRENT->current_nr_sectors << 9;
+
 	if ((MINOR(CURRENT->dev) != MINOR_RAMDISK) ||
 	    (addr+len > rd_start+rd_length)) {
 		end_request(0);
diff --git a/kernel/blk_drv/scsi/aha1542.c b/kernel/blk_drv/scsi/aha1542.c
index dc9ffe5..2e06f45 100644
--- a/kernel/blk_drv/scsi/aha1542.c
+++ b/kernel/blk_drv/scsi/aha1542.c
@@ -15,6 +15,7 @@
 #include <linux/head.h>
 #include <linux/types.h>
 #include <linux/string.h>
+#include <linux/ioport.h>
 
 #include <linux/sched.h>
 #include <asm/dma.h>
@@ -178,7 +179,7 @@
     
     /*  DEB(printk("aha1542_test_port called \n")); */
     
-    outb(SRST|IRST/*|SCRST*/, CONTROL);
+    outb(HRST|IRST/*|SCRST*/, CONTROL);
     
     debug = 1;
     /* Expect INIT and IDLE, any of the others are bad */
@@ -663,8 +664,10 @@
     
     indx = 0;
     while(indx < sizeof(bases)/sizeof(bases[0])){
-      i = aha1542_test_port(bases[indx]);
-      if (i) break;
+      if(!check_region(bases[indx], 4)){
+	i = aha1542_test_port(bases[indx]);
+	if (i) break;
+      };
       indx++;
     }
     if (indx == sizeof(bases)/sizeof(bases[0])) return 0;
@@ -755,6 +758,7 @@
 	  aha1542_command(0, cmd, buffer, 512);
       }
 #endif
+    snarf_region(bases[indx], 4);  /* Register the IO ports that we use */
     aha1542_host = hostnum;
     return 1;
 }
diff --git a/kernel/blk_drv/scsi/aha1740.c b/kernel/blk_drv/scsi/aha1740.c
index ef86500..1325cdc 100644
--- a/kernel/blk_drv/scsi/aha1740.c
+++ b/kernel/blk_drv/scsi/aha1740.c
@@ -21,6 +21,7 @@
 #include <linux/head.h>
 #include <linux/types.h>
 #include <linux/string.h>
+#include <linux/ioport.h>
 
 #include <linux/sched.h>
 #include <asm/dma.h>
@@ -432,6 +433,12 @@
     for ( slot=MINEISA; slot <= MAXEISA; slot++ )
     {
 	base = SLOTBASE(slot);
+
+	/* The ioports for eisa boards are generally beyond that used in the
+	   check,snarf_region code, but this may change at some point, so we
+	   go through the motions. */
+
+	if(check_region(base, 0x5c)) continue;  /* See if in use */
 	if ( aha1740_test_port())  break;
     }
     if ( slot > MAXEISA )
@@ -455,6 +462,7 @@
         printk("Unable to allocate IRQ for adaptec controller.\n");
         return 0;
     }
+    snarf_region(base, 0x5c);  /* Reserve the space that we need to use */
     return 1;
 }
 
diff --git a/kernel/blk_drv/scsi/fdomain.c b/kernel/blk_drv/scsi/fdomain.c
index 7bb9e19..d207945 100644
--- a/kernel/blk_drv/scsi/fdomain.c
+++ b/kernel/blk_drv/scsi/fdomain.c
@@ -138,6 +138,7 @@
 #include <asm/system.h>
 #include <linux/errno.h>
 #include <linux/string.h>
+#include <linux/ioport.h>
 
 #define VERSION          "$Revision: 3.18 $"
 
@@ -528,6 +529,8 @@
 
       for (i = 0; !flag && i < PORT_COUNT; i++) {
 	 port_base = ports[i];
+	 if(check_region(port_base, 0x10)) continue;  /* skip if I/O port in
+							 use */
 #if DEBUG_DETECT
 	 printk( " %x,", port_base );
 #endif
@@ -607,6 +610,8 @@
       scsi_hosts[this_host].this_id = 7;
    }
    
+   snarf_region(port_base, 0x10);  /* Register */
+
 #if DO_DETECT
 
    /* These routines are here because of the way the SCSI bus behaves after
diff --git a/kernel/blk_drv/scsi/scsi.c b/kernel/blk_drv/scsi/scsi.c
index 66b2222..0c9f94e 100644
--- a/kernel/blk_drv/scsi/scsi.c
+++ b/kernel/blk_drv/scsi/scsi.c
@@ -68,6 +68,7 @@
 #define WAS_TIMEDOUT 	0x02
 #define WAS_SENSE	0x04
 #define IS_RESETTING	0x08
+#define ASKED_FOR_SENSE 0x10
 
 extern int last_reset[];
 
@@ -661,7 +662,7 @@
 static void scsi_request_sense (Scsi_Cmnd * SCpnt)
 	{
 	cli();
-	SCpnt->flags |= WAS_SENSE;
+	SCpnt->flags |= WAS_SENSE | ASKED_FOR_SENSE;
 	update_timeout(SCpnt, SENSE_TIMEOUT);
 	sti();
 	
@@ -805,9 +806,17 @@
 
 static int check_sense (Scsi_Cmnd * SCpnt)
 	{
-  /* If there is no sense information, request it.  */
-  if (((SCpnt->sense_buffer[0] & 0x70) >> 4) != 7)
-    return SUGGEST_SENSE;
+  /* If there is no sense information, request it.  If we have already
+     requested it, there is no point in asking again - the firmware must be
+     confused. */
+  if (((SCpnt->sense_buffer[0] & 0x70) >> 4) != 7) {
+    if(!(SCpnt->flags & ASKED_FOR_SENSE))
+      return SUGGEST_SENSE;
+    else
+      return SUGGEST_RETRY;
+      }
+  
+  SCpnt->flags &= ~ASKED_FOR_SENSE;
 
 #ifdef DEBUG_INIT
 	printk("scsi%d : ", SCpnt->host);
diff --git a/kernel/blk_drv/scsi/sd.c b/kernel/blk_drv/scsi/sd.c
index 9675767..aeef78e 100644
--- a/kernel/blk_drv/scsi/sd.c
+++ b/kernel/blk_drv/scsi/sd.c
@@ -49,9 +49,6 @@
 static int * sd_sizes;
 static int * sd_blocksizes;
 
-/* used to re-read partitions. */
-extern void resetup_one_dev(struct gendisk *, unsigned int);
-
 extern int sd_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
 
 static sd_init_onedisk(int);
@@ -127,7 +124,9 @@
 
 static void sd_geninit (void)
 {
-	for (int i = 0; i < NR_SD; ++i)
+	int i;
+
+	for (i = 0; i < NR_SD; ++i)
 		sd[i << 4].nr_sects = rscsi_disks[i].capacity;
 	sd_gendisk.nr_real = NR_SD;
 }
@@ -324,6 +323,7 @@
 
     INIT_SCSI_REQUEST;
 
+
 /* We have to be careful here.  allocate_device will get a free pointer, but
    there is no guarantee that it is queueable.  In normal usage, we want to
    call this, because other types of devices may have the host all tied up,
@@ -668,6 +668,7 @@
   int j = 0;
   unsigned char cmd[10];
   unsigned char *buffer;
+  char spintime;
   int the_result, retries;
   Scsi_Cmnd * SCpnt;
 
@@ -678,6 +679,59 @@
   SCpnt = allocate_device(NULL, rscsi_disks[i].device->index, 1);
   buffer = (unsigned char *) scsi_malloc(512);
 
+  spintime = 0;
+
+  /* Spin up drives, as required.  Only do this at boot time */
+  if (current == task[0]){
+    do{
+      cmd[0] = TEST_UNIT_READY;
+      cmd[1] = (rscsi_disks[i].device->lun << 5) & 0xe0;
+      memset ((void *) &cmd[2], 0, 8);
+      SCpnt->request.dev = 0xffff;  /* Mark as really busy again */
+      SCpnt->sense_buffer[0] = 0;
+      SCpnt->sense_buffer[2] = 0;
+      
+      scsi_do_cmd (SCpnt,
+		   (void *) cmd, (void *) buffer,
+		   512, sd_init_done,  SD_TIMEOUT,
+		   MAX_RETRIES);
+      
+      while(SCpnt->request.dev != 0xfffe);
+      
+      the_result = SCpnt->result;
+      
+      /* Look for non-removable devices that return NOT_READY.  Issue command
+	 to spin up drive for these cases. */
+      if(the_result && !rscsi_disks[i].device->removable && 
+	 SCpnt->sense_buffer[2] == NOT_READY) {
+	int time1;
+	if(!spintime){
+	  cmd[0] = START_STOP;
+	  cmd[1] = (rscsi_disks[i].device->lun << 5) & 0xe0;
+	  cmd[1] |= 1;  /* Return immediately */
+	  memset ((void *) &cmd[2], 0, 8);
+	  cmd[4] = 1; /* Start spin cycle */
+	  SCpnt->request.dev = 0xffff;  /* Mark as really busy again */
+	  SCpnt->sense_buffer[0] = 0;
+	  SCpnt->sense_buffer[2] = 0;
+	  
+	  scsi_do_cmd (SCpnt,
+		       (void *) cmd, (void *) buffer,
+		       512, sd_init_done,  SD_TIMEOUT,
+		       MAX_RETRIES);
+	  
+	  while(SCpnt->request.dev != 0xfffe);
+
+	  spintime = jiffies;
+	};
+
+	time1 = jiffies;
+	while(jiffies < time1 + 100); /* Wait 1 second for next try */
+      };
+    } while(the_result && spintime && spintime+1500 < jiffies);
+  };  /* current == task[0] */
+
+
   retries = 3;
   do {
     cmd[0] = READ_CAPACITY;
diff --git a/kernel/blk_drv/scsi/sd_ioctl.c b/kernel/blk_drv/scsi/sd_ioctl.c
index 9365cb6..eefd1ff 100644
--- a/kernel/blk_drv/scsi/sd_ioctl.c
+++ b/kernel/blk_drv/scsi/sd_ioctl.c
@@ -55,7 +55,7 @@
 		case BLKFLSBUF:
 			if(!suser())  return -EACCES;
 			if(!inode->i_rdev) return -EINVAL;
- 			sync_dev(inode->i_rdev);
+ 			fsync_dev(inode->i_rdev);
 			invalidate_buffers(inode->i_rdev);
 			return 0;
 
diff --git a/kernel/blk_drv/scsi/seagate.c b/kernel/blk_drv/scsi/seagate.c
index 1631d62..2ef2321 100644
--- a/kernel/blk_drv/scsi/seagate.c
+++ b/kernel/blk_drv/scsi/seagate.c
@@ -10,6 +10,8 @@
  * 	Note : TMC-880 boards don't work because they have two bits in 
  *		the status register flipped, I'll fix this "RSN"
  *
+ *      This card does all the I/O via memory mapped I/O, so there is no need
+ *      to check or snarf a region of the I/O address space.
  */
 
 /*
@@ -825,9 +827,9 @@
  *	going on.
  */
 	cli();
+	DATA = (unsigned char) ((1 << target) | (controller_type == SEAGATE ? 0x80 : 0x40));
 	CONTROL = BASE_CMD | CMD_DRVR_ENABLE | CMD_SEL | 
 		(reselect ? CMD_ATTN : 0);
-	DATA = (unsigned char) ((1 << target) | (controller_type == SEAGATE ? 0x80 : 0x40));
 	sti();
 		while (!((status_read = STATUS) & STAT_BSY) && 
 			(jiffies < clock) && !st0x_aborted)
diff --git a/kernel/blk_drv/scsi/st.c b/kernel/blk_drv/scsi/st.c
index 2c38c19..0249be5 100644
--- a/kernel/blk_drv/scsi/st.c
+++ b/kernel/blk_drv/scsi/st.c
@@ -127,9 +127,11 @@
 /* Convert the result to success code */
 static int st_chk_result(Scsi_Cmnd * SCpnt)
 {
+#ifdef DEBUG
   int dev = SCpnt->request.dev;
+#endif
   int result = SCpnt->result;
-  char * sense = SCpnt->sense_buffer;
+  unsigned char * sense = SCpnt->sense_buffer;
 
   if (!result)
     return 0;
diff --git a/kernel/blk_drv/scsi/ultrastor.c b/kernel/blk_drv/scsi/ultrastor.c
index cc5bbca..a33605d 100644
--- a/kernel/blk_drv/scsi/ultrastor.c
+++ b/kernel/blk_drv/scsi/ultrastor.c
@@ -43,6 +43,7 @@
 #include <linux/string.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
+#include <linux/ioport.h>
 
 #include <asm/io.h>
 #include <asm/system.h>
@@ -194,6 +195,12 @@
     PORT_ADDRESS = 0;
     for (i = 0; i < ARRAY_SIZE(ultrastor_ports_14f); i++) {
 	PORT_ADDRESS = ultrastor_ports_14f[i];
+	if(check_region(PORT_ADDRESS, 4)) continue;
+#else
+	if(check_region(PORT_ADDRESS, 4)) {
+	  printk("Ultrastor I/O space already in use\n");
+	  return FALSE;
+	};
 #endif
 
 #if (ULTRASTOR_DEBUG & UD_DETECT)
@@ -248,6 +255,7 @@
 	   PORT_ADDRESS);
 #endif
 
+    snarf_region(PORT_ADDRESS, 4); /* Register the I/O space that we use */
     /* All above tests passed, must be the right thing.  Get some useful
        info. */
     *(char *)&config_1 = inb(CONFIG(PORT_ADDRESS + 0));
@@ -348,7 +356,7 @@
 	/* Save ourselves some casts; can eliminate when we don't have to look at it anymore! */
 	sglist = (ultrastor_sg_list *) SCpnt->host_scribble;
 	for (i = 0; i < SCpnt->use_sg; i++) {
-		sglist[i].address = sl[i].address;
+		sglist[i].address = (unsigned long) sl[i].address;
 		sglist[i].num_bytes = sl[i].length;
 		transfer_length += sl[i].length;
 	}
diff --git a/kernel/blk_drv/scsi/wd7000.c b/kernel/blk_drv/scsi/wd7000.c
index 88edabb..b1cf124 100644
--- a/kernel/blk_drv/scsi/wd7000.c
+++ b/kernel/blk_drv/scsi/wd7000.c
@@ -20,6 +20,8 @@
 #include <asm/system.h>
 #include <asm/dma.h>
 #include <asm/io.h>
+#include <linux/ioport.h>
+
 #include "../blk.h"
 #include "scsi.h"
 #include "hosts.h"
@@ -526,6 +528,7 @@
     int i,j;
     char const *base_address = NULL;
 
+    if(check_region(IO_BASE, 4)) return 0;  /* IO ports in use */
     for(i=0;i<(sizeof(wd_bases)/sizeof(char *));i++){
 	for(j=0;j<NUM_SIGNATURES;j++){
 	    if(!memcmp((void *)(wd_bases[i] + signatures[j].offset),
@@ -537,6 +540,7 @@
     }
     if (base_address == NULL) return 0;
 
+    snarf_region(IO_BASE, 4); /* Register our ports */
     /* Store our host number */
     wd7000_host = hostnum;
 
diff --git a/kernel/blk_drv/xd.c b/kernel/blk_drv/xd.c
index 14a4c3c..a8532f0 100644
--- a/kernel/blk_drv/xd.c
+++ b/kernel/blk_drv/xd.c
@@ -222,7 +222,7 @@
 			case BLKFLSBUF:
 				if(!suser())  return -EACCES;
 				if(!inode->i_rdev) return -EINVAL;
-				sync_dev(inode->i_rdev);
+				fsync_dev(inode->i_rdev);
 				invalidate_buffers(inode->i_rdev);
 				return 0;
 				
diff --git a/kernel/chr_drv/keyboard.c b/kernel/chr_drv/keyboard.c
index ca1dad5..fdf5684 100644
--- a/kernel/chr_drv/keyboard.c
+++ b/kernel/chr_drv/keyboard.c
@@ -62,10 +62,16 @@
 #define fake_keyboard_interrupt() \
 __asm__ __volatile__("int $0x21")
 
+unsigned char kbd_read_mask = 0x01;	/* modified by psaux.c */
+
 unsigned long kbd_dead_keys = 0;
 unsigned long kbd_prev_dead_keys = 0;
 
+/* shift state counters.. */
 static unsigned char k_down[NR_SHIFT] = {0, };
+/* keyboard key bitmap */
+static unsigned long key_down[8] = { 0, };
+
 static int want_console = -1;
 static int last_console = 0;		/* last used VC */
 static char rep = 0;			/* flag telling character repeat */
@@ -134,7 +140,7 @@
 		kbd_prev_dead_keys = 0;
 	kbd_dead_keys = 0;
 	kb_wait();
-	if (!(inb_p(0x64) & 0x01))
+	if ((inb_p(0x64) & kbd_read_mask) != 0x01)
 		goto end_kbd_intr;
 	scancode = inb(0x60);
 	mark_bh(KEYBOARD_BH);
@@ -149,6 +155,7 @@
 	kbd = kbd_table + fg_console;
 	if (vc_kbd_flag(kbd,VC_RAW)) {
 		memset(k_down, 0, sizeof(k_down));
+		memset(key_down, 0, sizeof(key_down));
 		put_queue(scancode);
 		goto end_kbd_intr;
 	} else
@@ -160,7 +167,6 @@
 static inline void translate(unsigned char scancode)
 {
 	char break_flag;
-	static unsigned long key_down[8] = { 0, };
      	static unsigned char e0_keys[] = {
 		0x1c,	/* keypad enter */
 		0x1d,	/* right control */
@@ -584,6 +590,8 @@
 		value = KVAL(K_SHIFT);
 		clr_vc_kbd_flag(kbd, VC_CAPSLOCK);
 	}
+	if (value > 3)
+		return;
 
 	if (up_flag) {
 		if (k_down[value])
@@ -683,7 +691,7 @@
 	}
 	do_keyboard_interrupt();
 	cli();
-	if (inb_p(0x64) & 0x01)
+	if ((inb_p(0x64) & kbd_read_mask) == 0x01)
 		fake_keyboard_interrupt();
 	sti();
 }
diff --git a/kernel/chr_drv/mem.c b/kernel/chr_drv/mem.c
index 5f3beec..c2ebb38 100644
--- a/kernel/chr_drv/mem.c
+++ b/kernel/chr_drv/mem.c
@@ -129,12 +129,28 @@
 static int mmap_mem(struct inode * inode, struct file * file,
 	unsigned long addr, size_t len, int prot, unsigned long off)
 {
+	struct vm_area_struct * mpnt;
+
 	if (off & 0xfff || off + len < off)
 		return -ENXIO;
-
 	if (remap_page_range(addr, off, len, prot))
 		return -EAGAIN;
-	
+/* try to create a dummy vmm-structure so that the rest of the kernel knows we are here */
+	mpnt = (struct vm_area_struct * ) kmalloc(sizeof(struct vm_area_struct), GFP_KERNEL);
+	if (!mpnt)
+		return 0;
+
+	mpnt->vm_task = current;
+	mpnt->vm_start = addr;
+	mpnt->vm_end = addr + len;
+	mpnt->vm_page_prot = prot;
+	mpnt->vm_share = NULL;
+	mpnt->vm_inode = inode;
+	inode->i_count++;
+	mpnt->vm_offset = off;
+	mpnt->vm_ops = NULL;
+	mpnt->vm_next = current->mmap;
+	current->mmap = mpnt;
 	return 0;
 }
 
@@ -187,11 +203,6 @@
 	return count;
 }
 
-static int write_zero(struct inode * inode,struct file * file,char * buf, int count)
-{
-	return count;
-}
-
 static int mmap_zero(struct inode * inode, struct file * file,
 	unsigned long addr, size_t len, int prot, unsigned long off)
 {
@@ -203,6 +214,15 @@
 }
 
 /*
+ * Special lseek() function for /dev/null and /dev/zero.  Most notably, you can fopen()
+ * both devices with "a" now.  This was previously impossible.  SRB.
+ */
+
+static int null_lseek(struct inode * inode, struct file * file, off_t offset, int orig)
+{
+	return file->f_pos=0;
+}
+/*
  * The memory devices use the full 32 bits of the offset, and so we cannot
  * check against negative addresses: they are ok. The return value is weird,
  * though, in that case (0).
@@ -227,9 +247,11 @@
 	return file->f_pos;
 }
 
-#define read_kmem read_mem
-#define write_kmem write_mem
-#define mmap_kmem mmap_mem
+#define read_kmem	read_mem
+#define write_kmem	write_mem
+#define mmap_kmem	mmap_mem
+#define zero_lseek	null_lseek
+#define write_zero	write_null
 
 static struct file_operations ram_fops = {
 	memory_lseek,
@@ -271,7 +293,7 @@
 };
 
 static struct file_operations null_fops = {
-	memory_lseek,
+	null_lseek,
 	read_null,
 	write_null,
 	NULL,		/* null_readdir */
@@ -297,7 +319,7 @@
 };
 
 static struct file_operations zero_fops = {
-	memory_lseek,
+	zero_lseek,
 	read_zero,
 	write_zero,
 	NULL,		/* zero_readdir */
diff --git a/kernel/chr_drv/mouse.c b/kernel/chr_drv/mouse.c
index 9a03f09..3ea9c47 100644
--- a/kernel/chr_drv/mouse.c
+++ b/kernel/chr_drv/mouse.c
@@ -44,7 +44,7 @@
 	                file->f_op = &bus_mouse_fops;
 	                break;
 #endif
-#ifdef CONFIG_PSMOUSE
+#if defined CONFIG_PSMOUSE || defined CONFIG_QUICKPORT_MOUSE
 		case PSMOUSE_MINOR:
 	                file->f_op = &psaux_fops;
 	                break;
@@ -82,7 +82,7 @@
 #ifdef CONFIG_BUSMOUSE
 	kmem_start = bus_mouse_init(kmem_start);
 #endif
-#ifdef CONFIG_PSMOUSE
+#if defined CONFIG_PSMOUSE || defined CONFIG_QUICKPORT_MOUSE
 	kmem_start = psaux_init(kmem_start);
 #endif
 #ifdef CONFIG_MS_BUSMOUSE
diff --git a/kernel/chr_drv/psaux.c b/kernel/chr_drv/psaux.c
index 28d94ac..e313633 100644
--- a/kernel/chr_drv/psaux.c
+++ b/kernel/chr_drv/psaux.c
@@ -6,16 +6,20 @@
  * Supports pointing devices attached to a PS/2 type
  * Keyboard and Auxiliary Device Controller.
  *
- * Modified by Dean Troyer (troyer@saifr00.cfsat.Honeywell.COM) 03Oct92
- *   to perform (some of) the hardware initialization formerly done in
- *   setup.S by the BIOS
+ * Corrections in device setup for some laptop mice & trackballs.
+ * 02Feb93  (troyer@saifr00.cfsat.Honeywell.COM,mch@wimsey.bc.ca)
  *
- * Modified by Dean Troyer (troyer@saifr00.cfsat.Honeywell.COM) 09Oct92
- *   to perform the hardware initialization formerly done in setup.S by
- *   the BIOS.  Mouse characteristic setup is now included.
+ * Changed to prevent keyboard lockups on AST Power Exec.
+ * 28Jul93  Brad Bosch - brad@lachman.com
  *
+ * Modified by Johan Myreen (jem@cs.hut.fi) 04Aug93
+ *   to include support for QuickPort mouse.
  */
 
+/* Uncomment the following line if your mouse needs initialization. */
+
+/* #define INITIALIZE_DEVICE */
+
 #include <linux/timer.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
@@ -26,6 +30,8 @@
 #include <asm/segment.h>
 #include <asm/system.h>
 
+#include <linux/config.h>
+
 /* aux controller ports */
 #define AUX_INPUT_PORT	0x60		/* Aux device output buffer */
 #define AUX_OUTPUT_PORT	0x60		/* Aux device input buffer */
@@ -33,7 +39,7 @@
 #define AUX_STATUS	0x64		/* Aux device status reg */
 
 /* aux controller status bits */
-#define AUX_OBUF_FULL	0x01		/* output buffer (from device) full */
+#define AUX_OBUF_FULL	0x21		/* output buffer (from device) full */
 #define AUX_IBUF_FULL	0x02		/* input buffer (to device) full */
 
 /* aux controller commands */
@@ -48,18 +54,37 @@
 
 /* aux device commands */
 #define AUX_SET_RES	0xe8		/* set resolution */
-#define AUX_SET_SCALE	0xe9		/* set scaling factor */
+#define AUX_SET_SCALE11	0xe6		/* set 1:1 scaling */
+#define AUX_SET_SCALE21	0xe7		/* set 2:1 scaling */
+#define AUX_GET_SCALE	0xe9		/* get scaling factor */
 #define AUX_SET_STREAM	0xea		/* set stream mode */
 #define AUX_SET_SAMPLE	0xf3		/* set sample rate */
 #define AUX_ENABLE_DEV	0xf4		/* enable aux device */
 #define AUX_DISABLE_DEV	0xf5		/* disable aux device */
 #define AUX_RESET	0xff		/* reset aux device */
 
-#define MAX_RETRIES	3
+#define MAX_RETRIES	30		/* some aux operations take long time*/
 #define AUX_IRQ		12
 #define AUX_BUF_SIZE	2048
 
+/* QuickPort definitions */
+
+#define QP_DATA         0x310		/* Data Port I/O Address */
+#define QP_STATUS       0x311		/* Status Port I/O Address */
+
+#define QP_DEV_IDLE     0x01	        /* Device Idle */
+#define QP_RX_FULL      0x02		/* Device Char received */
+#define QP_TX_IDLE      0x04		/* Device XMIT Idle */
+#define QP_RESET        0x08		/* Device Reset */
+#define QP_INTS_ON      0x10		/* Device Interrupt On */
+#define QP_ERROR_FLAG   0x20		/* Device Error */
+#define QP_CLEAR        0x40		/* Device Clear */
+#define QP_ENABLE       0x80		/* Device Enable */
+
+#define QP_IRQ          12
+
 extern unsigned char aux_device_present;
+extern unsigned char kbd_read_mask;	/* from keyboard.c */
 
 struct aux_queue {
 	unsigned long head;
@@ -72,37 +97,56 @@
 static int aux_ready = 0;
 static int aux_busy = 0;
 static int aux_present = 0;
+static int poll_aux_status(void);
 
-static int poll_status(void);
+#ifdef CONFIG_QUICKPORT_MOUSE
+static int qp_present = 0;
+static int qp_busy = 0;
+static int qp_data = QP_DATA;
+static int qp_status = QP_STATUS;
+
+static int poll_qp_status(void);
+static int probe_qp(void);
+#endif
+
 
 /*
  * Write to aux device
  */
+
 static void aux_write_dev(int val)
 {
-	poll_status();
+	poll_aux_status();
 	outb_p(AUX_MAGIC_WRITE,AUX_COMMAND);	/* write magic cookie */
-	poll_status();
+	poll_aux_status();
 	outb_p(val,AUX_OUTPUT_PORT);		/* write data */
-	
 }
 
-#if 0
 /*
  * Write to device & handle returned ack
  */
  
+#if defined INITIALIZE_DEVICE
 static int aux_write_ack(int val)
 {
+        int retries = 0;
+
 	aux_write_dev(val);		/* write the value to the device */
-	while ((inb(AUX_STATUS) & AUX_OBUF_FULL) == 0);  /* wait for ack */
-	if ((inb(AUX_STATUS) & 0x20) == 0x20)
+	while ((inb(AUX_STATUS) & AUX_OBUF_FULL) != AUX_OBUF_FULL
+	            && retries < MAX_RETRIES) {          /* wait for ack */
+       		current->state = TASK_INTERRUPTIBLE;
+		current->timeout = jiffies + 5;
+		schedule();
+		retries++;
+        }
+
+	if ((inb(AUX_STATUS) & AUX_OBUF_FULL) == AUX_OBUF_FULL)
 	{
 		return (inb(AUX_INPUT_PORT));
 	}
 	return 0;
 }
-#endif
+#endif /* INITIALIZE_DEVICE */
 
 /*
  * Write aux device command
@@ -110,9 +154,9 @@
 
 static void aux_write_cmd(int val)
 {
-	poll_status();
+	poll_aux_status();
 	outb_p(AUX_CMD_WRITE,AUX_COMMAND);
-	poll_status();
+	poll_aux_status();
 	outb_p(val,AUX_OUTPUT_PORT);
 }
 
@@ -137,6 +181,7 @@
 }
 
 
+
 /*
  * Interrupt from the auxiliary device: a character
  * is waiting in the keyboard/aux controller.
@@ -157,18 +202,55 @@
 	wake_up_interruptible(&queue->proc_list);
 }
 
+/*
+ * Interrupt handler for the QuickPort. A character
+ * is waiting in the 82C710.
+ */
+
+#ifdef CONFIG_QUICKPORT_MOUSE
+static void qp_interrupt(int cpl)
+{
+	int head = queue->head;
+	int maxhead = (queue->tail-1) & (AUX_BUF_SIZE-1);
+
+	queue->buf[head] = inb(qp_data);
+	if (head != maxhead) {
+		head++;
+		head &= AUX_BUF_SIZE-1;
+	}
+	queue->head = head;
+	aux_ready = 1;
+	wake_up_interruptible(&queue->proc_list);
+}
+#endif
+
 
 static void release_aux(struct inode * inode, struct file * file)
 {
-	poll_status();
 	aux_write_dev(AUX_DISABLE_DEV);		/* disable aux device */
-	poll_status();
-	outb_p(AUX_DISABLE,AUX_COMMAND);      	/* Disable Aux device */
 	aux_write_cmd(AUX_INTS_OFF);		/* disable controller ints */
+	poll_aux_status();
+	outb_p(AUX_DISABLE,AUX_COMMAND);      	/* Disable Aux device */
+	poll_aux_status();
 	free_irq(AUX_IRQ);
 	aux_busy = 0;
 }
 
+#ifdef CONFIG_QUICKPORT_MOUSE
+static void release_qp(struct inode * inode, struct file * file)
+{
+	unsigned char status;
+
+	if (!poll_qp_status())
+	        printk("Warning: QuickPort device busy in release_qp()\n");
+	status = inb_p(qp_status);
+	outb_p(status & ~(QP_ENABLE|QP_INTS_ON), qp_status);
+	if (!poll_qp_status())
+	        printk("Warning: QuickPort device busy in release_qp()\n");
+	free_irq(QP_IRQ);
+	qp_busy = 0;
+}
+#endif
 
 /*
  * Install interrupt handler.
@@ -181,19 +263,65 @@
 		return -EINVAL;
 	if (aux_busy)
 		return -EBUSY;
-	if (!poll_status())
+	if (!poll_aux_status())
 		return -EBUSY;
 	aux_busy = 1;
-	queue->head = queue->tail = 0;  /* Flush input queue */
-	if (request_irq(AUX_IRQ, aux_interrupt))
+	queue->head = queue->tail = 0;	        /* Flush input queue */
+	if (request_irq(AUX_IRQ, aux_interrupt)) {
+		aux_busy = 0;
 		return -EBUSY;
+	}
+	poll_aux_status();
+	outb_p(AUX_ENABLE,AUX_COMMAND);		/* Enable Aux */
 	aux_write_dev(AUX_ENABLE_DEV);		/* enable aux device */
 	aux_write_cmd(AUX_INTS_ON);		/* enable controller ints */
-	poll_status();
-	outb_p(AUX_ENABLE,AUX_COMMAND);		/* Enable Aux */
+	poll_aux_status();
+	aux_ready = 0;
 	return 0;
 }
 
+#ifdef CONFIG_QUICKPORT_MOUSE
+/*
+ * Install interrupt handler.
+ * Enable the device, enable interrupts. Set qp_busy
+ * (allow only one opener at a time.)
+ */
+
+static int open_qp(struct inode * inode, struct file * file)
+{
+        unsigned char status;
+
+	if (!qp_present)
+		return -EINVAL;
+
+	if (qp_busy)
+		return -EBUSY;
+
+	if (request_irq(QP_IRQ, qp_interrupt))
+		return -EBUSY;
+
+	qp_busy = 1;
+
+	status = inb_p(qp_status);
+	status |= (QP_ENABLE|QP_RESET);
+	outb_p(status, qp_status);
+	status &= ~(QP_RESET);
+	outb_p(status, qp_status);
+
+	queue->head = queue->tail = 0;          /* Flush input queue */
+	status |= QP_INTS_ON;
+	outb_p(status, qp_status);              /* Enable interrupts */
+
+	while (!poll_qp_status()) {
+	        printk("Error: QuickPort device busy in open_qp()\n");
+		return -EBUSY;
+        }
+
+	outb_p(AUX_ENABLE_DEV, qp_data);	/* Wake up mouse */
+
+	return 0;
+}
+#endif
 
 /*
  * Write to the aux device.
@@ -204,10 +332,10 @@
 	int i = count;
 
 	while (i--) {
-		if (!poll_status())
+		if (!poll_aux_status())
 			return -EIO;
 		outb_p(AUX_MAGIC_WRITE,AUX_COMMAND);
-		if (!poll_status())
+		if (!poll_aux_status())
 			return -EIO;
 		outb_p(get_fs_byte(buffer++),AUX_OUTPUT_PORT);
 	}
@@ -216,6 +344,26 @@
 }
 
 
+#ifdef CONFIG_QUICKPORT_MOUSE
+/*
+ * Write to the QuickPort device.
+ */
+
+static int write_qp(struct inode * inode, struct file * file, char * buffer, int count)
+{
+	int i = count;
+
+	while (i--) {
+		if (!poll_qp_status())
+			return -EIO;
+		outb_p(get_fs_byte(buffer++), qp_data);
+	}
+	inode->i_mtime = CURRENT_TIME;
+	return count;
+}
+#endif
+
+
 /*
  * Put bytes from input queue to buffer.
  */
@@ -279,34 +427,121 @@
 };
 
 
+/*
+ * Initialize driver. First check for QuickPort device; if found
+ * forget about the Aux port and use the QuickPort functions.
+ */
+
 unsigned long psaux_init(unsigned long kmem_start)
 {
-	if (aux_device_present != 0xaa) {
-		return kmem_start;
+        int qp_found = 0;
+
+#ifdef CONFIG_QUICKPORT_MOUSE
+	printk("Probing QuickPort device.\n");
+        if (qp_found = probe_qp()) {
+	        printk("QuickPort pointing device detected -- driver installed.\n");
+/*		printk("QuickPort address = %x (should be 0x310)\n", qp_data); */
+		qp_present = 1;
+		psaux_fops.write = write_qp;
+		psaux_fops.open = open_qp;
+		psaux_fops.release = release_qp;
+		poll_qp_status();
+	} else
+#endif
+	if (aux_device_present == 0xaa) {
+	        printk("PS/2 auxiliary pointing device detected -- driver installed.\n");
+         	aux_present = 1;
+		kbd_read_mask = AUX_OBUF_FULL;
+	        poll_aux_status();
+	} else {
+		return kmem_start;              /* No mouse at all */
 	}
-	printk("PS/2 type pointing device detected and installed.\n");
 	queue = (struct aux_queue *) kmem_start;
 	kmem_start += sizeof (struct aux_queue);
 	queue->head = queue->tail = 0;
 	queue->proc_list = NULL;
-	aux_present = 1;
-	poll_status();
-	outb_p(AUX_DISABLE,AUX_COMMAND);      	/* Disable Aux device */
-	aux_write_cmd(AUX_INTS_OFF);		/* disable controller ints */
+	if (!qp_found) {
+#if defined INITIALIZE_DEVICE
+                outb_p(AUX_ENABLE,AUX_COMMAND);		/* Enable Aux */
+	        aux_write_ack(AUX_SET_SAMPLE);
+	        aux_write_ack(100);			/* 100 samples/sec */
+	        aux_write_ack(AUX_SET_RES);
+	        aux_write_ack(3);			/* 8 counts per mm */
+	        aux_write_ack(AUX_SET_SCALE21);		/* 2:1 scaling */
+	        poll_aux_status();
+#endif /* INITIALIZE_DEVICE */
+        	outb_p(AUX_DISABLE,AUX_COMMAND);   /* Disable Aux device */
+	        aux_write_cmd(AUX_INTS_OFF);    /* disable controller ints */
+		poll_aux_status();
+	}
 	return kmem_start;
 }
 
-
-static int poll_status(void)
+static int poll_aux_status(void)
 {
 	int retries=0;
 
-	while ((inb(AUX_STATUS)&0x03) && retries++ < MAX_RETRIES) {
-		if (inb_p(AUX_STATUS)&0x01)
+	while ((inb(AUX_STATUS)&0x03) && retries < MAX_RETRIES) {
+ 		if (inb_p(AUX_STATUS) & AUX_OBUF_FULL == AUX_OBUF_FULL)
 			inb_p(AUX_INPUT_PORT);
 		current->state = TASK_INTERRUPTIBLE;
 		current->timeout = jiffies + 5;
 		schedule();
+		retries++;
 	}
 	return !(retries==MAX_RETRIES);
 }
+
+#ifdef CONFIG_QUICKPORT_MOUSE
+/*
+ * Wait for device to send output char and flush any input char.
+ */
+
+static int poll_qp_status(void)
+{
+	int retries=0;
+
+	while ((inb(qp_status)&(QP_RX_FULL|QP_TX_IDLE|QP_DEV_IDLE))
+	               != (QP_DEV_IDLE|QP_TX_IDLE)
+	               && retries < MAX_RETRIES) {
+
+	        if (inb_p(qp_status)&(QP_RX_FULL))
+		        inb_p(qp_data);
+		current->state = TASK_INTERRUPTIBLE;
+		current->timeout = jiffies + 5;
+		schedule();
+		retries++;
+	}
+	return !(retries==MAX_RETRIES);
+}
+
+/*
+ * Function to read register in 82C710.
+ */
+
+static inline unsigned char read_710(unsigned char index)
+{
+        outb_p(index, 0x390);			/* Write index */
+	return inb_p(0x391);			/* Read the data */
+}
+
+/*
+ * See if we can find a QuickPort device. Read mouse address.
+ */
+
+static int probe_qp(void)
+{
+        outb_p(0x55, 0x2fa);			/* Any value except 9, ff or 36 */
+	outb_p(0xaa, 0x3fa);			/* Inverse of 55 */
+	outb_p(0x36, 0x3fa);			/* Address the chip */
+	outb_p(0xe4, 0x3fa);			/* 390/4; 390 = config address */
+	outb_p(0x1b, 0x2fa);			/* Inverse of e4 */
+	if (read_710(0x0f) != 0xe4)		/* Config address found? */
+	  return 0;				/* No: no 82C710 here */
+	qp_data = read_710(0x0d)*4;		/* Get mouse I/O address */
+	qp_status = qp_data+1;
+	outb_p(0x0f, 0x390);
+	outb_p(0x0f, 0x391);			/* Close config mode */
+	return 1;
+}
+#endif
diff --git a/kernel/chr_drv/serial.c b/kernel/chr_drv/serial.c
index 6d3bb7a..204cca5 100644
--- a/kernel/chr_drv/serial.c
+++ b/kernel/chr_drv/serial.c
@@ -456,7 +456,7 @@
 		if (IRQ_timer[i] < timeout)
 			timeout = IRQ_timer[i];
 	}
-	timer_table[RS_TIMER].expires = timeout;
+	timer_table[RS_TIMER].expires = jiffies + timeout;
 	timer_active |= 1 << RS_TIMER;
 }
 
@@ -514,7 +514,7 @@
 				break; 		/* Prevent infinite loops */
 		}
 	}
-	if (info = IRQ_ports[irq]) {
+	if ((info = IRQ_ports[irq]) != NULL) {
 #ifdef 0
 		do {
 			serial_outp(info, UART_IER, 0);
@@ -1321,12 +1321,10 @@
 	
 	switch (cmd) {
 		case TCSBRK:	/* SVID version: non-zero arg --> no break */
-			wait_until_sent(tty);
 			if (!arg)
 				send_break(info, HZ/4);	/* 1/4 second */
 			return 0;
 		case TCSBRKP:	/* support for POSIX tcsendbreak() */
-			wait_until_sent(tty);
 			send_break(info, arg ? arg*(HZ/10) : HZ/4);
 			return 0;
 		case TIOCGSOFTCAR:
diff --git a/kernel/chr_drv/tty_io.c b/kernel/chr_drv/tty_io.c
index 532ef8d..dd6c81e 100644
--- a/kernel/chr_drv/tty_io.c
+++ b/kernel/chr_drv/tty_io.c
@@ -618,7 +618,7 @@
 		}
 		if (I_IXON(tty) && !tty->lnext) {
 			if (c == STOP_CHAR(tty)) {
-			        tty->status_changed = 1;
+				tty->ctrl_status &= ~(TIOCPKT_START);
 				tty->ctrl_status |= TIOCPKT_STOP;
 				tty->stopped=1;
 				if (tty->stop)
@@ -631,7 +631,7 @@
 			}
 			if (((I_IXANY(tty)) && tty->stopped) ||
 			    (c == START_CHAR(tty))) {
-			        tty->status_changed = 1;
+			    	tty->ctrl_status &= ~(TIOCPKT_STOP);
 				tty->ctrl_status |= TIOCPKT_START;
 				tty->stopped=0;
 				if (tty->start)
@@ -646,18 +646,27 @@
 		if (L_ISIG(tty) && !tty->lnext) {
 			if (c == INTR_CHAR(tty)) {
 				kill_pg(tty->pgrp, SIGINT, 1);
-				flush_input(tty);
+				if (! _L_FLAG(tty, NOFLSH)) {
+				  flush_input(tty);
+				  flush_output(tty);
+				}
 				continue;
 			}
 			if (c == QUIT_CHAR(tty)) {
 				kill_pg(tty->pgrp, SIGQUIT, 1);
-				flush_input(tty);
+				if (! _L_FLAG(tty, NOFLSH)) {
+				  flush_input(tty);
+				  flush_output(tty);
+				}
 				continue;
 			}
 			if (c == SUSPEND_CHAR(tty)) {
 				if (!is_orphaned_pgrp(tty->pgrp)) {
 					kill_pg(tty->pgrp, SIGTSTP, 1);
-					flush_input(tty);
+					if (! _L_FLAG(tty, NOFLSH)) {
+					  flush_input(tty);
+					  flush_output(tty);
+					}
 				}
 				continue;
 			}
@@ -750,9 +759,9 @@
 		minimum = nr;
 
 	/* deal with packet mode:  First test for status change */
-	if (tty->packet && tty->link && tty->link->status_changed) {
+	if (tty->packet && tty->link && tty->link->ctrl_status) {
 		put_fs_byte (tty->link->ctrl_status, b);
-		tty->link->status_changed = 0;
+		tty->link->ctrl_status = 0;
 		return 1;
 	}
 	  
@@ -1310,7 +1319,6 @@
 	 * variables get cleared.  Come to think of it, is anything 
 	 * using the packet mode at all???  - Ted, 1/27/93
 	 */
-	tty->status_changed = 0;
 	tty->ctrl_status = 0;
 	tty->packet = 0;
 
@@ -1596,7 +1604,7 @@
 		tp->c_lflag = ISIG | ICANON | ECHO |
 			ECHOCTL | ECHOKE;
 	} else if (IS_A_SERIAL(line)) {
-		tp->c_cflag = B2400 | CS8 | CREAD | HUPCL | CLOCAL;
+		tp->c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
 		tp->c_oflag = OPOST | ONLCR | XTABS;
 	} else if (IS_A_PTY_MASTER(line)) {
 		tp->c_cflag = B9600 | CS8 | CREAD;
diff --git a/kernel/chr_drv/tty_ioctl.c b/kernel/chr_drv/tty_ioctl.c
index 9efe47f..c50215d 100644
--- a/kernel/chr_drv/tty_ioctl.c
+++ b/kernel/chr_drv/tty_ioctl.c
@@ -51,7 +51,6 @@
 
 void flush_input(struct tty_struct * tty)
 {
-        tty->status_changed = 1;
 	tty->ctrl_status |= TIOCPKT_FLUSHREAD;
 	flush(&tty->read_q);
 	wake_up_interruptible(&tty->read_q.proc_list);
@@ -66,7 +65,6 @@
 
 void flush_output(struct tty_struct * tty)
 {
-   	tty->status_changed = 1;
 	tty->ctrl_status |= TIOCPKT_FLUSHWRITE;
 	flush(&tty->write_q);
 	wake_up_interruptible(&tty->write_q.proc_list);
@@ -184,7 +182,7 @@
 static int set_termios(struct tty_struct * tty, struct termios * termios,
 			int channel)
 {
-	int i;
+	int i, old_flow, new_flow;
 	struct termios old_termios = *tty->termios;
 
 	i = check_change(tty, channel);
@@ -193,6 +191,24 @@
 	for (i=0 ; i< (sizeof (*termios)) ; i++)
 		((char *)tty->termios)[i]=get_fs_byte(i+(char *)termios);
 
+	/* see if packet mode change of state */
+
+	old_flow = (old_termios.c_iflag & IXON) &&
+	      (old_termios.c_cc[VSTOP] == '\023') &&
+	      (old_termios.c_cc[VSTART] == '\021');
+
+	new_flow = (tty->termios->c_iflag & IXON) &&
+	      (tty->termios->c_cc[VSTOP] == '\023') &&
+	      (tty->termios->c_cc[VSTART] == '\021');
+
+	if (old_flow != new_flow) {
+	  tty->ctrl_status &= ~(TIOCPKT_DOSTOP|TIOCPKT_NOSTOP);
+	  if (new_flow)
+	     tty->ctrl_status |= TIOCPKT_DOSTOP;
+	  else
+	     tty->ctrl_status |= TIOCPKT_NOSTOP;		
+	}
+
 	/* puting mpty's into echo mode is very bad, and I think under
 	   some situations can cause the kernel to do nothing but
 	   copy characters back and forth. -RAB */
@@ -239,7 +255,7 @@
 static int set_termio(struct tty_struct * tty, struct termio * termio,
 			int channel)
 {
-	int i;
+	int i, old_flow, new_flow;
 	struct termio tmp_termio;
 	struct termios old_termios = *tty->termios;
 
@@ -249,21 +265,6 @@
 	for (i=0 ; i< (sizeof (*termio)) ; i++)
 		((char *)&tmp_termio)[i]=get_fs_byte(i+(char *)termio);
 
-	/* take care of the packet stuff. */
-	if ((tmp_termio.c_iflag & IXON) &&
-	    !(tty->termios->c_iflag & IXON))
-	  {
-	     tty->status_changed = 1;
-	     tty->ctrl_status |= TIOCPKT_DOSTOP;
-	  }
-
-	if ((tty->termios->c_iflag & IXON) &&
-	    !(tmp_termio.c_iflag & IXON))
-	  {
-	     tty->status_changed = 1;
-	     tty->ctrl_status |= TIOCPKT_NOSTOP;
-	  }
-
 	*(unsigned short *)&tty->termios->c_iflag = tmp_termio.c_iflag;
 	*(unsigned short *)&tty->termios->c_oflag = tmp_termio.c_oflag;
 	*(unsigned short *)&tty->termios->c_cflag = tmp_termio.c_cflag;
@@ -271,6 +272,25 @@
 	for(i=0 ; i < NCC ; i++)
 		tty->termios->c_cc[i] = tmp_termio.c_cc[i];
 
+	/* see if packet mode change of state */
+
+	old_flow = (old_termios.c_iflag & IXON) &&
+	      (old_termios.c_cc[VSTOP] == '\023') &&
+	      (old_termios.c_cc[VSTART] == '\021');
+
+	new_flow = (tty->termios->c_iflag & IXON) &&
+	      (tty->termios->c_cc[VSTOP] == '\023') &&
+	      (tty->termios->c_cc[VSTART] == '\021');
+
+	if (old_flow != new_flow) {
+	  tty->ctrl_status &= ~(TIOCPKT_DOSTOP|TIOCPKT_NOSTOP);
+	  if (new_flow)
+	     tty->ctrl_status |= TIOCPKT_DOSTOP;
+	  else
+	     tty->ctrl_status |= TIOCPKT_NOSTOP;		
+	}
+
+
 	unset_locked_termios(tty->termios, &old_termios,
 			     termios_locked[tty->line]);
 
@@ -605,7 +625,12 @@
 			     tty->packet = 0;
 			   return (0);
 			}
-
+		case TCSBRK: case TCSBRKP:
+			wait_until_sent(tty);
+			if (!tty->ioctl)
+				return 0;
+			tty->ioctl(tty, file, cmd, arg);
+			return 0;
 		default:
 			if (tty->ioctl) {
 				retval = (tty->ioctl)(tty, file, cmd, arg);
diff --git a/kernel/chr_drv/vt.c b/kernel/chr_drv/vt.c
index b1f9c59..124bd9a 100644
--- a/kernel/chr_drv/vt.c
+++ b/kernel/chr_drv/vt.c
@@ -35,7 +35,7 @@
 
 struct vt_cons vt_cons[NR_CONSOLES];
 
-extern "C" int sys_ioperm(unsigned long from, unsigned long num, int on);
+asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on);
 
 extern void change_console(unsigned int new_console);
 extern void complete_change_console(unsigned int new_console);
diff --git a/kernel/exit.c b/kernel/exit.c
index 09b905e..d324cb6 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -274,7 +274,7 @@
  * POSIX specifies that kill(-1,sig) is unspecified, but what we have
  * is probably wrong.  Should make it like BSD or SYSV.
  */
-extern "C" int sys_kill(int pid,int sig)
+asmlinkage int sys_kill(int pid,int sig)
 {
 	int err, retval = 0, count = 0;
 
@@ -376,7 +376,7 @@
 		current->mmap = NULL;
 		while (mpnt) {
 			mpnt1 = mpnt->vm_next;
-			if (mpnt->vm_ops->close)
+			if (mpnt->vm_ops && mpnt->vm_ops->close)
 				mpnt->vm_ops->close(mpnt);
 			kfree(mpnt);
 			mpnt = mpnt1;
@@ -491,12 +491,12 @@
 	goto fake_volatile;
 }
 
-extern "C" int sys_exit(int error_code)
+asmlinkage int sys_exit(int error_code)
 {
 	do_exit((error_code&0xff)<<8);
 }
 
-extern "C" int sys_wait4(pid_t pid,unsigned long * stat_addr, int options, struct rusage * ru)
+asmlinkage int sys_wait4(pid_t pid,unsigned long * stat_addr, int options, struct rusage * ru)
 {
 	int flag, retval;
 	struct wait_queue wait = { current, NULL };
@@ -587,7 +587,7 @@
  * sys_waitpid() remains for compatibility. waitpid() should be
  * implemented by calling sys_wait4() from libc.a.
  */
-extern "C" int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options)
+asmlinkage int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options)
 {
 	return sys_wait4(pid, stat_addr, options, NULL);
 }
diff --git a/kernel/fork.c b/kernel/fork.c
index 848615d..39b832d 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -23,16 +23,19 @@
 #include <asm/segment.h>
 #include <asm/system.h>
 
-extern "C" void ret_from_sys_call(void) __asm__("ret_from_sys_call");
+asmlinkage void ret_from_sys_call(void) __asm__("ret_from_sys_call");
+
+/* These should maybe be in <linux/tasks.h> */
 
 #define MAX_TASKS_PER_USER (NR_TASKS/2)
+#define MIN_TASKS_LEFT_FOR_ROOT 4
 
 extern int shm_fork(struct task_struct *, struct task_struct *);
 long last_pid=0;
 
 static int find_empty_process(void)
 {
-	int i, task_nr;
+	int i, task_nr, tasks_free;
 	int this_user_tasks;
 
 repeat:
@@ -49,17 +52,19 @@
 	}
 	if (this_user_tasks > MAX_TASKS_PER_USER && current->uid)
 		return -EAGAIN;
-/* Only the super-user can fill the last available slot */
-	task_nr = 0;
-	for(i=1 ; i<NR_TASKS ; i++)
-		if (!task[i])
-			if (task_nr)
-				return task_nr;
-			else
-				task_nr = i;
-	if (task_nr && suser())
-		return task_nr;
-	return -EAGAIN;
+
+/* Only the super-user can fill the last MIN_TASKS_LEFT_FOR_ROOT slots */
+
+	tasks_free = 0; task_nr = 0;
+	for (i=NR_TASKS-1; i > 0; i--) {
+		if (!task[i]) {
+			tasks_free++;
+			task_nr = i;
+		}
+	} 
+	if (tasks_free <= MIN_TASKS_LEFT_FOR_ROOT && current->uid)
+		return -EAGAIN;
+	return task_nr;
 }
 
 static struct file * copy_fd(struct file * old_file)
@@ -113,7 +118,7 @@
  * information (task[nr]) and sets up the necessary registers. It
  * also copies the data segment in it's entirety.
  */
-extern "C" int sys_fork(struct pt_regs regs)
+asmlinkage int sys_fork(struct pt_regs regs)
 {
 	struct pt_regs * childregs;
 	struct task_struct *p;
@@ -176,7 +181,7 @@
 	p->exit_signal = clone_flags & CSIGNAL;
 	p->tss.ldt = _LDT(nr);
 	if (p->ldt) {
-		if (p->ldt = (struct desc_struct*) __get_free_page(GFP_KERNEL))
+		if ((p->ldt = (struct desc_struct*) __get_free_page(GFP_KERNEL)) != NULL)
 			memcpy(p->ldt, current->ldt, PAGE_SIZE);
 	}
 	p->tss.bitmap = offsetof(struct tss_struct,io_bitmap);
diff --git a/kernel/info.c b/kernel/info.c
index cf6fa43..27cb324 100644
--- a/kernel/info.c
+++ b/kernel/info.c
@@ -14,7 +14,7 @@
 #include <linux/types.h>
 #include <linux/mm.h>
 
-extern "C" int sys_sysinfo(struct sysinfo *info)
+asmlinkage int sys_sysinfo(struct sysinfo *info)
 {
 	int error;
 	struct sysinfo val;
diff --git a/kernel/ioport.c b/kernel/ioport.c
index 87a55b6..883e58c 100644
--- a/kernel/ioport.c
+++ b/kernel/ioport.c
@@ -9,6 +9,9 @@
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/types.h>
+#include <linux/ioport.h>
+
+static unsigned long ioport_registrar[IO_BITMAP_SIZE] = {0, /* ... */};
 
 #define _IODEBUG
 
@@ -40,56 +43,87 @@
 }
 #endif
 
+/* Set EXTENT bits starting at BASE in BITMAP to value TURN_ON. */
+asmlinkage void set_bitmap(unsigned long *bitmap,
+						   short base, short extent, int new_value)
+{
+	int mask;
+	unsigned long *bitmap_base = bitmap + (base >> 5);
+	unsigned short low_index = base & 0x1f;
+	int length = low_index + extent;
+
+	if (low_index != 0) {
+		mask = (~0 << low_index);
+		if (length < 32)
+				mask &= ~(~0 << length);
+		if (new_value)
+			*bitmap_base++ |= mask;
+		else
+			*bitmap_base++ &= ~mask;
+		length -= 32;
+	}
+
+	mask = (new_value ? ~0 : 0);
+	while (length >= 32) {
+		*bitmap_base++ = mask;
+		length -= 32;
+	}
+
+	if (length > 0) {
+		mask = ~(~0 << length);
+		if (new_value)
+			*bitmap_base++ |= mask;
+		else
+			*bitmap_base++ &= ~mask;
+	}
+}
+
+/* Check for set bits in BITMAP starting at BASE, going to EXTENT. */
+asmlinkage int check_bitmap(unsigned long *bitmap, short base, short extent)
+{
+	int mask;
+	unsigned long *bitmap_base = bitmap + (base >> 5);
+	unsigned short low_index = base & 0x1f;
+	int length = low_index + extent;
+
+	if (low_index != 0) {
+		mask = (~0 << low_index);
+		if (length < 32)
+				mask &= ~(~0 << length);
+		if (*bitmap_base++ & mask)
+			return 1;
+		length -= 32;
+	}
+	while (length >= 32) {
+		if (*bitmap_base++ != 0)
+			return 1;
+		length -= 32;
+	}
+
+	if (length > 0) {
+		mask = ~(~0 << length);
+		if (*bitmap_base++ & mask)
+			return 1;
+	}
+	return 0;
+}
+
 /*
  * this changes the io permissions bitmap in the current task.
  */
-extern "C" int sys_ioperm(unsigned long from, unsigned long num, int turn_on)
+asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int turn_on)
 {
-	unsigned long froml, lindex, tnum, numl, rindex, mask;
-	unsigned long *iop;
-
 	if (from + num <= from)
 		return -EINVAL;
 	if (from + num > IO_BITMAP_SIZE*32)
 		return -EINVAL;
 	if (!suser())
 		return -EPERM;
-	froml = from >> 5;
-	lindex = from & 0x1f;
-	tnum = lindex + num;
-	numl = (tnum + 0x1f) >> 5;
-	rindex = tnum & 0x1f;
 
 #ifdef IODEBUG
 	printk("io: from=%d num=%d %s\n", from, num, (turn_on ? "on" : "off"));
 #endif
-
-	if (numl) {
-		iop = (unsigned long *)current->tss.io_bitmap + froml;
-		if (lindex != 0) {
-			mask = (~0 << lindex);
-			if (--numl == 0 && rindex)
-				mask &= ~(~0 << rindex);
-			if (turn_on)
-				*iop++ &= ~mask;
-			else
-				*iop++ |= mask;
-		}
-		if (numl) {
-			if (rindex)
-				--numl;
-			mask = (turn_on ? 0 : ~0);
-			while (numl--)
-				*iop++ = mask;
-			if (numl && rindex) {
-				mask = ~(~0 << rindex);
-				if (turn_on)
-					*iop++ &= ~mask;
-				else
-					*iop++ |= mask;
-			}
-		}
-	}
+	set_bitmap((unsigned long *)current->tss.io_bitmap, from, num, !turn_on);
 	return 0;
 }
 
@@ -105,7 +139,7 @@
  * on system-call entry - see also fork() and the signal handling
  * code.
  */
-extern "C" int sys_iopl(long ebx,long ecx,long edx,
+asmlinkage int sys_iopl(long ebx,long ecx,long edx,
 	     long esi, long edi, long ebp, long eax, long ds,
 	     long es, long fs, long gs, long orig_eax,
 	     long eip,long cs,long eflags,long esp,long ss)
@@ -119,3 +153,32 @@
 	*(&eflags) = (eflags & 0xffffcfff) | (level << 12);
 	return 0;
 }
+
+
+void snarf_region(unsigned int from, unsigned int num)
+{
+	if (from > IO_BITMAP_SIZE*32)
+		return;
+	if (from + num > IO_BITMAP_SIZE*32)
+		num = IO_BITMAP_SIZE*32 - from;
+	set_bitmap(ioport_registrar, from, num, 1);
+	return;
+}
+
+int check_region(unsigned int from, unsigned int num)
+{
+	if (from > IO_BITMAP_SIZE*32)
+		return 0;
+	if (from + num > IO_BITMAP_SIZE*32)
+		num = IO_BITMAP_SIZE*32 - from;
+	return check_bitmap(ioport_registrar, from, num);
+}
+
+/* Called from init/main.c to reserve IO ports. */
+void reserve_setup(char *str, int *ints)
+{
+	int i;
+
+	for (i = 1; i < ints[0]; i += 2)
+		snarf_region(ints[i], ints[i+1]);
+}
diff --git a/kernel/irq.c b/kernel/irq.c
index 3fd8b43..0fc155e 100644
--- a/kernel/irq.c
+++ b/kernel/irq.c
@@ -42,12 +42,52 @@
 unsigned long bh_mask = 0xFFFFFFFF;
 struct bh_struct bh_base[32]; 
 
+void disable_irq(unsigned int irq_nr)
+{
+	unsigned long flags;
+	unsigned char mask;
+
+	mask = 1 << (irq_nr & 7);
+	save_flags(flags);
+	if (irq_nr < 8) {
+		cli();
+		cache_21 |= mask;
+		outb(cache_21,0x21);
+		restore_flags(flags);
+		return;
+	}
+	cli();
+	cache_A1 |= mask;
+	outb(cache_A1,0xA1);
+	restore_flags(flags);
+}
+
+void enable_irq(unsigned int irq_nr)
+{
+	unsigned long flags;
+	unsigned char mask;
+
+	mask = ~(1 << (irq_nr & 7));
+	save_flags(flags);
+	if (irq_nr < 8) {
+		cli();
+		cache_21 &= mask;
+		outb(cache_21,0x21);
+		restore_flags(flags);
+		return;
+	}
+	cli();
+	cache_A1 &= mask;
+	outb(cache_A1,0xA1);
+	restore_flags(flags);
+}
+
 /*
  * do_bottom_half() runs at normal kernel priority: all interrupts
  * enabled.  do_bottom_half() is atomic with respect to itself: a
  * bottom_half handler need not be re-entrant.
  */
-extern "C" void do_bottom_half(void)
+asmlinkage void do_bottom_half(void)
 {
 	unsigned long active;
 	unsigned long mask, left;
@@ -156,7 +196,7 @@
  * IRQ's should use this format: notably the keyboard/timer
  * routines.
  */
-extern "C" void do_IRQ(int irq, struct pt_regs * regs)
+asmlinkage void do_IRQ(int irq, struct pt_regs * regs)
 {
 	struct sigaction * sa = irq + irq_sigaction;
 
@@ -168,7 +208,7 @@
  * stuff - the handler is also running with interrupts disabled unless
  * it explicitly enables them later.
  */
-extern "C" void do_fast_IRQ(int irq)
+asmlinkage void do_fast_IRQ(int irq)
 {
 	struct sigaction * sa = irq + irq_sigaction;
 
diff --git a/kernel/itimer.c b/kernel/itimer.c
index e7f507d..39d95e3 100644
--- a/kernel/itimer.c
+++ b/kernel/itimer.c
@@ -53,7 +53,7 @@
 	return(0);
 }
 
-extern "C" int sys_getitimer(int which, struct itimerval *value)
+asmlinkage int sys_getitimer(int which, struct itimerval *value)
 {
 	int error;
 	struct itimerval get_buffer;
@@ -98,7 +98,7 @@
 	return 0;
 }
 
-extern "C" int sys_setitimer(int which, struct itimerval *value, struct itimerval *ovalue)
+asmlinkage int sys_setitimer(int which, struct itimerval *value, struct itimerval *ovalue)
 {
 	int error;
 	struct itimerval set_buffer, get_buffer;
diff --git a/kernel/ldt.c b/kernel/ldt.c
index 021151e..5d9f514 100644
--- a/kernel/ldt.c
+++ b/kernel/ldt.c
@@ -86,7 +86,7 @@
 	return 0;
 }
 
-extern "C" int sys_modify_ldt(int func, void *ptr, unsigned long bytecount)
+asmlinkage int sys_modify_ldt(int func, void *ptr, unsigned long bytecount)
 {
 	if (func == 0)
 		return read_ldt(ptr, bytecount);
diff --git a/kernel/panic.c b/kernel/panic.c
index 2e8bdd7..24edec2 100644
--- a/kernel/panic.c
+++ b/kernel/panic.c
@@ -8,17 +8,26 @@
  * This function is used through-out the kernel (includeinh mm and fs)
  * to indicate a major problem.
  */
+#include <stdarg.h>
+
 #include <linux/kernel.h>
 #include <linux/sched.h>
 
-extern "C" void sys_sync(void);	/* it's really int */
+asmlinkage void sys_sync(void);	/* it's really int */
 
-volatile void panic(const char * s)
+extern int vsprintf(char * buf, const char * fmt, va_list args);
+
+volatile void panic(const char * fmt, ...)
 {
 	extern int log_to_console;
+	static char buf[1024];
+	va_list args;
 
+	va_start(args, fmt);
+	vsprintf(buf, fmt, args);
+	va_end(args);
 	log_to_console = 1;
-	printk("Kernel panic: %s\n",s);
+	printk("Kernel panic: %s\n",buf);
 	if (current == task[0])
 		printk("In swapper task - not syncing\n");
 	else
diff --git a/kernel/printk.c b/kernel/printk.c
index 3854604..7c37ee8 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -47,7 +47,7 @@
  * 	6 -- Disable printk's to console
  * 	7 -- Enable printk's to console
  */
-extern "C" int sys_syslog(int type, char * buf, int len)
+asmlinkage int sys_syslog(int type, char * buf, int len)
 {
 	unsigned long i, j, count;
 	int do_clear = 0;
@@ -104,7 +104,7 @@
 				count = logged_chars;
 			j = log_start + log_size - count;
 			for (i = 0; i < count; i++) {
-				c = *((char *) log_buf + (j++ & LOG_BUF_LEN-1));
+				c = *((char *) log_buf+(j++ & (LOG_BUF_LEN-1)));
 				put_fs_byte(c, buf++);
 			}
 			if (do_clear)
@@ -124,7 +124,7 @@
 }
 			
 
-extern "C" int printk(const char *fmt, ...)
+asmlinkage int printk(const char *fmt, ...)
 {
 	va_list args;
 	int i,j;
@@ -133,7 +133,7 @@
 	i=vsprintf(buf,fmt,args);
 	va_end(args);
 	for (j = 0; j < i ; j++) {
-		log_buf[(log_start+log_size) & LOG_BUF_LEN-1] = buf[j];
+		log_buf[(log_start+log_size) & (LOG_BUF_LEN-1)] = buf[j];
 		if (log_size < LOG_BUF_LEN)
 			log_size++;
 		else
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index 71626a4..ccc93a4 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -152,7 +152,7 @@
 	if ((addr & ~PAGE_MASK) > PAGE_SIZE-sizeof(long)) {
 		low = get_long(tsk,addr & ~(sizeof(long)-1));
 		high = get_long(tsk,(addr+sizeof(long)) & ~(sizeof(long)-1));
-		switch (addr & sizeof(long)-1) {
+		switch (addr & (sizeof(long)-1)) {
 			case 1:
 				low >>= 8;
 				low |= high << 24;
@@ -186,7 +186,7 @@
 	if ((addr & ~PAGE_MASK) > PAGE_SIZE-sizeof(long)) {
 		low = get_long(tsk,addr & ~(sizeof(long)-1));
 		high = get_long(tsk,(addr+sizeof(long)) & ~(sizeof(long)-1));
-		switch (addr & sizeof(long)-1) {
+		switch (addr & (sizeof(long)-1)) {
 			case 0: /* shouldn't happen, but safety first */
 				low = data;
 				break;
@@ -216,7 +216,7 @@
 	return 0;
 }
 
-extern "C" int sys_ptrace(long request, long pid, long addr, long data)
+asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
 {
 	struct task_struct *child;
 
@@ -285,6 +285,10 @@
 			if (res)
 				return res;
 			tmp = get_stack_long(child, sizeof(long)*addr - MAGICNUMBER);
+			if (addr == DS || addr == ES ||
+			    addr == FS || addr == GS ||
+			    addr == CS || addr == SS)
+				tmp &= 0xffff;
 			put_fs_long(tmp,(unsigned long *) data);
 			return 0;
 		}
@@ -302,8 +306,11 @@
 				return -EIO;
 			if (addr == DS || addr == ES ||
 			    addr == FS || addr == GS ||
-			    addr == CS || addr == SS)
-				return -EIO;
+			    addr == CS || addr == SS) {
+			    	data &= 0xffff;
+			    	if (data && (data & 3) != 3)
+					return -EIO;
+			}
 			if (addr == EFL) {   /* flags. */
 				data &= FLAG_MASK;
 				data |= get_stack_long(child, EFL*sizeof(long)-MAGICNUMBER)  & ~FLAG_MASK;
@@ -382,7 +389,7 @@
 	}
 }
 
-extern "C" void syscall_trace(void)
+asmlinkage void syscall_trace(void)
 {
 	if ((current->flags & (PF_PTRACED|PF_TRACESYS))
 			!= (PF_PTRACED|PF_TRACESYS))
diff --git a/kernel/sched.c b/kernel/sched.c
index 55d60d6..0cd5a3b 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -51,7 +51,7 @@
 extern void mem_use(void);
 
 extern int timer_interrupt(void);
-extern "C" int system_call(void);
+asmlinkage int system_call(void);
 
 static unsigned long init_kernel_stack[1024];
 struct task_struct init_task = INIT_TASK;
@@ -82,7 +82,7 @@
  * Careful.. There are problems with IBM-designed IRQ13 behaviour.
  * Don't touch unless you *really* know how it works.
  */
-extern "C" void math_state_restore(void)
+asmlinkage void math_state_restore(void)
 {
 	__asm__ __volatile__("clts");
 	if (last_task_used_math == current)
@@ -115,7 +115,7 @@
  * The "confuse_gcc" goto is used only to get better assembly code..
  * Djikstra probably hates me.
  */
-extern "C" void schedule(void)
+asmlinkage void schedule(void)
 {
 	int c;
 	struct task_struct * p;
@@ -143,7 +143,16 @@
 confuse_gcc1:
 
 /* this is the scheduler proper: */
-
+#if 0
+	/* give processes that go to sleep a bit higher priority.. */
+	/* This depends on the values for TASK_XXX */
+	/* This gives smoother scheduling for some things, but */
+	/* can be very unfair under some circumstances, so.. */
+ 	if (TASK_UNINTERRUPTIBLE >= (unsigned) current->state &&
+	    current->counter < current->priority*2) {
+		++current->counter;
+	}
+#endif
 	c = -1;
 	next = p = &init_task;
 	for (;;) {
@@ -160,7 +169,7 @@
 	switch_to(next);
 }
 
-extern "C" int sys_pause(void)
+asmlinkage int sys_pause(void)
 {
 	current->state = TASK_INTERRUPTIBLE;
 	schedule();
@@ -193,9 +202,9 @@
 		}
 		if (!tmp->next) {
 			printk("wait_queue is bad (eip = %08x)\n",((unsigned long *) q)[-1]);
-			printk("        q = %08x\n",q);
-			printk("       *q = %08x\n",*q);
-			printk("      tmp = %08x\n",tmp);
+			printk("        q = %p\n",q);
+			printk("       *q = %p\n",*q);
+			printk("      tmp = %p\n",tmp);
 			break;
 		}
 		tmp = tmp->next;
@@ -219,9 +228,9 @@
 		}
 		if (!tmp->next) {
 			printk("wait_queue is bad (eip = %08x)\n",((unsigned long *) q)[-1]);
-			printk("        q = %08x\n",q);
-			printk("       *q = %08x\n",*q);
-			printk("      tmp = %08x\n",tmp);
+			printk("        q = %p\n",q);
+			printk("       *q = %p\n",*q);
+			printk("      tmp = %p\n",tmp);
 			break;
 		}
 		tmp = tmp->next;
@@ -421,7 +430,7 @@
 	sti();
 }
 
-extern "C" int sys_alarm(long seconds)
+asmlinkage int sys_alarm(long seconds)
 {
 	struct itimerval it_new, it_old;
 
@@ -432,37 +441,37 @@
 	return(it_old.it_value.tv_sec + (it_old.it_value.tv_usec / 1000000));
 }
 
-extern "C" int sys_getpid(void)
+asmlinkage int sys_getpid(void)
 {
 	return current->pid;
 }
 
-extern "C" int sys_getppid(void)
+asmlinkage int sys_getppid(void)
 {
 	return current->p_pptr->pid;
 }
 
-extern "C" int sys_getuid(void)
+asmlinkage int sys_getuid(void)
 {
 	return current->uid;
 }
 
-extern "C" int sys_geteuid(void)
+asmlinkage int sys_geteuid(void)
 {
 	return current->euid;
 }
 
-extern "C" int sys_getgid(void)
+asmlinkage int sys_getgid(void)
 {
 	return current->gid;
 }
 
-extern "C" int sys_getegid(void)
+asmlinkage int sys_getegid(void)
 {
 	return current->egid;
 }
 
-extern "C" int sys_nice(long increment)
+asmlinkage int sys_nice(long increment)
 {
 	int newprio;
 
diff --git a/kernel/signal.c b/kernel/signal.c
index 6f6aeef..b84ce35 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -20,14 +20,39 @@
 
 extern int core_dump(long signr,struct pt_regs * regs);
 
-extern "C" int do_signal(unsigned long oldmask, struct pt_regs * regs);
+asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs);
 
-extern "C" int sys_sgetmask(void)
+struct sigcontext_struct {
+	unsigned short gs, __gsh;
+	unsigned short fs, __fsh;
+	unsigned short es, __esh;
+	unsigned short ds, __dsh;
+	unsigned long edi;
+	unsigned long esi;
+	unsigned long ebp;
+	unsigned long esp;
+	unsigned long ebx;
+	unsigned long edx;
+	unsigned long ecx;
+	unsigned long eax;
+	unsigned long trapno;
+	unsigned long err;
+	unsigned long eip;
+	unsigned short cs, __csh;
+	unsigned long eflags;
+	unsigned long esp_at_signal;
+	unsigned short ss, __ssh;
+	unsigned long i387;
+	unsigned long oldmask;
+	unsigned long cr2;
+};
+
+asmlinkage int sys_sgetmask(void)
 {
 	return current->blocked;
 }
 
-extern "C" int sys_ssetmask(int newmask)
+asmlinkage int sys_ssetmask(int newmask)
 {
 	int old=current->blocked;
 
@@ -35,7 +60,7 @@
 	return old;
 }
 
-extern "C" int sys_sigpending(sigset_t *set)
+asmlinkage int sys_sigpending(sigset_t *set)
 {
 	int error;
 	/* fill in "set" with signals pending but blocked. */
@@ -48,7 +73,7 @@
 /*
  * atomically swap in the new signal mask, and wait for a signal.
  */
-extern "C" int sys_sigsuspend(int restart, unsigned long oldmask, unsigned long set)
+asmlinkage int sys_sigsuspend(int restart, unsigned long oldmask, unsigned long set)
 {
 	unsigned long mask;
 	struct pt_regs * regs = (struct pt_regs *) &restart;
@@ -98,7 +123,7 @@
 	}	
 }
 
-extern "C" int sys_signal(int signum, unsigned long handler)
+asmlinkage int sys_signal(int signum, unsigned long handler)
 {
 	struct sigaction tmp;
 
@@ -116,7 +141,7 @@
 	return handler;
 }
 
-extern "C" int sys_sigaction(int signum, const struct sigaction * action,
+asmlinkage int sys_sigaction(int signum, const struct sigaction * action,
 	struct sigaction * oldaction)
 {
 	struct sigaction new_sa, *p;
@@ -146,35 +171,54 @@
 	return 0;
 }
 
-extern "C" int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options);
+asmlinkage int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options);
 
 /*
  * This sets regs->esp even though we don't actually use sigstacks yet..
  */
-extern "C" int sys_sigreturn(unsigned long oldmask, unsigned long eip, unsigned long esp)
+asmlinkage int sys_sigreturn(unsigned long __unused)
 {
+#define CHECK_SEG(x) if (x) x |= 3
+#define COPY(x) regs->x = context.x
+	struct sigcontext_struct context;
 	struct pt_regs * regs;
 
-	regs = (struct pt_regs *) &oldmask;
-	current->blocked = oldmask & _BLOCKABLE;
-	regs->eip = eip;
-	regs->esp = esp;
-	return 0;
+	regs = (struct pt_regs *) &__unused;
+	memcpy_fromfs(&context,(void *) regs->esp, sizeof(context));
+	current->blocked = context.oldmask & _BLOCKABLE;
+	CHECK_SEG(context.ss);
+	CHECK_SEG(context.cs);
+	CHECK_SEG(context.ds);
+	CHECK_SEG(context.es);
+	CHECK_SEG(context.fs);
+	CHECK_SEG(context.gs);
+	COPY(eip); COPY(eflags);
+	COPY(ecx); COPY(edx);
+	COPY(ebx);
+	COPY(esp); COPY(ebp);
+	COPY(edi); COPY(esi);
+	COPY(cs); COPY(ss);
+	COPY(ds); COPY(es);
+	COPY(fs); COPY(gs);
+	regs->orig_eax = -1;		/* disable syscall checks */
+	return context.eax;
 }
 
 /*
  * Set up a signal frame... Make the stack look the way iBCS2 expects
  * it to look.
  */
-static void setup_frame(unsigned long ** fp, unsigned long eip,
-	struct pt_regs * regs, int signr,
-	unsigned long sa_handler, unsigned long oldmask)
+static void setup_frame(struct sigaction * sa, unsigned long ** fp, unsigned long eip,
+	struct pt_regs * regs, int signr, unsigned long oldmask)
 {
 	unsigned long * frame;
 
 #define __CODE ((unsigned long)(frame+24))
 #define CODE(x) ((unsigned long *) ((x)+__CODE))
-	frame = *fp - 32;
+	frame = *fp;
+	if (regs->ss != USER_DS)
+		frame = (unsigned long *) sa->sa_restorer;
+	frame -= 32;
 	verify_area(VERIFY_WRITE,frame,32*4);
 /* set up the "normal" stack seen by the signal handler (iBCS2) */
 	put_fs_long(__CODE,frame);
@@ -186,32 +230,26 @@
 	put_fs_long(regs->edi, frame+6);
 	put_fs_long(regs->esi, frame+7);
 	put_fs_long(regs->ebp, frame+8);
-	put_fs_long(regs->esp, frame+9);
+	put_fs_long((long)*fp, frame+9);
 	put_fs_long(regs->ebx, frame+10);
 	put_fs_long(regs->edx, frame+11);
 	put_fs_long(regs->ecx, frame+12);
 	put_fs_long(regs->eax, frame+13);
-	put_fs_long(0, frame+14);		/* trapno */
-	put_fs_long(0, frame+15);		/* err */
-	put_fs_long(regs->eip, frame+16);
+	put_fs_long(0, frame+14);		/* trapno - not implemented */
+	put_fs_long(0, frame+15);		/* err - not implemented */
+	put_fs_long(eip, frame+16);
 	put_fs_long(regs->cs, frame+17);
 	put_fs_long(regs->eflags, frame+18);
 	put_fs_long(regs->esp, frame+19);
 	put_fs_long(regs->ss, frame+20);
-	put_fs_long(0,frame+21);		/* 387 state pointer */
-/* linux extended stack - easier to handle.. */
-	put_fs_long(regs->eflags, frame+22);
-	put_fs_long(eip, frame+23);
+	put_fs_long(0,frame+21);		/* 387 state pointer - not implemented*/
+/* non-iBCS2 extensions.. */
+	put_fs_long(oldmask, frame+22);
+	put_fs_long(0, frame+23);		/* cr2 - not implemented */
 /* set up the return code... */
 	put_fs_long(0x0000b858, CODE(0));	/* popl %eax ; movl $,%eax */
-	put_fs_long(0x00bb0000, CODE(4));	/* movl $,%ebx */
-	put_fs_long(0xcd000000, CODE(8));	/* int $0x80 */
-	put_fs_long(0x0fa90f80, CODE(12));	/* pop %gs ; pop %fs */
-	put_fs_long(0x611f07a1, CODE(16));	/* pop %es ; pop %ds ; popad */
-	put_fs_long(0x20c48390, CODE(20));	/* nop ; addl $32,%esp */
-	put_fs_long(0x0020c29d, CODE(24));	/* popfl ; ret $32 */
-	put_fs_long(__NR_ssetmask, CODE(2));
-	put_fs_long(oldmask, CODE(7));
+	put_fs_long(0x80cd0000, CODE(4));	/* int $0x80 */
+	put_fs_long(__NR_sigreturn, CODE(2));
 	*fp = frame;
 #undef __CODE
 #undef CODE
@@ -226,14 +264,13 @@
  * the kernel can handle, and then we build all the user-level signal handling
  * stack-frames in one go after that.
  */
-extern "C" int do_signal(unsigned long oldmask, struct pt_regs * regs)
+asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs)
 {
 	unsigned long mask = ~current->blocked;
 	unsigned long handler_signal = 0;
 	unsigned long *frame = NULL;
 	unsigned long eip = 0;
 	unsigned long signr;
-	unsigned long sa_handler;
 	struct sigaction * sa;
 
 	while ((signr = current->signal & mask)) {
@@ -317,20 +354,20 @@
 	frame = (unsigned long *) regs->esp;
 	signr = 1;
 	sa = current->sigaction;
-	if (regs->cs != USER_CS || regs->ss != USER_DS)
-		printk("Warning: signal handler with nonstandard code/stack segment\n");
 	for (mask = 1 ; mask ; sa++,signr++,mask += mask) {
 		if (mask > handler_signal)
 			break;
 		if (!(mask & handler_signal))
 			continue;
-		sa_handler = (unsigned long) sa->sa_handler;
+		setup_frame(sa,&frame,eip,regs,signr,oldmask);
+		eip = (unsigned long) sa->sa_handler;
 		if (sa->sa_flags & SA_ONESHOT)
 			sa->sa_handler = NULL;
 /* force a supervisor-mode page-in of the signal handler to reduce races */
-		__asm__("testb $0,%%fs:%0": :"m" (*(char *) sa_handler));
-		setup_frame(&frame,eip,regs,signr,sa_handler,oldmask);
-		eip = sa_handler;
+		__asm__("testb $0,%%fs:%0": :"m" (*(char *) eip));
+		regs->cs = USER_CS; regs->ss = USER_DS;
+		regs->ds = USER_DS; regs->es = USER_DS;
+		regs->gs = USER_DS; regs->fs = USER_DS;
 		current->blocked |= sa->sa_mask;
 		oldmask |= sa->sa_mask;
 	}
diff --git a/kernel/sys.c b/kernel/sys.c
index de25852..310989e 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -56,7 +56,7 @@
 	return 0;
 }
 
-extern "C" int sys_setpriority(int which, int who, int niceval)
+asmlinkage int sys_setpriority(int which, int who, int niceval)
 {
 	struct task_struct **p;
 	int error = ESRCH;
@@ -86,7 +86,7 @@
 	return -error;
 }
 
-extern "C" int sys_getpriority(int which, int who)
+asmlinkage int sys_getpriority(int which, int who)
 {
 	struct task_struct **p;
 	int max_prio = 0;
@@ -103,37 +103,37 @@
 	return(max_prio ? max_prio : -ESRCH);
 }
 
-extern "C" int sys_profil(void)
+asmlinkage int sys_profil(void)
 {
 	return -ENOSYS;
 }
 
-extern "C" int sys_ftime(void)
+asmlinkage int sys_ftime(void)
 {
 	return -ENOSYS;
 }
 
-extern "C" int sys_break(void)
+asmlinkage int sys_break(void)
 {
 	return -ENOSYS;
 }
 
-extern "C" int sys_stty(void)
+asmlinkage int sys_stty(void)
 {
 	return -ENOSYS;
 }
 
-extern "C" int sys_gtty(void)
+asmlinkage int sys_gtty(void)
 {
 	return -ENOSYS;
 }
 
-extern "C" int sys_prof(void)
+asmlinkage int sys_prof(void)
 {
 	return -ENOSYS;
 }
 
-extern "C" unsigned long save_v86_state(struct vm86_regs * regs)
+asmlinkage unsigned long save_v86_state(struct vm86_regs * regs)
 {
 	unsigned long stack;
 
@@ -169,7 +169,7 @@
 	}
 }
 
-extern "C" int sys_vm86(struct vm86_struct * v86)
+asmlinkage int sys_vm86(struct vm86_struct * v86)
 {
 	struct vm86_struct info;
 	struct pt_regs * pt_regs = (struct pt_regs *) &v86;
@@ -216,7 +216,7 @@
  *
  * reboot doesn't sync: do that yourself before calling this.
  */
-extern "C" int sys_reboot(int magic, int magic_too, int flag)
+asmlinkage int sys_reboot(int magic, int magic_too, int flag)
 {
 	if (!suser())
 		return -EPERM;
@@ -258,7 +258,7 @@
  * 100% compatible with BSD.  A program which uses just setgid() will be
  * 100% compatible with POSIX w/ Saved ID's. 
  */
-extern "C" int sys_setregid(gid_t rgid, gid_t egid)
+asmlinkage int sys_setregid(gid_t rgid, gid_t egid)
 {
 	int old_rgid = current->gid;
 
@@ -287,7 +287,7 @@
 /*
  * setgid() is implemeneted like SysV w/ SAVED_IDS 
  */
-extern "C" int sys_setgid(gid_t gid)
+asmlinkage int sys_setgid(gid_t gid)
 {
 	if (suser())
 		current->gid = current->egid = current->sgid = gid;
@@ -298,37 +298,37 @@
 	return 0;
 }
 
-extern "C" int sys_acct(void)
+asmlinkage int sys_acct(void)
 {
 	return -ENOSYS;
 }
 
-extern "C" int sys_phys(void)
+asmlinkage int sys_phys(void)
 {
 	return -ENOSYS;
 }
 
-extern "C" int sys_lock(void)
+asmlinkage int sys_lock(void)
 {
 	return -ENOSYS;
 }
 
-extern "C" int sys_mpx(void)
+asmlinkage int sys_mpx(void)
 {
 	return -ENOSYS;
 }
 
-extern "C" int sys_ulimit(void)
+asmlinkage int sys_ulimit(void)
 {
 	return -ENOSYS;
 }
 
-extern "C" int sys_old_syscall(void)
+asmlinkage int sys_old_syscall(void)
 {
 	return -ENOSYS;
 }
 
-extern "C" int sys_time(long * tloc)
+asmlinkage int sys_time(long * tloc)
 {
 	int i, error;
 
@@ -355,7 +355,7 @@
  * 100% compatible with BSD.  A program which uses just setuid() will be
  * 100% compatible with POSIX w/ Saved ID's. 
  */
-extern "C" int sys_setreuid(uid_t ruid, uid_t euid)
+asmlinkage int sys_setreuid(uid_t ruid, uid_t euid)
 {
 	int old_ruid = current->uid;
 	
@@ -392,7 +392,7 @@
  * will allow a root program to temporarily drop privileges and be able to
  * regain them by swapping the real and effective uid.  
  */
-extern "C" int sys_setuid(uid_t uid)
+asmlinkage int sys_setuid(uid_t uid)
 {
 	if (suser())
 		current->uid = current->euid = current->suid = uid;
@@ -403,7 +403,7 @@
 	return(0);
 }
 
-extern "C" int sys_stime(long * tptr)
+asmlinkage int sys_stime(long * tptr)
 {
 	if (!suser())
 		return -EPERM;
@@ -412,7 +412,7 @@
 	return 0;
 }
 
-extern "C" int sys_times(struct tms * tbuf)
+asmlinkage int sys_times(struct tms * tbuf)
 {
 	if (tbuf) {
 		int error = verify_area(VERIFY_WRITE,tbuf,sizeof *tbuf);
@@ -426,7 +426,7 @@
 	return jiffies;
 }
 
-extern "C" int sys_brk(unsigned long brk)
+asmlinkage int sys_brk(unsigned long brk)
 {
 	int freepages;
 	unsigned long rlim;
@@ -487,7 +487,7 @@
  * only important on a multi-user system anyway, to make sure one user
  * can't send a signal to a process owned by another.  -TYT, 12/12/91
  */
-extern "C" int sys_setpgid(pid_t pid, pid_t pgid)
+asmlinkage int sys_setpgid(pid_t pid, pid_t pgid)
 {
 	int i; 
 
@@ -513,12 +513,12 @@
 	return -ESRCH;
 }
 
-extern "C" int sys_getpgrp(void)
+asmlinkage int sys_getpgrp(void)
 {
 	return current->pgrp;
 }
 
-extern "C" int sys_setsid(void)
+asmlinkage int sys_setsid(void)
 {
 	if (current->leader && !suser())
 		return -EPERM;
@@ -531,7 +531,7 @@
 /*
  * Supplementary group ID's
  */
-extern "C" int sys_getgroups(int gidsetsize, gid_t *grouplist)
+asmlinkage int sys_getgroups(int gidsetsize, gid_t *grouplist)
 {
 	int i;
 
@@ -551,7 +551,7 @@
 	return(i);
 }
 
-extern "C" int sys_setgroups(int gidsetsize, gid_t *grouplist)
+asmlinkage int sys_setgroups(int gidsetsize, gid_t *grouplist)
 {
 	int	i;
 
@@ -583,7 +583,7 @@
 	return 0;
 }
 
-extern "C" int sys_newuname(struct new_utsname * name)
+asmlinkage int sys_newuname(struct new_utsname * name)
 {
 	int error;
 
@@ -595,7 +595,7 @@
 	return error;
 }
 
-extern "C" int sys_uname(struct old_utsname * name)
+asmlinkage int sys_uname(struct old_utsname * name)
 {
 	int error;
 	if (!name)
@@ -616,7 +616,7 @@
 	return 0;
 }
 
-extern "C" int sys_olduname(struct oldold_utsname * name)
+asmlinkage int sys_olduname(struct oldold_utsname * name)
 {
 	int error;
 	if (!name)
@@ -640,7 +640,7 @@
 /*
  * Only sethostname; gethostname can be implemented by calling uname()
  */
-extern "C" int sys_sethostname(char *name, int len)
+asmlinkage int sys_sethostname(char *name, int len)
 {
 	int	i;
 	
@@ -660,7 +660,7 @@
  * Only setdomainname; getdomainname can be implemented by calling
  * uname()
  */
-extern "C" int sys_setdomainname(char *name, int len)
+asmlinkage int sys_setdomainname(char *name, int len)
 {
 	int	i;
 	
@@ -676,7 +676,7 @@
 	return 0;
 }
 
-extern "C" int sys_getrlimit(unsigned int resource, struct rlimit *rlim)
+asmlinkage int sys_getrlimit(unsigned int resource, struct rlimit *rlim)
 {
 	int error;
 
@@ -692,7 +692,7 @@
 	return 0;	
 }
 
-extern "C" int sys_setrlimit(unsigned int resource, struct rlimit *rlim)
+asmlinkage int sys_setrlimit(unsigned int resource, struct rlimit *rlim)
 {
 	struct rlimit new_rlim, *old_rlim;
 
@@ -761,7 +761,7 @@
 	return 0;
 }
 
-extern "C" int sys_getrusage(int who, struct rusage *ru)
+asmlinkage int sys_getrusage(int who, struct rusage *ru)
 {
 	if (who != RUSAGE_SELF && who != RUSAGE_CHILDREN)
 		return -EINVAL;
@@ -808,7 +808,7 @@
 #endif /* not __i386__ */
 }
 
-extern "C" int sys_gettimeofday(struct timeval *tv, struct timezone *tz)
+asmlinkage int sys_gettimeofday(struct timeval *tv, struct timezone *tz)
 {
 	int error;
 
@@ -840,7 +840,7 @@
  * soon as possible, so that the clock can be set right.  Otherwise,
  * various programs will get confused when the clock gets warped.
  */
-extern "C" int sys_settimeofday(struct timeval *tv, struct timezone *tz)
+asmlinkage int sys_settimeofday(struct timeval *tv, struct timezone *tz)
 {
 	static int	firsttime = 1;
 
@@ -888,11 +888,10 @@
 	startup_time += sys_tz.tz_minuteswest*60;
 }
 
-extern "C" int sys_umask(int mask)
+asmlinkage int sys_umask(int mask)
 {
 	int old = current->umask;
 
 	current->umask = mask & S_IRWXUGO;
 	return (old);
 }
-
diff --git a/kernel/traps.c b/kernel/traps.c
index 0621668..e276cd4 100644
--- a/kernel/traps.c
+++ b/kernel/traps.c
@@ -41,33 +41,34 @@
 
 void page_exception(void);
 
-extern "C" void divide_error(void);
-extern "C" void debug(void);
-extern "C" void nmi(void);
-extern "C" void int3(void);
-extern "C" void overflow(void);
-extern "C" void bounds(void);
-extern "C" void invalid_op(void);
-extern "C" void device_not_available(void);
-extern "C" void double_fault(void);
-extern "C" void coprocessor_segment_overrun(void);
-extern "C" void invalid_TSS(void);
-extern "C" void segment_not_present(void);
-extern "C" void stack_segment(void);
-extern "C" void general_protection(void);
-extern "C" void page_fault(void);
-extern "C" void coprocessor_error(void);
-extern "C" void reserved(void);
-extern "C" void alignment_check(void);
+asmlinkage void divide_error(void);
+asmlinkage void debug(void);
+asmlinkage void nmi(void);
+asmlinkage void int3(void);
+asmlinkage void overflow(void);
+asmlinkage void bounds(void);
+asmlinkage void invalid_op(void);
+asmlinkage void device_not_available(void);
+asmlinkage void double_fault(void);
+asmlinkage void coprocessor_segment_overrun(void);
+asmlinkage void invalid_TSS(void);
+asmlinkage void segment_not_present(void);
+asmlinkage void stack_segment(void);
+asmlinkage void general_protection(void);
+asmlinkage void page_fault(void);
+asmlinkage void coprocessor_error(void);
+asmlinkage void reserved(void);
+asmlinkage void alignment_check(void);
 
 /*static*/ void die_if_kernel(char * str, struct pt_regs * regs, long err)
 {
 	int i;
 
-	if ((regs->eflags & VM_MASK) || ((0xffff & regs->cs) == USER_CS))
+	if ((regs->eflags & VM_MASK) || (3 & regs->cs) == 3)
 		return;
+
 	printk("%s: %04x\n", str, err & 0xffff);
-	printk("EIP:    %04x:%p\nEFLAGS: %p\n", 0xffff & regs->cs,regs->eip,regs->eflags);
+	printk("EIP:    %04x:%08x\nEFLAGS: %08x\n", 0xffff & regs->cs,regs->eip,regs->eflags);
 	printk("eax: %08x   ebx: %08x   ecx: %08x   edx: %08x\n",
 		regs->eax, regs->ebx, regs->ecx, regs->edx);
 	printk("esi: %08x   edi: %08x   ebp: %08x\n",
@@ -82,31 +83,31 @@
 	do_exit(SIGSEGV);
 }
 
-extern "C" void do_double_fault(struct pt_regs * regs, long error_code)
+asmlinkage void do_double_fault(struct pt_regs * regs, long error_code)
 {
 	send_sig(SIGSEGV, current, 1);
 	die_if_kernel("double fault",regs,error_code);
 }
 
-extern "C" void do_general_protection(struct pt_regs * regs, long error_code)
+asmlinkage void do_general_protection(struct pt_regs * regs, long error_code)
 {
 	send_sig(SIGSEGV, current, 1);
 	die_if_kernel("general protection",regs,error_code);
 }
 
-extern "C" void do_alignment_check(struct pt_regs * regs, long error_code)
+asmlinkage void do_alignment_check(struct pt_regs * regs, long error_code)
 {
 	send_sig(SIGSEGV, current, 1);
 	die_if_kernel("alignment check",regs,error_code);
 }
 
-extern "C" void do_divide_error(struct pt_regs * regs, long error_code)
+asmlinkage void do_divide_error(struct pt_regs * regs, long error_code)
 {
 	send_sig(SIGFPE, current, 1);
 	die_if_kernel("divide error",regs,error_code);
 }
 
-extern "C" void do_int3(struct pt_regs * regs, long error_code)
+asmlinkage void do_int3(struct pt_regs * regs, long error_code)
 {
 	if (current->flags & PF_PTRACED)
 		current->blocked &= ~(1 << (SIGTRAP-1));
@@ -114,12 +115,12 @@
 	die_if_kernel("int3",regs,error_code);
 }
 
-extern "C" void do_nmi(struct pt_regs * regs, long error_code)
+asmlinkage void do_nmi(struct pt_regs * regs, long error_code)
 {
 	printk("Uhhuh. NMI received. Dazed and confused, but trying to continue\n");
 }
 
-extern "C" void do_debug(struct pt_regs * regs, long error_code)
+asmlinkage void do_debug(struct pt_regs * regs, long error_code)
 {
 	if (current->flags & PF_PTRACED)
 		current->blocked &= ~(1 << (SIGTRAP-1));
@@ -127,49 +128,49 @@
 	die_if_kernel("debug",regs,error_code);
 }
 
-extern "C" void do_overflow(struct pt_regs * regs, long error_code)
+asmlinkage void do_overflow(struct pt_regs * regs, long error_code)
 {
 	send_sig(SIGSEGV, current, 1);
 	die_if_kernel("overflow",regs,error_code);
 }
 
-extern "C" void do_bounds(struct pt_regs * regs, long error_code)
+asmlinkage void do_bounds(struct pt_regs * regs, long error_code)
 {
 	send_sig(SIGSEGV, current, 1);
 	die_if_kernel("bounds",regs,error_code);
 }
 
-extern "C" void do_invalid_op(struct pt_regs * regs, long error_code)
+asmlinkage void do_invalid_op(struct pt_regs * regs, long error_code)
 {
 	send_sig(SIGILL, current, 1);
 	die_if_kernel("invalid operand",regs,error_code);
 }
 
-extern "C" void do_device_not_available(struct pt_regs * regs, long error_code)
+asmlinkage void do_device_not_available(struct pt_regs * regs, long error_code)
 {
 	send_sig(SIGSEGV, current, 1);
 	die_if_kernel("device not available",regs,error_code);
 }
 
-extern "C" void do_coprocessor_segment_overrun(struct pt_regs * regs, long error_code)
+asmlinkage void do_coprocessor_segment_overrun(struct pt_regs * regs, long error_code)
 {
 	send_sig(SIGFPE, last_task_used_math, 1);
 	die_if_kernel("coprocessor segment overrun",regs,error_code);
 }
 
-extern "C" void do_invalid_TSS(struct pt_regs * regs,long error_code)
+asmlinkage void do_invalid_TSS(struct pt_regs * regs,long error_code)
 {
 	send_sig(SIGSEGV, current, 1);
 	die_if_kernel("invalid TSS",regs,error_code);
 }
 
-extern "C" void do_segment_not_present(struct pt_regs * regs,long error_code)
+asmlinkage void do_segment_not_present(struct pt_regs * regs,long error_code)
 {
 	send_sig(SIGSEGV, current, 1);
 	die_if_kernel("segment not present",regs,error_code);
 }
 
-extern "C" void do_stack_segment(struct pt_regs * regs,long error_code)
+asmlinkage void do_stack_segment(struct pt_regs * regs,long error_code)
 {
 	send_sig(SIGSEGV, current, 1);
 	die_if_kernel("stack segment",regs,error_code);
@@ -210,13 +211,13 @@
 	env->twd = 0xffffffff;
 }
 
-extern "C" void do_coprocessor_error(struct pt_regs * regs, long error_code)
+asmlinkage void do_coprocessor_error(struct pt_regs * regs, long error_code)
 {
 	ignore_irq13 = 1;
 	math_error();
 }
 
-extern "C" void do_reserved(struct pt_regs * regs, long error_code)
+asmlinkage void do_reserved(struct pt_regs * regs, long error_code)
 {
 	send_sig(SIGSEGV, current, 1);
 	die_if_kernel("reserved (15,17-47) error",regs,error_code);
diff --git a/lib/malloc.c b/lib/malloc.c
index 789e5d3..4d14749 100644
--- a/lib/malloc.c
+++ b/lib/malloc.c
@@ -442,7 +442,7 @@
 	}
 
 	restore_flags(flags);
-	printk("Bad address passed to kernel kfree_s(%X, %d)\n",obj, size);
+	printk("Bad address passed to kernel kfree_s(%p, %d)\n",obj, size);
 #ifdef CONFIG_DEBUG_MALLOC
 	printk("Offending code: %s:%d\n",deb_file,deb_line);
 #else
diff --git a/mm/memory.c b/mm/memory.c
index 33ae7c1..5fe17a4 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -86,7 +86,7 @@
 		return;
 	*page_dir = 0;
 	if (pg_table >= high_memory || !(pg_table & PAGE_PRESENT)) {
-		printk("Bad page table: [%08x]=%08x\n",page_dir,pg_table);
+		printk("Bad page table: [%p]=%08x\n",page_dir,pg_table);
 		return;
 	}
 	if (mem_map[MAP_NR(pg_table)] & MAP_PAGE_RESERVED)
@@ -278,7 +278,7 @@
 	}
 	size = (size + ~PAGE_MASK) >> PAGE_SHIFT;
 	dir = PAGE_DIR_OFFSET(current->tss.cr3,from);
-	poff = (from >> PAGE_SHIFT) & PTRS_PER_PAGE-1;
+	poff = (from >> PAGE_SHIFT) & (PTRS_PER_PAGE-1);
 	if ((pcnt = PTRS_PER_PAGE - poff) > size)
 		pcnt = size;
 
@@ -337,7 +337,7 @@
 	}
 	dir = PAGE_DIR_OFFSET(current->tss.cr3,from);
 	size = (size + ~PAGE_MASK) >> PAGE_SHIFT;
-	poff = (from >> PAGE_SHIFT) & PTRS_PER_PAGE-1;
+	poff = (from >> PAGE_SHIFT) & (PTRS_PER_PAGE-1);
 	if ((pcnt = PTRS_PER_PAGE - poff) > size)
 		pcnt = size;
 
@@ -399,7 +399,7 @@
 	}
 	dir = PAGE_DIR_OFFSET(current->tss.cr3,from);
 	size = (size + ~PAGE_MASK) >> PAGE_SHIFT;
-	poff = (from >> PAGE_SHIFT) & PTRS_PER_PAGE-1;
+	poff = (from >> PAGE_SHIFT) & (PTRS_PER_PAGE-1);
 	if ((pcnt = PTRS_PER_PAGE - poff) > size)
 		pcnt = size;
 
@@ -472,7 +472,7 @@
 	if ((prot & (PAGE_MASK|PAGE_PRESENT)) != PAGE_PRESENT)
 		printk("put_page: prot = %08x\n",prot);
 	if (page >= high_memory) {
-		printk("put_page: trying to put page %p at %p\n",page,address);
+		printk("put_page: trying to put page %08x at %08x\n",page,address);
 		return 0;
 	}
 	page_table = PAGE_DIR_OFFSET(tsk->tss.cr3,address);
@@ -484,7 +484,7 @@
 		*page_table = BAD_PAGETABLE | PAGE_TABLE;
 		return 0;
 	}
-	page_table += (address >> PAGE_SHIFT) & PTRS_PER_PAGE-1;
+	page_table += (address >> PAGE_SHIFT) & (PTRS_PER_PAGE-1);
 	if (*page_table) {
 		printk("put_page: page already exists\n");
 		*page_table = 0;
@@ -506,9 +506,9 @@
 	unsigned long tmp, *page_table;
 
 	if (page >= high_memory)
-		printk("put_dirty_page: trying to put page %p at %p\n",page,address);
+		printk("put_dirty_page: trying to put page %08x at %08x\n",page,address);
 	if (mem_map[MAP_NR(page)] != 1)
-		printk("mem_map disagrees with %p at %p\n",page,address);
+		printk("mem_map disagrees with %08x at %08x\n",page,address);
 	page_table = PAGE_DIR_OFFSET(tsk->tss.cr3,address);
 	if (PAGE_PRESENT & *page_table)
 		page_table = (unsigned long *) (PAGE_MASK & *page_table);
@@ -523,7 +523,7 @@
 			page_table = (unsigned long *) tmp;
 		}
 	}
-	page_table += (address >> PAGE_SHIFT) & PTRS_PER_PAGE-1;
+	page_table += (address >> PAGE_SHIFT) & (PTRS_PER_PAGE-1);
 	if (*page_table) {
 		printk("put_dirty_page: page already exists\n");
 		*page_table = 0;
@@ -760,7 +760,7 @@
 {
 	struct task_struct ** p;
 
-	if (!inode || inode->i_count < 2)
+	if (!inode || inode->i_count < 2 || !area->vm_ops)
 		return 0;
 	for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) {
 		if (!*p)
@@ -773,8 +773,8 @@
 			   we can share pages with */
 			if(area){
 			  struct vm_area_struct * mpnt;
-			  for(mpnt = (*p)->mmap; mpnt; mpnt = mpnt->vm_next){
-			    if(mpnt->vm_ops && mpnt->vm_ops == area->vm_ops &&
+			  for (mpnt = (*p)->mmap; mpnt; mpnt = mpnt->vm_next) {
+			    if (mpnt->vm_ops == area->vm_ops &&
 			       mpnt->vm_inode->i_ino == area->vm_inode->i_ino&&
 			       mpnt->vm_inode->i_dev == area->vm_inode->i_dev){
 			      if (mpnt->vm_ops->share(mpnt, area, address))
@@ -851,6 +851,8 @@
 			continue;
 		if (address >= ((mpnt->vm_end + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)))
 			continue;
+		if (!mpnt->vm_ops || !mpnt->vm_ops->nopage)
+			break;
 		mpnt->vm_ops->nopage(error_code, mpnt, address);
 		return;
 	}
@@ -858,7 +860,7 @@
 	get_empty_page(tsk,address);
 	if (tsk != current)
 		return;
-	if (address < tsk->brk)
+	if (address >= tsk->end_data && address < tsk->brk)
 		return;
 	if (address+8192 >= (user_esp & 0xfffff000) && 
 	    address <= current->start_stack)
@@ -872,7 +874,7 @@
  * and the problem, and then passes it off to one of the appropriate
  * routines.
  */
-extern "C" void do_page_fault(struct pt_regs *regs, unsigned long error_code)
+asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code)
 {
 	unsigned long address;
 	unsigned long user_esp = 0;
@@ -966,9 +968,9 @@
 	int shared = 0;
 
 	printk("Mem-info:\n");
-	printk("Free pages:      %6dkB\n",nr_free_pages<<PAGE_SHIFT-10);
-	printk("Secondary pages: %6dkB\n",nr_secondary_pages<<PAGE_SHIFT-10);
-	printk("Free swap:       %6dkB\n",nr_swap_pages<<PAGE_SHIFT-10);
+	printk("Free pages:      %6dkB\n",nr_free_pages<<(PAGE_SHIFT-10));
+	printk("Secondary pages: %6dkB\n",nr_secondary_pages<<(PAGE_SHIFT-10));
+	printk("Free swap:       %6dkB\n",nr_swap_pages<<(PAGE_SHIFT-10));
 	printk("Buffer memory:   %6dkB\n",buffermem>>10);
 	printk("Buffer heads:    %6d\n",nr_buffer_heads);
 	printk("Buffer blocks:   %6d\n",nr_buffers);
@@ -1085,9 +1087,9 @@
 	printk("Memory: %dk/%dk available (%dk kernel code, %dk reserved, %dk data)\n",
 		tmp >> 10,
 		end_mem >> 10,
-		codepages << PAGE_SHIFT-10,
-		reservedpages << PAGE_SHIFT-10,
-		datapages << PAGE_SHIFT-10);
+		codepages << (PAGE_SHIFT-10),
+		reservedpages << (PAGE_SHIFT-10),
+		datapages << (PAGE_SHIFT-10));
 	return;
 }
 
diff --git a/mm/mmap.c b/mm/mmap.c
index cec3eb2..e84fe47 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -52,11 +52,11 @@
 	switch (flags & MAP_TYPE) {
 	case MAP_SHARED:
 		if ((prot & PROT_WRITE) && !(file->f_mode & 2))
-			return -EINVAL;
+			return -EACCES;
 		/* fall through */
 	case MAP_PRIVATE:
 		if (!(file->f_mode & 1))
-			return -EINVAL;
+			return -EACCES;
 		break;
 
 	default:
@@ -121,7 +121,7 @@
 	return -1;
 }
 
-extern "C" int sys_mmap(unsigned long *buffer)
+asmlinkage int sys_mmap(unsigned long *buffer)
 {
 	unsigned long fd;
 	struct file * file;
@@ -133,7 +133,7 @@
 		get_fs_long(buffer+2), get_fs_long(buffer+3), get_fs_long(buffer+5));
 }
 
-extern "C" int sys_munmap(unsigned long addr, size_t len)
+asmlinkage int sys_munmap(unsigned long addr, size_t len)
 {
 	struct vm_area_struct *mpnt, **p, *free;
 
@@ -169,7 +169,7 @@
 	while (free) {
 		mpnt = free;
 		free = free->vm_next;
-		if (mpnt->vm_ops->close)
+		if (mpnt->vm_ops && mpnt->vm_ops->close)
 			mpnt->vm_ops->close(mpnt);
 		kfree(mpnt);
 	}
@@ -201,10 +201,6 @@
 		return -EINVAL;
 	if (off & (inode->i_sb->s_blocksize - 1))
 		return -EINVAL;
-	if (len > high_memory || off > high_memory - len) /* avoid overflow */
-		return -ENXIO;
-	if (get_limit(USER_DS)  != TASK_SIZE)
-		return -EINVAL;
 	if (!inode->i_sb || !S_ISREG(inode->i_mode))
 		return -EACCES;
 	if (!inode->i_op || !inode->i_op->bmap)
@@ -233,10 +229,6 @@
 	mpnt->vm_ops = &file_mmap;
 	mpnt->vm_next = current->mmap;
 	current->mmap = mpnt;
-#if 0
-	printk("VFS: Loaded mmap at %08x -  %08x\n",
-		mpnt->vm_start,	mpnt->vm_end);
-#endif
 	return 0;
 }
 
diff --git a/mm/swap.c b/mm/swap.c
index c5b4ea5..8869959 100644
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -265,7 +265,7 @@
  * swapping out or forgetting about. This speeds up the search when we
  * actually have to swap.
  */
-extern "C" int sys_idle(void)
+asmlinkage int sys_idle(void)
 {
 	need_resched = 1;
 	return 0;
@@ -661,7 +661,7 @@
 	return 0;
 }
 
-extern "C" int sys_swapoff(const char * specialfile)
+asmlinkage int sys_swapoff(const char * specialfile)
 {
 	struct swap_info_struct * p;
 	struct inode * inode;
@@ -713,7 +713,7 @@
  *
  * The swapon system call
  */
-extern "C" int sys_swapon(const char * specialfile)
+asmlinkage int sys_swapon(const char * specialfile)
 {
 	struct swap_info_struct * p;
 	struct inode * swap_inode;
diff --git a/net/inet/3c509.c b/net/inet/3c509.c
index fd5fccb..172921f 100644
--- a/net/inet/3c509.c
+++ b/net/inet/3c509.c
@@ -1,4 +1,4 @@
-/* el3.c: An 3c509 EtherLink3 ethernet driver for linux. */
+/* 3c509.c: A 3c509 EtherLink3 ethernet driver for linux. */
 /*
     Written 1993 by Donald Becker.
 
@@ -7,13 +7,13 @@
     distributed according to the terms of the GNU Public License,
     incorporated herein by reference.
     
-    This driver should work with the 3Com EtherLinkIII series.
+    This driver is for the 3Com EtherLinkIII series.
 
     The author may be reached as becker@super.org or
     C/O Supercomputing Research Ctr., 17100 Science Dr., Bowie MD 20715
 */
 
-static char *version = "el3.c: v0.02 8/13/93 becker@super.org\n";
+static char *version = "3c509.c: v0.06 9/3/93 becker@super.org\n";
 
 #include <linux/config.h>
 #include <linux/kernel.h>
@@ -23,6 +23,14 @@
 #include <linux/ptrace.h>
 #include <linux/errno.h>
 #include <linux/in.h>
+
+#ifndef PRE_PL13
+#include <linux/ioport.h>
+#else
+#define snarf_region(base,extent) do {;}while(0)
+#define check_region(base,extent) (0)
+#endif
+
 /*#include <asm/system.h>*/
 #include <asm/io.h>
 #ifndef port_read
@@ -34,10 +42,12 @@
 #include "skbuff.h"
 #include "arp.h"
 
+#ifndef HAVE_AUTOIRQ
 /* From auto_irq.c, should be in a *.h file. */
 extern void autoirq_setup(int waittime);
 extern int autoirq_report(int waittime);
 extern struct device *irq2dev_map[16];
+#endif
 
 /* These should be in <asm/io.h>. */
 #define port_read_l(port,buf,nr) \
@@ -49,9 +59,12 @@
 #ifdef EL3_DEBUG
 int el3_debug = EL3_DEBUG;
 #else
-int el3_debug = 1;
+int el3_debug = 2;
 #endif
 
+/* To minimize the size of the driver source I only define operating
+   constants if they are used several times.  You'll need the manual
+   if you want to understand driver details. */
 /* Offsets from base I/O address. */
 #define EL3_DATA 0x00
 #define EL3_CMD 0x0e
@@ -59,6 +72,9 @@
 #define ID_PORT 0x100
 #define  EEPROM_READ 0x80
 
+#define EL3WINDOW(win_num) outw(0x0800+(win_num), ioaddr + EL3_CMD)
+
+
 /* Register window 1 offsets, used in normal operation. */
 #define TX_FREE 0x0C
 #define TX_STATUS 0x0B
@@ -66,11 +82,12 @@
 #define RX_STATUS 0x08
 #define RX_FIFO 0x00
 
+#define WN4_MEDIA	0x0A
+
 struct el3_private {
     struct enet_statistics stats;
 };
 
-static int el3_init(struct device *dev);
 static int read_eeprom(int index);
 static int el3_open(struct device *dev);
 static int el3_start_xmit(struct sk_buff *skb, struct device *dev);
@@ -85,7 +102,9 @@
 int el3_probe(struct device *dev)
 {
     short lrs_state = 0xff, i;
-    unsigned short iobase = 0;
+    short ioaddr, irq;
+    short *phys_addr = (short *)dev->dev_addr;
+    static int current_tag = 0;
 
     /* Send the ID sequence to the ID_PORT. */
     outb(0x00, ID_PORT);
@@ -96,75 +115,57 @@
 	lrs_state = lrs_state & 0x100 ? lrs_state ^ 0xcf : lrs_state;
     }
 
-    /* The current Space.c initialization makes it difficult to have more
-       than one adaptor initialized.  Send me email if you have a need for
-       multiple adaptors. */
+    /* For the first probe, clear all board's tag registers. */
+    if (current_tag == 0)
+	outb(0xd0, ID_PORT);
+    else		/* Otherwise kill off already-found boards. */
+	outb(0xd8, ID_PORT);
 
-    /* Read in EEPROM data.
-       Only the highest address board will stay on-line. */
+    if (read_eeprom(7) != 0x6d50) {
+	return -ENODEV;
+    }
+
+    /* Read in EEPROM data, which does contention-select.
+       Only the lowest address board will stay "on-line".
+       3Com got the byte order backwards. */
+    for (i = 0; i < 3; i++) {
+	phys_addr[i] = htons(read_eeprom(i));
+    }
 
     {
-	short *phys_addr = (short *)dev->dev_addr;
-	phys_addr[0] = htons(read_eeprom(0));
-	if (phys_addr[0] != 0x6000)
-	    return 1;
-	phys_addr[1] = htons(read_eeprom(1));
-	phys_addr[2] = htons(read_eeprom(2));
+	unsigned short iobase = read_eeprom(8);
+	dev->if_port = iobase >> 14;
+	ioaddr = 0x200 + ((iobase & 0x1f) << 4);
     }
+    irq = read_eeprom(9) >> 12;
 
-    iobase = read_eeprom(8);
-    dev->irq = read_eeprom(9) >> 12;
-
-    /* Activate the adaptor at the EEPROM location (if set), else 0x320. */
-
-    if (iobase == 0x0000) {
-	dev->base_addr = 0x320;
-	outb(0xf2, ID_PORT);
-    } else {
-	dev->base_addr = 0x200 + ((iobase & 0x1f) << 4);
-	outb(0xff, ID_PORT);
-    }
-
-    outw(0x0800, dev->base_addr + EL3_CMD);	 /* Window 0. */
-    printk("%s: 3c509 at %#3.3x  key %4.4x iobase %4.4x.\n",
-	   dev->name, dev->base_addr, inw(dev->base_addr), iobase);
-
-    if (inw(dev->base_addr) == 0x6d50) {
-	el3_init(dev);
-	return 0;
-    } else
+    /* The current Space.c structure makes it difficult to have more
+       than one adaptor initialized.  Send me email if you have a need for
+       multiple adaptors, and we'll work out something.  -becker@super.org */
+    if (dev->base_addr != 0
+	&&  dev->base_addr != (unsigned short)ioaddr) {
 	return -ENODEV;
-}
+    }
 
-static int
-read_eeprom(int index)
-{
-    int timer, bit, word = 0;
-    
-    /* Issue read command, and pause for at least 162 us. for it to complete.
-       Assume extra-fast 16Mhz bus. */
-    outb(EEPROM_READ + index, ID_PORT);
+    /* Set the adaptor tag so that the next card can be found. */
+    outb(0xd0 + ++current_tag, ID_PORT);
 
-    for (timer = 0; timer < 162*4 + 400; timer++)
-	SLOW_DOWN_IO;
+    /* Activate the adaptor at the EEPROM location. */
+    outb(0xff, ID_PORT);
 
-    for (bit = 15; bit >= 0; bit--)
-	word = (word << 1) + (inb(ID_PORT) & 0x01);
-	
-    if (el3_debug > 3)
-	printk("  3c509 EEPROM word %d %#4.4x.\n", index, word);
+    EL3WINDOW(0);
+    if (inw(ioaddr) != 0x6d50)
+	return -ENODEV;
 
-    return word;
-}
+    dev->base_addr = ioaddr;
+    dev->irq = irq;
+    snarf_region(dev->base_addr, 16);
 
-static int
-el3_init(struct device *dev)
-{
-    struct el3_private *lp;
-    int ioaddr = dev->base_addr;
-    int i;
-
-    printk("%s: EL3 at %#3x, address", dev->name, ioaddr);
+    {
+	char *if_names[] = {"10baseT", "AUI", "undefined", "BNC"};
+	printk("%s: 3c509 at %#3.3x  tag %d, %s port, address ",
+	       dev->name, dev->base_addr, current_tag, if_names[dev->if_port]);
+    }
 
     /* Read in the station address. */
     for (i = 0; i < 6; i++)
@@ -174,9 +175,8 @@
     /* Make up a EL3-specific-data structure. */
     dev->priv = kmalloc(sizeof(struct el3_private), GFP_KERNEL);
     memset(dev->priv, 0, sizeof(struct el3_private));
-    lp = (struct el3_private *)dev->priv;
 
-    if (el3_debug > 1)
+    if (el3_debug > 0)
 	printk(version);
 
     /* The EL3-specific entries in the device structure. */
@@ -199,7 +199,7 @@
     dev->hard_header_len = ETH_HLEN;
     dev->mtu		= 1500; /* eth_mtu */
     dev->addr_len	= ETH_ALEN;
-    for (i = 0; i < dev->addr_len; i++) {
+    for (i = 0; i < ETH_ALEN; i++) {
 	dev->broadcast[i]=0xff;
     }
 
@@ -214,6 +214,30 @@
     return 0;
 }
 
+
+static int
+read_eeprom(int index)
+{
+    int timer, bit, word = 0;
+    
+    /* Issue read command, and pause for at least 162 us. for it to complete.
+       Assume extra-fast 16Mhz bus. */
+    outb(EEPROM_READ + index, ID_PORT);
+
+    /* This should really be done by looking at one of the timer channels. */
+    for (timer = 0; timer < 162*4 + 400; timer++)
+	SLOW_DOWN_IO;
+
+    for (bit = 15; bit >= 0; bit--)
+	word = (word << 1) + (inb(ID_PORT) & 0x01);
+	
+    if (el3_debug > 3)
+	printk("  3c509 EEPROM word %d %#4.4x.\n", index, word);
+
+    return word;
+}
+
+
 
 static int
 el3_open(struct device *dev)
@@ -225,45 +249,51 @@
 	return -EAGAIN;
     }
 
+    EL3WINDOW(0);
     if (el3_debug > 3)
-	printk("%s: Opening, IRQ %d  status@%x %4.4x reg4 %4.4x.\n",
-	       dev->name, dev->irq, ioaddr + EL3_STATUS,
-	       inw(ioaddr + EL3_STATUS), inw(ioaddr + 4));
-    outw(0x0800, ioaddr + EL3_CMD); /* Make certain we are in window 0. */
+	printk("%s: Opening, IRQ %d  status@%x %4.4x.\n", dev->name,
+	       dev->irq, ioaddr + EL3_STATUS, inw(ioaddr + EL3_STATUS));
 
-    /* This is probably unnecessary. */
+    /* Activate board: this is probably unnecessary. */
     outw(0x0001, ioaddr + 4);
 
-    outw((dev->irq << 12) | 0x0f00, ioaddr + 8);
-
     irq2dev_map[dev->irq] = dev;
 
+    /* Set the IRQ line. */
+    outw((dev->irq << 12) | 0x0f00, ioaddr + 8);
+
     /* Set the station address in window 2 each time opened. */
-    outw(0x0802, ioaddr + EL3_CMD);
+    EL3WINDOW(2);
 
     for (i = 0; i < 6; i++)
 	outb(dev->dev_addr[i], ioaddr + i);
 
-    outw(0x1000, ioaddr + EL3_CMD); /* Start the thinnet transceiver. */
+    if (dev->if_port == 3)
+	/* Start the thinnet transceiver. We should really wait 50ms...*/
+	outw(0x1000, ioaddr + EL3_CMD);
+    else if (dev->if_port == 0) {
+	/* 10baseT interface, enabled link beat and jabber check. */
+	EL3WINDOW(4);
+	outw(inw(ioaddr + WN4_MEDIA) | 0x00C0, ioaddr + WN4_MEDIA);
+    }
+
+    /* Switch to register set 1 for normal use. */
+    EL3WINDOW(1);
 
     outw(0x8005, ioaddr + EL3_CMD); /* Accept b-case and phys addr only. */
     outw(0xA800, ioaddr + EL3_CMD); /* Turn on statistics. */
     outw(0x2000, ioaddr + EL3_CMD); /* Enable the receiver. */
     outw(0x4800, ioaddr + EL3_CMD); /* Enable transmitter. */
     outw(0x78ff, ioaddr + EL3_CMD); /* Allow all status bits to be seen. */
+    dev->interrupt = 0;
+    dev->tbusy = 0;
+    dev->start = 1;
     outw(0x7098, ioaddr + EL3_CMD); /* Set interrupt mask. */
 
-    /* Switch to register set 1 for normal use. */
-    outw(0x0801, ioaddr + EL3_CMD);
-
     if (el3_debug > 3)
 	printk("%s: Opened 3c509  IRQ %d  status %4.4x.\n",
 	       dev->name, dev->irq, inw(ioaddr + EL3_STATUS));
 
-    dev->tbusy = 0;
-    dev->interrupt = 0;
-    dev->start = 1;
-
     return 0;			/* Always succeed */
 }
 
@@ -278,7 +308,7 @@
 	int tickssofar = jiffies - dev->trans_start;
 	if (tickssofar < 10)
 	    return 1;
-	printk("%s: transmit timed out, tx_status %4.4x status %4.4x.\n",
+	printk("%s: transmit timed out, tx_status %2.2x status %4.4x.\n",
 	       dev->name, inb(ioaddr + TX_STATUS), inw(ioaddr + EL3_STATUS));
 	dev->trans_start = jiffies;
 	/* Issue TX_RESET and TX_START commands. */
@@ -308,8 +338,9 @@
     }
 
     if (inw(ioaddr + EL3_STATUS) & 0x0001) { /* IRQ line active, missed one. */
-      printk("%s: Missed interrupt, status %4.4x.\n", dev->name,
-	     inw(ioaddr + EL3_STATUS));
+      printk("%s: Missed interrupt, status %4.4x  Tx %2.2x Rx %4.4x.\n",
+	     dev->name, inw(ioaddr + EL3_STATUS), inb(ioaddr + TX_STATUS),
+	     inw(ioaddr + RX_STATUS));
       outw(0x7800, ioaddr + EL3_CMD); /* Fake interrupt trigger. */
       outw(0x6899, ioaddr + EL3_CMD); /* Ack IRQ */
       outw(0x78ff, ioaddr + EL3_CMD); /* Allow all status bits to be seen. */
@@ -322,8 +353,7 @@
     outw(skb->len, ioaddr + TX_FIFO);
     outw(0x00, ioaddr + TX_FIFO);
     /* ... and the packet rounded to a doubleword. */
-    port_write(ioaddr + TX_FIFO, (void *)(skb+1),
-	       ((skb->len + 3) >> 1) & ~0x1);
+    port_write_l(ioaddr + TX_FIFO, (void *)(skb+1), (skb->len + 3) >> 2);
     
     dev->trans_start = jiffies;
     if (skb->free)
@@ -360,8 +390,9 @@
 el3_interrupt(int reg_ptr)
 {
     int irq = -(((struct pt_regs *)reg_ptr)->orig_eax+2);
-    struct device *dev = irq2dev_map[irq];
+    struct device *dev = (struct device *)(irq2dev_map[irq]);
     int ioaddr, status;
+    int i = 0;
 
     if (dev == NULL) {
 	printk ("el3_interrupt(): irq %d for unknown device.\n", irq);
@@ -380,6 +411,9 @@
     
     while ((status = inw(ioaddr + EL3_STATUS)) & 0x01) {
 
+	if (status & 0x10)
+	    el3_rx(dev);
+
 	if (status & 0x08) {
 	    if (el3_debug > 5)
 		printk("    TX room bit was handled.\n");
@@ -391,10 +425,12 @@
 	if (status & 0x80)		/* Statistics full. */
 	    update_stats(ioaddr, dev);
 	
-	if (status & 0x10)
-	    el3_rx(dev);
-
-	/* Clear the interrupts we've handled. */
+	if (++i > 10) {
+	    printk("%s: Infinite loop in interrupt, status %4.4x.\n",
+		   dev->name, status);
+	    break;
+	}
+	/* Clear the other interrupts we have handled. */
 	outw(0x6899, ioaddr + EL3_CMD); /* Ack IRQ */
     }
 
@@ -403,16 +439,6 @@
 	       inw(ioaddr + EL3_STATUS));
     }
     
-    if (inw(ioaddr + EL3_STATUS) & 0x01) {
-	int i = 100000;
-	printk("%s: exiting interrupt with status %4.4x.\n", dev->name,
-	       inw(ioaddr + EL3_STATUS));
-	while (i--)		/* Delay loop to see the message. */
-	    inw(ioaddr + EL3_STATUS);
-	while ((inw(ioaddr + EL3_STATUS) & 0x0010)  && i++ < 20)
-	    outw(0x00, ioaddr + RX_STATUS);
-    }
-
     dev->interrupt = 0;
     return;
 }
@@ -430,7 +456,9 @@
 }
 
 /* Update statistics.  We change to register window 6, so this
-   must be run single-threaded. */
+   should be run single-threaded if the device is active. This
+   is expected to be a rare operation, and not worth a special
+   window-state variable. */
 static void update_stats(int ioaddr, struct device *dev)
 {
     struct el3_private *lp = (struct el3_private *)dev->priv;
@@ -440,7 +468,7 @@
     /* Turn off statistics updates while reading. */
     outw(0xB000, ioaddr + EL3_CMD);
     /* Switch to the stats window, and read everything. */
-    outw(0x0806, ioaddr + EL3_CMD);
+    EL3WINDOW(6);
     lp->stats.tx_carrier_errors	+= inb(ioaddr + 0);
     lp->stats.tx_heartbeat_errors	+= inb(ioaddr + 1);
     /* Multiple collisions. */	   inb(ioaddr + 2);
@@ -454,25 +482,11 @@
     inw(ioaddr + 12);
 
     /* Back to window 1, and turn statistics back on. */
-    outw(0x0801, ioaddr + EL3_CMD);
+    EL3WINDOW(1);
     outw(0xA800, ioaddr + EL3_CMD);
     return;
 }
 
-/* Print statistics on the kernel error output. */
-void printk_stats(struct enet_statistics *stats)
-{
-
-    printk("  Ethernet statistics:  Rx packets %6d  Tx packets %6d.\n",
-	   stats->rx_packets, stats->tx_packets);
-    printk("   Carrier errors:   %6d.\n", stats->tx_carrier_errors);
-    printk("   Heartbeat errors: %6d.\n", stats->tx_heartbeat_errors);
-    printk("   Collisions:       %6d.\n", stats->collisions);
-    printk("   Rx FIFO problems: %6d.\n", stats->rx_fifo_errors);
-
-    return;
-}
-
 static int
 el3_rx(struct device *dev)
 {
@@ -498,21 +512,32 @@
 	}
 	if ( (! (rx_status & 0x4000))
 	    || ! (rx_status & 0x2000)) { /* Dribble bits are OK. */
-	    short length = rx_status & 0x3ff;
-	    int sksize = sizeof(struct sk_buff) + length + 3;
+	    short pkt_len = rx_status & 0x7ff;
+	    int sksize = sizeof(struct sk_buff) + pkt_len + 3;
 	    struct sk_buff *skb;
 	    skb = (struct sk_buff *) kmalloc(sksize, GFP_ATOMIC);
 
 	    if (el3_debug > 4)
 		printk("       Receiving packet size %d status %4.4x.\n",
-		       length, rx_status);
+		       pkt_len, rx_status);
 	    if (skb != NULL) {
-		skb->lock = 0;
 		skb->mem_len = sksize;
 		skb->mem_addr = skb;
+		skb->len = pkt_len;
+		skb->dev = dev;
+
 		/* 'skb+1' points to the start of sk_buff data area. */
-		port_read(ioaddr+RX_FIFO, (void *)(skb+1), ((length + 3) >> 2) << 1);
-		if (dev_rint((unsigned char *)skb, length, IN_SKBUFF,dev)== 0){
+		port_read_l(ioaddr+RX_FIFO, (void *)(skb+1),
+			    (pkt_len + 3) >> 2);
+
+#ifdef HAVE_NETIF_RX
+		netif_rx(skb);
+		outw(0x4000, ioaddr + EL3_CMD); /* Rx discard */
+		continue;
+#else
+		skb->lock = 0;
+		if (dev_rint((unsigned char *)skb, pkt_len,
+			     IN_SKBUFF,dev)== 0){
 		    if (el3_debug > 6)
 			printk("     dev_rint() happy, status %4.4x.\n",
 			inb(ioaddr + EL3_STATUS));
@@ -527,7 +552,8 @@
 		} else {
 		    printk("%s: receive buffers full.\n", dev->name);
 		    kfree_s(skb, sksize);
-		}	    
+		}
+#endif
 	    } else if (el3_debug)
 		printk("%s: Couldn't allocate a sk_buff of size %d.\n",
 		       dev->name, sksize);
@@ -564,22 +590,21 @@
     outw(0x1800, ioaddr + EL3_CMD);
     outw(0x5000, ioaddr + EL3_CMD);
 
-    /* Turn off thinnet power. */
-    outw(0xb800, ioaddr + EL3_CMD);
-
-    if (el3_debug > 2) {
-	struct el3_private *lp = (struct el3_private *)dev->priv;
-	printk("%s: Status was %4.4x.\n", dev->name, inw(ioaddr + EL3_STATUS));
-	printk_stats(&lp->stats);
+    if (dev->if_port == 3)
+	/* Turn off thinnet power. */
+	outw(0xb800, ioaddr + EL3_CMD);
+    else if (dev->if_port == 0) {
+	/* Disable link beat and jabber, if_port may change ere next open(). */
+	EL3WINDOW(4);
+	outw(inw(ioaddr + WN4_MEDIA) & ~ 0x00C0, ioaddr + WN4_MEDIA);
     }
 
-    /* Free the interrupt line. */
     free_irq(dev->irq);
-    outw(0x1000, ioaddr + EL3_CMD);
+    /* Switching back to window 0 disables the IRQ. */
+    EL3WINDOW(0);
+    /* But we explicitly zero the IRQ line select anyway. */
     outw(0x0f00, ioaddr + 8);
 
-    /* Switch back to register window 0. */
-    outw(0x0800, ioaddr + EL3_CMD);
 
     irq2dev_map[dev->irq] = 0;
 
diff --git a/net/inet/8390.c b/net/inet/8390.c
index 15bb757..3c15fe9 100644
--- a/net/inet/8390.c
+++ b/net/inet/8390.c
@@ -14,15 +14,8 @@
 */
 
 static char *version =
-    "8390.c:v0.99-12 8/9/93 for 0.99.12+ Donald Becker (becker@super.org)\n";
+    "8390.c:v0.99-13 9/3/93 for 0.99.13 Donald Becker (becker@super.org)\n";
 #include <linux/config.h>
-#if !defined(EL2) && !defined(NE2000) && !defined(WD80x3) && !defined(HPLAN)
-/* They don't know what they want -- give it all to them! */
-#define EL2
-#define NE2000
-#define WD80x3
-#define HPLAN
-#endif
 
 /*
   Braindamage remaining:
@@ -94,12 +87,6 @@
 static void NS8390_trigger_send(struct device *dev, unsigned int length,
 				int start_page);
 
-extern int el2autoprobe(int ioaddr, struct device *dev);
-extern int el2probe(int ioaddr, struct device *dev);
-extern int neprobe(int ioaddr, struct device *dev);
-extern int wdprobe(int ioaddr, struct device *dev);
-extern int hpprobe(int ioaddr, struct device *dev);
-
 struct sigaction ei_sigaction = { ei_interrupt, 0, 0, NULL, };
 
 /* Open/initialize the board.  This routine goes all-out, setting everything
@@ -260,7 +247,7 @@
 ei_interrupt(int reg_ptr)
 {
     int irq = -(((struct pt_regs *)reg_ptr)->orig_eax+2);
-    struct device *dev = irq2dev_map[irq];
+    struct device *dev = (struct device *)(irq2dev_map[irq]);
     int e8390_base;
     int interrupts, boguscount = 0;
     struct ei_device *ei_local;
@@ -580,36 +567,15 @@
     return &ei_local->stat;
 }
 
-int
-ethif_init(struct device *dev)
-{
-    if (1
-#ifdef WD80x3
-	&& ! wdprobe(dev->base_addr, dev)
-#endif
-#ifdef EL2
-	&& ! el2autoprobe(dev->base_addr, dev)
-#endif
-#ifdef NE2000
-	&& ! neprobe(dev->base_addr, dev)
-#endif
-#ifdef HPLAN
-	&& ! hpprobe(dev->base_addr, dev)
-#endif
-	&& 1 ) {
-	return 1;	/* -ENODEV or -EAGAIN would be more accurate. */
-    }
-    if (ei_debug > 1)
-	printk(version);
-    return 0;
-}
-
-/* Initialize the rest of the device structure. */
+/* Initialize the rest of the 8390 device structure. */
 int
 ethdev_init(struct device *dev)
 {
     int i;
 
+    if (ei_debug > 1)
+	printk(version);
+
     for (i = 0; i < DEV_NUMBUFFS; i++)
 	dev->buffs[i] = NULL;
 
diff --git a/net/inet/8390.h b/net/inet/8390.h
index 5d7cae8..08e763e 100644
--- a/net/inet/8390.h
+++ b/net/inet/8390.h
@@ -8,6 +8,7 @@
 #define _8390_h
 
 #include <linux/if_ether.h>
+#include <linux/ioport.h>
 
 #define TX_2X_PAGES 12
 #define TX_1X_PAGES 6
@@ -25,10 +26,12 @@
 extern int ei_open(struct device *dev);
 extern void ei_interrupt(int reg_ptr);
 
+#ifndef HAVE_AUTOIRQ
 /* From auto_irq.c */
 extern struct device *irq2dev_map[16];
 extern void autoirq_setup(int waittime);
 extern int autoirq_report(int waittime);
+#endif
 
 /* Most of these entries should be in 'struct device' (or most of the
    things in there should be here!) */
diff --git a/net/inet/CONFIG b/net/inet/CONFIG
index 99900b7..694fc0d 100644
--- a/net/inet/CONFIG
+++ b/net/inet/CONFIG
@@ -1,53 +1,47 @@
 #
-# Set the address and IRQ here. The ne.c and 3c503 driver will autoprobe
+# Set any special options here.  Most drivers will autoprobe/autoIRQ
 # if you set the address or IRQ to zero, so we do that by default.
-# Cards supportted:
+# Cards and options supported:
 #
-#	WD80x3		The Western Digital (SMC) WD80x3 driver
-#	  WD_SHMEM=xxx	Forces the address of the shared memory
-#	  FORCE_8BIT	Force card into 8-bit mode (WD8003)
-#	NE2000		The Novell NE-2000 driver
-#	HPLAN		The HP-LAN driver
-#	EL1		The 3c501 EtherLink I driver (source missing?)
-#	EL2		The 3c503 EtherLink II driver
-#	  EL2_AUI	Selects the AUI port instead of the BNC port
-#	PLIP		The Crynwe PL/IP driver
-#	SLIP		The MicroWalt SLIP driver
+#  EI_DEBUG		Set the debugging level for 8390-based boards
+#  CONFIG_WD80x3	The Western Digital (SMC) WD80x3 driver
+#	WD_SHMEM=xxx	Forces the address of the shared memory
+#	WD_no_mapout	Don't map out the shared memory (faster, but
+#			your machine may not warm-boot).
+#  CONFIG_NE2000	The NE-[12]000 clone driver.
+#	PACKETBUF_MEMSIZE  Allows an extra-large packet buffer to be
+#			used.  Usually pointless under Linux.
+#	show_all_SAPROM  Show the entire address PROM, not just the
+#			ethernet address, during boot.
+#	rw_bugfix	Patch an obscure bug with a version of the 8390.
+#  CONFIG_HPLAN		The HP-LAN driver (for 8390-based boards only).
+#	rw_bugfix	Fix the same obscure bug.
+#  CONFIG_EL1		The 3c501 driver (just joking, never released)
+#  CONFIG_EL2		The 3c503 EtherLink II driver
+#	EL2_AUI		Default to the AUI port instead of the BNC port
+#	no_probe_nonshared_memory  Don't probe for programmed-I/O boards.
+#	EL2MEMTEST	Test shared memory at boot-time.
+#  CONFIG_EL3
+#	EL3_DEBUG	Set the debugging message level.
+#  CONFIG_AT1500
+#	LANCE_DEBUG	Set the debugging message level.
+#	DEFAULT_DMA	Change the default DMA to other than 5.
+#  CONFIG_PLIP		The Crynwr-protocol PL/IP driver
+#  SLIP			The MicroWalt SLIP driver
 #	  SL_DUMP	Uses the "dump frame" debug code
 #	  SL_COMPRESSED Use CSLIP
-#	D_LINK		The D-Link DE-600 Portable Ethernet Adaptor.
+#  D_LINK		The D-Link DE-600 Portable Ethernet Adaptor.
 #	  D_LINK_IO	The D-Link I/O address (0x378 == default)
 #	  D_LINK_IRQ	The D-Link IRQ number to use (IRQ7 == default)
 #	  D_LINK_DEBUG	Enable or disable D-Link debugging
 #
-# Note: for most WD (SMC) cards, the AutoProbe doesn't work.  You have
-#	to force those cards into operation, by specifying the I/O add-
-#	ress (EI8390=xxx), the IRQ (EI8390_IRQ=xxx) and the address of
-#	the shared memory (WD_SHMEM=xxxx).  All other supported cards
-#	behave like they should, you can leave the values to 0. -FvK
-#
 
-# Comment out the lines you don't want..
+# This is at the top level with 'make config'
+CARDS =
 
-#CARDS	:= $(CARDS) -DSLIP
-#CARDS	:= $(CARDS) -DPLIP
-CARDS	:= $(CARDS) -DWD80x3
-CARDS	:= $(CARDS) -DNE2000
-CARDS	:= $(CARDS) -DHPLAN
-CARDS	:= $(CARDS) -DEL2
-CARDS	:= $(CARDS) -DD_LINK
-CARDS	:= $(CARDS) -DCONFIG_AT1500
 
-# For WD and SMC cards:
-#OPTS		= -DEI8390=0x280 -DEI8390_IRQ=15
-#WD_OPTS		= -DWD_SHMEM=0xCC000 -UFORCE_8BIT
-OPTS		= -DEI8390=0 -DEI8390_IRQ=0
-WD_OPTS		= -DWD_SHMEM=0
-
-# For all other cards:
-#OPTS		= -DEI8390=0 -DEI8390_IRQ=0
-#WD_OPTS	= -DUD_SHMEM=0xCC000 -UFORCE_8BIT
-
+OPTS		= #-DEI8390=0 -DEI8390_IRQ=0
+WD_OPTS		= #-DWD_SHMEM=0
 EL2_OPTS	= #-UEL2_AUI
 NE_OPTS		=
 HP_OPTS		=
diff --git a/net/inet/Makefile b/net/inet/Makefile
index 1c7a6d7..eeebd52 100644
--- a/net/inet/Makefile
+++ b/net/inet/Makefile
@@ -20,7 +20,7 @@
 OBJS	= Space.o sock.o utils.o route.o proc.o timer.o protocol.o loopback.o \
 	  eth.o packet.o arp.o dev.o 8390.o wd.o ne.o el2.o hp.o plip.o \
 	  slip.o slhc.o d_link.o auto_irq.o ip.o raw.o icmp.o tcp.o udp.o\
-	  lance.o
+	  lance.o 3c509.o #ip-frag.o
 
 ifdef CONFIG_INET
 
@@ -38,36 +38,39 @@
 include	CONFIG
 
 
-Space.o:	CONFIG Space.c Makefile
+Space.o:	Space.c CONFIG /usr/include/linux/autoconf.h
 		$(CC) $(CPPFLAGS) $(CFLAGS) $(OPTS) $(CARDS) $(DL_OPTS) \
-							-c Space.c -o $@
+							-c $< -o $@
 
-8390.o:		CONFIG 8390.c Makefile
-		$(CC) $(CPPFLAGS) $(CFLAGS) $(CARDS) -c 8390.c -o $@
+8390.o:		8390.c CONFIG
+		$(CC) $(CPPFLAGS) $(CFLAGS) $(CARDS) -c $< -o $@
 
-wd.o:		CONFIG wd.c Makefile
-		$(CC) $(CPPFLAGS) $(CFLAGS) $(WD_OPTS) -c wd.c -o $@
+wd.o:		wd.c CONFIG
+		$(CC) $(CPPFLAGS) $(CFLAGS) $(WD_OPTS) -c $< -o $@
 
-el2.o:		CONFIG el2.c el2reg.h Makefile
-		$(CC) $(CPPFLAGS) $(CFLAGS) $(EL2_OPTS) -c el2.c -o $@
+el2.o:		el2.c CONFIG el2reg.h
+		$(CC) $(CPPFLAGS) $(CFLAGS) $(EL2_OPTS) -c $< -o $@
 
-ne.o:		CONFIG ne.c Makefile
-		$(CC) $(CPPFLAGS) $(CFLAGS) $(NE_OPTS) -c ne.c -o $@
+ne.o:		ne.c CONFIG
+		$(CC) $(CPPFLAGS) $(CFLAGS) $(NE_OPTS) -c $< -o $@
 
-hp.o:		CONFIG hp.c Makefile
-		$(CC) $(CPPFLAGS) $(CFLAGS) $(HP_OPTS) -c hp.c -o $@
+hp.o:		hp.c CONFIG
+		$(CC) $(CPPFLAGS) $(CFLAGS) $(HP_OPTS) -c $< -o $@
 
-plip.o:		CONFIG plip.c Makefile
-		$(CC) $(CPPFLAGS) $(CFLAGS) $(PLIP_OPTS) -c plip.c -o $@
+plip.o:		plip.c CONFIG
+		$(CC) $(CPPFLAGS) $(CFLAGS) $(PLIP_OPTS) -c $< -o $@
 
-slip.o:		CONFIG slip.c Makefile
-		$(CC) $(CPPFLAGS) $(CFLAGS) $(SLIP_OPTS) -c slip.c -o $@
+slip.o:		slip.c CONFIG
+		$(CC) $(CPPFLAGS) $(CFLAGS) $(SLIP_OPTS) -c $< -o $@
 
-d_link.o:	CONFIG d_link.c Makefile
-		$(CC) $(CPPFLAGS) $(CFLAGS) $(DL_OPTS) -c d_link.c -o $@
+d_link.o:	d_link.c CONFIG
+		$(CC) $(CPPFLAGS) $(CFLAGS) $(DL_OPTS) -c $< -o $@
 
-lance.o:	CONFIG lance.c Makefile
-		$(CC) $(CPPFLAGS) $(CFLAGS) $(AT_OPTS) -c lance.c -o $@
+lance.o:	lance.c CONFIG
+		$(CC) $(CPPFLAGS) $(CFLAGS) $(AT_OPTS) -c $< -o $@
+
+3c509.o:	3c509.c CONFIG
+		$(CC) $(CPPFLAGS) $(CFLAGS) $(EL3_OPTS) -c $< -o $@
 
 subdirs:	dummy
 		for i in $(SUBDIRS); do (cd $$i; $(MAKE)); done
diff --git a/net/inet/Space.c b/net/inet/Space.c
index a547399..b63db1f 100644
--- a/net/inet/Space.c
+++ b/net/inet/Space.c
@@ -33,6 +33,73 @@
 #define	NEXT_DEV	NULL
 
 
+/* A unifed ethernet device probe.  This is the easiest way to have every
+   ethernet adaptor have the name "eth[0123...]".
+   */
+
+extern int wd_probe(struct device *dev);
+extern int el2_probe(struct device *dev);
+extern int ne_probe(struct device *dev);
+extern int hp_probe(struct device *dev);
+extern int znet_probe(struct device *);
+extern int express_probe(struct device *);
+extern int el3_probe(struct device *);
+extern int atp_probe(struct device *);
+extern int at1500_probe(struct device *);
+extern int depca_probe(struct device *);
+extern int el1_probe(struct device *);
+
+static int
+ethif_probe(struct device *dev)
+{
+    short base_addr = dev->base_addr;
+
+    if (base_addr < 0  ||  base_addr == 1)
+	return 1;		/* ENXIO */
+
+    if (1
+#if defined(CONFIG_WD80x3) || defined(WD80x3)
+	&& wd_probe(dev)
+#endif
+#if defined(CONFIG_EL2) || defined(EL2)
+	&& el2_probe(dev)
+#endif
+#if defined(CONFIG_NE2000) || defined(NE2000)
+	&& ne_probe(dev)
+#endif
+#if defined(CONFIG_HPLAN) || defined(HPLAN)
+	&& hp_probe(dev)
+#endif
+#ifdef CONFIG_AT1500
+	&& at1500_probe(dev)
+#endif
+#ifdef CONFIG_EL3
+	&& el3_probe(dev)
+#endif
+#ifdef CONFIG_ZNET
+	&& znet_probe(dev)
+#endif
+#ifdef CONFIG_EEXPRESS
+	&& express_probe(dev)
+#endif
+#ifdef CONFIG_ATP		/* AT-LAN-TEC (RealTek) pocket adaptor. */
+	&& atp_probe(dev)
+#endif
+#ifdef CONFIG_DEPCA
+	&& depca_probe(dev)
+#endif
+#ifdef CONFIG_EL1
+	&& el1_probe(dev)
+#endif
+	&& 1 ) {
+	return 1;	/* -ENODEV or -EAGAIN would be more accurate. */
+    }
+    return 0;
+}
+
+
+/* This remains seperate because it requires the addr and IRQ to be
+   set. */
 #if defined(D_LINK) || defined(CONFIG_DE600)
     extern int d_link_init(struct device *);
     static struct device d_link_dev = {
@@ -51,101 +118,32 @@
 #   define NEXT_DEV	(&d_link_dev)
 #endif
 
-#ifdef CONFIG_EL1
-#error 
-#   ifndef EL1_IRQ
-#	define EL1_IRQ 9
-#   endif
-#   ifndef EL1
-#	define EL1 0
-#   endif
-    extern int el1_init(struct device *);
-    static struct device el1_dev = {
-        "el0", 0, 0, 0, 0, EL1,	EL1_IRQ, 0, 0, 0, NEXT_DEV, el1_init
-    };
-#   undef NEXT_DEV
-#   define NEXT_DEV	(&el1_dev)
-#endif  /* EL1 */
+/* The first device defaults to I/O base '0', which means autoprobe. */
+#ifdef EI8390
+# define ETH0_ADDR EI8390
+#else
+# define ETH0_ADDR 0
+#endif
+#ifdef EI8390_IRQ
+# define ETH0_IRQ EI8390_IRQ
+#else
+# define ETH0_IRQ 0
+#endif
+/* "eth0" defaults to autoprobe, other use a base of "-0x20", "don't probe".
+   Enable these with boot-time setup. 0.99pl13+ can optionally autoprobe. */
 
-#ifdef CONFIG_DEPCA
-    extern int depca_probe(struct device *);
-    static struct device depca_dev = {
-        "depca0", 0,0,0,0, 0, 0, 0, 0, 0, NEXT_DEV, depca_probe,
-    };
-#   undef NEXT_DEV
-#   define NEXT_DEV	(&depca_dev)
-#endif  /* CONFIG_DEPCA */
+static struct device eth3_dev = {
+    "eth3", 0,0,0,0,0xffe0 /* I/O base*/, 0,0,0,0, NEXT_DEV, ethif_probe };
+static struct device eth2_dev = {
+    "eth2", 0,0,0,0,0xffe0 /* I/O base*/, 0,0,0,0, &eth3_dev, ethif_probe };
+static struct device eth1_dev = {
+    "eth1", 0,0,0,0,0xffe0 /* I/O base*/, 0,0,0,0, &eth2_dev, ethif_probe };
 
+static struct device eth0_dev = {
+    "eth0", 0, 0, 0, 0, ETH0_ADDR, ETH0_IRQ, 0, 0, 0, &eth1_dev, ethif_probe };
 
-#ifdef CONFIG_ATP		/* AT-LAN-TEC (RealTek) pocket adaptor. */
-    extern int atp_probe(struct device *);
-    static struct device atp_dev = {
-        "atp0", 0,0,0,0, 0, 0, 0, 0, 0, NEXT_DEV, atp_probe,
-    };
 #   undef NEXT_DEV
-#   define NEXT_DEV	(&atp_dev)
-#endif  /* CONFIG_ATP */
-
-#ifdef CONFIG_EL3
-    extern int el3_probe(struct device *);
-    static struct device eliii0_dev = {
-        "eliii0", 0,0,0,0, 0, 0, 0, 0, 0, NEXT_DEV, el3_probe,
-    };
-#   undef NEXT_DEV
-#   define NEXT_DEV	(&eliii0_dev)
-#endif  /* CONFIG_3C509 aka EL3 */
-
-#ifdef CONFIG_ZNET
-    extern int znet_probe(struct device *);
-    static struct device znet_dev = {
-	"znet", 0,0,0,0, 0, 0, 0, 0, 0, NEXT_DEV, znet_probe, };
-#   undef NEXT_DEV
-#   define NEXT_DEV	(&znet_dev)
-#endif  /* CONFIG_ZNET */
-
-#ifdef CONFIG_EEXPRESS
-    extern int express_probe(struct device *);
-    static struct device express0_dev = {
-	"exp0", 0,0,0,0, 0, 0, 0, 0, 0, NEXT_DEV, express_probe, };
-#   undef NEXT_DEV
-#   define NEXT_DEV	(&express0_dev)
-#endif  /* CONFIG_EEPRESS */
-
-#ifdef CONFIG_AT1500
-    extern int at1500_probe(struct device *);
-    static struct device lance_dev = {
-        "le0",
-	0,0,0,0, 0 /* I/O Base */, 0 /* pre-set IRQ */,
-        0, 0, 0, NEXT_DEV, at1500_probe,
-    };
-#   undef NEXT_DEV
-#   define NEXT_DEV	(&lance_dev)
-#endif  /* AT1500BT */
-
-#if defined(EI8390) || defined(CONFIG_EL2) || defined(CONFIG_NE2000) \
-    || defined(CONFIG_WD80x3) || defined(CONFIG_HPLAN)
-#   ifndef EI8390
-#	define EI8390 0
-#   endif
-#   ifndef EI8390_IRQ
-#	define EI8390_IRQ 0
-#   endif
-    extern int ethif_init(struct device *);
-    static struct device ei8390_dev = {
-	"eth0",
-	0,				/* auto-config			*/
-	0,
-	0,
-	0,
-	EI8390,
-	EI8390_IRQ,
-	0, 0, 0,
-	NEXT_DEV,
-	ethif_init
-    };
-#   undef NEXT_DEV
-#   define NEXT_DEV	(&ei8390_dev)
-#endif  /* The EI8390 drivers. */
+#   define NEXT_DEV	(&eth0_dev)
 
 #if defined(PLIP) || defined(CONFIG_PLIP)
     extern int plip_init(struct device *);
diff --git a/net/inet/dev.c b/net/inet/dev.c
index 78e7223..78726ad 100644
--- a/net/inet/dev.c
+++ b/net/inet/dev.c
@@ -18,6 +18,7 @@
  */
 #include <asm/segment.h>
 #include <asm/system.h>
+#include <asm/bitops.h>
 #include <linux/config.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
@@ -29,6 +30,7 @@
 #include <linux/in.h>
 #include <linux/errno.h>
 #include <linux/interrupt.h>
+#include <linux/if_ether.h>
 #include "inet.h"
 #include "dev.h"
 #include "eth.h"
@@ -262,8 +264,8 @@
 		return dev;
   for (dev = dev_base; dev; dev = dev->next)
 	if ((dev->flags & IFF_UP) && !(dev->flags & IFF_POINTOPOINT) &&
-	    addr == (dev->flags & IFF_LOOPBACK ? dev->pa_addr : dev->pa_addr &
-	    dev->pa_mask))
+	    (dev->flags & IFF_LOOPBACK ? (addr == dev->pa_addr) :
+	    (dev->pa_addr & addr) == (dev->pa_addr & dev->pa_mask)))
 		break;
   /* no need to check broadcast addresses */
   return dev;
@@ -368,9 +370,40 @@
   sti();
 }
 
+/*
+ * Receive a packet from a device driver and queue it for the upper
+ * (protocol) levels.  It always succeeds.
+ */
+void
+netif_rx(struct sk_buff *skb)
+{
+  /* Set any necessary flags. */
+  skb->lock = 0;
+  skb->sk = NULL;
+
+  /* and add it to the "backlog" queue. */
+  cli();
+  if (backlog == NULL) {
+	skb->prev = skb;
+	skb->next = skb;
+	backlog = skb;
+  } else {
+	skb->prev = (struct sk_buff *) backlog->prev;
+	skb->next = (struct sk_buff *) backlog;
+	skb->next->prev = skb;
+	skb->prev->next = skb;
+  }
+  sti();
+   
+  /* If any packet arrived, mark it for processing. */
+  if (backlog != NULL) mark_bh(INET_BH);
+
+  return;
+}
+
 
 /*
- * Fetch a packet from a device driver.
+ * The old interface to fetch a packet from a device driver.
  * This function is the base level entry point for all drivers that
  * want to send a packet to the upper (protocol) levels.  It takes
  * care of de-multiplexing the packet to the various modules based
@@ -389,18 +422,20 @@
   int len2;
 
   if (dev == NULL || buff == NULL || len <= 0) return(1);
-  if (dropping && backlog != NULL) {
-	return(1);
-  }
-  if (dropping) printk("INET: dev_rint: no longer dropping packets.\n");
-  dropping = 0;
-
   if (flags & IN_SKBUFF) {
 	skb = (struct sk_buff *) buff;
   } else {
+	if (dropping) {
+	  if (backlog != NULL)
+	      return(1);
+	  printk("INET: dev_rint: no longer dropping packets.\n");
+	  dropping = 0;
+	}
+
 	skb = (struct sk_buff *) kmalloc(sizeof(*skb) + len, GFP_ATOMIC);
 	if (skb == NULL) {
-		printk("dev_rint: packet dropped (no memory) !\n");
+		printk("dev_rint: packet dropped on %s (no memory) !\n",
+		       dev->name);
 		dropping = 1;
 		return(1);
 	}
@@ -426,25 +461,8 @@
   }
   skb->len = len;
   skb->dev = dev;
-  skb->sk = NULL;
 
-  /* Now add it to the backlog. */
-  cli();
-  if (backlog == NULL) {
-	skb->prev = skb;
-	skb->next = skb;
-	backlog = skb;
-  } else {
-	skb->prev = (struct sk_buff *) backlog->prev;
-	skb->next = (struct sk_buff *) backlog;
-	skb->next->prev = skb;
-	skb->prev->next = skb;
-  }
-  sti();
-   
-  /* If any packet arrived, mark it for processing. */
-  if (backlog != NULL) mark_bh(INET_BH);
-
+  netif_rx(skb);
   /* OK, all done. */
   return(0);
 }
@@ -475,16 +493,11 @@
   struct packet_type *ptype;
   unsigned short type;
   unsigned char flag = 0;
-  static volatile int in_bh = 0;
+  static volatile char in_bh = 0;
 
-  /* Check && mark our BUSY state. */
-  cli();
-  if (in_bh != 0) {
-	sti();
-	return;
-  }
-  in_bh = 1;
-  sti();
+  /* Atomically check and mark our BUSY state. */
+  if (set_bit(1, (void*)&in_bh))
+      return;
 
   /* Can we send anything now? */
   dev_transmit();
@@ -671,14 +684,46 @@
   return(pos - arg);
 }
 
+/* Print device statistics. */
+char *sprintf_stats(char *buffer, struct device *dev)
+{
+  char *pos = buffer;
+  struct enet_statistics *stats = (dev->get_stats ? dev->get_stats(dev): NULL);
+
+  if (stats)
+    pos += sprintf(pos, "%6s:%7d %4d %4d %4d %4d %8d %4d %4d %4d %5d %4d\n",
+		   dev->name,
+		   stats->rx_packets, stats->rx_errors,
+		   stats->rx_dropped + stats->rx_missed_errors,
+		   stats->rx_fifo_errors,
+		   stats->rx_length_errors + stats->rx_over_errors
+		   + stats->rx_crc_errors + stats->rx_frame_errors,
+		   stats->tx_packets, stats->tx_errors, stats->tx_dropped,
+		   stats->tx_fifo_errors, stats->collisions,
+		   stats->tx_carrier_errors + stats->tx_aborted_errors
+		   + stats->tx_window_errors + stats->tx_heartbeat_errors);
+  else
+      pos += sprintf(pos, "%6s: No statistics available.\n", dev->name);
+
+  return pos;
+}
 
 /* Called from the PROCfs module. */
 int
 dev_get_info(char *buffer)
 {
-  return(dev_ifconf(buffer));
-}
+  char *pos = buffer;
+  struct device *dev;
 
+  pos +=
+      sprintf(pos,
+	      "Inter-|   Receive                  |  Transmit\n"
+	      " face |packets errs drop fifo frame|packets errs drop fifo colls carrier\n");
+  for (dev = dev_base; dev != NULL; dev = dev->next) {
+      pos = sprintf_stats(pos, dev);
+  }
+  return pos - buffer;
+}
 
 /* Perform the SIOCxIFxxx calls. */
 static int
@@ -702,18 +747,18 @@
 		ret = 0;
 		break;
 	case SIOCSIFFLAGS:
-		ret = dev->flags;
-		dev->flags = ifr.ifr_flags & (
+		{
+		  int old_flags = dev->flags;
+		  dev->flags = ifr.ifr_flags & (
 			IFF_UP | IFF_BROADCAST | IFF_DEBUG | IFF_LOOPBACK |
 			IFF_POINTOPOINT | IFF_NOTRAILERS | IFF_RUNNING |
 			IFF_NOARP | IFF_PROMISC | IFF_ALLMULTI);
-		if ((ret & IFF_UP) && ((dev->flags & IFF_UP) == 0)) {
+		  if ((old_flags & IFF_UP) && ((dev->flags & IFF_UP) == 0)) {
 			ret = dev_close(dev);
-		} else {
-			if (((ret & IFF_UP) == 0) && (dev->flags & IFF_UP)) {
-				ret = dev_open(dev);
-			} else ret = 0;
-		}
+		  } else
+		      ret = (! (old_flags & IFF_UP) && (dev->flags & IFF_UP))
+			? dev_open(dev) : 0;
+	        }
 		break;
 	case SIOCGIFADDR:
 		(*(struct sockaddr_in *)
@@ -820,9 +865,55 @@
   int ret;
 
   switch(cmd) {
-	case IP_SET_DEV:
-		printk("INET: Warning: old-style ioctl(IP_SET_DEV) called!\n");
-		return(-EINVAL);
+  case IP_SET_DEV:
+      {	  /* Maintain backwards-compatibility, to be deleted for 1.00. */
+	  struct device *dev;
+	  /* The old 'struct ip_config'. */
+	  struct ip_config {
+	      char name[MAX_IP_NAME];
+	      unsigned long paddr, router, net,up:1,destroy:1;
+	  } ipc;
+	  int retval, loopback;
+
+	  printk("INET: Warning: old-style ioctl(IP_SET_DEV) called!\n");
+	  if (!suser())
+	      return (-EPERM);
+	  
+	  verify_area (VERIFY_WRITE, arg, sizeof (ipc));
+	  memcpy_fromfs(&ipc, arg, sizeof (ipc));
+	  ipc.name[MAX_IP_NAME-1] = 0;
+	  loopback = (strcmp(ipc.name, "loopback") == 0);
+	  dev = dev_get( loopback ? "lo" : ipc.name);
+	  if (dev == NULL)
+	      return -EINVAL;
+	  ipc.destroy = 0;
+	  dev->pa_addr = ipc.paddr;
+	  dev->family = AF_INET;
+	  dev->pa_mask = get_mask(dev->pa_addr);
+	  dev->pa_brdaddr = dev->pa_addr | ~dev->pa_mask;
+	  if (ipc.net != 0xffffffff) {
+	      dev->flags |= IFF_BROADCAST;
+	      dev->pa_brdaddr = ipc.net;
+	  }
+	  
+	  /* To be proper we should delete the route here. */
+	  if (ipc.up == 0)
+	      return (dev->flags & IFF_UP != 0) ? dev_close(dev) : 0;
+
+	  if ((dev->flags & IFF_UP) == 0
+	      && (retval = dev_open(dev)) != 0)
+	      return retval;
+	  printk("%s: adding HOST route of %8.8x.\n", dev->name,
+		 htonl(ipc.paddr));
+	  rt_add(RTF_HOST, ipc.paddr, 0, dev);
+	  if (ipc.router != 0 && ipc.router != -1) {
+	      rt_add(RTF_GATEWAY, ipc.paddr, ipc.router, dev);
+	      printk("%s: adding GATEWAY route of %8.8x.\n",
+		     dev->name, htonl(ipc.paddr));
+
+	  }
+	  return 0;
+      }
 	case SIOCGIFCONF:
 		(void) dev_ifconf((char *) arg);
 		ret = 0;
diff --git a/net/inet/dev.h b/net/inet/dev.h
index 316e18c..5a69b25 100644
--- a/net/inet/dev.h
+++ b/net/inet/dev.h
@@ -169,6 +169,9 @@
 extern int		dev_close(struct device *dev);
 extern void		dev_queue_xmit(struct sk_buff *skb, struct device *dev,
 				       int pri);
+#define HAVE_NETIF_RX 1
+extern void		netif_rx(struct sk_buff *skb);
+/* The old interface to netif_rx(). */
 extern int		dev_rint(unsigned char *buff, long len, int flags,
 				 struct device * dev);
 extern void		dev_transmit(void);
diff --git a/net/inet/el2.c b/net/inet/el2.c
index b5adbff..4ff9e31 100644
--- a/net/inet/el2.c
+++ b/net/inet/el2.c
@@ -16,7 +16,7 @@
 */
 
 static char *version =
-    "el2.c:v0.99.12B 8/12/93 Donald Becker (becker@super.org)\n";
+    "el2.c:v0.99.13 8/30/93 Donald Becker (becker@super.org)\n";
 
 #include <linux/config.h>
 #include <linux/kernel.h>
@@ -30,9 +30,9 @@
 #include "8390.h"
 #include "el2reg.h"
 
-int el2autoprobe(int ioaddr, struct device *dev);
+int el2_probe(struct device *dev);
 int el2_pio_autoprobe(struct device *dev);
-int el2probe(int ioaddr, struct device *dev);
+int el2probe1(int ioaddr, struct device *dev);
 
 static int el2_open(struct device *dev);
 static int el2_close(struct device *dev);
@@ -55,13 +55,15 @@
 static int ports[] = {0x300,0x310,0x330,0x350,0x250,0x280,0x2a0,0x2e0,0};
 
 int
-el2autoprobe(int ioaddr, struct device *dev)
+el2_probe(struct device *dev)
 {
     int *addr, addrs[] = { 0xddffe, 0xd9ffe, 0xcdffe, 0xc9ffe, 0};
+    short ioaddr = dev->base_addr;
 
-    /* Non-autoprobe case first: */
+    if (ioaddr < 0)
+	return ENXIO;		/* Don't probe at all. */
     if (ioaddr > 0)
-	return el2probe(ioaddr, dev);
+	return ! el2probe1(ioaddr, dev);
 
     for (addr = addrs; *addr; addr++) {
 	int i;
@@ -70,13 +72,19 @@
 	for(i = 7; i >= 0; i--, base_bits >>= 1)
 	    if (base_bits & 0x1)
 		break;
-	if (base_bits == 1 &&  el2probe(ports[i], dev))
-	    return dev->base_addr;
+	if (base_bits != 1)
+	    continue;
+#ifdef HAVE_PORTRESERVE
+	if (check_region(ports[i], 16))
+	    continue;
+#endif
+	if (el2probe1(ports[i], dev))
+	    return 0;
     }
-#ifdef probe_nonshared_memory
+#ifndef no_probe_nonshared_memory
     return el2_pio_autoprobe(dev);
 #else
-    return 0;
+    return ENODEV;
 #endif
 }
 
@@ -87,21 +95,25 @@
 {
     int i;
     for (i = 0; i < 8; i++) {
+#ifdef HAVE_PORTRESERVE
+	if (check_region(ports[i], 16))
+	    continue;
+#endif
 	/* Reset and/or avoid any lurking NE2000 */
 	if (inb_p(ports[i] + 0x408) == 0xff)
 	    continue;
 	if (inb(ports[i] + 0x403) == (0x80 >> i) /* Preliminary check */
-	    && el2probe(ports[i], dev))
-	    return dev->base_addr;
+	    && el2probe1(ports[i], dev))
+	    return 0;
     }
-    return 0;
+    return ENODEV;
 }
 
 /* Probe for the Etherlink II card at I/O port base IOADDR,
    returning non-zero on sucess.  If found, set the station
    address and memory parameters in DEVICE. */
 int
-el2probe(int ioaddr, struct device *dev)
+el2probe1(int ioaddr, struct device *dev)
 {
     int i, iobase_reg, membase_reg, saved_406;
     unsigned char *station_addr = dev->dev_addr;
@@ -134,6 +146,9 @@
 	return 0;
     }
 
+#ifdef HAVE_PORTRESERVE
+    snarf_region(ioaddr, 16);
+#endif
     ethdev_init(dev);
 
     /* Map the 8390 back into the window. */
@@ -336,10 +351,10 @@
 	memcpy(dest_addr, buf, count);
 	if (ei_debug > 2  &&  memcmp(dest_addr, buf, count))
 	    printk("%s: 3c503 send_packet() bad memory copy @ %#5x.\n",
-		   dev->name, dest_addr);
+		   dev->name, (int) dest_addr);
 	else if (ei_debug > 4)
 	    printk("%s: 3c503 send_packet() good memory copy @ %#5x.\n",
-		   dev->name, dest_addr);
+		   dev->name, (int) dest_addr);
 	return;
     }
     /* No shared memory, put the packet out the slow way. */
@@ -383,7 +398,7 @@
 	    if (ei_debug > 4)
 		printk("%s: 3c503 block_input() @ %#5x+%x=%5x.\n",
 		       dev->name, dev->mem_start, ring_offset,
-		       (char *)dev->mem_start + ring_offset);
+		       dev->mem_start + ring_offset);
 	    memcpy(buf, (char *)dev->mem_start + ring_offset, semi_count);
 	    count -= semi_count;
 	    memcpy(buf + semi_count, (char *)dev->rmem_start, count);
@@ -392,7 +407,7 @@
 	if (ei_debug > 4)
 	    printk("%s: 3c503 block_input() @ %#5x+%x=%5x.\n",
 		   dev->name, dev->mem_start, ring_offset,
-		   (char *)dev->mem_start + ring_offset);
+		   dev->mem_start + ring_offset);
 	memcpy(buf, (char *)dev->mem_start + ring_offset, count);
 	return ring_offset + count;
     }
diff --git a/net/inet/eth.c b/net/inet/eth.c
index da06dea..8ad98d5 100644
--- a/net/inet/eth.c
+++ b/net/inet/eth.c
@@ -134,6 +134,15 @@
   dst = *(unsigned long *) eth->h_dest;
   DPRINTF((DBG_DEV, "ETH: RebuildHeader: SRC=%s ", in_ntoa(src)));
   DPRINTF((DBG_DEV, "DST=%s\n", in_ntoa(dst)));
+/*  Kludge to check IP address before sending an ARP request 
+     to fix invalid IP addresses on ARP calls.  jacob@mayhem 9/5/93  */
+  if (src != dev->pa_addr) {
+   /*	
+     printk("Got bad arp_find request in eth_rebuild_header: %s\n", in_ntoa(src));
+     printk("Replacing with correct source IP address: %s\n", in_ntoa(dev->pa_addr));
+   */
+    src = dev->pa_addr;
+  }
   if (arp_find(eth->h_dest, dst, dev, src)) return(1);
   memcpy(eth->h_source, dev->dev_addr, dev->addr_len);
   return(0);
diff --git a/net/inet/hp.c b/net/inet/hp.c
index 18a49a3..9ffbff4 100644
--- a/net/inet/hp.c
+++ b/net/inet/hp.c
@@ -13,7 +13,7 @@
 */
 
 static char *version =
-    "hp.c:v0.99.12+ 8/12/93 Donald Becker (becker@super.org)\n";
+    "hp.c:v0.99.13 8/30/93 Donald Becker (becker@super.org)\n";
 
 #include <linux/config.h>
 #include <linux/kernel.h>
@@ -40,7 +40,7 @@
 #define HP_8BSTOP_PG	0x80	/* Last page +1 of RX ring */
 #define HP_16BSTOP_PG	0xFF	/* Last page +1 of RX ring */
 
-int hpprobe(int ioaddr, struct device *dev);
+int hp_probe(struct device *dev);
 int hpprobe1(int ioaddr, struct device *dev);
 
 static void hp_reset_8390(struct device *dev);
@@ -59,17 +59,27 @@
     Also initialize the card and fill in STATION_ADDR with the station
    address. */
 
-int hpprobe(int ioaddr,  struct device *dev)
+int hp_probe(struct device *dev)
 {
     int *port, ports[] = {0x300, 0x320, 0x340, 0x280, 0x2C0, 0x200, 0x240, 0};
+    short ioaddr = dev->base_addr;
 
+    if (ioaddr < 0)
+	return ENXIO;		/* Don't probe at all. */
     if (ioaddr > 0x100)
-	return hpprobe1(ioaddr, dev);
+	return ! hpprobe1(ioaddr, dev);
 
-    for (port = &ports[0]; *port; port++)
-	if (inb_p(*port) != 0xff && hpprobe1(*port, dev))
-	    return dev->base_addr;
-    return 0;
+    for (port = &ports[0]; *port; port++) {
+#ifdef HAVE_PORTRESERVE
+	if (check_region(*port, 32))
+	    continue;
+#endif
+	if (inb_p(*port) != 0xff && hpprobe1(*port, dev)) {
+	    return 0;
+	}
+    }
+    dev->base_addr = ioaddr;
+    return ENODEV;
 }
 
 int hpprobe1(int ioaddr, struct device *dev)
@@ -140,6 +150,10 @@
       }
   }
 
+#ifdef HAVE_PORTRESERVE
+    snarf_region(ioaddr, 32);
+#endif
+
   if (ei_debug > 1)
       printk(version);
 
@@ -179,7 +193,7 @@
 	    printk("%s: hp_reset_8390() did not complete.\n", dev->name);
 	    return;
 	}
-    if (ei_debug > 1) printk("8390 reset done.", jiffies);
+    if (ei_debug > 1) printk("8390 reset done (%d).", jiffies);
 }
 
 /* Block input and output, similar to the Crynwr packet driver.  If you
diff --git a/net/inet/ip.c b/net/inet/ip.c
index 636a0b3..90eb68f 100644
--- a/net/inet/ip.c
+++ b/net/inet/ip.c
@@ -5,10 +5,11 @@
  *
  *		The Internet Protocol (IP) module.
  *
- * Version:	@(#)ip.c	1.0.16	06/02/93
+ * Version:	@(#)ip.c	1.0.16b	9/1/93
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
+ *		Donald Becker, <becker@super.org>
  *
  *		This program is free software; you can redistribute it and/or
  *		modify it under the terms of the GNU General Public License
@@ -382,6 +383,27 @@
   return(0);
 }
 
+/* This is a version of ip_compute_csum() optimized for IP headers, which
+   always checksum on 4 octet boundaries. */
+static inline unsigned short
+ip_fast_csum(unsigned char * buff, int wlen)
+{
+    unsigned long sum = 0;
+    __asm__("\t clc\n"
+	    "1:\n"
+	    "\t lodsl\n"
+	    "\t adcl %%eax, %%ebx\n"
+	    "\t loop 1b\n"
+	    "\t adcl $0, %%ebx\n"
+	    "\t movl %%ebx, %%eax\n"
+	    "\t shrl $16, %%eax\n"
+	    "\t addw %%ax, %%bx\n"
+	    "\t adcw $0, %%bx\n"
+	    : "=b" (sum) , "=S" (buff)
+	    : "0" (sum), "c" (wlen) ,"1" (buff)
+	    : "ax", "cx", "si", "bx" );
+    return (~sum) & 0xffff;
+}
 
 /*
  * This routine does all the checksum computations that don't
@@ -429,23 +451,21 @@
   return(sum & 0xffff);
 }
 
-
-/* Check the header of an incoming IP datagram. */
+/* Check the header of an incoming IP datagram.  This version is still used in slhc.c. */
 int
 ip_csum(struct iphdr *iph)
 {
-  if (iph->check == 0) return(0);
-  if (ip_compute_csum((unsigned char *)iph, iph->ihl*4) == 0) return(0);
+  if (iph->check == 0  || ip_fast_csum((unsigned char *)iph, iph->ihl) == 0)
+      return(0);
   return(1);
 }
 
-
 /* Generate a checksym for an outgoing IP datagram. */
 static void
 ip_send_check(struct iphdr *iph)
 {
    iph->check = 0;
-   iph->check = ip_compute_csum((unsigned char *)iph, iph->ihl*4);
+   iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
 }
 
 
@@ -554,21 +574,20 @@
 int
 ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
 {
-  struct iphdr *iph;
+  struct iphdr *iph = skb->h.iph;
   unsigned char hash;
   unsigned char flag = 0;
+  unsigned char opts_p = 0;	/* Set iff the packet has options. */
   struct inet_protocol *ipprot;
   static struct options opt; /* since we don't use these yet, and they
 				take up stack space. */
   int brd;
 
-  iph = skb->h.iph;
-  memset((char *) &opt, 0, sizeof(opt));
   DPRINTF((DBG_IP, "<<\n"));
-  ip_print(iph);
 
   /* Is the datagram acceptable? */
-  if (ip_csum(iph) || do_options(iph, &opt) || iph->version != 4) {
+  if (iph->version != 4
+      || (iph->check != 0 && ip_fast_csum((unsigned char *)iph, iph->ihl) !=0)) {
 	DPRINTF((DBG_IP, "\nIP: *** datagram error ***\n"));
 	DPRINTF((DBG_IP, "    SRC = %s   ", in_ntoa(iph->saddr)));
 	DPRINTF((DBG_IP, "    DST = %s (ignored)\n", in_ntoa(iph->daddr)));
@@ -577,7 +596,15 @@
 	return(0);
   }
 
-  /* Do any IP forwarding required. */
+  if (iph->ihl != 5) {  	/* Fast path for the typical optionless IP packet. */
+      ip_print(iph);		/* Bogus, only for debugging. */
+      memset((char *) &opt, 0, sizeof(opt));
+      if (do_options(iph, &opt) != 0)
+	  return 0;
+      opts_p = 1;
+  }
+
+  /* Do any IP forwarding required.  chk_addr() is expensive -- avoid it someday. */
   if ((brd = chk_addr(iph->daddr)) == 0) {
 #ifdef CONFIG_IP_FORWARD
 	ip_forward(skb, dev);
@@ -588,17 +615,12 @@
   }
 
   /*
-   * Deal with fragments: not really...
-   * Fragmentation is definitely a required part of IP (yeah, guys,
-   * I read Linux-Activists.NET too :-), but the current "sk_buff"
-   * allocation stuff doesn't make things simpler.  When we're all
-   * done cleaning up the mess, we'll add Ross Biro's "mbuf" stuff
-   * to the code, which will replace the sk_buff stuff completely.
-   * That will (a) make the code even cleaner, (b) allow me to do
-   * the DDI (Device Driver Interface) the way I want to, and (c),
-   * it will allow for easy addition of fragging.  Any takers? -FvK
-   */
-  if ((iph->frag_off & 32) || (ntohs(iph->frag_off) & 0x1fff)) {
+   * Reassemble IP fragments. */
+
+  if ((iph->frag_off & 0x0020) || (ntohs(iph->frag_off) & 0x1fff)) {
+#ifdef CONFIG_IP_DEFRAG
+      ip_defrag(skb);
+#else
 	printk("\nIP: *** datagram fragmentation not yet implemented ***\n");
 	printk("    SRC = %s   ", in_ntoa(iph->saddr));
 	printk("    DST = %s (ignored)\n", in_ntoa(iph->daddr));
@@ -606,6 +628,7 @@
 	skb->sk = NULL;
 	kfree_skb(skb, FREE_WRITE);
 	return(0);
+#endif
   }
 
   /* Point into the IP datagram, just past the header. */
@@ -646,7 +669,7 @@
 	* based on the datagram protocol.  We should really
 	* check the protocol handler's return values here...
 	*/
-	ipprot->handler(skb2, dev, &opt, iph->daddr,
+	ipprot->handler(skb2, dev, opts_p ? &opt : 0, iph->daddr,
 			(ntohs(iph->tot_len) - (iph->ihl * 4)),
 			iph->saddr, 0, ipprot);
 
@@ -751,6 +774,12 @@
   skb = sk->send_head;
   while (skb != NULL) {
 	dev = skb->dev;
+	/* I know this can't happen but as it does.. */
+	if(dev==NULL)
+	{
+		printk("ip_forward: NULL device bug!\n");
+		goto oops;
+	}
 
 	/*
 	 * The rebuild_header function sees if the ARP is done.
@@ -773,7 +802,7 @@
 		  else dev->queue_xmit(skb, dev, SOPRI_NORMAL );
 	}
 
-	sk->retransmits++;
+oops:	sk->retransmits++;
 	sk->prot->retransmits ++;
 	if (!all) break;
 
diff --git a/net/inet/ip.h b/net/inet/ip.h
index af203cc..611dd1f 100644
--- a/net/inet/ip.h
+++ b/net/inet/ip.h
@@ -21,6 +21,8 @@
 
 #include <linux/ip.h>
 
+#include "sock.h"	/* struct sock */
+
 extern int		backoff(int n);
 
 extern void		ip_print(struct iphdr *ip);
diff --git a/net/inet/lance.c b/net/inet/lance.c
index 0ae14c6..eca3d20 100644
--- a/net/inet/lance.c
+++ b/net/inet/lance.c
@@ -7,13 +7,14 @@
     distributed according to the terms of the GNU Public License,
     incorporated herein by reference.
 
-    This driver should work with the Allied Telesis 1500, and NE2100 clones.
+    This driver is for the Allied Telesis AT1500, and should work with
+    NE2100 clones.
 
     The author may be reached as becker@super.org or
     C/O Supercomputing Research Ctr., 17100 Science Dr., Bowie MD 20715
 */
 
-static char *version = "lance.c:v0.08 8/12/93 becker@super.org\n";
+static char *version = "lance.c:v0.12 9/3/93 becker@super.org\n";
 
 #include <linux/config.h>
 #include <linux/kernel.h>
@@ -22,6 +23,7 @@
 /*#include <linux/interrupt.h>*/
 #include <linux/ptrace.h>
 #include <linux/errno.h>
+#include <linux/ioport.h>
 #include <asm/io.h>
 #include <asm/dma.h>
 /*#include <asm/system.h>*/
@@ -32,12 +34,12 @@
 #include "skbuff.h"
 #include "arp.h"
 
+#ifndef HAVE_AUTOIRQ
 /* From auto_irq.c, should be in a *.h file. */
 extern void autoirq_setup(int waittime);
 extern int autoirq_report(int waittime);
 extern struct device *irq2dev_map[16];
-
-extern void printk_stats(struct enet_statistics *stats);
+#endif
 
 #ifdef LANCE_DEBUG
 int lance_debug = LANCE_DEBUG;
@@ -60,6 +62,7 @@
 #define LANCE_ADDR 0x12
 #define LANCE_RESET 0x14
 #define LANCE_BUS_IF 0x16
+#define LANCE_TOTAL_SIZE 0x18
 
 /* The LANCE Rx and Tx ring descriptors. */
 struct lance_rx_head {
@@ -96,14 +99,17 @@
     int pad0, pad1;		/* Used for alignment */
 };
 
-/* This is a temporary solution to the lack of a ethercard low-memory
-   allocation scheme.  We need it for bus-master or DMA ethercards if
-   they are to work >16M memory systems.  */
+/* We need a ethercard low-memory allocation scheme for for bus-master or
+   DMA ethercards if they are to work >16M memory systems. This is a
+   temporary solution to the lack of one, but it limits us to a single
+   AT1500 and <16M. Bummer. */
+
 #define PKT_BUF_SZ	1550
 static char rx_buffs[PKT_BUF_SZ][RING_SIZE];
 
-int at1500_init(int ioaddr, struct device *dev);
+int at1500_probe1(struct device *dev);
 static int lance_open(struct device *dev);
+static void lance_init_ring(struct device *dev);
 static int lance_start_xmit(struct sk_buff *skb, struct device *dev);
 static int lance_rx(struct device *dev);
 static void lance_interrupt(int reg_ptr);
@@ -119,33 +125,52 @@
 int at1500_probe(struct device *dev)
 {
     int *port, ports[] = {0x300, 0x320, 0x340, 0x360, 0};
-    int ioaddr = dev->base_addr;
+    int base_addr = dev->base_addr;
 
-    if (ioaddr > 0x100)
-	return ! at1500_init(ioaddr, dev);
+    if (base_addr < 0)
+	return ENXIO;		/* Don't probe at all. */
+    if (base_addr > 0x100)	/* Check a single specified location. */
+	return at1500_probe1(dev);
 
+    /* First probe for the ethercard ID, 0x57, and then look for a LANCE
+       chip. */
+    
     for (port = &ports[0]; *port; port++) {
-	/* Probe for the Allied-Telesys vendor ID.  This will not detect
-	   other NE2100-like ethercards, which must use a hard-wired ioaddr.
-	   There must be a better way to detect a LANCE... */
-	int ioaddr = *port;
-	if (inb(ioaddr) != 0x00
-	    || inb(ioaddr+1) != 0x00
-	    || inb(ioaddr+2) != 0xF4)
+	int probe_addr = *port;
+	short temp;
+
+#ifdef HAVE_PORTRESERVE
+	if (check_region(probe_addr, LANCE_TOTAL_SIZE))
 	    continue;
-	if (at1500_init(ioaddr, dev))
+#endif
+	if (inb(probe_addr + 14) != 0x57
+	    || inb(probe_addr + 15) != 0x57)
+	    continue;
+
+	/* Reset the LANCE. Un-Reset needed only for the real NE2100. */
+	temp = inw(probe_addr+LANCE_RESET); /* Reset the LANCE */
+	outw(temp, probe_addr+LANCE_RESET);	/* "Un-reset" */
+	
+	outw(0x0000, probe_addr+LANCE_ADDR); /* Switch to window 0 */
+	if (inw(probe_addr+LANCE_DATA) != 0x0004)
+	    continue;
+	dev->base_addr = probe_addr;
+	if (at1500_probe1(dev) == 0)
 	    return 0;
     }
-    return 1;			/* ENODEV would be more accurate. */
+
+    dev->base_addr = base_addr;
+    return ENODEV;			/* ENODEV would be more accurate. */
 }
 
 int
-at1500_init(int ioaddr, struct device *dev)
+at1500_probe1(struct device *dev)
 {
     struct lance_private *lp;
+    short ioaddr = dev->base_addr;
+
     int i;
 
-    dev->base_addr = ioaddr;
     printk("%s: LANCE at %#3x, address", dev->name, ioaddr);
 
     /* There is a 16 byte station address PROM at the base address.
@@ -163,12 +188,16 @@
 
     if ((int)dev->priv & 0xff000000  ||  (int) rx_buffs & 0xff000000) {
 	printk(" disabled (buff %#x > 16M).\n", (int)rx_buffs);
-	return 0;
+	return -ENOMEM;
     }
 
     memset(dev->priv, 0, sizeof(struct lance_private));
     lp = (struct lance_private *)dev->priv;
 
+    if ((int)(lp->rx_ring) & 0x07)
+	printk("%s: LANCE Rx and Tx rings not on even boundary.\n",
+	       dev->name);
+
     /* Un-Reset the LANCE, needed only for the NE2100. */
     outw(0, ioaddr+LANCE_RESET);
 
@@ -181,7 +210,7 @@
     lp->init_block.tx_ring = (int)lp->tx_ring | RING_LEN_BITS;
 
     outw(0x0001, ioaddr+LANCE_ADDR);
-    outw((short) &lp->init_block, ioaddr+LANCE_DATA);
+    outw((short) (int) &lp->init_block, ioaddr+LANCE_DATA);
     outw(0x0002, ioaddr+LANCE_ADDR);
     outw(((int)&lp->init_block) >> 16, ioaddr+LANCE_DATA);
     outw(0x0000, ioaddr+LANCE_ADDR);
@@ -199,11 +228,14 @@
 	    printk(", using IRQ %d.\n", dev->irq);
 	else {
 	    printk(", failed to detect IRQ line.\n");
-	    return 0;
+	    return -EAGAIN;
 	}
     } else
 	printk(" assigned IRQ %d.\n", dev->irq);
 
+    /* The DMA channel may be passed in on this parameter. */
+    dev->dma = dev->mem_start & 0x07;
+
 #ifndef NE2100			/* The NE2100 might not understand */
     /* Turn on auto-select of media (10baseT or BNC) so that the user
        can watch the LEDs even if the board isn't opened. */
@@ -211,9 +243,9 @@
     outw(0x0002, ioaddr+LANCE_BUS_IF);
 #endif
 
-    if ((int)(lp->rx_ring) & 0x07)
-	printk("%s: LANCE Rx and Tx rings not on even boundary.\n",
-	       dev->name);
+#ifdef HAVE_PORTRESERVE
+    snarf_region(ioaddr, LANCE_TOTAL_SIZE);
+#endif
 
     if (lance_debug > 0)
 	printk(version);
@@ -225,7 +257,6 @@
     dev->get_stats = &lance_get_stats;
 
     dev->mem_start = 0;
-    dev->rmem_end = 0x00ffffff;		/* Bogus, needed for dev_rint(). */
 
     /* Fill in the generic field of the device structure. */
     for (i = 0; i < DEV_NUMBUFFS; i++)
@@ -253,7 +284,7 @@
     dev->pa_mask	= 0;
     dev->pa_alen	= sizeof(unsigned long);
 
-    return ioaddr;
+    return 0;
 }
 
 
@@ -268,8 +299,7 @@
 	return -EAGAIN;
     }
 
-    if (lp->dma < 1)
-	lp->dma = DEFAULT_DMA;
+    lp->dma = dev->dma ? dev->dma : DEFAULT_DMA;
 
     if (request_dma(lp->dma)) {
 	free_irq(dev->irq);
@@ -287,7 +317,8 @@
     /* Un-Reset the LANCE, needed only for the NE2100. */
     outw(0, ioaddr+LANCE_RESET);
 
-#ifndef NE2100			/* The NE2100 might not understand */
+#ifndef NE2100
+    /* This is really 79C960-specific, NE2100 might not understand */
     /* Turn on auto-select of media (10baseT or BNC). */
     outw(0x0002, ioaddr+LANCE_ADDR);
     outw(0x0002, ioaddr+LANCE_BUS_IF);
@@ -295,29 +326,13 @@
 
     if (lance_debug > 1)
 	printk("%s: lance_open() irq %d dma %d tx/rx rings %#x/%#x init %#x.\n",
-	       dev->name, dev->irq, lp->dma, lp->tx_ring, lp->rx_ring,
-	       &lp->init_block);
+	       dev->name, dev->irq, lp->dma, (int) lp->tx_ring, (int) lp->rx_ring,
+	       (int) &lp->init_block);
 
-    lp->cur_rx = lp->cur_tx = 0;
-    lp->dirty_rx = lp->dirty_tx = 0;
-
-    for (i = 0; i < RING_SIZE; i++) {
-	lp->rx_ring[i].base = (int)rx_buffs | 0x80000000 + i*PKT_BUF_SZ;
-	lp->rx_ring[i].buf_length = -PKT_BUF_SZ;
-	lp->tx_ring[i].base = 0;
-    }
-
-    lp->init_block.mode = 0x0000;
-    for (i = 0; i < 6; i++)
-	lp->init_block.phys_addr[i] = dev->dev_addr[i];
-    lp->init_block.filter[0] = 0x00000000;
-    lp->init_block.filter[1] = 0x00000000;
-    lp->init_block.rx_ring = (int)lp->rx_ring | RING_LEN_BITS;
-    lp->init_block.tx_ring = (int)lp->tx_ring | RING_LEN_BITS;
-
+    lance_init_ring(dev);
     /* Re-initialize the LANCE, and start it when done. */
     outw(0x0001, ioaddr+LANCE_ADDR);
-    outw((short) &lp->init_block, ioaddr+LANCE_DATA);
+    outw((short) (int) &lp->init_block, ioaddr+LANCE_DATA);
     outw(0x0002, ioaddr+LANCE_ADDR);
     outw(((int)&lp->init_block) >> 16, ioaddr+LANCE_DATA);
 
@@ -338,11 +353,36 @@
 
     if (lance_debug > 2)
 	printk("%s: LANCE open after %d ticks, init block %#x csr0 %4.4x.\n",
-	       dev->name, i, &lp->init_block, inw(ioaddr+LANCE_DATA));
+	       dev->name, i, (int) &lp->init_block, inw(ioaddr+LANCE_DATA));
 
     return 0;			/* Always succeed */
 }
 
+/* Initialize the LANCE Rx and Tx rings. */
+static void
+lance_init_ring(struct device *dev)
+{
+    struct lance_private *lp = (struct lance_private *)dev->priv;
+    int i;
+
+    lp->cur_rx = lp->cur_tx = 0;
+    lp->dirty_rx = lp->dirty_tx = 0;
+
+    for (i = 0; i < RING_SIZE; i++) {
+	lp->rx_ring[i].base = (int) rx_buffs | (0x80000000 + i*PKT_BUF_SZ);
+	lp->rx_ring[i].buf_length = -PKT_BUF_SZ;
+	lp->tx_ring[i].base = 0;
+    }
+
+    lp->init_block.mode = 0x0000;
+    for (i = 0; i < 6; i++)
+	lp->init_block.phys_addr[i] = dev->dev_addr[i];
+    lp->init_block.filter[0] = 0x00000000;
+    lp->init_block.filter[1] = 0x00000000;
+    lp->init_block.rx_ring = (int)lp->rx_ring | RING_LEN_BITS;
+    lp->init_block.tx_ring = (int)lp->tx_ring | RING_LEN_BITS;
+}
+
 static int
 lance_start_xmit(struct sk_buff *skb, struct device *dev)
 {
@@ -352,18 +392,16 @@
     /* Transmitter timeout, serious problems. */
     if (dev->tbusy) {
 	int tickssofar = jiffies - dev->trans_start;
-	int entry = lp->cur_tx++;
 	if (tickssofar < 5)
 	    return 1;
 	outw(0, ioaddr+LANCE_ADDR);
-	printk("%s: transmit timed out, status %4.4x.\n", dev->name,
-	       inw(ioaddr+LANCE_DATA));
+	printk("%s: transmit timed out, status %4.4x, resetting.\n",
+	       dev->name, inw(ioaddr+LANCE_DATA));
 
-	if (lp->tx_ring[(entry+1) & RING_MOD_MASK].base >= 0)
-	    dev->tbusy=0;
-	else
-	    outw(0x00, ioaddr+LANCE_DATA),
-	    outw(0x43, ioaddr+LANCE_DATA);;
+	lance_init_ring(dev);
+	outw(0x43, ioaddr+LANCE_DATA);
+
+	dev->tbusy=0;
 	dev->trans_start = jiffies;
 
 	return 0;
@@ -424,7 +462,7 @@
 		(unsigned char *)(lp->tx_ring[entry].base & 0x00ffffff);
 
 	    printk("%s: tx ring[%d], %#x, sk_buf %#x len %d.\n",
-		   dev->name, entry, &lp->tx_ring[entry],
+		   dev->name, entry, (int) &lp->tx_ring[entry],
 		   lp->tx_ring[entry].base, -lp->tx_ring[entry].length);
 	    printk("%s:  Tx %2.2x %2.2x %2.2x ... %2.2x  %2.2x %2.2x %2.2x...%2.2x len %2.2x %2.2x  %2.2x %2.2x.\n",
 		   dev->name, pkt[0], pkt[1], pkt[2], pkt[5], pkt[6],
@@ -446,7 +484,7 @@
 lance_interrupt(int reg_ptr)
 {
     int irq = -(((struct pt_regs *)reg_ptr)->orig_eax+2);
-    struct device *dev = irq2dev_map[irq];
+    struct device *dev = (struct device *)(irq2dev_map[irq]);
     struct lance_private *lp;
     int csr0, ioaddr;
 
@@ -485,8 +523,8 @@
 	/* This code is broken for >16M RAM systems. */
 	while (dirty_tx != (lp->cur_tx & RING_MOD_MASK)
 	       && lp->tx_ring[dirty_tx].base > 0) {
-	    sk_buff *skb =
-		(sk_buff *)(lp->tx_ring[dirty_tx].base & 0x00ffffff);
+	    struct sk_buff *skb =
+		(struct sk_buff *)(lp->tx_ring[dirty_tx].base & 0x00ffffff);
 	    unsigned short *tmdp = (unsigned short *)(&lp->tx_ring[dirty_tx]);
 	    int status = lp->tx_ring[dirty_tx].base >> 24;
 
@@ -510,6 +548,7 @@
 		kfree_skb (skb-1, FREE_WRITE);
 	    dirty_tx = ++lp->dirty_tx & RING_MOD_MASK;
 	}
+	/* mark_bh(INET_BH); */
     }
 
     /* Clear the interrupts we've handled. */
@@ -531,21 +570,10 @@
     struct lance_private *lp = (struct lance_private *)dev->priv;
     int entry = lp->cur_rx & RING_MOD_MASK;
 	
-    /* Check to see if we own this entry. */
+    /* If we own the next entry, it's a new packet. Send it up. */
     while (lp->rx_ring[entry].base >= 0) {
 	int status = lp->rx_ring[entry].base >> 24;
-	if (lance_debug > 5) {
-	    unsigned char *pkt =
-		(unsigned char *)(lp->rx_ring[entry].base & 0x00ffffff);
-	    printk("%s: Rx packet at ring entry %d, len %d status %2.2x.\n",
-		   dev->name, entry, lp->rx_ring[entry].msg_length,
-		   lp->rx_ring[entry].base >> 24);
-	    printk("%s:  Rx %2.2x %2.2x %2.2x ... %2.2x  %2.2x %2.2x %2.2x...%2.2x len %2.2x %2.2x  %2.2x %2.2x.\n",
-		   dev->name, pkt[0], pkt[1], pkt[2], pkt[5], pkt[6],
-		   pkt[7], pkt[8], pkt[11], pkt[12], pkt[13],
-		   pkt[14], pkt[15]);
-	}
-	/* If so, copy it to the upper layers. */
+
 	if (status & 0x40) {	/* There was an error. */
 	    lp->stats.rx_errors++;
 	    if (status & 0x20) lp->stats.rx_frame_errors++;
@@ -553,18 +581,43 @@
 	    if (status & 0x08) lp->stats.rx_crc_errors++;
 	    if (status & 0x04) lp->stats.rx_fifo_errors++;
 	} else {
-	    if (dev_rint((unsigned char *)(lp->rx_ring[entry].base
-					   & 0x00ffffff),
-			 lp->rx_ring[entry].msg_length, 0, dev)) {
+	    /* Malloc up new buffer, compatible with net-2e. */
+	    short pkt_len = lp->rx_ring[entry].msg_length;
+	    int sksize = sizeof(struct sk_buff) + pkt_len;
+	    struct sk_buff *skb;
+	    skb = (struct sk_buff *) kmalloc(sksize, GFP_ATOMIC);
+	    if (skb == NULL) {
+		printk("%s: Memory squeeze, deferring packet.\n", dev->name);
+		lp->stats.rx_dropped++;	/* Really, deferred. */
+		break;
+	    }
+	    skb->mem_len = sksize;
+	    skb->mem_addr = skb;
+	    skb->len = pkt_len;
+	    skb->dev = dev;
+	    memcpy((unsigned char *) (skb + 1),
+		   (unsigned char *)(lp->rx_ring[entry].base & 0x00ffffff),
+		   pkt_len);
+#ifdef HAVE_NETIF_RX
+	    netif_rx(skb);
+#else
+	    skb->lock = 0;
+	    if (dev_rint((unsigned char*)skb, pkt_len, IN_SKBUFF, dev) != 0) {
+		kfree_s(skb, sksize);
 		lp->stats.rx_dropped++;
 		break;
 	    }
+#endif
 	    lp->stats.rx_packets++;
 	}
 
 	lp->rx_ring[entry].base |= 0x80000000;
 	entry = (entry+1) & RING_MOD_MASK;
     }
+
+    /* We should check that at least two ring entries are free.  If not,
+       we should free one and mark stats->rx_dropped++. */
+
     lp->cur_rx = entry;
 
     return 0;
@@ -587,10 +640,6 @@
     if (lance_debug > 1)
 	printk("%s: Shutting down ethercard, status was %2.2x.\n",
 	       dev->name, inw(ioaddr+LANCE_DATA));
-#ifdef PRINTK_STATS
-    if (lance_debug > 2)
-	printk_stats(&lp->stats);
-#endif
 
     /* We stop the LANCE here -- it occasionally polls
        memory if we don't. */
diff --git a/net/inet/loopback.c b/net/inet/loopback.c
index 27fc00e..7629425 100644
--- a/net/inet/loopback.c
+++ b/net/inet/loopback.c
@@ -5,10 +5,11 @@
  *
  *		Pseudo-driver for the loopback interface.
  *
- * Version:	@(#)loopback.c	1.0.4	05/25/93
+ * Version:	@(#)loopback.c	1.0.4b	08/16/93
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
+ *		Donald Becker, <becker@super.org>
  *
  *		This program is free software; you can redistribute it and/or
  *		modify it under the terms of the GNU General Public License
@@ -30,6 +31,7 @@
 #include <linux/errno.h>
 #include <linux/fcntl.h>
 #include <linux/in.h>
+#include <linux/if_ether.h>	/* For the statistics structure. */
 #include "inet.h"
 #include "dev.h"
 #include "eth.h"
@@ -44,6 +46,7 @@
 static int
 loopback_xmit(struct sk_buff *skb, struct device *dev)
 {
+  struct enet_statistics *stats = (struct enet_statistics *)dev->priv;
   int done;
 
   DPRINTF((DBG_LOOPB, "loopback_xmit(dev=%X, skb=%X)\n", dev, skb));
@@ -52,6 +55,7 @@
   cli();
   if (dev->tbusy != 0) {
 	sti();
+	stats->tx_errors++;
 	return(1);
   }
   dev->tbusy = 1;
@@ -63,6 +67,8 @@
   while (done != 1) {
 	done = dev_rint(NULL, 0, 0, dev);
   }
+  stats->tx_packets++;
+
   dev->tbusy = 0;
 
 #if 1
@@ -83,6 +89,11 @@
   return(0);
 }
 
+static struct enet_statistics *
+get_stats(struct device *dev)
+{
+    return (struct enet_statistics *)dev->priv;
+}
 
 /* Initialize the rest of the LOOPBACK device. */
 int
@@ -118,6 +129,9 @@
   dev->pa_brdaddr	= in_aton("127.255.255.255");
   dev->pa_mask		= in_aton("255.0.0.0");
   dev->pa_alen		= sizeof(unsigned long);
-
+  dev->priv = kmalloc(sizeof(struct enet_statistics), GFP_KERNEL);
+  memset(dev->priv, 0, sizeof(struct enet_statistics));
+  dev->get_stats = get_stats;
+  
   return(0);
 };
diff --git a/net/inet/ne.c b/net/inet/ne.c
index 28093eb..86cfec2 100644
--- a/net/inet/ne.c
+++ b/net/inet/ne.c
@@ -17,11 +17,12 @@
 /* Routines for the NatSemi-based designs (NE[12]000). */
 
 static char *version =
-    "ne.c:v0.99-12B 8/12/93 Donald Becker (becker@super.org)\n";
+    "ne.c:v0.99-13 8/30/93 Donald Becker (becker@super.org)\n";
 
 #include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
+#include <linux/errno.h>
 #include <asm/system.h>
 #include <asm/io.h>
 #ifndef port_read
@@ -41,7 +42,7 @@
 #define NESM_START_PG	0x40	/* First page of TX buffer */
 #define NESM_STOP_PG	0x80	/* Last page +1 of RX ring */
 
-int neprobe(int ioaddr, struct device *dev);
+int ne_probe(struct device *dev);
 static int neprobe1(int ioaddr, struct device *dev, int verbose);
 
 static void ne_reset_8390(struct device *dev);
@@ -72,17 +73,28 @@
 	E2010	 starts at 0x100 and ends at 0x4000.
 	E2010-x starts at 0x100 and ends at 0xffff.  */
 
-int neprobe(int ioaddr,  struct device *dev)
+int ne_probe(struct device *dev)
 {
     int *port, ports[] = {0x300, 0x280, 0x320, 0x340, 0x360, 0};
+    short ioaddr = dev->base_addr;
 
+    if (ioaddr < 0)
+	return ENXIO;		/* Don't probe at all. */
     if (ioaddr > 0x100)
-	return neprobe1(ioaddr, dev, 1);
+	return ! neprobe1(ioaddr, dev, 1);
 
-    for (port = &ports[0]; *port; port++)
-	if (inb_p(*port) != 0xff && neprobe1(*port, dev, 0))
-	    return dev->base_addr = *port;
-    return 0;
+    for (port = &ports[0]; *port; port++) {
+#ifdef HAVE_PORTRESERVE
+	if (check_region(*port, 32))
+	    continue;
+#endif
+	if (inb_p(*port) != 0xff && neprobe1(*port, dev, 0)) {
+	    dev->base_addr = *port;
+	    return 0;
+	}
+    }
+    dev->base_addr = ioaddr;
+    return ENODEV;
 }
 
 static int neprobe1(int ioaddr, struct device *dev, int verbose)
@@ -216,12 +228,15 @@
 	}
     }
 
-    printk("\n%s: %s found at %#x, using IRQ %d.\n",
-	   dev->name, name, ioaddr, dev->irq);
-
     dev->base_addr = ioaddr;
 
+#ifdef HAVE_PORTRESERVE
+    snarf_region(ioaddr, 32);
+#endif
+
     ethdev_init(dev);
+    printk("\n%s: %s found at %#x, using IRQ %d.\n",
+	   dev->name, name, ioaddr, dev->irq);
 
     if (ei_debug > 0)
 	printk(version);
diff --git a/net/inet/route.c b/net/inet/route.c
index 374befe..007878c 100644
--- a/net/inet/route.c
+++ b/net/inet/route.c
@@ -131,8 +131,10 @@
    * an Internet class C network mask.  Yuck :-(
    */
   if (flags & RTF_DYNAMIC) {
-	if (flags & RTF_HOST) rt->rt_dst = dst;
-	  else rt->rt_dst = (dst & htonl(IN_CLASSC_NET));
+	if (flags & RTF_HOST)
+		rt->rt_dst = dst;
+	else
+		rt->rt_dst = (dst & dev->pa_mask);
   } else rt->rt_dst = dst;
 
   rt_print(rt);
@@ -219,8 +221,10 @@
 	dev = dev_check(((struct sockaddr_in *) &r->rt_dst)->sin_addr.s_addr);
   else
 	if ((rt = rt_route(((struct sockaddr_in *) &r->rt_gateway)->sin_addr.
-	    s_addr,NULL))) dev = rt->rt_dev;
-	else dev = NULL;
+			   s_addr,NULL)))
+	    dev = rt->rt_dev;
+	else
+	    dev = NULL;
 
   DPRINTF((DBG_RT, "RT: dev for %s gw ",
 	in_ntoa((*(struct sockaddr_in *)&r->rt_dst).sin_addr.s_addr)));
@@ -258,12 +262,14 @@
 
   pos = buffer;
 
-  pos += sprintf(pos, "Iface\tDestination\tGateway \tFlags\tRefCnt\tUse\n");
+  pos += sprintf(pos,
+		 "Iface\tDestination\tGateway \tFlags\tRefCnt\tUse\tMetric\n");
   
+  /* This isn't quite right -- r->rt_dst is a struct! */
   for (r = rt_base; r != NULL; r = r->rt_next) {
-        pos += sprintf(pos, "%s\t%08X\t%08X\t%02X\t%d\t%d\n",
+        pos += sprintf(pos, "%s\t%08X\t%08X\t%02X\t%d\t%d\t%d\n",
 		r->rt_dev->name, r->rt_dst, r->rt_gateway,
-		r->rt_flags, r->rt_refcnt, r->rt_use);
+		r->rt_flags, r->rt_refcnt, r->rt_use, r->rt_metric);
   }
   return(pos - buffer);
 }
@@ -317,7 +323,9 @@
 int
 rt_ioctl(unsigned int cmd, void *arg)
 {
+  struct device *dev;
   struct rtentry rt;
+  char namebuf[32];
   int ret;
 
   switch(cmd) {
@@ -325,16 +333,17 @@
 		ret = dbg_ioctl(arg, DBG_RT);
 		break;
 	case SIOCADDRT:
-		if (!suser()) return(-EPERM);
-		verify_area(VERIFY_WRITE, arg, sizeof(struct rtentry));
-		memcpy_fromfs(&rt, arg, sizeof(struct rtentry));
-		ret = rt_new(&rt);
-		break;
 	case SIOCDELRT:
 		if (!suser()) return(-EPERM);
 		verify_area(VERIFY_WRITE, arg, sizeof(struct rtentry));
 		memcpy_fromfs(&rt, arg, sizeof(struct rtentry));
-		ret = rt_kill(&rt);
+		if (rt.rt_dev) {
+		    verify_area(VERIFY_WRITE, rt.rt_dev, sizeof namebuf);
+		    memcpy_fromfs(&namebuf, rt.rt_dev, sizeof namebuf);
+		    dev = dev_get(namebuf);
+		    rt.rt_dev = dev;
+		}
+		ret = (cmd == SIOCDELRT) ? rt_kill(&rt) : rt_new(&rt);
 		break;
 	default:
 		ret = -EINVAL;
diff --git a/net/inet/skbuff.h b/net/inet/skbuff.h
index 13847d4..8591a3d 100644
--- a/net/inet/skbuff.h
+++ b/net/inet/skbuff.h
@@ -25,9 +25,9 @@
 
 
 struct sk_buff {
-  struct sk_buff		*next;
-  struct sk_buff		*prev;
-  struct sk_buff		*link3;
+  struct sk_buff		*volatile next;
+  struct sk_buff		*volatile prev;
+  struct sk_buff		*volatile link3;
   struct sock			*sk;
   volatile unsigned long	when;	/* used to compute rtt's	*/
   struct device			*dev;
diff --git a/net/inet/slip.c b/net/inet/slip.c
index e7d03d1..148baf2 100644
--- a/net/inet/slip.c
+++ b/net/inet/slip.c
@@ -76,7 +76,7 @@
   return;
 
   printk("\r*****\n");
-  printk("%x %d\n", ptr, len);
+  printk("%p %d\n", ptr, len);
   ip = (struct iphdr *) ptr;
   dlen = ntohs(ip->tot_len);
   doff = ((ntohs(ip->frag_off) & IPF_F_OFFSET) << 3);
@@ -688,7 +688,7 @@
   if (already++ == 0) {
 	printk("SLIP: version %s (%d channels): ",
 				SLIP_VERSION, SL_NRUNIT);
-
+	printk("CSLIP code copyright 1989 Regents of the University of California\n");
 	/* Fill in our LDISC request block. */
 	sl_ldisc.flags	= 0;
 	sl_ldisc.open	= slip_open;
diff --git a/net/inet/sock.c b/net/inet/sock.c
index c7dd815..7f97fd7 100644
--- a/net/inet/sock.c
+++ b/net/inet/sock.c
@@ -63,19 +63,19 @@
   }
   printk("  wmem_alloc = %d\n", sk->wmem_alloc);
   printk("  rmem_alloc = %d\n", sk->rmem_alloc);
-  printk("  send_head = %X\n", sk->send_head);
+  printk("  send_head = %p\n", sk->send_head);
   printk("  state = %d\n",sk->state);
-  printk("  wback = %X, rqueue = %X\n", sk->wback, sk->rqueue);
-  printk("  wfront = %X\n", sk->wfront);
+  printk("  wback = %p, rqueue = %p\n", sk->wback, sk->rqueue);
+  printk("  wfront = %p\n", sk->wfront);
   printk("  daddr = %X, saddr = %X\n", sk->daddr,sk->saddr);
   printk("  num = %d", sk->num);
-  printk(" next = %X\n", sk->next);
+  printk(" next = %p\n", sk->next);
   printk("  send_seq = %d, acked_seq = %d, copied_seq = %d\n",
 	  sk->send_seq, sk->acked_seq, sk->copied_seq);
   printk("  rcv_ack_seq = %d, window_seq = %d, fin_seq = %d\n",
 	  sk->rcv_ack_seq, sk->window_seq, sk->fin_seq);
-  printk("  prot = %X\n", sk->prot);
-  printk("  pair = %X, back_log = %X\n", sk->pair,sk->back_log);
+  printk("  prot = %p\n", sk->prot);
+  printk("  pair = %p, back_log = %p\n", sk->pair,sk->back_log);
   printk("  inuse = %d , blog = %d\n", sk->inuse, sk->blog);
   printk("  dead = %d delay_acks=%d\n", sk->dead, sk->delay_acks);
   printk("  retransmits = %d, timeout = %d\n", sk->retransmits, sk->timeout);
@@ -92,9 +92,9 @@
 	printk("  print_skb(NULL)\n");
 	return;
   }
-  printk("  prev = %X, next = %X\n", skb->prev, skb->next);
-  printk("  sk = %X link3 = %X\n", skb->sk, skb->link3);
-  printk("  mem_addr = %X, mem_len = %d\n", skb->mem_addr, skb->mem_len);
+  printk("  prev = %p, next = %p\n", skb->prev, skb->next);
+  printk("  sk = %p link3 = %p\n", skb->sk, skb->link3);
+  printk("  mem_addr = %p, mem_len = %d\n", skb->mem_addr, skb->mem_len);
   printk("  used = %d free = %d\n", skb->used,skb->free);
 }
 
@@ -967,6 +967,8 @@
 		sti();
 		return(-EADDRINUSE);
 	}
+	if (sk2->num != snum) continue;		/* more than one */
+	if (sk2->saddr != sk->saddr) continue;	/* socket per slot ! -FB */
 	if (!sk2->reuse) {
 		sti();
 		return(-EADDRINUSE);
diff --git a/net/inet/sock.h b/net/inet/sock.h
index 4b89e25..1d0ebb3 100644
--- a/net/inet/sock.h
+++ b/net/inet/sock.h
@@ -21,6 +21,11 @@
 #define _SOCK_H
 
 #include <linux/timer.h>
+#include <linux/ip.h>		/* struct options */
+#include <linux/tcp.h>		/* struct tcphdr */
+
+#include "skbuff.h"		/* struct sk_buff */
+#include "protocol.h"		/* struct inet_protocol */
 
 #define SOCK_ARRAY_SIZE	64
 
@@ -62,14 +67,14 @@
   int				proc;
   struct sock			*next;
   struct sock			*pair;
-  struct sk_buff		*send_tail;
-  struct sk_buff		*send_head;
+  struct sk_buff		*volatile send_tail;
+  struct sk_buff		*volatile send_head;
   struct sk_buff		*volatile back_log;
   struct sk_buff		*send_tmp;
   long				retransmits;
-  struct sk_buff		*wback,
-				*wfront,
-				*rqueue;
+  struct sk_buff		*volatile wback,
+				*volatile wfront,
+				*volatile rqueue;
   struct proto			*prot;
   struct wait_queue		**sleep;
   unsigned long			daddr;
diff --git a/net/inet/tcp.c b/net/inet/tcp.c
index 0dffa08..479d6a4 100644
--- a/net/inet/tcp.c
+++ b/net/inet/tcp.c
@@ -1433,9 +1433,11 @@
   t1->dest = th->source;
   t1->source = th->dest;
   t1->seq = th->ack_seq; /* add one so it will be in the right range */
+  t1->ack_seq = htonl(ntohl(th->seq)+1);
   t1->rst = 1;
+  t1->ack_seq = htonl(ntohl(th->seq)+1); /* send correct ack -FB */
   t1->window = 0;		/* should be set to 0 -FB */
-  t1->ack = 0;
+  t1->ack = 1;
   t1->syn = 0;
   t1->urg = 0;
   t1->fin = 0;
diff --git a/net/inet/udp.c b/net/inet/udp.c
index 3f9e047..17c19da 100644
--- a/net/inet/udp.c
+++ b/net/inet/udp.c
@@ -202,7 +202,8 @@
   unsigned char *buff;
   unsigned long saddr;
   int size, tmp;
-
+  int err;
+  
   DPRINTF((DBG_UDP, "UDP: send(dst=%s:%d buff=%X len=%d)\n",
 		in_ntoa(sin->sin_addr.s_addr), ntohs(sin->sin_port),
 		from, len));
@@ -257,7 +258,9 @@
   buff = (unsigned char *) (uh + 1);
 
   /* Copy the user data. */
-  verify_area(VERIFY_WRITE, from, len);
+  err=verify_area(VERIFY_READ, from, len);
+  if(err)
+  	return(err);
   memcpy_fromfs(buff, from, len);
 
   /* Set up the UDP checksum. */
@@ -276,6 +279,7 @@
 {
   struct sockaddr_in sin;
   int tmp;
+  int err;
 
   DPRINTF((DBG_UDP, "UDP: sendto(len=%d, flags=%X)\n", len, flags));
 
@@ -287,7 +291,9 @@
   /* Get and verify the address. */
   if (usin) {
 	if (addr_len < sizeof(sin)) return(-EINVAL);
-	/* verify_area(VERIFY_WRITE, usin, sizeof(sin));*/
+	err=verify_area(VERIFY_READ, usin, sizeof(sin));
+	if(err)
+		return err;
 	memcpy_fromfs(&sin, usin, sizeof(sin));
 	if (sin.sin_family && sin.sin_family != AF_INET) return(-EINVAL);
 	if (sin.sin_port == 0) return(-EINVAL);
@@ -319,13 +325,16 @@
 int
 udp_ioctl(struct sock *sk, int cmd, unsigned long arg)
 {
+  int err;
   switch(cmd) {
 	case DDIOCSDBG:
 		{
 			int val;
 
 			if (!suser()) return(-EPERM);
-			verify_area(VERIFY_WRITE, (void *)arg, sizeof(int));
+			err=verify_area(VERIFY_READ, (void *)arg, sizeof(int));
+			if(err)
+				return err;
 			val = get_fs_long((int *)arg);
 			switch(val) {
 				case 0:
@@ -345,8 +354,10 @@
 
 			if (sk->state == TCP_LISTEN) return(-EINVAL);
 			amount = sk->prot->wspace(sk)/2;
-			verify_area(VERIFY_WRITE,(void *)arg,
+			err=verify_area(VERIFY_WRITE,(void *)arg,
 					sizeof(unsigned long));
+			if(err)
+				return(err);
 			put_fs_long(amount,(unsigned long *)arg);
 			return(0);
 		}
@@ -370,8 +381,10 @@
 				 */
 				amount = skb->len;
 			}
-			verify_area(VERIFY_WRITE,(void *)arg,
+			err=verify_area(VERIFY_WRITE,(void *)arg,
 						sizeof(unsigned long));
+			if(err)
+				return(err);
 			put_fs_long(amount,(unsigned long *)arg);
 			return(0);
 		}
@@ -394,6 +407,7 @@
 {
   int copied = 0;
   struct sk_buff *skb;
+  int er;
 
   if (len == 0) return(0);
   if (len < 0) return(-EINVAL);
@@ -410,9 +424,20 @@
 	return(err);
   }
   if (addr_len) {
-	verify_area(VERIFY_WRITE, addr_len, sizeof(*addr_len));
+	er=verify_area(VERIFY_WRITE, addr_len, sizeof(*addr_len));
+	if(er)
+		return(er);
 	put_fs_long(sizeof(*sin), addr_len);
   }
+  if(sin)
+  {
+  	er=verify_area(VERIFY_WRITE, sin, sizeof(*sin));
+  	if(er)
+  		return(er);
+  }
+  er=verify_area(VERIFY_WRITE,to,len);
+  if(er)
+  	return er;
   sk->inuse = 1;
   while(sk->rqueue == NULL) {
 	if (sk->shutdown & RCV_SHUTDOWN) {
@@ -446,7 +471,9 @@
 	}
   }
   copied = min(len, skb->len);
+  /* This was checked in the wrong place
   verify_area(VERIFY_WRITE, to, copied);
+  */
   memcpy_tofs(to, skb->h.raw + sizeof(struct udphdr), copied);
 
   /* Copy the address. */
@@ -456,7 +483,10 @@
 	addr.sin_family = AF_INET;
 	addr.sin_port = skb->h.uh->source;
 	addr.sin_addr.s_addr = skb->daddr;
-	verify_area(VERIFY_WRITE, sin, sizeof(*sin));
+	/* Also in the wrong place, jumping out here will lose
+	   a packet for good and leave the socket in use
+	   now tested above
+	verify_area(VERIFY_WRITE, sin, sizeof(*sin));*/
 	memcpy_tofs(sin, &addr, sizeof(*sin));
   }
 
@@ -480,10 +510,13 @@
 udp_connect(struct sock *sk, struct sockaddr_in *usin, int addr_len)
 {
   struct sockaddr_in sin;
-
+  int er;
+  
   if (addr_len < sizeof(sin)) return(-EINVAL);
 
-  /* verify_area(VERIFY_WRITE, usin, sizeof(sin)); */
+  er=verify_area(VERIFY_READ, usin, sizeof(sin));
+  if(er)
+  	return er;
 
   memcpy_fromfs(&sin, usin, sizeof(sin));
   if (sin.sin_family && sin.sin_family != AF_INET) return(-EAFNOSUPPORT);
diff --git a/net/inet/wd.c b/net/inet/wd.c
index bbb3e06..154450c 100644
--- a/net/inet/wd.c
+++ b/net/inet/wd.c
@@ -15,11 +15,12 @@
 */
 
 static char *version =
-    "wd.c:v0.99-12 8/12/93 Donald Becker (becker@super.org)\n";
+    "wd.c:v0.99-13 8/30/93 Donald Becker (becker@super.org)\n";
 
 #include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
+#include <linux/errno.h>
 #include <asm/io.h>
 #include <asm/system.h>
 #include <memory.h>
@@ -59,19 +60,28 @@
     The wdprobe1() routine initializes the card and fills the
     station address field. */
 
-int wdprobe(int ioaddr,  struct device *dev)
+int wd_probe(struct device *dev)
 {
     int *port, ports[] = {0x300, 0x280, 0x380, 0x240, 0};
+    short ioaddr = dev->base_addr;
 
+    if (ioaddr < 0)
+	return ENXIO;		/* Don't probe at all. */
     if (ioaddr > 0x100)
-	return wdprobe1(ioaddr, dev);
+	return ! wdprobe1(ioaddr, dev);
 
-    for (port = &ports[0]; *port; port++)
+    for (port = &ports[0]; *port; port++) {
+#ifdef HAVE_PORTRESERVE
+	if (check_region(*port, 32))
+	    continue;
+#endif
 	if (inb(*port + 8) != 0xff
 	    && inb(*port + 9) != 0xff /* Extra check to avoid soundcard. */
 	    && wdprobe1(*port, dev))
-	    return *port;
-    return 0;
+	    return 0;
+    }
+    dev->base_addr = ioaddr;
+    return ENODEV;
 }
 
 int wdprobe1(int ioaddr, struct device *dev)
@@ -93,7 +103,7 @@
       printk(" %2.2X", station_addr[i] = inb(ioaddr + 8 + i));
 
   /* The following PureData probe code was contributed by
-     Mike Jagdis <jaggy@purplet.demon.co.uk>. Puredata seem to do software
+     Mike Jagdis <jaggy@purplet.demon.co.uk>. Puredata does software
      configuration differently from others so we have to check for them.
      This detects an 8 bit, 16 bit or dumb (Toshiba, jumpered) card.
      */
@@ -192,6 +202,9 @@
   }
 
   /* OK, were are certain this is going to work.  Setup the device. */
+#ifdef HAVE_PORTRESERVE
+  snarf_region(ioaddr, 32);
+#endif
   ethdev_init(dev);
 
   ei_status.name = model_name;
@@ -231,8 +244,9 @@
   ei_status.reg5 = ((dev->mem_start>>19) & 0x1f) | NIC16;
 
   if (ei_status.word16)
-      outb(ISA16 | ei_status.reg5, ioaddr+WD_CMDREG5);
+      outb(ei_status.reg5, ioaddr+WD_CMDREG5);
   outb(ei_status.reg0, ioaddr); /* WD_CMDREG */
+
   return ei_open(dev);
 }
 
@@ -273,7 +287,8 @@
 }
 
 /* Block input and output are easy on shared memory ethercards, and trivial
-   on the Western digital card where there is no choice of how to do it. */
+   on the Western digital card where there is no choice of how to do it.
+   The only complication is if the ring buffer wraps. */
 
 static int
 wd_block_input(struct device *dev, int count, char *buf, int ring_offset)
@@ -281,7 +296,7 @@
     void *xfer_start = (void *)(dev->mem_start + ring_offset
 				- (WD_START_PG<<8));
 
-    /* This mapout won't be necessary when wd_close_card is called. */
+    /* This mapout isn't necessary if wd_close_card is called. */
 #if !defined(WD_no_mapout)
     int wd_cmdreg = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */
 
@@ -299,12 +314,6 @@
 	return dev->rmem_start + count;
     }
     memcpy(buf, xfer_start, count);
-    if (ei_debug > 4) {
-	unsigned short *board = (unsigned short *) xfer_start;
-	printk("%s: wd8013 block_input(cnt=%d offset=%3x addr=%#x) = %2x %2x %2x...\n",
-	       dev->name, count, ring_offset, xfer_start,
-	       board[-1], board[0], board[1]);
-    }
 
 #if !defined(WD_no_mapout)
     /* Turn off 16 bit access so that reboot works. */
@@ -314,8 +323,6 @@
     return ring_offset + count;
 }
 
-/* This could only be outputting to the transmit buffer.  The
-   ping-pong transmit setup doesn't work with this yet. */
 static void
 wd_block_output(struct device *dev, int count, const unsigned char *buf,
 		int start_page)
@@ -332,9 +339,6 @@
 #endif
 
     memcpy(shmem, buf, count);
-    if (ei_debug > 4)
-	printk("%s: wd80*3 block_output(addr=%#x cnt=%d) -> %2x=%2x %2x=%2x %d...\n",
-	       shmem, count, shmem[23], buf[23], shmem[24], buf[24], memcmp(shmem,buf,count));
 
 #if !defined(WD_no_mapout)
     /* Turn off 16 bit access so that reboot works. */
diff --git a/net/socket.c b/net/socket.c
index f64c123..ed50a10 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -806,7 +806,7 @@
  * we have this level of indirection. Not a lot of overhead, since more of
  * the work is done via read/write/select directly.
  */
-extern "C" int
+asmlinkage int
 sys_socketcall(int call, unsigned long *args)
 {
   switch(call) {
diff --git a/net/unix/sock.c b/net/unix/sock.c
index 7ea64fb..97a9e25 100644
--- a/net/unix/sock.c
+++ b/net/unix/sock.c
@@ -737,7 +737,7 @@
 		if (UN_BUF_AVAIL(upd) || peerupd)
 			put_fs_long(UN_BUF_AVAIL(upd),(unsigned long *)arg);
 		  else
-			put_fs_long(1,(unsigned long *)arg); /* read EOF */
+			put_fs_long(0,(unsigned long *)arg);
 		break;
 	case TIOCOUTQ:
 		if (sock->flags & SO_ACCEPTCON) return(-EINVAL);