diff -u --recursive --new-file v1.1.17/linux/Makefile linux/Makefile
--- v1.1.17/linux/Makefile	Thu Jun  2 13:50:54 1994
+++ linux/Makefile	Thu Jun  2 10:56:25 1994
@@ -1,6 +1,6 @@
 VERSION = 1
 PATCHLEVEL = 1
-SUBLEVEL = 17
+SUBLEVEL = 18
 
 all:	Version zImage
 
diff -u --recursive --new-file v1.1.17/linux/drivers/FPU-emu/Makefile linux/drivers/FPU-emu/Makefile
--- v1.1.17/linux/drivers/FPU-emu/Makefile	Tue Jan 11 11:10:47 1994
+++ linux/drivers/FPU-emu/Makefile	Thu Jun  2 10:28:22 1994
@@ -5,14 +5,13 @@
 #DEBUG	= -DDEBUGGING
 DEBUG	=
 PARANOID = -DPARANOID
-REENTRANT	= -DREENTRANT_FPU
 CFLAGS	:= $(CFLAGS) $(PARANOID) $(DEBUG) -fno-builtin
 
 .c.o:
 	$(CC) $(CFLAGS) $(MATH_EMULATION) -c $<
 
 .S.o:
-	$(CC) -D__ASSEMBLER__ $(PARANOID) $(REENTRANT) -c $<
+	$(CC) -D__ASSEMBLER__ $(PARANOID) -c $<
 
 .s.o:
 	$(CC) -c $<
diff -u --recursive --new-file v1.1.17/linux/drivers/FPU-emu/README linux/drivers/FPU-emu/README
--- v1.1.17/linux/drivers/FPU-emu/README	Sat Mar 26 14:04:23 1994
+++ linux/drivers/FPU-emu/README	Thu Jun  2 10:28:23 1994
@@ -47,7 +47,7 @@
 
 
 --Bill Metzenthen
-  March 1994
+  June 1994
 
 
 ----------------------- Internals of wm-FPU-emu -----------------------
@@ -80,20 +80,24 @@
 However, it may happen that when the emulator is accessing the user
 memory space, swapping may be needed. In this case the emulator may be
 temporarily suspended while disk i/o takes place. During this time
-another process may use the emulator, thereby changing some static
-variables (eg FPU_st0_ptr, etc). The code which accesses user memory
-is confined to five files:
+another process may use the emulator, thereby perhaps changing static
+variables. The code which accesses user memory is confined to five
+files:
     fpu_entry.c
     reg_ld_str.c
     load_store.c
     get_address.c
     errors.c
+As from version 1.12 of the emulator, no static variables are used
+(apart from those in the kernel's per-process tables). The emulator is
+therefore now fully re-entrant, rather than having just the restricted
+form of re-entrancy which is required by the Linux kernel.
 
 ----------------------- Limitations of wm-FPU-emu -----------------------
 
 There are a number of differences between the current wm-FPU-emu
-(version beta 1.11) and the 80486 FPU (apart from bugs). Some of the
-more important differences are listed below:
+(version 1.12) and the 80486 FPU (apart from bugs). Some of the more
+important differences are listed below:
 
 The Roundup flag does not have much meaning for the transcendental
 functions and its 80486 value with these functions is likely to differ
@@ -154,6 +158,11 @@
 protection fault message when run under the MS-DOS prompt of Windows
 3.1. (The program simply reads data from a valid address).
 
+The emulator supports 16-bit protected mode, with one difference from
+an 80486DX.  A 80486DX will allow some floating point instructions to
+write a few bytes below the lowest address of the stack.  The emulator
+will not allow this in 16-bit protected mode: no instructions are
+allowed to write outside the bounds set by the protection.
 
 ----------------------- Performance of wm-FPU-emu -----------------------
 
@@ -322,6 +331,7 @@
 Bruce Evans, bde@kralizec.zeta.org.au
 Timo Korvola, Timo.Korvola@hut.fi
 Rick Lyons, rick@razorback.brisnet.org.au
+Rick, jrs@world.std.com
  
 ...and numerous others who responded to my request for help with
 a real 80486.
diff -u --recursive --new-file v1.1.17/linux/drivers/FPU-emu/errors.c linux/drivers/FPU-emu/errors.c
--- v1.1.17/linux/drivers/FPU-emu/errors.c	Fri Feb 25 14:42:45 1994
+++ linux/drivers/FPU-emu/errors.c	Thu Jun  2 10:28:23 1994
@@ -42,20 +42,28 @@
   RE_ENTRANT_CHECK_OFF;
   /* No need to verify_area(), we have previously fetched these bytes. */
   printk("Unimplemented FPU Opcode at eip=%p : ", (void *) address);
-  while ( 1 )
+  if ( FPU_CS == USER_CS )
     {
-      byte1 = get_fs_byte((unsigned char *) address);
-      if ( (byte1 & 0xf8) == 0xd8 ) break;
-      printk("[%02x]", byte1);
-      address++;
+      while ( 1 )
+	{
+	  byte1 = get_fs_byte((unsigned char *) address);
+	  if ( (byte1 & 0xf8) == 0xd8 ) break;
+	  printk("[%02x]", byte1);
+	  address++;
+	}
+      printk("%02x ", byte1);
+      FPU_modrm = get_fs_byte(1 + (unsigned char *) address);
+      
+      if (FPU_modrm >= 0300)
+	printk("%02x (%02x+%d)\n", FPU_modrm, FPU_modrm & 0xf8, FPU_modrm & 7);
+      else
+	printk("/%d\n", (FPU_modrm >> 3) & 7);
     }
-  printk("%02x ", byte1);
-  FPU_modrm = get_fs_byte(1 + (unsigned char *) address);
-
-  if (FPU_modrm >= 0300)
-    printk("%02x (%02x+%d)\n", FPU_modrm, FPU_modrm & 0xf8, FPU_modrm & 7);
   else
-    printk("/%d\n", (FPU_modrm >> 3) & 7);
+    {
+      printk("cs selector = %04x\n", FPU_CS);
+    }
+
   RE_ENTRANT_CHECK_ON;
 
   EXCEPTION(EX_Invalid);
@@ -85,29 +93,36 @@
   RE_ENTRANT_CHECK_OFF;
   /* No need to verify_area(), we have previously fetched these bytes. */
   printk("At %p:", (void *) address);
-#define MAX_PRINTED_BYTES 20
-  for ( i = 0; i < MAX_PRINTED_BYTES; i++ )
+  if ( FPU_CS == USER_CS )
     {
-      byte1 = get_fs_byte((unsigned char *) address);
-      if ( (byte1 & 0xf8) == 0xd8 )
+#define MAX_PRINTED_BYTES 20
+      for ( i = 0; i < MAX_PRINTED_BYTES; i++ )
 	{
-	  printk(" %02x", byte1);
-	  break;
+	  byte1 = get_fs_byte((unsigned char *) address);
+	  if ( (byte1 & 0xf8) == 0xd8 )
+	    {
+	      printk(" %02x", byte1);
+	      break;
+	    }
+	  printk(" [%02x]", byte1);
+	  address++;
+	}
+      if ( i == MAX_PRINTED_BYTES )
+	printk(" [more..]\n");
+      else
+	{
+	  FPU_modrm = get_fs_byte(1 + (unsigned char *) address);
+	  
+	  if (FPU_modrm >= 0300)
+	    printk(" %02x (%02x+%d)\n", FPU_modrm, FPU_modrm & 0xf8, FPU_modrm & 7);
+	  else
+	    printk(" /%d, mod=%d rm=%d\n",
+		   (FPU_modrm >> 3) & 7, (FPU_modrm >> 6) & 3, FPU_modrm & 7);
 	}
-      printk(" [%02x]", byte1);
-      address++;
     }
-  if ( i == MAX_PRINTED_BYTES )
-    printk(" [more..]\n");
   else
     {
-      FPU_modrm = get_fs_byte(1 + (unsigned char *) address);
-
-      if (FPU_modrm >= 0300)
-	printk(" %02x (%02x+%d)\n", FPU_modrm, FPU_modrm & 0xf8, FPU_modrm & 7);
-      else
-	printk(" /%d, mod=%d rm=%d\n",
-	       (FPU_modrm >> 3) & 7, (FPU_modrm >> 6) & 3, FPU_modrm & 7);
+      printk("%04x\n", FPU_CS);
     }
 
   partial_status = status_word();
@@ -181,6 +196,7 @@
       printk("%s\n", tag_desc[(int) (unsigned) r->tag]);
     }
 
+#ifdef OBSOLETE
   printk("[data] %c .%04lx %04lx %04lx %04lx e%+-6ld ",
 	 FPU_loaded_data.sign ? '-' : '+',
 	 (long)(FPU_loaded_data.sigh >> 16),
@@ -189,6 +205,7 @@
 	 (long)(FPU_loaded_data.sigl & 0xFFFF),
 	 FPU_loaded_data.exp - EXP_BIAS + 1);
   printk("%s\n", tag_desc[(int) (unsigned) FPU_loaded_data.tag]);
+#endif OBSOLETE
   RE_ENTRANT_CHECK_ON;
 
 }
@@ -214,7 +231,6 @@
  error was detected.
 
  Internal error types:
-       0      in load_store.c
        0x14   in fpu_etc.c
        0x1nn  in a *.c file:
               0x101  in reg_add_sub.c
@@ -244,7 +260,13 @@
 	      0x126  in fpu_entry.c
 	      0x127  in poly_2xm1.c
 	      0x128  in fpu_entry.c
+	      0x129  in fpu_entry.c
 	      0x130  in get_address.c
+	      0x131  in get_address.c
+	      0x132  in get_address.c
+	      0x133  in get_address.c
+	      0x140  in load_store.c
+	      0x141  in load_store.c
        0x2nn  in an *.S file:
               0x201  in reg_u_add.S
               0x202  in reg_u_div.S
@@ -583,7 +605,7 @@
     {
       /* The masked response */
       top--;
-      reg_move(&CONST_QNaN, FPU_st0_ptr = &st(0));
+      reg_move(&CONST_QNaN, &st(0));
     }
 
   EXCEPTION(EX_StackOver);
@@ -599,7 +621,7 @@
  if ( control_word & CW_Invalid )
     {
       /* The masked response */
-      reg_move(&CONST_QNaN, FPU_st0_ptr);
+      reg_move(&CONST_QNaN, &st(0));
     }
 
   EXCEPTION(EX_StackUnder);
diff -u --recursive --new-file v1.1.17/linux/drivers/FPU-emu/fpu_arith.c linux/drivers/FPU-emu/fpu_arith.c
--- v1.1.17/linux/drivers/FPU-emu/fpu_arith.c	Wed Dec  1 14:44:16 1993
+++ linux/drivers/FPU-emu/fpu_arith.c	Thu Jun  2 10:28:23 1994
@@ -20,7 +20,7 @@
 {
   /* fadd st,st(i) */
   clear_C1();
-  reg_add(FPU_st0_ptr, &st(FPU_rm), FPU_st0_ptr, control_word);
+  reg_add(&st(0), &st(FPU_rm), &st(0), control_word);
 }
 
 
@@ -28,7 +28,7 @@
 {
   /* fmul st,st(i) */
   clear_C1();
-  reg_mul(FPU_st0_ptr, &st(FPU_rm), FPU_st0_ptr, control_word);
+  reg_mul(&st(0), &st(FPU_rm), &st(0), control_word);
 }
 
 
@@ -37,7 +37,7 @@
 {
   /* fsub st,st(i) */
   clear_C1();
-  reg_sub(FPU_st0_ptr, &st(FPU_rm), FPU_st0_ptr, control_word);
+  reg_sub(&st(0), &st(FPU_rm), &st(0), control_word);
 }
 
 
@@ -45,7 +45,7 @@
 {
   /* fsubr st,st(i) */
   clear_C1();
-  reg_sub(&st(FPU_rm), FPU_st0_ptr, FPU_st0_ptr, control_word);
+  reg_sub(&st(FPU_rm), &st(0), &st(0), control_word);
 }
 
 
@@ -53,7 +53,7 @@
 {
   /* fdiv st,st(i) */
   clear_C1();
-  reg_div(FPU_st0_ptr, &st(FPU_rm), FPU_st0_ptr, control_word);
+  reg_div(&st(0), &st(FPU_rm), &st(0), control_word);
 }
 
 
@@ -61,7 +61,7 @@
 {
   /* fdivr st,st(i) */
   clear_C1();
-  reg_div(&st(FPU_rm), FPU_st0_ptr, FPU_st0_ptr, control_word);
+  reg_div(&st(FPU_rm), &st(0), &st(0), control_word);
 }
 
 
@@ -70,7 +70,7 @@
 {
   /* fadd st(i),st */
   clear_C1();
-  reg_add(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm), control_word);
+  reg_add(&st(0), &st(FPU_rm), &st(FPU_rm), control_word);
 }
 
 
@@ -78,7 +78,7 @@
 {
   /* fmul st(i),st */
   clear_C1();
-  reg_mul(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm), control_word);
+  reg_mul(&st(0), &st(FPU_rm), &st(FPU_rm), control_word);
 }
 
 
@@ -86,9 +86,9 @@
 {
   /* 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); */
+     reg_sub(&st(FPU_rm), &st(0), &st(FPU_rm), control_word); */
   clear_C1();
-  reg_sub(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm), control_word);
+  reg_sub(&st(0), &st(FPU_rm), &st(FPU_rm), control_word);
 }
 
 
@@ -96,9 +96,9 @@
 {
   /* 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); */
+     reg_sub(&st(0), &st(FPU_rm), &st(FPU_rm), control_word); */
   clear_C1();
-  reg_sub(&st(FPU_rm), FPU_st0_ptr, &st(FPU_rm), control_word);
+  reg_sub(&st(FPU_rm), &st(0), &st(FPU_rm), control_word);
 }
 
 
@@ -106,7 +106,7 @@
 {
   /* fdivr st(i),st */
   clear_C1();
-  reg_div(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm), control_word);
+  reg_div(&st(0), &st(FPU_rm), &st(FPU_rm), control_word);
 }
 
 
@@ -114,7 +114,7 @@
 {
   /* fdiv st(i),st */
   clear_C1();
-  reg_div(&st(FPU_rm), FPU_st0_ptr, &st(FPU_rm), control_word);
+  reg_div(&st(FPU_rm), &st(0), &st(FPU_rm), control_word);
 }
 
 
@@ -123,7 +123,7 @@
 {
   /* faddp st(i),st */
   clear_C1();
-  if ( !reg_add(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm), control_word) )
+  if ( !reg_add(&st(0), &st(FPU_rm), &st(FPU_rm), control_word) )
     pop();
 }
 
@@ -132,7 +132,7 @@
 {
   /* fmulp st(i),st */
   clear_C1();
-  if ( !reg_mul(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm), control_word) )
+  if ( !reg_mul(&st(0), &st(FPU_rm), &st(FPU_rm), control_word) )
     pop();
 }
 
@@ -142,9 +142,9 @@
 {
   /* 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); */
+     reg_sub(&st(FPU_rm), &st(0), &st(FPU_rm), control_word); */
   clear_C1();
-  if ( !reg_sub(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm), control_word) )
+  if ( !reg_sub(&st(0), &st(FPU_rm), &st(FPU_rm), control_word) )
     pop();
 }
 
@@ -153,9 +153,9 @@
 {
   /* 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); */
+     reg_sub(&st(0), &st(FPU_rm), &st(FPU_rm), control_word); */
   clear_C1();
-  if ( !reg_sub(&st(FPU_rm), FPU_st0_ptr, &st(FPU_rm), control_word) )
+  if ( !reg_sub(&st(FPU_rm), &st(0), &st(FPU_rm), control_word) )
     pop();
 }
 
@@ -164,7 +164,7 @@
 {
   /* fdivrp st(i),st */
   clear_C1();
-  if ( !reg_div(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm), control_word) )
+  if ( !reg_div(&st(0), &st(FPU_rm), &st(FPU_rm), control_word) )
     pop();
 }
 
@@ -173,7 +173,7 @@
 {
   /* fdivp st(i),st */
   clear_C1();
-  if ( !reg_div(&st(FPU_rm), FPU_st0_ptr, &st(FPU_rm), control_word) )
+  if ( !reg_div(&st(FPU_rm), &st(0), &st(FPU_rm), control_word) )
     pop();
 }
 
diff -u --recursive --new-file v1.1.17/linux/drivers/FPU-emu/fpu_aux.c linux/drivers/FPU-emu/fpu_aux.c
--- v1.1.17/linux/drivers/FPU-emu/fpu_aux.c	Mon Feb  7 09:35:20 1994
+++ linux/drivers/FPU-emu/fpu_aux.c	Thu Jun  2 10:28:23 1994
@@ -26,8 +26,7 @@
   partial_status &= ~(SW_Backward|SW_Summary|SW_Stack_Fault|SW_Precision|
 		   SW_Underflow|SW_Overflow|SW_Zero_Div|SW_Denorm_Op|
 		   SW_Invalid);
-  NO_NET_DATA_EFFECT;
-  FPU_entry_eip = ip_offset;               /* We want no net effect */
+  no_ip_update = 1;
 }
 
 /* Needs to be externally visible */
@@ -43,11 +42,12 @@
     }
   /* The behaviour is different to that detailed in
      Section 15.1.6 of the Intel manual */
-  data_operand_offset = 0;
-  operand_selector = 0;
-  NO_NET_DATA_EFFECT;
-  FPU_entry_op_cs = 0;
-  FPU_entry_eip = ip_offset = 0;
+  operand_address.offset = 0;
+  operand_address.selector = 0;
+  instruction_address.offset = 0;
+  instruction_address.selector = 0;
+  instruction_address.opcode = 0;
+  no_ip_update = 1;
 }
 
 /*
@@ -71,7 +71,7 @@
 static void fstsw_ax(void)
 {
   *(short *) &FPU_EAX = status_word();
-  NO_NET_INSTR_EFFECT;
+  no_ip_update = 1;
 }
 
 static FUNC const fstsw_table[] = {
@@ -108,10 +108,9 @@
     { reg_move(&st(FPU_rm), st_new_ptr); push(); }
   else
     {
-      if ( control_word & EX_Invalid )
+      if ( control_word & CW_Invalid )
 	{
 	  /* The masked response */
-	  push();
 	  stack_underflow();
 	}
       else
@@ -125,9 +124,9 @@
 {
   /* fxch st(i) */
   FPU_REG t;
-  register FPU_REG *sti_ptr = &st(FPU_rm);
+  register FPU_REG *sti_ptr = &st(FPU_rm), *st0_ptr = &st(0);
 
-  if ( FPU_st0_tag == TW_Empty )
+  if ( st0_ptr->tag == TW_Empty )
     {
       if ( sti_ptr->tag == TW_Empty )
 	{
@@ -136,20 +135,20 @@
 	  return;
 	}
       if ( control_word & CW_Invalid )
-	reg_move(sti_ptr, FPU_st0_ptr);   /* Masked response */
+	reg_move(sti_ptr, st0_ptr);   /* Masked response */
       stack_underflow_i(FPU_rm);
       return;
     }
   if ( sti_ptr->tag == TW_Empty )
     {
       if ( control_word & CW_Invalid )
-	reg_move(FPU_st0_ptr, sti_ptr);   /* Masked response */
+	reg_move(st0_ptr, sti_ptr);   /* Masked response */
       stack_underflow();
       return;
     }
   clear_C1();
-  reg_move(FPU_st0_ptr, &t);
-  reg_move(sti_ptr, FPU_st0_ptr);
+  reg_move(st0_ptr, &t);
+  reg_move(sti_ptr, st0_ptr);
   reg_move(&t, sti_ptr);
 }
 
@@ -172,14 +171,14 @@
 void fst_i_()
 {
   /* fst st(i) */
-  reg_move(FPU_st0_ptr, &st(FPU_rm));
+  reg_move(&st(0), &st(FPU_rm));
 }
 
 
 void fstp_i()
 {
   /* fstp st(i) */
-  reg_move(FPU_st0_ptr, &st(FPU_rm));
+  reg_move(&st(0), &st(FPU_rm));
   pop();
 }
 
diff -u --recursive --new-file v1.1.17/linux/drivers/FPU-emu/fpu_emu.h linux/drivers/FPU-emu/fpu_emu.h
--- v1.1.17/linux/drivers/FPU-emu/fpu_emu.h	Tue May 24 00:34:46 1994
+++ linux/drivers/FPU-emu/fpu_emu.h	Thu Jun  2 10:28:23 1994
@@ -60,14 +60,18 @@
 #include <linux/math_emu.h>
 #include <linux/linkage.h>
 
-#ifdef PARANOID
+/*
+#define RE_ENTRANT_CHECKING
+ */
+
+#ifdef RE_ENTRANT_CHECKING
 extern char emulating;
 #  define RE_ENTRANT_CHECK_OFF emulating = 0
 #  define RE_ENTRANT_CHECK_ON emulating = 1
 #else
 #  define RE_ENTRANT_CHECK_OFF
 #  define RE_ENTRANT_CHECK_ON
-#endif PARANOID
+#endif RE_ENTRANT_CHECKING
 
 #define FWAIT_OPCODE 0x9b
 #define OP_SIZE_PREFIX 0x66
@@ -89,46 +93,43 @@
 #define PREFIX_SS_ 6
 #define PREFIX_DEFAULT 7
 
-/* These are to defeat the default action, giving the instruction
-   no net effect: */
-#define NO_NET_DATA_EFFECT \
-      { FPU_data_address = (void *)data_operand_offset; \
-	FPU_data_selector = operand_selector; }
-#define NO_NET_INSTR_EFFECT \
-      { FPU_entry_eip = ip_offset; \
-	FPU_entry_op_cs = cs_selector; }
-
-
+struct address {
+  unsigned int offset;
+  unsigned int selector:16;
+  unsigned int opcode:11;
+  unsigned int empty:5;
+};
 typedef void (*FUNC)(void);
 typedef struct fpu_reg FPU_REG;
+typedef void (*FUNC_ST0)(FPU_REG *st0_ptr);
 typedef struct { unsigned char address_size, operand_size, segment; }
         overrides;
-/* This structure is 48 bits: */
+/* This structure is 32 bits: */
 typedef struct { overrides override;
-		 unsigned char mode16, vm86, p286; } fpu_addr_modes;
+		 unsigned char default_mode; } fpu_addr_modes;
+/* PROTECTED has a restricted meaning in the emulator; it is used
+   to signal that the emulator needs to do special things to ensure
+   that protection is respected in a segmented model. */
+#define PROTECTED 4
+#define SIXTEEN   1         /* We rely upon this being 1 (true) */
+#define VM86      SIXTEEN
+#define PM16      (SIXTEEN | PROTECTED)
+#define SEG32     PROTECTED
+extern unsigned char const data_sizes_16[32];
 
 #define	st(x)	( regs[((top+x) &7 )] )
 
 #define	STACK_OVERFLOW	(st_new_ptr = &st(-1), st_new_ptr->tag != TW_Empty)
 #define	NOT_EMPTY(i)	(st(i).tag != TW_Empty)
-#define	NOT_EMPTY_0	(FPU_st0_tag ^ TW_Empty)
-
-extern unsigned char FPU_rm;
-
-extern	char	FPU_st0_tag;
-extern	FPU_REG	*FPU_st0_ptr;
-
-/* ###### These need to be shifted to somewhere safe. */
-/* extern void  *FPU_data_address; has been shifted */
-extern unsigned short FPU_data_selector;
-extern unsigned long FPU_entry_op_cs;
-
-extern  FPU_REG  FPU_loaded_data;
+#define	NOT_EMPTY_ST0	(st0_tag ^ TW_Empty)
 
-#define pop()	{ FPU_st0_ptr->tag = TW_Empty; top++; }
+#define pop()	{ regs[(top++ & 7 )].tag = TW_Empty; }
+#define poppop() { regs[((top + 1) & 7 )].tag \
+		     = regs[(top & 7 )].tag = TW_Empty; \
+		   top += 2; }
 
 /* push() does not affect the tags */
-#define push()	{ top--; FPU_st0_ptr = st_new_ptr; }
+#define push()	{ top--; }
 
 
 #define reg_move(x, y) { \
diff -u --recursive --new-file v1.1.17/linux/drivers/FPU-emu/fpu_entry.c linux/drivers/FPU-emu/fpu_entry.c
--- v1.1.17/linux/drivers/FPU-emu/fpu_entry.c	Tue May 24 00:34:46 1994
+++ linux/drivers/FPU-emu/fpu_entry.c	Thu Jun  2 10:28:24 1994
@@ -122,39 +122,36 @@
 #endif NO_UNDOC_CODE
 
 
-/* Be careful when using any of these global variables...
-   they might change if swapping is triggered */
-unsigned char  FPU_rm;
-char	       FPU_st0_tag;
-FPU_REG       *FPU_st0_ptr;
-
-/* ######## To be shifted */
-unsigned long FPU_entry_op_cs;
-unsigned short FPU_data_selector;
-
-
-#ifdef PARANOID
+#ifdef RE_ENTRANT_CHECKING
 char emulating=0;
-#endif PARANOID
+#endif RE_ENTRANT_CHECKING
 
 static int valid_prefix(unsigned char *Byte, unsigned char **fpu_eip,
 			overrides *override);
 
-
 asmlinkage void math_emulate(long arg)
 {
   unsigned char  FPU_modrm, byte1;
   unsigned short code;
   fpu_addr_modes addr_modes;
   int unmasked;
+  FPU_REG loaded_data;
+  void *data_address;
+  struct address data_sel_off;
+  struct address entry_sel_off;
+  unsigned long code_base = 0;
+  unsigned long code_limit = 0;  /* Initialized to stop compiler warnings */
+  char	       st0_tag;
+  FPU_REG      *st0_ptr;
+  struct desc_struct code_descriptor;
 
-#ifdef PARANOID
+#ifdef RE_ENTRANT_CHECKING
   if ( emulating )
     {
       printk("ERROR: wm-FPU-emu is not RE-ENTRANT!\n");
     }
   RE_ENTRANT_CHECK_ON;
-#endif PARANOID
+#endif RE_ENTRANT_CHECKING
 
   if (!current->used_math)
     {
@@ -172,34 +169,51 @@
 
   SETUP_DATA_AREA(arg);
 
-  addr_modes.vm86 = (FPU_EFLAGS & 0x00020000) != 0;
-  addr_modes.p286 = (!addr_modes.vm86
-		     && current->ldt
-		     && (current->ldt[FPU_CS >> 3].b & 0xf000) == 0xf000
-		     && (current->ldt[FPU_CS >> 3].b & (1 << 22)) == 0);
-  addr_modes.mode16 = addr_modes.vm86 | addr_modes.p286;
-
-  if ( addr_modes.vm86 )
-    FPU_EIP += FPU_CS << 4;
-  else if ( addr_modes.p286 )
-    FPU_EIP += LDT_BASE_ADDR(FPU_CS);
-
   FPU_ORIG_EIP = FPU_EIP;
 
-  if ( !addr_modes.mode16 )
+  if ( (FPU_EFLAGS & 0x00020000) != 0 )
+    {
+      /* Virtual 8086 mode */
+      addr_modes.default_mode = VM86;
+      FPU_EIP += code_base = FPU_CS << 4;
+      code_limit = code_base + 0xffff;  /* Assumes code_base <= 0xffff0000 */
+    }
+  else if ( FPU_CS == USER_CS && FPU_DS == USER_DS )
+    {
+      addr_modes.default_mode = 0;
+    }
+  else if ( FPU_CS == KERNEL_CS )
     {
-      /* user code space? */
-      if (FPU_CS == KERNEL_CS)
+      printk("math_emulate: %04x:%08lx\n",FPU_CS,FPU_EIP);
+      panic("Math emulation needed in kernel");
+    }
+  else
+    {
+
+      if ( (FPU_CS & 4) != 4 )   /* Must be in the LDT */
 	{
-	  printk("math_emulate: %04x:%08lx\n",FPU_CS,FPU_EIP);
-	  panic("Math emulation needed in kernel");
+	  /* Can only handle segmented addressing via the LDT
+	     for now, and it must be 16 bit */
+	  printk("FPU emulator: Unsupported addressing mode\n");
+	  math_abort(FPU_info, SIGILL);
 	}
 
-      /* We cannot handle multiple segments yet */
-      if (FPU_CS != USER_CS || FPU_DS != USER_DS)
+      if ( SEG_D_SIZE(code_descriptor = LDT_DESCRIPTOR(FPU_CS)) )
+	{
+	  /* The above test may be wrong, the book is not clear */
+	  /* Segmented 32 bit protected mode */
+	  addr_modes.default_mode = SEG32;
+	}
+      else
 	{
-	  math_abort(FPU_info,SIGILL);
+	  /* 16 bit protected mode */
+	  addr_modes.default_mode = PM16;
 	}
+      FPU_EIP += code_base = SEG_BASE_ADDR(code_descriptor);
+      code_limit = code_base
+	+ (SEG_LIMIT(code_descriptor)+1) * SEG_GRANULARITY(code_descriptor)
+	  - 1;
+      if ( code_limit < code_base ) code_limit = 0xffffffff;
     }
 
   FPU_lookahead = 1;
@@ -220,14 +234,17 @@
 
 do_another_FPU_instruction:
 
+  no_ip_update = 0;
+
   FPU_EIP++;  /* We have fetched the prefix and first code bytes. */
 
-#ifdef PECULIAR_486
-  /* It would be more logical to do this only in get_address(),
-     but although it is supposed to be undefined for many fpu
-     instructions, an 80486 behaves as if this were done here: */
-  FPU_data_selector = FPU_DS;
-#endif PECULIAR_486
+  if ( addr_modes.default_mode )
+    {
+      /* This checks for the minimum instruction bytes.
+	 We also need to check any extra (address mode) code access. */
+      if ( FPU_EIP > code_limit )
+	math_abort(FPU_info,SIGSEGV);
+    }
 
   if ( (byte1 & 0xf8) != 0xd8 )
     {
@@ -273,9 +290,8 @@
 	   *  via the cs selector and operand selector, so we do the same.
 	   */
 	do_the_FPU_interrupt:
-	  cs_selector &= 0xffff0000;
-	  cs_selector |= status_word();
-      	  operand_selector = tag_word();
+	  instruction_address.selector = status_word();
+      	  operand_address.selector = tag_word();
 	  partial_status = 0;
 	  top = 0;
 	  {
@@ -288,11 +304,6 @@
 
 	  FPU_EIP = FPU_ORIG_EIP;	/* Point to current FPU instruction. */
 
-	  if ( addr_modes.vm86 )
-	    FPU_EIP -= FPU_CS << 4;
-	  else if ( addr_modes.p286 )
-	    FPU_EIP -= LDT_BASE_ADDR(FPU_CS);
-
 	  RE_ENTRANT_CHECK_OFF;
 	  current->tss.trap_no = 16;
 	  current->tss.error_code = 0;
@@ -301,57 +312,74 @@
 	}
     }
 
-  FPU_entry_eip = FPU_ORIG_EIP;
-
-  FPU_entry_op_cs = (byte1 << 24) | (FPU_modrm << 16) | (FPU_CS & 0xffff) ;
+  entry_sel_off.offset = FPU_ORIG_EIP;
+  entry_sel_off.selector = FPU_CS;
+  entry_sel_off.opcode = (byte1 << 8) | FPU_modrm;
 
   FPU_rm = FPU_modrm & 7;
 
   if ( FPU_modrm < 0300 )
     {
       /* All of these instructions use the mod/rm byte to get a data address */
-      if ( addr_modes.vm86
+
+      if ( (addr_modes.default_mode & SIXTEEN)
 	  ^ (addr_modes.override.address_size == ADDR_SIZE_PREFIX) )
-	get_address_16(FPU_modrm, &FPU_EIP, addr_modes);
+	data_address = get_address_16(FPU_modrm, &FPU_EIP, &data_sel_off,
+				      addr_modes);
       else
-	get_address(FPU_modrm, &FPU_EIP, addr_modes);
+	data_address = get_address(FPU_modrm, &FPU_EIP, &data_sel_off,
+				   addr_modes);
+
+      if ( addr_modes.default_mode )
+	{
+	  if ( FPU_EIP-1 > code_limit )
+	    math_abort(FPU_info,SIGSEGV);
+	}
 
       if ( !(byte1 & 1) )
 	{
 	  unsigned short status1 = partial_status;
-	  FPU_st0_ptr = &st(0);
-	  FPU_st0_tag = FPU_st0_ptr->tag;
+
+	  st0_ptr = &st(0);
+	  st0_tag = st0_ptr->tag;
 
 	  /* Stack underflow has priority */
-	  if ( NOT_EMPTY_0 )
+	  if ( NOT_EMPTY_ST0 )
 	    {
+	      if ( addr_modes.default_mode & PROTECTED )
+		{
+		  /* This table works for 16 and 32 bit protected mode */
+		  if ( access_limit < data_sizes_16[(byte1 >> 1) & 3] )
+		    math_abort(FPU_info,SIGSEGV);
+		}
+
 	      unmasked = 0;  /* Do this here to stop compiler warnings. */
 	      switch ( (byte1 >> 1) & 3 )
 		{
 		case 0:
-		  unmasked = reg_load_single();
+		  unmasked = reg_load_single((float *)data_address,
+					     &loaded_data);
 		  break;
 		case 1:
-		  reg_load_int32();
+		  reg_load_int32((long *)data_address, &loaded_data);
 		  break;
 		case 2:
-		  unmasked = reg_load_double();
+		  unmasked = reg_load_double((double *)data_address,
+					     &loaded_data);
 		  break;
 		case 3:
-		  reg_load_int16();
+		  reg_load_int16((short *)data_address, &loaded_data);
 		  break;
 		}
 	      
 	      /* No more access to user memory, it is safe
 		 to use static data now */
-	      FPU_st0_ptr = &st(0);
-	      FPU_st0_tag = FPU_st0_ptr->tag;
 
 	      /* NaN operands have the next priority. */
 	      /* We have to delay looking at st(0) until after
 		 loading the data, because that data might contain an SNaN */
-	      if ( (FPU_st0_tag == TW_NaN) ||
-		  (FPU_loaded_data.tag == TW_NaN) )
+	      if ( (st0_tag == TW_NaN) ||
+		  (loaded_data.tag == TW_NaN) )
 		{
 		  /* Restore the status word; we might have loaded a
 		     denormal. */
@@ -371,13 +399,13 @@
 			 identical to an 80486 */
 		      if ( (FPU_modrm & 0x28) == 0x20 )
 			/* fdiv or fsub */
-			real_2op_NaN(&FPU_loaded_data, FPU_st0_ptr,
-				     FPU_st0_ptr);
+			real_2op_NaN(&loaded_data, st0_ptr,
+				     st0_ptr);
 		      else
 #endif PECULIAR_486
 			/* fadd, fdivr, fmul, or fsubr */
-			real_2op_NaN(FPU_st0_ptr, &FPU_loaded_data,
-				     FPU_st0_ptr);
+			real_2op_NaN(st0_ptr, &loaded_data,
+				     st0_ptr);
 		    }
 		  goto reg_mem_instr_done;
 		}
@@ -388,11 +416,11 @@
 		  if ( (FPU_modrm & 0x38) == 0x38 )
 		    {
 		      /* fdivr */
-		      if ( (FPU_st0_tag == TW_Zero) &&
-			  (FPU_loaded_data.tag == TW_Valid) )
+		      if ( (st0_tag == TW_Zero) &&
+			  (loaded_data.tag == TW_Valid) )
 			{
-			  if ( divide_by_zero(FPU_loaded_data.sign,
-					      FPU_st0_ptr) )
+			  if ( divide_by_zero(loaded_data.sign,
+					      st0_ptr) )
 			    {
 			      /* We use the fact here that the unmasked
 				 exception in the loaded data was for a
@@ -410,42 +438,42 @@
 		{
 		case 0:         /* fadd */
 		  clear_C1();
-		  reg_add(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr,
+		  reg_add(st0_ptr, &loaded_data, st0_ptr,
 			  control_word);
 		  break;
 		case 1:         /* fmul */
 		  clear_C1();
-		  reg_mul(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr,
+		  reg_mul(st0_ptr, &loaded_data, st0_ptr,
 			  control_word);
 		  break;
 		case 2:         /* fcom */
-		  compare_st_data();
+		  compare_st_data(&loaded_data);
 		  break;
 		case 3:         /* fcomp */
-		  if ( !compare_st_data() && !unmasked )
+		  if ( !compare_st_data(&loaded_data) && !unmasked )
 		    pop();
 		  break;
 		case 4:         /* fsub */
 		  clear_C1();
-		  reg_sub(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr,
+		  reg_sub(st0_ptr, &loaded_data, st0_ptr,
 			  control_word);
 		  break;
 		case 5:         /* fsubr */
 		  clear_C1();
-		  reg_sub(&FPU_loaded_data, FPU_st0_ptr, FPU_st0_ptr,
+		  reg_sub(&loaded_data, st0_ptr, st0_ptr,
 			  control_word);
 		  break;
 		case 6:         /* fdiv */
 		  clear_C1();
-		  reg_div(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr,
+		  reg_div(st0_ptr, &loaded_data, st0_ptr,
 			  control_word);
 		  break;
 		case 7:         /* fdivr */
 		  clear_C1();
-		  if ( FPU_st0_tag == TW_Zero )
+		  if ( st0_tag == TW_Zero )
 		    partial_status = status1;  /* Undo any denorm tag,
 					       zero-divide has priority. */
-		  reg_div(&FPU_loaded_data, FPU_st0_ptr, FPU_st0_ptr,
+		  reg_div(&loaded_data, st0_ptr, st0_ptr,
 			  control_word);
 		  break;
 		}
@@ -463,19 +491,19 @@
 	      else
 		stack_underflow();
 	    }
+	reg_mem_instr_done:
+	  operand_address = data_sel_off;
 	}
       else
 	{
-	  load_store_instr(((FPU_modrm & 0x38) | (byte1 & 6)) >> 1,
-			   addr_modes);
+	  if ( !(no_ip_update =
+		 load_store_instr(((FPU_modrm & 0x38) | (byte1 & 6)) >> 1,
+				  addr_modes, data_address)) )
+	    {
+	      operand_address = data_sel_off;
+	    }
 	}
 
-    reg_mem_instr_done:
-
-#ifndef PECULIAR_486
-      *(unsigned short *)&operand_selector = FPU_data_selector;
-#endif PECULIAR_486
-      ;
     }
   else
     {
@@ -485,38 +513,39 @@
 #ifdef PECULIAR_486
       /* This is supposed to be undefined, but a real 80486 seems
 	 to do this: */
-      FPU_data_address = 0;
+      operand_address.offset = 0;
+      operand_address.selector = FPU_DS;
 #endif PECULIAR_486
 
-      FPU_st0_ptr = &st(0);
-      FPU_st0_tag = FPU_st0_ptr->tag;
+      st0_ptr = &st(0);
+      st0_tag = st0_ptr->tag;
       switch ( type_table[(int) instr_index] )
 	{
 	case _NONE_:   /* also _REGIc: _REGIn */
 	  break;
 	case _REG0_:
-	  if ( !NOT_EMPTY_0 )
+	  if ( !NOT_EMPTY_ST0 )
 	    {
 	      stack_underflow();
 	      goto FPU_instruction_done;
 	    }
 	  break;
 	case _REGIi:
-	  if ( !NOT_EMPTY_0 || !NOT_EMPTY(FPU_rm) )
+	  if ( !NOT_EMPTY_ST0 || !NOT_EMPTY(FPU_rm) )
 	    {
 	      stack_underflow_i(FPU_rm);
 	      goto FPU_instruction_done;
 	    }
 	  break;
 	case _REGIp:
-	  if ( !NOT_EMPTY_0 || !NOT_EMPTY(FPU_rm) )
+	  if ( !NOT_EMPTY_ST0 || !NOT_EMPTY(FPU_rm) )
 	    {
 	      stack_underflow_pop(FPU_rm);
 	      goto FPU_instruction_done;
 	    }
 	  break;
 	case _REGI_:
-	  if ( !NOT_EMPTY_0 || !NOT_EMPTY(FPU_rm) )
+	  if ( !NOT_EMPTY_ST0 || !NOT_EMPTY(FPU_rm) )
 	    {
 	      stack_underflow();
 	      goto FPU_instruction_done;
@@ -532,17 +561,14 @@
 	  goto FPU_instruction_done;
 	}
       (*st_instr_table[(int) instr_index])();
-    }
 
 FPU_instruction_done:
+      ;
+    }
 
-  ip_offset = FPU_entry_eip;
-  cs_selector = FPU_entry_op_cs;
-  data_operand_offset = (unsigned long)FPU_data_address;
-#ifdef PECULIAR_486
-  *(unsigned short *)&operand_selector = FPU_data_selector;
-#endif PECULIAR_486
-  
+  if ( ! no_ip_update )
+    instruction_address = entry_sel_off;
+
 FPU_fwait_done:
 
 #ifdef DEBUG
@@ -553,16 +579,14 @@
 
   if (FPU_lookahead && !need_resched)
     {
-      FPU_ORIG_EIP = FPU_EIP;
+      FPU_ORIG_EIP = FPU_EIP - code_base;
       if ( valid_prefix(&byte1, (unsigned char **)&FPU_EIP,
 			&addr_modes.override) )
 	goto do_another_FPU_instruction;
     }
 
-  if ( addr_modes.vm86 )
-    FPU_EIP -= FPU_CS << 4;
-  else if ( addr_modes.p286 )
-    FPU_EIP -= LDT_BASE_ADDR(FPU_CS);
+  if ( addr_modes.default_mode )
+    FPU_EIP -= code_base;
 
   RE_ENTRANT_CHECK_OFF;
 }
diff -u --recursive --new-file v1.1.17/linux/drivers/FPU-emu/fpu_etc.c linux/drivers/FPU-emu/fpu_etc.c
--- v1.1.17/linux/drivers/FPU-emu/fpu_etc.c	Thu Feb  3 12:11:38 1994
+++ linux/drivers/FPU-emu/fpu_etc.c	Thu Jun  2 10:28:24 1994
@@ -17,22 +17,22 @@
 #include "reg_constant.h"
 
 
-static void fchs(void)
+static void fchs(FPU_REG *st0_ptr)
 {
-  if ( NOT_EMPTY_0 )
+  if ( st0_ptr->tag ^ TW_Empty )
     {
-      FPU_st0_ptr->sign ^= SIGN_POS^SIGN_NEG;
+      st0_ptr->sign ^= SIGN_POS^SIGN_NEG;
       clear_C1();
     }
   else
     stack_underflow();
 }
 
-static void fabs(void)
+static void fabs(FPU_REG *st0_ptr)
 {
-  if ( FPU_st0_tag ^ TW_Empty )
+  if ( st0_ptr->tag ^ TW_Empty )
     {
-      FPU_st0_ptr->sign = SIGN_POS;
+      st0_ptr->sign = SIGN_POS;
       clear_C1();
     }
   else
@@ -40,25 +40,25 @@
 }
 
 
-static void ftst_(void)
+static void ftst_(FPU_REG *st0_ptr)
 {
-  switch (FPU_st0_tag)
+  switch (st0_ptr->tag)
     {
     case TW_Zero:
       setcc(SW_C3);
       break;
     case TW_Valid:
-      if (FPU_st0_ptr->sign == SIGN_POS)
+      if (st0_ptr->sign == SIGN_POS)
         setcc(0);
       else
         setcc(SW_C0);
 
 #ifdef DENORM_OPERAND
-      if ( (FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
+      if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
 	{
 #ifdef PECULIAR_486
 	  /* This is wierd! */
-	  if (FPU_st0_ptr->sign == SIGN_POS)
+	  if (st0_ptr->sign == SIGN_POS)
 	    setcc(SW_C3);
 #endif PECULIAR_486
 	  return;
@@ -71,7 +71,7 @@
       EXCEPTION(EX_Invalid);
       break;
     case TW_Infinity:
-      if (FPU_st0_ptr->sign == SIGN_POS)
+      if (st0_ptr->sign == SIGN_POS)
         setcc(0);
       else
         setcc(SW_C0);
@@ -87,10 +87,10 @@
     }
 }
 
-static void fxam(void)
+static void fxam(FPU_REG *st0_ptr)
 {
   int c=0;
-  switch (FPU_st0_tag)
+  switch (st0_ptr->tag)
     {
     case TW_Empty:
       c = SW_C3|SW_C0;
@@ -100,7 +100,7 @@
       break;
     case TW_Valid:
       /* This will need to be changed if TW_Denormal is ever used. */
-      if ( FPU_st0_ptr->exp <= EXP_UNDER )
+      if ( st0_ptr->exp <= EXP_UNDER )
         c = SW_C2|SW_C3;  /* Denormal */
       else
         c = SW_C2;
@@ -112,16 +112,18 @@
       c = SW_C2|SW_C0;
       break;
     }
-  if (FPU_st0_ptr->sign == SIGN_NEG)
+  if (st0_ptr->sign == SIGN_NEG)
     c |= SW_C1;
   setcc(c);
 }
 
-static FUNC const fp_etc_table[] = {
-  fchs, fabs, FPU_illegal, FPU_illegal, ftst_, fxam, FPU_illegal, FPU_illegal
+
+static FUNC_ST0 const fp_etc_table[] = {
+  fchs, fabs, (FUNC_ST0)FPU_illegal, (FUNC_ST0)FPU_illegal,
+  ftst_, fxam, (FUNC_ST0)FPU_illegal, (FUNC_ST0)FPU_illegal
 };
 
 void fp_etc()
 {
-  (fp_etc_table[FPU_rm])();
+  (fp_etc_table[FPU_rm])(&st(0));
 }
diff -u --recursive --new-file v1.1.17/linux/drivers/FPU-emu/fpu_proto.h linux/drivers/FPU-emu/fpu_proto.h
--- v1.1.17/linux/drivers/FPU-emu/fpu_proto.h	Wed Feb 16 13:07:56 1994
+++ linux/drivers/FPU-emu/fpu_proto.h	Thu Jun  2 10:28:24 1994
@@ -63,13 +63,16 @@
 extern void trig_b(void);
 
 /* get_address.c */
-extern void get_address(unsigned char FPU_modrm, unsigned long *fpu_eip,
-			fpu_addr_modes);
-extern void get_address_16(unsigned char FPU_modrm, unsigned long *fpu_eip,
-			   fpu_addr_modes);
+extern void *get_address(unsigned char FPU_modrm, unsigned long *fpu_eip,
+			 struct address *addr,
+			 fpu_addr_modes);
+extern void *get_address_16(unsigned char FPU_modrm, unsigned long *fpu_eip,
+			    struct address *addr,
+			    fpu_addr_modes);
 
 /* load_store.c */
-extern void load_store_instr(char type, fpu_addr_modes addr_modes);
+extern int load_store_instr(unsigned char type, fpu_addr_modes addr_modes,
+			     void *address);
 
 /* poly_2xm1.c */
 extern int poly_2xm1(FPU_REG const *arg, FPU_REG *result);
@@ -96,7 +99,7 @@
 
 /* reg_compare.c */
 extern int compare(FPU_REG const *b);
-extern int compare_st_data(void);
+extern int compare_st_data(FPU_REG const *b);
 extern void fcom_st(void);
 extern void fcompst(void);
 extern void fcompp(void);
@@ -108,26 +111,26 @@
 extern void fconst(void);
 
 /* reg_ld_str.c */
-extern int reg_load_extended(void);
-extern int reg_load_double(void);
-extern int reg_load_single(void);
-extern void reg_load_int64(void);
-extern void reg_load_int32(void);
-extern void reg_load_int16(void);
-extern void reg_load_bcd(void);
-extern int reg_store_extended(void);
-extern int reg_store_double(void);
-extern int reg_store_single(void);
-extern int reg_store_int64(void);
-extern int reg_store_int32(void);
-extern int reg_store_int16(void);
-extern int reg_store_bcd(void);
+extern int reg_load_extended(long double *addr, FPU_REG *loaded_data);
+extern int reg_load_double(double *dfloat, FPU_REG *loaded_data);
+extern int reg_load_single(float *single, FPU_REG *loaded_data);
+extern void reg_load_int64(long long *_s, FPU_REG *loaded_data);
+extern void reg_load_int32(long *_s, FPU_REG *loaded_data);
+extern void reg_load_int16(short *_s, FPU_REG *loaded_data);
+extern void reg_load_bcd(char *s, FPU_REG *loaded_data);
+extern int reg_store_extended(long double *d, FPU_REG *st0_ptr);
+extern int reg_store_double(double *dfloat, FPU_REG *st0_ptr);
+extern int reg_store_single(float *single, FPU_REG *st0_ptr);
+extern int reg_store_int64(long long *d, FPU_REG *st0_ptr);
+extern int reg_store_int32(long *d, FPU_REG *st0_ptr);
+extern int reg_store_int16(short *d, FPU_REG *st0_ptr);
+extern int reg_store_bcd(char *d, FPU_REG *st0_ptr);
 extern int round_to_int(FPU_REG *r);
-extern char *fldenv(fpu_addr_modes addr_modes);
-extern void frstor(fpu_addr_modes addr_modes);
+extern char *fldenv(fpu_addr_modes addr_modes, char *address);
+extern void frstor(fpu_addr_modes addr_modes, char *address);
 extern unsigned short tag_word(void);
-extern char *fstenv(fpu_addr_modes addr_modes);
-extern void fsave(fpu_addr_modes addr_modes);
+extern char *fstenv(fpu_addr_modes addr_modes, char *address);
+extern void fsave(fpu_addr_modes addr_modes, char *address);
 
 /* reg_mul.c */
 extern int reg_mul(FPU_REG const *a, FPU_REG const *b,
diff -u --recursive --new-file v1.1.17/linux/drivers/FPU-emu/fpu_system.h linux/drivers/FPU-emu/fpu_system.h
--- v1.1.17/linux/drivers/FPU-emu/fpu_system.h	Tue May 24 00:34:46 1994
+++ linux/drivers/FPU-emu/fpu_system.h	Thu Jun  2 10:28:24 1994
@@ -19,6 +19,19 @@
    of the stack frame of math_emulate() */
 #define SETUP_DATA_AREA(arg)    FPU_info = (struct info *) &arg
 
+#define LDT_DESCRIPTOR(s)       (current->ldt[(s) >> 3])
+#define SEG_D_SIZE(x)           ((x).b & (3 << 21))
+#define SEG_G_BIT(x)            ((x).b & (1 << 23))
+#define SEG_GRANULARITY(x)      (((x).b & (1 << 23)) ? 4096 : 1)
+#define SEG_286_MODE(x)         ((x).b & ( 0xff000000 | 0xf0000 | (1 << 23)))
+#define SEG_BASE_ADDR(s)        (((s).b & 0xff000000) \
+				 | (((s).b & 0xff) << 16) | ((s).a >> 16))
+#define SEG_LIMIT(s)            (((s).b & 0xff0000) | ((s).a & 0xffff))
+#define SEG_EXECUTE_ONLY(s)     (((s).b & ((1 << 11) | (1 << 9))) == (1 << 11))
+#define SEG_WRITE_PERM(s)       (((s).b & ((1 << 11) | (1 << 9))) == (1 << 9))
+#define SEG_EXPAND_DOWN(s)      (((s).b & ((1 << 11) | (1 << 10))) \
+				 == (1 << 10))
+
 #define I387			(current->tss.i387)
 #define FPU_info		(I387.soft.info)
 
@@ -30,22 +43,24 @@
 #define FPU_EIP			(FPU_info->___eip)
 #define FPU_ORIG_EIP		(FPU_info->___orig_eip)
 
-#define LDT_BASE_ADDR(s)	((current->ldt[(s) >> 3].b & 0xff000000)     \
-				 | ((current->ldt[(s) >> 3].b & 0xff) << 16) \
-				 | (current->ldt[(s) >> 3].a >> 16))
-
 #define FPU_lookahead           (I387.soft.lookahead)
-#define FPU_entry_eip           (I387.soft.entry_eip)
 
+/* nz if ip_offset and cs_selector are not to be set for the current
+   instruction. */
+#define no_ip_update            (((char *)&(I387.soft.twd))[0])
+#define FPU_rm                  (((unsigned char *)&(I387.soft.twd))[1])
+
+/* Number of bytes of data which can be legally accessed by the current
+   instruction. This only needs to hold a number <= 108, so a byte will do. */
+#define access_limit            (((unsigned char *)&(I387.soft.twd))[2])
+
 #define partial_status       	(I387.soft.swd)
 #define control_word		(I387.soft.cwd)
 #define regs			(I387.soft.regs)
 #define top			(I387.soft.top)
 
-#define ip_offset		(I387.soft.fip)
-#define cs_selector		(I387.soft.fcs)
-#define data_operand_offset	(I387.soft.foo)
-#define operand_selector	(I387.soft.fos)
+#define instruction_address     (*(struct address *)&I387.soft.fip)
+#define operand_address         (*(struct address *)&I387.soft.foo)
 
 #define FPU_verify_area(x,y,z)  if ( verify_area(x,y,z) ) \
                                 math_abort(FPU_info,SIGSEGV)
@@ -63,8 +78,5 @@
    past the upper boundary of a legal code area. */
 #define	FPU_code_verify_area(z) FPU_verify_area(VERIFY_READ,(void *)FPU_EIP,z)
 #endif
-
-/* ######## temporary and ugly ;-) */
-#define FPU_data_address        ((void *)(I387.soft.twd))
 
 #endif
diff -u --recursive --new-file v1.1.17/linux/drivers/FPU-emu/fpu_trig.c linux/drivers/FPU-emu/fpu_trig.c
--- v1.1.17/linux/drivers/FPU-emu/fpu_trig.c	Tue Jan 11 11:10:49 1994
+++ linux/drivers/FPU-emu/fpu_trig.c	Thu Jun  2 10:28:26 1994
@@ -166,16 +166,16 @@
 }
 
 
-static void single_arg_error(void)
+static void single_arg_error(FPU_REG *st0_ptr)
 {
-  switch ( FPU_st0_tag )
+  switch ( st0_ptr->tag )
     {
     case TW_NaN:
-      if ( !(FPU_st0_ptr->sigh & 0x40000000) )   /* Signaling ? */
+      if ( !(st0_ptr->sigh & 0x40000000) )   /* Signaling ? */
 	{
 	  EXCEPTION(EX_Invalid);
 	  if ( control_word & CW_Invalid )
-	    FPU_st0_ptr->sigh |= 0x40000000;	  /* Convert to a QNaN */
+	    st0_ptr->sigh |= 0x40000000;	  /* Convert to a QNaN */
 	}
       break;              /* return with a NaN in st(0) */
     case TW_Empty:
@@ -189,24 +189,24 @@
 }
 
 
-static void single_arg_2_error(void)
+static void single_arg_2_error(FPU_REG *st0_ptr)
 {
   FPU_REG *st_new_ptr;
 
-  switch ( FPU_st0_tag )
+  switch ( st0_ptr->tag )
     {
     case TW_NaN:
-      if ( !(FPU_st0_ptr->sigh & 0x40000000) )   /* Signaling ? */
+      if ( !(st0_ptr->sigh & 0x40000000) )   /* Signaling ? */
 	{
 	  EXCEPTION(EX_Invalid);
 	  if ( control_word & CW_Invalid )
 	    {
 	      /* The masked response */
 	      /* Convert to a QNaN */
-	      FPU_st0_ptr->sigh |= 0x40000000;
+	      st0_ptr->sigh |= 0x40000000;
 	      st_new_ptr = &st(-1);
 	      push();
-	      reg_move(&st(1), FPU_st0_ptr);
+	      reg_move(&st(1), st_new_ptr);
 	    }
 	}
       else
@@ -214,7 +214,7 @@
 	  /* A QNaN */
 	  st_new_ptr = &st(-1);
 	  push();
-	  reg_move(&st(1), FPU_st0_ptr);
+	  reg_move(&st(1), st_new_ptr);
 	}
       break;              /* return with a NaN in st(0) */
 #ifdef PARANOID
@@ -227,48 +227,48 @@
 
 /*---------------------------------------------------------------------------*/
 
-static void f2xm1(void)
+static void f2xm1(FPU_REG *st0_ptr)
 {
   clear_C1();
-  switch ( FPU_st0_tag )
+  switch ( st0_ptr->tag )
     {
     case TW_Valid:
       {
 	FPU_REG rv, tmp;
 
-	if ( FPU_st0_ptr->exp >= 0 )
+	if ( st0_ptr->exp >= 0 )
 	  {
 	    /* For an 80486 FPU, the result is undefined. */
 	  }
-	else if ( FPU_st0_ptr->exp >= -64 )
+	else if ( st0_ptr->exp >= -64 )
 	  {
-	    if ( FPU_st0_ptr->sign == SIGN_POS )
+	    if ( st0_ptr->sign == SIGN_POS )
 	      {
 		/* poly_2xm1(x) requires 0 < x < 1. */
-		poly_2xm1(FPU_st0_ptr, &rv);
-		reg_mul(&rv, FPU_st0_ptr, FPU_st0_ptr, FULL_PRECISION);
+		poly_2xm1(st0_ptr, &rv);
+		reg_mul(&rv, st0_ptr, st0_ptr, FULL_PRECISION);
 	      }
 	    else
 	      {
 		/* poly_2xm1(x) doesn't handle negative numbers yet. */
 		/* So we compute z=poly_2xm1(-x), and the answer is
 		   then -z/(1+z) */
-		FPU_st0_ptr->sign = SIGN_POS;
-		poly_2xm1(FPU_st0_ptr, &rv);
-		reg_mul(&rv, FPU_st0_ptr, &rv, FULL_PRECISION);
+		st0_ptr->sign = SIGN_POS;
+		poly_2xm1(st0_ptr, &rv);
+		reg_mul(&rv, st0_ptr, &rv, FULL_PRECISION);
 		reg_add(&rv, &CONST_1, &tmp, FULL_PRECISION);
-		reg_div(&rv, &tmp, FPU_st0_ptr, FULL_PRECISION);
-		FPU_st0_ptr->sign = SIGN_NEG;
+		reg_div(&rv, &tmp, st0_ptr, FULL_PRECISION);
+		st0_ptr->sign = SIGN_NEG;
 	      }
 	  }
 	else
 	  {
 #ifdef DENORM_OPERAND
-	    if ( (FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
+	    if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
 	      return;
 #endif DENORM_OPERAND
 	    /* For very small arguments, this is accurate enough. */
-	    reg_mul(&CONST_LN2, FPU_st0_ptr, FPU_st0_ptr, FULL_PRECISION);
+	    reg_mul(&CONST_LN2, st0_ptr, st0_ptr, FULL_PRECISION);
 	  }
 	set_precision_flag_up();
 	return;
@@ -276,27 +276,28 @@
     case TW_Zero:
       return;
     case TW_Infinity:
-      if ( FPU_st0_ptr->sign == SIGN_NEG )
+      if ( st0_ptr->sign == SIGN_NEG )
 	{
 	  /* -infinity gives -1 (p16-10) */
-	  reg_move(&CONST_1, FPU_st0_ptr);
-	  FPU_st0_ptr->sign = SIGN_NEG;
+	  reg_move(&CONST_1, st0_ptr);
+	  st0_ptr->sign = SIGN_NEG;
 	}
       return;
     default:
-      single_arg_error();
+      single_arg_error(st0_ptr);
     }
 }
 
 
-static void fptan(void)
+static void fptan(FPU_REG *st0_ptr)
 {
+  char st0_tag = st0_ptr->tag;
   FPU_REG *st_new_ptr;
   int q;
-  char arg_sign = FPU_st0_ptr->sign;
+  char arg_sign = st0_ptr->sign;
 
   /* Stack underflow has higher priority */
-  if ( FPU_st0_tag == TW_Empty )
+  if ( st0_tag == TW_Empty )
     {
       stack_underflow();  /* Puts a QNaN in st(0) */
       if ( control_word & CW_Invalid )
@@ -311,24 +312,24 @@
   if ( STACK_OVERFLOW )
     { stack_overflow(); return; }
 
-  switch ( FPU_st0_tag )
+  switch ( st0_tag )
     {
     case TW_Valid:
 
-      if ( FPU_st0_ptr->exp > EXP_BIAS - 40 )
+      if ( st0_ptr->exp > EXP_BIAS - 40 )
 	{
-	  FPU_st0_ptr->sign = SIGN_POS;
-	  if ( (q = trig_arg(FPU_st0_ptr, FPTAN)) != -1 )
+	  st0_ptr->sign = SIGN_POS;
+	  if ( (q = trig_arg(st0_ptr, FPTAN)) != -1 )
 	    {
-	      reg_div(FPU_st0_ptr, &CONST_PI2, FPU_st0_ptr,
+	      reg_div(st0_ptr, &CONST_PI2, st0_ptr,
 		      FULL_PRECISION);
-	      poly_tan(FPU_st0_ptr, FPU_st0_ptr, q & FCOS);
-	      FPU_st0_ptr->sign = (q & 1) ^ arg_sign;
+	      poly_tan(st0_ptr, st0_ptr, q & FCOS);
+	      st0_ptr->sign = (q & 1) ^ arg_sign;
 	    }
 	  else
 	    {
 	      /* Operand is out of range */
-	      FPU_st0_ptr->sign = arg_sign;         /* restore st(0) */
+	      st0_ptr->sign = arg_sign;         /* restore st(0) */
 	      return;
 	    }
 	}
@@ -337,7 +338,7 @@
 	  /* For a small arg, the result == the argument */
 	  /* Underflow may happen */
 
-	  if ( FPU_st0_ptr->exp <= EXP_UNDER )
+	  if ( st0_ptr->exp <= EXP_UNDER )
 	    {
 #ifdef DENORM_OPERAND
 	      if ( denormal_operand() )
@@ -346,90 +347,91 @@
 	      /* A denormal result has been produced.
 		 Precision must have been lost, this is always
 		 an underflow. */
-	      if ( arith_underflow(FPU_st0_ptr) )
+	      if ( arith_underflow(st0_ptr) )
 		return;
 	    }
 	  else
 	    set_precision_flag_up();  /* Must be up. */
 	}
       push();
-      reg_move(&CONST_1, FPU_st0_ptr);
+      reg_move(&CONST_1, st_new_ptr);
       return;
       break;
     case TW_Infinity:
       /* The 80486 treats infinity as an invalid operand */
-      arith_invalid(FPU_st0_ptr);
+      arith_invalid(st0_ptr);
       if ( control_word & CW_Invalid )
 	{
 	  st_new_ptr = &st(-1);
 	  push();
-	  arith_invalid(FPU_st0_ptr);
+	  arith_invalid(st_new_ptr);
 	}
       return;
     case TW_Zero:
       push();
-      reg_move(&CONST_1, FPU_st0_ptr);
+      reg_move(&CONST_1, st_new_ptr);
       setcc(0);
       break;
     default:
-      single_arg_2_error();
+      single_arg_2_error(st0_ptr);
       break;
     }
 }
 
 
-static void fxtract(void)
+static void fxtract(FPU_REG *st0_ptr)
 {
+  char st0_tag = st0_ptr->tag;
   FPU_REG *st_new_ptr;
-  register FPU_REG *st1_ptr = FPU_st0_ptr;  /* anticipate */
+  register FPU_REG *st1_ptr = st0_ptr;  /* anticipate */
 
   if ( STACK_OVERFLOW )
     {  stack_overflow(); return; }
   clear_C1();
-  if ( !(FPU_st0_tag ^ TW_Valid) )
+  if ( !(st0_tag ^ TW_Valid) )
     {
       long e;
 
 #ifdef DENORM_OPERAND
-      if ( (FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
+      if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
 	return;
 #endif DENORM_OPERAND
 	  
       push();
-      reg_move(st1_ptr, FPU_st0_ptr);
-      FPU_st0_ptr->exp = EXP_BIAS;
+      reg_move(st1_ptr, st_new_ptr);
+      st_new_ptr->exp = EXP_BIAS;
       e = st1_ptr->exp - EXP_BIAS;
       convert_l2reg(&e, st1_ptr);
       return;
     }
-  else if ( FPU_st0_tag == TW_Zero )
+  else if ( st0_tag == TW_Zero )
     {
-      char sign = FPU_st0_ptr->sign;
-      if ( divide_by_zero(SIGN_NEG, FPU_st0_ptr) )
+      char sign = st0_ptr->sign;
+      if ( divide_by_zero(SIGN_NEG, st0_ptr) )
 	return;
       push();
-      reg_move(&CONST_Z, FPU_st0_ptr);
-      FPU_st0_ptr->sign = sign;
+      reg_move(&CONST_Z, st_new_ptr);
+      st_new_ptr->sign = sign;
       return;
     }
-  else if ( FPU_st0_tag == TW_Infinity )
+  else if ( st0_tag == TW_Infinity )
     {
-      char sign = FPU_st0_ptr->sign;
-      FPU_st0_ptr->sign = SIGN_POS;
+      char sign = st0_ptr->sign;
+      st0_ptr->sign = SIGN_POS;
       push();
-      reg_move(&CONST_INF, FPU_st0_ptr);
-      FPU_st0_ptr->sign = sign;
+      reg_move(&CONST_INF, st_new_ptr);
+      st_new_ptr->sign = sign;
       return;
     }
-  else if ( FPU_st0_tag == TW_NaN )
+  else if ( st0_tag == TW_NaN )
     {
-      if ( real_2op_NaN(FPU_st0_ptr, FPU_st0_ptr, FPU_st0_ptr) )
+      if ( real_2op_NaN(st0_ptr, st0_ptr, st0_ptr) )
 	return;
       push();
-      reg_move(st1_ptr, FPU_st0_ptr);
+      reg_move(st1_ptr, st_new_ptr);
       return;
     }
-  else if ( FPU_st0_tag == TW_Empty )
+  else if ( st0_tag == TW_Empty )
     {
       /* Is this the correct behaviour? */
       if ( control_word & EX_Invalid )
@@ -448,110 +450,114 @@
 }
 
 
-static void fdecstp(void)
+static void fdecstp(FPU_REG *st0_ptr)
 {
   clear_C1();
-  top--;  /* FPU_st0_ptr will be fixed in math_emulate() before the next instr */
+  top--;  /* st0_ptr will be fixed in math_emulate() before the next instr */
 }
 
-static void fincstp(void)
+static void fincstp(FPU_REG *st0_ptr)
 {
   clear_C1();
-  top++;  /* FPU_st0_ptr will be fixed in math_emulate() before the next instr */
+  top++;  /* st0_ptr will be fixed in math_emulate() before the next instr */
 }
 
 
-static void fsqrt_(void)
+static void fsqrt_(FPU_REG *st0_ptr)
 {
+  char st0_tag = st0_ptr->tag;
+
   clear_C1();
-  if ( !(FPU_st0_tag ^ TW_Valid) )
+  if ( !(st0_tag ^ TW_Valid) )
     {
       int expon;
       
-      if (FPU_st0_ptr->sign == SIGN_NEG)
+      if (st0_ptr->sign == SIGN_NEG)
 	{
-	  arith_invalid(FPU_st0_ptr);  /* sqrt(negative) is invalid */
+	  arith_invalid(st0_ptr);  /* sqrt(negative) is invalid */
 	  return;
 	}
 
 #ifdef DENORM_OPERAND
-      if ( (FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
+      if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
 	return;
 #endif DENORM_OPERAND
 
-      expon = FPU_st0_ptr->exp - EXP_BIAS;
-      FPU_st0_ptr->exp = EXP_BIAS + (expon & 1);  /* make st(0) in  [1.0 .. 4.0) */
+      expon = st0_ptr->exp - EXP_BIAS;
+      st0_ptr->exp = EXP_BIAS + (expon & 1);  /* make st(0) in  [1.0 .. 4.0) */
       
-      wm_sqrt(FPU_st0_ptr, control_word);	/* Do the computation */
+      wm_sqrt(st0_ptr, control_word);	/* Do the computation */
       
-      FPU_st0_ptr->exp += expon >> 1;
-      FPU_st0_ptr->sign = SIGN_POS;
+      st0_ptr->exp += expon >> 1;
+      st0_ptr->sign = SIGN_POS;
     }
-  else if ( FPU_st0_tag == TW_Zero )
+  else if ( st0_tag == TW_Zero )
     return;
-  else if ( FPU_st0_tag == TW_Infinity )
+  else if ( st0_tag == TW_Infinity )
     {
-      if ( FPU_st0_ptr->sign == SIGN_NEG )
-	arith_invalid(FPU_st0_ptr);  /* sqrt(-Infinity) is invalid */
+      if ( st0_ptr->sign == SIGN_NEG )
+	arith_invalid(st0_ptr);  /* sqrt(-Infinity) is invalid */
       return;
     }
   else
-    { single_arg_error(); return; }
+    { single_arg_error(st0_ptr); return; }
 
 }
 
 
-static void frndint_(void)
+static void frndint_(FPU_REG *st0_ptr)
 {
+  char st0_tag = st0_ptr->tag;
   int flags;
 
-  if ( !(FPU_st0_tag ^ TW_Valid) )
+  if ( !(st0_tag ^ TW_Valid) )
     {
-      if (FPU_st0_ptr->exp > EXP_BIAS+63)
+      if (st0_ptr->exp > EXP_BIAS+63)
 	return;
 
 #ifdef DENORM_OPERAND
-      if ( (FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
+      if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
 	return;
 #endif DENORM_OPERAND
 
       /* Fortunately, this can't overflow to 2^64 */
-      if ( (flags = round_to_int(FPU_st0_ptr)) )
+      if ( (flags = round_to_int(st0_ptr)) )
 	set_precision_flag(flags);
 
-      FPU_st0_ptr->exp = EXP_BIAS + 63;
-      normalize(FPU_st0_ptr);
+      st0_ptr->exp = EXP_BIAS + 63;
+      normalize(st0_ptr);
       return;
     }
-  else if ( (FPU_st0_tag == TW_Zero) || (FPU_st0_tag == TW_Infinity) )
+  else if ( (st0_tag == TW_Zero) || (st0_tag == TW_Infinity) )
     return;
   else
-    single_arg_error();
+    single_arg_error(st0_ptr);
 }
 
 
-static void fsin(void)
+static void fsin(FPU_REG *st0_ptr)
 {
-  char arg_sign = FPU_st0_ptr->sign;
+  char st0_tag = st0_ptr->tag;
+  char arg_sign = st0_ptr->sign;
 
-  if ( FPU_st0_tag == TW_Valid )
+  if ( st0_tag == TW_Valid )
     {
       FPU_REG rv;
       int q;
 
-      if ( FPU_st0_ptr->exp > EXP_BIAS - 40 )
+      if ( st0_ptr->exp > EXP_BIAS - 40 )
 	{
-	  FPU_st0_ptr->sign = SIGN_POS;
-	  if ( (q = trig_arg(FPU_st0_ptr, 0)) != -1 )
+	  st0_ptr->sign = SIGN_POS;
+	  if ( (q = trig_arg(st0_ptr, 0)) != -1 )
 	    {
-	      reg_div(FPU_st0_ptr, &CONST_PI2, FPU_st0_ptr, FULL_PRECISION);
+	      reg_div(st0_ptr, &CONST_PI2, st0_ptr, FULL_PRECISION);
 
-	      poly_sine(FPU_st0_ptr, &rv);
+	      poly_sine(st0_ptr, &rv);
 
 	      if (q & 2)
 		rv.sign ^= SIGN_POS ^ SIGN_NEG;
 	      rv.sign ^= arg_sign;
-	      reg_move(&rv, FPU_st0_ptr);
+	      reg_move(&rv, st0_ptr);
 
 	      /* We do not really know if up or down */
 	      set_precision_flag_up();
@@ -560,7 +566,7 @@
 	  else
 	    {
 	      /* Operand is out of range */
-	      FPU_st0_ptr->sign = arg_sign;         /* restore st(0) */
+	      st0_ptr->sign = arg_sign;         /* restore st(0) */
 	      return;
 	    }
 	}
@@ -569,7 +575,7 @@
 	  /* For a small arg, the result == the argument */
 	  /* Underflow may happen */
 
-	  if ( FPU_st0_ptr->exp <= EXP_UNDER )
+	  if ( st0_ptr->exp <= EXP_UNDER )
 	    {
 #ifdef DENORM_OPERAND
 	      if ( denormal_operand() )
@@ -578,26 +584,26 @@
 	      /* A denormal result has been produced.
 		 Precision must have been lost, this is always
 		 an underflow. */
-	      arith_underflow(FPU_st0_ptr);
+	      arith_underflow(st0_ptr);
 	      return;
 	    }
 
 	  set_precision_flag_up();  /* Must be up. */
 	}
     }
-  else if ( FPU_st0_tag == TW_Zero )
+  else if ( st0_tag == TW_Zero )
     {
       setcc(0);
       return;
     }
-  else if ( FPU_st0_tag == TW_Infinity )
+  else if ( st0_tag == TW_Infinity )
     {
       /* The 80486 treats infinity as an invalid operand */
-      arith_invalid(FPU_st0_ptr);
+      arith_invalid(st0_ptr);
       return;
     }
   else
-    single_arg_error();
+    single_arg_error(st0_ptr);
 }
 
 
@@ -658,33 +664,34 @@
       setcc(0);
       return 0;
     }
-  else if ( FPU_st0_tag == TW_Infinity )
+  else if ( arg->tag == TW_Infinity )
     {
       /* The 80486 treats infinity as an invalid operand */
-      arith_invalid(FPU_st0_ptr);
+      arith_invalid(arg);
       return 1;
     }
   else
     {
-      single_arg_error();  /* requires arg == &st(0) */
+      single_arg_error(arg);  /* requires arg == &st(0) */
       return 1;
     }
 }
 
 
-static void fcos(void)
+static void fcos(FPU_REG *st0_ptr)
 {
-  f_cos(FPU_st0_ptr);
+  f_cos(st0_ptr);
 }
 
 
-static void fsincos(void)
+static void fsincos(FPU_REG *st0_ptr)
 {
+  char st0_tag = st0_ptr->tag;
   FPU_REG *st_new_ptr;
   FPU_REG arg;
 
   /* Stack underflow has higher priority */
-  if ( FPU_st0_tag == TW_Empty )
+  if ( st0_tag == TW_Empty )
     {
       stack_underflow();  /* Puts a QNaN in st(0) */
       if ( control_word & CW_Invalid )
@@ -699,29 +706,29 @@
   if ( STACK_OVERFLOW )
     { stack_overflow(); return; }
 
-  if ( FPU_st0_tag == TW_NaN )
+  if ( st0_tag == TW_NaN )
     {
-      single_arg_2_error();
+      single_arg_2_error(st0_ptr);
       return;
     }
-  else if ( FPU_st0_tag == TW_Infinity )
+  else if ( st0_tag == TW_Infinity )
     {
       /* The 80486 treats infinity as an invalid operand */
-      if ( !arith_invalid(FPU_st0_ptr) )
+      if ( !arith_invalid(st0_ptr) )
 	{
 	  /* unmasked response */
 	  push();
-	  arith_invalid(FPU_st0_ptr);
+	  arith_invalid(st_new_ptr);
 	}
       return;
     }
 
-  reg_move(FPU_st0_ptr,&arg);
+  reg_move(st0_ptr,&arg);
   if ( !f_cos(&arg) )
     {
-      fsin();
+      fsin(st0_ptr);
       push();
-      reg_move(&arg,FPU_st0_ptr);
+      reg_move(&arg,st_new_ptr);
     }
 
 }
@@ -760,23 +767,24 @@
 /* Remainder of st(0) / st(1) */
 /* This routine produces exact results, i.e. there is never any
    rounding or truncation, etc of the result. */
-static void do_fprem(int round)
+static void do_fprem(FPU_REG *st0_ptr, int round)
 {
   FPU_REG *st1_ptr = &st(1);
   char st1_tag = st1_ptr->tag;
-  char sign = FPU_st0_ptr->sign;
+  char st0_tag = st0_ptr->tag;
+  char sign = st0_ptr->sign;
 
-  if ( !((FPU_st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid)) )
+  if ( !((st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid)) )
     {
       FPU_REG tmp;
       int old_cw = control_word;
-      int expdif = FPU_st0_ptr->exp - st1_ptr->exp;
+      int expdif = st0_ptr->exp - st1_ptr->exp;
       long long q;
       unsigned short saved_status;
       int cc = 0;
 
 #ifdef DENORM_OPERAND
-      if ( ((FPU_st0_ptr->exp <= EXP_UNDER) ||
+      if ( ((st0_ptr->exp <= EXP_UNDER) ||
 	    (st1_ptr->exp <= EXP_UNDER)) && (denormal_operand()) )
 	return;
 #endif DENORM_OPERAND
@@ -793,7 +801,7 @@
 
 	  if ( expdif > -2 )
 	    {
-	      reg_div(FPU_st0_ptr, st1_ptr, &tmp, PR_64_BITS | RC_CHOP | 0x3f);
+	      reg_div(st0_ptr, st1_ptr, &tmp, PR_64_BITS | RC_CHOP | 0x3f);
 
 	      if ( tmp.exp >= EXP_BIAS )
 		{
@@ -801,7 +809,7 @@
 					  to 2^64 */
 		  q = significand(&tmp);
 
-		  rem_kernel(significand(FPU_st0_ptr),
+		  rem_kernel(significand(st0_ptr),
 			     &significand(&tmp),
 			     significand(st1_ptr),
 			     q, expdif);
@@ -810,7 +818,7 @@
 		}
 	      else
 		{
-		  reg_move(FPU_st0_ptr, &tmp);
+		  reg_move(st0_ptr, &tmp);
 		  q = 0;
 		}
 	      tmp.sign = sign;
@@ -858,7 +866,7 @@
 
 	  /* prevent overflow here */
 	  /* N is 'a number between 32 and 63' (p26-113) */
-	  reg_move(FPU_st0_ptr, &tmp);
+	  reg_move(st0_ptr, &tmp);
 	  tmp.exp = EXP_BIAS + 56;
 	  exp_1 = st1_ptr->exp;      st1_ptr->exp = EXP_BIAS;
 	  expdif -= 56;
@@ -868,7 +876,7 @@
 
 	  round_to_int(&tmp);  /* Fortunately, this can't overflow to 2^64 */
 
-	  rem_kernel(significand(FPU_st0_ptr),
+	  rem_kernel(significand(st0_ptr),
 		     &significand(&tmp),
 		     significand(st1_ptr),
 		     significand(&tmp),
@@ -887,8 +895,8 @@
 	      /* The result is zero */
 	      control_word = old_cw;
 	      partial_status = saved_status;
-	      reg_move(&CONST_Z, FPU_st0_ptr);
-	      FPU_st0_ptr->sign = sign;
+	      reg_move(&CONST_Z, st0_ptr);
+	      st0_ptr->sign = sign;
 #ifdef PECULIAR_486
 	      setcc(SW_C2);
 #else
@@ -902,23 +910,23 @@
       control_word = old_cw;
       partial_status = saved_status;
       normalize_nuo(&tmp);
-      reg_move(&tmp, FPU_st0_ptr);
+      reg_move(&tmp, st0_ptr);
       setcc(cc);
 
       /* 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)
+      if ( (st0_ptr->exp <= EXP_UNDER) && (st0_ptr->tag != TW_Zero)
 	  && !(control_word & CW_Underflow) )
-	arith_underflow(FPU_st0_ptr);
+	arith_underflow(st0_ptr);
 
       return;
     }
-  else if ( (FPU_st0_tag == TW_Empty) | (st1_tag == TW_Empty) )
+  else if ( (st0_tag == TW_Empty) | (st1_tag == TW_Empty) )
     {
       stack_underflow();
       return;
     }
-  else if ( FPU_st0_tag == TW_Zero )
+  else if ( st0_tag == TW_Zero )
     {
       if ( st1_tag == TW_Valid )
 	{
@@ -930,21 +938,21 @@
 	  setcc(0); return;
 	}
       else if ( st1_tag == TW_Zero )
-	{ arith_invalid(FPU_st0_ptr); return; } /* fprem(?,0) always invalid */
+	{ arith_invalid(st0_ptr); return; } /* fprem(?,0) always invalid */
       else if ( st1_tag == TW_Infinity )
 	{ setcc(0); return; }
     }
-  else if ( FPU_st0_tag == TW_Valid )
+  else if ( st0_tag == TW_Valid )
     {
       if ( st1_tag == TW_Zero )
 	{
-	  arith_invalid(FPU_st0_ptr); /* fprem(Valid,Zero) is invalid */
+	  arith_invalid(st0_ptr); /* fprem(Valid,Zero) is invalid */
 	  return;
 	}
       else if ( st1_tag != TW_NaN )
 	{
 #ifdef DENORM_OPERAND
-	  if ( (FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
+	  if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
 	    return;
 #endif DENORM_OPERAND
 
@@ -955,11 +963,11 @@
 	    }
 	}
     }
-  else if ( FPU_st0_tag == TW_Infinity )
+  else if ( st0_tag == TW_Infinity )
     {
       if ( st1_tag != TW_NaN )
 	{
-	  arith_invalid(FPU_st0_ptr); /* fprem(Infinity,?) is invalid */
+	  arith_invalid(st0_ptr); /* fprem(Infinity,?) is invalid */
 	  return;
 	}
     }
@@ -967,30 +975,31 @@
   /* One of the registers must contain a NaN is we got here. */
 
 #ifdef PARANOID
-  if ( (FPU_st0_tag != TW_NaN) && (st1_tag != TW_NaN) )
+  if ( (st0_tag != TW_NaN) && (st1_tag != TW_NaN) )
       EXCEPTION(EX_INTERNAL | 0x118);
 #endif PARANOID
 
-  real_2op_NaN(st1_ptr, FPU_st0_ptr, FPU_st0_ptr);
+  real_2op_NaN(st1_ptr, st0_ptr, st0_ptr);
 
 }
 
 
 /* ST(1) <- ST(1) * log ST;  pop ST */
-static void fyl2x(void)
+static void fyl2x(FPU_REG *st0_ptr)
 {
+  char st0_tag = st0_ptr->tag;
   FPU_REG *st1_ptr = &st(1);
   char st1_tag = st1_ptr->tag;
 
   clear_C1();
-  if ( !((FPU_st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid)) )
+  if ( !((st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid)) )
     {
-      if ( FPU_st0_ptr->sign == SIGN_POS )
+      if ( st0_ptr->sign == SIGN_POS )
 	{
 	  int saved_control, saved_status;
 
 #ifdef DENORM_OPERAND
-	  if ( ((FPU_st0_ptr->exp <= EXP_UNDER) ||
+	  if ( ((st0_ptr->exp <= EXP_UNDER) ||
 		(st1_ptr->exp <= EXP_UNDER)) && (denormal_operand()) )
 	    return;
 #endif DENORM_OPERAND
@@ -1001,16 +1010,16 @@
 	  saved_control = control_word;
 	  control_word = FULL_PRECISION;
 
-	  poly_l2(FPU_st0_ptr, FPU_st0_ptr);
+	  poly_l2(st0_ptr, st0_ptr);
 
 	  /* Enough of the basic arithmetic is done now */
 	  control_word = saved_control;
 	  partial_status = saved_status;
 
 	  /* Let the multiply set the flags */
-	  reg_mul(FPU_st0_ptr, st1_ptr, st1_ptr, FULL_PRECISION);
+	  reg_mul(st0_ptr, st1_ptr, st1_ptr, FULL_PRECISION);
 
-	  pop(); FPU_st0_ptr = &st(0);
+	  pop();
 	}
       else
 	{
@@ -1020,21 +1029,21 @@
 	  return;
 	}
     }
-  else if ( (FPU_st0_tag == TW_Empty) || (st1_tag == TW_Empty) )
+  else if ( (st0_tag == TW_Empty) || (st1_tag == TW_Empty) )
     {
       stack_underflow_pop(1);
       return;
     }
-  else if ( (FPU_st0_tag == TW_NaN) || (st1_tag == TW_NaN) )
+  else if ( (st0_tag == TW_NaN) || (st1_tag == TW_NaN) )
     {
-      if ( !real_2op_NaN(FPU_st0_ptr, st1_ptr, st1_ptr) )
+      if ( !real_2op_NaN(st0_ptr, st1_ptr, st1_ptr) )
 	pop();
       return;
     }
-  else if ( (FPU_st0_tag <= TW_Zero) && (st1_tag <= TW_Zero) )
+  else if ( (st0_tag <= TW_Zero) && (st1_tag <= TW_Zero) )
     {
       /* one of the args is zero, the other valid, or both zero */
-      if ( FPU_st0_tag == TW_Zero )
+      if ( st0_tag == TW_Zero )
 	{
 	  if ( st1_tag == TW_Zero )
 	    {
@@ -1046,7 +1055,7 @@
 	  /* This case is not specifically covered in the manual,
 	     but divide-by-zero would seem to be the best response.
 	     However, a real 80486 does it this way... */
-	  else if ( FPU_st0_ptr->tag == TW_Infinity )
+	  else if ( st0_ptr->tag == TW_Infinity )
 	    {
 	      reg_move(&CONST_INF, st1_ptr);
 	      pop();
@@ -1065,7 +1074,7 @@
 	  /* Zero is the valid answer */
 	  char sign = st1_ptr->sign;
 
-	  if ( FPU_st0_ptr->sign == SIGN_NEG )
+	  if ( st0_ptr->sign == SIGN_NEG )
 	    {
 	      /* log(negative) */
 	      if ( !arith_invalid(st1_ptr) )
@@ -1074,21 +1083,21 @@
 	    }
 
 #ifdef DENORM_OPERAND
-	  if ( (FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
+	  if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
 	    return;
 #endif DENORM_OPERAND
 
-	  if ( FPU_st0_ptr->exp < EXP_BIAS ) sign ^= SIGN_NEG^SIGN_POS;
-	  pop(); FPU_st0_ptr = &st(0);
-	  reg_move(&CONST_Z, FPU_st0_ptr);
-	  FPU_st0_ptr->sign = sign;
+	  if ( st0_ptr->exp < EXP_BIAS ) sign ^= SIGN_NEG^SIGN_POS;
+	  pop(); st0_ptr = &st(0);
+	  reg_move(&CONST_Z, st0_ptr);
+	  st0_ptr->sign = sign;
 	  return;
 	}
     }
   /* One or both arg must be an infinity */
-  else if ( FPU_st0_tag == TW_Infinity )
+  else if ( st0_tag == TW_Infinity )
     {
-      if ( (FPU_st0_ptr->sign == SIGN_NEG) || (st1_tag == TW_Zero) )
+      if ( (st0_ptr->sign == SIGN_NEG) || (st1_tag == TW_Zero) )
 	{
 	  /* log(-infinity) or 0*log(infinity) */
 	  if ( !arith_invalid(st1_ptr) )
@@ -1104,20 +1113,20 @@
 	    return;
 #endif DENORM_OPERAND
 
-	  pop(); FPU_st0_ptr = &st(0);
-	  reg_move(&CONST_INF, FPU_st0_ptr);
-	  FPU_st0_ptr->sign = sign;
+	  pop(); st0_ptr = &st(0);
+	  reg_move(&CONST_INF, st0_ptr);
+	  st0_ptr->sign = sign;
 	  return;
 	}
     }
   /* st(1) must be infinity here */
-  else if ( (FPU_st0_tag == TW_Valid) && (FPU_st0_ptr->sign == SIGN_POS) )
+  else if ( (st0_tag == TW_Valid) && (st0_ptr->sign == SIGN_POS) )
     {
-      if ( FPU_st0_ptr->exp >= EXP_BIAS )
+      if ( st0_ptr->exp >= EXP_BIAS )
 	{
-	  if ( (FPU_st0_ptr->exp == EXP_BIAS) &&
-	      (FPU_st0_ptr->sigh == 0x80000000) &&
-	      (FPU_st0_ptr->sigl == 0) )
+	  if ( (st0_ptr->exp == EXP_BIAS) &&
+	      (st0_ptr->sigh == 0x80000000) &&
+	      (st0_ptr->sigl == 0) )
 	    {
 	      /* st(0) holds 1.0 */
 	      /* infinity*log(1) */
@@ -1133,7 +1142,7 @@
 	  /* st(0) is positive and < 1.0 */
 
 #ifdef DENORM_OPERAND
-	  if ( (FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
+	  if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
 	    return;
 #endif DENORM_OPERAND
 
@@ -1145,7 +1154,7 @@
   else
     {
       /* st(0) must be zero or negative */
-      if ( FPU_st0_ptr->tag == TW_Zero )
+      if ( st0_ptr->tag == TW_Zero )
 	{
 	  /* This should be invalid, but a real 80486 is happy with it. */
 #ifndef PECULIAR_486
@@ -1167,21 +1176,22 @@
 }
 
 
-static void fpatan(void)
+static void fpatan(FPU_REG *st0_ptr)
 {
+  char st0_tag = st0_ptr->tag;
   FPU_REG *st1_ptr = &st(1);
   char st1_tag = st1_ptr->tag;
-  char st1_sign = st1_ptr->sign, st0_sign = FPU_st0_ptr->sign;
+  char st1_sign = st1_ptr->sign, st0_sign = st0_ptr->sign;
 
   clear_C1();
-  if ( !((FPU_st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid)) )
+  if ( !((st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid)) )
     {
       int saved_control, saved_status;
       FPU_REG sum;
       char inverted;
 
 #ifdef DENORM_OPERAND
-      if ( ((FPU_st0_ptr->exp <= EXP_UNDER) ||
+      if ( ((st0_ptr->exp <= EXP_UNDER) ||
 	    (st1_ptr->exp <= EXP_UNDER)) && (denormal_operand()) )
 	return;
 #endif DENORM_OPERAND
@@ -1191,28 +1201,28 @@
       saved_control = control_word;
       control_word = FULL_PRECISION;
 
-      st1_ptr->sign = FPU_st0_ptr->sign = SIGN_POS;
+      st1_ptr->sign = st0_ptr->sign = SIGN_POS;
       if ( (compare(st1_ptr) & ~COMP_Denormal) == COMP_A_lt_B )
 	{
 	  inverted = 1;
-	  reg_div(FPU_st0_ptr, st1_ptr, &sum, FULL_PRECISION);
+	  reg_div(st0_ptr, st1_ptr, &sum, FULL_PRECISION);
 	}
       else
 	{
 	  inverted = 0;
 	  if ( (st0_sign == 0) &&
-	      (st1_ptr->exp - FPU_st0_ptr->exp < -64) )
+	      (st1_ptr->exp - st0_ptr->exp < -64) )
 	    {
 	      control_word = saved_control;
 	      partial_status = saved_status;
-	      reg_div(st1_ptr, FPU_st0_ptr, st1_ptr,
+	      reg_div(st1_ptr, st0_ptr, st1_ptr,
 		      control_word | PR_64_BITS);
 	      st1_ptr->sign = st1_sign;
 	      pop();
 	      set_precision_flag_down();
 	      return;
 	    }
-	  reg_div(st1_ptr, FPU_st0_ptr, &sum, FULL_PRECISION);
+	  reg_div(st1_ptr, st0_ptr, &sum, FULL_PRECISION);
 	}
 
       poly_atan(&sum);
@@ -1233,25 +1243,25 @@
 
       reg_move(&sum, st1_ptr);
     }
-  else if ( (FPU_st0_tag == TW_Empty) || (st1_tag == TW_Empty) )
+  else if ( (st0_tag == TW_Empty) || (st1_tag == TW_Empty) )
     {
       stack_underflow_pop(1);
       return;
     }
-  else if ( (FPU_st0_tag == TW_NaN) || (st1_tag == TW_NaN) )
+  else if ( (st0_tag == TW_NaN) || (st1_tag == TW_NaN) )
     {
-      if ( !real_2op_NaN(FPU_st0_ptr, st1_ptr, st1_ptr) )
+      if ( !real_2op_NaN(st0_ptr, st1_ptr, st1_ptr) )
 	  pop();
       return;
     }
-  else if ( (FPU_st0_tag == TW_Infinity) || (st1_tag == TW_Infinity) )
+  else if ( (st0_tag == TW_Infinity) || (st1_tag == TW_Infinity) )
     {
       char sign = st1_ptr->sign;
-      if ( FPU_st0_tag == TW_Infinity )
+      if ( st0_tag == TW_Infinity )
 	{
 	  if ( st1_tag == TW_Infinity )
 	    {
-	      if ( FPU_st0_ptr->sign == SIGN_POS )
+	      if ( st0_ptr->sign == SIGN_POS )
 		{ reg_move(&CONST_PI4, st1_ptr); }
 	      else
 		reg_add(&CONST_PI4, &CONST_PI2, st1_ptr, FULL_PRECISION);
@@ -1266,7 +1276,7 @@
 		}
 #endif DENORM_OPERAND
 
-	      if ( FPU_st0_ptr->sign == SIGN_POS )
+	      if ( st0_ptr->sign == SIGN_POS )
 		{
 		  reg_move(&CONST_Z, st1_ptr);
 		  st1_ptr->sign = sign;   /* An 80486 preserves the sign */
@@ -1281,9 +1291,9 @@
 	{
 	  /* st(1) is infinity, st(0) not infinity */
 #ifdef DENORM_OPERAND
-	  if ( FPU_st0_tag != TW_Zero )
+	  if ( st0_tag != TW_Zero )
 	    {
-	      if ( (FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
+	      if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
 		return;
 	    }
 #endif DENORM_OPERAND
@@ -1298,20 +1308,20 @@
       char sign = st1_ptr->sign;
 
 #ifdef DENORM_OPERAND
-      if ( FPU_st0_tag != TW_Zero )
+      if ( st0_tag != TW_Zero )
 	{
-	  if ( (FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
+	  if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
 	    return;
 	}
 #endif DENORM_OPERAND
 
-      if ( FPU_st0_ptr->sign == SIGN_POS )
+      if ( st0_ptr->sign == SIGN_POS )
 	{ /* An 80486 preserves the sign */ pop(); return; }
       else
 	reg_move(&CONST_PI, st1_ptr);
       st1_ptr->sign = sign;
     }
-  else if ( FPU_st0_tag == TW_Zero )
+  else if ( st0_tag == TW_Zero )
     {
       /* st(1) must be TW_Valid here */
       char sign = st1_ptr->sign;
@@ -1334,30 +1344,31 @@
 }
 
 
-static void fprem(void)
+static void fprem(FPU_REG *st0_ptr)
 {
-  do_fprem(RC_CHOP);
+  do_fprem(st0_ptr, RC_CHOP);
 }
 
 
-static void fprem1(void)
+static void fprem1(FPU_REG *st0_ptr)
 {
-  do_fprem(RC_RND);
+  do_fprem(st0_ptr, RC_RND);
 }
 
 
-static void fyl2xp1(void)
+static void fyl2xp1(FPU_REG *st0_ptr)
 {
+  char st0_tag = st0_ptr->tag;
   FPU_REG *st1_ptr = &st(1);
   char st1_tag = st1_ptr->tag;
 
   clear_C1();
-  if ( !((FPU_st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid)) )
+  if ( !((st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid)) )
     {
       int saved_control, saved_status;
 
 #ifdef DENORM_OPERAND
-      if ( ((FPU_st0_ptr->exp <= EXP_UNDER) ||
+      if ( ((st0_ptr->exp <= EXP_UNDER) ||
 	    (st1_ptr->exp <= EXP_UNDER)) && denormal_operand() )
 	return;
 #endif DENORM_OPERAND
@@ -1367,7 +1378,7 @@
       saved_control = control_word;
       control_word = FULL_PRECISION;
 
-      if ( poly_l2p1(FPU_st0_ptr, FPU_st0_ptr) )
+      if ( poly_l2p1(st0_ptr, st0_ptr) )
 	{
 #ifdef PECULIAR_486   /* Stupid 80486 doesn't worry about log(negative). */
 	  st1_ptr->sign ^= SIGN_POS^SIGN_NEG;
@@ -1386,16 +1397,16 @@
       partial_status = saved_status;
 
       /* Let the multiply set the flags */
-      reg_mul(FPU_st0_ptr, st1_ptr, st1_ptr, FULL_PRECISION);
+      reg_mul(st0_ptr, st1_ptr, st1_ptr, FULL_PRECISION);
 
       pop();
     }
-  else if ( (FPU_st0_tag == TW_Empty) | (st1_tag == TW_Empty) )
+  else if ( (st0_tag == TW_Empty) | (st1_tag == TW_Empty) )
     {
       stack_underflow_pop(1);
       return;
     }
-  else if ( FPU_st0_tag == TW_Zero )
+  else if ( st0_tag == TW_Zero )
     {
       if ( st1_tag <= TW_Zero )
 	{
@@ -1405,8 +1416,8 @@
 	    return;
 #endif DENORM_OPERAND
 	  
-	  FPU_st0_ptr->sign ^= st1_ptr->sign;
-	  reg_move(FPU_st0_ptr, st1_ptr);
+	  st0_ptr->sign ^= st1_ptr->sign;
+	  reg_move(st0_ptr, st1_ptr);
 	}
       else if ( st1_tag == TW_Infinity )
 	{
@@ -1417,7 +1428,7 @@
 	}
       else if ( st1_tag == TW_NaN )
 	{
-	  if ( !real_2op_NaN(FPU_st0_ptr, st1_ptr, st1_ptr) )
+	  if ( !real_2op_NaN(st0_ptr, st1_ptr, st1_ptr) )
 	    pop();
 	  return;
 	}
@@ -1430,13 +1441,13 @@
 #endif PARANOID
       pop(); return;
     }
-  else if ( FPU_st0_tag == TW_Valid )
+  else if ( st0_tag == TW_Valid )
     {
       if ( st1_tag == TW_Zero )
 	{
-	  if ( FPU_st0_ptr->sign == SIGN_NEG )
+	  if ( st0_ptr->sign == SIGN_NEG )
 	    {
-	      if ( FPU_st0_ptr->exp >= EXP_BIAS )
+	      if ( st0_ptr->exp >= EXP_BIAS )
 		{
 		  /* st(0) holds <= -1.0 */
 #ifdef PECULIAR_486   /* Stupid 80486 doesn't worry about log(negative). */
@@ -1447,25 +1458,25 @@
 		  pop(); return;
 		}
 #ifdef DENORM_OPERAND
-	      if ( (FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
+	      if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
 		return;
 #endif DENORM_OPERAND
 	      st1_ptr->sign ^= SIGN_POS^SIGN_NEG;
 	      pop(); return;
 	    }
 #ifdef DENORM_OPERAND
-	  if ( (FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
+	  if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
 	    return;
 #endif DENORM_OPERAND
 	  pop(); return;
 	}
       if ( st1_tag == TW_Infinity )
 	{
-	  if ( FPU_st0_ptr->sign == SIGN_NEG )
+	  if ( st0_ptr->sign == SIGN_NEG )
 	    {
-	      if ( (FPU_st0_ptr->exp >= EXP_BIAS) &&
-		  !((FPU_st0_ptr->sigh == 0x80000000) &&
-		    (FPU_st0_ptr->sigl == 0)) )
+	      if ( (st0_ptr->exp >= EXP_BIAS) &&
+		  !((st0_ptr->sigh == 0x80000000) &&
+		    (st0_ptr->sigl == 0)) )
 		{
 		  /* st(0) holds < -1.0 */
 #ifdef PECULIAR_486   /* Stupid 80486 doesn't worry about log(negative). */
@@ -1476,40 +1487,40 @@
 		  pop(); return;
 		}
 #ifdef DENORM_OPERAND
-	      if ( (FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
+	      if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
 		return;
 #endif DENORM_OPERAND
 	      st1_ptr->sign ^= SIGN_POS^SIGN_NEG;
 	      pop(); return;
 	    }
 #ifdef DENORM_OPERAND
-	  if ( (FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
+	  if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
 	    return;
 #endif DENORM_OPERAND
 	  pop(); return;
 	}
       if ( st1_tag == TW_NaN )
 	{
-	  if ( !real_2op_NaN(FPU_st0_ptr, st1_ptr, st1_ptr) )
+	  if ( !real_2op_NaN(st0_ptr, st1_ptr, st1_ptr) )
 	    pop();
 	  return;
 	}
     }
-  else if ( FPU_st0_tag == TW_NaN )
+  else if ( st0_tag == TW_NaN )
     {
-      if ( !real_2op_NaN(FPU_st0_ptr, st1_ptr, st1_ptr) )
+      if ( !real_2op_NaN(st0_ptr, st1_ptr, st1_ptr) )
 	pop();
       return;
     }
-  else if ( FPU_st0_tag == TW_Infinity )
+  else if ( st0_tag == TW_Infinity )
     {
       if ( st1_tag == TW_NaN )
 	{
-	  if ( !real_2op_NaN(FPU_st0_ptr, st1_ptr, st1_ptr) )
+	  if ( !real_2op_NaN(st0_ptr, st1_ptr, st1_ptr) )
 	    pop();
 	  return;
 	}
-      else if ( FPU_st0_ptr->sign == SIGN_NEG )
+      else if ( st0_ptr->sign == SIGN_NEG )
 	{
 	  int exponent = st1_ptr->exp;
 #ifndef PECULIAR_486
@@ -1565,21 +1576,22 @@
 }
 
 
-static void fscale(void)
+static void fscale(FPU_REG *st0_ptr)
 {
+  char st0_tag = st0_ptr->tag;
   FPU_REG *st1_ptr = &st(1);
   char st1_tag = st1_ptr->tag;
   int old_cw = control_word;
-  char sign = FPU_st0_ptr->sign;
+  char sign = st0_ptr->sign;
 
   clear_C1();
-  if ( !((FPU_st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid)) )
+  if ( !((st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid)) )
     {
       long scale;
       FPU_REG tmp;
 
 #ifdef DENORM_OPERAND
-      if ( ((FPU_st0_ptr->exp <= EXP_UNDER) ||
+      if ( ((st0_ptr->exp <= EXP_UNDER) ||
 	    (st1_ptr->exp <= EXP_UNDER)) && (denormal_operand()) )
 	return;
 #endif DENORM_OPERAND
@@ -1592,16 +1604,16 @@
 	  if ( st1_ptr->sign == SIGN_POS )
 	    {
 	      EXCEPTION(EX_Overflow);
-	      sign = FPU_st0_ptr->sign;
-	      reg_move(&CONST_INF, FPU_st0_ptr);
-	      FPU_st0_ptr->sign = sign;
+	      sign = st0_ptr->sign;
+	      reg_move(&CONST_INF, st0_ptr);
+	      st0_ptr->sign = sign;
 	    }
 	  else
 	    {
 	      EXCEPTION(EX_Underflow);
-	      sign = FPU_st0_ptr->sign;
-	      reg_move(&CONST_Z, FPU_st0_ptr);
-	      FPU_st0_ptr->sign = sign;
+	      sign = st0_ptr->sign;
+	      reg_move(&CONST_Z, st0_ptr);
+	      st0_ptr->sign = sign;
 	    }
 	  return;
 	}
@@ -1612,21 +1624,21 @@
       round_to_int(&tmp);               /* This can never overflow here */
       control_word = old_cw;
       scale = st1_ptr->sign ? -tmp.sigl : tmp.sigl;
-      scale += FPU_st0_ptr->exp;
-      FPU_st0_ptr->exp = scale;
+      scale += st0_ptr->exp;
+      st0_ptr->exp = scale;
 
       /* Use round_reg() to properly detect under/overflow etc */
-      round_reg(FPU_st0_ptr, 0, control_word);
+      round_reg(st0_ptr, 0, control_word);
 
       return;
     }
-  else if ( FPU_st0_tag == TW_Valid )
+  else if ( st0_tag == TW_Valid )
     {
       if ( st1_tag == TW_Zero )
 	{
 
 #ifdef DENORM_OPERAND
-	  if ( (FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
+	  if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
 	    return;
 #endif DENORM_OPERAND
 
@@ -1635,21 +1647,21 @@
       if ( st1_tag == TW_Infinity )
 	{
 #ifdef DENORM_OPERAND
-	  if ( (FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
+	  if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
 	    return;
 #endif DENORM_OPERAND
 
 	  if ( st1_ptr->sign == SIGN_POS )
-	    { reg_move(&CONST_INF, FPU_st0_ptr); }
+	    { reg_move(&CONST_INF, st0_ptr); }
 	  else
-	      reg_move(&CONST_Z, FPU_st0_ptr);
-	  FPU_st0_ptr->sign = sign;
+	      reg_move(&CONST_Z, st0_ptr);
+	  st0_ptr->sign = sign;
 	  return;
 	}
       if ( st1_tag == TW_NaN )
-	{ real_2op_NaN(FPU_st0_ptr, st1_ptr, FPU_st0_ptr); return; }
+	{ real_2op_NaN(st0_ptr, st1_ptr, st0_ptr); return; }
     }
-  else if ( FPU_st0_tag == TW_Zero )
+  else if ( st0_tag == TW_Zero )
     {
       if ( st1_tag == TW_Valid )
 	{
@@ -1668,14 +1680,14 @@
 	    return;
 	  else
 	    {
-	      arith_invalid(FPU_st0_ptr); /* Zero scaled by +Infinity */
+	      arith_invalid(st0_ptr); /* Zero scaled by +Infinity */
 	      return;
 	    }
 	}
       else if ( st1_tag == TW_NaN )
-	{ real_2op_NaN(FPU_st0_ptr, st1_ptr, FPU_st0_ptr); return; }
+	{ real_2op_NaN(st0_ptr, st1_ptr, st0_ptr); return; }
     }
-  else if ( FPU_st0_tag == TW_Infinity )
+  else if ( st0_tag == TW_Infinity )
     {
       if ( st1_tag == TW_Valid )
 	{
@@ -1692,20 +1704,20 @@
 	return;
       else if ( st1_tag == TW_Infinity )
 	{
-	  arith_invalid(FPU_st0_ptr); /* Infinity scaled by -Infinity */
+	  arith_invalid(st0_ptr); /* Infinity scaled by -Infinity */
 	  return;
 	}
       else if ( st1_tag == TW_NaN )
-	{ real_2op_NaN(FPU_st0_ptr, st1_ptr, FPU_st0_ptr); return; }
+	{ real_2op_NaN(st0_ptr, st1_ptr, st0_ptr); return; }
     }
-  else if ( FPU_st0_tag == TW_NaN )
+  else if ( st0_tag == TW_NaN )
     {
       if ( st1_tag != TW_Empty )
-	{ real_2op_NaN(FPU_st0_ptr, st1_ptr, FPU_st0_ptr); return; }
+	{ real_2op_NaN(st0_ptr, st1_ptr, st0_ptr); return; }
     }
 
 #ifdef PARANOID
-  if ( !((FPU_st0_tag == TW_Empty) || (st1_tag == TW_Empty)) )
+  if ( !((st0_tag == TW_Empty) || (st1_tag == TW_Empty)) )
     {
       EXCEPTION(EX_INTERNAL | 0x115);
       return;
@@ -1720,22 +1732,22 @@
 
 /*---------------------------------------------------------------------------*/
 
-static FUNC const trig_table_a[] = {
+static FUNC_ST0 const trig_table_a[] = {
   f2xm1, fyl2x, fptan, fpatan, fxtract, fprem1, fdecstp, fincstp
 };
 
 void trig_a(void)
 {
-  (trig_table_a[FPU_rm])();
+  (trig_table_a[FPU_rm])(&st(0));
 }
 
 
-static FUNC const trig_table_b[] =
+static FUNC_ST0 const trig_table_b[] =
   {
     fprem, fyl2xp1, fsqrt_, fsincos, frndint_, fscale, fsin, fcos
   };
 
 void trig_b(void)
 {
-  (trig_table_b[FPU_rm])();
+  (trig_table_b[FPU_rm])(&st(0));
 }
diff -u --recursive --new-file v1.1.17/linux/drivers/FPU-emu/get_address.c linux/drivers/FPU-emu/get_address.c
--- v1.1.17/linux/drivers/FPU-emu/get_address.c	Tue May 24 00:34:46 1994
+++ linux/drivers/FPU-emu/get_address.c	Thu Jun  2 10:28:26 1994
@@ -19,6 +19,7 @@
 
 
 #include <linux/stddef.h>
+#include <linux/head.h>
 
 #include <asm/segment.h>
 
@@ -26,6 +27,9 @@
 #include "exception.h"
 #include "fpu_emu.h"
 
+
+#define FPU_WRITE_BIT 0x10
+
 static int reg_offset[] = {
 	offsetof(struct info,___eax),
 	offsetof(struct info,___ecx),
@@ -52,7 +56,7 @@
 #define VM86_REG_(x) (*(unsigned short *) \
 		      (reg_offset_vm86[((unsigned)x)]+(char *) FPU_info))
 
-static int reg_offset_p286[] = {
+static int reg_offset_pm[] = {
 	offsetof(struct info,___cs),
 	offsetof(struct info,___ds),
 	offsetof(struct info,___es),
@@ -62,12 +66,12 @@
 	offsetof(struct info,___ds)
       };
 
-#define P286_REG_(x) (*(unsigned short *) \
-		      (reg_offset_p286[((unsigned)x)]+(char *) FPU_info))
+#define PM_REG_(x) (*(unsigned short *) \
+		      (reg_offset_pm[((unsigned)x)]+(char *) FPU_info))
 
 
 /* Decode the SIB byte. This function assumes mod != 0 */
-static void *sib(int mod, unsigned long *fpu_eip)
+static int sib(int mod, unsigned long *fpu_eip)
 {
   unsigned char ss,index,base;
   long offset;
@@ -117,14 +121,14 @@
       (*fpu_eip) += 4;
     }
 
-  return (void *) offset;
+  return offset;
 }
 
 
-static unsigned long mode16_segment(fpu_addr_modes addr_modes)
+static unsigned long vm86_segment(unsigned char segment,
+				  unsigned short *selector)
 { 
-  int segment = addr_modes.override.segment - 1;
-
+  segment--;
 #ifdef PARANOID
   if ( segment > PREFIX_SS_ )
     {
@@ -132,11 +136,61 @@
       math_abort(FPU_info,SIGSEGV);
     }
 #endif PARANOID
-  if ( addr_modes.vm86 )
-    return (unsigned long)VM86_REG_(segment) << 4;
-  else if ( addr_modes.p286 )
-    return (unsigned long)LDT_BASE_ADDR(P286_REG_(segment));
-  return 0;
+  *selector = VM86_REG_(segment);
+  return (unsigned long)VM86_REG_(segment) << 4;
+}
+
+
+/* This should work for 16 and 32 bit protected mode. */
+static long pm_address(unsigned char FPU_modrm, unsigned char segment,
+		       unsigned short *selector, long offset)
+{ 
+  struct desc_struct descriptor;
+  unsigned long base_address, limit, address, seg_top;
+
+  segment--;
+#ifdef PARANOID
+  if ( segment > PREFIX_SS_ )
+    {
+      EXCEPTION(EX_INTERNAL|0x132);
+      math_abort(FPU_info,SIGSEGV);
+    }
+#endif PARANOID
+
+  *selector = PM_REG_(segment);
+
+  descriptor = LDT_DESCRIPTOR(PM_REG_(segment));
+  base_address = SEG_BASE_ADDR(descriptor);
+  address = base_address + offset;
+  limit = base_address
+	+ (SEG_LIMIT(descriptor)+1) * SEG_GRANULARITY(descriptor) - 1;
+  if ( limit < base_address ) limit = 0xffffffff;
+
+  if ( SEG_EXPAND_DOWN(descriptor) )
+    {
+      if ( SEG_G_BIT(descriptor) )
+	seg_top = 0xffffffff;
+      else
+	{
+	  seg_top = base_address + (1 << 20);
+	  if ( seg_top < base_address ) seg_top = 0xffffffff;
+	}
+      access_limit =
+	(address <= limit) || (address >= seg_top) ? 0 :
+	  ((seg_top-address) >= 255 ? 255 : seg_top-address);
+    }
+  else
+    {
+      access_limit =
+	(address > limit) || (address < base_address) ? 0 :
+	  ((limit-address) >= 254 ? 255 : limit-address+1);
+    }
+  if ( SEG_EXECUTE_ONLY(descriptor) ||
+      (!SEG_WRITE_PERM(descriptor) && (FPU_modrm & FPU_WRITE_BIT)) )
+    {
+      access_limit = 0;
+    }
+  return address;
 }
 
 
@@ -157,117 +211,132 @@
 
 */
 
-void get_address(unsigned char FPU_modrm, unsigned long *fpu_eip,
-		 fpu_addr_modes addr_modes)
+void *get_address(unsigned char FPU_modrm, unsigned long *fpu_eip,
+		  struct address *addr,
+/*		  unsigned short *selector, unsigned long *offset, */
+		  fpu_addr_modes addr_modes)
 {
   unsigned char mod;
+  unsigned rm = FPU_modrm & 7;
   long *cpu_reg_ptr;
-  int offset = 0;     /* Initialized just to stop compiler warnings. */
-
-#ifndef PECULIAR_486
-  /* This is a reasonable place to do this */
-  FPU_data_selector = FPU_DS;
-#endif PECULIAR_486
+  int address = 0;     /* Initialized just to stop compiler warnings. */
 
   /* Memory accessed via the cs selector is write protected
-     in protected mode. */
-#define FPU_WRITE_BIT 0x10
-  if ( !addr_modes.vm86 && (FPU_modrm & FPU_WRITE_BIT)
+     in `non-segmented' 32 bit protected mode. */
+  if ( !addr_modes.default_mode && (FPU_modrm & FPU_WRITE_BIT)
       && (addr_modes.override.segment == PREFIX_CS_) )
     {
       math_abort(FPU_info,SIGSEGV);
     }
 
+  addr->selector = FPU_DS;   /* Default, for 32 bit non-segmented mode. */
+
   mod = (FPU_modrm >> 6) & 3;
 
-  if (FPU_rm == 4 && mod != 3)
+  if (rm == 4 && mod != 3)
     {
-      FPU_data_address = sib(mod, fpu_eip);
-      return;
+      address = sib(mod, fpu_eip);
     }
-
-  cpu_reg_ptr = & REG_(FPU_rm);
-  switch (mod)
+  else
     {
-    case 0:
-      if (FPU_rm == 5)
+      cpu_reg_ptr = & REG_(rm);
+      switch (mod)
 	{
-	  /* Special case: disp32 */
+	case 0:
+	  if (rm == 5)
+	    {
+	      /* Special case: disp32 */
+	      RE_ENTRANT_CHECK_OFF;
+	      FPU_code_verify_area(4);
+	      address = get_fs_long((unsigned long *) (*fpu_eip));
+	      (*fpu_eip) += 4;
+	      RE_ENTRANT_CHECK_ON;
+	      addr->offset = address;
+	      return (void *) address;
+	    }
+	  else
+	    {
+	      address = *cpu_reg_ptr;  /* Just return the contents
+					  of the cpu register */
+	      addr->offset = address;
+	      return (void *) address;
+	    }
+	case 1:
+	  /* 8 bit signed displacement */
 	  RE_ENTRANT_CHECK_OFF;
+	  FPU_code_verify_area(1);
+	  address = (signed char) get_fs_byte((char *) (*fpu_eip));
+	  RE_ENTRANT_CHECK_ON;
+	  (*fpu_eip)++;
+	  break;
+	case 2:
+	  /* 32 bit displacement */
+	  RE_ENTRANT_CHECK_OFF;
 	  FPU_code_verify_area(4);
-	  offset = get_fs_long((unsigned long *) (*fpu_eip));
+	  address = (signed) get_fs_long((unsigned long *) (*fpu_eip));
 	  (*fpu_eip) += 4;
 	  RE_ENTRANT_CHECK_ON;
-	  FPU_data_address = (void *) offset;
-	  return;
-	}
-      else
-	{
-	  FPU_data_address = (void *)*cpu_reg_ptr;  /* Just return the contents
-						   of the cpu register */
-	  return;
+	  break;
+	case 3:
+	  /* Not legal for the FPU */
+	  EXCEPTION(EX_Invalid);
 	}
-    case 1:
-      /* 8 bit signed displacement */
-      RE_ENTRANT_CHECK_OFF;
-      FPU_code_verify_area(1);
-      offset = (signed char) get_fs_byte((char *) (*fpu_eip));
-      RE_ENTRANT_CHECK_ON;
-      (*fpu_eip)++;
-      break;
-    case 2:
-      /* 32 bit displacement */
-      RE_ENTRANT_CHECK_OFF;
-      FPU_code_verify_area(4);
-      offset = (signed) get_fs_long((unsigned long *) (*fpu_eip));
-      (*fpu_eip) += 4;
-      RE_ENTRANT_CHECK_ON;
-      break;
-    case 3:
-      /* Not legal for the FPU */
-      EXCEPTION(EX_Invalid);
+      address += *cpu_reg_ptr;
     }
 
-  if ( addr_modes.mode16 )
+  addr->offset = address;
+
+  switch ( addr_modes.default_mode )
     {
-      offset += mode16_segment(addr_modes);
+    case 0:
+      break;
+    case VM86:
+      address += vm86_segment(addr_modes.override.segment,
+			      (unsigned short *)&(addr->selector));
+      break;
+    case PM16:
+    case SEG32:
+      address = pm_address(FPU_modrm, addr_modes.override.segment,
+			   (unsigned short *)&(addr->selector), address);
+      break;
+    default:
+      EXCEPTION(EX_INTERNAL|0x133);
     }
 
-  FPU_data_address = offset + (char *)*cpu_reg_ptr;
+  return (void *)address;
 }
 
 
-void get_address_16(unsigned char FPU_modrm, unsigned long *fpu_eip,
-		      fpu_addr_modes addr_modes)
+void *get_address_16(unsigned char FPU_modrm, unsigned long *fpu_eip,
+		     struct address *addr,
+/*		     unsigned short *selector, unsigned long *offset, */
+		     fpu_addr_modes addr_modes)
 {
   unsigned char mod;
-  int offset = 0;     /* Default used for mod == 0 */
+  unsigned rm = FPU_modrm & 7;
+  int address = 0;     /* Default used for mod == 0 */
 
-#ifndef PECULIAR_486
-  /* This is a reasonable place to do this */
-  FPU_data_selector = FPU_DS;
-#endif PECULIAR_486
-
   /* Memory accessed via the cs selector is write protected
-     in protected mode. */
-#define FPU_WRITE_BIT 0x10
-  if ( !addr_modes.vm86 && (FPU_modrm & FPU_WRITE_BIT)
+     in `non-segmented' 32 bit protected mode. */
+  if ( !addr_modes.default_mode && (FPU_modrm & FPU_WRITE_BIT)
       && (addr_modes.override.segment == PREFIX_CS_) )
     {
       math_abort(FPU_info,SIGSEGV);
     }
 
+  addr->selector = FPU_DS;   /* Default, for 32 bit non-segmented mode. */
+
   mod = (FPU_modrm >> 6) & 3;
 
   switch (mod)
     {
     case 0:
-      if (FPU_rm == 6)
+      if (rm == 6)
 	{
 	  /* Special case: disp16 */
 	  RE_ENTRANT_CHECK_OFF;
 	  FPU_code_verify_area(2);
-	  offset = (unsigned short)get_fs_word((unsigned short *) (*fpu_eip));
+	  address = (unsigned short)get_fs_word((unsigned short *) (*fpu_eip));
 	  (*fpu_eip) += 2;
 	  RE_ENTRANT_CHECK_ON;
 	  goto add_segment;
@@ -277,7 +346,7 @@
       /* 8 bit signed displacement */
       RE_ENTRANT_CHECK_OFF;
       FPU_code_verify_area(1);
-      offset = (signed char) get_fs_byte((signed char *) (*fpu_eip));
+      address = (signed char) get_fs_byte((signed char *) (*fpu_eip));
       RE_ENTRANT_CHECK_ON;
       (*fpu_eip)++;
       break;
@@ -285,7 +354,7 @@
       /* 16 bit displacement */
       RE_ENTRANT_CHECK_OFF;
       FPU_code_verify_area(2);
-      offset = (unsigned) get_fs_word((unsigned short *) (*fpu_eip));
+      address = (unsigned) get_fs_word((unsigned short *) (*fpu_eip));
       (*fpu_eip) += 2;
       RE_ENTRANT_CHECK_ON;
       break;
@@ -294,47 +363,61 @@
       EXCEPTION(EX_Invalid);
       break;
     }
-  switch ( FPU_rm )
+  switch ( rm )
     {
     case 0:
-      offset += FPU_info->___ebx + FPU_info->___esi;
+      address += FPU_info->___ebx + FPU_info->___esi;
       break;
     case 1:
-      offset += FPU_info->___ebx + FPU_info->___edi;
+      address += FPU_info->___ebx + FPU_info->___edi;
       break;
     case 2:
-      offset += FPU_info->___ebp + FPU_info->___esi;
+      address += FPU_info->___ebp + FPU_info->___esi;
       if ( addr_modes.override.segment == PREFIX_DEFAULT )
 	addr_modes.override.segment = PREFIX_SS_;
       break;
     case 3:
-      offset += FPU_info->___ebp + FPU_info->___edi;
+      address += FPU_info->___ebp + FPU_info->___edi;
       if ( addr_modes.override.segment == PREFIX_DEFAULT )
 	addr_modes.override.segment = PREFIX_SS_;
       break;
     case 4:
-      offset += FPU_info->___esi;
+      address += FPU_info->___esi;
       break;
     case 5:
-      offset += FPU_info->___edi;
+      address += FPU_info->___edi;
       break;
     case 6:
-      offset += FPU_info->___ebp;
+      address += FPU_info->___ebp;
       if ( addr_modes.override.segment == PREFIX_DEFAULT )
 	addr_modes.override.segment = PREFIX_SS_;
       break;
     case 7:
-      offset += FPU_info->___ebx;
+      address += FPU_info->___ebx;
       break;
     }
 
  add_segment:
-  offset &= 0xffff;
+  address &= 0xffff;
+
+  addr->offset = address;
 
-  if ( addr_modes.mode16 )
+  switch ( addr_modes.default_mode )
     {
-      offset += mode16_segment(addr_modes);
+    case 0:
+      break;
+    case VM86:
+      address += vm86_segment(addr_modes.override.segment,
+			      (unsigned short *)&(addr->selector));
+      break;
+    case PM16:
+    case SEG32:
+      address = pm_address(FPU_modrm, addr_modes.override.segment,
+			   (unsigned short *)&(addr->selector), address);
+      break;
+    default:
+      EXCEPTION(EX_INTERNAL|0x131);
     }
 
-  FPU_data_address = (void *)offset ;
+  return (void *)address ;
 }
diff -u --recursive --new-file v1.1.17/linux/drivers/FPU-emu/load_store.c linux/drivers/FPU-emu/load_store.c
--- v1.1.17/linux/drivers/FPU-emu/load_store.c	Mon Feb 14 13:10:46 1994
+++ linux/drivers/FPU-emu/load_store.c	Thu Jun  2 10:28:26 1994
@@ -27,12 +27,12 @@
 #include "control_w.h"
 
 
-#define _NONE_ 0   /* FPU_st0_ptr etc not needed */
+#define _NONE_ 0   /* st0_ptr etc not needed */
 #define _REG0_ 1   /* Will be storing st(0) */
 #define _PUSH_ 3   /* Need to check for space to push onto stack */
 #define _null_ 4   /* Function illegal or not implemented */
 
-#define pop_0()	{ pop_ptr->tag = TW_Empty; top++; }
+#define pop_0()	{ st0_ptr->tag = TW_Empty; top++; }
 
 
 static unsigned char const type_table[32] = {
@@ -46,192 +46,215 @@
   _NONE_, _REG0_, _NONE_, _REG0_
   };
 
-void load_store_instr(char type, fpu_addr_modes addr_modes)
+unsigned char const data_sizes_16[32] = {
+  4,  4,  8,  2,  0,  0,  0,  0,
+  4,  4,  8,  2,  4,  4,  8,  2,
+  14, 0, 94, 10,  2, 10,  0,  8,  
+  14, 0, 94, 10,  2, 10,  2,  8
+};
+
+unsigned char const data_sizes_32[32] = {
+  4,  4,  8,  2,  0,  0,  0,  0,
+  4,  4,  8,  2,  4,  4,  8,  2,
+  28, 0,108, 10,  2, 10,  0,  8,  
+  28, 0,108, 10,  2, 10,  2,  8
+};
+
+int load_store_instr(unsigned char type, fpu_addr_modes addr_modes,
+		     void *data_address)
 {
-  FPU_REG *pop_ptr;  /* We need a version of FPU_st0_ptr which won't
-			change if the emulator is re-entered. */
+  FPU_REG loaded_data;
+  FPU_REG *st0_ptr;
+
+  st0_ptr = NULL;    /* Initialized just to stop compiler warnings. */
+
+  if ( addr_modes.default_mode & PROTECTED )
+    {
+      if ( addr_modes.default_mode == SEG32 )
+	{
+	  if ( access_limit < data_sizes_32[type] )
+	    math_abort(FPU_info,SIGSEGV);
+	}
+      else if ( addr_modes.default_mode == PM16 )
+	{
+	  if ( access_limit < data_sizes_16[type] )
+	    math_abort(FPU_info,SIGSEGV);
+	}
+#ifdef PARANOID
+      else
+	EXCEPTION(EX_INTERNAL|0x140);
+#endif PARANOID
+    }
 
-  pop_ptr = NULL;    /* Initialized just to stop compiler warnings. */
-  switch ( type_table[(int) (unsigned) type] )
+  switch ( type_table[type] )
     {
     case _NONE_:
       break;
     case _REG0_:
-      pop_ptr = &st(0);       /* Some of these instructions pop after
+      st0_ptr = &st(0);       /* Some of these instructions pop after
 				 storing */
-
-      FPU_st0_ptr = pop_ptr;      /* Set the global variables. */
-      FPU_st0_tag = FPU_st0_ptr->tag;
       break;
     case _PUSH_:
       {
-	pop_ptr = &st(-1);
-	if ( pop_ptr->tag != TW_Empty )
-	  { stack_overflow(); return; }
+	st0_ptr = &st(-1);
+	if ( st0_ptr->tag != TW_Empty )
+	  { stack_overflow(); return 0; }
 	top--;
       }
       break;
     case _null_:
       FPU_illegal();
-      return;
+      return 0;
 #ifdef PARANOID
     default:
-      EXCEPTION(EX_INTERNAL);
-      return;
+      EXCEPTION(EX_INTERNAL|0x141);
+      return 0;
 #endif PARANOID
     }
 
-switch ( type )
-  {
-  case 000:       /* fld m32real */
-    clear_C1();
-    reg_load_single();
-    if ( (FPU_loaded_data.tag == TW_NaN) &&
-	real_2op_NaN(&FPU_loaded_data, &FPU_loaded_data, &FPU_loaded_data) )
-      {
-	top++;
-	break;
-      }
-    reg_move(&FPU_loaded_data, pop_ptr);
-    break;
-  case 001:      /* fild m32int */
-    clear_C1();
-    reg_load_int32();
-    reg_move(&FPU_loaded_data, pop_ptr);
-    break;
-  case 002:      /* fld m64real */
-    clear_C1();
-    reg_load_double();
-    if ( (FPU_loaded_data.tag == TW_NaN) &&
-	real_2op_NaN(&FPU_loaded_data, &FPU_loaded_data, &FPU_loaded_data) )
-      {
-	top++;
-	break;
-      }
-    reg_move(&FPU_loaded_data, pop_ptr);
-    break;
-  case 003:      /* fild m16int */
-    clear_C1();
-    reg_load_int16();
-    reg_move(&FPU_loaded_data, pop_ptr);
-    break;
-  case 010:      /* fst m32real */
-    clear_C1();
-    reg_store_single();
-    break;
-  case 011:      /* fist m32int */
-    clear_C1();
-    reg_store_int32();
-    break;
-  case 012:     /* fst m64real */
-    clear_C1();
-    reg_store_double();
-    break;
-  case 013:     /* fist m16int */
-    clear_C1();
-    reg_store_int16();
-    break;
-  case 014:     /* fstp m32real */
-    clear_C1();
-    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 */
-    clear_C1();
-    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 */
-    clear_C1();
-    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 */
-    clear_C1();
-    if ( reg_store_int16() )
-      pop_0();  /* pop only if the number was actually stored
-		 (see the 80486 manual p16-28) */
-    break;
-  case 020:     /* fldenv  m14/28byte */
-    fldenv(addr_modes);
-    break;
-  case 022:     /* frstor m94/108byte */
-    frstor(addr_modes);
-    break;
-  case 023:     /* fbld m80dec */
-    clear_C1();
-    reg_load_bcd();
-    reg_move(&FPU_loaded_data, pop_ptr);
-    break;
-  case 024:     /* fldcw */
-    RE_ENTRANT_CHECK_OFF;
-    FPU_verify_area(VERIFY_READ, FPU_data_address, 2);
-    control_word = get_fs_word((unsigned short *) FPU_data_address);
-    RE_ENTRANT_CHECK_ON;
-    if ( partial_status & ~control_word & CW_Exceptions )
-      partial_status |= (SW_Summary | SW_Backward);
-    else
-      partial_status &= ~(SW_Summary | SW_Backward);
+  switch ( type )
+    {
+    case 000:       /* fld m32real */
+      clear_C1();
+      reg_load_single((float *)data_address, &loaded_data);
+      if ( (loaded_data.tag == TW_NaN) &&
+	  real_2op_NaN(&loaded_data, &loaded_data, &loaded_data) )
+	{
+	  top++;
+	  break;
+	}
+      reg_move(&loaded_data, st0_ptr);
+      break;
+    case 001:      /* fild m32int */
+      clear_C1();
+      reg_load_int32((long *)data_address, st0_ptr);
+      break;
+    case 002:      /* fld m64real */
+      clear_C1();
+      reg_load_double((double *)data_address, &loaded_data);
+      if ( (loaded_data.tag == TW_NaN) &&
+	  real_2op_NaN(&loaded_data, &loaded_data, &loaded_data) )
+	{
+	  top++;
+	  break;
+	}
+      reg_move(&loaded_data, st0_ptr);
+      break;
+    case 003:      /* fild m16int */
+      clear_C1();
+      reg_load_int16((short *)data_address, st0_ptr);
+      break;
+    case 010:      /* fst m32real */
+      clear_C1();
+      reg_store_single((float *)data_address, st0_ptr);
+      break;
+    case 011:      /* fist m32int */
+      clear_C1();
+      reg_store_int32((long *)data_address, st0_ptr);
+      break;
+    case 012:     /* fst m64real */
+      clear_C1();
+      reg_store_double((double *)data_address, st0_ptr);
+      break;
+    case 013:     /* fist m16int */
+      clear_C1();
+      reg_store_int16((short *)data_address, st0_ptr);
+      break;
+    case 014:     /* fstp m32real */
+      clear_C1();
+      if ( reg_store_single((float *)data_address, st0_ptr) )
+	pop_0();  /* pop only if the number was actually stored
+		     (see the 80486 manual p16-28) */
+      break;
+    case 015:     /* fistp m32int */
+      clear_C1();
+      if ( reg_store_int32((long *)data_address, st0_ptr) )
+	pop_0();  /* pop only if the number was actually stored
+		     (see the 80486 manual p16-28) */
+      break;
+    case 016:     /* fstp m64real */
+      clear_C1();
+      if ( reg_store_double((double *)data_address, st0_ptr) )
+	pop_0();  /* pop only if the number was actually stored
+		     (see the 80486 manual p16-28) */
+      break;
+    case 017:     /* fistp m16int */
+      clear_C1();
+      if ( reg_store_int16((short *)data_address, st0_ptr) )
+	pop_0();  /* pop only if the number was actually stored
+		     (see the 80486 manual p16-28) */
+      break;
+    case 020:     /* fldenv  m14/28byte */
+      fldenv(addr_modes, (char *)data_address);
+      /* Ensure that the values just loaded are not changed by
+	 fix-up operations. */
+      return 1;
+    case 022:     /* frstor m94/108byte */
+      frstor(addr_modes, (char *)data_address);
+      /* Ensure that the values just loaded are not changed by
+	 fix-up operations. */
+      return 1;
+    case 023:     /* fbld m80dec */
+      clear_C1();
+      reg_load_bcd((char *)data_address, st0_ptr);
+      break;
+    case 024:     /* fldcw */
+      RE_ENTRANT_CHECK_OFF;
+      FPU_verify_area(VERIFY_READ, data_address, 2);
+      control_word = get_fs_word((unsigned short *) data_address);
+      RE_ENTRANT_CHECK_ON;
+      if ( partial_status & ~control_word & CW_Exceptions )
+	partial_status |= (SW_Summary | SW_Backward);
+      else
+	partial_status &= ~(SW_Summary | SW_Backward);
 #ifdef PECULIAR_486
-    control_word |= 0x40;  /* An 80486 appears to always set this bit */
+      control_word |= 0x40;  /* An 80486 appears to always set this bit */
 #endif PECULIAR_486
-    NO_NET_DATA_EFFECT;
-    NO_NET_INSTR_EFFECT;
-    break;
-  case 025:      /* fld m80real */
-    clear_C1();
-    reg_load_extended();
-    reg_move(&FPU_loaded_data, pop_ptr);
-    break;
-  case 027:      /* fild m64int */
-    clear_C1();
-    reg_load_int64();
-    reg_move(&FPU_loaded_data, pop_ptr);
-    break;
-  case 030:     /* fstenv  m14/28byte */
-    fstenv(addr_modes);
-    NO_NET_DATA_EFFECT;
-    break;
-  case 032:      /* fsave */
-    fsave(addr_modes);
-    NO_NET_DATA_EFFECT;
-    break;
-  case 033:      /* fbstp m80dec */
-    clear_C1();
-    if ( reg_store_bcd() )
-      pop_0();  /* pop only if the number was actually stored
-		 (see the 80486 manual p16-28) */
-    break;
-  case 034:      /* fstcw m16int */
-    RE_ENTRANT_CHECK_OFF;
-    FPU_verify_area(VERIFY_WRITE,FPU_data_address,2);
-    put_fs_word(control_word, (short *) FPU_data_address);
-    RE_ENTRANT_CHECK_ON;
-    NO_NET_DATA_EFFECT;
-    NO_NET_INSTR_EFFECT;
-    break;
-  case 035:      /* fstp m80real */
-    clear_C1();
-    if ( reg_store_extended() )
-      pop_0();  /* pop only if the number was actually stored
-		 (see the 80486 manual p16-28) */
-    break;
-  case 036:      /* fstsw m2byte */
-    RE_ENTRANT_CHECK_OFF;
-    FPU_verify_area(VERIFY_WRITE,FPU_data_address,2);
-    put_fs_word(status_word(),(short *) FPU_data_address);
-    RE_ENTRANT_CHECK_ON;
-    NO_NET_DATA_EFFECT;
-    NO_NET_INSTR_EFFECT;
-    break;
-  case 037:      /* fistp m64int */
-    clear_C1();
-    if ( reg_store_int64() )
-      pop_0();  /* pop only if the number was actually stored
-		 (see the 80486 manual p16-28) */
-    break;
-  }
+      return 1;
+    case 025:      /* fld m80real */
+      clear_C1();
+      reg_load_extended((long double *)data_address, st0_ptr);
+      break;
+    case 027:      /* fild m64int */
+      clear_C1();
+      reg_load_int64((long long *)data_address, st0_ptr);
+      break;
+    case 030:     /* fstenv  m14/28byte */
+      fstenv(addr_modes, (char *)data_address);
+      return 1;
+    case 032:      /* fsave */
+      fsave(addr_modes, (char *)data_address);
+      return 1;
+    case 033:      /* fbstp m80dec */
+      clear_C1();
+      if ( reg_store_bcd((char *)data_address, st0_ptr) )
+	pop_0();  /* pop only if the number was actually stored
+		     (see the 80486 manual p16-28) */
+      break;
+    case 034:      /* fstcw m16int */
+      RE_ENTRANT_CHECK_OFF;
+      FPU_verify_area(VERIFY_WRITE,data_address,2);
+      put_fs_word(control_word, (short *) data_address);
+      RE_ENTRANT_CHECK_ON;
+      return 1;
+    case 035:      /* fstp m80real */
+      clear_C1();
+      if ( reg_store_extended((long double *)data_address, st0_ptr) )
+	pop_0();  /* pop only if the number was actually stored
+		     (see the 80486 manual p16-28) */
+      break;
+    case 036:      /* fstsw m2byte */
+      RE_ENTRANT_CHECK_OFF;
+      FPU_verify_area(VERIFY_WRITE,data_address,2);
+      put_fs_word(status_word(),(short *) data_address);
+      RE_ENTRANT_CHECK_ON;
+      return 1;
+    case 037:      /* fistp m64int */
+      clear_C1();
+      if ( reg_store_int64((long long *)data_address, st0_ptr) )
+	pop_0();  /* pop only if the number was actually stored
+		     (see the 80486 manual p16-28) */
+      break;
+    }
+  return 0;
 }
diff -u --recursive --new-file v1.1.17/linux/drivers/FPU-emu/poly_atan.c linux/drivers/FPU-emu/poly_atan.c
--- v1.1.17/linux/drivers/FPU-emu/poly_atan.c	Wed Dec  1 14:44:16 1993
+++ linux/drivers/FPU-emu/poly_atan.c	Thu Jun  2 10:28:26 1994
@@ -187,15 +187,7 @@
    for the use of this function in poly_atan. Simple truncation
    is used here instead of round-to-nearest. */
 
-#ifdef OBSOLETE
-char round = (src->sigl & 3) == 3;
-#endif OBSOLETE
-
 shrx(&src->sigl, 1);
-
-#ifdef OBSOLETE
-if ( round ) significand(src)++;   /* Round to even */
-#endif OBSOLETE
 
 src->sigh |= 0x80000000;
 
diff -u --recursive --new-file v1.1.17/linux/drivers/FPU-emu/reg_compare.c linux/drivers/FPU-emu/reg_compare.c
--- v1.1.17/linux/drivers/FPU-emu/reg_compare.c	Thu Feb  3 12:11:39 1994
+++ linux/drivers/FPU-emu/reg_compare.c	Thu Jun  2 10:28:27 1994
@@ -24,10 +24,15 @@
 int compare(FPU_REG const *b)
 {
   int diff;
+  char	       st0_tag;
+  FPU_REG      *st0_ptr;
 
-  if ( FPU_st0_ptr->tag | b->tag )
+  st0_ptr = &st(0);
+  st0_tag = st0_ptr->tag;
+
+  if ( st0_tag | b->tag )
     {
-      if ( FPU_st0_ptr->tag == TW_Zero )
+      if ( st0_tag == TW_Zero )
 	{
 	  if ( b->tag == TW_Zero ) return COMP_A_eq_B;
 	  if ( b->tag == TW_Valid )
@@ -42,23 +47,23 @@
 	}
       else if ( b->tag == TW_Zero )
 	{
-	  if ( FPU_st0_ptr->tag == TW_Valid )
+	  if ( st0_tag == TW_Valid )
 	    {
-	      return ((FPU_st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B
+	      return ((st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B
 		      : COMP_A_lt_B)
 #ifdef DENORM_OPERAND
-		| ((FPU_st0_ptr->exp <= EXP_UNDER )
+		| ((st0_ptr->exp <= EXP_UNDER )
 		   ? COMP_Denormal : 0 )
 #endif DENORM_OPERAND
 		  ;
 	    }
 	}
 
-      if ( FPU_st0_ptr->tag == TW_Infinity )
+      if ( st0_tag == TW_Infinity )
 	{
 	  if ( (b->tag == TW_Valid) || (b->tag == TW_Zero) )
 	    {
-	      return ((FPU_st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B
+	      return ((st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B
 		      : COMP_A_lt_B)
 #ifdef DENORM_OPERAND
 	      | (((b->tag == TW_Valid) && (b->exp <= EXP_UNDER)) ?
@@ -69,19 +74,19 @@
 	  else if ( b->tag == TW_Infinity )
 	    {
 	      /* The 80486 book says that infinities can be equal! */
-	      return (FPU_st0_ptr->sign == b->sign) ? COMP_A_eq_B :
-		((FPU_st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B);
+	      return (st0_ptr->sign == b->sign) ? COMP_A_eq_B :
+		((st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B);
 	    }
 	  /* Fall through to the NaN code */
 	}
       else if ( b->tag == TW_Infinity )
 	{
-	  if ( (FPU_st0_ptr->tag == TW_Valid) || (FPU_st0_ptr->tag == TW_Zero) )
+	  if ( (st0_tag == TW_Valid) || (st0_tag == TW_Zero) )
 	    {
 	      return ((b->sign == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B)
 #ifdef DENORM_OPERAND
-		| (((FPU_st0_ptr->tag == TW_Valid)
-		    && (FPU_st0_ptr->exp <= EXP_UNDER)) ?
+		| (((st0_tag == TW_Valid)
+		    && (st0_ptr->exp <= EXP_UNDER)) ?
 		   COMP_Denormal : 0)
 #endif DENORM_OPERAND
 		  ;
@@ -91,9 +96,9 @@
 
       /* The only possibility now should be that one of the arguments
 	 is a NaN */
-      if ( (FPU_st0_ptr->tag == TW_NaN) || (b->tag == TW_NaN) )
+      if ( (st0_tag == TW_NaN) || (b->tag == TW_NaN) )
 	{
-	  if ( ((FPU_st0_ptr->tag == TW_NaN) && !(FPU_st0_ptr->sigh & 0x40000000))
+	  if ( ((st0_tag == TW_NaN) && !(st0_ptr->sigh & 0x40000000))
 	      || ((b->tag == TW_NaN) && !(b->sigh & 0x40000000)) )
 	    /* At least one arg is a signaling NaN */
 	    return COMP_No_Comp | COMP_SNaN | COMP_NaN;
@@ -106,51 +111,51 @@
     }
   
 #ifdef PARANOID
-  if (!(FPU_st0_ptr->sigh & 0x80000000)) EXCEPTION(EX_Invalid);
+  if (!(st0_ptr->sigh & 0x80000000)) EXCEPTION(EX_Invalid);
   if (!(b->sigh & 0x80000000)) EXCEPTION(EX_Invalid);
 #endif PARANOID
 
   
-  if (FPU_st0_ptr->sign != b->sign)
+  if (st0_ptr->sign != b->sign)
     {
-      return ((FPU_st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
+      return ((st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
 #ifdef DENORM_OPERAND
 	|
-	  ( ((FPU_st0_ptr->exp <= EXP_UNDER) || (b->exp <= EXP_UNDER)) ?
+	  ( ((st0_ptr->exp <= EXP_UNDER) || (b->exp <= EXP_UNDER)) ?
 	   COMP_Denormal : 0)
 #endif DENORM_OPERAND
 	    ;
     }
 
-  diff = FPU_st0_ptr->exp - b->exp;
+  diff = st0_ptr->exp - b->exp;
   if ( diff == 0 )
     {
-      diff = FPU_st0_ptr->sigh - b->sigh;  /* Works only if ms bits are
+      diff = st0_ptr->sigh - b->sigh;  /* Works only if ms bits are
 					      identical */
       if ( diff == 0 )
 	{
-	diff = FPU_st0_ptr->sigl > b->sigl;
+	diff = st0_ptr->sigl > b->sigl;
 	if ( diff == 0 )
-	  diff = -(FPU_st0_ptr->sigl < b->sigl);
+	  diff = -(st0_ptr->sigl < b->sigl);
 	}
     }
 
   if ( diff > 0 )
     {
-      return ((FPU_st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
+      return ((st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
 #ifdef DENORM_OPERAND
 	|
-	  ( ((FPU_st0_ptr->exp <= EXP_UNDER) || (b->exp <= EXP_UNDER)) ?
+	  ( ((st0_ptr->exp <= EXP_UNDER) || (b->exp <= EXP_UNDER)) ?
 	   COMP_Denormal : 0)
 #endif DENORM_OPERAND
 	    ;
     }
   if ( diff < 0 )
     {
-      return ((FPU_st0_ptr->sign == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B)
+      return ((st0_ptr->sign == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B)
 #ifdef DENORM_OPERAND
 	|
-	  ( ((FPU_st0_ptr->exp <= EXP_UNDER) || (b->exp <= EXP_UNDER)) ?
+	  ( ((st0_ptr->exp <= EXP_UNDER) || (b->exp <= EXP_UNDER)) ?
 	   COMP_Denormal : 0)
 #endif DENORM_OPERAND
 	    ;
@@ -159,7 +164,7 @@
   return COMP_A_eq_B
 #ifdef DENORM_OPERAND
     |
-      ( ((FPU_st0_ptr->exp <= EXP_UNDER) || (b->exp <= EXP_UNDER)) ?
+      ( ((st0_ptr->exp <= EXP_UNDER) || (b->exp <= EXP_UNDER)) ?
        COMP_Denormal : 0)
 #endif DENORM_OPERAND
 	;
@@ -168,11 +173,11 @@
 
 
 /* This function requires that st(0) is not empty */
-int compare_st_data(void)
+int compare_st_data(FPU_REG const *loaded_data)
 {
   int f, c;
 
-  c = compare(&FPU_loaded_data);
+  c = compare(loaded_data);
 
   if (c & COMP_NaN)
     {
@@ -214,7 +219,7 @@
 {
   int f, c;
 
-  if ( !NOT_EMPTY_0 || !NOT_EMPTY(nr) )
+  if ( !NOT_EMPTY(0) || !NOT_EMPTY(nr) )
     {
       setcc(SW_C3 | SW_C2 | SW_C0);
       /* Stack fault */
@@ -264,7 +269,7 @@
 {
   int f, c;
 
-  if ( !NOT_EMPTY_0 || !NOT_EMPTY(nr) )
+  if ( !NOT_EMPTY(0) || !NOT_EMPTY(nr) )
     {
       setcc(SW_C3 | SW_C2 | SW_C0);
       /* Stack fault */
@@ -340,10 +345,7 @@
       return;
     }
   if ( !compare_st_st(1) )
-    {
-      pop(); FPU_st0_ptr = &st(0);
-      pop();
-    }
+      poppop();
 }
 
 
@@ -369,10 +371,7 @@
   if (FPU_rm == 1)
     {
       if ( !compare_u_st_st(1) )
-	{
-	  pop(); FPU_st0_ptr = &st(0);
-	  pop();
-	}
+	poppop();
     }
   else
     FPU_illegal();
diff -u --recursive --new-file v1.1.17/linux/drivers/FPU-emu/reg_constant.c linux/drivers/FPU-emu/reg_constant.c
--- v1.1.17/linux/drivers/FPU-emu/reg_constant.c	Thu Feb  3 12:11:40 1994
+++ linux/drivers/FPU-emu/reg_constant.c	Thu Jun  2 10:28:27 1994
@@ -66,7 +66,7 @@
       return;
     }
   push();
-  reg_move(c, FPU_st0_ptr);
+  reg_move(c, st_new_ptr);
   clear_C1();
 }
 
diff -u --recursive --new-file v1.1.17/linux/drivers/FPU-emu/reg_div.S linux/drivers/FPU-emu/reg_div.S
--- v1.1.17/linux/drivers/FPU-emu/reg_div.S	Thu Feb  3 12:11:40 1994
+++ linux/drivers/FPU-emu/reg_div.S	Thu Jun  2 10:28:27 1994
@@ -25,9 +25,9 @@
 _reg_div:
 	pushl	%ebp
 	movl	%esp,%ebp
-#ifdef REENTRANT_FPU
+#ifndef NON_REENTRANT_FPU
 	subl	$28,%esp	/* Needed by divide_kernel */
-#endif REENTRANT_FPU
+#endif NON_REENTRANT_FPU
 
 	pushl	%esi
 	pushl	%edi
@@ -214,11 +214,11 @@
 	xorl	%eax,%eax		/* Valid result */
 
 LDiv_exit:
-#ifdef REENTRANT_FPU
+#ifndef NON_REENTRANT_FPU
 	leal	-40(%ebp),%esp
 #else
 	leal	-12(%ebp),%esp
-#endif REENTRANT_FPU
+#endif NON_REENTRANT_FPU
 
 	popl	%ebx
 	popl	%edi
diff -u --recursive --new-file v1.1.17/linux/drivers/FPU-emu/reg_ld_str.c linux/drivers/FPU-emu/reg_ld_str.c
--- v1.1.17/linux/drivers/FPU-emu/reg_ld_str.c	Tue May 24 00:34:46 1994
+++ linux/drivers/FPU-emu/reg_ld_str.c	Thu Jun  2 10:28:28 1994
@@ -40,42 +40,34 @@
 
 static void write_to_extended(FPU_REG *rp, char *d);
 
-FPU_REG FPU_loaded_data;
 
-
 /* Get a long double from user memory */
-int reg_load_extended(void)
+int reg_load_extended(long double *s, FPU_REG *loaded_data)
 {
-  long double *s = (long double *)FPU_data_address;
   unsigned long sigl, sigh, exp;
 
   RE_ENTRANT_CHECK_OFF;
   FPU_verify_area(VERIFY_READ, s, 10);
-  /* Use temporary variables here because FPU_loaded data is
-     static and hence re-entrancy problems can arise */
   sigl = get_fs_long((unsigned long *) s);
   sigh = get_fs_long(1 + (unsigned long *) s);
   exp = get_fs_word(4 + (unsigned short *) s);
   RE_ENTRANT_CHECK_ON;
 
-  FPU_loaded_data.tag = TW_Valid;   /* Default */
-  FPU_loaded_data.sigl = sigl;
-  FPU_loaded_data.sigh = sigh;
+  loaded_data->tag = TW_Valid;   /* Default */
+  loaded_data->sigl = sigl;
+  loaded_data->sigh = sigh;
   if (exp & 0x8000)
-    FPU_loaded_data.sign = SIGN_NEG;
+    loaded_data->sign = SIGN_NEG;
   else
-    FPU_loaded_data.sign = SIGN_POS;
+    loaded_data->sign = SIGN_POS;
   exp &= 0x7fff;
-  FPU_loaded_data.exp = exp - EXTENDED_Ebias + EXP_BIAS;
+  loaded_data->exp = exp - EXTENDED_Ebias + EXP_BIAS;
 
-  /* Assume that optimisation can keep sigl, sigh, and exp in
-     registers, otherwise it would be more efficient to work
-     with FPU_loaded_data (which is static) here. */
   if ( exp == 0 )
     {
       if ( !(sigh | sigl) )
 	{
-	  FPU_loaded_data.tag = TW_Zero;
+	  loaded_data->tag = TW_Zero;
 	  return 0;
 	}
       /* The number is a de-normal or pseudodenormal. */
@@ -85,15 +77,15 @@
 	  /* Convert it for internal use. */
 	  /* This is non-80486 behaviour because the number
 	     loses its 'denormal' identity. */
-	  FPU_loaded_data.exp++;
+	  loaded_data->exp++;
 	  return 1;
 	}
       else
 	{
 	  /* Is a denormal. */
 	  /* Convert it for internal use. */
-	  FPU_loaded_data.exp++;
-	  normalize_nuo(&FPU_loaded_data);
+	  loaded_data->exp++;
+	  normalize_nuo(loaded_data);
 	  return 0;
 	}
     }
@@ -102,13 +94,13 @@
       if ( !((sigh ^ 0x80000000) | sigl) )
 	{
 	  /* Matches the bit pattern for Infinity. */
-	  FPU_loaded_data.exp = EXP_Infinity;
-	  FPU_loaded_data.tag = TW_Infinity;
+	  loaded_data->exp = EXP_Infinity;
+	  loaded_data->tag = TW_Infinity;
 	  return 0;
 	}
 
-      FPU_loaded_data.exp = EXP_NaN;
-      FPU_loaded_data.tag = TW_NaN;
+      loaded_data->exp = EXP_NaN;
+      loaded_data->tag = TW_NaN;
       if ( !(sigh & 0x80000000) )
 	{
 	  /* NaNs have the ms bit set to 1. */
@@ -116,9 +108,9 @@
 	  /* This is non 80486 behaviour */
 	  /* This should generate an Invalid Operand exception
 	     later, so we convert it to a SNaN */
-	  FPU_loaded_data.sigh = 0x80000000;
-	  FPU_loaded_data.sigl = 0x00000001;
-	  FPU_loaded_data.sign = SIGN_NEG;
+	  loaded_data->sigh = 0x80000000;
+	  loaded_data->sigl = 0x00000001;
+	  loaded_data->sign = SIGN_NEG;
 	  return 1;
 	}
       return 0;
@@ -133,11 +125,11 @@
       /* This is non-80486 behaviour */
       /* This should generate an Invalid Operand exception
 	 later, so we convert it to a SNaN */
-      FPU_loaded_data.sigh = 0x80000000;
-      FPU_loaded_data.sigl = 0x00000001;
-      FPU_loaded_data.sign = SIGN_NEG;
-      FPU_loaded_data.exp = EXP_NaN;
-      FPU_loaded_data.tag = TW_NaN;
+      loaded_data->sigh = 0x80000000;
+      loaded_data->sigl = 0x00000001;
+      loaded_data->sign = SIGN_NEG;
+      loaded_data->exp = EXP_NaN;
+      loaded_data->tag = TW_NaN;
       return 1;
     }
   return 0;
@@ -145,9 +137,8 @@
 
 
 /* Get a double from user memory */
-int reg_load_double(void)
+int reg_load_double(double *dfloat, FPU_REG *loaded_data)
 {
-  double *dfloat = (double *)FPU_data_address;
   int exp;
   unsigned m64, l64;
 
@@ -158,9 +149,9 @@
   RE_ENTRANT_CHECK_ON;
 
   if (m64 & 0x80000000)
-    FPU_loaded_data.sign = SIGN_NEG;
+    loaded_data->sign = SIGN_NEG;
   else
-    FPU_loaded_data.sign = SIGN_POS;
+    loaded_data->sign = SIGN_POS;
   exp = ((m64 & 0x7ff00000) >> 20) - DOUBLE_Ebias;
   m64 &= 0xfffff;
   if (exp > DOUBLE_Emax)
@@ -169,20 +160,20 @@
       if ((m64 == 0) && (l64 == 0))
 	{
 	  /* +- infinity */
-	  FPU_loaded_data.sigh = 0x80000000;
-	  FPU_loaded_data.sigl = 0x00000000;
-	  FPU_loaded_data.exp = EXP_Infinity;
-	  FPU_loaded_data.tag = TW_Infinity;
+	  loaded_data->sigh = 0x80000000;
+	  loaded_data->sigl = 0x00000000;
+	  loaded_data->exp = EXP_Infinity;
+	  loaded_data->tag = TW_Infinity;
 	  return 0;
 	}
       else
 	{
 	  /* Must be a signaling or quiet NaN */
-	  FPU_loaded_data.exp = EXP_NaN;
-	  FPU_loaded_data.tag = TW_NaN;
-	  FPU_loaded_data.sigh = (m64 << 11) | 0x80000000;
-	  FPU_loaded_data.sigh |= l64 >> 21;
-	  FPU_loaded_data.sigl = l64 << 11;
+	  loaded_data->exp = EXP_NaN;
+	  loaded_data->tag = TW_NaN;
+	  loaded_data->sigh = (m64 << 11) | 0x80000000;
+	  loaded_data->sigh |= l64 >> 21;
+	  loaded_data->sigl = l64 << 11;
 	  return 0; /* The calling function must look for NaNs */
 	}
     }
@@ -192,30 +183,30 @@
       if ((m64 == 0) && (l64 == 0))
 	{
 	  /* Zero */
-	  int c = FPU_loaded_data.sign;
-	  reg_move(&CONST_Z, &FPU_loaded_data);
-	  FPU_loaded_data.sign = c;
+	  int c = loaded_data->sign;
+	  reg_move(&CONST_Z, loaded_data);
+	  loaded_data->sign = c;
 	  return 0;
 	}
       else
 	{
 	  /* De-normal */
-	  FPU_loaded_data.exp = DOUBLE_Emin + EXP_BIAS;
-	  FPU_loaded_data.tag = TW_Valid;
-	  FPU_loaded_data.sigh = m64 << 11;
-	  FPU_loaded_data.sigh |= l64 >> 21;
-	  FPU_loaded_data.sigl = l64 << 11;
-	  normalize_nuo(&FPU_loaded_data);
+	  loaded_data->exp = DOUBLE_Emin + EXP_BIAS;
+	  loaded_data->tag = TW_Valid;
+	  loaded_data->sigh = m64 << 11;
+	  loaded_data->sigh |= l64 >> 21;
+	  loaded_data->sigl = l64 << 11;
+	  normalize_nuo(loaded_data);
 	  return denormal_operand();
 	}
     }
   else
     {
-      FPU_loaded_data.exp = exp + EXP_BIAS;
-      FPU_loaded_data.tag = TW_Valid;
-      FPU_loaded_data.sigh = (m64 << 11) | 0x80000000;
-      FPU_loaded_data.sigh |= l64 >> 21;
-      FPU_loaded_data.sigl = l64 << 11;
+      loaded_data->exp = exp + EXP_BIAS;
+      loaded_data->tag = TW_Valid;
+      loaded_data->sigh = (m64 << 11) | 0x80000000;
+      loaded_data->sigh |= l64 >> 21;
+      loaded_data->sigl = l64 << 11;
 
       return 0;
     }
@@ -223,9 +214,8 @@
 
 
 /* Get a float from user memory */
-int reg_load_single(void)
+int reg_load_single(float *single, FPU_REG *loaded_data)
 {
-  float *single = (float *)FPU_data_address;
   unsigned m32;
   int exp;
 
@@ -235,15 +225,15 @@
   RE_ENTRANT_CHECK_ON;
 
   if (m32 & 0x80000000)
-    FPU_loaded_data.sign = SIGN_NEG;
+    loaded_data->sign = SIGN_NEG;
   else
-    FPU_loaded_data.sign = SIGN_POS;
+    loaded_data->sign = SIGN_POS;
   if (!(m32 & 0x7fffffff))
     {
       /* Zero */
-      int c = FPU_loaded_data.sign;
-      reg_move(&CONST_Z, &FPU_loaded_data);
-      FPU_loaded_data.sign = c;
+      int c = loaded_data->sign;
+      reg_move(&CONST_Z, loaded_data);
+      loaded_data->sign = c;
       return 0;
     }
   exp = ((m32 & 0x7f800000) >> 23) - SINGLE_Ebias;
@@ -251,11 +241,11 @@
   if ( exp < SINGLE_Emin )
     {
       /* De-normals */
-      FPU_loaded_data.exp = SINGLE_Emin + EXP_BIAS;
-      FPU_loaded_data.tag = TW_Valid;
-      FPU_loaded_data.sigh = m32;
-      FPU_loaded_data.sigl = 0;
-      normalize_nuo(&FPU_loaded_data);
+      loaded_data->exp = SINGLE_Emin + EXP_BIAS;
+      loaded_data->tag = TW_Valid;
+      loaded_data->sigh = m32;
+      loaded_data->sigl = 0;
+      normalize_nuo(loaded_data);
       return denormal_operand();
     }
   else if ( exp > SINGLE_Emax )
@@ -264,37 +254,36 @@
       if ( m32 == 0 )
 	{
 	  /* +- infinity */
-	  FPU_loaded_data.sigh = 0x80000000;
-	  FPU_loaded_data.sigl = 0x00000000;
-	  FPU_loaded_data.exp = EXP_Infinity;
-	  FPU_loaded_data.tag = TW_Infinity;
+	  loaded_data->sigh = 0x80000000;
+	  loaded_data->sigl = 0x00000000;
+	  loaded_data->exp = EXP_Infinity;
+	  loaded_data->tag = TW_Infinity;
 	  return 0;
 	}
       else
 	{
 	  /* Must be a signaling or quiet NaN */
-	  FPU_loaded_data.exp = EXP_NaN;
-	  FPU_loaded_data.tag = TW_NaN;
-	  FPU_loaded_data.sigh = m32 | 0x80000000;
-	  FPU_loaded_data.sigl = 0;
+	  loaded_data->exp = EXP_NaN;
+	  loaded_data->tag = TW_NaN;
+	  loaded_data->sigh = m32 | 0x80000000;
+	  loaded_data->sigl = 0;
 	  return 0; /* The calling function must look for NaNs */
 	}
     }
   else
     {
-      FPU_loaded_data.exp = exp + EXP_BIAS;
-      FPU_loaded_data.sigh = m32 | 0x80000000;
-      FPU_loaded_data.sigl = 0;
-      FPU_loaded_data.tag = TW_Valid;
+      loaded_data->exp = exp + EXP_BIAS;
+      loaded_data->sigh = m32 | 0x80000000;
+      loaded_data->sigl = 0;
+      loaded_data->tag = TW_Valid;
       return 0;
     }
 }
 
 
 /* Get a long long from user memory */
-void reg_load_int64(void)
+void reg_load_int64(long long *_s, FPU_REG *loaded_data)
 {
-  long long *_s = (long long *)FPU_data_address;
   int e;
   long long s;
 
@@ -305,28 +294,27 @@
   RE_ENTRANT_CHECK_ON;
 
   if (s == 0)
-    { reg_move(&CONST_Z, &FPU_loaded_data); return; }
+    { reg_move(&CONST_Z, loaded_data); return; }
 
   if (s > 0)
-    FPU_loaded_data.sign = SIGN_POS;
+    loaded_data->sign = SIGN_POS;
   else
   {
     s = -s;
-    FPU_loaded_data.sign = SIGN_NEG;
+    loaded_data->sign = SIGN_NEG;
   }
 
   e = EXP_BIAS + 63;
-  significand(&FPU_loaded_data) = s;
-  FPU_loaded_data.exp = e;
-  FPU_loaded_data.tag = TW_Valid;
-  normalize_nuo(&FPU_loaded_data);
+  significand(loaded_data) = s;
+  loaded_data->exp = e;
+  loaded_data->tag = TW_Valid;
+  normalize_nuo(loaded_data);
 }
 
 
 /* Get a long from user memory */
-void reg_load_int32(void)
+void reg_load_int32(long *_s, FPU_REG *loaded_data)
 {
-  long *_s = (long *)FPU_data_address;
   long s;
   int e;
 
@@ -336,29 +324,28 @@
   RE_ENTRANT_CHECK_ON;
 
   if (s == 0)
-    { reg_move(&CONST_Z, &FPU_loaded_data); return; }
+    { reg_move(&CONST_Z, loaded_data); return; }
 
   if (s > 0)
-    FPU_loaded_data.sign = SIGN_POS;
+    loaded_data->sign = SIGN_POS;
   else
   {
     s = -s;
-    FPU_loaded_data.sign = SIGN_NEG;
+    loaded_data->sign = SIGN_NEG;
   }
 
   e = EXP_BIAS + 31;
-  FPU_loaded_data.sigh = s;
-  FPU_loaded_data.sigl = 0;
-  FPU_loaded_data.exp = e;
-  FPU_loaded_data.tag = TW_Valid;
-  normalize_nuo(&FPU_loaded_data);
+  loaded_data->sigh = s;
+  loaded_data->sigl = 0;
+  loaded_data->exp = e;
+  loaded_data->tag = TW_Valid;
+  normalize_nuo(loaded_data);
 }
 
 
 /* Get a short from user memory */
-void reg_load_int16(void)
+void reg_load_int16(short *_s, FPU_REG *loaded_data)
 {
-  short *_s = (short *)FPU_data_address;
   int s, e;
 
   RE_ENTRANT_CHECK_OFF;
@@ -368,30 +355,29 @@
   RE_ENTRANT_CHECK_ON;
 
   if (s == 0)
-    { reg_move(&CONST_Z, &FPU_loaded_data); return; }
+    { reg_move(&CONST_Z, loaded_data); return; }
 
   if (s > 0)
-    FPU_loaded_data.sign = SIGN_POS;
+    loaded_data->sign = SIGN_POS;
   else
   {
     s = -s;
-    FPU_loaded_data.sign = SIGN_NEG;
+    loaded_data->sign = SIGN_NEG;
   }
 
   e = EXP_BIAS + 15;
-  FPU_loaded_data.sigh = s << 16;
+  loaded_data->sigh = s << 16;
 
-  FPU_loaded_data.sigl = 0;
-  FPU_loaded_data.exp = e;
-  FPU_loaded_data.tag = TW_Valid;
-  normalize_nuo(&FPU_loaded_data);
+  loaded_data->sigl = 0;
+  loaded_data->exp = e;
+  loaded_data->tag = TW_Valid;
+  normalize_nuo(loaded_data);
 }
 
 
 /* Get a packed bcd array from user memory */
-void reg_load_bcd(void)
+void reg_load_bcd(char *s, FPU_REG *loaded_data)
 {
-  char *s = (char *)FPU_data_address;
   int pos;
   unsigned char bcd;
   long long l=0;
@@ -409,48 +395,45 @@
       l *= 10;
       l += bcd & 0x0f;
     }
-  
-  /* Finish all access to user memory before putting stuff into
-     the static FPU_loaded_data */
+ 
   RE_ENTRANT_CHECK_OFF;
-  FPU_loaded_data.sign =
+  loaded_data->sign =
     ((unsigned char)get_fs_byte((unsigned char *) s+9)) & 0x80 ?
       SIGN_NEG : SIGN_POS;
   RE_ENTRANT_CHECK_ON;
 
   if (l == 0)
     {
-      char sign = FPU_loaded_data.sign;
-      reg_move(&CONST_Z, &FPU_loaded_data);
-      FPU_loaded_data.sign = sign;
+      char sign = loaded_data->sign;
+      reg_move(&CONST_Z, loaded_data);
+      loaded_data->sign = sign;
     }
   else
     {
-      significand(&FPU_loaded_data) = l;
-      FPU_loaded_data.exp = EXP_BIAS + 63;
-      FPU_loaded_data.tag = TW_Valid;
-      normalize_nuo(&FPU_loaded_data);
+      significand(loaded_data) = l;
+      loaded_data->exp = EXP_BIAS + 63;
+      loaded_data->tag = TW_Valid;
+      normalize_nuo(loaded_data);
     }
 }
 
 /*===========================================================================*/
 
 /* Put a long double into user memory */
-int reg_store_extended(void)
+int reg_store_extended(long double *d, FPU_REG *st0_ptr)
 {
   /*
     The only exception raised by an attempt to store to an
     extended format is the Invalid Stack exception, i.e.
     attempting to store from an empty register.
    */
-  long double *d = (long double *)FPU_data_address;
 
-  if ( FPU_st0_tag != TW_Empty )
+  if ( st0_ptr->tag != TW_Empty )
     {
       RE_ENTRANT_CHECK_OFF;
       FPU_verify_area(VERIFY_WRITE, d, 10);
       RE_ENTRANT_CHECK_ON;
-      write_to_extended(FPU_st0_ptr, (char *) FPU_data_address);
+      write_to_extended(st0_ptr, (char *) d);
       return 1;
     }
 
@@ -475,18 +458,18 @@
 
 
 /* Put a double into user memory */
-int reg_store_double(void)
+int reg_store_double(double *dfloat, FPU_REG *st0_ptr)
 {
-  double *dfloat = (double *)FPU_data_address;
   unsigned long l[2];
   unsigned long increment = 0;	/* avoid gcc warnings */
+  char st0_tag = st0_ptr->tag;
 
-  if (FPU_st0_tag == TW_Valid)
+  if (st0_tag == TW_Valid)
     {
       int exp;
       FPU_REG tmp;
 
-      reg_move(FPU_st0_ptr, &tmp);
+      reg_move(st0_ptr, &tmp);
       exp = tmp.exp - EXP_BIAS;
 
       if ( exp < DOUBLE_Emin )     /* It may be a denormal */
@@ -497,7 +480,7 @@
 #ifndef PECULIAR_486
 	  /* An 80486 is supposed to be able to generate
 	     a denormal exception here, but... */
-	  if ( FPU_st0_ptr->exp <= EXP_UNDER )
+	  if ( st0_ptr->exp <= EXP_UNDER )
 	    {
 	      /* Underflow has priority. */
 	      if ( control_word & CW_Underflow )
@@ -515,7 +498,7 @@
 		 that the 80486 rounds to the dest precision, then
 		 converts to decide underflow. */
 	      if ( !((tmp.sigh == 0x00100000) && (tmp.sigl == 0) &&
-		  (FPU_st0_ptr->sigl & 0x000007ff)) )
+		  (st0_ptr->sigl & 0x000007ff)) )
 #endif PECULIAR_486
 		{
 		  EXCEPTION(EX_Underflow);
@@ -612,23 +595,23 @@
 	    }
 	}
     }
-  else if (FPU_st0_tag == TW_Zero)
+  else if (st0_tag == TW_Zero)
     {
       /* Number is zero */
       l[0] = 0;
       l[1] = 0;
     }
-  else if (FPU_st0_tag == TW_Infinity)
+  else if (st0_tag == TW_Infinity)
     {
       l[0] = 0;
       l[1] = 0x7ff00000;
     }
-  else if (FPU_st0_tag == TW_NaN)
+  else if (st0_tag == TW_NaN)
     {
       /* See if we can get a valid NaN from the FPU_REG */
-      l[0] = (FPU_st0_ptr->sigl >> 11) | (FPU_st0_ptr->sigh << 21);
-      l[1] = ((FPU_st0_ptr->sigh >> 11) & 0xfffff);
-      if ( !(FPU_st0_ptr->sigh & 0x40000000) )
+      l[0] = (st0_ptr->sigl >> 11) | (st0_ptr->sigh << 21);
+      l[1] = ((st0_ptr->sigh >> 11) & 0xfffff);
+      if ( !(st0_ptr->sigh & 0x40000000) )
 	{
 	  /* It is a signalling NaN */
 	  EXCEPTION(EX_Invalid);
@@ -638,7 +621,7 @@
 	}
       l[1] |= 0x7ff00000;
     }
-  else if ( FPU_st0_tag == TW_Empty )
+  else if ( st0_tag == TW_Empty )
     {
       /* Empty register (stack underflow) */
       EXCEPTION(EX_StackUnder);
@@ -656,7 +639,7 @@
       else
 	return 0;
     }
-  if (FPU_st0_ptr->sign)
+  if ( st0_ptr->sign )
     l[1] |= 0x80000000;
 
   RE_ENTRANT_CHECK_OFF;
@@ -670,18 +653,18 @@
 
 
 /* Put a float into user memory */
-int reg_store_single(void)
+int reg_store_single(float *single, FPU_REG *st0_ptr)
 {
-  float *single = (float *)FPU_data_address;
   long templ;
   unsigned long increment = 0;     	/* avoid gcc warnings */
+  char st0_tag = st0_ptr->tag;
 
-  if (FPU_st0_tag == TW_Valid)
+  if (st0_tag == TW_Valid)
     {
       int exp;
       FPU_REG tmp;
 
-      reg_move(FPU_st0_ptr, &tmp);
+      reg_move(st0_ptr, &tmp);
       exp = tmp.exp - EXP_BIAS;
 
       if ( exp < SINGLE_Emin )
@@ -692,7 +675,7 @@
 #ifndef PECULIAR_486
 	  /* An 80486 is supposed to be able to generate
 	     a denormal exception here, but... */
-	  if ( FPU_st0_ptr->exp <= EXP_UNDER )
+	  if ( st0_ptr->exp <= EXP_UNDER )
 	    {
 	      /* Underflow has priority. */
 	      if ( control_word & CW_Underflow )
@@ -710,7 +693,7 @@
 		 that the 80486 rounds to the dest precision, then
 		 converts to decide underflow. */
 	      if ( !((tmp.sigl == 0x00800000) &&
-		  ((FPU_st0_ptr->sigh & 0x000000ff) || FPU_st0_ptr->sigl)) )
+		  ((st0_ptr->sigh & 0x000000ff) || st0_ptr->sigl)) )
 #endif PECULIAR_486
 		{
 		  EXCEPTION(EX_Underflow);
@@ -800,19 +783,19 @@
 	    templ |= ((exp+SINGLE_Ebias) & 0xff) << 23;
 	}
     }
-  else if (FPU_st0_tag == TW_Zero)
+  else if (st0_tag == TW_Zero)
     {
       templ = 0;
     }
-  else if (FPU_st0_tag == TW_Infinity)
+  else if (st0_tag == TW_Infinity)
     {
       templ = 0x7f800000;
     }
-  else if (FPU_st0_tag == TW_NaN)
+  else if (st0_tag == TW_NaN)
     {
       /* See if we can get a valid NaN from the FPU_REG */
-      templ = FPU_st0_ptr->sigh >> 8;
-      if ( !(FPU_st0_ptr->sigh & 0x40000000) )
+      templ = st0_ptr->sigh >> 8;
+      if ( !(st0_ptr->sigh & 0x40000000) )
 	{
 	  /* It is a signalling NaN */
 	  EXCEPTION(EX_Invalid);
@@ -822,7 +805,7 @@
 	}
       templ |= 0x7f800000;
     }
-  else if ( FPU_st0_tag == TW_Empty )
+  else if ( st0_tag == TW_Empty )
     {
       /* Empty register (stack underflow) */
       EXCEPTION(EX_StackUnder);
@@ -846,7 +829,7 @@
       return 0;
     }
 #endif
-  if (FPU_st0_ptr->sign)
+  if (st0_ptr->sign)
     templ |= 0x80000000;
 
   RE_ENTRANT_CHECK_OFF;
@@ -859,27 +842,27 @@
 
 
 /* Put a long long into user memory */
-int reg_store_int64(void)
+int reg_store_int64(long long *d, FPU_REG *st0_ptr)
 {
-  long long *d = (long long *)FPU_data_address;
   FPU_REG t;
   long long tll;
   int precision_loss;
+  char st0_tag = st0_ptr->tag;
 
-  if ( FPU_st0_tag == TW_Empty )
+  if ( st0_tag == TW_Empty )
     {
       /* Empty register (stack underflow) */
       EXCEPTION(EX_StackUnder);
       goto invalid_operand;
     }
-  else if ( (FPU_st0_tag == TW_Infinity) ||
-	   (FPU_st0_tag == TW_NaN) )
+  else if ( (st0_tag == TW_Infinity) ||
+	   (st0_tag == TW_NaN) )
     {
       EXCEPTION(EX_Invalid);
       goto invalid_operand;
     }
 
-  reg_move(FPU_st0_ptr, &t);
+  reg_move(st0_ptr, &t);
   precision_loss = round_to_int(&t);
   ((long *)&tll)[0] = t.sigl;
   ((long *)&tll)[1] = t.sigh;
@@ -918,26 +901,26 @@
 
 
 /* Put a long into user memory */
-int reg_store_int32(void)
+int reg_store_int32(long *d, FPU_REG *st0_ptr)
 {
-  long *d = (long *)FPU_data_address;
   FPU_REG t;
   int precision_loss;
+  char st0_tag = st0_ptr->tag;
 
-  if ( FPU_st0_tag == TW_Empty )
+  if ( st0_tag == TW_Empty )
     {
       /* Empty register (stack underflow) */
       EXCEPTION(EX_StackUnder);
       goto invalid_operand;
     }
-  else if ( (FPU_st0_tag == TW_Infinity) ||
-	   (FPU_st0_tag == TW_NaN) )
+  else if ( (st0_tag == TW_Infinity) ||
+	   (st0_tag == TW_NaN) )
     {
       EXCEPTION(EX_Invalid);
       goto invalid_operand;
     }
 
-  reg_move(FPU_st0_ptr, &t);
+  reg_move(st0_ptr, &t);
   precision_loss = round_to_int(&t);
   if (t.sigh ||
       ((t.sigl & 0x80000000) &&
@@ -972,26 +955,26 @@
 
 
 /* Put a short into user memory */
-int reg_store_int16(void)
+int reg_store_int16(short *d, FPU_REG *st0_ptr)
 {
-  short *d = (short *)FPU_data_address;
   FPU_REG t;
   int precision_loss;
+  char st0_tag = st0_ptr->tag;
 
-  if ( FPU_st0_tag == TW_Empty )
+  if ( st0_tag == TW_Empty )
     {
       /* Empty register (stack underflow) */
       EXCEPTION(EX_StackUnder);
       goto invalid_operand;
     }
-  else if ( (FPU_st0_tag == TW_Infinity) ||
-	   (FPU_st0_tag == TW_NaN) )
+  else if ( (st0_tag == TW_Infinity) ||
+	   (st0_tag == TW_NaN) )
     {
       EXCEPTION(EX_Invalid);
       goto invalid_operand;
     }
 
-  reg_move(FPU_st0_ptr, &t);
+  reg_move(st0_ptr, &t);
   precision_loss = round_to_int(&t);
   if (t.sigh ||
       ((t.sigl & 0xffff8000) &&
@@ -1026,23 +1009,23 @@
 
 
 /* Put a packed bcd array into user memory */
-int reg_store_bcd(void)
+int reg_store_bcd(char *d, FPU_REG *st0_ptr)
 {
-  char *d = (char *)FPU_data_address;
   FPU_REG t;
   unsigned long long ll;
   unsigned char b;
   int i, precision_loss;
-  unsigned char sign = (FPU_st0_ptr->sign == SIGN_NEG) ? 0x80 : 0;
+  unsigned char sign = (st0_ptr->sign == SIGN_NEG) ? 0x80 : 0;
+  char st0_tag = st0_ptr->tag;
 
-  if ( FPU_st0_tag == TW_Empty )
+  if ( st0_tag == TW_Empty )
     {
       /* Empty register (stack underflow) */
       EXCEPTION(EX_StackUnder);
       goto invalid_operand;
     }
 
-  reg_move(FPU_st0_ptr, &t);
+  reg_move(st0_ptr, &t);
   precision_loss = round_to_int(&t);
   ll = significand(&t);
 
@@ -1163,36 +1146,32 @@
 
 /*===========================================================================*/
 
-char *fldenv(fpu_addr_modes addr_modes)
+char *fldenv(fpu_addr_modes addr_modes, char *s)
 {
-  char *s = (char *)FPU_data_address;
   unsigned short tag_word = 0;
   unsigned char tag;
   int i;
 
-  if ( addr_modes.mode16
-      || (addr_modes.override.operand_size == OP_SIZE_PREFIX) )
+  if ( (addr_modes.default_mode == VM86) ||
+      ((addr_modes.default_mode == PM16)
+      ^ (addr_modes.override.operand_size == OP_SIZE_PREFIX)) )
     {
       RE_ENTRANT_CHECK_OFF;
       FPU_verify_area(VERIFY_READ, s, 0x0e);
       control_word = get_fs_word((unsigned short *) s);
       partial_status = get_fs_word((unsigned short *) (s+2));
       tag_word = get_fs_word((unsigned short *) (s+4));
-      ip_offset = get_fs_word((unsigned short *) (s+6));
-      cs_selector = get_fs_word((unsigned short *) (s+8));
-      data_operand_offset = get_fs_word((unsigned short *) (s+0x0a));
-      operand_selector = get_fs_word((unsigned short *) (s+0x0c));
+      instruction_address.offset = get_fs_word((unsigned short *) (s+6));
+      instruction_address.selector = get_fs_word((unsigned short *) (s+8));
+      operand_address.offset = get_fs_word((unsigned short *) (s+0x0a));
+      operand_address.selector = get_fs_word((unsigned short *) (s+0x0c));
       RE_ENTRANT_CHECK_ON;
       s += 0x0e;
-      if ( addr_modes.vm86 )
-	{
-	  ip_offset += (cs_selector & 0xf000) << 4;
-	  data_operand_offset += (operand_selector & 0xf000) << 4;
-	}
-      else if ( addr_modes.p286 )
+      if ( addr_modes.default_mode == VM86 )
 	{
-	  ip_offset += LDT_BASE_ADDR(cs_selector);
-	  data_operand_offset += LDT_BASE_ADDR(operand_selector);
+	  instruction_address.offset
+	    += (instruction_address.selector & 0xf000) << 4;
+	  operand_address.offset += (operand_address.selector & 0xf000) << 4;
 	}
     }
   else
@@ -1202,10 +1181,11 @@
       control_word = get_fs_word((unsigned short *) s);
       partial_status = get_fs_word((unsigned short *) (s+4));
       tag_word = get_fs_word((unsigned short *) (s+8));
-      ip_offset = get_fs_long((unsigned long *) (s+0x0c));
-      cs_selector = get_fs_long((unsigned long *) (s+0x10));
-      data_operand_offset = get_fs_long((unsigned long *) (s+0x14));
-      operand_selector = get_fs_long((unsigned long *) (s+0x18));
+      instruction_address.offset = get_fs_long((unsigned long *) (s+0x0c));
+      instruction_address.selector = get_fs_word((unsigned short *) (s+0x10));
+      instruction_address.opcode = get_fs_word((unsigned short *) (s+0x12));
+      operand_address.offset = get_fs_long((unsigned long *) (s+0x14));
+      operand_address.selector = get_fs_long((unsigned long *) (s+0x18));
       RE_ENTRANT_CHECK_ON;
       s += 0x1c;
     }
@@ -1254,37 +1234,26 @@
 	 remains correct */
     }
 
-  /* Ensure that the values just loaded are not changed by
-     fix-up operations. */
-  NO_NET_DATA_EFFECT;
-  NO_NET_INSTR_EFFECT;
-
   return s;
 }
 
 
-void frstor(fpu_addr_modes addr_modes)
+void frstor(fpu_addr_modes addr_modes, char *data_address)
 {
   int i, stnr;
   unsigned char tag;
-  char *s = fldenv(addr_modes);
+  char *s = fldenv(addr_modes, data_address);
 
   for ( i = 0; i < 8; i++ )
     {
       /* Load each register. */
-      FPU_data_address = (void *)(s+i*10);
-      reg_load_extended();
       stnr = (i+top) & 7;
-      tag = regs[stnr].tag;   /* Derived from the loaded tag word. */
-      reg_move(&FPU_loaded_data, &regs[stnr]);
+      tag = regs[stnr].tag;   /* Derived from the fldenv() loaded tag word. */
+      reg_load_extended((long double *)(s+i*10), &regs[stnr]);
       if ( tag == TW_Empty )  /* The loaded data over-rides all other cases. */
 	regs[stnr].tag = tag;
     }
 
-  /* Reverse the effect which loading the registers had on the
-     data pointer */
-  NO_NET_DATA_EFFECT;
-
 }
 
 
@@ -1318,12 +1287,11 @@
 }
 
 
-char *fstenv(fpu_addr_modes addr_modes)
+char *fstenv(fpu_addr_modes addr_modes, char *d)
 {
-  char *d = (char *)FPU_data_address;
-
-  if ( addr_modes.mode16
-      || (addr_modes.override.operand_size == OP_SIZE_PREFIX) )
+  if ( (addr_modes.default_mode == VM86) ||
+      ((addr_modes.default_mode == PM16)
+      ^ (addr_modes.override.operand_size == OP_SIZE_PREFIX)) )
     {
       RE_ENTRANT_CHECK_OFF;
       FPU_verify_area(VERIFY_WRITE,d,14);
@@ -1334,19 +1302,19 @@
 #endif PECULIAR_486
       put_fs_word(status_word(), (unsigned short *) (d+2));
       put_fs_word(tag_word(), (unsigned short *) (d+4));
-      put_fs_word(ip_offset, (unsigned short *) (d+6));
-      put_fs_word(data_operand_offset, (unsigned short *) (d+0x0a));
-      if ( addr_modes.vm86 )
+      put_fs_word(instruction_address.offset, (unsigned short *) (d+6));
+      put_fs_word(operand_address.offset, (unsigned short *) (d+0x0a));
+      if ( addr_modes.default_mode == VM86 )
 	{
-	  put_fs_word((ip_offset & 0xf0000) >> 4,
+	  put_fs_word((instruction_address.offset & 0xf0000) >> 4,
 		      (unsigned short *) (d+8));
-	  put_fs_word((data_operand_offset & 0xf0000) >> 4,
+	  put_fs_word((operand_address.offset & 0xf0000) >> 4,
 		      (unsigned short *) (d+0x0c));
 	}
       else
 	{
-	  put_fs_word(cs_selector, (unsigned short *) (d+8));
-	  put_fs_word(operand_selector, (unsigned short *) (d+0x0c));
+	  put_fs_word(instruction_address.selector, (unsigned short *) (d+8));
+	  put_fs_word(operand_address.selector, (unsigned short *) (d+0x0c));
 	}
       RE_ENTRANT_CHECK_ON;
       d += 0x0e;
@@ -1365,14 +1333,16 @@
       put_fs_word(status_word(), (unsigned short *) (d+4));
       put_fs_word(tag_word(), (unsigned short *) (d+8));
 #endif PECULIAR_486
-      put_fs_long(ip_offset, (unsigned long *) (d+0x0c));
-      put_fs_long(cs_selector & ~0xf8000000, (unsigned long *) (d+0x10));
-      put_fs_long(data_operand_offset, (unsigned long *) (d+0x14));
+      put_fs_long(instruction_address.offset, (unsigned long *) (d+0x0c));
+      put_fs_word(instruction_address.selector, (unsigned short *) (d+0x10));
+      put_fs_word(instruction_address.opcode, (unsigned short *) (d+0x12));
+      put_fs_long(operand_address.offset, (unsigned long *) (d+0x14));
 #ifdef PECULIAR_486
       /* An 80486 sets all the reserved bits to 1. */
-      put_fs_long(0xffff0000 | operand_selector, (unsigned long *) (d+0x18));
+      put_fs_word(operand_address.selector, (unsigned short *) (d+0x18));
+      put_fs_word(0xffff, (unsigned short *) (d+0x1a));
 #else
-      put_fs_long(operand_selector, (unsigned long *) (d+0x18));
+      put_fs_long(operand_address.selector, (unsigned long *) (d+0x18));
 #endif PECULIAR_486
       RE_ENTRANT_CHECK_ON;
       d += 0x1c;
@@ -1385,12 +1355,12 @@
 }
 
 
-void fsave(fpu_addr_modes addr_modes)
+void fsave(fpu_addr_modes addr_modes, char *data_address)
 {
   char *d;
   int i;
 
-  d = fstenv(addr_modes);
+  d = fstenv(addr_modes, data_address);
   RE_ENTRANT_CHECK_OFF;
   FPU_verify_area(VERIFY_WRITE,d,80);
   RE_ENTRANT_CHECK_ON;
diff -u --recursive --new-file v1.1.17/linux/drivers/FPU-emu/reg_round.S linux/drivers/FPU-emu/reg_round.S
--- v1.1.17/linux/drivers/FPU-emu/reg_round.S	Wed Feb 16 13:07:57 1994
+++ linux/drivers/FPU-emu/reg_round.S	Thu Jun  2 10:28:28 1994
@@ -82,7 +82,7 @@
 #define	UNMASKED_UNDERFLOW $2
 
 
-#ifdef REENTRANT_FPU
+#ifndef NON_REENTRANT_FPU
 /*	Make the code re-entrant by putting
 	local storage on the stack: */
 #define FPU_bits_lost	(%esp)
@@ -97,7 +97,7 @@
 	.byte	0
 FPU_denormal:
 	.byte	0
-#endif REENTRANT_FPU
+#endif NON_REENTRANT_FPU
 
 
 .text
@@ -127,9 +127,9 @@
 
 fpu_reg_round_sqrt:		/* Entry point from wm_sqrt.S */
 
-#ifdef REENTRANT_FPU
+#ifndef NON_REENTRANT_FPU
 	pushl	%ebx		/* adjust the stack pointer */
-#endif REENTRANT_FPU
+#endif NON_REENTRANT_FPU
 
 #ifdef PARANOID
 /* Cannot use this here yet */
@@ -417,9 +417,9 @@
 	jge	L_overflow
 
 fpu_reg_round_exit:
-#ifdef REENTRANT_FPU
+#ifndef NON_REENTRANT_FPU
 	popl	%ebx		/* adjust the stack pointer */
-#endif REENTRANT_FPU
+#endif NON_REENTRANT_FPU
 
 fpu_Arith_exit:
 	popl	%ebx
diff -u --recursive --new-file v1.1.17/linux/drivers/FPU-emu/reg_u_div.S linux/drivers/FPU-emu/reg_u_div.S
--- v1.1.17/linux/drivers/FPU-emu/reg_u_div.S	Wed Dec  1 14:44:16 1993
+++ linux/drivers/FPU-emu/reg_u_div.S	Thu Jun  2 10:28:28 1994
@@ -29,7 +29,7 @@
 /* #define	dSIGH(x)	4(x) */
 
 
-#ifdef REENTRANT_FPU
+#ifndef NON_REENTRANT_FPU
 /*
 	Local storage on the stack:
 	Result:		FPU_accum_3:FPU_accum_2:FPU_accum_1:FPU_accum_0
@@ -65,7 +65,7 @@
 	.long	0
 FPU_ovfl_flag:
 	.byte	0
-#endif REENTRANT_FPU
+#endif NON_REENTRANT_FPU
 
 
 .text
@@ -78,9 +78,9 @@
 _reg_u_div:
 	pushl	%ebp
 	movl	%esp,%ebp
-#ifdef REENTRANT_FPU
+#ifndef NON_REENTRANT_FPU
 	subl	$28,%esp
-#endif REENTRANT_FPU
+#endif NON_REENTRANT_FPU
 
 	pushl	%esi
 	pushl	%edi
diff -u --recursive --new-file v1.1.17/linux/drivers/FPU-emu/reg_u_mul.S linux/drivers/FPU-emu/reg_u_mul.S
--- v1.1.17/linux/drivers/FPU-emu/reg_u_mul.S	Wed Dec  1 14:44:16 1993
+++ linux/drivers/FPU-emu/reg_u_mul.S	Thu Jun  2 10:28:28 1994
@@ -27,7 +27,7 @@
 
 
 
-#ifdef REENTRANT_FPU
+#ifndef NON_REENTRANT_FPU
 /*  Local storage on the stack: */
 #define FPU_accum_0	-4(%ebp)	/* ms word */
 #define FPU_accum_1	-8(%ebp)
@@ -40,7 +40,7 @@
 	.long	0
 FPU_accum_1:
 	.long	0
-#endif REENTRANT_FPU
+#endif NON_REENTRANT_FPU
 
 
 .text
@@ -50,9 +50,9 @@
 _reg_u_mul:
 	pushl	%ebp
 	movl	%esp,%ebp
-#ifdef REENTRANT_FPU
+#ifndef NON_REENTRANT_FPU
 	subl	$8,%esp
-#endif REENTRANT_FPU
+#endif NON_REENTRANT_FPU
 
 	pushl	%esi
 	pushl	%edi
diff -u --recursive --new-file v1.1.17/linux/drivers/FPU-emu/version.h linux/drivers/FPU-emu/version.h
--- v1.1.17/linux/drivers/FPU-emu/version.h	Sat Mar 26 14:04:24 1994
+++ linux/drivers/FPU-emu/version.h	Thu Jun  2 10:28:28 1994
@@ -9,5 +9,4 @@
  |                                                                           |
  +---------------------------------------------------------------------------*/
 
-#define FPU_VERSION "wm-FPU-emu version Beta 1.11"
-
+#define FPU_VERSION "wm-FPU-emu version 1.12"
diff -u --recursive --new-file v1.1.17/linux/drivers/FPU-emu/wm_sqrt.S linux/drivers/FPU-emu/wm_sqrt.S
--- v1.1.17/linux/drivers/FPU-emu/wm_sqrt.S	Wed Dec  1 14:44:16 1993
+++ linux/drivers/FPU-emu/wm_sqrt.S	Thu Jun  2 10:28:28 1994
@@ -29,7 +29,7 @@
 #include "fpu_asm.h"
 
 
-#ifdef REENTRANT_FPU
+#ifndef NON_REENTRANT_FPU
 /*	Local storage on the stack: */
 #define FPU_accum_3	-4(%ebp)	/* ms word */
 #define FPU_accum_2	-8(%ebp)
@@ -70,7 +70,7 @@
 	.long	0
 FPU_fsqrt_arg_0:
 	.long	0		/* ls word, at most the ms bit is set */
-#endif REENTRANT_FPU
+#endif NON_REENTRANT_FPU
 
 
 .text
@@ -80,9 +80,9 @@
 _wm_sqrt:
 	pushl	%ebp
 	movl	%esp,%ebp
-#ifdef REENTRANT_FPU
+#ifndef NON_REENTRANT_FPU
 	subl	$28,%esp
-#endif REENTRANT_FPU
+#endif NON_REENTRANT_FPU
 	pushl	%esi
 	pushl	%edi
 	pushl	%ebx
diff -u --recursive --new-file v1.1.17/linux/drivers/block/README.sbpcd linux/drivers/block/README.sbpcd
--- v1.1.17/linux/drivers/block/README.sbpcd	Tue Apr 19 10:52:12 1994
+++ linux/drivers/block/README.sbpcd	Thu Jun  2 10:33:26 1994
@@ -1,42 +1,59 @@
-This is release 1.4 of the SoundBlaster Pro (Matsushita, Kotobuki,
-Panasonic, CreativeLabs, Aztech) CD-ROM driver for Linux.
+This README belongs to release 1.6 of the SoundBlaster Pro (Matsushita,
+Kotobuki, Panasonic, CreativeLabs) CD-ROM driver for Linux.
 
 The driver is able to drive the whole family of IDE-style
-Matsushita/Kotobuki/Panasonic drives (the "double speed" versions
-like CR-562 and CR-563, too), and it will work with the soundcard
-interfaces (SB Pro, SB 16, Galaxy, SoundFX, ...) and/or with
-the "no-sound" cards (Panasonic CI-101P, LaserMate, Aztech, ...).
+Matsushita/Kotobuki/Panasonic drives (the "double speed" versions like CR-562
+and CR-563, too), and it will work with the soundcard interfaces (SB Pro,
+SB 16, Galaxy, SoundFX, ...) and/or with the "no-sound" cards (Panasonic
+CI-101P, LaserMate, Aztech, ...).
+It should work too now with the "configurable" interface "Sequoia S-1000",
+which is found on the Spea Media FX sound card.
 The interface type has to get configured in /usr/include/linux/sbpcd.h, 
 because the behavior is different.
 
-The driver respects different drive firmware releases - my old drive
-is a 2.11, but it should work with "old" drives <2.01 ... >3.00
-and with "new" drives (which count the releases around 0.75 or
-1.00).
-
-Up to 4 drives are supported. CR-52x ("old") and CR-56x ("new") drives
-can be mixed, but the CR-521 ones are hard-wired to drive ID 0. 
-The drives have to use different drive IDs, but the same controller 
-(it will be a little bit harder to support up to four interface cards - 
-but I plan to do it the day somebody wishes to connect a fifth drive).
-Each drive has to get a unique minor number (0...3), corresponding
-to it's drive ID. The drive IDs may be selected freely from 0 to 3 -
-they must not be in consecutive order.
-
-The driver supports reading of data from the CD and playing of
-audio tracks. The audio part should run with WorkMan, xcdplayer,
-with the "non-X11" products CDplayer and WorkBone - tell me if
-it is not compatible with other software.
-
-MultiSession is supported (but "old" drives lack this capability),
-"ManySession" (see below) alternatively.
-Photo CDs work, too. At ftp.gwdg.de:/pub/linux/hpcdtoppm/ is a package 
-to convert photo CD image files.
-
-The transfer rate will reach 150 kB/sec with "old" drives and
-the full 300 kB/sec with double-speed drives. XA (PhotoCD) disks
-with "old" drives are as slow as 50 kB/sec.
+The driver respects different drive firmware releases - my old drive is a 2.11,
+but it should work with "old" drives <2.01 ... >3.00 and with "new" drives
+(which count the releases around 0.75 or 1.00).
+
+Up to 4 drives are supported. CR-52x ("old") and CR-56x ("new") drives can be
+mixed, but the CR-521 ones are hard-wired to drive ID 0. 
+
+As Don Carroll, don@ds9.us.dell.com or FIDO 1:382/14, told me, it is possible
+to change old drives to any ID, too. He writes in this sense:
+   "In order to be able to use more than one single speed drive
+   (they do not have the ID jumpers) you must add a DIP switch
+   and two resistors. The pads are already on the board next to
+   the power connector. You will see the silkscreen for the
+   switch if you remove the top cover.
+                    1 2 3 4
+             ID 0 = x F F x             O = "on"
+             ID 1 = x O F x             F = "off"
+             ID 2 = x F O x             x = "don't care"
+             ID 3 = x O O x
+   Next to the switch are the positions for R76 (7k) and R78
+   (12k). I had to play around with the resistor values - ID 3
+   did not work with other values. If the values are not good,
+   ID 3 behaves like ID 0."
+
+The drives have to use different drive IDs, but the same controller (it will
+be a little bit harder to support up to four interface cards -  but I plan to
+do it the day somebody wishes to connect a fifth drive).
+Each drive has to get a unique minor number (0...3), corresponding to it's
+drive ID. The drive IDs may be selected freely from 0 to 3 - they must not be
+in consecutive order.
+
+The driver supports reading of data from the CD and playing of audio tracks.
+The audio part should run with WorkMan, xcdplayer, with the "non-X11" products
+CDplayer and WorkBone - tell me if it is not compatible with other software.
+
+MultiSession is supported (even my "old" CR-521 can handle it), "ManySession"
+(not recommended, see below) alternatively.
+Photo CDs work, too. At ftp.gwdg.de:/pub/linux/hpcdtoppm/ is Hadmut Danisch's
+package to convert photo CD image files.
 
+The transfer rate will reach 150 kB/sec with "old" drives and 300 kB/sec with
+double-speed drives. XA (PhotoCD) disks with "old" drives give only 50 kB/sec.
+
 This release is part of the standard kernel and consists of
 - this README file
 - the driver file linux/drivers/block/sbpcd.c
@@ -46,43 +63,47 @@
 To install:
 -----------
 
-1. Setup your hardware parameters. Though the driver does "auto-probing"
-   now, this step is recommended for every-day use.
-   a. Go into /usr/src/linux/include/linux/sbpcd.h and configure
-      it for your hardware (near the beginning):
+1. Setup your hardware parameters. Though the driver does "auto-probing" at a
+   lot of (not all possible!) addresses, this step is recommended for
+   every-day use.
+   a. Go into /usr/src/linux/include/linux/sbpcd.h and configure it for your
+      hardware (near the beginning):
       a1. Set it up for the appropriate type of interface board.
-          Most "compatible" sound boards (for example "Highscreen",
-          "SoundFX" and "Galaxy") need the "SBPRO 0" setup. The
-          "no-sound" board from OmniCd needs the "SBPRO 1" setup.
+          "Original" CreativeLabs sound cards need "SBPRO 1".
+          Most "compatible" sound cards (for example "Highscreen", "SoundFX"
+          and "Galaxy") need "SBPRO 0".
+          The "no-sound" board from OmniCd needs the "SBPRO 1" setup.
+          The Spea Media FX sound card needs "SBPRO 2".
           sbpcd.c holds some examples in it's auto-probe list.
-      a2. Tell the address of your CDROM_PORT.
+          If you configure "SBPRO" wrong, the playing of audio CDs will work,
+          but you will not be able to mount a data CD.
+      a2. Tell the address of your CDROM_PORT (not of the sound port).
    b. Additionally for 2.a1 and 2.a2, the setup may be done during
       boot time (via the "kernel command line" or "LILO option"):
           sbpcd=0x230,SoundBlaster
       or
           sbpcd=0x320,LaserMate
+      or
+          sbpcd=0x330,SPEA
       (these strings are case sensitive!).
-
-2. Do a "make config" and select "yes" for Matsushita CD-ROM
-   support and for ISO9660 FileSystem support.
+      This is especially useful if you install a fresh distribution.
+2. Do a "make config" and select "yes" for Matsushita CD-ROM support and for
+   ISO9660 FileSystem support.
    SCSI and/or SCSI CD-ROM support is not needed.
 
-3. Then do a "make dep", then make the kernel image ("make zlilo"
-   or else).
+3. Then do a "make dep", then make the kernel image ("make zlilo" or else).
 
-4. Make the device file(s). The driver uses definitely and exclusive
-   the MAJOR 25, so do
-
+4. Make the device file(s). The driver uses definitely and exclusive the
+   MAJOR 25, so do
         mknod /dev/sbpcd b 25 0       (if you have only drive #0)
-and/or
+   and/or
         mknod /dev/sbpcd0 b 25 0
         mknod /dev/sbpcd1 b 25 1
         mknod /dev/sbpcd2 b 25 2
         mknod /dev/sbpcd3 b 25 3
-
    to make the node(s).
-   Take care that you create a node with the same MINOR as your drive
-   id is. So, if the DOS driver tells you have drive id #3, you have to
+   Take care that you create a node with the same MINOR as your drive ID is.
+   So, if the DOS driver tells you have drive id #3, you have to
         mknod /dev/<any_name> b 25 3
    
    If you further make a link like
@@ -91,123 +112,120 @@
 
 5. Reboot with the new kernel.
 
-You should now be able to do "mount -t iso9660 /dev/sbpcd /mnt"
-and see the contents of your CD in the /mnt directory, and/or
-hear music with "workman -c /dev/sbpcd &".
+You should now be able to do "mount -t iso9660 -o block=2048 /dev/sbpcd /mnt"
+and see the contents of your CD in the /mnt directory, and/or hear music with
+"workman -c /dev/sbpcd &".
 
 
 Things of interest:
 -------------------
 
-The driver is configured to try the SoundBlaster Pro type of
-interface at I/O port 0x0230 first. If this is not appropriate,
-sbpcd.h should get changed (you will find the right place -
-just at the beginning).
-
-No DMA and no IRQ is used, so the IRQ adjusting is not necessary,
-and the IRQ line stays free for the SB Pro sound drivers.
-
-To reduce or increase the amount of kernel messages, edit
-sbpcd.c and change the initialization of the variable
-"sbpcd_debug". This is the way to get rid of the initial
-warning message block, too.
-
-With "#define MANY_SESSION 1" (sbpcd.c), the driver can use
-"many-session" CDs. This will work only with "new" drives like 
-CR-562 or CR-563. That is NOT multisession - it is a CD
-with multiple independent sessions, each containing block
-addresses as if it were the only session. With this feature
-enabled, the driver will read the LAST session. Without it,
-the FIRST session gets read.
-If you would like the support of reading "in-between" sessions,
-drop me a mail and some food for the soul. :-)
-Those "many-session" CDs can get made by CDROM writers like
-Philips CDD 521.
-If you enable this feature, it is impossible to read true
-multisession CDs.
+The driver is configured to try the SoundBlaster Pro type of interface at
+I/O port 0x0230 first. If this is not appropriate, sbpcd.h should get changed
+(you will find the right place - just at the beginning).
+
+No DMA and no IRQ is used, so the IRQ line stays free for the SB Pro sound
+drivers.
+
+To reduce or increase the amount of kernel messages, edit sbpcd.c and change
+the initialization of the variable "sbpcd_debug". This is the way to get rid
+of the initial warning message block, too.
+
+With "#define MANY_SESSION 1" (sbpcd.c), the driver can use "many-session" CDs.
+This will work only with "new" drives like CR-562 or CR-563. That is NOT
+multisession - it is a CD with multiple independent sessions, each containing
+block addresses as if it were the only session. With this feature enabled, the
+driver will read the LAST session. Without it, the FIRST session gets read.
+If you would like the support of reading "in-between" sessions, drop me a mail
+and some food for the soul. :-)
+Those "many-session" CDs can get made by CDROM writers like Philips CDD 521.
+If you enable this feature, it is impossible to read true multisession CDs.
 
+The driver uses the "variable BLOCK_SIZE" feature. To use it, you have to
+specify "block=2048" as a mount option.
 
+
 Auto-probing at boot time:
 --------------------------
 
-The driver does auto-probing at all well-known interface card
-addresses now. The idea to do that came from Adam J. Richter 
-(YGGDRASIL).
-
-This auto-probing looks first at the configured address resp.
-the address submitted by the kernel command line. With this,
-it is possible to use this driver within installation boot
-floppies, and for any non-standard address, too.
-
-Auto-probing will make an assumption about the interface type 
-("SBPRO" or not), based upon the address. That assumption may
-be wrong (initialization will be o.k., but you will get I/O
-errors during mount). In that case, use the "kernel command 
-line" feature and specify address & type at boot time to find 
-out the right setup.
-
-SBPCD's auto-probing happens before the initialization of the
-net drivers. That makes a hang possible if an ethernet card
-gets touched.
-
-For every-day use, address and type should get configured
-within sbpcd.h. That will stop the auto-probing due to success
-with the first try.
+The driver does auto-probing at many well-known interface card addresses. The
+idea to do that came from Adam J. Richter (YGGDRASIL). Some well-known
+addresses are excluded from auto-probing because they can cause a hang if an
+ethernet card gets touched.
+
+This auto-probing looks first at the configured address resp. the address
+submitted by the kernel command line. With this, it is possible to use this
+driver within installation boot floppies, and for any non-standard address,
+too.
+
+Auto-probing will make an assumption about the interface type ("SBPRO" or not),
+based upon the address. That assumption may be wrong (initialization will be
+o.k., but you will get I/O errors during mount). In that case, use the "kernel
+command line" feature and specify address & type at boot time to find out the
+right setup.
+
+SBPCD's auto-probing happens before the initialization of the net drivers. That
+makes a hang possible if an ethernet card gets touched.
+
+For every-day use, address and type should get configured within sbpcd.h. That
+will stop the auto-probing due to success with the first try.
 
 
 Setting up address and interface type:
 --------------------------------------
 
-If your I/O port address is not 0x0230 or if you use a "no-sound"
-interface other than OmniCD, you have to look for the #defines
-near the beginning of sbpcd.h and configure them: set SBPRO to
-0 or 1, and change CDROM_PORT to the address of your CDROM I/O port.
-
-Most of the "SoundBlaster compatible" cards behave like the
-no-sound interfaces! 
-
-With "original" SB Pro cards, an initial setting of CD_volume
-through the sound cards MIXER register gets done. That happens
-at the end of "sbpcd_init". If you are using a "compatible"
-sound card of type "LaserMate", you can change that code to get
-it done with your card, too...
+If your I/O port address is not 0x0230 or if you use a "no-sound" interface
+other than OmniCD, you have to look for the #defines near the beginning of
+sbpcd.h and configure them: set SBPRO to 0 or 1 or 2, and change CDROM_PORT to
+the address of your CDROM I/O port.
+
+Most of the "SoundBlaster compatible" cards behave like the no-sound
+interfaces! 
+
+With "original" SB Pro cards, an initial setting of CD_volume through the
+sound cards MIXER register gets done. That happens at the end of "sbpcd_init".
+If you are using a "compatible" sound card of type "LaserMate", you can change
+that code to get it done with your card, too...
 
 
 Using audio CDs:
 ----------------
 
-Workman, WorkBone, xcdplayer and cdplayer should work good now,
-even with the double-speed drives.
+Workman, WorkBone, xcdplayer and cdplayer should work good now, even with the
+double-speed drives.
 
-The program CDplayer likes to talk to "/dev/mcd" only, xcdplayer
-wants "/dev/rsr0", workman loves "/dev/sr0" - so, do the appropriate
-links for using them without the need of supplying parameters.
+The program CDplayer likes to talk to "/dev/mcd" only, xcdplayer wants
+"/dev/rsr0", workman loves "/dev/sr0" - so, do the appropriate links for using
+them without the need of supplying parameters.
 
 
 Known problems:
 ---------------
 
-Currently, the detection of disk change or removal does not
-work as good as it should.
+Currently, the detection of disk change or removal does not work as good as it
+should.
+
+The "door (un)lock" commands get done at every "(u)mount" (only the "new"
+drives support it), but after an unlock, locking again does not work properly.
+
+All attempts to read the UPC/EAN code result in a stream of zeroes. All my
+drives are telling there is no UPC/EAN code on disk or there is, but it is an
+all-zero number.
 
-The "door (un)lock" commands get done at every "(u)mount" (only the
-"new" drives support it), but after an unlock, locking again does not
-work.
-
-All attempts to read the UPC/EAN code result in a stream of zeroes.
-All my drives are telling there is no UPC/EAN code on disk or there
-is, but it is an all-zero number.
+My attempts to read audio tracks like data files are of no success. Contact me,
+if you have an idea, please.
 
-Bug reports, comments, wishes, donations (technical information
-is a donation, too :-) etc. to
+Bug reports, comments, wishes, donations (technical information is a donation,
+too :-) etc. to
                          emoenke@gwdg.de
  or to                   eberhard_moenkeberg@rollo.central.de
  or to my FIDO address:  Eberhard Moenkeberg, 2:2437/210.27
 
 
-SnailMail address, preferable for CD editors if they want to submit
-a free "cooperation" copy:
+SnailMail address, preferable for CD editors if they want to submit a free
+"cooperation" copy:
                          Eberhard Moenkeberg
                          Reinholdstr. 14
                          D-37083 Goettingen
                          Germany
+---
diff -u --recursive --new-file v1.1.17/linux/drivers/block/blk.h linux/drivers/block/blk.h
--- v1.1.17/linux/drivers/block/blk.h	Wed Apr  6 10:40:57 1994
+++ linux/drivers/block/blk.h	Thu Jun  2 10:33:26 1994
@@ -82,6 +82,9 @@
 extern unsigned long hd_init(unsigned long mem_start, unsigned long mem_end);
 extern unsigned long cdu31a_init(unsigned long mem_start, unsigned long mem_end);
 extern unsigned long mcd_init(unsigned long mem_start, unsigned long mem_end);
+#ifdef CONFIG_SBPCD
+extern unsigned long sbpcd_init(unsigned long, unsigned long);
+#endif CONFIG_SBPCD
 extern int is_read_only(int dev);
 extern void set_device_ro(int dev,int flag);
 
diff -u --recursive --new-file v1.1.17/linux/drivers/block/ll_rw_blk.c linux/drivers/block/ll_rw_blk.c
--- v1.1.17/linux/drivers/block/ll_rw_blk.c	Tue Apr 19 10:53:18 1994
+++ linux/drivers/block/ll_rw_blk.c	Thu Jun  2 10:33:26 1994
@@ -19,10 +19,6 @@
 
 #include "blk.h"
 
-#ifdef CONFIG_SBPCD
-extern u_long sbpcd_init(u_long, u_long);
-#endif CONFIG_SBPCD
-
 /*
  * The request-struct contains all necessary data
  * to load a nr of sectors into memory
diff -u --recursive --new-file v1.1.17/linux/drivers/block/sbpcd.c linux/drivers/block/sbpcd.c
--- v1.1.17/linux/drivers/block/sbpcd.c	Tue May 31 12:48:15 1994
+++ linux/drivers/block/sbpcd.c	Thu Jun  2 10:33:27 1994
@@ -5,7 +5,7 @@
  *            and for "no-sound" interfaces like Lasermate and the
  *            Panasonic CI-101P.
  *
- *  NOTE:     This is release 1.5.
+ *  NOTE:     This is release 1.6.
  *            It works with my SbPro & drive CR-521 V2.11 from 2/92
  *            and with the new CR-562-B V0.75 on a "naked" Panasonic
  *            CI-101P interface. And vice versa. 
@@ -76,6 +76,22 @@
  *       Adapt to kernel 1.1.8 change (have to explicitely include
  *       <linux/string.h> now).
  *
+ *  1.6  Trying to read audio frames as data. Impossible with the current
+ *       drive firmware levels, as it seems. Awaiting any hint. ;-)
+ *       Changed "door unlock": repeat it until success.
+ *       Changed CDROMSTOP routine (stop somewhat "softer" so that Workman
+ *       won't get confused).
+ *       Added a third interface type: Sequoia S-1000, as used with the SPEA
+ *       Media FX sound card. This interface (useable for Sony and Mitsumi 
+ *       drives, too) needs a special configuration setup and behaves like a 
+ *       LaserMate type after that. Still experimental - I do not have such
+ *       an interface.
+ *       Use the "variable BLOCK_SIZE" feature (2048). But it does only work
+ *       if you give the mount option "block=2048".
+ *       The media_check routine is currently disabled; now that it gets
+ *       called as it should I fear it must get synchronized for not to
+ *       disturb the normal driver's activity.
+ *
  *     special thanks to Kai Makisara (kai.makisara@vtt.fi) for his fine
  *     elaborated speed-up experiments (and the fabulous results!), for
  *     the "push" towards load-free wait loops, and for the extensive mail
@@ -111,6 +127,7 @@
 #include <linux/errno.h>
 
 #include <linux/sched.h>
+/* #undef DS */
 #include <linux/timer.h>
 #include <linux/fs.h>
 #include <linux/kernel.h>
@@ -118,13 +135,7 @@
 #include <linux/ioport.h>
 #include <linux/sbpcd.h>
 #include <linux/string.h>
-
-#if SBPCD_USE_IRQ
-#include <linux/signal.h>
-#endif SBPCD_USE_IRQ
-
 #include <linux/major.h> 
-
 #include <asm/system.h>
 #include <asm/io.h>
 #include <asm/segment.h>
@@ -133,7 +144,7 @@
 #define MAJOR_NR MATSUSHITA_CDROM_MAJOR
 #include "blk.h"
 
-#define VERSION "1.5 Eberhard Moenkeberg <emoenke@gwdg.de>"
+#define VERSION "1.6 Eberhard Moenkeberg <emoenke@gwdg.de>"
 
 #define SBPCD_DEBUG
 
@@ -159,6 +170,7 @@
 #define XA_TEST2
 
 #define TEST_UPC 0
+#define READ_AUDIO 0 /* does not work today (the drives won't read audio) */
 
 /*==========================================================================*/
 /*==========================================================================*/
@@ -167,8 +179,14 @@
 #undef LONG_TIMING
 #define LONG_TIMING 1
 #endif
-
 /*==========================================================================*/
+#if SBPCD_DIS_IRQ
+#define SBPCD_CLI cli()
+#define SBPCD_STI sti()
+#else
+#define SBPCD_CLI
+#define SBPCD_STI
+#endif SBPCD_DIS_IRQ
 /*==========================================================================*/
 /*
  * auto-probing address list
@@ -201,6 +219,10 @@
   0x650, 0, /* "sound card #9" */
   0x670, 0, /* "sound card #9" */
   0x690, 0, /* "sound card #9" */
+  0x330, 2, /* SPEA Media FX (default) */
+  0x320, 2, /* SPEA Media FX */
+  0x340, 2, /* SPEA Media FX */
+  0x350, 2, /* SPEA Media FX */
 #if 0
 /* some "hazardous" locations (ethernet cards) */
   0x330, 0, /* Lasermate, CI-101P */
@@ -227,7 +249,7 @@
  * pattern for printk selection:
  *
  * (1<<DBG_INF)  necessary information
- * (1<<DBG_IRQ)  interrupt trace
+ * (1<<DBG_BSZ)  BLOCK_SIZE trace
  * (1<<DBG_REA)  "read" status trace
  * (1<<DBG_CHK)  "media check" trace
  * (1<<DBG_TIM)  datarate timer test
@@ -250,6 +272,7 @@
  * (1<<DBG_XA)   XA mode debugging
  * (1<<DBG_LCK)  door (un)lock info
  * (1<<DBG_SQ)   dump SubQ frame
+ * (1<<DBG_AUD)  "read audio" debugging
  * (1<<DBG_000)  unnecessary information
  */
 #if 1
@@ -261,7 +284,9 @@
                           (1<<DBG_IOC) |
                           (1<<DBG_XA)  |
                           (1<<DBG_LCK) |
-                          (1<<DBG_SQ)  |
+                          (1<<DBG_CHK) |
+                          (1<<DBG_AUD) |
+                          (1<<DBG_BSZ) |
                           (1<<DBG_IOX);
 #endif
 static int sbpcd_ioaddr = CDROM_PORT;	/* default I/O base address */
@@ -278,6 +303,7 @@
 static struct cdrom_volctrl volctrl;
 char *str_sb = "SoundBlaster";
 char *str_lm = "LaserMate";
+char *str_sp = "SPEA";
 char *type;
 
 /*==========================================================================*/
@@ -323,6 +349,8 @@
 /*  /A:... for (i=0;i<4;i++) drv_pattern[i] |= sax_a; */
 /*  /N:... ndrives=i-'0';                             */
 
+static int sbpcd_blocksizes[NR_SBPCD] = {0, };
+
 /*==========================================================================*/
 /*
  * drive space begins here (needed separate for each unit) 
@@ -341,6 +369,12 @@
   int sbp_read_frames;   /* Number of frames being read to buffer */
   int sbp_current;       /* Frame being currently read */
 
+  u_char mode;           /* read_mode: READ_M1, READ_M2, READ_SC, READ_AU */
+#if READ_AUDIO
+  u_char *aud_buf;                  /* Pointer to internal data buffer,
+                                 space allocated during sbpcd_init() */
+#endif READ_AUDIO
+
   u_char drv_type;
   u_char drv_options;
   u_char status_byte;
@@ -405,7 +439,7 @@
   
   int in_SpinUp;
   
-} DriveStruct[4];
+} DriveStruct[NR_SBPCD];
 
 /*
  * drive space ends here (needed separate for each unit)
@@ -739,14 +773,10 @@
   if (!new_drive) OUT(CDo_command,0x81);
   else
     {
-#if SBPCD_DIS_IRQ
-      cli();
-#endif SBPCD_DIS_IRQ
+      SBPCD_CLI;
       OUT(CDo_command,0x05);
       for (i=0;i<6;i++) OUT(CDo_command,0);
-#if SBPCD_DIS_IRQ
-      sti();
-#endif SBPCD_DIS_IRQ
+      SBPCD_STI;
     }
 }
 /*==========================================================================*/
@@ -791,21 +821,17 @@
       for (i=0;i<7;i++) DPRINTF((DBG_CMD," %02X",drvcmd[i]));
       DPRINTF((DBG_CMD,"\n"));
 
-#if SBPCD_DIS_IRQ
-      cli();
-#endif SBPCD_DIS_IRQ
+      SBPCD_CLI;
       for (i=0;i<7;i++) OUT(CDo_command,drvcmd[i]);
-#if SBPCD_DIS_IRQ
-      sti();
-#endif SBPCD_DIS_IRQ
+      SBPCD_STI;
     }
   if (response_count!=0)
     {
       if (cmd_type!=0)
 	{
-	  if (sbpro_type) OUT(CDo_sel_d_i,0x01);
+	  if (sbpro_type==1) OUT(CDo_sel_d_i,0x01);
 	  DPRINTF((DBG_INF,"SBPCD: misleaded to try ResponseData.\n"));
-	  if (sbpro_type) OUT(CDo_sel_d_i,0x00);
+	  if (sbpro_type==1) OUT(CDo_sel_d_i,0x00);
 	  return (-22);
 	}
       else i=ResponseInfo();
@@ -1738,7 +1764,7 @@
   d=num;
 
   i=num;
-  if (sbpro_type) i=(i&0x01)<<1|(i&0x02)>>1;
+  if (sbpro_type==1) i=(i&0x01)<<1|(i&0x02)>>1;
   OUT(CDo_enable,i);
   DPRINTF((DBG_DID,"SBPCD: switch_drive: drive %d activated.\n",DriveStruct[d].drv_minor));
   return (0);
@@ -1951,6 +1977,10 @@
 {
   int i;
 
+#if READ_AUDIO
+      DriveStruct[d].mode=READ_M1;
+#endif READ_AUDIO
+
   i=SetSpeed();
   if (i<0)
     {
@@ -2139,6 +2169,51 @@
 }
 /*==========================================================================*/
 /*==========================================================================*/
+/*==========================================================================*/
+/*
+ * Called from the timer to check the results of the get-status cmd.
+ */
+static int sbp_status(void)
+{
+  int st;
+
+  st=ResponseStatus();
+  if (st<0)
+    {
+      DPRINTF((DBG_INF,"SBPCD: sbp_status: timeout.\n"));
+      return (0);
+    }
+
+  if (!st_spinning) DPRINTF((DBG_SPI,"SBPCD: motor got off - ignoring.\n"));
+
+  if (st_check) 
+    {
+      DPRINTF((DBG_INF,"SBPCD: st_check detected - retrying.\n"));
+      return (0);
+    }
+  if (!st_door_closed)
+    {
+      DPRINTF((DBG_INF,"SBPCD: door is open - retrying.\n"));
+      return (0);
+    }
+  if (!st_caddy_in)
+    {
+      DPRINTF((DBG_INF,"SBPCD: disk removed - retrying.\n"));
+      return (0);
+    }
+  if (!st_diskok) 
+    {
+      DPRINTF((DBG_INF,"SBPCD: !st_diskok detected - retrying.\n"));
+      return (0);
+    }
+  if (st_busy) 
+    {
+      DPRINTF((DBG_INF,"SBPCD: st_busy detected - retrying.\n"));
+      return (0);
+    }
+  return (1);
+}
+/*==========================================================================*/
 
 /*==========================================================================*/
 /*==========================================================================*/
@@ -2310,14 +2385,8 @@
 
     case CDROMSTOP:      /* Spin down the drive */
       DPRINTF((DBG_IOC,"SBPCD: ioctl: CDROMSTOP entered.\n"));
-      i=DriveReset();
-#if WORKMAN
-      DriveStruct[d].CD_changed=0xFF;
-      DriveStruct[d].diskstate_flags=0;
-#endif WORKMAN
-      DPRINTF((DBG_IOC,"SBPCD: ioctl: DriveReset returns %d\n",i));
+      i=xx_Pause_Resume(1);
       DriveStruct[d].audio_state=0;
-      i=DiskInfo();
       return (0);
 
     case CDROMSTART:  /* Spin up the drive */
@@ -2396,14 +2465,238 @@
 	       SC.cdsc_absaddr,SC.cdsc_reladdr));
       return (0);
 
+    case CDROMREADMODE1:
+      DPRINTF((DBG_IOC,"SBPCD: ioctl: CDROMREADMODE1 requested.\n"));
+      xx_ModeSelect(CD_FRAMESIZE);
+      xx_ModeSense();
+      DriveStruct[d].mode=READ_M1;
+      return (0);
+
     case CDROMREADMODE2:
       DPRINTF((DBG_IOC,"SBPCD: ioctl: CDROMREADMODE2 requested.\n"));
-      return (-EINVAL);
+      xx_ModeSelect(CD_FRAMESIZE_XA);
+      xx_ModeSense();
+      DriveStruct[d].mode=READ_M2;
+      return (0);
 
-    case CDROMREADMODE1:
-      DPRINTF((DBG_IOC,"SBPCD: ioctl: CDROMREADMODE1 requested.\n"));
-      return (-EINVAL);
-      
+#if READ_AUDIO
+    case CDROMREADAUDIO:
+      { /* start of CDROMREADAUDIO */
+
+      int i=0, j=0, frame, block;
+      u_int try=0;
+      u_long timeout;
+      u_char *p;
+      u_int data_tries = 0;
+      u_int data_waits = 0;
+      u_int data_retrying = 0;
+      int status_tries;
+      int error_flag;
+      struct cdrom_aud aud_arg;
+
+      error_flag=0;
+
+#if 0
+#define AUD_FRM_SIZ CD_FRAMESIZE_RAW
+#else
+#define AUD_FRM_SIZ CD_FRAMESIZE_XA
+#endif
+
+      DPRINTF((DBG_IOC,"SBPCD: read_audio: ioctl: CDROMREADAUDIO requested.\n"));
+
+      i=verify_area(VERIFY_READ, (void *) arg, sizeof(struct cdrom_aud));
+      if (i) return (i);
+      memcpy_fromfs(&aud_arg, (void *) arg, sizeof(struct cdrom_aud));
+      i=verify_area(VERIFY_WRITE, aud_arg.buf, AUD_FRM_SIZ);
+      if (i) return (i);
+      DPRINTF((DBG_AUD,"SBPCD: read_audio: lba: %d, buffer: %08X\n", aud_arg.lba, aud_arg.buf));
+
+      DPRINTF((DBG_AUD,"SBPCD: read_audio: before xx_ReadStatus.\n"));
+      for (data_tries=5; data_tries>0; data_tries--)
+	{
+	  DPRINTF((DBG_AUD,"SBPCD: data_tries=%d ...\n", data_tries));
+	  DriveStruct[d].mode=READ_AU;
+	  xx_ModeSelect(AUD_FRM_SIZ);
+	  xx_ModeSense();
+
+
+	  for (status_tries=3; status_tries > 0; status_tries--)
+	    {
+	      flags_cmd_out |= f_respo3;
+	      xx_ReadStatus();
+	      if (sbp_status() != 0) break;
+	      sbp_sleep(1);    /* wait a bit, try again */
+	    }
+	  if (status_tries == 0)
+	    {
+	      DPRINTF((DBG_AUD,"SBPCD: read_audio: sbp_status: failed after 3 tries.\n"));
+	      continue;
+	    }
+	  DPRINTF((DBG_AUD,"SBPCD: read_audio: sbp_status: ok.\n"));
+
+
+	  block=aud_arg.lba;
+	  flags_cmd_out = f_putcmd |
+	                  f_respo2 |
+                          f_ResponseStatus |
+                          f_obey_p_check;
+
+
+
+
+	  if (!new_drive)
+	    {
+	      flags_cmd_out |= f_lopsta | f_getsta | f_bit1;
+	      cmd_type=READ_M2;
+	      drvcmd[0]=0x03;   /* "read XA frames" command for old drives */
+	      drvcmd[1]=(block>>16)&0x000000ff;
+	      drvcmd[2]=(block>>8)&0x000000ff;
+	      drvcmd[3]=block&0x000000ff;
+	      drvcmd[4]=0;
+	      drvcmd[5]=1;   /* # of frames */
+	      drvcmd[6]=0;
+	    }
+	  else /* if new_drive */
+	    {
+	      drvcmd[0]=0x10;              /* "read frames" command for new drives */
+	      lba2msf(block,&drvcmd[1]); /* msf-bin format required */
+	      drvcmd[4]=0;
+	      drvcmd[5]=0;
+	      drvcmd[6]=1;   /* # of frames */
+	    }
+
+
+
+	  DPRINTF((DBG_AUD,"SBPCD: read_audio: before giving \"read\" command.\n"));
+	  for (i=0;i<7;i++) OUT(CDo_command,drvcmd[i]);
+
+	  sbp_sleep(0);
+
+	  DPRINTF((DBG_AUD,"SBPCD: read_audio: after giving \"read\" command.\n"));
+	  for (frame=1;frame<2 && !error_flag; frame++)
+	    {
+	      try=maxtim_data;
+	      for (timeout=jiffies+900; ; )
+		{
+		  for ( ; try!=0;try--)
+		    {
+		      j=inb(CDi_status);
+		      if (!(j&s_not_data_ready)) break;
+		      if (!(j&s_not_result_ready)) break;
+		      if (!new_drive) if (j&s_attention) break;
+		    }
+		  if (try != 0 || timeout <= jiffies) break;
+		  if (data_retrying == 0) data_waits++;
+		  data_retrying = 1;
+		  sbp_sleep(1);
+		  try = 1;
+		}
+	      if (try==0)
+		{
+		  DPRINTF((DBG_INF,"SBPCD: read_audio: sbp_data: CDi_status timeout.\n"));
+		  error_flag++;
+		  break;
+		}
+	      DPRINTF((DBG_INF,"SBPCD: read_audio: sbp_data: CDi_status ok.\n"));
+	      
+	      if (j&s_not_data_ready)
+		{
+		  printk("SBPCD: read_audio: sbp_data: DATA_READY timeout.\n");
+		  error_flag++;
+		  break;
+		}
+	      
+	      DPRINTF((DBG_AUD,"SBPCD: read_audio: before reading data.\n"));
+	      CLEAR_TIMER;
+	      error_flag=0;
+	      p = DriveStruct[d].aud_buf;
+	      if (sbpro_type==1) OUT(CDo_sel_d_i,0x01);
+	      READ_DATA(CDi_data, p, AUD_FRM_SIZ);
+	      if (sbpro_type==1) OUT(CDo_sel_d_i,0x00);
+	      data_retrying = 0;
+	    }
+	  DPRINTF((DBG_AUD,"SBPCD: read_audio: after reading data.\n"));
+	  if (error_flag)    /* must have been spurious D_RDY or (ATTN&&!D_RDY) */
+	    {
+	      DPRINTF((DBG_AUD,"SBPCD: read_audio: read aborted by drive\n"));
+#if 0000
+	      i=DriveReset();                /* ugly fix to prevent a hang */
+#endif 0000
+	      continue;
+	    }
+
+	  if (!new_drive)
+	    {
+	      i=maxtim_data;
+	      for (timeout=jiffies+900; timeout > jiffies; timeout--)
+		{
+		  for ( ;i!=0;i--)
+		    {
+		      j=inb(CDi_status);
+		      if (!(j&s_not_data_ready)) break;
+		      if (!(j&s_not_result_ready)) break;
+		      if (j&s_attention) break;
+		    }
+		  if (i != 0 || timeout <= jiffies) break;
+		  sbp_sleep(0);
+		  i = 1;
+		}
+	      if (i==0) { DPRINTF((DBG_AUD,"SBPCD: read_audio: STATUS TIMEOUT AFTER READ")); }
+	      if (!(j&s_attention))
+		{
+		  DPRINTF((DBG_AUD,"SBPCD: read_audio: sbp_data: timeout waiting DRV_ATTN - retrying\n"));
+		  i=DriveReset();  /* ugly fix to prevent a hang */
+		  continue;
+		}
+	    }
+
+	  do
+	    {
+	      if (!new_drive) xx_ReadStatus();
+	      i=ResponseStatus();  /* builds status_byte, returns orig. status (old) or faked p_success_old (new) */
+	      if (i<0) { DPRINTF((DBG_AUD,
+				  "SBPCD: read_audio: xx_ReadStatus error after read: %02X\n",
+				  DriveStruct[d].status_byte));
+			 continue; /* FIXME */
+		       }
+	    }
+	  while ((!new_drive)&&(!st_check)&&(!(i&p_success_old)));
+	  if (st_check)
+	    {
+	      i=xx_ReadError();
+	      DPRINTF((DBG_AUD,"SBPCD: read_audio: xx_ReadError was necessary after read: %02X\n",i));
+	      continue;
+	    }
+	  memcpy_tofs((u_char *) aud_arg.buf,
+		      (u_char *) DriveStruct[d].aud_buf, AUD_FRM_SIZ);
+	  DPRINTF((DBG_AUD,"SBPCD: read_audio: memcpy_tofs done.\n"));
+	  break;
+	}
+      xx_ModeSelect(CD_FRAMESIZE);
+      xx_ModeSense();
+      DriveStruct[d].mode=READ_M1;
+
+
+      if (data_tries == 0)
+	{
+	  DPRINTF((DBG_AUD,"SBPCD: read_audio: failed after 5 tries.\n"));
+	  return (-8);
+	}
+      DPRINTF((DBG_AUD,"SBPCD: read_audio: successful return.\n"));
+      return (0);
+    } /* end of CDROMREADAUDIO */
+#endif READ_AUDIO
+
+
+
+
+    case BLKRASET:
+      if(!suser())  return -EACCES;
+      if(!inode->i_rdev) return -EINVAL;
+      if(arg > 0xff) return -EINVAL;
+      read_ahead[MAJOR(inode->i_rdev)] = arg;
+      return (0);
+
     default:
       DPRINTF((DBG_IOC,"SBPCD: ioctl: unknown function request %04X\n", cmd));
       return (-EINVAL);
@@ -2431,63 +2724,6 @@
 }
 /*==========================================================================*/
 /*
- *  We seem to get never an interrupt.
- */
-#if SBPCD_USE_IRQ
-static void sbpcd_interrupt(int unused)
-{
-  int st;
-  
-  st = inb(CDi_status) & 0xFF;
-  DPRINTF((DBG_IRQ,"SBPCD: INTERRUPT received - CDi_status=%02X\n", st));
-}
-#endif SBPCD_USE_IRQ
-/*==========================================================================*/
-/*
- * Called from the timer to check the results of the get-status cmd.
- */
-static int sbp_status(void)
-{
-  int st;
-
-  st=ResponseStatus();
-  if (st<0)
-    {
-      DPRINTF((DBG_INF,"SBPCD: sbp_status: timeout.\n"));
-      return (0);
-    }
-
-  if (!st_spinning) DPRINTF((DBG_SPI,"SBPCD: motor got off - ignoring.\n"));
-
-  if (st_check) 
-    {
-      DPRINTF((DBG_INF,"SBPCD: st_check detected - retrying.\n"));
-      return (0);
-    }
-  if (!st_door_closed)
-    {
-      DPRINTF((DBG_INF,"SBPCD: door is open - retrying.\n"));
-      return (0);
-    }
-  if (!st_caddy_in)
-    {
-      DPRINTF((DBG_INF,"SBPCD: disk removed - retrying.\n"));
-      return (0);
-    }
-  if (!st_diskok) 
-    {
-      DPRINTF((DBG_INF,"SBPCD: !st_diskok detected - retrying.\n"));
-      return (0);
-    }
-  if (st_busy) 
-    {
-      DPRINTF((DBG_INF,"SBPCD: st_busy detected - retrying.\n"));
-      return (0);
-    }
-  return (1);
-}
-/*==========================================================================*/
-/*
  *  I/O request routine, called from Linux kernel.
  */
 static void do_sbpcd_request(void)
@@ -2513,9 +2749,8 @@
   switch_drive(dev);
 
   INIT_REQUEST;
-  block = CURRENT->sector;
-  nsect = CURRENT->nr_sectors;
-
+  block = CURRENT->sector; /* always numbered as 512-byte-pieces */
+  nsect = CURRENT->nr_sectors; /* always counted as 512-byte-pieces */
   if (CURRENT->cmd != READ)
     {
       printk("SBPCD: bad cmd %d\n", CURRENT->cmd);
@@ -2523,11 +2758,11 @@
       goto request_loop;
     }
 
+  DPRINTF((DBG_BSZ,"SBPCD: read sector %d (%d sectors)\n", block, nsect));
   DPRINTF((DBG_MUL,"SBPCD: read LBA %d\n", block/4));
-  sbp_transfer();
 
+  sbp_transfer();
   /* if we satisfied the request from the buffer, we're done. */
-
   if (CURRENT->nr_sectors == 0)
     {
       end_request(1);
@@ -2535,7 +2770,8 @@
     }
 
   i=prepare(0,0); /* at moment not really a hassle check, but ... */
-  if (i!=0) DPRINTF((DBG_INF,"SBPCD: \"prepare\" tells error %d -- ignored\n", i));
+  if (i!=0)
+    DPRINTF((DBG_INF,"SBPCD: \"prepare\" tells error %d -- ignored\n", i));
 
   if (!st_spinning) xx_SpinUp();
 
@@ -2674,13 +2910,9 @@
       drvcmd[5]=0;
       drvcmd[6]=DriveStruct[d].sbp_read_frames;
     }
-#if SBPCD_DIS_IRQ
-  cli();
-#endif SBPCD_DIS_IRQ
+  SBPCD_CLI;
   for (i=0;i<7;i++) OUT(CDo_command,drvcmd[i]);
-#if SBPCD_DIS_IRQ
-  sti();
-#endif SBPCD_DIS_IRQ
+  SBPCD_STI;
 
   return;
 }
@@ -2704,9 +2936,7 @@
 
   for (frame=DriveStruct[d].sbp_current;frame<DriveStruct[d].sbp_read_frames&&!error_flag; frame++)
     {
-#if SBPCD_DIS_IRQ
-      cli();
-#endif SBPCD_DIS_IRQ
+      SBPCD_CLI;
       try=maxtim_data;
 #if LONG_TIMING
       for (timeout=jiffies+900; ; )
@@ -2742,20 +2972,17 @@
 	  error_flag++;
 	  break;
 	}
-      
-#if SBPCD_DIS_IRQ
-      sti();
-#endif SBPCD_DIS_IRQ
 
+      SBPCD_STI;
       CLEAR_TIMER;
       error_flag=0;
       p = DriveStruct[d].sbp_buf + frame *  CD_FRAMESIZE;
 
-      if (sbpro_type) OUT(CDo_sel_d_i,0x01);
+      if (sbpro_type==1) OUT(CDo_sel_d_i,0x01);
       if (cmd_type==READ_M2) READ_DATA(CDi_data, xa_head_buf, CD_XA_HEAD);
       READ_DATA(CDi_data, p, CD_FRAMESIZE);
       if (cmd_type==READ_M2) READ_DATA(CDi_data, xa_tail_buf, CD_XA_TAIL);
-      if (sbpro_type) OUT(CDo_sel_d_i,0x00);
+      if (sbpro_type==1) OUT(CDo_sel_d_i,0x00);
       DriveStruct[d].sbp_current++;
       if (cmd_type==READ_M2)
 	{
@@ -2773,9 +3000,7 @@
 	  data_waits = data_tries = 0;
 	}
     }
-#if SBPCD_DIS_IRQ
-  sti();
-#endif SBPCD_DIS_IRQ
+  SBPCD_STI;
   
   if (error_flag)    /* must have been spurious D_RDY or (ATTN&&!D_RDY) */
     {
@@ -2786,9 +3011,7 @@
 
   if (!new_drive)
     {
-#if SBPCD_DIS_IRQ
-      cli();
-#endif	SBPCD_DIS_IRQ
+      SBPCD_CLI;
       i=maxtim_data;
       for (timeout=jiffies+100; timeout > jiffies; timeout--)
 	{
@@ -2808,14 +3031,10 @@
 	{
 	  DPRINTF((DBG_INF,"SBPCD: sbp_data: timeout waiting DRV_ATTN - retrying\n"));
 	  i=DriveReset();  /* ugly fix to prevent a hang */
-#if SBPCD_DIS_IRQ
-	  sti();
-#endif SBPCD_DIS_IRQ
+	  SBPCD_STI;
 	  return (0);
 	}
-#if SBPCD_DIS_IRQ
-      sti();
-#endif SBPCD_DIS_IRQ
+      SBPCD_STI;
     }
 
   do
@@ -2916,7 +3135,12 @@
  */
   DPRINTF((DBG_LCK,"SBPCD: open_count: %d -> %d\n",
 	   DriveStruct[d].open_count,DriveStruct[d].open_count-1));
-  if (--DriveStruct[d].open_count==0) yy_LockDoor(0);
+  if (--DriveStruct[d].open_count==0) 
+    {
+      do
+	i=yy_LockDoor(0);
+      while (i!=0);
+    }
 }
 /*==========================================================================*/
 /*
@@ -2932,21 +3156,10 @@
   sbpcd_ioctl,            /* ioctl */
   NULL,                   /* mmap */
   sbpcd_open,             /* open */
-  sbpcd_release           /* release */
-};
-/*==========================================================================*/
-/*
- *  SBP interrupt descriptor
- */
-#if SBPCD_USE_IRQ
-static struct sigaction sbpcd_sigaction =
-{
-  sbpcd_interrupt,
-  0,
-  SA_INTERRUPT,
-  NULL
+  sbpcd_release,          /* release */
+  NULL,                   /* fsync */
+  NULL                    /* fasync */
 };
-#endif SBPCD_USE_IRQ
 /*==========================================================================*/
 /*
  * accept "kernel command line" parameters 
@@ -2956,6 +3169,8 @@
  *                 sbpcd=0x230,SoundBlaster
  *             or
  *                 sbpcd=0x300,LaserMate
+ *             or
+ *                 sbpcd=0x330,SPEA
  *
  * (upper/lower case sensitive here!!!).
  *
@@ -2966,8 +3181,9 @@
 void sbpcd_setup(char *s, int *p)
 {
   DPRINTF((DBG_INI,"SBPCD: sbpcd_setup called with %04X,%s\n",p[1], s));
+  sbpro_type=0;
   if (!strcmp(s,str_sb)) sbpro_type=1;
-  else sbpro_type=0;
+  else if (!strcmp(s,str_sp)) sbpro_type=2;
   if (p[0]>0) sbpcd_ioaddr=p[1];
 
   CDo_command=sbpcd_ioaddr;
@@ -2986,6 +3202,57 @@
 }
 /*==========================================================================*/
 /*
+ * Sequoia S-1000 CD-ROM Interface Configuration
+ * as used within SPEA Media FX card
+ * The SPEA soundcard has to get jumpered for 
+ *     -> interface type "Matsushita/Panasonic" (not Sony or Mitsumi)
+ *     -> I/O base address (0x320, 0x330, 0x340, 0x350)
+ */
+int config_spea(void)
+{
+  int n_ports=0x10; /* 2:0x00, 8:0x10, 16:0x20, 32:0x30 */
+  int irq_number=0; /* 2:0x01, 7:0x03, 12:0x05, 15:0x07, OFF:0x00 */
+  int dma_channel=0; /* 0:0x08, 1:0x18, 3:0x38, 5:0x58, 6:0x68, 7:0x78, OFF: 0x00 */
+  int dack_polarity=0; /* L:0x00, H:0x80 */
+  int drq_polarity=0x40; /* L:0x00, H:0x40 */
+
+  int i;
+
+#define SPEA_REG_1 sbpcd_ioaddr+4
+#define SPEA_REG_2 sbpcd_ioaddr+5
+
+  OUT(SPEA_REG_1,0xFF);
+  i=inb(SPEA_REG_1);
+  if (i!=0x0F)
+    {
+      DPRINTF((DBG_INF,"SBPCD: no SPEA interface at %04X present.\n",
+	       sbpcd_ioaddr));
+      return (-1); /* no interface found */
+    }
+  OUT(SPEA_REG_1,0x04);
+  OUT(SPEA_REG_2,0xC0);
+
+  OUT(SPEA_REG_1,0x05);
+  OUT(SPEA_REG_2,0x10|drq_polarity|dack_polarity);
+
+#if 1
+#define SPEA_PATTERN 0x80
+#else
+#define SPEA_PATTERN 0x00
+#endif
+  OUT(SPEA_REG_1,0x06);
+  OUT(SPEA_REG_2,dma_channel|irq_number|SPEA_PATTERN);
+  OUT(SPEA_REG_2,dma_channel|irq_number|SPEA_PATTERN);
+
+  OUT(SPEA_REG_1,0x09);
+  i=(inb(SPEA_REG_2)&0xCF)|n_ports;
+  OUT(SPEA_REG_2,i);
+
+  sbpro_type = 0; /* acts like a LaserMate interface now */
+  return (0);
+}
+/*==========================================================================*/
+/*
  *  Test for presence of drive and initialize it.  Called at boot time.
  */
 u_long sbpcd_init(u_long mem_start, u_long mem_end)
@@ -3006,6 +3273,8 @@
   DPRINTF((DBG_WRN,"SBPCD:    LILO boot: linux sbpcd=0x230,SoundBlaster\n"));
   DPRINTF((DBG_WRN,"SBPCD: or like:\n"));
   DPRINTF((DBG_WRN,"SBPCD:    LILO boot: linux sbpcd=0x300,LaserMate\n"));
+  DPRINTF((DBG_WRN,"SBPCD: or like:\n"));
+  DPRINTF((DBG_WRN,"SBPCD:    LILO boot: linux sbpcd=0x330,SPEA\n"));
   DPRINTF((DBG_WRN,"SBPCD: \n"));
   DPRINTF((DBG_WRN,"SBPCD: with your REAL address.\n"));
   DPRINTF((DBG_WRN,"SBPCD: = = = = = = = = = = END of WARNING = = = = = = = = = =\n"));
@@ -3021,13 +3290,19 @@
       if (check_region(addr[1],4)) continue;
       DPRINTF((DBG_INI,"SBPCD: check_region done.\n"));
       if (autoprobe[port_index+1]==0) type=str_lm;
-      else type=str_sb;
+      else if (autoprobe[port_index+1]==1) type=str_sb;
+      else type=str_sp;
       sbpcd_setup(type, addr);
       DPRINTF((DBG_INF,"SBPCD: Trying to detect a %s CD-ROM drive at 0x%X.\n",
 	             type, CDo_command));
 
       DPRINTF((DBG_INF,"SBPCD: - "));
       sti(); /* to avoid possible "printk" bug */
+      if (autoprobe[port_index+1]==2)
+	{
+	  i=config_spea();
+	  if (i<0) continue;
+	}
       i=check_drives();
       DPRINTF((DBG_INI,"SBPCD: check_drives done.\n"));
       sti(); /* to avoid possible "printk" bug */
@@ -3098,62 +3373,66 @@
       if (i>=0) DriveStruct[d].CD_changed=1;
     }
 
-  if (sbpro_type)
+  if (sbpro_type==1)
     {
       OUT(MIXER_addr,MIXER_CD_Volume);
       OUT(MIXER_data,0xCC); /* one nibble per channel */
     }
   
-  if (register_blkdev(MATSUSHITA_CDROM_MAJOR, "sbpcd", &sbpcd_fops) != 0)
+  if (register_blkdev(MAJOR_NR, "sbpcd", &sbpcd_fops) != 0)
     {
-      printk("SBPCD: Can't get MAJOR %d for Matsushita CDROM\n",
-	       MATSUSHITA_CDROM_MAJOR);
+      printk("SBPCD: Can't get MAJOR %d for Matsushita CDROM\n", MAJOR_NR);
       sti(); /* to avoid possible "printk" bug */
       return (mem_start);
     }
-  blk_dev[MATSUSHITA_CDROM_MAJOR].request_fn = DEVICE_REQUEST;
-  read_ahead[MATSUSHITA_CDROM_MAJOR] = 4; /* just one frame */ 
+  blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
+  read_ahead[MAJOR_NR] = SBP_BUFFER_FRAMES * (CD_FRAMESIZE / 512);
   
   snarf_region(CDo_command,4);
 
-#if SBPCD_USE_IRQ
-  if (irqaction(SBPCD_INTR_NR, &sbpcd_sigaction))
+  for (j=0;j<NR_SBPCD;j++)
     {
-      printk("SBPCD: Can't get IRQ%d for sbpcd driver\n", SBPCD_INTR_NR);
-      sti(); /* to avoid possible "printk" bug */
-    }
-#endif SBPCD_USE_IRQ
-
+      if (DriveStruct[j].drv_minor==-1) continue;
 /*
  * allocate memory for the frame buffers
  */ 
-  for (j=0;j<NR_SBPCD;j++)
-    {
-      if (DriveStruct[j].drv_minor==-1) continue;
       DriveStruct[j].sbp_buf=(u_char *)mem_start;
       mem_start += SBP_BUFFER_FRAMES*CD_FRAMESIZE;
+#if READ_AUDIO
+      DriveStruct[j].aud_buf=(u_char *)mem_start;
+      mem_start += CD_FRAMESIZE_RAW;
+#endif READ_AUDIO
+/*
+ * set the block size
+ */
+      sbpcd_blocksizes[j]=CD_FRAMESIZE;
     }
+  blksize_size[MAJOR_NR]=sbpcd_blocksizes;
+
   DPRINTF((DBG_INF,"SBPCD: init done.\n"));
   sti(); /* to avoid possible "printk" bug */
   return (mem_start);
 }
 /*==========================================================================*/
 /*
- * adopted from sr.c
- *
  * Check if the media has changed in the CD-ROM drive.
- * used externally (isofs/inode.c) - but still does not work.
- *
+ * used externally (isofs/inode.c, fs/buffer.c)
+ * Currently disabled (has to get "synchronized").
  */
 int check_sbpcd_media_change(int full_dev, int unused_minor)
 {
   int st;
 
-  if (MAJOR(full_dev) != MATSUSHITA_CDROM_MAJOR) 
+  DPRINTF((DBG_CHK,"SBPCD: media_check (%d) called\n", MINOR(full_dev)));
+  return (0); /* "busy" test necessary before we really can check */
+
+  if ((MAJOR(full_dev)!=MAJOR_NR)||(MINOR(full_dev)>=NR_SBPCD))
     {
-      printk("SBPCD: media_check: invalid device.\n");
+      printk("SBPCD: media_check: invalid device %04X.\n", full_dev);
       return (-1);
     }
+
+  switch_drive(MINOR(full_dev));
   
   xx_ReadStatus();                         /* command: give 1-byte status */
   st=ResponseStatus();
diff -u --recursive --new-file v1.1.17/linux/drivers/net/Space.c linux/drivers/net/Space.c
--- v1.1.17/linux/drivers/net/Space.c	Tue May 31 12:48:17 1994
+++ linux/drivers/net/Space.c	Wed Jun  1 09:40:01 1994
@@ -281,6 +281,14 @@
 #define NEXT_DEV (&ppp0_dev)
 #endif   /* PPP */
 
+#ifdef CONFIG_DUMMY
+    extern int dummy_init(struct device *dev);
+    static struct device dummy_dev = {
+	"dummy", 0x0, 0x0, 0x0, 0x0, 0, 0, 0, 0, 0, NEXT_DEV, dummy_init, };
+#   undef	NEXT_DEV
+#   define	NEXT_DEV	(&dummy_dev)
+#endif
+
 #ifdef LOOPBACK
     extern int loopback_init(struct device *dev);
     static struct device loopback_dev = {
diff -u --recursive --new-file v1.1.17/linux/drivers/net/ppp.c linux/drivers/net/ppp.c
--- v1.1.17/linux/drivers/net/ppp.c	Tue May 31 12:48:18 1994
+++ linux/drivers/net/ppp.c	Thu Jun  2 10:36:43 1994
@@ -94,6 +94,7 @@
 int ppp_init(struct device *);
 static void ppp_init_ctrl_blk(struct ppp *);
 static int ppp_dev_open(struct device *);
+static int ppp_dev_ioctl(struct device *dev, struct ifreq *ifr);
 static int ppp_dev_close(struct device *);
 static void ppp_kick_tty(struct ppp *);
 
@@ -264,6 +265,7 @@
   dev->mtu             = PPP_MTU;
   dev->hard_start_xmit = ppp_xmit;
   dev->open            = ppp_dev_open;
+  dev->do_ioctl        = ppp_dev_ioctl;
   dev->stop            = ppp_dev_close;
   dev->get_stats       = ppp_get_stats;
   dev->hard_header     = ppp_header;
@@ -601,6 +603,32 @@
   return 0;
 }
 
+static int ppp_dev_ioctl(struct device *dev, struct ifreq *ifr)
+{
+  struct ppp *ppp = &ppp_ctrl[dev->base_addr];
+  int    error;
+
+  struct stats
+  {
+    struct ppp_stats  ppp_stats;
+    struct slcompress slhc;
+  } *result;
+
+  error = verify_area (VERIFY_READ,
+		       ifr->ifr_ifru.ifru_data,
+		       sizeof (struct stats));
+
+  if (error == 0) {
+    result = (struct stats *) ifr->ifr_ifru.ifru_data;
+
+    memcpy_tofs (&result->ppp_stats, &ppp->stats, sizeof (struct ppp_stats));
+    if (ppp->slcomp)
+      memcpy_tofs (&result->slhc,    ppp->slcomp, sizeof (struct slcompress));
+  }
+
+  return error;
+}
+
 /*************************************************************
  * TTY OUTPUT
  *    The following function delivers a fully-formed PPP
@@ -882,6 +910,8 @@
   if (ppp_debug >= 5) {
     ppp_print_buffer ("receive buffer", cp, count, KERNEL_DS);
   }
+
+  ppp->stats.rbytes += count;
  
   while (count-- > 0) {
     c = *cp++;
@@ -1367,7 +1397,7 @@
       PRINTKN (3,(KERN_INFO "ppp_ioctl: set mru to %x\n", temp_i));
       temp_i = (int) get_fs_long (l);
       if (ppp->mru != temp_i)
-	ppp_changedmtu (ppp, ppp->mtu, temp_i);
+	ppp_changedmtu (ppp, ppp->dev->mtu, temp_i);
     }
     break;
 
diff -u --recursive --new-file v1.1.17/linux/drivers/scsi/buslogic.c linux/drivers/scsi/buslogic.c
--- v1.1.17/linux/drivers/scsi/buslogic.c	Fri May 27 10:49:08 1994
+++ linux/drivers/scsi/buslogic.c	Thu Jun  2 10:22:04 1994
@@ -562,7 +562,6 @@
 	if (bufflen != sizeof SCpnt->sense_buffer) {
 	    buslogic_printk("Wrong buffer length supplied for request sense (%d)\n",
 			    bufflen);
-	    panic("buslogic.c: wrong buffer length for request sense");
 	}
 #endif
 	SCpnt->result = 0;
@@ -781,6 +780,7 @@
 	buslogic_printk("buslogic_detect: failed setting up mailboxes\n");
     }
     ok = TRUE;
+    return ok;
   must_be_adaptec:
     INTR_RESET(base);
     printk("- must be Adaptec\n"); /* So that the adaptec detect looks clean */
@@ -888,7 +888,6 @@
 /* Query the board to find out the model. */
 static int buslogic_query(unsigned int base, int *trans)
 {
-#if 0
     unsigned const char inquiry_cmd[] = { CMD_INQUIRY };
     unsigned char inquiry_result[4];
     int i;
@@ -899,14 +898,18 @@
     buslogic_out(base, inquiry_cmd, sizeof inquiry_cmd);
     buslogic_in(base, inquiry_result, 4);
     WAIT_UNTIL(INTERRUPT(base), CMDC);
+    INTR_RESET(base);
+
+    buslogic_printk("Inquiry Bytes: %X %X %X %X\n",
+		    inquiry_result[0],inquiry_result[1],
+		    inquiry_result[2],inquiry_result[3]);
     while (0) {
       fail:
-	buslogic_printk("buslogic_detect: query card type\n");
+	buslogic_printk("buslogic_query: query board settings\n");
+	return TRUE;
     }
-    INTR_RESET(base);
-#endif
 
-    *trans = BIOS_TRANSLATION_6432;	/* Default case */
+    *trans = BIOS_TRANSLATION_6432;     /* Default case */
 
     return FALSE;
 }
@@ -1018,8 +1021,13 @@
 
 	    host[irq - 9] = SHpnt;
 	    SHpnt->this_id = id;
+#ifdef CONFIG_NO_BUGGY_BUSLOGIC
 	    /* Only type 'A' (AT/ISA) bus adapters use unchecked DMA. */
 	    SHpnt->unchecked_isa_dma = (bus_type == 'A');
+#else
+	    /* bugs in the firmware with 16M+. Gaah */
+	    SHpnt->unchecked_isa_dma = 1;
+#endif
 	    SHpnt->sg_tablesize = max_sg;
 	    if (SHpnt->sg_tablesize > BUSLOGIC_MAX_SG)
 		SHpnt->sg_tablesize = BUSLOGIC_MAX_SG;
diff -u --recursive --new-file v1.1.17/linux/fs/buffer.c linux/fs/buffer.c
--- v1.1.17/linux/fs/buffer.c	Mon May 23 12:14:24 1994
+++ linux/fs/buffer.c	Thu Jun  2 10:33:28 1994
@@ -44,6 +44,9 @@
 #ifdef CONFIG_MCD
 extern int check_mcd_media_change(int, int);
 #endif
+#ifdef CONFIG_SBPCD
+extern int check_sbpcd_media_change(int, int);
+#endif
 
 #define NR_SIZES 4
 static char buffersize_index[9] = {-1,  0,  1, -1,  2, -1, -1, -1, 3};
@@ -331,6 +334,12 @@
 #if defined(CONFIG_MCD)
          case MITSUMI_CDROM_MAJOR:
 		i = check_mcd_media_change(dev, 0);
+		break;
+#endif
+
+#if defined(CONFIG_SBPCD)
+         case MATSUSHITA_CDROM_MAJOR:
+		i = check_sbpcd_media_change(dev, 0);
 		break;
 #endif
 
Only in v1.1.17/linux/include/linux: mktime.h
diff -u --recursive --new-file v1.1.17/linux/include/linux/sbpcd.h linux/include/linux/sbpcd.h
--- v1.1.17/linux/include/linux/sbpcd.h	Tue May 31 12:48:19 1994
+++ linux/include/linux/sbpcd.h	Thu Jun  2 10:33:28 1994
@@ -8,6 +8,8 @@
  *                                 sbpcd=0x230,SoundBlaster
  *                             or
  *                                 sbpcd=0x300,LaserMate
+ *                             or
+ *                                 sbpcd=0x330,SPEA
  * these strings are case sensitive !!!
  */
 
@@ -17,6 +19,7 @@
  * set SBPRO to 1 for "true" SoundBlaster card
  * set SBPRO to 0 for "poor" (no sound) interface cards
  *                and for "compatible" soundcards.
+ * set SBPRO to 2 for the SPEA Media FX card
  *
  * most "compatible" sound boards like Galaxy need to set SBPRO to 0 !!!
  * if SBPRO gets set wrong, the drive will get found - but any
@@ -33,6 +36,7 @@
  * put your CDROM port base address here:
  * SBPRO addresses typically are 0x0230 (=0x220+0x10), 0x0250, ...
  * LASERMATE (CI-101P) adresses typically are 0x0300, 0x0310, ...
+ * SPEA addresses are 0x320, 0x330, 0x340, 0x350
  * there are some soundcards on the market with 0x0630, 0x0650, ...
  *
  * example: if your SBPRO audio address is 0x220, specify 0x230.
@@ -52,7 +56,7 @@
  * Debug output levels
  */
 #define DBG_INF		1	/* necessary information */
-#define DBG_IRQ		2	/* interrupt trace */
+#define DBG_BSZ		2	/* BLOCK_SIZE trace */
 #define DBG_REA		3	/* "read" status trace */
 #define DBG_CHK		4	/* "media check" trace */
 #define DBG_TIM		5	/* datarate timer test */
@@ -75,7 +79,8 @@
 #define DBG_XA 		22	/* XA mode debugging */
 #define DBG_LCK		23	/* door (un)lock info */
 #define DBG_SQ 		24	/* dump SubQ frame */
-#define DBG_000		25	/* unnecessary information */
+#define DBG_AUD		25      /* "read audio" debugging */
+#define DBG_000		26      /* unnecessary information */
 
 /*==========================================================================*/
 /*==========================================================================*/
@@ -199,8 +204,18 @@
 #define READ_M1  0x01 /* "data mode 1": 2048 bytes per frame */
 #define READ_M2  0x02 /* "data mode 2": 12+2048+280 bytes per frame */
 #define READ_SC  0x04 /* "subchannel info": 96 bytes per frame */
+#define READ_AU  0x08 /* "audio frame": 2352 bytes per frame */
 
 /*
+ * preliminary extensions to cdrom.h for transfering audio frames:
+ */
+#define CDROMREADAUDIO 0xE0 /* IOCTL function (arg = &cdrom_aud) */
+
+struct cdrom_aud { u_int lba; /* frame address */
+                   u_char *buf; /* frame buffer (2352 bytes) */
+                 };
+
+/*
  * sense byte: used only if new_drive
  *                  only during cmd 09 00 xx ah al 00 00
  *
@@ -401,17 +416,6 @@
 #define SBPCD_DIS_IRQ 0
 
 /*
- * we don't use the IRQ line - leave it free for the sound driver
- */
-#define SBPCD_USE_IRQ	0
-
-/*
- * you can set the interrupt number of your interface board here:
- * It is not used at this time. No need to set it correctly.
- */
-#define SBPCD_INTR_NR	7            
-
-/*
  * "write byte to port"
  */
 #define OUT(x,y) outb(y,x)
@@ -463,9 +467,3 @@
 BLK;
 
 /*==========================================================================*/
-
-
-
-
-
-
diff -u --recursive --new-file v1.1.17/linux/kernel/Makefile linux/kernel/Makefile
--- v1.1.17/linux/kernel/Makefile	Tue May 24 00:34:58 1994
+++ linux/kernel/Makefile	Thu Jun  2 10:43:14 1994
@@ -18,7 +18,7 @@
 
 OBJS  = sched.o sys_call.o traps.o irq.o dma.o fork.o \
  	panic.o printk.o vsprintf.o sys.o module.o ksyms.o exit.o \
-	signal.o mktime.o ptrace.o ioport.o itimer.o \
+	signal.o ptrace.o ioport.o itimer.o \
 	info.o ldt.o time.o tqueue.o vm86.o
 
 all: kernel.o
Only in v1.1.17/linux/kernel: mktime.c
diff -u --recursive --new-file v1.1.17/linux/kernel/sched.c linux/kernel/sched.c
--- v1.1.17/linux/kernel/sched.c	Fri May 27 10:49:15 1994
+++ linux/kernel/sched.c	Thu Jun  2 10:37:53 1994
@@ -517,6 +517,8 @@
 	if (xtime.tv_sec > last_rtc_update + 660)
 	  if (set_rtc_mmss(xtime.tv_sec) == 0)
 	    last_rtc_update = xtime.tv_sec;
+	  else
+	    last_rtc_update = xtime.tv_sec - 600; /* do it again in one min */
 }
 
 /*
diff -u --recursive --new-file v1.1.17/linux/kernel/time.c linux/kernel/time.c
--- v1.1.17/linux/kernel/time.c	Mon Jan 31 09:01:36 1994
+++ linux/kernel/time.c	Thu Jun  2 10:54:37 1994
@@ -14,6 +14,8 @@
  *      Created file with time related functions from sched.c and adjtimex() 
  * 08 Oct 93    Torsten Duwe
  *      adjtime interface update and CMOS clock write code
+ * 02 Jul 94	Alan Modra
+ *	fixed set_rtc_mmss, fixed time.year for >= 2000, new mktime
  */
 
 #include <linux/config.h>
@@ -32,12 +34,36 @@
 #include <linux/timex.h>
 extern struct timeval xtime;
 
-#include <linux/mktime.h>
-extern long kernel_mktime(struct mktime * time);
+/* converts date to days since 1/1/1970
+ * assumes year,mon,day in normal date format
+ * ie. 1/1/1970 => year=1970, mon=1, day=1
+ *
+ * For the Julian calendar (which was used in Russia before 1917,
+ * Britain & colonies before 1752, anywhere else before 1582,
+ * and is still in use by some communities) leave out the
+ * -year/100+year/400 terms, and add 10.
+ *
+ * This algorithm was first published by Gauss (I think).
+ */
+static inline unsigned long mktime(unsigned int year, unsigned int mon,
+	unsigned int day, unsigned int hour,
+	unsigned int min, unsigned int sec)
+{
+	if (0 >= (int) (mon -= 2)) {	/* 1..12 -> 11,12,1..10 */
+		mon += 12;	/* Puts Feb last since it has leap day */
+		year -= 1;
+	}
+	return (((
+	    (unsigned long)(year/4 - year/100 + year/400 + 367*mon/12 + day) +
+	      year*365 - 719499
+	    )*24 + hour /* now have hours */
+	   )*60 + min /* now have minutes */
+	  )*60 + sec; /* finally seconds */
+}
 
 void time_init(void)
 {
-	struct mktime time;
+	unsigned int year, mon, day, hour, min, sec;
 	int i;
 
 	/* checking for Update-In-Progress could be done more elegantly
@@ -53,25 +79,26 @@
 		if (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP))
 			break;
 	do { /* Isn't this overkill ? UIP above should guarantee consistency */
-		time.sec = CMOS_READ(RTC_SECONDS);
-		time.min = CMOS_READ(RTC_MINUTES);
-		time.hour = CMOS_READ(RTC_HOURS);
-		time.day = CMOS_READ(RTC_DAY_OF_MONTH);
-		time.mon = CMOS_READ(RTC_MONTH);
-		time.year = CMOS_READ(RTC_YEAR);
-	} while (time.sec != CMOS_READ(RTC_SECONDS));
+		sec = CMOS_READ(RTC_SECONDS);
+		min = CMOS_READ(RTC_MINUTES);
+		hour = CMOS_READ(RTC_HOURS);
+		day = CMOS_READ(RTC_DAY_OF_MONTH);
+		mon = CMOS_READ(RTC_MONTH);
+		year = CMOS_READ(RTC_YEAR);
+	} while (sec != CMOS_READ(RTC_SECONDS));
 	if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
 	  {
-	    BCD_TO_BIN(time.sec);
-	    BCD_TO_BIN(time.min);
-	    BCD_TO_BIN(time.hour);
-	    BCD_TO_BIN(time.day);
-	    BCD_TO_BIN(time.mon);
-	    BCD_TO_BIN(time.year);
+	    BCD_TO_BIN(sec);
+	    BCD_TO_BIN(min);
+	    BCD_TO_BIN(hour);
+	    BCD_TO_BIN(day);
+	    BCD_TO_BIN(mon);
+	    BCD_TO_BIN(year);
 	  }
-	time.mon--;
-	xtime.tv_sec = kernel_mktime(&time);
-      }
+	if ((year += 1900) < 1970)
+		year += 100;
+	xtime.tv_sec = mktime(year, mon, day, hour, min, sec);
+}
 /* 
  * The timezone where the local system is located.  Used as a default by some
  * programs who obtain this value by using gettimeofday.
@@ -403,8 +430,8 @@
 int set_rtc_mmss(unsigned long nowtime)
 {
   int retval = 0;
-  short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60;
-  unsigned char save_control, save_freq_select, cmos_minutes;
+  int real_seconds, real_minutes, cmos_minutes;
+  unsigned char save_control, save_freq_select;
 
   save_control = CMOS_READ(RTC_CONTROL); /* tell the clock it's being set */
   CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL);
@@ -419,11 +446,15 @@
   /* since we're only adjusting minutes and seconds,
    * don't interfere with hour overflow. This avoids
    * messing with unknown time zones but requires your
-   * RTC not to be off by more than 30 minutes
+   * RTC not to be off by more than 15 minutes
    */
-  if (((cmos_minutes < real_minutes) ?
-       (real_minutes - cmos_minutes) :
-       (cmos_minutes - real_minutes)) < 30)
+  real_seconds = nowtime % 60;
+  real_minutes = nowtime / 60;
+  if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1)
+    real_minutes += 30;		/* correct for half hour time zone */
+  real_minutes %= 60;
+
+  if (abs(real_minutes - cmos_minutes) < 30)
     {
       if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
 	{
diff -u --recursive --new-file v1.1.17/linux/mm/memory.c linux/mm/memory.c
--- v1.1.17/linux/mm/memory.c	Sat May  7 14:54:17 1994
+++ linux/mm/memory.c	Thu Jun  2 12:36:00 1994
@@ -46,6 +46,13 @@
 #include <linux/ptrace.h>
 #include <linux/mman.h>
 
+/*
+ * Define this if things work differently on a i386 and a i486:
+ * it will (on a i486) warn about kernel memory accesses that are
+ * done without a 'verify_area(VERIFY_WRITE,..)'
+ */
+#undef CONFIG_TEST_VERIFY_AREA
+
 unsigned long high_memory = 0;
 
 extern unsigned long pg0[1024];		/* page table for 0-4MB for everybody */
@@ -902,10 +909,15 @@
 			} else 
 				user_esp = regs->esp;
 		}
-		if (error_code & PAGE_PRESENT)
+		if (error_code & PAGE_PRESENT) {
+#ifdef CONFIG_TEST_VERIFY_AREA
+			if (regs->cs == KERNEL_CS)
+				printk("WP fault at %08x\n", regs->eip);
+#endif
 			do_wp_page(error_code, address, current, user_esp);
-		else
+		} else {
 			do_no_page(error_code, address, current, user_esp);
+		}
 		return;
 	}
 	address -= TASK_SIZE;
@@ -1124,6 +1136,9 @@
 	invalidate();
 	if (wp_works_ok < 0)
 		wp_works_ok = 0;
+#ifdef CONFIG_TEST_VERIFY_AREA
+	wp_works_ok = 0;
+#endif
 	return;
 }
 
diff -u --recursive --new-file v1.1.17/linux/net/inet/af_inet.c linux/net/inet/af_inet.c
--- v1.1.17/linux/net/inet/af_inet.c	Tue May 24 00:35:00 1994
+++ linux/net/inet/af_inet.c	Thu Jun  2 11:18:51 1994
@@ -1137,7 +1137,7 @@
 		return -EINVAL;
 	if(size==0)
 		return 0;
-	err=verify_area(VERIFY_READ,ubuf,size);
+	err=verify_area(VERIFY_WRITE,ubuf,size);
 	if(err)
 		return err;
 
@@ -1259,6 +1259,8 @@
 		case SIOCSIFMAP:
 		case SIOCGIFMAP:
 		case SIOCDEVPRIVATE:
+		case SIOCSIFSLAVE:
+		case SIOCGIFSLAVE:
 			return(dev_ioctl(cmd,(void *) arg));
 
 		default:
diff -u --recursive --new-file v1.1.17/linux/net/inet/arp.c linux/net/inet/arp.c
--- v1.1.17/linux/net/inet/arp.c	Thu Jun  2 13:50:55 1994
+++ linux/net/inet/arp.c	Thu Jun  2 10:36:43 1994
@@ -26,6 +26,7 @@
  *		Alan Cox	:	Make ARP add its own protocol entry
  *
  *              Ross Martin     :       Rewrote arp_rcv() and arp_get_info()
+ *		Stephen Henson	:	Add AX25 support to arp_get_info()
  */
 
 #include <linux/types.h>
@@ -846,6 +847,13 @@
 /*
  *	Convert hardware address to XX:XX:XX:XX ... form.
  */
+#ifdef CONFIG_AX25
+
+			if(entry->htype==ARPHRD_AX25)
+			     strcpy(hbuffer,ax2asc((ax25_address *)entry->ha));
+			else {
+#endif
+
 			for(k=0,j=0;k<HBUFFERLEN-3 && j<entry->hlen;j++)
 			{
 				hbuffer[k++]=hexbuf[ (entry->ha[j]>>4)&15 ];
@@ -854,6 +862,9 @@
 			}
 			hbuffer[--k]=0;
 	
+#ifdef CONFIG_AX25
+			}
+#endif
 			size = sprintf(buffer+len,
 				"%-17s0x%-10x0x%-10x%s\n",
 				in_ntoa(entry->ip),
@@ -926,9 +937,6 @@
 	 */
 	
 	switch (r.arp_ha.sa_family) {
-		case 0:
-			/* Moan about this. ARP family 0 is NetROM and _will_ be needed */
-			printk("Application using old BSD convention for arp set. Please recompile it.\n");
 		case ARPHRD_ETHER:
 			htype = ARPHRD_ETHER;
 			hlen = ETH_ALEN;
diff -u --recursive --new-file v1.1.17/linux/net/inet/dev.c linux/net/inet/dev.c
--- v1.1.17/linux/net/inet/dev.c	Tue May 31 12:48:20 1994
+++ linux/net/inet/dev.c	Thu Jun  2 10:36:44 1994
@@ -1267,7 +1267,7 @@
 				return -ENODEV;
 			}
 			cli();
-			if(slave->flags&(IFF_UP|IFF_RUNNING)!=(IFF_UP|IFF_RUNNING))
+			if((slave->flags&(IFF_UP|IFF_RUNNING))!=(IFF_UP|IFF_RUNNING))
 			{
 				restore_flags(flags);
 				return -EINVAL;
@@ -1275,7 +1275,7 @@
 			if(dev->flags&IFF_SLAVE)
 			{
 				restore_flags(flags);
-				return -EINVAL;
+				return -EBUSY;
 			}
 			if(dev->slave!=NULL)
 			{
diff -u --recursive --new-file v1.1.17/linux/net/inet/ip.c linux/net/inet/ip.c
--- v1.1.17/linux/net/inet/ip.c	Thu Jun  2 13:50:56 1994
+++ linux/net/inet/ip.c	Wed Jun  1 10:14:57 1994
@@ -90,6 +90,7 @@
 extern void sort_send(struct sock *sk);
 
 #define min(a,b)	((a)<(b)?(a):(b))
+#define LOOPBACK(x)	(((x) & htonl(0xff000000)) == htonl(0x7f000000))
 
 /*
  *	SNMP management statistics
@@ -226,7 +227,7 @@
 		 *	If the frame is from us and going off machine it MUST MUST MUST
 		 *	have the output device ip address and never the loopback
 		 */
-		if (saddr == htonl(0x7F000001L) && daddr != htonl(0x7F000001L))
+		if (LOOPBACK(saddr) && !LOOPBACK(daddr))
 			saddr = src;/*rt->rt_dev->pa_addr;*/
 		raddr = rt->rt_gateway;
 
@@ -245,7 +246,7 @@
 		 *	If the frame is from us and going off machine it MUST MUST MUST
 		 *	have the output device ip address and never the loopback
 		 */
-		if (saddr == 0x0100007FL && daddr != 0x0100007FL) 
+		if (LOOPBACK(saddr) && !LOOPBACK(daddr))
 			saddr = src;/*rt->rt_dev->pa_addr;*/
 
 		raddr = (rt == NULL) ? 0 : rt->rt_gateway;
