diff -u --recursive --new-file v2.1.72/linux/Documentation/Configure.help linux/Documentation/Configure.help
--- v2.1.72/linux/Documentation/Configure.help	Wed Dec 10 11:12:42 1997
+++ linux/Documentation/Configure.help	Wed Dec 17 11:11:16 1997
@@ -248,11 +248,13 @@
 
 Include IDE/ATAPI FLOPPY support
 CONFIG_BLK_DEV_IDEFLOPPY
-  If you have an IDE floppy drive which uses the ATAPI protocol, say
-  Y. Chances are that you don't, because these animals are rare.
+  If you have an IDE floppy drive which uses the ATAPI protocol, say Y.
   ATAPI is a new protocol used by IDE CDROM/tape/floppy drives,
-  similar to the SCSI protocol.  At boot time, the FLOPPY drive will
-  be identified along with other IDE devices, as "hdb" or "hdc", or
+  similar to the SCSI protocol.  IDE floppy drives include the
+  LS-120 and the ATAPI ZIP (ATAPI PD-CD/CDR drives are not supported
+  by this driver; support for PD-CD/CDR drives is available through
+  the SCSI emulation). At boot time, the FLOPPY drive will be
+  identified along with other IDE devices, as "hdb" or "hdc", or
   something similar. If you want to compile the driver as a module ( =
   code which can be inserted in and removed from the running kernel
   whenever you want), say M here and read Documentation/modules.txt.
@@ -263,10 +265,11 @@
   This will provide SCSI host adapter emulation for IDE ATAPI devices,
   and will allow you to use a SCSI device driver instead of a native
   ATAPI driver. This is useful if you have an ATAPI device for which
-  no native driver has been written; you can then use this emulation
-  together with an appropriate SCSI device driver. If both this SCSI
-  emulation and native ATAPI support are compiled into the kernel, the
-  native support will be used.  Normally, say N.
+  no native driver has been written (for example, an ATAPI PD-CD or
+  CDR drive); you can then use this emulation together with an
+  appropriate SCSI device driver. If both this SCSI emulation and
+  native ATAPI support are compiled into the kernel, the native
+  support will be used.  Normally, say N.
 
 CMD640 chipset bugfix/support
 CONFIG_BLK_DEV_CMD640
@@ -303,17 +306,24 @@
   Linux.  This may slow disk throughput by a few percent, but at least
   things will operate 100% reliably. If unsure, say Y.
 
-Intel 82371 PIIX (Triton I/II), VIA VP-1 DMA support
+Generic PCI IDE chipset support
+CONFIG_BLK_DEV_IDEPCI
+  Enable this for PCI systems which use IDE drive(s).
+  This option helps the IDE driver to automatically detect and
+  configure all PCI-based IDE interfaces in your system.
+  It is safe to say Y to this question.
+
+Generic PCI bus-master DMA support
 CONFIG_BLK_DEV_IDEDMA
-  If your PCI system uses IDE drive(s) (as opposed to SCSI, say)
-  and is capable of bus-master DMA operation (most Pentium PCI
-  systems), you will want to enable this option to allow use of 
-  bus-mastering DMA data transfers. Read the comments at the
-  beginning of drivers/block/idedma.c and Documentation/ide.txt.
-  You can get the latest version of the hdparm utility via 
-  ftp (user: anonymous) from
-  sunsite.unc.edu/pub/Linux/kernel/patches/diskdrives/; it is
-  used to tune your harddisk. 
+  If your PCI IDE controller is capable of bus-master DMA
+  (Direct Memory Access) transfers (most newer systems),
+  then you will want to enable this option to reduce CPU overhead.
+  With this option, Linux will automatically enable DMA transfers
+  in most cases, noting this with "DMA" appended to the drive
+  identification info.  You can also use the "hdparm" utility to
+  enable DMA for drives which were not enabled automatically.
+  You can get the latest version of the hdparm utility via anonymous
+  FTP from sunsite.unc.edu/pub/Linux/system/hardware/
   It is safe to say Y to this question.
 
 Other IDE chipset support
@@ -371,6 +381,12 @@
   for drives attached to an OPTi MIDE controller.
   Please read the comments at the top of drivers/block/opti621.c.
 
+NS87415 support (EXPERIMENTAL)
+CONFIG_BLK_DEV_NS87415
+  This driver adds detection and support for the NS87415 chip
+  (used in SPARC64, among others).
+  Please read the comments at the top of drivers/block/ns87415.c.
+
 QDI QD6580 support
 CONFIG_BLK_DEV_QD6580
   This driver is enabled at runtime using the "ide0=qd6580" kernel
@@ -875,31 +891,8 @@
 
 Kernel support for JAVA binaries
 CONFIG_BINFMT_JAVA
-  JAVA(tm) is an object oriented programming language developed by
-  SUN; JAVA programs are compiled into "JAVA bytecode" binaries which
-  can then be interpreted by run time systems on many different
-  operating systems.  These JAVA binaries are becoming a universal
-  executable format. If you want to execute JAVA binaries, read the
-  Java on Linux HOWTO, available via ftp (user: anonymous) at
-  sunsite.unc.edu:/pub/Linux/docs/HOWTO. You will then need to install
-  the run time system contained in the Java Developers Kit (JDK) as
-  described in the HOWTO. This is completely independent of the Linux
-  kernel and you do NOT need to say Y here for this to work.
-  Saying Y here allows you to execute a JAVA bytecode binary just like
-  any other Linux program: by simply typing in its name. (You also
-  need to have the JDK installed for this to work).  As more and more
-  Java programs become available, the use for this will gradually
-  increase. You can even execute HTML files containing JAVA applets (=
-  JAVA binaries) if those files start with the string
-  "<!--applet-->". If you want to use this, say Y here and read
-  Documentation/java.txt. If you disable this option it will reduce
-  your kernel by about 4kB. This is not much and by itself does not
-  warrant removing support. However its removal is a good idea if you
-  do not have the JDK installed. You may answer M for module support
-  and later load the module when you install the JDK or find an
-  interesting Java program that you can't live without. The module
-  will be called binfmt_java.o. If you don't know what to answer at
-  this point then answer Y.
+  This option is obsolete. Use binfmt_misc instead. It is more 
+  flexible. 
 
 Kernel support for Linux/Intel ELF binaries
 CONFIG_BINFMT_EM86
@@ -1331,6 +1324,37 @@
   automatically be compiled. Modules are pieces of code which can be
   inserted in and removed from the running kernel whenever you want;
   read Documentation/modules.txt for details.
+
+IP: ICMP masquerading
+CONFIG_IP_MASQUERADE_ICMP
+  The basic masquerade code described for CONFIG_IP_MASQUERADE only
+  handles TCP or UDP packets (and ICMP errors for existing 
+  connections).  This option adds additional support for masquerading
+  ICMP packets, such as ping or the probes used by the Windows 95
+  tracert program.
+  If you want this, say Y.
+
+IP: ipautofw masquerade support
+CONFIG_IP_MASQUERADE_IPAUTOFW (Experimental)
+  ipautofw is a program by Richard Lynch allowing additional
+  support for masquerading protocols which do not (as yet)
+  have additional protocol helpers.  
+  Information and source for ipautofw is available from
+  ftp://ftp.netis.com/pub/members/rlynch/
+  The ipautofw code is still under development and so is currently
+  marked EXPERIMENTAL.
+  If you want this, say Y.
+
+IP: ipportfw masquerade support
+CONFIG_IP_MASQUERADE_IPPORTFW
+  ipportfw is an addition to IP Masquerading written by Steven Clarke
+  to allow some forwarding of packets from outside to inside a
+  firewall on given ports. Information and source for ipportfw is
+  available from
+  http://www.monmouth.demon.co.uk/ipsubs/portforwarding.html
+  The portfw code is still under development and so is currently
+  marked EXPERIMENTAL.
+  If you want this, say Y.
 
 IP: always defragment 
 CONFIG_IP_ALWAYS_DEFRAG
diff -u --recursive --new-file v2.1.72/linux/Documentation/filesystems/sysv-fs.txt linux/Documentation/filesystems/sysv-fs.txt
--- v2.1.72/linux/Documentation/filesystems/sysv-fs.txt	Sun Feb 25 01:17:59 1996
+++ linux/Documentation/filesystems/sysv-fs.txt	Tue Dec 16 09:43:36 1997
@@ -28,9 +28,9 @@
 
 
 Please report any bugs and suggestions to
-  Bruno Haible <haible@ma2s2.mathematik.uni-karlsruhe.de> or
-  Pascal Haible <haible@izfm.uni-stuttgart.de> .
-
+  Bruno Haible <haible@ma2s2.mathematik.uni-karlsruhe.de>
+  Pascal Haible <haible@izfm.uni-stuttgart.de>
+  Krzysztof G. Baranowski <kgb@manjak.knm.org.pl>
 
 Bruno Haible
 <haible@ma2s2.mathematik.uni-karlsruhe.de>
diff -u --recursive --new-file v2.1.72/linux/MAINTAINERS linux/MAINTAINERS
--- v2.1.72/linux/MAINTAINERS	Wed Dec 10 11:12:42 1997
+++ linux/MAINTAINERS	Wed Dec 17 11:11:16 1997
@@ -279,6 +279,12 @@
 L:	linux-kernel@vger.rutgers.edu
 S:	Maintained
 
+IDE/ATAPI TAPE/FLOPPY DRIVERS
+P:	Gadi Oxman
+M:	Gadi Oxman <gadio@netvision.net.il>
+L:	linux-kernel@vger.rutgers.edu
+S:	Maintained
+
 ISDN SUBSYSTEM
 P:	Fritz Elfert
 M:	fritz@wuemaus.franken.de
@@ -549,6 +555,11 @@
 NETWORK BLOCK DEVICE
 P:	Pavel Machek
 M:	pavel@atrey.karlin.mff.cuni.cz
+S:	Maintained
+
+SYSV FILESYSTEM
+P:	Krzysztof G. Baranowski
+M:	kgb@manjak.knm.org.pl
 S:	Maintained
 
 REST:
diff -u --recursive --new-file v2.1.72/linux/Makefile linux/Makefile
--- v2.1.72/linux/Makefile	Wed Dec 10 11:12:42 1997
+++ linux/Makefile	Wed Dec 10 10:31:53 1997
@@ -1,6 +1,6 @@
 VERSION = 2
 PATCHLEVEL = 1
-SUBLEVEL = 72
+SUBLEVEL = 73
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/)
 
diff -u --recursive --new-file v2.1.72/linux/arch/i386/defconfig linux/arch/i386/defconfig
--- v2.1.72/linux/arch/i386/defconfig	Thu Dec  4 14:53:54 1997
+++ linux/arch/i386/defconfig	Wed Dec 17 15:17:35 1997
@@ -58,6 +58,7 @@
 CONFIG_BLK_DEV_CMD640=y
 # CONFIG_BLK_DEV_CMD640_ENHANCED is not set
 CONFIG_BLK_DEV_RZ1000=y
+CONFIG_BLK_DEV_IDEPCI=y
 CONFIG_BLK_DEV_IDEDMA=y
 # CONFIG_IDE_CHIPSETS is not set
 
@@ -221,7 +222,6 @@
 # CONFIG_VFAT_FS is not set
 CONFIG_PROC_FS=y
 CONFIG_NFS_FS=y
-# CONFIG_ROOT_NFS is not set
 CONFIG_NFSD=y
 CONFIG_SUNRPC=y
 CONFIG_LOCKD=y
diff -u --recursive --new-file v2.1.72/linux/arch/i386/kernel/process.c linux/arch/i386/kernel/process.c
--- v2.1.72/linux/arch/i386/kernel/process.c	Wed Dec 10 11:12:43 1997
+++ linux/arch/i386/kernel/process.c	Tue Dec  9 17:57:09 1997
@@ -40,6 +40,10 @@
 #include <asm/system.h>
 #include <asm/io.h>
 #include <asm/ldt.h>
+#include <asm/processor.h>
+#ifdef CONFIG_MATH_EMULATION
+#include <asm/math_emu.h>
+#endif
 
 #ifdef __SMP__
 asmlinkage void ret_from_smpfork(void) __asm__("ret_from_smpfork");
@@ -525,19 +529,16 @@
 {
 	int fpvalid;
 
-/* Flag indicating the math stuff is valid. We don't support this for the
-   soft-float routines yet */
-	if (hard_math) {
-		if ((fpvalid = current->used_math) != 0) {
-			if (last_task_used_math == current)
-				__asm__("clts ; fnsave %0": :"m" (*fpu));
+	if ((fpvalid = current->used_math) != 0) {
+		if (hard_math) {
+		  if (last_task_used_math == current) {
+			  __asm__("clts ; fsave %0; fwait": :"m" (*fpu));
+		  }
 			else
 				memcpy(fpu,&current->tss.i387.hard,sizeof(*fpu));
+		} else {
+			memcpy(fpu,&current->tss.i387.hard,sizeof(*fpu));
 		}
-	} else {
-		/* we should dump the emulator state here, but we need to
-		   convert it into standard 387 format first.. */
-		fpvalid = 0;
 	}
 
 	return fpvalid;
diff -u --recursive --new-file v2.1.72/linux/arch/i386/kernel/ptrace.c linux/arch/i386/kernel/ptrace.c
--- v2.1.72/linux/arch/i386/kernel/ptrace.c	Mon Dec  1 12:04:11 1997
+++ linux/arch/i386/kernel/ptrace.c	Tue Dec  9 17:57:09 1997
@@ -16,6 +16,7 @@
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
 #include <asm/system.h>
+#include <asm/processor.h>
 
 /*
  * does not yet catch signals sent when the child dies.
@@ -560,6 +561,102 @@
 			ret = 0;
 			goto out;
 		}
+
+		case PTRACE_GETREGS: { /* Get all gp regs from the child. */
+		  	if (!access_ok(VERIFY_WRITE, (unsigned *)data,
+				       17*sizeof(long)))
+			  {
+			    ret = -EIO;
+			    goto out;
+			  }
+			for ( i = 0; i < 17*sizeof(long); i += sizeof(long) )
+			  {
+			    __put_user(getreg(child, i),(unsigned long *) data);
+			    data += sizeof(long);
+			  }
+			ret = 0;
+			goto out;
+		  };
+
+		case PTRACE_SETREGS: { /* Set all gp regs in the child. */
+			unsigned long tmp;
+		  	if (!access_ok(VERIFY_READ, (unsigned *)data,
+				       17*sizeof(long)))
+			  {
+			    ret = -EIO;
+			    goto out;
+			  }
+			for ( i = 0; i < 17*sizeof(long); i += sizeof(long) )
+			  {
+			    __get_user(tmp, (unsigned long *) data);
+			    putreg(child, i, tmp);
+			    data += sizeof(long);
+			  }
+			ret = 0;
+			goto out;
+		  };
+
+		case PTRACE_GETFPREGS: { /* Get the child FPU state. */
+			if (!access_ok(VERIFY_WRITE, (unsigned *)data,
+				       sizeof(struct user_i387_struct)))
+			  {
+			    ret = -EIO;
+			    goto out;
+			  }
+			ret = 0;
+			if ( !child->used_math ) {
+			  /* Simulate an empty FPU. */
+			  child->tss.i387.hard.cwd = 0xffff037f;
+			  child->tss.i387.hard.swd = 0xffff0000;
+			  child->tss.i387.hard.twd = 0xffffffff;
+			}
+#ifdef CONFIG_MATH_EMULATION
+			if ( hard_math ) {
+#endif
+			  if (last_task_used_math == child) {
+			    clts();
+			    __asm__("fnsave %0; fwait":"=m" (child->tss.i387.hard));
+			    last_task_used_math = NULL;
+			    stts();
+			  }
+			  __copy_to_user((void *)data, &child->tss.i387.hard,
+					 sizeof(struct user_i387_struct));
+#ifdef CONFIG_MATH_EMULATION
+			} else {
+			  save_i387_soft(&child->tss.i387.soft,
+					 (struct _fpstate *)data);
+			}
+#endif
+			goto out;
+		  };
+
+		case PTRACE_SETFPREGS: { /* Set the child FPU state. */
+			if (!access_ok(VERIFY_READ, (unsigned *)data,
+				       sizeof(struct user_i387_struct)))
+			  {
+			    ret = -EIO;
+			    goto out;
+			  }
+			child->used_math = 1;
+#ifdef CONFIG_MATH_EMULATION
+			if ( hard_math ) {
+#endif
+			  if (last_task_used_math == child) {
+			    /* Discard the state of the FPU */
+			    last_task_used_math = NULL;
+			  }
+			  __copy_from_user(&child->tss.i387.hard, (void *)data,
+					   sizeof(struct user_i387_struct));
+			  child->flags &= ~PF_USEDFPU;
+#ifdef CONFIG_MATH_EMULATION
+			} else {
+			  restore_i387_soft(&child->tss.i387.soft,
+					    (struct _fpstate *)data);
+			}
+#endif
+			ret = 0;
+			goto out;
+		  };
 
 		default:
 			ret = -EIO;
diff -u --recursive --new-file v2.1.72/linux/arch/i386/kernel/signal.c linux/arch/i386/kernel/signal.c
--- v2.1.72/linux/arch/i386/kernel/signal.c	Tue Dec  2 09:49:39 1997
+++ linux/arch/i386/kernel/signal.c	Tue Dec  9 17:57:09 1997
@@ -156,7 +156,6 @@
 		stts();
 	}
 #endif
-	current->used_math = 1;
 	current->flags &= ~PF_USEDFPU;
 	__copy_from_user(&current->tss.i387.hard, buf, sizeof(*buf));
 }
@@ -169,8 +168,9 @@
 	if (hard_math)
 		restore_i387_hard(buf);
 	else
-		restore_i387_soft(buf);
+		restore_i387_soft(&current->tss.i387.soft, buf);
 #endif
+	current->used_math = 1;
 }
 
 static int
@@ -309,7 +309,6 @@
 #endif
 	current->tss.i387.hard.status = current->tss.i387.hard.swd;
 	copy_to_user(buf, &current->tss.i387.hard, sizeof(*buf));
-	current->used_math = 0;
 	return buf;
 }
 
@@ -318,10 +317,16 @@
 	if (!current->used_math)
 		return NULL;
 
+	/* This will cause a "finit" to be triggered by the next
+	   attempted FPU operation by the 'current' process.
+	   */
+	current->used_math = 0;
+
 #ifndef CONFIG_MATH_EMULATION
 	return save_i387_hard(buf);
 #else
-	return hard_math ? save_i387_hard(buf) : save_i387_soft(buf);
+	return hard_math ? save_i387_hard(buf)
+	  : save_i387_soft(&current->tss.i387.soft, buf);
 #endif
 }
 
diff -u --recursive --new-file v2.1.72/linux/arch/i386/math-emu/Makefile linux/arch/i386/math-emu/Makefile
--- v2.1.72/linux/arch/i386/math-emu/Makefile	Tue Aug 15 05:07:02 1995
+++ linux/arch/i386/math-emu/Makefile	Tue Dec  9 17:57:09 1997
@@ -12,17 +12,22 @@
 .S.o:
 	$(CC) -D__ASSEMBLY__ $(PARANOID) -c $<
 
-L_OBJS =fpu_entry.o div_small.o errors.o \
-	fpu_arith.o fpu_aux.o fpu_etc.o fpu_trig.o \
+# From 'C' language sources:
+C_OBJS =fpu_entry.o errors.o \
+	fpu_arith.o fpu_aux.o fpu_etc.o fpu_tags.o fpu_trig.o \
 	load_store.o get_address.o \
 	poly_atan.o poly_l2.o poly_2xm1.o poly_sin.o poly_tan.o \
-	reg_add_sub.o reg_compare.o reg_constant.o reg_ld_str.o \
-	reg_div.o reg_mul.o reg_norm.o \
-	reg_u_add.o reg_u_div.o reg_u_mul.o reg_u_sub.o \
-	reg_round.o \
+	reg_add_sub.o reg_compare.o reg_constant.o reg_convert.o \
+	reg_ld_str.o reg_divide.o reg_mul.o
+
+# From 80x86 assembler sources:
+A_OBJS =reg_u_add.o reg_u_div.o reg_u_mul.o reg_u_sub.o \
+	div_small.o reg_norm.o reg_round.o \
 	wm_shrx.o wm_sqrt.o \
 	div_Xsig.o polynom_Xsig.o round_Xsig.o \
 	shr_Xsig.o mul_Xsig.o
+
+L_OBJS =$(C_OBJS) $(A_OBJS)
 
 include $(TOPDIR)/Rules.make
 
diff -u --recursive --new-file v2.1.72/linux/arch/i386/math-emu/README linux/arch/i386/math-emu/README
--- v2.1.72/linux/arch/i386/math-emu/README	Tue Oct 29 05:16:36 1996
+++ linux/arch/i386/math-emu/README	Tue Dec  9 17:57:09 1997
@@ -1,7 +1,7 @@
  +---------------------------------------------------------------------------+
  |  wm-FPU-emu   an FPU emulator for 80386 and 80486SX microprocessors.      |
  |                                                                           |
- | Copyright (C) 1992,1993,1994,1995,1996                                    |
+ | Copyright (C) 1992,1993,1994,1995,1996,1997                               |
  |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
  |                       Australia.  E-mail billm@suburbia.net               |
  |                                                                           |
@@ -44,9 +44,12 @@
 Please report bugs, etc to me at:
        billm@suburbia.net
 
+For more information on the emulator and on floating point topics, see
+my web pages, currently at  http://www.suburbia.net/~billm/
+
 
 --Bill Metzenthen
-  October 1996
+  December 1997
 
 
 ----------------------- Internals of wm-FPU-emu -----------------------
@@ -95,8 +98,9 @@
 ----------------------- Limitations of wm-FPU-emu -----------------------
 
 There are a number of differences between the current wm-FPU-emu
-(version 1.20) and the 80486 FPU (apart from bugs). Some of the more
-important differences are listed below:
+(version 2.00) and the 80486 FPU (apart from bugs).  The differences
+are fewer than those which applied to the 1.xx series of the emulator.
+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
@@ -121,18 +125,6 @@
 and Unnormals. None of these will be generated by an 80486 or by the
 emulator. Do not use them. The emulator treats them differently in
 detail from the way an 80486 does.
-
-The emulator treats PseudoDenormals differently from an 80486. These
-numbers are in fact properly normalised numbers with the exponent
-offset by 1, and the emulator treats them as such. Unlike the 80486,
-the emulator does not generate a Denormal Operand exception for these
-numbers. The arithmetical results produced when using such a number as
-an operand are the same for the emulator and a real 80486 (apart from
-any slight precision difference for the transcendental functions).
-Neither the emulator nor an 80486 produces one of these numbers as the
-result of any arithmetic operation. An 80486 can keep one of these
-numbers in an FPU register with its identity as a PseudoDenormal, but
-the emulator will not; they are always converted to a valid number.
 
 Self modifying code can cause the emulator to fail. An example of such
 code is:
diff -u --recursive --new-file v2.1.72/linux/arch/i386/math-emu/div_small.S linux/arch/i386/math-emu/div_small.S
--- v2.1.72/linux/arch/i386/math-emu/div_small.S	Thu Oct  5 06:30:43 1995
+++ linux/arch/i386/math-emu/div_small.S	Tue Dec  9 17:57:09 1997
@@ -12,13 +12,13 @@
  +---------------------------------------------------------------------------*/
 
 /*---------------------------------------------------------------------------+
- |    unsigned long div_small(unsigned long long *x, unsigned long y)        |
+ |    unsigned long FPU_div_small(unsigned long long *x, unsigned long y)    |
  +---------------------------------------------------------------------------*/
 
 #include "fpu_emu.h"
 
 .text
-ENTRY(div_small)
+ENTRY(FPU_div_small)
 	pushl	%ebp
 	movl	%esp,%ebp
 
diff -u --recursive --new-file v2.1.72/linux/arch/i386/math-emu/errors.c linux/arch/i386/math-emu/errors.c
--- v2.1.72/linux/arch/i386/math-emu/errors.c	Tue Dec  2 09:49:39 1997
+++ linux/arch/i386/math-emu/errors.c	Tue Dec  9 17:57:09 1997
@@ -21,9 +21,9 @@
 
 #include <asm/uaccess.h>
 
+#include "fpu_emu.h"
 #include "fpu_system.h"
 #include "exception.h"
-#include "fpu_emu.h"
 #include "status_w.h"
 #include "control_w.h"
 #include "reg_constant.h"
@@ -36,7 +36,7 @@
 
 void Un_impl(void)
 {
-  unsigned char byte1, FPU_modrm;
+  u_char byte1, FPU_modrm;
   unsigned long address = FPU_ORIG_EIP;
 
   RE_ENTRANT_CHECK_OFF;
@@ -46,13 +46,13 @@
     {
       while ( 1 )
 	{
-	  get_user(byte1, (unsigned char *) address);
+	  FPU_get_user(byte1, (u_char *) address);
 	  if ( (byte1 & 0xf8) == 0xd8 ) break;
 	  printk("[%02x]", byte1);
 	  address++;
 	}
       printk("%02x ", byte1);
-      get_user(FPU_modrm, 1 + (unsigned char *) address);
+      FPU_get_user(FPU_modrm, 1 + (u_char *) address);
       
       if (FPU_modrm >= 0300)
 	printk("%02x (%02x+%d)\n", FPU_modrm, FPU_modrm & 0xf8, FPU_modrm & 7);
@@ -82,12 +82,12 @@
 
 
 
-void emu_printall(void)
+void FPU_printall(void)
 {
   int i;
-  static const char *tag_desc[] = { "Valid", "Zero", "ERROR", "ERROR",
-                              "DeNorm", "Inf", "NaN", "Empty" };
-  unsigned char byte1, FPU_modrm;
+  static const char *tag_desc[] = { "Valid", "Zero", "ERROR", "Empty",
+                              "DeNorm", "Inf", "NaN" };
+  u_char byte1, FPU_modrm;
   unsigned long address = FPU_ORIG_EIP;
 
   RE_ENTRANT_CHECK_OFF;
@@ -98,7 +98,7 @@
 #define MAX_PRINTED_BYTES 20
       for ( i = 0; i < MAX_PRINTED_BYTES; i++ )
 	{
-	  get_user(byte1, (unsigned char *) address);
+	  FPU_get_user(byte1, (u_char *) address);
 	  if ( (byte1 & 0xf8) == 0xd8 )
 	    {
 	      printk(" %02x", byte1);
@@ -111,7 +111,7 @@
 	printk(" [more..]\n");
       else
 	{
-	  get_user(FPU_modrm, 1 + (unsigned char *) address);
+	  FPU_get_user(FPU_modrm, 1 + (u_char *) address);
 	  
 	  if (FPU_modrm >= 0300)
 	    printk(" %02x (%02x+%d)\n", FPU_modrm, FPU_modrm & 0xf8, FPU_modrm & 7);
@@ -166,29 +166,23 @@
   for ( i = 0; i < 8; i++ )
     {
       FPU_REG *r = &st(i);
-      char tagi = r->tag;
+      u_char tagi = FPU_gettagi(i);
       switch (tagi)
 	{
-	case TW_Empty:
+	case TAG_Empty:
 	  continue;
 	  break;
-	case TW_Zero:
-#if 0
-	  printk("st(%d)  %c .0000 0000 0000 0000         ",
-		 i, r->sign ? '-' : '+');
-	  break;
-#endif
-	case TW_Valid:
-	case TW_NaN:
-/*	case TW_Denormal: */
-	case TW_Infinity:
-	  printk("st(%d)  %c .%04lx %04lx %04lx %04lx e%+-6ld ", i,
-		 r->sign ? '-' : '+',
+	case TAG_Zero:
+	case TAG_Special:
+	  tagi = FPU_Special(r);
+	case TAG_Valid:
+	  printk("st(%d)  %c .%04lx %04lx %04lx %04lx e%+-6d ", i,
+		 getsign(r) ? '-' : '+',
 		 (long)(r->sigh >> 16),
 		 (long)(r->sigh & 0xFFFF),
 		 (long)(r->sigl >> 16),
 		 (long)(r->sigl & 0xFFFF),
-		 r->exp - EXP_BIAS + 1);
+		 exponent(r) - EXP_BIAS + 1);
 	  break;
 	default:
 	  printk("Whoops! Error in errors.c: tag%d is %d ", i, tagi);
@@ -262,6 +256,11 @@
 	      0x161  in reg_ld_str.c
 	      0x162  in reg_ld_str.c
 	      0x163  in reg_ld_str.c
+	      0x164  in reg_ld_str.c
+	      0x170  in fpu_tags.c
+	      0x171  in fpu_tags.c
+	      0x172  in fpu_tags.c
+	      0x180  in reg_convert.c
        0x2nn  in an *.S file:
               0x201  in reg_u_add.S
               0x202  in reg_u_div.S
@@ -347,11 +346,11 @@
       if ( n == EX_INTERNAL )
 	{
 	  printk("FPU emulator: Internal error type 0x%04x\n", int_type);
-	  emu_printall();
+	  FPU_printall();
 	}
 #ifdef PRINT_MESSAGES
       else
-	emu_printall();
+	FPU_printall();
 #endif PRINT_MESSAGES
 
       /*
@@ -369,24 +368,97 @@
 }
 
 
-/* Real operation attempted on two operands, one a NaN. */
-/* Returns nz if the exception is unmasked */
-asmlinkage int real_2op_NaN(FPU_REG const *a, FPU_REG const *b, FPU_REG *dest)
+/* Real operation attempted on a NaN. */
+/* Returns < 0 if the exception is unmasked */
+int real_1op_NaN(FPU_REG *a)
 {
-  FPU_REG const *x;
-  int signalling;
+  int signalling, isNaN;
+
+  isNaN = (exponent(a) == EXP_OVER) && (a->sigh & 0x80000000);
 
   /* The default result for the case of two "equal" NaNs (signs may
      differ) is chosen to reproduce 80486 behaviour */
-  x = a;
-  if (a->tag == TW_NaN)
+  signalling = isNaN && !(a->sigh & 0x40000000);
+
+  if ( !signalling )
     {
-      if (b->tag == TW_NaN)
+      if ( !isNaN )  /* pseudo-NaN, or other unsupported? */
+	{
+	  if ( control_word & CW_Invalid )
+	    {
+	      /* Masked response */
+	      reg_copy(&CONST_QNaN, a);
+	    }
+	  EXCEPTION(EX_Invalid);
+	  return (!(control_word & CW_Invalid) ? FPU_Exception : 0) | TAG_Special;
+	}
+      return TAG_Special;
+    }
+
+  if ( control_word & CW_Invalid )
+    {
+      /* The masked response */
+      if ( !(a->sigh & 0x80000000) )  /* pseudo-NaN ? */
+	{
+	  reg_copy(&CONST_QNaN, a);
+	}
+      /* ensure a Quiet NaN */
+      a->sigh |= 0x40000000;
+    }
+
+  EXCEPTION(EX_Invalid);
+
+  return (!(control_word & CW_Invalid) ? FPU_Exception : 0) | TAG_Special;
+}
+
+
+/* Real operation attempted on two operands, one a NaN. */
+/* Returns < 0 if the exception is unmasked */
+int real_2op_NaN(FPU_REG const *b, u_char tagb,
+		 int deststnr,
+		 FPU_REG const *defaultNaN)
+{
+  FPU_REG *dest = &st(deststnr);
+  FPU_REG const *a = dest;
+  u_char taga = FPU_gettagi(deststnr);
+  FPU_REG const *x;
+  int signalling, unsupported;
+
+  if ( taga == TAG_Special )
+    taga = FPU_Special(a);
+  if ( tagb == TAG_Special )
+    tagb = FPU_Special(b);
+
+  /* TW_NaN is also used for unsupported data types. */
+  unsupported = ((taga == TW_NaN)
+		 && !((exponent(a) == EXP_OVER) && (a->sigh & 0x80000000)))
+    || ((tagb == TW_NaN)
+	&& !((exponent(b) == EXP_OVER) && (b->sigh & 0x80000000)));
+  if ( unsupported )
+    {
+      if ( control_word & CW_Invalid )
+	{
+	  /* Masked response */
+	  FPU_copy_to_regi(&CONST_QNaN, TAG_Special, deststnr);
+	}
+      EXCEPTION(EX_Invalid);
+      return (!(control_word & CW_Invalid) ? FPU_Exception : 0) | TAG_Special;
+    }
+
+  if (taga == TW_NaN)
+    {
+      x = a;
+      if (tagb == TW_NaN)
 	{
 	  signalling = !(a->sigh & b->sigh & 0x40000000);
-	  /* find the "larger" */
-	  if ( significand(a) < significand(b) )
+	  if ( significand(b) > significand(a) )
 	    x = b;
+	  else if ( significand(b) == significand(a) )
+	    {
+	      /* The default result for the case of two "equal" NaNs (signs may
+		 differ) is chosen to reproduce 80486 behaviour */
+	      x = defaultNaN;
+	    }
 	}
       else
 	{
@@ -396,7 +468,7 @@
     }
   else
 #ifdef PARANOID
-    if (b->tag == TW_NaN)
+    if (tagb == TW_NaN)
 #endif PARANOID
     {
       signalling = !(b->sigh & 0x40000000);
@@ -411,33 +483,32 @@
     }
 #endif PARANOID
 
-  if ( !signalling )
+  if ( (!signalling) || (control_word & CW_Invalid) )
     {
-      if ( !(x->sigh & 0x80000000) )  /* pseudo-NaN ? */
-	x = &CONST_QNaN;
-      reg_move(x, dest);
-      return 0;
-    }
+      if ( ! x )
+	x = b;
 
-  if ( control_word & CW_Invalid )
-    {
-      /* The masked response */
       if ( !(x->sigh & 0x80000000) )  /* pseudo-NaN ? */
 	x = &CONST_QNaN;
-      reg_move(x, dest);
+
+      FPU_copy_to_regi(x, TAG_Special, deststnr);
+
+      if ( !signalling )
+	return TAG_Special;
+
       /* ensure a Quiet NaN */
       dest->sigh |= 0x40000000;
     }
 
   EXCEPTION(EX_Invalid);
-  
-  return !(control_word & CW_Invalid);
+
+  return (!(control_word & CW_Invalid) ? FPU_Exception : 0) | TAG_Special;
 }
 
 
 /* Invalid arith operation on Valid registers */
-/* Returns nz if the exception is unmasked */
-asmlinkage int arith_invalid(FPU_REG *dest)
+/* Returns < 0 if the exception is unmasked */
+asmlinkage int arith_invalid(int deststnr)
 {
 
   EXCEPTION(EX_Invalid);
@@ -445,28 +516,31 @@
   if ( control_word & CW_Invalid )
     {
       /* The masked response */
-      reg_move(&CONST_QNaN, dest);
+      FPU_copy_to_regi(&CONST_QNaN, TAG_Special, deststnr);
     }
   
-  return !(control_word & CW_Invalid);
+  return (!(control_word & CW_Invalid) ? FPU_Exception : 0) | TAG_Valid;
 
 }
 
 
 /* Divide a finite number by zero */
-asmlinkage int divide_by_zero(int sign, FPU_REG *dest)
+asmlinkage int FPU_divide_by_zero(int deststnr, u_char sign)
 {
+  FPU_REG *dest = &st(deststnr);
+  int tag = TAG_Valid;
 
   if ( control_word & CW_ZeroDiv )
     {
       /* The masked response */
-      reg_move(&CONST_INF, dest);
-      dest->sign = (unsigned char)sign;
+      FPU_copy_to_regi(&CONST_INF, TAG_Special, deststnr);
+      setsign(dest, sign);
+      tag = TAG_Special;
     }
  
   EXCEPTION(EX_ZeroDiv);
 
-  return !(control_word & CW_ZeroDiv);
+  return (!(control_word & CW_ZeroDiv) ? FPU_Exception : 0) | tag;
 
 }
 
@@ -495,7 +569,6 @@
     partial_status |= (SW_Precision | SW_C1);   /* The masked response */
   else
     EXCEPTION(EX_Precision | SW_C1);
-
 }
 
 
@@ -517,32 +590,31 @@
   if ( control_word & CW_Denormal )
     {   /* The masked response */
       partial_status |= SW_Denorm_Op;
-      return 0;
+      return TAG_Special;
     }
   else
     {
       EXCEPTION(EX_Denormal);
-      return 1;
+      return TAG_Special | FPU_Exception;
     }
 }
 
 
 asmlinkage int arith_overflow(FPU_REG *dest)
 {
+  int tag = TAG_Valid;
 
   if ( control_word & CW_Overflow )
     {
-      char sign;
       /* The masked response */
 /* ###### The response here depends upon the rounding mode */
-      sign = dest->sign;
-      reg_move(&CONST_INF, dest);
-      dest->sign = sign;
+      reg_copy(&CONST_INF, dest);
+      tag = TAG_Special;
     }
   else
     {
       /* Subtract the magic number from the exponent */
-      dest->exp -= (3 * (1 << 13));
+      addexponent(dest, (-3 * (1 << 13)));
     }
 
   EXCEPTION(EX_Overflow);
@@ -553,30 +625,36 @@
 	 The roundup bit (C1) is also set because we have
 	 "rounded" upwards to Infinity. */
       EXCEPTION(EX_Precision | SW_C1);
-      return !(control_word & CW_Precision);
+      return tag;
     }
 
-  return 0;
+  return tag;
 
 }
 
 
 asmlinkage int arith_underflow(FPU_REG *dest)
 {
+  int tag = TAG_Valid;
 
   if ( control_word & CW_Underflow )
     {
       /* The masked response */
-      if ( dest->exp <= EXP_UNDER - 63 )
+      if ( exponent16(dest) <= EXP_UNDER - 63 )
 	{
-	  reg_move(&CONST_Z, dest);
+	  reg_copy(&CONST_Z, dest);
 	  partial_status &= ~SW_C1;       /* Round down. */
+	  tag = TAG_Zero;
+	}
+      else
+	{
+	  stdexp(dest);
 	}
     }
   else
     {
       /* Add the magic number to the exponent. */
-      dest->exp += (3 * (1 << 13));
+      addexponent(dest, (3 * (1 << 13)) + EXTENDED_Ebias);
     }
 
   EXCEPTION(EX_Underflow);
@@ -584,22 +662,22 @@
     {
       /* The underflow exception is masked. */
       EXCEPTION(EX_Precision);
-      return !(control_word & CW_Precision);
+      return tag;
     }
 
-  return 0;
+  return tag;
 
 }
 
 
-void stack_overflow(void)
+void FPU_stack_overflow(void)
 {
 
  if ( control_word & CW_Invalid )
     {
       /* The masked response */
       top--;
-      reg_move(&CONST_QNaN, &st(0));
+      FPU_copy_to_reg0(&CONST_QNaN, TAG_Special);
     }
 
   EXCEPTION(EX_StackOver);
@@ -609,13 +687,13 @@
 }
 
 
-void stack_underflow(void)
+void FPU_stack_underflow(void)
 {
 
  if ( control_word & CW_Invalid )
     {
       /* The masked response */
-      reg_move(&CONST_QNaN, &st(0));
+      FPU_copy_to_reg0(&CONST_QNaN, TAG_Special);
     }
 
   EXCEPTION(EX_StackUnder);
@@ -625,13 +703,13 @@
 }
 
 
-void stack_underflow_i(int i)
+void FPU_stack_underflow_i(int i)
 {
 
  if ( control_word & CW_Invalid )
     {
       /* The masked response */
-      reg_move(&CONST_QNaN, &(st(i)));
+      FPU_copy_to_regi(&CONST_QNaN, TAG_Special, i);
     }
 
   EXCEPTION(EX_StackUnder);
@@ -641,14 +719,14 @@
 }
 
 
-void stack_underflow_pop(int i)
+void FPU_stack_underflow_pop(int i)
 {
 
  if ( control_word & CW_Invalid )
     {
       /* The masked response */
-      reg_move(&CONST_QNaN, &(st(i)));
-      pop();
+      FPU_copy_to_regi(&CONST_QNaN, TAG_Special, i);
+      FPU_pop();
     }
 
   EXCEPTION(EX_StackUnder);
diff -u --recursive --new-file v2.1.72/linux/arch/i386/math-emu/fpu_arith.c linux/arch/i386/math-emu/fpu_arith.c
--- v2.1.72/linux/arch/i386/math-emu/fpu_arith.c	Thu Jun  2 00:28:23 1994
+++ linux/arch/i386/math-emu/fpu_arith.c	Tue Dec  9 17:57:09 1997
@@ -3,9 +3,9 @@
  |                                                                           |
  | Code to implement the FPU register/register arithmetic instructions       |
  |                                                                           |
- | Copyright (C) 1992,1993                                                   |
- |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
- |                       Australia.  E-mail   billm@vaxc.cc.monash.edu.au    |
+ | Copyright (C) 1992,1993,1997                                              |
+ |                  W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
+ |                  E-mail   billm@suburbia.net                              |
  |                                                                           |
  |                                                                           |
  +---------------------------------------------------------------------------*/
@@ -19,16 +19,18 @@
 void fadd__()
 {
   /* fadd st,st(i) */
+  int i = FPU_rm;
   clear_C1();
-  reg_add(&st(0), &st(FPU_rm), &st(0), control_word);
+  FPU_add(&st(i), FPU_gettagi(i), 0, control_word);
 }
 
 
 void fmul__()
 {
   /* fmul st,st(i) */
+  int i = FPU_rm;
   clear_C1();
-  reg_mul(&st(0), &st(FPU_rm), &st(0), control_word);
+  FPU_mul(&st(i), FPU_gettagi(i), 0, control_word);
 }
 
 
@@ -37,7 +39,7 @@
 {
   /* fsub st,st(i) */
   clear_C1();
-  reg_sub(&st(0), &st(FPU_rm), &st(0), control_word);
+  FPU_sub(0, FPU_rm, control_word);
 }
 
 
@@ -45,7 +47,7 @@
 {
   /* fsubr st,st(i) */
   clear_C1();
-  reg_sub(&st(FPU_rm), &st(0), &st(0), control_word);
+  FPU_sub(REV, FPU_rm, control_word);
 }
 
 
@@ -53,7 +55,7 @@
 {
   /* fdiv st,st(i) */
   clear_C1();
-  reg_div(&st(0), &st(FPU_rm), &st(0), control_word);
+  FPU_div(0, FPU_rm, control_word);
 }
 
 
@@ -61,7 +63,7 @@
 {
   /* fdivr st,st(i) */
   clear_C1();
-  reg_div(&st(FPU_rm), &st(0), &st(0), control_word);
+  FPU_div(REV, FPU_rm, control_word);
 }
 
 
@@ -69,8 +71,9 @@
 void fadd_i()
 {
   /* fadd st(i),st */
+  int i = FPU_rm;
   clear_C1();
-  reg_add(&st(0), &st(FPU_rm), &st(FPU_rm), control_word);
+  FPU_add(&st(i), FPU_gettagi(i), i, control_word);
 }
 
 
@@ -78,27 +81,23 @@
 {
   /* fmul st(i),st */
   clear_C1();
-  reg_mul(&st(0), &st(FPU_rm), &st(FPU_rm), control_word);
+  FPU_mul(&st(0), FPU_gettag0(), FPU_rm, control_word);
 }
 
 
 void fsubri()
 {
   /* fsubr st(i),st */
-  /* This is the sense of the 80486 manual
-     reg_sub(&st(FPU_rm), &st(0), &st(FPU_rm), control_word); */
   clear_C1();
-  reg_sub(&st(0), &st(FPU_rm), &st(FPU_rm), control_word);
+  FPU_sub(DEST_RM, FPU_rm, control_word);
 }
 
 
 void fsub_i()
 {
   /* fsub st(i),st */
-  /* This is the sense of the 80486 manual
-     reg_sub(&st(0), &st(FPU_rm), &st(FPU_rm), control_word); */
   clear_C1();
-  reg_sub(&st(FPU_rm), &st(0), &st(FPU_rm), control_word);
+  FPU_sub(REV|DEST_RM, FPU_rm, control_word);
 }
 
 
@@ -106,7 +105,7 @@
 {
   /* fdivr st(i),st */
   clear_C1();
-  reg_div(&st(0), &st(FPU_rm), &st(FPU_rm), control_word);
+  FPU_div(DEST_RM, FPU_rm, control_word);
 }
 
 
@@ -114,7 +113,7 @@
 {
   /* fdiv st(i),st */
   clear_C1();
-  reg_div(&st(FPU_rm), &st(0), &st(FPU_rm), control_word);
+  FPU_div(REV|DEST_RM, FPU_rm, control_word);
 }
 
 
@@ -122,9 +121,10 @@
 void faddp_()
 {
   /* faddp st(i),st */
+  int i = FPU_rm;
   clear_C1();
-  if ( !reg_add(&st(0), &st(FPU_rm), &st(FPU_rm), control_word) )
-    pop();
+  if ( FPU_add(&st(i), FPU_gettagi(i), i, control_word) >= 0 )
+    FPU_pop();
 }
 
 
@@ -132,8 +132,8 @@
 {
   /* fmulp st(i),st */
   clear_C1();
-  if ( !reg_mul(&st(0), &st(FPU_rm), &st(FPU_rm), control_word) )
-    pop();
+  if ( FPU_mul(&st(0), FPU_gettag0(), FPU_rm, control_word) >= 0 )
+    FPU_pop();
 }
 
 
@@ -141,22 +141,18 @@
 void fsubrp()
 {
   /* fsubrp st(i),st */
-  /* This is the sense of the 80486 manual
-     reg_sub(&st(FPU_rm), &st(0), &st(FPU_rm), control_word); */
   clear_C1();
-  if ( !reg_sub(&st(0), &st(FPU_rm), &st(FPU_rm), control_word) )
-    pop();
+  if ( FPU_sub(DEST_RM, FPU_rm, control_word) >= 0 )
+    FPU_pop();
 }
 
 
 void fsubp_()
 {
   /* fsubp st(i),st */
-  /* This is the sense of the 80486 manual
-     reg_sub(&st(0), &st(FPU_rm), &st(FPU_rm), control_word); */
   clear_C1();
-  if ( !reg_sub(&st(FPU_rm), &st(0), &st(FPU_rm), control_word) )
-    pop();
+  if ( FPU_sub(REV|DEST_RM, FPU_rm, control_word) >= 0 )
+    FPU_pop();
 }
 
 
@@ -164,8 +160,8 @@
 {
   /* fdivrp st(i),st */
   clear_C1();
-  if ( !reg_div(&st(0), &st(FPU_rm), &st(FPU_rm), control_word) )
-    pop();
+  if ( FPU_div(DEST_RM, FPU_rm, control_word) >= 0 )
+    FPU_pop();
 }
 
 
@@ -173,7 +169,6 @@
 {
   /* fdivp st(i),st */
   clear_C1();
-  if ( !reg_div(&st(FPU_rm), &st(0), &st(FPU_rm), control_word) )
-    pop();
+  if ( FPU_div(REV|DEST_RM, FPU_rm, control_word) >= 0 )
+    FPU_pop();
 }
-
diff -u --recursive --new-file v2.1.72/linux/arch/i386/math-emu/fpu_asm.h linux/arch/i386/math-emu/fpu_asm.h
--- v2.1.72/linux/arch/i386/math-emu/fpu_asm.h	Thu Oct 10 06:01:12 1996
+++ linux/arch/i386/math-emu/fpu_asm.h	Tue Dec  9 17:57:09 1997
@@ -1,9 +1,9 @@
 /*---------------------------------------------------------------------------+
  |  fpu_asm.h                                                                |
  |                                                                           |
- | Copyright (C) 1992,1995                                                   |
+ | Copyright (C) 1992,1995,1997                                              |
  |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
- |                       Australia.  E-mail billm@jacobi.maths.monash.edu.au |
+ |                       Australia.  E-mail billm@suburbia.net               |
  |                                                                           |
  +---------------------------------------------------------------------------*/
 
@@ -19,13 +19,14 @@
 #define	PARAM2	12(%ebp)
 #define	PARAM3	16(%ebp)
 #define	PARAM4	20(%ebp)
+#define	PARAM5	24(%ebp)
+#define	PARAM6	28(%ebp)
+#define	PARAM7	32(%ebp)
 
-#define SIGL_OFFSET 8
-#define SIGN(x)	(x)
-#define	TAG(x)	1(x)
-#define	EXP(x)	4(x)
+#define SIGL_OFFSET 0
+#define	EXP(x)	8(x)
 #define SIG(x)	SIGL_OFFSET##(x)
 #define	SIGL(x)	SIGL_OFFSET##(x)
-#define	SIGH(x)	12(x)
+#define	SIGH(x)	4(x)
 
 #endif _FPU_ASM_H_
diff -u --recursive --new-file v2.1.72/linux/arch/i386/math-emu/fpu_aux.c linux/arch/i386/math-emu/fpu_aux.c
--- v2.1.72/linux/arch/i386/math-emu/fpu_aux.c	Thu Jun  2 00:28:23 1994
+++ linux/arch/i386/math-emu/fpu_aux.c	Tue Dec  9 17:57:09 1997
@@ -3,9 +3,9 @@
  |                                                                           |
  | Code to implement some of the FPU auxiliary instructions.                 |
  |                                                                           |
- | Copyright (C) 1992,1993,1994                                              |
- |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
- |                       Australia.  E-mail   billm@vaxc.cc.monash.edu.au    |
+ | Copyright (C) 1992,1993,1994,1997                                         |
+ |                  W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
+ |                  E-mail   billm@suburbia.net                              |
  |                                                                           |
  |                                                                           |
  +---------------------------------------------------------------------------*/
@@ -32,15 +32,11 @@
 /* Needs to be externally visible */
 void finit()
 {
-  int r;
   control_word = 0x037f;
   partial_status = 0;
   top = 0;            /* We don't keep top in the status word internally. */
-  for (r = 0; r < 8; r++)
-    {
-      regs[r].tag = TW_Empty;
-    }
-  /* The behaviour is different to that detailed in
+  fpu_tag_word = 0xffff;
+  /* The behaviour is different from that detailed in
      Section 15.1.6 of the Intel manual */
   operand_address.offset = 0;
   operand_address.selector = 0;
@@ -99,19 +95,27 @@
 void fld_i_()
 {
   FPU_REG *st_new_ptr;
+  int i;
+  u_char tag;
 
   if ( STACK_OVERFLOW )
-    { stack_overflow(); return; }
+    { FPU_stack_overflow(); return; }
 
   /* fld st(i) */
-  if ( NOT_EMPTY(FPU_rm) )
-    { reg_move(&st(FPU_rm), st_new_ptr); push(); }
+  i = FPU_rm;
+  if ( NOT_EMPTY(i) )
+    {
+      reg_copy(&st(i), st_new_ptr);
+      tag = FPU_gettagi(i);
+      push();
+      FPU_settag0(tag);
+    }
   else
     {
       if ( control_word & CW_Invalid )
 	{
 	  /* The masked response */
-	  stack_underflow();
+	  FPU_stack_underflow();
 	}
       else
 	EXCEPTION(EX_StackUnder);
@@ -124,61 +128,77 @@
 {
   /* fxch st(i) */
   FPU_REG t;
-  register FPU_REG *sti_ptr = &st(FPU_rm), *st0_ptr = &st(0);
+  int i = FPU_rm;
+  FPU_REG *st0_ptr = &st(0), *sti_ptr = &st(i);
+  long tag_word = fpu_tag_word;
+  int regnr = top & 7, regnri = ((regnr + i) & 7);
+  u_char st0_tag = (tag_word >> (regnr*2)) & 3;
+  u_char sti_tag = (tag_word >> (regnri*2)) & 3;
 
-  if ( st0_ptr->tag == TW_Empty )
+  if ( st0_tag == TAG_Empty )
     {
-      if ( sti_ptr->tag == TW_Empty )
+      if ( sti_tag == TAG_Empty )
 	{
-	  stack_underflow();
-	  stack_underflow_i(FPU_rm);
+	  FPU_stack_underflow();
+	  FPU_stack_underflow_i(i);
 	  return;
 	}
       if ( control_word & CW_Invalid )
-	reg_move(sti_ptr, st0_ptr);   /* Masked response */
-      stack_underflow_i(FPU_rm);
+	{
+	  /* Masked response */
+	  FPU_copy_to_reg0(sti_ptr, sti_tag);
+	}
+      FPU_stack_underflow_i(i);
       return;
     }
-  if ( sti_ptr->tag == TW_Empty )
+  if ( sti_tag == TAG_Empty )
     {
       if ( control_word & CW_Invalid )
-	reg_move(st0_ptr, sti_ptr);   /* Masked response */
-      stack_underflow();
+	{
+	  /* Masked response */
+	  FPU_copy_to_regi(st0_ptr, st0_tag, i);
+	}
+      FPU_stack_underflow();
       return;
     }
   clear_C1();
-  reg_move(st0_ptr, &t);
-  reg_move(sti_ptr, st0_ptr);
-  reg_move(&t, sti_ptr);
+
+  reg_copy(st0_ptr, &t);
+  reg_copy(sti_ptr, st0_ptr);
+  reg_copy(&t, sti_ptr);
+
+  tag_word &= ~(3 << (regnr*2)) & ~(3 << (regnri*2));
+  tag_word |= (sti_tag << (regnr*2)) | (st0_tag << (regnri*2));
+  fpu_tag_word = tag_word;
 }
 
 
 void ffree_()
 {
   /* ffree st(i) */
-  st(FPU_rm).tag = TW_Empty;
+  FPU_settagi(FPU_rm, TAG_Empty);
 }
 
 
 void ffreep()
 {
   /* ffree st(i) + pop - unofficial code */
-  st(FPU_rm).tag = TW_Empty;
-  pop();
+  FPU_settagi(FPU_rm, TAG_Empty);
+  FPU_pop();
 }
 
 
 void fst_i_()
 {
   /* fst st(i) */
-  reg_move(&st(0), &st(FPU_rm));
+  FPU_copy_to_regi(&st(0), FPU_gettag0(), FPU_rm);
 }
 
 
 void fstp_i()
 {
   /* fstp st(i) */
-  reg_move(&st(0), &st(FPU_rm));
-  pop();
+  FPU_copy_to_regi(&st(0), FPU_gettag0(), FPU_rm);
+  FPU_pop();
 }
 
diff -u --recursive --new-file v2.1.72/linux/arch/i386/math-emu/fpu_emu.h linux/arch/i386/math-emu/fpu_emu.h
--- v2.1.72/linux/arch/i386/math-emu/fpu_emu.h	Tue Oct 15 01:07:13 1996
+++ linux/arch/i386/math-emu/fpu_emu.h	Tue Dec  9 17:57:09 1997
@@ -1,9 +1,9 @@
 /*---------------------------------------------------------------------------+
  |  fpu_emu.h                                                                |
  |                                                                           |
- | Copyright (C) 1992,1993,1994                                              |
+ | Copyright (C) 1992,1993,1994,1997                                         |
  |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
- |                       Australia.  E-mail   billm@vaxc.cc.monash.edu.au    |
+ |                       Australia.  E-mail   billm@suburbia.net             |
  |                                                                           |
  +---------------------------------------------------------------------------*/
 
@@ -12,14 +12,6 @@
 #define _FPU_EMU_H_
 
 /*
- * Define DENORM_OPERAND to make the emulator detect denormals
- * and use the denormal flag of the status word. Note: this only
- * affects the flag and corresponding interrupt, the emulator
- * will always generate denormals and operate upon them as required.
- */
-#define DENORM_OPERAND
-
-/*
  * Define PECULIAR_486 to get a closer approximation to 80486 behaviour,
  * rather than behaviour which appears to be cleaner.
  * This is a matter of opinion: for all I know, the 80486 may simply
@@ -38,28 +30,51 @@
 #define EXP_BIAS	Const(0)
 #define EXP_OVER	Const(0x4000)    /* smallest invalid large exponent */
 #define	EXP_UNDER	Const(-0x3fff)   /* largest invalid small exponent */
+#define EXP_WAY_UNDER   Const(-0x6000)   /* Below the smallest denormal, but
+					    still a 16 bit nr. */
 #define EXP_Infinity    EXP_OVER
 #define EXP_NaN         EXP_OVER
 
+#define EXTENDED_Ebias Const(0x3fff)
+#define EXTENDED_Emin (-0x3ffe)  /* smallest valid exponent */
+
 #define SIGN_POS	Const(0)
-#define SIGN_NEG	Const(1)
+#define SIGN_NEG	Const(0x80)
 
-/* Keep the order TW_Valid, TW_Zero, TW_Denormal */
-#define TW_Valid	Const(0)	/* valid */
-#define TW_Zero		Const(1)	/* zero */
+#define SIGN_Positive	Const(0)
+#define SIGN_Negative	Const(0x8000)
+
+
+/* Keep the order TAG_Valid, TAG_Zero, TW_Denormal */
 /* The following fold to 2 (Special) in the Tag Word */
-/* #define TW_Denormal     Const(4) */       /* De-normal */
+#define TW_Denormal     Const(4)        /* De-normal */
 #define TW_Infinity	Const(5)	/* + or - infinity */
 #define	TW_NaN		Const(6)	/* Not a Number */
+#define	TW_Unsupported	Const(7)	/* Not supported by an 80486 */
+
+#define TAG_Valid	Const(0)	/* valid */
+#define TAG_Zero	Const(1)	/* zero */
+#define TAG_Special	Const(2)	/* De-normal, + or - infinity,
+					   or Not a Number */
+#define TAG_Empty	Const(3)	/* empty */
+
+#define LOADED_DATA	Const(10101)	/* Special st() number to identify
+					   loaded data (not on stack). */
+
+/* A few flags (must be >= 0x10). */
+#define REV             0x10
+#define DEST_RM         0x20
+#define LOADED          0x40
 
-#define TW_Empty	Const(7)	/* empty */
+#define FPU_Exception   Const(0x80000000)   /* Added to tag returns. */
 
 
 #ifndef __ASSEMBLY__
 
-#include <asm/sigcontext.h>	/* for struct _fpstate */
-#include <asm/math_emu.h>
+#include "fpu_system.h"
 
+#include <asm/sigcontext.h>   /* for struct _fpstate */
+#include <asm/math_emu.h>
 #include <linux/linkage.h>
 
 /*
@@ -67,7 +82,7 @@
  */
 
 #ifdef RE_ENTRANT_CHECKING
-extern char emulating;
+extern u_char emulating;
 #  define RE_ENTRANT_CHECK_OFF emulating = 0
 #  define RE_ENTRANT_CHECK_ON emulating = 1
 #else
@@ -97,18 +112,24 @@
 
 struct address {
   unsigned int offset;
-  unsigned short selector;
-  unsigned short opcode:11,
-		 empty:5;
+  unsigned int selector:16;
+  unsigned int opcode:11;
+  unsigned int empty:5;
+};
+struct fpu__reg {
+  unsigned sigl;
+  unsigned sigh;
+  short exp;
 };
+
 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; }
+typedef struct fpu__reg FPU_REG;
+typedef void (*FUNC_ST0)(FPU_REG *st0_ptr, u_char st0_tag);
+typedef struct { u_char address_size, operand_size, segment; }
         overrides;
 /* This structure is 32 bits: */
 typedef struct { overrides override;
-		 unsigned char default_mode; } fpu_addr_modes;
+		 u_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. */
@@ -117,27 +138,50 @@
 #define VM86      SIXTEEN
 #define PM16      (SIXTEEN | PROTECTED)
 #define SEG32     PROTECTED
-extern unsigned char const data_sizes_16[32];
+extern u_char const data_sizes_16[32];
+
+#define register_base ((u_char *) registers )
+#define fpu_register(x)  ( * ((FPU_REG *)( register_base + 10 * (x & 7) )) )
+#define	st(x)      ( * ((FPU_REG *)( register_base + 10 * ((top+x) & 7) )) )
+
+#define	STACK_OVERFLOW	(FPU_stackoverflow(&st_new_ptr))
+#define	NOT_EMPTY(i)	(!FPU_empty_i(i))
 
-#define	st(x)	( regs[((top+x) &7 )] )
+#define	NOT_EMPTY_ST0	(st0_tag ^ TAG_Empty)
 
-#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_ST0	(st0_tag ^ TW_Empty)
-
-#define pop()	{ regs[(top++ & 7 )].tag = TW_Empty; }
-#define poppop() { regs[((top + 1) & 7 )].tag \
-		     = regs[(top & 7 )].tag = TW_Empty; \
-		   top += 2; }
+#define poppop() { FPU_pop(); FPU_pop(); }
 
 /* push() does not affect the tags */
 #define push()	{ top--; }
 
+#define signbyte(a) (((u_char *)(a))[9])
+#define getsign(a) (signbyte(a) & 0x80)
+#define setsign(a,b) { if (b) signbyte(a) |= 0x80; else signbyte(a) &= 0x7f; }
+#define copysign(a,b) { if (getsign(a)) signbyte(b) |= 0x80; \
+                        else signbyte(b) &= 0x7f; }
+#define changesign(a) { signbyte(a) ^= 0x80; }
+#define setpositive(a) { signbyte(a) &= 0x7f; }
+#define setnegative(a) { signbyte(a) |= 0x80; }
+#define signpositive(a) ( (signbyte(a) & 0x80) == 0 )
+#define signnegative(a) (signbyte(a) & 0x80)
+
+#include "fpu_proto.h"
+
+static inline void reg_copy(FPU_REG const *x, FPU_REG *y)
+{
+  *(short *)&(y->exp) = *(const short *)&(x->exp); 
+  *(long long *)&(y->sigl) = *(const long long *)&(x->sigl);
+}
+
+#define exponent(x)  (((*(short *)&((x)->exp)) & 0x7fff) - EXTENDED_Ebias)
+#define setexponentpos(x,y) { (*(short *)&((x)->exp)) = \
+  ((y) + EXTENDED_Ebias) & 0x7fff; }
+#define exponent16(x)         (*(short *)&((x)->exp))
+#define setexponent16(x,y)  { (*(short *)&((x)->exp)) = (y); }
+#define addexponent(x,y)    { (*(short *)&((x)->exp)) += (y); }
+#define stdexp(x)           { (*(short *)&((x)->exp)) += EXTENDED_Ebias; }
 
-#define reg_move(x, y) { \
-		 *(short *)&((y)->sign) = *(const short *)&((x)->sign); \
-		 *(long *)&((y)->exp) = *(const long *)&((x)->exp); \
-		 *(long long *)&((y)->sigl) = *(const long long *)&((x)->sigl); }
+#define isdenormal(ptr)   (exponent(ptr) == EXP_BIAS+EXP_UNDER)
 
 #define significand(x) ( ((unsigned long long *)&((x)->sigl))[0] )
 
@@ -145,24 +189,26 @@
 /*----- Prototypes for functions written in assembler -----*/
 /* extern void reg_move(FPU_REG *a, FPU_REG *b); */
 
-asmlinkage void normalize(FPU_REG *x);
-asmlinkage void normalize_nuo(FPU_REG *x);
-asmlinkage int reg_div(FPU_REG const *arg1, FPU_REG const *arg2,
-		       FPU_REG *answ, unsigned int control_w);
-asmlinkage int reg_u_sub(FPU_REG const *arg1, FPU_REG const *arg2,
-			 FPU_REG *answ, unsigned int control_w);
-asmlinkage int reg_u_mul(FPU_REG const *arg1, FPU_REG const *arg2,
-			 FPU_REG *answ, unsigned int control_w);
-asmlinkage int reg_u_div(FPU_REG const *arg1, FPU_REG const *arg2,
-			 FPU_REG *answ, unsigned int control_w);
-asmlinkage int reg_u_add(FPU_REG const *arg1, FPU_REG const *arg2,
-			 FPU_REG *answ, unsigned int control_w);
-asmlinkage int wm_sqrt(FPU_REG *n, unsigned int control_w);
-asmlinkage unsigned	shrx(void *l, unsigned x);
-asmlinkage unsigned	shrxs(void *v, unsigned x);
-asmlinkage unsigned long div_small(unsigned long long *x, unsigned long y);
-asmlinkage void round_reg(FPU_REG *arg, unsigned int extent,
-		      unsigned int control_w);
+asmlinkage int FPU_normalize(FPU_REG *x);
+asmlinkage int FPU_normalize_nuo(FPU_REG *x);
+asmlinkage int FPU_u_sub(FPU_REG const *arg1, FPU_REG const *arg2,
+			 FPU_REG *answ, unsigned int control_w, u_char sign,
+			 int expa, int expb);
+asmlinkage int FPU_u_mul(FPU_REG const *arg1, FPU_REG const *arg2,
+			 FPU_REG *answ, unsigned int control_w, u_char sign,
+			 int expon);
+asmlinkage int FPU_u_div(FPU_REG const *arg1, FPU_REG const *arg2,
+			 FPU_REG *answ, unsigned int control_w, u_char sign);
+asmlinkage int FPU_u_add(FPU_REG const *arg1, FPU_REG const *arg2,
+			 FPU_REG *answ, unsigned int control_w, u_char sign,
+			 int expa, int expb);
+asmlinkage int wm_sqrt(FPU_REG *n, int dummy1, int dummy2,
+		       unsigned int control_w, u_char sign);
+asmlinkage unsigned	FPU_shrx(void *l, unsigned x);
+asmlinkage unsigned	FPU_shrxs(void *v, unsigned x);
+asmlinkage unsigned long FPU_div_small(unsigned long long *x, unsigned long y);
+asmlinkage int FPU_round(FPU_REG *arg, unsigned int extent, int dummy,
+			 unsigned int control_w, u_char sign);
 
 #ifndef MAKING_PROTO
 #include "fpu_proto.h"
diff -u --recursive --new-file v2.1.72/linux/arch/i386/math-emu/fpu_entry.c linux/arch/i386/math-emu/fpu_entry.c
--- v2.1.72/linux/arch/i386/math-emu/fpu_entry.c	Tue Dec  2 09:49:39 1997
+++ linux/arch/i386/math-emu/fpu_entry.c	Tue Dec  9 17:57:09 1997
@@ -3,9 +3,9 @@
  |                                                                           |
  | The entry functions for wm-FPU-emu                                        |
  |                                                                           |
- | Copyright (C) 1992,1993,1994,1996                                         |
+ | Copyright (C) 1992,1993,1994,1996,1997                                    |
  |                  W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
- |                  E-mail   billm@jacobi.maths.monash.edu.au                |
+ |                  E-mail   billm@suburbia.net                              |
  |                                                                           |
  | See the files "README" and "COPYING" for further copyright and warranty   |
  | information.                                                              |
@@ -54,27 +54,27 @@
 #define _df_d8_ fstp_i    /* unofficial code (1f) */
 
 static FUNC const st_instr_table[64] = {
-  fadd__,   fld_i_,  __BAD__, __BAD__, fadd_i,  ffree_,  faddp_,  _df_c0_,
-  fmul__,   fxch_i,  __BAD__, __BAD__, fmul_i,  _dd_c8_, fmulp_,  _df_c8_,
-  fcom_st,  fp_nop,  __BAD__, __BAD__, _dc_d0_, fst_i_,  _de_d0_, _df_d0_,
-  fcompst,  _d9_d8_, __BAD__, __BAD__, _dc_d8_, fstp_i,  fcompp,  _df_d8_,
-  fsub__,   fp_etc,  __BAD__, finit_,  fsubri,  fucom_,  fsubrp,  fstsw_,
-  fsubr_,   fconst,  fucompp, __BAD__, fsub_i,  fucomp,  fsubp_,  __BAD__,
-  fdiv__,   trig_a,  __BAD__, __BAD__, fdivri,  __BAD__, fdivrp,  __BAD__,
-  fdivr_,   trig_b,  __BAD__, __BAD__, fdiv_i,  __BAD__, fdivp_,  __BAD__,
+  fadd__,   fld_i_,     __BAD__, __BAD__, fadd_i,  ffree_,  faddp_,  _df_c0_,
+  fmul__,   fxch_i,     __BAD__, __BAD__, fmul_i,  _dd_c8_, fmulp_,  _df_c8_,
+  fcom_st,  fp_nop,     __BAD__, __BAD__, _dc_d0_, fst_i_,  _de_d0_, _df_d0_,
+  fcompst,  _d9_d8_,    __BAD__, __BAD__, _dc_d8_, fstp_i,  fcompp,  _df_d8_,
+  fsub__,   FPU_etc,    __BAD__, finit_,  fsubri,  fucom_,  fsubrp,  fstsw_,
+  fsubr_,   fconst,     fucompp, __BAD__, fsub_i,  fucomp,  fsubp_,  __BAD__,
+  fdiv__,   FPU_triga,  __BAD__, __BAD__, fdivri,  __BAD__, fdivrp,  __BAD__,
+  fdivr_,   FPU_trigb,  __BAD__, __BAD__, fdiv_i,  __BAD__, fdivp_,  __BAD__,
 };
 
 #else     /* Support only documented FPU op-codes */
 
 static FUNC const st_instr_table[64] = {
-  fadd__,   fld_i_,  __BAD__, __BAD__, fadd_i,  ffree_,  faddp_,  __BAD__,
-  fmul__,   fxch_i,  __BAD__, __BAD__, fmul_i,  __BAD__, fmulp_,  __BAD__,
-  fcom_st,  fp_nop,  __BAD__, __BAD__, __BAD__, fst_i_,  __BAD__, __BAD__,
-  fcompst,  __BAD__, __BAD__, __BAD__, __BAD__, fstp_i,  fcompp,  __BAD__,
-  fsub__,   fp_etc,  __BAD__, finit_,  fsubri,  fucom_,  fsubrp,  fstsw_,
-  fsubr_,   fconst,  fucompp, __BAD__, fsub_i,  fucomp,  fsubp_,  __BAD__,
-  fdiv__,   trig_a,  __BAD__, __BAD__, fdivri,  __BAD__, fdivrp,  __BAD__,
-  fdivr_,   trig_b,  __BAD__, __BAD__, fdiv_i,  __BAD__, fdivp_,  __BAD__,
+  fadd__,   fld_i_,     __BAD__, __BAD__, fadd_i,  ffree_,  faddp_,  __BAD__,
+  fmul__,   fxch_i,     __BAD__, __BAD__, fmul_i,  __BAD__, fmulp_,  __BAD__,
+  fcom_st,  fp_nop,     __BAD__, __BAD__, __BAD__, fst_i_,  __BAD__, __BAD__,
+  fcompst,  __BAD__,    __BAD__, __BAD__, __BAD__, fstp_i,  fcompp,  __BAD__,
+  fsub__,   FPU_etc,    __BAD__, finit_,  fsubri,  fucom_,  fsubrp,  fstsw_,
+  fsubr_,   fconst,     fucompp, __BAD__, fsub_i,  fucomp,  fsubp_,  __BAD__,
+  fdiv__,   FPU_triga,  __BAD__, __BAD__, fdivri,  __BAD__, fdivrp,  __BAD__,
+  fdivr_,   FPU_trigb,  __BAD__, __BAD__, fdiv_i,  __BAD__, fdivp_,  __BAD__,
 };
 
 #endif NO_UNDOC_CODE
@@ -95,7 +95,7 @@
 
 /* Un-documented FPU op-codes supported by default. (see above) */
 
-static unsigned char const type_table[64] = {
+static u_char const type_table[64] = {
   _REGI_, _NONE_, _null_, _null_, _REGIi, _REGi_, _REGIp, _REGi_,
   _REGI_, _REGIn, _null_, _null_, _REGIi, _REGI_, _REGIp, _REGI_,
   _REGIc, _NONE_, _null_, _null_, _REGIc, _REG0_, _REGIc, _REG0_,
@@ -108,7 +108,7 @@
 
 #else     /* Support only documented FPU op-codes */
 
-static unsigned char const type_table[64] = {
+static u_char const type_table[64] = {
   _REGI_, _NONE_, _null_, _null_, _REGIi, _REGi_, _REGIp, _null_,
   _REGI_, _REGIn, _null_, _null_, _REGIi, _null_, _REGIp, _null_,
   _REGIc, _NONE_, _null_, _null_, _null_, _REG0_, _null_, _null_,
@@ -123,26 +123,26 @@
 
 
 #ifdef RE_ENTRANT_CHECKING
-char emulating=0;
+u_char emulating=0;
 #endif RE_ENTRANT_CHECKING
 
-static int valid_prefix(unsigned char *Byte, unsigned char **fpu_eip,
+static int valid_prefix(u_char *Byte, u_char **fpu_eip,
 			overrides *override);
 
 asmlinkage void math_emulate(long arg)
 {
-  unsigned char  FPU_modrm, byte1;
+  u_char  FPU_modrm, byte1;
   unsigned short code;
   fpu_addr_modes addr_modes;
   int unmasked;
   FPU_REG loaded_data;
+  FPU_REG *st0_ptr;
+  u_char	  loaded_tag, st0_tag;
   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 RE_ENTRANT_CHECKING
@@ -155,15 +155,6 @@
 
   if (!current->used_math)
     {
-      int i;
-      for ( i = 0; i < 8; i++ )
-	{
-	  /* Make sure that the registers are compatible
-	     with the assumptions of the emulator. */
-	  if ( !((regs[i].exp == EXP_UNDER) && (regs[i].sigh == 0)
-		 && (regs[i].sigl == 0)) )
-	    regs[i].sigh |= 0x80000000;
-	}
       finit();
       current->used_math = 1;
     }
@@ -221,7 +212,7 @@
   if (current->flags & PF_PTRACED)
     FPU_lookahead = 0;
 
-  if ( !valid_prefix(&byte1, (unsigned char **)&FPU_EIP,
+  if ( !valid_prefix(&byte1, (u_char **)&FPU_EIP,
 		     &addr_modes.override) )
     {
       RE_ENTRANT_CHECK_OFF;
@@ -264,7 +255,7 @@
 
   RE_ENTRANT_CHECK_OFF;
   FPU_code_verify_area(1);
-  get_user(FPU_modrm, (unsigned char *) FPU_EIP);
+  FPU_get_user(FPU_modrm, (u_char *) FPU_EIP);
   RE_ENTRANT_CHECK_ON;
   FPU_EIP++;
 
@@ -287,6 +278,7 @@
 	   *  interrupts here.
 	   */
 	do_the_FPU_interrupt:
+
 	  FPU_EIP = FPU_ORIG_EIP;	/* Point to current FPU instruction. */
 
 	  RE_ENTRANT_CHECK_OFF;
@@ -309,11 +301,11 @@
 
       if ( (addr_modes.default_mode & SIXTEEN)
 	  ^ (addr_modes.override.address_size == ADDR_SIZE_PREFIX) )
-	data_address = get_address_16(FPU_modrm, &FPU_EIP, &data_sel_off,
-				      addr_modes);
+	data_address = FPU_get_address_16(FPU_modrm, &FPU_EIP, &data_sel_off,
+					  addr_modes);
       else
-	data_address = get_address(FPU_modrm, &FPU_EIP, &data_sel_off,
-				   addr_modes);
+	data_address = FPU_get_address(FPU_modrm, &FPU_EIP, &data_sel_off,
+				       addr_modes);
 
       if ( addr_modes.default_mode )
 	{
@@ -326,7 +318,7 @@
 	  unsigned short status1 = partial_status;
 
 	  st0_ptr = &st(0);
-	  st0_tag = st0_ptr->tag;
+	  st0_tag = FPU_gettag0();
 
 	  /* Stack underflow has priority */
 	  if ( NOT_EMPTY_ST0 )
@@ -342,29 +334,34 @@
 	      switch ( (byte1 >> 1) & 3 )
 		{
 		case 0:
-		  unmasked = reg_load_single((float *)data_address,
+		  unmasked = FPU_load_single((float *)data_address,
 					     &loaded_data);
+		  loaded_tag = unmasked & 0xff;
+		  unmasked &= ~0xff;
 		  break;
 		case 1:
-		  reg_load_int32((long *)data_address, &loaded_data);
+		  loaded_tag = FPU_load_int32((long *)data_address, &loaded_data);
 		  break;
 		case 2:
-		  unmasked = reg_load_double((double *)data_address,
+		  unmasked = FPU_load_double((double *)data_address,
 					     &loaded_data);
+		  loaded_tag = unmasked & 0xff;
+		  unmasked &= ~0xff;
 		  break;
 		case 3:
-		  reg_load_int16((short *)data_address, &loaded_data);
+		default:  /* Used here to suppress gcc warnings. */
+		  loaded_tag = FPU_load_int16((short *)data_address, &loaded_data);
 		  break;
 		}
-	      
+
 	      /* No more access to user memory, it is safe
 		 to use static data now */
 
 	      /* 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 ( (st0_tag == TW_NaN) ||
-		  (loaded_data.tag == TW_NaN) )
+	      if ( ((st0_tag == TAG_Special) && isNaN(st0_ptr)) ||
+		  ((loaded_tag == TAG_Special) && isNaN(&loaded_data)) )
 		{
 		  /* Restore the status word; we might have loaded a
 		     denormal. */
@@ -375,22 +372,22 @@
 		      EXCEPTION(EX_Invalid);
 		      setcc(SW_C3 | SW_C2 | SW_C0);
 		      if ( (FPU_modrm & 0x08) && (control_word & CW_Invalid) )
-			pop();             /* fcomp, masked, so we pop. */
+			FPU_pop();             /* fcomp, masked, so we pop. */
 		    }
 		  else
 		    {
+		      if ( loaded_tag == TAG_Special )
+			loaded_tag = FPU_Special(&loaded_data);
 #ifdef PECULIAR_486
 		      /* This is not really needed, but gives behaviour
 			 identical to an 80486 */
 		      if ( (FPU_modrm & 0x28) == 0x20 )
 			/* fdiv or fsub */
-			real_2op_NaN(&loaded_data, st0_ptr,
-				     st0_ptr);
+			real_2op_NaN(&loaded_data, loaded_tag, 0, &loaded_data);
 		      else
 #endif PECULIAR_486
 			/* fadd, fdivr, fmul, or fsubr */
-			real_2op_NaN(st0_ptr, &loaded_data,
-				     st0_ptr);
+			real_2op_NaN(&loaded_data, loaded_tag, 0, st0_ptr);
 		    }
 		  goto reg_mem_instr_done;
 		}
@@ -401,11 +398,13 @@
 		  if ( (FPU_modrm & 0x38) == 0x38 )
 		    {
 		      /* fdivr */
-		      if ( (st0_tag == TW_Zero) &&
-			  (loaded_data.tag == TW_Valid) )
+		      if ( (st0_tag == TAG_Zero) &&
+			   ((loaded_tag == TAG_Valid)
+			    || (loaded_tag == TAG_Special
+				&& isdenormal(&loaded_data))) )
 			{
-			  if ( divide_by_zero(loaded_data.sign,
-					      st0_ptr) )
+			  if ( FPU_divide_by_zero(0, getsign(&loaded_data))
+			       < 0 )
 			    {
 			      /* We use the fact here that the unmasked
 				 exception in the loaded data was for a
@@ -414,6 +413,8 @@
 			      partial_status &= ~SW_Denorm_Op;
 			      partial_status |= status1 & SW_Denorm_Op;
 			    }
+			  else
+			    setsign(st0_ptr, getsign(&loaded_data));
 			}
 		    }
 		  goto reg_mem_instr_done;
@@ -423,43 +424,38 @@
 		{
 		case 0:         /* fadd */
 		  clear_C1();
-		  reg_add(st0_ptr, &loaded_data, st0_ptr,
-			  control_word);
+		  FPU_add(&loaded_data, loaded_tag, 0, control_word);
 		  break;
 		case 1:         /* fmul */
 		  clear_C1();
-		  reg_mul(st0_ptr, &loaded_data, st0_ptr,
-			  control_word);
+		  FPU_mul(&loaded_data, loaded_tag, 0, control_word);
 		  break;
 		case 2:         /* fcom */
-		  compare_st_data(&loaded_data);
+		  FPU_compare_st_data(&loaded_data, loaded_tag);
 		  break;
 		case 3:         /* fcomp */
-		  if ( !compare_st_data(&loaded_data) && !unmasked )
-		    pop();
+		  if ( !FPU_compare_st_data(&loaded_data, loaded_tag)
+		       && !unmasked )
+		    FPU_pop();
 		  break;
 		case 4:         /* fsub */
 		  clear_C1();
-		  reg_sub(st0_ptr, &loaded_data, st0_ptr,
-			  control_word);
+		  FPU_sub(LOADED|loaded_tag, (int)&loaded_data, control_word);
 		  break;
 		case 5:         /* fsubr */
 		  clear_C1();
-		  reg_sub(&loaded_data, st0_ptr, st0_ptr,
-			  control_word);
+		  FPU_sub(REV|LOADED|loaded_tag, (int)&loaded_data, control_word);
 		  break;
 		case 6:         /* fdiv */
 		  clear_C1();
-		  reg_div(st0_ptr, &loaded_data, st0_ptr,
-			  control_word);
+		  FPU_div(LOADED|loaded_tag, (int)&loaded_data, control_word);
 		  break;
 		case 7:         /* fdivr */
 		  clear_C1();
-		  if ( st0_tag == TW_Zero )
+		  if ( st0_tag == TAG_Zero )
 		    partial_status = status1;  /* Undo any denorm tag,
-					       zero-divide has priority. */
-		  reg_div(&loaded_data, st0_ptr, st0_ptr,
-			  control_word);
+						  zero-divide has priority. */
+		  FPU_div(REV|LOADED|loaded_tag, (int)&loaded_data, control_word);
 		  break;
 		}
 	    }
@@ -471,10 +467,10 @@
 		  EXCEPTION(EX_StackUnder);
 		  setcc(SW_C3 | SW_C2 | SW_C0);
 		  if ( (FPU_modrm & 0x08) && (control_word & CW_Invalid) )
-		    pop();             /* fcomp */
+		    FPU_pop();             /* fcomp */
 		}
 	      else
-		stack_underflow();
+		FPU_stack_underflow();
 	    }
 	reg_mem_instr_done:
 	  operand_address = data_sel_off;
@@ -482,8 +478,8 @@
       else
 	{
 	  if ( !(no_ip_update =
-		 load_store_instr(((FPU_modrm & 0x38) | (byte1 & 6)) >> 1,
-				  addr_modes, data_address)) )
+		 FPU_load_store(((FPU_modrm & 0x38) | (byte1 & 6)) >> 1,
+				addr_modes, data_address)) )
 	    {
 	      operand_address = data_sel_off;
 	    }
@@ -493,7 +489,7 @@
   else
     {
       /* None of these instructions access user memory */
-      unsigned char instr_index = (FPU_modrm & 0x38) | (byte1 & 7);
+      u_char instr_index = (FPU_modrm & 0x38) | (byte1 & 7);
 
 #ifdef PECULIAR_486
       /* This is supposed to be undefined, but a real 80486 seems
@@ -503,7 +499,7 @@
 #endif PECULIAR_486
 
       st0_ptr = &st(0);
-      st0_tag = st0_ptr->tag;
+      st0_tag = FPU_gettag0();
       switch ( type_table[(int) instr_index] )
 	{
 	case _NONE_:   /* also _REGIc: _REGIn */
@@ -511,28 +507,28 @@
 	case _REG0_:
 	  if ( !NOT_EMPTY_ST0 )
 	    {
-	      stack_underflow();
+	      FPU_stack_underflow();
 	      goto FPU_instruction_done;
 	    }
 	  break;
 	case _REGIi:
 	  if ( !NOT_EMPTY_ST0 || !NOT_EMPTY(FPU_rm) )
 	    {
-	      stack_underflow_i(FPU_rm);
+	      FPU_stack_underflow_i(FPU_rm);
 	      goto FPU_instruction_done;
 	    }
 	  break;
 	case _REGIp:
 	  if ( !NOT_EMPTY_ST0 || !NOT_EMPTY(FPU_rm) )
 	    {
-	      stack_underflow_pop(FPU_rm);
+	      FPU_stack_underflow_pop(FPU_rm);
 	      goto FPU_instruction_done;
 	    }
 	  break;
 	case _REGI_:
 	  if ( !NOT_EMPTY_ST0 || !NOT_EMPTY(FPU_rm) )
 	    {
-	      stack_underflow();
+	      FPU_stack_underflow();
 	      goto FPU_instruction_done;
 	    }
 	  break;
@@ -558,14 +554,14 @@
 
 #ifdef DEBUG
   RE_ENTRANT_CHECK_OFF;
-  emu_printall();
+  FPU_printall();
   RE_ENTRANT_CHECK_ON;
 #endif DEBUG
 
   if (FPU_lookahead && !need_resched)
     {
       FPU_ORIG_EIP = FPU_EIP - code_base;
-      if ( valid_prefix(&byte1, (unsigned char **)&FPU_EIP,
+      if ( valid_prefix(&byte1, (u_char **)&FPU_EIP,
 			&addr_modes.override) )
 	goto do_another_FPU_instruction;
     }
@@ -581,17 +577,17 @@
    all prefix bytes, further changes are needed in the emulator code
    which accesses user address space. Access to separate segments is
    important for msdos emulation. */
-static int valid_prefix(unsigned char *Byte, unsigned char **fpu_eip,
+static int valid_prefix(u_char *Byte, u_char **fpu_eip,
 			overrides *override)
 {
-  unsigned char byte;
-  unsigned char *ip = *fpu_eip;
+  u_char byte;
+  u_char *ip = *fpu_eip;
 
   *override = (overrides) { 0, 0, PREFIX_DEFAULT };       /* defaults */
 
   RE_ENTRANT_CHECK_OFF;
   FPU_code_verify_area(1);
-  get_user(byte, ip);
+  FPU_get_user(byte, ip);
   RE_ENTRANT_CHECK_ON;
 
   while ( 1 )
@@ -637,7 +633,7 @@
 	  ip++;
 	  RE_ENTRANT_CHECK_OFF;
 	  FPU_code_verify_area(1);
-	  get_user(byte, ip);
+	  FPU_get_user(byte, ip);
 	  RE_ENTRANT_CHECK_ON;
 	  break;
 	case FWAIT_OPCODE:
@@ -677,19 +673,79 @@
 
 
 
-void restore_i387_soft(struct _fpstate *buf)
+#define S387 ((struct i387_soft_struct *)s387)
+#define sstatus_word() \
+  ((S387->swd & ~SW_Top & 0xffff) | ((S387->ftop << SW_Top_Shift) & SW_Top))
+
+void restore_i387_soft(void *s387, struct _fpstate *buf)
 {
-  fpu_addr_modes addr_modes = {{ 0, 0, PREFIX_DEFAULT }, 0};
+  u_char *d = (u_char *)buf;
+  int offset, other, i, tags, regnr, tag, newtop;
+
+  RE_ENTRANT_CHECK_OFF;
+  FPU_verify_area(VERIFY_READ, d, 7*4 + 8*10);
+  __copy_from_user(&S387->cwd, d, 7*4);
+  RE_ENTRANT_CHECK_ON;
+
+  d += 7*4;
+
+  S387->ftop = (S387->swd >> SW_Top_Shift) & 7;
+  offset = (S387->ftop & 7) * 10;
+  other = 80 - offset;
+
+  RE_ENTRANT_CHECK_OFF;
+  /* Copy all registers in stack order. */
+  __copy_from_user(((u_char *)&S387->st_space)+offset, d, other);
+  if ( offset )
+    __copy_from_user((u_char *)&S387->st_space, d+other, offset);
+  RE_ENTRANT_CHECK_ON;
+
+  /* The tags may need to be corrected now. */
+  tags = S387->twd;
+  newtop = S387->ftop;
+  for ( i = 0; i < 8; i++ )
+    {
+      regnr = (i+newtop) & 7;
+      if ( ((tags >> ((regnr & 7)*2)) & 3) != TAG_Empty )
+	{
+	  /* The loaded data over-rides all other cases. */
+	  tag = FPU_tagof((FPU_REG *)((u_char *)S387->st_space + 10*regnr));
+	  tags &= ~(3 << (regnr*2));
+	  tags |= (tag & 3) << (regnr*2);
+	}
+    }
+  S387->twd = tags;
 
-  frstor(addr_modes, (char *)buf);
 }
 
 
-struct _fpstate * save_i387_soft(struct _fpstate * buf)
+struct _fpstate * save_i387_soft(void *s387, struct _fpstate * buf)
 {
-  fpu_addr_modes addr_modes = {{ 0, 0, PREFIX_DEFAULT }, 0};
+  u_char *d = (u_char *)buf;
+  int offset = (S387->ftop & 7) * 10, other = 80 - offset;
 
-  fsave(addr_modes, (char *)buf);
+  RE_ENTRANT_CHECK_OFF;
+  FPU_verify_area(VERIFY_WRITE, d, 7*4 + 8*10);
+#ifdef PECULIAR_486
+  S387->cwd &= ~0xe080;
+  /* An 80486 sets all the reserved bits to 1. */
+  S387->cwd |= 0xffff0000;
+  S387->swd = sstatus_word() | 0xffff0000;
+  S387->twd |= 0xffff0000;
+  S387->fcs |= 0xf8000000;
+  S387->fos |= 0xffff0000;
+#endif PECULIAR_486
+  __copy_to_user(d, &S387->cwd, 7*4);
+  RE_ENTRANT_CHECK_ON;
+
+  d += 7*4;
+
+  RE_ENTRANT_CHECK_OFF;
+  /* Copy all registers in stack order. */
+  __copy_to_user(d, ((u_char *)&S387->st_space)+offset, other);
+  if ( offset )
+    __copy_to_user(d+other, (u_char *)&S387->st_space, offset);
+  RE_ENTRANT_CHECK_ON;
 
   return buf;
 }
diff -u --recursive --new-file v2.1.72/linux/arch/i386/math-emu/fpu_etc.c linux/arch/i386/math-emu/fpu_etc.c
--- v2.1.72/linux/arch/i386/math-emu/fpu_etc.c	Thu Aug 18 22:54:01 1994
+++ linux/arch/i386/math-emu/fpu_etc.c	Tue Dec  9 17:57:09 1997
@@ -3,9 +3,9 @@
  |                                                                           |
  | Implement a few FPU instructions.                                         |
  |                                                                           |
- | Copyright (C) 1992,1993,1994                                              |
+ | Copyright (C) 1992,1993,1994,1997                                         |
  |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
- |                       Australia.  E-mail   billm@vaxc.cc.monash.edu.au    |
+ |                       Australia.  E-mail   billm@suburbia.net             |
  |                                                                           |
  |                                                                           |
  +---------------------------------------------------------------------------*/
@@ -17,102 +17,116 @@
 #include "reg_constant.h"
 
 
-static void fchs(FPU_REG *st0_ptr)
+static void fchs(FPU_REG *st0_ptr, u_char st0tag)
 {
-  if ( st0_ptr->tag ^ TW_Empty )
+  if ( st0tag ^ TAG_Empty )
     {
-      st0_ptr->sign ^= SIGN_POS^SIGN_NEG;
+      signbyte(st0_ptr) ^= SIGN_NEG;
       clear_C1();
     }
   else
-    stack_underflow();
+    FPU_stack_underflow();
 }
 
-static void fabs(FPU_REG *st0_ptr)
+
+static void fabs(FPU_REG *st0_ptr, u_char st0tag)
 {
-  if ( st0_ptr->tag ^ TW_Empty )
+  if ( st0tag ^ TAG_Empty )
     {
-      st0_ptr->sign = SIGN_POS;
+      setpositive(st0_ptr);
       clear_C1();
     }
   else
-    stack_underflow();
+    FPU_stack_underflow();
 }
 
 
-static void ftst_(FPU_REG *st0_ptr)
+static void ftst_(FPU_REG *st0_ptr, u_char st0tag)
 {
-  switch (st0_ptr->tag)
+  switch (st0tag)
     {
-    case TW_Zero:
+    case TAG_Zero:
       setcc(SW_C3);
       break;
-    case TW_Valid:
-      if (st0_ptr->sign == SIGN_POS)
+    case TAG_Valid:
+      if (getsign(st0_ptr) == SIGN_POS)
         setcc(0);
       else
         setcc(SW_C0);
-
-#ifdef DENORM_OPERAND
-      if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
+      break;
+    case TAG_Special:
+      switch ( FPU_Special(st0_ptr) )
 	{
+	case TW_Denormal:
+	  if (getsign(st0_ptr) == SIGN_POS)
+	    setcc(0);
+	  else
+	    setcc(SW_C0);
+	  if ( denormal_operand() < 0 )
+	    {
 #ifdef PECULIAR_486
-	  /* This is weird! */
-	  if (st0_ptr->sign == SIGN_POS)
-	    setcc(SW_C3);
+	      /* This is weird! */
+	      if (getsign(st0_ptr) == SIGN_POS)
+		setcc(SW_C3);
 #endif PECULIAR_486
-	  return;
+	      return;
+	    }
+	  break;
+	case TW_NaN:
+	  setcc(SW_C0|SW_C2|SW_C3);   /* Operand is not comparable */ 
+	  EXCEPTION(EX_Invalid);
+	  break;
+	case TW_Infinity:
+	  if (getsign(st0_ptr) == SIGN_POS)
+	    setcc(0);
+	  else
+	    setcc(SW_C0);
+	  break;
+	default:
+	  setcc(SW_C0|SW_C2|SW_C3);   /* Operand is not comparable */ 
+	  EXCEPTION(EX_INTERNAL|0x14);
+	  break;
 	}
-#endif DENORM_OPERAND
-
-      break;
-    case TW_NaN:
-      setcc(SW_C0|SW_C2|SW_C3);   /* Operand is not comparable */ 
-      EXCEPTION(EX_Invalid);
-      break;
-    case TW_Infinity:
-      if (st0_ptr->sign == SIGN_POS)
-        setcc(0);
-      else
-        setcc(SW_C0);
       break;
-    case TW_Empty:
+    case TAG_Empty:
       setcc(SW_C0|SW_C2|SW_C3);
       EXCEPTION(EX_StackUnder);
       break;
-    default:
-      setcc(SW_C0|SW_C2|SW_C3);   /* Operand is not comparable */ 
-      EXCEPTION(EX_INTERNAL|0x14);
-      break;
     }
 }
 
-static void fxam(FPU_REG *st0_ptr)
+
+static void fxam(FPU_REG *st0_ptr, u_char st0tag)
 {
-  int c=0;
-  switch (st0_ptr->tag)
+  int c = 0;
+  switch (st0tag)
     {
-    case TW_Empty:
+    case TAG_Empty:
       c = SW_C3|SW_C0;
       break;
-    case TW_Zero:
+    case TAG_Zero:
       c = SW_C3;
       break;
-    case TW_Valid:
-      /* This will need to be changed if TW_Denormal is ever used. */
-      if ( st0_ptr->exp <= EXP_UNDER )
-        c = SW_C2|SW_C3;  /* Denormal */
-      else
-        c = SW_C2;
-      break;
-    case TW_NaN:
-      c = SW_C0;
-      break;
-    case TW_Infinity:
-      c = SW_C2|SW_C0;
+    case TAG_Valid:
+      c = SW_C2;
       break;
+    case TAG_Special:
+      switch ( FPU_Special(st0_ptr) )
+	{
+	case TW_Denormal:
+	  c = SW_C2|SW_C3;  /* Denormal */
+	  break;
+	case TW_NaN:
+	  /* We also use NaN for unsupported types. */
+	  if ( (st0_ptr->sigh & 0x80000000) && (exponent(st0_ptr) == EXP_OVER) )
+	    c = SW_C0;
+	  break;
+	case TW_Infinity:
+	  c = SW_C2|SW_C0;
+	  break;
+	}
     }
-  if (st0_ptr->sign == SIGN_NEG)
+  if ( getsign(st0_ptr) == SIGN_NEG )
     c |= SW_C1;
   setcc(c);
 }
@@ -123,7 +137,7 @@
   ftst_, fxam, (FUNC_ST0)FPU_illegal, (FUNC_ST0)FPU_illegal
 };
 
-void fp_etc()
+void FPU_etc()
 {
-  (fp_etc_table[FPU_rm])(&st(0));
+  (fp_etc_table[FPU_rm])(&st(0), FPU_gettag0());
 }
diff -u --recursive --new-file v2.1.72/linux/arch/i386/math-emu/fpu_proto.h linux/arch/i386/math-emu/fpu_proto.h
--- v2.1.72/linux/arch/i386/math-emu/fpu_proto.h	Thu Oct 10 06:01:12 1996
+++ linux/arch/i386/math-emu/fpu_proto.h	Tue Dec  9 17:57:09 1997
@@ -1,22 +1,26 @@
+#ifndef _FPU_PROTO_H
+#define _FPU_PROTO_H
+
 /* errors.c */
 extern void Un_impl(void);
 extern void FPU_illegal(void);
-extern void emu_printall(void);
-extern void stack_overflow(void);
-extern void stack_underflow(void);
-extern void stack_underflow_i(int i);
-extern void stack_underflow_pop(int i);
-extern int set_precision_flag(int flags);
+extern void FPU_printall(void);
 asmlinkage void FPU_exception(int n);
-asmlinkage int real_2op_NaN(FPU_REG const *a, FPU_REG const *b, FPU_REG *dest);
-asmlinkage int arith_invalid(FPU_REG *dest);
-asmlinkage int divide_by_zero(int sign, FPU_REG *dest);
-asmlinkage void set_precision_flag_up(void);
-asmlinkage void set_precision_flag_down(void);
-asmlinkage int denormal_operand(void);
-asmlinkage int arith_overflow(FPU_REG *dest);
-asmlinkage int arith_underflow(FPU_REG *dest);
-
+extern int real_1op_NaN(FPU_REG *a);
+extern int real_2op_NaN(FPU_REG const *b, u_char tagb, int deststnr,
+			FPU_REG const *defaultNaN);
+extern int arith_invalid(int deststnr);
+extern int FPU_divide_by_zero(int deststnr, u_char sign);
+extern int set_precision_flag(int flags);
+extern void set_precision_flag_up(void);
+extern void set_precision_flag_down(void);
+extern int denormal_operand(void);
+extern int arith_overflow(FPU_REG *dest);
+extern int arith_underflow(FPU_REG *dest);
+extern void FPU_stack_overflow(void);
+extern void FPU_stack_underflow(void);
+extern void FPU_stack_underflow_i(int i);
+extern void FPU_stack_underflow_pop(int i);
 /* fpu_arith.c */
 extern void fadd__(void);
 extern void fmul__(void);
@@ -36,7 +40,6 @@
 extern void fsubp_(void);
 extern void fdivrp(void);
 extern void fdivp_(void);
-
 /* fpu_aux.c */
 extern void fclex(void);
 extern void finit(void);
@@ -49,89 +52,92 @@
 extern void ffreep(void);
 extern void fst_i_(void);
 extern void fstp_i(void);
-
 /* fpu_entry.c */
-asmlinkage void math_emulate(long arg);
+extern void math_emulate(long arg);
 extern void math_abort(struct info *info, unsigned int signal);
-
 /* fpu_etc.c */
-extern void fp_etc(void);
-
+extern void FPU_etc(void);
+/* fpu_tags.c */
+extern int FPU_gettag0(void);
+extern int FPU_gettagi(int stnr);
+extern int FPU_gettag(int regnr);
+extern void FPU_settag0(int tag);
+extern void FPU_settagi(int stnr, int tag);
+extern void FPU_settag(int regnr, int tag);
+extern int FPU_Special(FPU_REG const *ptr);
+extern int isNaN(FPU_REG const *ptr);
+extern void FPU_pop(void);
+extern int FPU_empty_i(int stnr);
+extern int FPU_stackoverflow(FPU_REG **st_new_ptr);
+extern void FPU_sync_tags(void);
+extern void FPU_copy_to_regi(FPU_REG const *r, u_char tag, int stnr);
+extern void FPU_copy_to_reg1(FPU_REG const *r, u_char tag);
+extern void FPU_copy_to_reg0(FPU_REG const *r, u_char tag);
 /* fpu_trig.c */
-extern void convert_l2reg(long const *arg, FPU_REG *dest);
-extern void trig_a(void);
-extern void trig_b(void);
-
+extern void FPU_triga(void);
+extern void FPU_trigb(void);
 /* get_address.c */
-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);
-
+extern void *FPU_get_address(u_char FPU_modrm, unsigned long *fpu_eip,
+			 struct address *addr, fpu_addr_modes addr_modes);
+extern void *FPU_get_address_16(u_char FPU_modrm, unsigned long *fpu_eip,
+			    struct address *addr, fpu_addr_modes addr_modes);
 /* load_store.c */
-extern int load_store_instr(unsigned char type, fpu_addr_modes addr_modes,
-			     void *address);
-
+extern int FPU_load_store(u_char type, fpu_addr_modes addr_modes,
+			    void *data_address);
 /* poly_2xm1.c */
-extern int poly_2xm1(FPU_REG const *arg, FPU_REG *result);
-
+extern int poly_2xm1(u_char sign, FPU_REG *arg, FPU_REG *result);
 /* poly_atan.c */
-extern void poly_atan(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *result);
-
+extern void poly_atan(FPU_REG *st0_ptr, u_char st0_tag, FPU_REG *st1_ptr,
+		      u_char st1_tag);
 /* poly_l2.c */
-extern void poly_l2(FPU_REG const *arg, FPU_REG const *y, FPU_REG *result);
-extern int poly_l2p1(FPU_REG const *arg, FPU_REG const *y, FPU_REG *result);
-
+extern void poly_l2(FPU_REG *st0_ptr, FPU_REG *st1_ptr, u_char st1_sign);
+extern int poly_l2p1(u_char s0, u_char s1, FPU_REG *r0, FPU_REG *r1,
+		     FPU_REG *d);
 /* poly_sin.c */
-extern void poly_sine(FPU_REG const *arg, FPU_REG *result);
-extern void poly_cos(FPU_REG const *arg, FPU_REG *result);
-
+extern void poly_sine(FPU_REG *st0_ptr);
+extern void poly_cos(FPU_REG *st0_ptr);
 /* poly_tan.c */
-extern void poly_tan(FPU_REG const *arg, FPU_REG *result);
-
+extern void poly_tan(FPU_REG *st0_ptr);
 /* reg_add_sub.c */
-extern int reg_add(FPU_REG const *a, FPU_REG const *b,
-		   FPU_REG *dest, int control_w);
-extern int reg_sub(FPU_REG const *a, FPU_REG const *b,
-		   FPU_REG *dest, int control_w);
-
+extern int FPU_add(FPU_REG const *b, u_char tagb, int destrnr, int control_w);
+extern int FPU_sub(int flags, int rm, int control_w);
 /* reg_compare.c */
-extern int compare(FPU_REG const *b);
-extern int compare_st_data(FPU_REG const *b);
+extern int FPU_compare_st_data(FPU_REG const *loaded_data, u_char loaded_tag);
 extern void fcom_st(void);
 extern void fcompst(void);
 extern void fcompp(void);
 extern void fucom_(void);
 extern void fucomp(void);
 extern void fucompp(void);
-
 /* reg_constant.c */
 extern void fconst(void);
-
 /* reg_ld_str.c */
-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, 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, char *address);
-extern void fsave(fpu_addr_modes addr_modes, char *address);
-
+extern int FPU_load_extended(long double *s, int stnr);
+extern int FPU_load_double(double *dfloat, FPU_REG *loaded_data);
+extern int FPU_load_single(float *single, FPU_REG *loaded_data);
+extern int FPU_load_int64(long long *_s);
+extern int FPU_load_int32(long *_s, FPU_REG *loaded_data);
+extern int FPU_load_int16(short *_s, FPU_REG *loaded_data);
+extern int FPU_load_bcd(u_char *s);
+extern int FPU_store_extended(FPU_REG *st0_ptr, u_char st0_tag,
+			      long double *d);
+extern int FPU_store_double(FPU_REG *st0_ptr, u_char st0_tag, double *dfloat);
+extern int FPU_store_single(FPU_REG *st0_ptr, u_char st0_tag, float *single);
+extern int FPU_store_int64(FPU_REG *st0_ptr, u_char st0_tag, long long *d);
+extern int FPU_store_int32(FPU_REG *st0_ptr, u_char st0_tag, long *d);
+extern int FPU_store_int16(FPU_REG *st0_ptr, u_char st0_tag, short *d);
+extern int FPU_store_bcd(FPU_REG *st0_ptr, u_char st0_tag, u_char *d);
+extern int FPU_round_to_int(FPU_REG *r, u_char tag);
+extern u_char *fldenv(fpu_addr_modes addr_modes, u_char *s);
+extern void frstor(fpu_addr_modes addr_modes, u_char *data_address);
+extern u_char *fstenv(fpu_addr_modes addr_modes, u_char *d);
+extern void fsave(fpu_addr_modes addr_modes, u_char *data_address);
+extern int FPU_tagof(FPU_REG *ptr);
 /* reg_mul.c */
-extern int reg_mul(FPU_REG const *a, FPU_REG const *b,
-		   FPU_REG *dest, unsigned int control_w);
+extern int FPU_mul(FPU_REG const *b, u_char tagb, int deststnr, int control_w);
+
+extern int FPU_div(int flags, int regrm, int control_w);
+/* reg_convert.c */
+extern int FPU_to_exp16(FPU_REG const *a, FPU_REG *x);
+#endif /* _FPU_PROTO_H */
+
diff -u --recursive --new-file v2.1.72/linux/arch/i386/math-emu/fpu_system.h linux/arch/i386/math-emu/fpu_system.h
--- v2.1.72/linux/arch/i386/math-emu/fpu_system.h	Tue Oct 15 05:42:06 1996
+++ linux/arch/i386/math-emu/fpu_system.h	Tue Dec  9 17:57:09 1997
@@ -1,9 +1,9 @@
 /*---------------------------------------------------------------------------+
  |  fpu_system.h                                                             |
  |                                                                           |
- | Copyright (C) 1992,1994                                                   |
+ | Copyright (C) 1992,1994,1997                                              |
  |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
- |                       Australia.  E-mail   billm@vaxc.cc.monash.edu.au    |
+ |                       Australia.  E-mail   billm@suburbia.net             |
  |                                                                           |
  +---------------------------------------------------------------------------*/
 
@@ -18,19 +18,19 @@
 
 /* This sets the pointer FPU_info to point to the argument part
    of the stack frame of math_emulate() */
-#define SETUP_DATA_AREA(arg)    FPU_info = (struct info *) &arg
+#define 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) \
+#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))) \
+#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)
@@ -48,23 +48,24 @@
 
 /* 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])
+#define no_ip_update		(*(u_char *)&(I387.soft.no_update))
+#define FPU_rm			(*(u_char *)&(I387.soft.rm))
 
 /* 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 access_limit		(*(u_char *)&(I387.soft.alimit))
 
-#define partial_status       	(I387.soft.swd)
+#define partial_status		(I387.soft.swd)
 #define control_word		(I387.soft.cwd)
-#define regs			(I387.soft.regs)
-#define top			(I387.soft.top)
+#define fpu_tag_word		(I387.soft.twd)
+#define registers		(I387.soft.st_space)
+#define top			(I387.soft.ftop)
 
-#define instruction_address     (*(struct address *)&I387.soft.fip)
-#define operand_address         (*(struct address *)&I387.soft.foo)
+#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)
+#define FPU_verify_area(x,y,z)	if ( verify_area(x,y,z) ) \
+				math_abort(FPU_info,SIGSEGV)
 
 #undef FPU_IGNORE_CODE_SEGV
 #ifdef FPU_IGNORE_CODE_SEGV
@@ -79,5 +80,8 @@
    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
+
+#define FPU_get_user(x,y)       get_user((x),(y))
+#define FPU_put_user(x,y)       put_user((x),(y))
 
 #endif
diff -u --recursive --new-file v2.1.72/linux/arch/i386/math-emu/fpu_tags.c linux/arch/i386/math-emu/fpu_tags.c
--- v2.1.72/linux/arch/i386/math-emu/fpu_tags.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/i386/math-emu/fpu_tags.c	Tue Dec  9 17:57:09 1997
@@ -0,0 +1,127 @@
+/*---------------------------------------------------------------------------+
+ |  fpu_tags.c                                                               |
+ |                                                                           |
+ |  Set FPU register tags.                                                   |
+ |                                                                           |
+ | Copyright (C) 1997                                                        |
+ |                  W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
+ |                  E-mail   billm@jacobi.maths.monash.edu.au                |
+ |                                                                           |
+ |                                                                           |
+ +---------------------------------------------------------------------------*/
+
+#include "fpu_emu.h"
+#include "fpu_system.h"
+#include "exception.h"
+
+
+void FPU_pop(void)
+{
+  fpu_tag_word |= 3 << ((top & 7)*2);
+  top++;
+}
+
+
+int FPU_gettag0(void)
+{
+  return (fpu_tag_word >> ((top & 7)*2)) & 3;
+}
+
+
+int FPU_gettagi(int stnr)
+{
+  return (fpu_tag_word >> (((top+stnr) & 7)*2)) & 3;
+}
+
+
+int FPU_gettag(int regnr)
+{
+  return (fpu_tag_word >> ((regnr & 7)*2)) & 3;
+}
+
+
+void FPU_settag0(int tag)
+{
+  int regnr = top;
+  regnr &= 7;
+  fpu_tag_word &= ~(3 << (regnr*2));
+  fpu_tag_word |= (tag & 3) << (regnr*2);
+}
+
+
+void FPU_settagi(int stnr, int tag)
+{
+  int regnr = stnr+top;
+  regnr &= 7;
+  fpu_tag_word &= ~(3 << (regnr*2));
+  fpu_tag_word |= (tag & 3) << (regnr*2);
+}
+
+
+void FPU_settag(int regnr, int tag)
+{
+  regnr &= 7;
+  fpu_tag_word &= ~(3 << (regnr*2));
+  fpu_tag_word |= (tag & 3) << (regnr*2);
+}
+
+
+int FPU_Special(FPU_REG const *ptr)
+{
+  int exp = exponent(ptr);
+
+  if ( exp == EXP_BIAS+EXP_UNDER )
+    return TW_Denormal;
+  else if ( exp != EXP_BIAS+EXP_OVER )
+    return TW_NaN;
+  else if ( (ptr->sigh == 0x80000000) && (ptr->sigl == 0) )
+    return TW_Infinity;
+  return TW_NaN;
+}
+
+
+int isNaN(FPU_REG const *ptr)
+{
+  return ( (exponent(ptr) == EXP_BIAS+EXP_OVER)
+	   && !((ptr->sigh == 0x80000000) && (ptr->sigl == 0)) );
+}
+
+
+int FPU_empty_i(int stnr)
+{
+  int regnr = (top+stnr) & 7;
+
+  return ((fpu_tag_word >> (regnr*2)) & 3) == TAG_Empty;
+}
+
+
+int FPU_stackoverflow(FPU_REG **st_new_ptr)
+{
+  *st_new_ptr = &st(-1);
+
+  return ((fpu_tag_word >> (((top - 1) & 7)*2)) & 3) != TAG_Empty;
+}
+
+
+void FPU_copy_to_regi(FPU_REG const *r, u_char tag, int stnr)
+{
+  reg_copy(r, &st(stnr));
+  FPU_settagi(stnr, tag);
+}
+
+void FPU_copy_to_reg1(FPU_REG const *r, u_char tag)
+{
+  reg_copy(r, &st(1));
+  FPU_settagi(1, tag);
+}
+
+void FPU_copy_to_reg0(FPU_REG const *r, u_char tag)
+{
+  int regnr = top;
+  regnr &= 7;
+
+  reg_copy(r, &st(0));
+
+  fpu_tag_word &= ~(3 << (regnr*2));
+  fpu_tag_word |= (tag & 3) << (regnr*2);
+}
diff -u --recursive --new-file v2.1.72/linux/arch/i386/math-emu/fpu_trig.c linux/arch/i386/math-emu/fpu_trig.c
--- v2.1.72/linux/arch/i386/math-emu/fpu_trig.c	Sun Jul 31 22:19:13 1994
+++ linux/arch/i386/math-emu/fpu_trig.c	Tue Dec  9 17:57:09 1997
@@ -3,9 +3,9 @@
  |                                                                           |
  | Implementation of the FPU "transcendental" functions.                     |
  |                                                                           |
- | Copyright (C) 1992,1993,1994                                              |
+ | Copyright (C) 1992,1993,1994,1997                                         |
  |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
- |                       Australia.  E-mail   billm@vaxc.cc.monash.edu.au    |
+ |                       Australia.  E-mail   billm@suburbia.net             |
  |                                                                           |
  |                                                                           |
  +---------------------------------------------------------------------------*/
@@ -17,7 +17,6 @@
 #include "control_w.h"
 #include "reg_constant.h"	
 
-
 static void rem_kernel(unsigned long long st0, unsigned long long *y,
 		       unsigned long long st1,
 		       unsigned long long q, int n);
@@ -25,9 +24,6 @@
 #define BETTER_THAN_486
 
 #define FCOS  4
-/* Not needed now with new code
-#define FPTAN 1
- */
 
 /* Used only by fptan, fsin, fcos, and fsincos. */
 /* This routine produces very accurate results, similar to
@@ -35,13 +31,15 @@
 /* Limited measurements show no results worse than 64 bit precision
    except for the results for arguments close to 2^63, where the
    precision of the result sometimes degrades to about 63.9 bits */
-static int trig_arg(FPU_REG *X, int even)
+static int trig_arg(FPU_REG *st0_ptr, int even)
 {
   FPU_REG tmp;
+  u_char tmptag;
   unsigned long long q;
   int old_cw = control_word, saved_status = partial_status;
+  int tag, st0_tag = TAG_Valid;
 
-  if ( X->exp >= EXP_BIAS + 63 )
+  if ( exponent(st0_ptr) >= 63 )
     {
       partial_status |= SW_C2;     /* Reduction incomplete. */
       return -1;
@@ -50,58 +48,52 @@
   control_word &= ~CW_RC;
   control_word |= RC_CHOP;
 
-  reg_div(X, &CONST_PI2, &tmp, PR_64_BITS | RC_CHOP | 0x3f);
-  round_to_int(&tmp);  /* Fortunately, this can't overflow
-			  to 2^64 */
+  setpositive(st0_ptr);
+  tag = FPU_u_div(st0_ptr, &CONST_PI2, &tmp, PR_64_BITS | RC_CHOP | 0x3f,
+		  SIGN_POS);
+
+  FPU_round_to_int(&tmp, tag);  /* Fortunately, this can't overflow
+				   to 2^64 */
   q = significand(&tmp);
   if ( q )
     {
-      rem_kernel(significand(X),
+      rem_kernel(significand(st0_ptr),
 		 &significand(&tmp),
 		 significand(&CONST_PI2),
-		 q, X->exp - CONST_PI2.exp);
-      tmp.exp = CONST_PI2.exp;
-      normalize(&tmp);
-      reg_move(&tmp, X);
+		 q, exponent(st0_ptr) - exponent(&CONST_PI2));
+      setexponent16(&tmp, exponent(&CONST_PI2));
+      st0_tag = FPU_normalize(&tmp);
+      FPU_copy_to_reg0(&tmp, st0_tag);
     }
 
-#ifdef FPTAN
-  if ( even == FPTAN )
-    {
-      if ( ((X->exp >= EXP_BIAS) ||
-	    ((X->exp == EXP_BIAS-1)
-	     && (X->sigh >= 0xc90fdaa2))) ^ (q & 1) )
-	even = FCOS;
-      else
-	even = 0;
-    }
-#endif FPTAN
-
   if ( (even && !(q & 1)) || (!even && (q & 1)) )
     {
-      reg_sub(&CONST_PI2, X, X, FULL_PRECISION);
+      st0_tag = FPU_sub(REV|LOADED|TAG_Valid, (int)&CONST_PI2, FULL_PRECISION);
+
 #ifdef BETTER_THAN_486
       /* So far, the results are exact but based upon a 64 bit
 	 precision approximation to pi/2. The technique used
 	 now is equivalent to using an approximation to pi/2 which
 	 is accurate to about 128 bits. */
-      if ( (X->exp <= CONST_PI2extra.exp + 64) || (q > 1) )
+      if ( (exponent(st0_ptr) <= exponent(&CONST_PI2extra) + 64) || (q > 1) )
 	{
-	  /* This code gives the effect of having p/2 to better than
+	  /* This code gives the effect of having pi/2 to better than
 	     128 bits precision. */
+
 	  significand(&tmp) = q + 1;
-	  tmp.exp = EXP_BIAS + 63;
-	  tmp.tag = TW_Valid;
-	  normalize(&tmp);
-	  reg_mul(&CONST_PI2extra, &tmp, &tmp, FULL_PRECISION);
-	  reg_add(X, &tmp,  X, FULL_PRECISION);
-	  if ( X->sign == SIGN_NEG )
+	  setexponent16(&tmp, 63);
+	  FPU_normalize(&tmp);
+	  tmptag =
+	    FPU_u_mul(&CONST_PI2extra, &tmp, &tmp, FULL_PRECISION, SIGN_POS,
+		      exponent16(&CONST_PI2extra) + exponent16(&tmp));
+	  st0_tag = FPU_add(&tmp, tmptag, 0, FULL_PRECISION);
+	  if ( signnegative(st0_ptr) )
 	    {
 	      /* CONST_PI2extra is negative, so the result of the addition
 		 can be negative. This means that the argument is actually
 		 in a different quadrant. The correction is always < pi/2,
 		 so it can't overflow into yet another quadrant. */
-	      X->sign = SIGN_POS;
+	      setpositive(st0_ptr);
 	      q++;
 	    }
 	}
@@ -114,33 +106,39 @@
 	 precision approximation to pi/2. The technique used
 	 now is equivalent to using an approximation to pi/2 which
 	 is accurate to about 128 bits. */
-      if ( ((q > 0) && (X->exp <= CONST_PI2extra.exp + 64)) || (q > 1) )
+      if ( ((q > 0) && (exponent(st0_ptr) <= exponent(&CONST_PI2extra) + 64))
+	   || (q > 1) )
 	{
 	  /* This code gives the effect of having p/2 to better than
 	     128 bits precision. */
+
 	  significand(&tmp) = q;
-	  tmp.exp = EXP_BIAS + 63;
-	  tmp.tag = TW_Valid;
-	  normalize(&tmp);
-	  reg_mul(&CONST_PI2extra, &tmp, &tmp, FULL_PRECISION);
-	  reg_sub(X, &tmp, X, FULL_PRECISION);
-	  if ( (X->exp == CONST_PI2.exp) &&
-	      ((X->sigh > CONST_PI2.sigh)
-	       || ((X->sigh == CONST_PI2.sigh)
-		   && (X->sigl > CONST_PI2.sigl))) )
+	  setexponent16(&tmp, 63);
+	  FPU_normalize(&tmp);         /* This must return TAG_Valid */
+	  tmptag = FPU_u_mul(&CONST_PI2extra, &tmp, &tmp, FULL_PRECISION,
+			     SIGN_POS,
+			     exponent16(&CONST_PI2extra) + exponent16(&tmp));
+	  st0_tag = FPU_sub(LOADED|(tmptag & 0x0f), (int)&tmp,
+			    FULL_PRECISION);
+	  if ( (exponent(st0_ptr) == exponent(&CONST_PI2)) &&
+	      ((st0_ptr->sigh > CONST_PI2.sigh)
+	       || ((st0_ptr->sigh == CONST_PI2.sigh)
+		   && (st0_ptr->sigl > CONST_PI2.sigl))) )
 	    {
 	      /* CONST_PI2extra is negative, so the result of the
 		 subtraction can be larger than pi/2. This means
 		 that the argument is actually in a different quadrant.
 		 The correction is always < pi/2, so it can't overflow
 		 into yet another quadrant. */
-	      reg_sub(&CONST_PI, X, X, FULL_PRECISION);
+	      st0_tag = FPU_sub(REV|LOADED|TAG_Valid, (int)&CONST_PI2,
+				FULL_PRECISION);
 	      q++;
 	    }
 	}
     }
 #endif BETTER_THAN_486
 
+  FPU_settag0(st0_tag);
   control_word = old_cw;
   partial_status = saved_status & ~SW_C2;     /* Reduction complete. */
 
@@ -149,57 +147,56 @@
 
 
 /* Convert a long to register */
-void convert_l2reg(long const *arg, FPU_REG *dest)
+static void convert_l2reg(long const *arg, int deststnr)
 {
+  int tag;
   long num = *arg;
+  u_char sign;
+  FPU_REG *dest = &st(deststnr);
 
   if (num == 0)
-    { reg_move(&CONST_Z, dest); return; }
+    {
+      FPU_copy_to_regi(&CONST_Z, TAG_Zero, deststnr);
+      return;
+    }
 
   if (num > 0)
-    dest->sign = SIGN_POS;
+    { sign = SIGN_POS; }
   else
-    { num = -num; dest->sign = SIGN_NEG; }
+    { num = -num; sign = SIGN_NEG; }
 
   dest->sigh = num;
   dest->sigl = 0;
-  dest->exp = EXP_BIAS + 31;
-  dest->tag = TW_Valid;
-  normalize(dest);
+  setexponent16(dest, 31);
+  tag = FPU_normalize(dest);
+  FPU_settagi(deststnr, tag);
+  setsign(dest, sign);
+  return;
 }
 
 
-static void single_arg_error(FPU_REG *st0_ptr)
+static void single_arg_error(FPU_REG *st0_ptr, u_char st0_tag)
 {
-  switch ( st0_ptr->tag )
-    {
-    case TW_NaN:
-      if ( !(st0_ptr->sigh & 0x40000000) )   /* Signaling ? */
-	{
-	  EXCEPTION(EX_Invalid);
-	  if ( control_word & CW_Invalid )
-	    st0_ptr->sigh |= 0x40000000;	  /* Convert to a QNaN */
-	}
-      break;              /* return with a NaN in st(0) */
-    case TW_Empty:
-      stack_underflow();  /* Puts a QNaN in st(0) */
-      break;
+  if ( st0_tag == TAG_Empty )
+    FPU_stack_underflow();  /* Puts a QNaN in st(0) */
+  else if ( st0_tag == TW_NaN )
+    real_1op_NaN(st0_ptr);       /* return with a NaN in st(0) */
 #ifdef PARANOID
-    default:
-      EXCEPTION(EX_INTERNAL|0x0112);
+  else
+    EXCEPTION(EX_INTERNAL|0x0112);
 #endif PARANOID
-    }
 }
 
 
-static void single_arg_2_error(FPU_REG *st0_ptr)
+static void single_arg_2_error(FPU_REG *st0_ptr, u_char st0_tag)
 {
-  FPU_REG *st_new_ptr;
+  int isNaN;
 
-  switch ( st0_ptr->tag )
+  switch ( st0_tag )
     {
     case TW_NaN:
-      if ( !(st0_ptr->sigh & 0x40000000) )   /* Signaling ? */
+      isNaN = (exponent(st0_ptr) == EXP_OVER) && (st0_ptr->sigh & 0x80000000);
+      if ( isNaN && !(st0_ptr->sigh & 0x40000000) )   /* Signaling ? */
 	{
 	  EXCEPTION(EX_Invalid);
 	  if ( control_word & CW_Invalid )
@@ -207,17 +204,27 @@
 	      /* The masked response */
 	      /* Convert to a QNaN */
 	      st0_ptr->sigh |= 0x40000000;
-	      st_new_ptr = &st(-1);
 	      push();
-	      reg_move(&st(1), st_new_ptr);
+	      FPU_copy_to_reg0(st0_ptr, TAG_Special);
 	    }
 	}
-      else
+      else if ( isNaN )
 	{
 	  /* A QNaN */
-	  st_new_ptr = &st(-1);
 	  push();
-	  reg_move(&st(1), st_new_ptr);
+	  FPU_copy_to_reg0(st0_ptr, TAG_Special);
+	}
+      else
+	{
+	  /* pseudoNaN or other unsupported */
+	  EXCEPTION(EX_Invalid);
+	  if ( control_word & CW_Invalid )
+	    {
+	      /* The masked response */
+	      FPU_copy_to_reg0(&CONST_QNaN, TAG_Special);
+	      push();
+	      FPU_copy_to_reg0(&CONST_QNaN, TAG_Special);
+	    }
 	}
       break;              /* return with a NaN in st(0) */
 #ifdef PARANOID
@@ -230,92 +237,88 @@
 
 /*---------------------------------------------------------------------------*/
 
-static void f2xm1(FPU_REG *st0_ptr)
+static void f2xm1(FPU_REG *st0_ptr, u_char tag)
 {
+  FPU_REG a;
+
   clear_C1();
-  switch ( st0_ptr->tag )
+
+  if ( tag == TAG_Valid )
     {
-    case TW_Valid:
-      {
-	if ( st0_ptr->exp >= 0 )
-	  {
-	    /* For an 80486 FPU, the result is undefined. */
-	  }
-#ifdef DENORM_OPERAND
-	else if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
-	  return;
-#endif DENORM_OPERAND
-	else
-	  {
-	    /* poly_2xm1(x) requires 0 < x < 1. */
-	    poly_2xm1(st0_ptr, st0_ptr);
-	  }
-	if ( st0_ptr->exp <= EXP_UNDER )
-	  {
-	    /* A denormal result has been produced.
-	       Precision must have been lost, this is always
-	       an underflow. */
-	    arith_underflow(st0_ptr);
-	  }
-	set_precision_flag_up();   /* 80486 appears to always do this */
-	return;
-      }
-    case TW_Zero:
+      /* For an 80486 FPU, the result is undefined if the arg is >= 1.0 */
+      if ( exponent(st0_ptr) < 0 )
+	{
+	denormal_arg:
+
+	  FPU_to_exp16(st0_ptr, &a);
+
+	  /* poly_2xm1(x) requires 0 < st(0) < 1. */
+	  poly_2xm1(getsign(st0_ptr), &a, st0_ptr);
+	}
+      set_precision_flag_up();   /* 80486 appears to always do this */
       return;
+    }
+
+  if ( tag == TAG_Zero )
+    return;
+
+  if ( tag == TAG_Special )
+    tag = FPU_Special(st0_ptr);
+
+  switch ( tag )
+    {
+    case TW_Denormal:
+      if ( denormal_operand() < 0 )
+	return;
+      goto denormal_arg;
     case TW_Infinity:
-      if ( st0_ptr->sign == SIGN_NEG )
+      if ( signnegative(st0_ptr) )
 	{
 	  /* -infinity gives -1 (p16-10) */
-	  reg_move(&CONST_1, st0_ptr);
-	  st0_ptr->sign = SIGN_NEG;
+	  FPU_copy_to_reg0(&CONST_1, TAG_Valid);
+	  setnegative(st0_ptr);
 	}
       return;
     default:
-      single_arg_error(st0_ptr);
+      single_arg_error(st0_ptr, tag);
     }
 }
 
 
-static void fptan(FPU_REG *st0_ptr)
+static void fptan(FPU_REG *st0_ptr, u_char st0_tag)
 {
-  char st0_tag = st0_ptr->tag;
   FPU_REG *st_new_ptr;
   int q;
-  char arg_sign = st0_ptr->sign;
+  u_char arg_sign = getsign(st0_ptr);
 
   /* Stack underflow has higher priority */
-  if ( st0_tag == TW_Empty )
+  if ( st0_tag == TAG_Empty )
     {
-      stack_underflow();  /* Puts a QNaN in st(0) */
+      FPU_stack_underflow();  /* Puts a QNaN in st(0) */
       if ( control_word & CW_Invalid )
 	{
 	  st_new_ptr = &st(-1);
 	  push();
-	  stack_underflow();  /* Puts a QNaN in the new st(0) */
+	  FPU_stack_underflow();  /* Puts a QNaN in the new st(0) */
 	}
       return;
     }
 
   if ( STACK_OVERFLOW )
-    { stack_overflow(); return; }
+    { FPU_stack_overflow(); return; }
 
-  switch ( st0_tag )
+  if ( st0_tag == TAG_Valid )
     {
-    case TW_Valid:
-      if ( st0_ptr->exp > EXP_BIAS - 40 )
+      if ( exponent(st0_ptr) > -40 )
 	{
-	  st0_ptr->sign = SIGN_POS;
-	  if ( (q = trig_arg(st0_ptr, 0)) != -1 )
-	    {
-	      poly_tan(st0_ptr, st0_ptr);
-	      st0_ptr->sign = (q & 1) ^ arg_sign;
-	    }
-	  else
+	  if ( (q = trig_arg(st0_ptr, 0)) == -1 )
 	    {
 	      /* Operand is out of range */
-	      st0_ptr->sign = arg_sign;         /* restore st(0) */
 	      return;
 	    }
+
+	  poly_tan(st0_ptr);
+	  setsign(st0_ptr, (q & 1) ^ (arg_sign != 0));
 	  set_precision_flag_up();  /* We do not really know if up or down */
 	}
       else
@@ -323,106 +326,134 @@
 	  /* For a small arg, the result == the argument */
 	  /* Underflow may happen */
 
-	  if ( st0_ptr->exp <= EXP_UNDER )
-	    {
-#ifdef DENORM_OPERAND
-	      if ( denormal_operand() )
-		return;
-#endif DENORM_OPERAND
-	      /* A denormal result has been produced.
-		 Precision must have been lost, this is always
-		 an underflow. */
-	      if ( arith_underflow(st0_ptr) )
-		return;
-	    }
-	  set_precision_flag_down();  /* Must be down. */
+	denormal_arg:
+
+	  FPU_to_exp16(st0_ptr, st0_ptr);
+      
+	  st0_tag = FPU_round(st0_ptr, 1, 0, FULL_PRECISION, arg_sign);
+	  FPU_settag0(st0_tag);
 	}
       push();
-      reg_move(&CONST_1, st_new_ptr);
+      FPU_copy_to_reg0(&CONST_1, TAG_Valid);
       return;
-      break;
-    case TW_Infinity:
+    }
+
+  if ( st0_tag == TAG_Zero )
+    {
+      push();
+      FPU_copy_to_reg0(&CONST_1, TAG_Valid);
+      setcc(0);
+      return;
+    }
+
+  if ( st0_tag == TAG_Special )
+    st0_tag = FPU_Special(st0_ptr);
+
+  if ( st0_tag == TW_Denormal )
+    {
+      if ( denormal_operand() < 0 )
+	return;
+
+      goto denormal_arg;
+    }
+
+  if ( st0_tag == TW_Infinity )
+    {
       /* The 80486 treats infinity as an invalid operand */
-      arith_invalid(st0_ptr);
-      if ( control_word & CW_Invalid )
+      if ( arith_invalid(0) >= 0 )
 	{
 	  st_new_ptr = &st(-1);
 	  push();
-	  arith_invalid(st_new_ptr);
+	  arith_invalid(0);
 	}
       return;
-    case TW_Zero:
-      push();
-      reg_move(&CONST_1, st_new_ptr);
-      setcc(0);
-      break;
-    default:
-      single_arg_2_error(st0_ptr);
-      break;
     }
+
+  single_arg_2_error(st0_ptr, st0_tag);
 }
 
 
-static void fxtract(FPU_REG *st0_ptr)
+static void fxtract(FPU_REG *st0_ptr, u_char st0_tag)
 {
-  char st0_tag = st0_ptr->tag;
   FPU_REG *st_new_ptr;
+  u_char sign;
   register FPU_REG *st1_ptr = st0_ptr;  /* anticipate */
 
   if ( STACK_OVERFLOW )
-    {  stack_overflow(); return; }
+    {  FPU_stack_overflow(); return; }
+
   clear_C1();
-  if ( !(st0_tag ^ TW_Valid) )
+
+  if ( st0_tag == TAG_Valid )
     {
       long e;
 
-#ifdef DENORM_OPERAND
-      if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
-	return;
-#endif DENORM_OPERAND
-	  
       push();
-      reg_move(st1_ptr, st_new_ptr);
-      st_new_ptr->exp = EXP_BIAS;
-      e = st1_ptr->exp - EXP_BIAS;
-      convert_l2reg(&e, st1_ptr);
+      sign = getsign(st1_ptr);
+      reg_copy(st1_ptr, st_new_ptr);
+      setexponent16(st_new_ptr, exponent(st_new_ptr));
+
+    denormal_arg:
+
+      e = exponent16(st_new_ptr);
+      convert_l2reg(&e, 1);
+      setexponentpos(st_new_ptr, 0);
+      setsign(st_new_ptr, sign);
+      FPU_settag0(TAG_Valid);       /* Needed if arg was a denormal */
       return;
     }
-  else if ( st0_tag == TW_Zero )
+  else if ( st0_tag == TAG_Zero )
     {
-      char sign = st0_ptr->sign;
-      if ( divide_by_zero(SIGN_NEG, st0_ptr) )
+      sign = getsign(st0_ptr);
+
+      if ( FPU_divide_by_zero(0, SIGN_NEG) < 0 )
 	return;
+
       push();
-      reg_move(&CONST_Z, st_new_ptr);
-      st_new_ptr->sign = sign;
+      FPU_copy_to_reg0(&CONST_Z, TAG_Zero);
+      setsign(st_new_ptr, sign);
       return;
     }
+
+  if ( st0_tag == TAG_Special )
+    st0_tag = FPU_Special(st0_ptr);
+
+  if ( st0_tag == TW_Denormal )
+    {
+      if (denormal_operand() < 0 )
+	return;
+
+      push();
+      sign = getsign(st1_ptr);
+      FPU_to_exp16(st1_ptr, st_new_ptr);
+      goto denormal_arg;
+    }
   else if ( st0_tag == TW_Infinity )
     {
-      char sign = st0_ptr->sign;
-      st0_ptr->sign = SIGN_POS;
+      sign = getsign(st0_ptr);
+      setpositive(st0_ptr);
       push();
-      reg_move(&CONST_INF, st_new_ptr);
-      st_new_ptr->sign = sign;
+      FPU_copy_to_reg0(&CONST_INF, TAG_Special);
+      setsign(st_new_ptr, sign);
       return;
     }
   else if ( st0_tag == TW_NaN )
     {
-      if ( real_2op_NaN(st0_ptr, st0_ptr, st0_ptr) )
+      if ( real_1op_NaN(st0_ptr) < 0 )
 	return;
+
       push();
-      reg_move(st1_ptr, st_new_ptr);
+      FPU_copy_to_reg0(st0_ptr, TAG_Special);
       return;
     }
-  else if ( st0_tag == TW_Empty )
+  else if ( st0_tag == TAG_Empty )
     {
       /* Is this the correct behaviour? */
       if ( control_word & EX_Invalid )
 	{
-	  stack_underflow();
+	  FPU_stack_underflow();
 	  push();
-	  stack_underflow();
+	  FPU_stack_underflow();
 	}
       else
 	EXCEPTION(EX_StackUnder);
@@ -434,193 +465,233 @@
 }
 
 
-static void fdecstp(FPU_REG *st0_ptr)
+static void fdecstp(void)
 {
   clear_C1();
-  top--;  /* st0_ptr will be fixed in math_emulate() before the next instr */
+  top--;
 }
 
-static void fincstp(FPU_REG *st0_ptr)
+static void fincstp(void)
 {
   clear_C1();
-  top++;  /* st0_ptr will be fixed in math_emulate() before the next instr */
+  top++;
 }
 
 
-static void fsqrt_(FPU_REG *st0_ptr)
+static void fsqrt_(FPU_REG *st0_ptr, u_char st0_tag)
 {
-  char st0_tag = st0_ptr->tag;
+  int expon;
 
   clear_C1();
-  if ( !(st0_tag ^ TW_Valid) )
+
+  if ( st0_tag == TAG_Valid )
     {
-      int expon;
+      u_char tag;
       
-      if (st0_ptr->sign == SIGN_NEG)
+      if (signnegative(st0_ptr))
 	{
-	  arith_invalid(st0_ptr);  /* sqrt(negative) is invalid */
+	  arith_invalid(0);  /* sqrt(negative) is invalid */
 	  return;
 	}
 
-#ifdef DENORM_OPERAND
-      if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
-	return;
-#endif DENORM_OPERAND
+      /* make st(0) in  [1.0 .. 4.0) */
+      expon = exponent(st0_ptr);
 
-      expon = st0_ptr->exp - EXP_BIAS;
-      st0_ptr->exp = EXP_BIAS + (expon & 1);  /* make st(0) in  [1.0 .. 4.0) */
-      
-      wm_sqrt(st0_ptr, control_word);	/* Do the computation */
-      
-      st0_ptr->exp += expon >> 1;
-      st0_ptr->sign = SIGN_POS;
+    denormal_arg:
+
+      setexponent16(st0_ptr, (expon & 1));
+
+      /* Do the computation, the sign of the result will be positive. */
+      tag = wm_sqrt(st0_ptr, 0, 0, control_word, SIGN_POS);
+      addexponent(st0_ptr, expon >> 1);
+      FPU_settag0(tag);
+      return;
     }
-  else if ( st0_tag == TW_Zero )
+
+  if ( st0_tag == TAG_Zero )
     return;
-  else if ( st0_tag == TW_Infinity )
+
+  if ( st0_tag == TAG_Special )
+    st0_tag = FPU_Special(st0_ptr);
+
+  if ( st0_tag == TW_Infinity )
     {
-      if ( st0_ptr->sign == SIGN_NEG )
-	arith_invalid(st0_ptr);  /* sqrt(-Infinity) is invalid */
+      if ( signnegative(st0_ptr) )
+	arith_invalid(0);  /* sqrt(-Infinity) is invalid */
       return;
     }
-  else
-    { single_arg_error(st0_ptr); return; }
+  else if ( st0_tag == TW_Denormal )
+    {
+      if (signnegative(st0_ptr))
+	{
+	  arith_invalid(0);  /* sqrt(negative) is invalid */
+	  return;
+	}
+
+      if ( denormal_operand() < 0 )
+	return;
+
+      FPU_to_exp16(st0_ptr, st0_ptr);
+
+      expon = exponent16(st0_ptr);
+
+      goto denormal_arg;
+    }
+
+  single_arg_error(st0_ptr, st0_tag);
 
 }
 
 
-static void frndint_(FPU_REG *st0_ptr)
+static void frndint_(FPU_REG *st0_ptr, u_char st0_tag)
 {
-  char st0_tag = st0_ptr->tag;
-  int flags;
+  int flags, tag;
 
-  if ( !(st0_tag ^ TW_Valid) )
+  if ( st0_tag == TAG_Valid )
     {
-      if (st0_ptr->exp > EXP_BIAS+63)
-	return;
+      u_char sign;
 
-#ifdef DENORM_OPERAND
-      if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
+    denormal_arg:
+
+      sign = getsign(st0_ptr);
+
+      if (exponent(st0_ptr) > 63)
 	return;
-#endif DENORM_OPERAND
+
+      if ( st0_tag == TW_Denormal )
+	{
+	  if (denormal_operand() < 0 )
+	    return;
+	}
 
       /* Fortunately, this can't overflow to 2^64 */
-      if ( (flags = round_to_int(st0_ptr)) )
+      if ( (flags = FPU_round_to_int(st0_ptr, st0_tag)) )
 	set_precision_flag(flags);
 
-      st0_ptr->exp = EXP_BIAS + 63;
-      normalize(st0_ptr);
+      setexponent16(st0_ptr, 63);
+      tag = FPU_normalize(st0_ptr);
+      setsign(st0_ptr, sign);
+      FPU_settag0(tag);
       return;
     }
-  else if ( (st0_tag == TW_Zero) || (st0_tag == TW_Infinity) )
+
+  if ( st0_tag == TAG_Zero )
+    return;
+
+  if ( st0_tag == TAG_Special )
+    st0_tag = FPU_Special(st0_ptr);
+
+  if ( st0_tag == TW_Denormal )
+    goto denormal_arg;
+  else if ( st0_tag == TW_Infinity )
     return;
   else
-    single_arg_error(st0_ptr);
+    single_arg_error(st0_ptr, st0_tag);
 }
 
 
-static void fsin(FPU_REG *st0_ptr)
+static int fsin(FPU_REG *st0_ptr, u_char tag)
 {
-  char st0_tag = st0_ptr->tag;
-  char arg_sign = st0_ptr->sign;
+  u_char arg_sign = getsign(st0_ptr);
 
-  if ( st0_tag == TW_Valid )
+  if ( tag == TAG_Valid )
     {
-      FPU_REG rv;
       int q;
 
-      if ( st0_ptr->exp > EXP_BIAS - 40 )
+      if ( exponent(st0_ptr) > -40 )
 	{
-	  st0_ptr->sign = SIGN_POS;
-	  if ( (q = trig_arg(st0_ptr, 0)) != -1 )
+	  if ( (q = trig_arg(st0_ptr, 0)) == -1 )
 	    {
+	      /* Operand is out of range */
+	      return 1;
+	    }
 
-	      poly_sine(st0_ptr, &rv);
+	  poly_sine(st0_ptr);
+	  
+	  if (q & 2)
+	    changesign(st0_ptr);
 
-	      if (q & 2)
-		rv.sign ^= SIGN_POS ^ SIGN_NEG;
-	      rv.sign ^= arg_sign;
-	      reg_move(&rv, st0_ptr);
+	  setsign(st0_ptr, getsign(st0_ptr) ^ arg_sign);
 
-	      /* We do not really know if up or down */
-	      set_precision_flag_up();
-	      return;
-	    }
-	  else
-	    {
-	      /* Operand is out of range */
-	      st0_ptr->sign = arg_sign;         /* restore st(0) */
-	      return;
-	    }
+	  /* We do not really know if up or down */
+	  set_precision_flag_up();
+	  return 0;
 	}
       else
 	{
 	  /* For a small arg, the result == the argument */
-	  /* Underflow may happen */
-
-	  if ( st0_ptr->exp <= EXP_UNDER )
-	    {
-#ifdef DENORM_OPERAND
-	      if ( denormal_operand() )
-		return;
-#endif DENORM_OPERAND
-	      /* A denormal result has been produced.
-		 Precision must have been lost, this is always
-		 an underflow. */
-	      arith_underflow(st0_ptr);
-	      return;
-	    }
-
 	  set_precision_flag_up();  /* Must be up. */
+	  return 0;
 	}
     }
-  else if ( st0_tag == TW_Zero )
+
+  if ( tag == TAG_Zero )
     {
       setcc(0);
-      return;
+      return 0;
     }
-  else if ( st0_tag == TW_Infinity )
+
+  if ( tag == TAG_Special )
+    tag = FPU_Special(st0_ptr);
+
+  if ( tag == TW_Denormal )
+    {
+      if ( denormal_operand() < 0 )
+	return 1;
+
+      /* For a small arg, the result == the argument */
+      /* Underflow may happen */
+      FPU_to_exp16(st0_ptr, st0_ptr);
+      
+      tag = FPU_round(st0_ptr, 1, 0, FULL_PRECISION, arg_sign);
+
+      FPU_settag0(tag);
+
+      return 0;
+    }
+  else if ( tag == TW_Infinity )
     {
       /* The 80486 treats infinity as an invalid operand */
-      arith_invalid(st0_ptr);
-      return;
+      arith_invalid(0);
+      return 1;
     }
   else
-    single_arg_error(st0_ptr);
+    {
+      single_arg_error(st0_ptr, tag);
+      return 1;
+    }
 }
 
 
-static int f_cos(FPU_REG *arg)
+static int f_cos(FPU_REG *st0_ptr, u_char tag)
 {
-  char arg_sign = arg->sign;
+  u_char st0_sign;
 
-  if ( arg->tag == TW_Valid )
+  st0_sign = getsign(st0_ptr);
+
+  if ( tag == TAG_Valid )
     {
-      FPU_REG rv;
       int q;
 
-      if ( arg->exp > EXP_BIAS - 40 )
+      if ( exponent(st0_ptr) > -40 )
 	{
-	  arg->sign = SIGN_POS;
-	  if ( (arg->exp < EXP_BIAS)
-	      || ((arg->exp == EXP_BIAS)
-		  && (significand(arg) <= 0xc90fdaa22168c234LL)) )
+	  if ( (exponent(st0_ptr) < 0)
+	      || ((exponent(st0_ptr) == 0)
+		  && (significand(st0_ptr) <= 0xc90fdaa22168c234LL)) )
 	    {
-	      poly_cos(arg, &rv);
-	      reg_move(&rv, arg);
+	      poly_cos(st0_ptr);
 
 	      /* We do not really know if up or down */
 	      set_precision_flag_down();
 	  
 	      return 0;
 	    }
-	  else if ( (q = trig_arg(arg, FCOS)) != -1 )
+	  else if ( (q = trig_arg(st0_ptr, FCOS)) != -1 )
 	    {
-	      poly_sine(arg, &rv);
+	      poly_sine(st0_ptr);
 
 	      if ((q+1) & 2)
-		rv.sign ^= SIGN_POS ^ SIGN_NEG;
-	      reg_move(&rv, arg);
+		changesign(st0_ptr);
 
 	      /* We do not really know if up or down */
 	      set_precision_flag_down();
@@ -630,19 +701,15 @@
 	  else
 	    {
 	      /* Operand is out of range */
-	      arg->sign = arg_sign;         /* restore st(0) */
 	      return 1;
 	    }
 	}
       else
 	{
-#ifdef DENORM_OPERAND
-	  if ( (arg->exp <= EXP_UNDER) && (denormal_operand()) )
-	    return 1;
-#endif DENORM_OPERAND
+	denormal_arg:
 
 	  setcc(0);
-	  reg_move(&CONST_1, arg);
+	  FPU_copy_to_reg0(&CONST_1, TAG_Valid);
 #ifdef PECULIAR_486
 	  set_precision_flag_down();  /* 80486 appears to do this. */
 #else
@@ -651,79 +718,99 @@
 	  return 0;
 	}
     }
-  else if ( arg->tag == TW_Zero )
+  else if ( tag == TAG_Zero )
     {
-      reg_move(&CONST_1, arg);
+      FPU_copy_to_reg0(&CONST_1, TAG_Valid);
       setcc(0);
       return 0;
     }
-  else if ( arg->tag == TW_Infinity )
+
+  if ( tag == TAG_Special )
+    tag = FPU_Special(st0_ptr);
+
+  if ( tag == TW_Denormal )
+    {
+      if ( denormal_operand() < 0 )
+	return 1;
+
+      goto denormal_arg;
+    }
+  else if ( tag == TW_Infinity )
     {
       /* The 80486 treats infinity as an invalid operand */
-      arith_invalid(arg);
+      arith_invalid(0);
       return 1;
     }
   else
     {
-      single_arg_error(arg);  /* requires arg == &st(0) */
+      single_arg_error(st0_ptr, tag);  /* requires st0_ptr == &st(0) */
       return 1;
     }
 }
 
 
-static void fcos(FPU_REG *st0_ptr)
+static void fcos(FPU_REG *st0_ptr, u_char st0_tag)
 {
-  f_cos(st0_ptr);
+  f_cos(st0_ptr, st0_tag);
 }
 
 
-static void fsincos(FPU_REG *st0_ptr)
+static void fsincos(FPU_REG *st0_ptr, u_char st0_tag)
 {
-  char st0_tag = st0_ptr->tag;
   FPU_REG *st_new_ptr;
   FPU_REG arg;
+  u_char tag;
 
   /* Stack underflow has higher priority */
-  if ( st0_tag == TW_Empty )
+  if ( st0_tag == TAG_Empty )
     {
-      stack_underflow();  /* Puts a QNaN in st(0) */
+      FPU_stack_underflow();  /* Puts a QNaN in st(0) */
       if ( control_word & CW_Invalid )
 	{
 	  st_new_ptr = &st(-1);
 	  push();
-	  stack_underflow();  /* Puts a QNaN in the new st(0) */
+	  FPU_stack_underflow();  /* Puts a QNaN in the new st(0) */
 	}
       return;
     }
 
   if ( STACK_OVERFLOW )
-    { stack_overflow(); return; }
+    { FPU_stack_overflow(); return; }
 
-  if ( st0_tag == TW_NaN )
+  if ( st0_tag == TAG_Special )
+    tag = FPU_Special(st0_ptr);
+  else
+    tag = st0_tag;
+
+  if ( tag == TW_NaN )
     {
-      single_arg_2_error(st0_ptr);
+      single_arg_2_error(st0_ptr, TW_NaN);
       return;
     }
-  else if ( st0_tag == TW_Infinity )
+  else if ( tag == TW_Infinity )
     {
       /* The 80486 treats infinity as an invalid operand */
-      if ( !arith_invalid(st0_ptr) )
+      if ( arith_invalid(0) >= 0 )
 	{
-	  /* unmasked response */
+	  /* Masked response */
 	  push();
-	  arith_invalid(st_new_ptr);
+	  arith_invalid(0);
 	}
       return;
     }
 
-  reg_move(st0_ptr,&arg);
-  if ( !f_cos(&arg) )
+  reg_copy(st0_ptr, &arg);
+  if ( !fsin(st0_ptr, st0_tag) )
     {
-      fsin(st0_ptr);
       push();
-      reg_move(&arg,st_new_ptr);
+      FPU_copy_to_reg0(&arg, st0_tag);
+      f_cos(&st(0), st0_tag);
+    }
+  else
+    {
+      /* An error, so restore st(0) */
+      FPU_copy_to_reg0(&arg, st0_tag);
     }
-
 }
 
 
@@ -760,79 +847,86 @@
 /* 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(FPU_REG *st0_ptr, int round)
+static void do_fprem(FPU_REG *st0_ptr, u_char st0_tag, int round)
 {
   FPU_REG *st1_ptr = &st(1);
-  char st1_tag = st1_ptr->tag;
-  char st0_tag = st0_ptr->tag;
-  char sign = st0_ptr->sign;
+  u_char st1_tag = FPU_gettagi(1);
 
-  if ( !((st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid)) )
+  if ( !((st0_tag ^ TAG_Valid) | (st1_tag ^ TAG_Valid)) )
     {
-      FPU_REG tmp;
-      int old_cw = control_word;
-      int expdif = st0_ptr->exp - st1_ptr->exp;
+      FPU_REG tmp, st0, st1;
+      u_char st0_sign, st1_sign;
+      u_char tmptag;
+      int tag;
+      int old_cw;
+      int expdif;
       long long q;
       unsigned short saved_status;
-      int cc = 0;
+      int cc;
+
+    fprem_valid:
+      /* Convert registers for internal use. */
+      st0_sign = FPU_to_exp16(st0_ptr, &st0);
+      st1_sign = FPU_to_exp16(st1_ptr, &st1);
+      expdif = exponent16(&st0) - exponent16(&st1);
+
+      old_cw = control_word;
+      cc = 0;
 
-#ifdef DENORM_OPERAND
-      if ( ((st0_ptr->exp <= EXP_UNDER) ||
-	    (st1_ptr->exp <= EXP_UNDER)) && (denormal_operand()) )
-	return;
-#endif DENORM_OPERAND
-      
       /* We want the status following the denorm tests, but don't want
 	 the status changed by the arithmetic operations. */
       saved_status = partial_status;
       control_word &= ~CW_RC;
       control_word |= RC_CHOP;
 
-      if (expdif < 64)
+      if ( expdif < 64 )
 	{
 	  /* This should be the most common case */
 
 	  if ( expdif > -2 )
 	    {
-	      reg_div(st0_ptr, st1_ptr, &tmp, PR_64_BITS | RC_CHOP | 0x3f);
+	      u_char sign = st0_sign ^ st1_sign;
+	      tag = FPU_u_div(&st0, &st1, &tmp,
+			      PR_64_BITS | RC_CHOP | 0x3f,
+			      sign);
+	      setsign(&tmp, sign);
 
-	      if ( tmp.exp >= EXP_BIAS )
+	      if ( exponent(&tmp) >= 0 )
 		{
-		  round_to_int(&tmp);  /* Fortunately, this can't overflow
-					  to 2^64 */
+		  FPU_round_to_int(&tmp, tag);  /* Fortunately, this can't
+						   overflow to 2^64 */
 		  q = significand(&tmp);
 
-		  rem_kernel(significand(st0_ptr),
+		  rem_kernel(significand(&st0),
 			     &significand(&tmp),
-			     significand(st1_ptr),
+			     significand(&st1),
 			     q, expdif);
 
-		  tmp.exp = st1_ptr->exp;
+		  setexponent16(&tmp, exponent16(&st1));
 		}
 	      else
 		{
-		  reg_move(st0_ptr, &tmp);
+		  reg_copy(&st0, &tmp);
 		  q = 0;
 		}
-	      tmp.sign = sign;
 
 	      if ( (round == RC_RND) && (tmp.sigh & 0xc0000000) )
 		{
 		  /* We may need to subtract st(1) once more,
 		     to get a result <= 1/2 of st(1). */
 		  unsigned long long x;
-		  expdif = st1_ptr->exp - tmp.exp;
+		  expdif = exponent16(&st1) - exponent16(&tmp);
 		  if ( expdif <= 1 )
 		    {
 		      if ( expdif == 0 )
-			x = significand(st1_ptr) - significand(&tmp);
+			x = significand(&st1) - significand(&tmp);
 		      else /* expdif is 1 */
-			x = (significand(st1_ptr) << 1) - significand(&tmp);
+			x = (significand(&st1) << 1) - significand(&tmp);
 		      if ( (x < significand(&tmp)) ||
 			  /* or equi-distant (from 0 & st(1)) and q is odd */
 			  ((x == significand(&tmp)) && (q & 1) ) )
 			{
-			  tmp.sign ^= (SIGN_POS^SIGN_NEG);
+			  st0_sign = ! st0_sign;
 			  significand(&tmp) = x;
 			  q++;
 			}
@@ -855,28 +949,35 @@
 	  /* There is a large exponent difference ( >= 64 ) */
 	  /* To make much sense, the code in this section should
 	     be done at high precision. */
-	  int exp_1;
+	  int exp_1, N;
+	  u_char sign;
 
 	  /* prevent overflow here */
 	  /* N is 'a number between 32 and 63' (p26-113) */
-	  reg_move(st0_ptr, &tmp);
-	  tmp.exp = EXP_BIAS + 56;
-	  exp_1 = st1_ptr->exp;      st1_ptr->exp = EXP_BIAS;
-	  expdif -= 56;
-
-	  reg_div(&tmp, st1_ptr, &tmp, PR_64_BITS | RC_CHOP | 0x3f);
-	  st1_ptr->exp = exp_1;
+	  reg_copy(&st0, &tmp);
+	  tmptag = st0_tag;
+	  N = (expdif & 0x0000001f) + 32;  /* This choice gives results
+					      identical to an AMD 486 */
+	  setexponent16(&tmp, N);
+	  exp_1 = exponent16(&st1);
+	  setexponent16(&st1, 0);
+	  expdif -= N;
+
+	  sign = getsign(&tmp) ^ st1_sign;
+	  tag = FPU_u_div(&tmp, &st1, &tmp, PR_64_BITS | RC_CHOP | 0x3f,
+			  sign);
+	  setsign(&tmp, sign);
 
-	  round_to_int(&tmp);  /* Fortunately, this can't overflow to 2^64 */
+	  FPU_round_to_int(&tmp, tag);  /* Fortunately, this can't
+					   overflow to 2^64 */
 
-	  rem_kernel(significand(st0_ptr),
+	  rem_kernel(significand(&st0),
 		     &significand(&tmp),
-		     significand(st1_ptr),
+		     significand(&st1),
 		     significand(&tmp),
-		     tmp.exp - EXP_BIAS
+		     exponent(&tmp)
 		     ); 
-	  tmp.exp = exp_1 + expdif;
-	  tmp.sign = sign;
+	  setexponent16(&tmp, exp_1 + expdif);
 
 	  /* It is possible for the operation to be complete here.
 	     What does the IEEE standard say? The Intel 80486 manual
@@ -888,8 +989,8 @@
 	      /* The result is zero */
 	      control_word = old_cw;
 	      partial_status = saved_status;
-	      reg_move(&CONST_Z, st0_ptr);
-	      st0_ptr->sign = sign;
+	      FPU_copy_to_reg0(&CONST_Z, TAG_Zero);
+	      setsign(&st0, st0_sign);
 #ifdef PECULIAR_486
 	      setcc(SW_C2);
 #else
@@ -902,52 +1003,82 @@
 
       control_word = old_cw;
       partial_status = saved_status;
-      normalize_nuo(&tmp);
-      reg_move(&tmp, st0_ptr);
-      setcc(cc);
+      tag = FPU_normalize_nuo(&tmp);
+      reg_copy(&tmp, st0_ptr);
 
       /* The only condition to be looked for is underflow,
 	 and it can occur here only if underflow is unmasked. */
-      if ( (st0_ptr->exp <= EXP_UNDER) && (st0_ptr->tag != TW_Zero)
+      if ( (exponent16(&tmp) <= EXP_UNDER) && (tag != TAG_Zero)
 	  && !(control_word & CW_Underflow) )
-	arith_underflow(st0_ptr);
+	{
+	  setcc(cc);
+	  tag = arith_underflow(st0_ptr);
+	  setsign(st0_ptr, st0_sign);
+	  FPU_settag0(tag);
+	  return;
+	}
+      else if ( (exponent16(&tmp) > EXP_UNDER) || (tag == TAG_Zero) )
+	{
+	  stdexp(st0_ptr);
+	  setsign(st0_ptr, st0_sign);
+	}
+      else
+	{
+	  tag = FPU_round(st0_ptr, 0, 0, FULL_PRECISION, st0_sign);
+	}
+      FPU_settag0(tag);
+      setcc(cc);
 
       return;
     }
-  else if ( (st0_tag == TW_Empty) | (st1_tag == TW_Empty) )
+
+  if ( st0_tag == TAG_Special )
+    st0_tag = FPU_Special(st0_ptr);
+  if ( st1_tag == TAG_Special )
+    st1_tag = FPU_Special(st1_ptr);
+
+  if ( ((st0_tag == TAG_Valid) && (st1_tag == TW_Denormal))
+	    || ((st0_tag == TW_Denormal) && (st1_tag == TAG_Valid))
+	    || ((st0_tag == TW_Denormal) && (st1_tag == TW_Denormal)) )
     {
-      stack_underflow();
+      if ( denormal_operand() < 0 )
+	return;
+      goto fprem_valid;
+    }
+  else if ( (st0_tag == TAG_Empty) | (st1_tag == TAG_Empty) )
+    {
+      FPU_stack_underflow();
       return;
     }
-  else if ( st0_tag == TW_Zero )
+  else if ( st0_tag == TAG_Zero )
     {
-      if ( st1_tag == TW_Valid )
+      if ( st1_tag == TAG_Valid )
 	{
-#ifdef DENORM_OPERAND
-	  if ( (st1_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
+	  setcc(0); return;
+	}
+      else if ( st1_tag == TW_Denormal )
+	{
+	  if ( denormal_operand() < 0 )
 	    return;
-#endif DENORM_OPERAND
-
 	  setcc(0); return;
 	}
-      else if ( st1_tag == TW_Zero )
-	{ arith_invalid(st0_ptr); return; } /* fprem(?,0) always invalid */
+      else if ( st1_tag == TAG_Zero )
+	{ arith_invalid(0); return; } /* fprem(?,0) always invalid */
       else if ( st1_tag == TW_Infinity )
 	{ setcc(0); return; }
     }
-  else if ( st0_tag == TW_Valid )
+  else if ( (st0_tag == TAG_Valid) || (st0_tag == TW_Denormal) )
     {
-      if ( st1_tag == TW_Zero )
+      if ( st1_tag == TAG_Zero )
 	{
-	  arith_invalid(st0_ptr); /* fprem(Valid,Zero) is invalid */
+	  arith_invalid(0); /* fprem(Valid,Zero) is invalid */
 	  return;
 	}
       else if ( st1_tag != TW_NaN )
 	{
-#ifdef DENORM_OPERAND
-	  if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
+	  if ( ((st0_tag == TW_Denormal) || (st1_tag == TW_Denormal))
+	       && (denormal_operand() < 0) )
 	    return;
-#endif DENORM_OPERAND
 
 	  if ( st1_tag == TW_Infinity )
 	    {
@@ -960,729 +1091,710 @@
     {
       if ( st1_tag != TW_NaN )
 	{
-	  arith_invalid(st0_ptr); /* fprem(Infinity,?) is invalid */
+	  arith_invalid(0); /* fprem(Infinity,?) is invalid */
 	  return;
 	}
     }
 
-  /* One of the registers must contain a NaN is we got here. */
+  /* One of the registers must contain a NaN if we got here. */
 
 #ifdef PARANOID
   if ( (st0_tag != TW_NaN) && (st1_tag != TW_NaN) )
       EXCEPTION(EX_INTERNAL | 0x118);
 #endif PARANOID
 
-  real_2op_NaN(st1_ptr, st0_ptr, st0_ptr);
+  real_2op_NaN(st1_ptr, st1_tag, 0, st1_ptr);
 
 }
 
 
 /* ST(1) <- ST(1) * log ST;  pop ST */
-static void fyl2x(FPU_REG *st0_ptr)
+static void fyl2x(FPU_REG *st0_ptr, u_char st0_tag)
 {
-  char st0_tag = st0_ptr->tag;
   FPU_REG *st1_ptr = &st(1), exponent;
-  char st1_tag = st1_ptr->tag;
-  int e;
+  u_char st1_tag = FPU_gettagi(1);
+  u_char sign;
+  int e, tag;
 
   clear_C1();
-  if ( !((st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid)) )
+
+  if ( (st0_tag == TAG_Valid) && (st1_tag == TAG_Valid) )
     {
-      if ( st0_ptr->sign == SIGN_POS )
+    both_valid:
+      /* Both regs are Valid or Denormal */
+      if ( signpositive(st0_ptr) )
 	{
-#ifdef DENORM_OPERAND
-	  if ( ((st0_ptr->exp <= EXP_UNDER) ||
-		(st1_ptr->exp <= EXP_UNDER)) && (denormal_operand()) )
-	    return;
-#endif DENORM_OPERAND
+	  if ( st0_tag == TW_Denormal )
+	    FPU_to_exp16(st0_ptr, st0_ptr);
+	  else
+	    /* Convert st(0) for internal use. */
+	    setexponent16(st0_ptr, exponent(st0_ptr));
 
 	  if ( (st0_ptr->sigh == 0x80000000) && (st0_ptr->sigl == 0) )
 	    {
 	      /* Special case. The result can be precise. */
-	      e = st0_ptr->exp - EXP_BIAS;
-	      if ( e > 0 )
+	      u_char esign;
+	      e = exponent16(st0_ptr);
+	      if ( e >= 0 )
 		{
 		  exponent.sigh = e;
-		  exponent.sign = SIGN_POS;
+		  esign = SIGN_POS;
 		}
 	      else
 		{
 		  exponent.sigh = -e;
-		  exponent.sign = SIGN_NEG;
+		  esign = SIGN_NEG;
 		}
 	      exponent.sigl = 0;
-	      exponent.exp = EXP_BIAS + 31;
-	      exponent.tag = TW_Valid;
-	      normalize_nuo(&exponent);
-	      reg_mul(&exponent, st1_ptr, st1_ptr, FULL_PRECISION);
+	      setexponent16(&exponent, 31);
+	      tag = FPU_normalize_nuo(&exponent);
+	      stdexp(&exponent);
+	      setsign(&exponent, esign);
+	      tag = FPU_mul(&exponent, tag, 1, FULL_PRECISION);
+	      if ( tag >= 0 )
+		FPU_settagi(1, tag);
 	    }
 	  else
 	    {
 	      /* The usual case */
-	      poly_l2(st0_ptr, st1_ptr, st1_ptr);
-	      if ( st1_ptr->exp <= EXP_UNDER )
-		{
-		  /* A denormal result has been produced.
-		     Precision must have been lost, this is always
-		     an underflow. */
-		  arith_underflow(st1_ptr);
-		}
+	      sign = getsign(st1_ptr);
+	      if ( st1_tag == TW_Denormal )
+		FPU_to_exp16(st1_ptr, st1_ptr);
 	      else
-		set_precision_flag_up();  /* 80486 appears to always do this */
+		/* Convert st(1) for internal use. */
+		setexponent16(st1_ptr, exponent(st1_ptr));
+	      poly_l2(st0_ptr, st1_ptr, sign);
 	    }
-	  pop();
-	  return;
 	}
       else
 	{
 	  /* negative */
-	  if ( !arith_invalid(st1_ptr) )
-	    pop();
-	  return;
+	  if ( arith_invalid(1) < 0 )
+	    return;
 	}
-    }
-  else if ( (st0_tag == TW_Empty) || (st1_tag == TW_Empty) )
-    {
-      stack_underflow_pop(1);
+
+      FPU_pop();
+
       return;
     }
-  else if ( (st0_tag == TW_NaN) || (st1_tag == TW_NaN) )
+
+  if ( st0_tag == TAG_Special )
+    st0_tag = FPU_Special(st0_ptr);
+  if ( st1_tag == TAG_Special )
+    st1_tag = FPU_Special(st1_ptr);
+
+  if ( (st0_tag == TAG_Empty) || (st1_tag == TAG_Empty) )
     {
-      if ( !real_2op_NaN(st0_ptr, st1_ptr, st1_ptr) )
-	pop();
+      FPU_stack_underflow_pop(1);
       return;
     }
-  else if ( (st0_tag <= TW_Zero) && (st1_tag <= TW_Zero) )
+  else if ( (st0_tag <= TW_Denormal) && (st1_tag <= TW_Denormal) )
     {
-      /* one of the args is zero, the other valid, or both zero */
-      if ( st0_tag == TW_Zero )
+      if ( st0_tag == TAG_Zero )
 	{
-	  if ( st1_tag == TW_Zero )
+	  if ( st1_tag == TAG_Zero )
 	    {
 	      /* Both args zero is invalid */
-	      if ( !arith_invalid(st1_ptr) )
-		pop();
-	    }
-#ifdef PECULIAR_486
-	  /* 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 ( st0_ptr->tag == TW_Infinity )
-	    {
-	      reg_move(&CONST_INF, st1_ptr);
-	      pop();
+	      if ( arith_invalid(1) < 0 )
+		return;
 	    }
-#endif PECULIAR_486
 	  else
 	    {
-	      if ( !divide_by_zero(st1_ptr->sign^SIGN_NEG^SIGN_POS, st1_ptr) )
-		pop();
+	      u_char sign;
+	      sign = getsign(st1_ptr)^SIGN_NEG;
+	      if ( FPU_divide_by_zero(1, sign) < 0 )
+		return;
+
+	      setsign(st1_ptr, sign);
 	    }
-	  return;
 	}
-      else
+      else if ( st1_tag == TAG_Zero )
 	{
 	  /* st(1) contains zero, st(0) valid <> 0 */
 	  /* Zero is the valid answer */
-	  char sign = st1_ptr->sign;
-
-	  if ( st0_ptr->sign == SIGN_NEG )
+	  sign = getsign(st1_ptr);
+	  
+	  if ( signnegative(st0_ptr) )
 	    {
 	      /* log(negative) */
-	      if ( !arith_invalid(st1_ptr) )
-		pop();
-	      return;
+	      if ( arith_invalid(1) < 0 )
+		return;
 	    }
-
-#ifdef DENORM_OPERAND
-	  if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
+	  else if ( (st0_tag == TW_Denormal) && (denormal_operand() < 0) )
 	    return;
-#endif DENORM_OPERAND
+	  else
+	    {
+	      if ( exponent(st0_ptr) < 0 )
+		sign ^= SIGN_NEG;
 
-	  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;
+	      FPU_copy_to_reg1(&CONST_Z, TAG_Zero);
+	      setsign(st1_ptr, sign);
+	    }
+	}
+      else
+	{
+	  /* One or both operands are denormals. */
+	  if ( denormal_operand() < 0 )
+	    return;
+	  goto both_valid;
 	}
     }
+  else if ( (st0_tag == TW_NaN) || (st1_tag == TW_NaN) )
+    {
+      if ( real_2op_NaN(st0_ptr, st0_tag, 1, st0_ptr) < 0 )
+	return;
+    }
   /* One or both arg must be an infinity */
   else if ( st0_tag == TW_Infinity )
     {
-      if ( (st0_ptr->sign == SIGN_NEG) || (st1_tag == TW_Zero) )
+      if ( (signnegative(st0_ptr)) || (st1_tag == TAG_Zero) )
 	{
 	  /* log(-infinity) or 0*log(infinity) */
-	  if ( !arith_invalid(st1_ptr) )
-	    pop();
-	  return;
+	  if ( arith_invalid(1) < 0 )
+	    return;
 	}
       else
 	{
-	  char sign = st1_ptr->sign;
+	  u_char sign = getsign(st1_ptr);
 
-#ifdef DENORM_OPERAND
-	  if ( (st1_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
+	  if ( (st1_tag == TW_Denormal) && (denormal_operand() < 0) )
 	    return;
-#endif DENORM_OPERAND
 
-	  pop(); st0_ptr = &st(0);
-	  reg_move(&CONST_INF, st0_ptr);
-	  st0_ptr->sign = sign;
-	  return;
+	  FPU_copy_to_reg1(&CONST_INF, TAG_Special);
+	  setsign(st1_ptr, sign);
 	}
     }
   /* st(1) must be infinity here */
-  else if ( (st0_tag == TW_Valid) && (st0_ptr->sign == SIGN_POS) )
+  else if ( ((st0_tag == TAG_Valid) || (st0_tag == TW_Denormal))
+	    && ( signpositive(st0_ptr) ) )
     {
-      if ( st0_ptr->exp >= EXP_BIAS )
+      if ( exponent(st0_ptr) >= 0 )
 	{
-	  if ( (st0_ptr->exp == EXP_BIAS) &&
+	  if ( (exponent(st0_ptr) == 0) &&
 	      (st0_ptr->sigh == 0x80000000) &&
 	      (st0_ptr->sigl == 0) )
 	    {
 	      /* st(0) holds 1.0 */
 	      /* infinity*log(1) */
-	      if ( !arith_invalid(st1_ptr) )
-		pop();
-	      return;
+	      if ( arith_invalid(1) < 0 )
+		return;
 	    }
-	  /* st(0) is positive and > 1.0 */
-	  pop();
+	  /* else st(0) is positive and > 1.0 */
 	}
       else
 	{
 	  /* st(0) is positive and < 1.0 */
 
-#ifdef DENORM_OPERAND
-	  if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
+	  if ( (st0_tag == TW_Denormal) && (denormal_operand() < 0) )
 	    return;
-#endif DENORM_OPERAND
 
-	  st1_ptr->sign ^= SIGN_NEG;
-	  pop();
+	  changesign(st1_ptr);
 	}
-      return;
     }
   else
     {
       /* st(0) must be zero or negative */
-      if ( st0_ptr->tag == TW_Zero )
+      if ( st0_tag == TAG_Zero )
 	{
 	  /* This should be invalid, but a real 80486 is happy with it. */
+
 #ifndef PECULIAR_486
-	  if ( !divide_by_zero(st1_ptr->sign, st1_ptr) )
+	  sign = getsign(st1_ptr);
+	  if ( FPU_divide_by_zero(1, sign) < 0 )
+	    return;
 #endif PECULIAR_486
-	    {
-	      st1_ptr->sign ^= SIGN_NEG^SIGN_POS;
-	      pop();
-	    }
-	}
-      else
-	{
-	  /* log(negative) */
-	  if ( !arith_invalid(st1_ptr) )
-	    pop();
+
+	  changesign(st1_ptr);
 	}
-      return;
+      else if ( arith_invalid(1) < 0 )	  /* log(negative) */
+	return;
     }
+
+  FPU_pop();
 }
 
 
-static void fpatan(FPU_REG *st0_ptr)
+static void fpatan(FPU_REG *st0_ptr, u_char st0_tag)
 {
-  char st0_tag = st0_ptr->tag;
   FPU_REG *st1_ptr = &st(1);
-  char st1_tag = st1_ptr->tag;
+  u_char st1_tag = FPU_gettagi(1);
+  int tag;
 
   clear_C1();
-  if ( !((st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid)) )
+  if ( !((st0_tag ^ TAG_Valid) | (st1_tag ^ TAG_Valid)) )
     {
-#ifdef DENORM_OPERAND
-      if ( ((st0_ptr->exp <= EXP_UNDER) ||
-	    (st1_ptr->exp <= EXP_UNDER)) && (denormal_operand()) )
-	return;
-#endif DENORM_OPERAND
+    valid_atan:
 
-      poly_atan(st0_ptr, st1_ptr, st1_ptr);
+      poly_atan(st0_ptr, st0_tag, st1_ptr, st1_tag);
 
-      if ( st1_ptr->exp <= EXP_UNDER )
-	{
-	  /* A denormal result has been produced.
-	     Precision must have been lost.
-	     This is by definition an underflow. */
-	  arith_underflow(st1_ptr);
-	  pop();
-	  return;
-	}
+      FPU_pop();
+
+      return;
     }
-  else if ( (st0_tag == TW_Empty) || (st1_tag == TW_Empty) )
+
+  if ( st0_tag == TAG_Special )
+    st0_tag = FPU_Special(st0_ptr);
+  if ( st1_tag == TAG_Special )
+    st1_tag = FPU_Special(st1_ptr);
+
+  if ( ((st0_tag == TAG_Valid) && (st1_tag == TW_Denormal))
+	    || ((st0_tag == TW_Denormal) && (st1_tag == TAG_Valid))
+	    || ((st0_tag == TW_Denormal) && (st1_tag == TW_Denormal)) )
     {
-      stack_underflow_pop(1);
+      if ( denormal_operand() < 0 )
+	return;
+
+      goto valid_atan;
+    }
+  else if ( (st0_tag == TAG_Empty) || (st1_tag == TAG_Empty) )
+    {
+      FPU_stack_underflow_pop(1);
       return;
     }
   else if ( (st0_tag == TW_NaN) || (st1_tag == TW_NaN) )
     {
-      if ( !real_2op_NaN(st0_ptr, st1_ptr, st1_ptr) )
-	  pop();
+      if ( real_2op_NaN(st0_ptr, st0_tag, 1, st0_ptr) >= 0 )
+	  FPU_pop();
       return;
     }
   else if ( (st0_tag == TW_Infinity) || (st1_tag == TW_Infinity) )
     {
-      char sign = st1_ptr->sign;
+      u_char sign = getsign(st1_ptr);
       if ( st0_tag == TW_Infinity )
 	{
 	  if ( st1_tag == TW_Infinity )
 	    {
-	      if ( st0_ptr->sign == SIGN_POS )
-		{ reg_move(&CONST_PI4, st1_ptr); }
+	      if ( signpositive(st0_ptr) )
+		{
+		  FPU_copy_to_reg1(&CONST_PI4, TAG_Valid);
+		}
 	      else
-		reg_add(&CONST_PI4, &CONST_PI2, st1_ptr, FULL_PRECISION);
+		{
+		  setpositive(st1_ptr);
+		  tag = FPU_u_add(&CONST_PI4, &CONST_PI2, st1_ptr,
+				  FULL_PRECISION, SIGN_POS,
+				  exponent(&CONST_PI4), exponent(&CONST_PI2));
+		  if ( tag >= 0 )
+		    FPU_settagi(1, tag);
+		}
 	    }
 	  else
 	    {
-#ifdef DENORM_OPERAND
-	      if ( st1_tag != TW_Zero )
-		{
-		  if ( (st1_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
-		    return;
-		}
-#endif DENORM_OPERAND
+	      if ( (st1_tag == TW_Denormal) && (denormal_operand() < 0) )
+		return;
 
-	      if ( st0_ptr->sign == SIGN_POS )
+	      if ( signpositive(st0_ptr) )
 		{
-		  reg_move(&CONST_Z, st1_ptr);
-		  st1_ptr->sign = sign;   /* An 80486 preserves the sign */
-		  pop();
+		  FPU_copy_to_reg1(&CONST_Z, TAG_Zero);
+		  setsign(st1_ptr, sign);   /* An 80486 preserves the sign */
+		  FPU_pop();
 		  return;
 		}
 	      else
-		reg_move(&CONST_PI, st1_ptr);
+		{
+		  FPU_copy_to_reg1(&CONST_PI, TAG_Valid);
+		}
 	    }
 	}
       else
 	{
 	  /* st(1) is infinity, st(0) not infinity */
-#ifdef DENORM_OPERAND
-	  if ( st0_tag != TW_Zero )
-	    {
-	      if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
-		return;
-	    }
-#endif DENORM_OPERAND
+	  if ( (st0_tag == TW_Denormal) && (denormal_operand() < 0) )
+	    return;
 
-	  reg_move(&CONST_PI2, st1_ptr);
+	  FPU_copy_to_reg1(&CONST_PI2, TAG_Valid);
 	}
-      st1_ptr->sign = sign;
+      setsign(st1_ptr, sign);
     }
-  else if ( st1_tag == TW_Zero )
+  else if ( st1_tag == TAG_Zero )
     {
       /* st(0) must be valid or zero */
-      char sign = st1_ptr->sign;
+      u_char sign = getsign(st1_ptr);
 
-#ifdef DENORM_OPERAND
-      if ( st0_tag != TW_Zero )
+      if ( (st0_tag == TW_Denormal) && (denormal_operand() < 0) )
+	return;
+
+      if ( signpositive(st0_ptr) )
 	{
-	  if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
-	    return;
+	  /* An 80486 preserves the sign */
+	  FPU_pop();
+	  return;
 	}
-#endif DENORM_OPERAND
 
-      if ( st0_ptr->sign == SIGN_POS )
-	{ /* An 80486 preserves the sign */ pop(); return; }
-      else
-	reg_move(&CONST_PI, st1_ptr);
-      st1_ptr->sign = sign;
+      FPU_copy_to_reg1(&CONST_PI, TAG_Valid);
+      setsign(st1_ptr, sign);
     }
-  else if ( st0_tag == TW_Zero )
+  else if ( st0_tag == TAG_Zero )
     {
-      /* st(1) must be TW_Valid here */
-      char sign = st1_ptr->sign;
+      /* st(1) must be TAG_Valid here */
+      u_char sign = getsign(st1_ptr);
 
-#ifdef DENORM_OPERAND
-      if ( (st1_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
+      if ( (st1_tag == TW_Denormal) && (denormal_operand() < 0) )
 	return;
-#endif DENORM_OPERAND
 
-      reg_move(&CONST_PI2, st1_ptr);
-      st1_ptr->sign = sign;
+      FPU_copy_to_reg1(&CONST_PI2, TAG_Valid);
+      setsign(st1_ptr, sign);
     }
 #ifdef PARANOID
   else
     EXCEPTION(EX_INTERNAL | 0x125);
 #endif PARANOID
 
-  pop();
+  FPU_pop();
   set_precision_flag_up();  /* We do not really know if up or down */
 }
 
 
-static void fprem(FPU_REG *st0_ptr)
+static void fprem(FPU_REG *st0_ptr, u_char st0_tag)
 {
-  do_fprem(st0_ptr, RC_CHOP);
+  do_fprem(st0_ptr, st0_tag, RC_CHOP);
 }
 
 
-static void fprem1(FPU_REG *st0_ptr)
+static void fprem1(FPU_REG *st0_ptr, u_char st0_tag)
 {
-  do_fprem(st0_ptr, RC_RND);
+  do_fprem(st0_ptr, st0_tag, RC_RND);
 }
 
 
-static void fyl2xp1(FPU_REG *st0_ptr)
+static void fyl2xp1(FPU_REG *st0_ptr, u_char st0_tag)
 {
-  char st0_tag = st0_ptr->tag, sign;
-  FPU_REG *st1_ptr = &st(1);
-  char st1_tag = st1_ptr->tag;
+  u_char sign, sign1;
+  FPU_REG *st1_ptr = &st(1), a, b;
+  u_char st1_tag = FPU_gettagi(1);
 
   clear_C1();
-  if ( !((st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid)) )
+  if ( !((st0_tag ^ TAG_Valid) | (st1_tag ^ TAG_Valid)) )
     {
-#ifdef DENORM_OPERAND
-      if ( ((st0_ptr->exp <= EXP_UNDER) ||
-	    (st1_ptr->exp <= EXP_UNDER)) && denormal_operand() )
+    valid_yl2xp1:
+
+      sign = getsign(st0_ptr);
+      sign1 = getsign(st1_ptr);
+
+      FPU_to_exp16(st0_ptr, &a);
+      FPU_to_exp16(st1_ptr, &b);
+
+      if ( poly_l2p1(sign, sign1, &a, &b, st1_ptr) )
 	return;
-#endif DENORM_OPERAND
 
-      if ( poly_l2p1(st0_ptr, st1_ptr, st1_ptr) )
-	{
-#ifdef PECULIAR_486   /* Stupid 80486 doesn't worry about log(negative). */
-	  st1_ptr->sign ^= SIGN_POS^SIGN_NEG;
-#else
-	  if ( arith_invalid(st1_ptr) )  /* poly_l2p1() returned invalid */
-	    return;
-#endif PECULIAR_486
-	}
-      if ( st1_ptr->exp <= EXP_UNDER )
-	{
-	  /* A denormal result has been produced.
-	     Precision must have been lost, this is always
-	     an underflow. */
-	  sign = st1_ptr->sign;
-	  arith_underflow(st1_ptr);
-	  st1_ptr->sign = sign;
-	}
-      else
-	set_precision_flag_up();   /* 80486 appears to always do this */
-      pop();
+      FPU_pop();
       return;
     }
-  else if ( (st0_tag == TW_Empty) | (st1_tag == TW_Empty) )
+
+  if ( st0_tag == TAG_Special )
+    st0_tag = FPU_Special(st0_ptr);
+  if ( st1_tag == TAG_Special )
+    st1_tag = FPU_Special(st1_ptr);
+
+  if ( ((st0_tag == TAG_Valid) && (st1_tag == TW_Denormal))
+	    || ((st0_tag == TW_Denormal) && (st1_tag == TAG_Valid))
+	    || ((st0_tag == TW_Denormal) && (st1_tag == TW_Denormal)) )
+    {
+      if ( denormal_operand() < 0 )
+	return;
+
+      goto valid_yl2xp1;
+    }
+  else if ( (st0_tag == TAG_Empty) | (st1_tag == TAG_Empty) )
     {
-      stack_underflow_pop(1);
+      FPU_stack_underflow_pop(1);
       return;
     }
-  else if ( st0_tag == TW_Zero )
+  else if ( st0_tag == TAG_Zero )
     {
-      if ( st1_tag <= TW_Zero )
+      switch ( st1_tag )
 	{
-#ifdef DENORM_OPERAND
-	  if ( (st1_tag == TW_Valid) && (st1_ptr->exp <= EXP_UNDER) &&
-	      (denormal_operand()) )
+	case TW_Denormal:
+	  if ( denormal_operand() < 0 )
 	    return;
-#endif DENORM_OPERAND
-	  
-	  st0_ptr->sign ^= st1_ptr->sign;
-	  reg_move(st0_ptr, st1_ptr);
-	}
-      else if ( st1_tag == TW_Infinity )
-	{
+
+	case TAG_Zero:
+	case TAG_Valid:
+	  setsign(st0_ptr, getsign(st0_ptr) ^ getsign(st1_ptr));
+	  FPU_copy_to_reg1(st0_ptr, st0_tag);
+	  break;
+
+	case TW_Infinity:
 	  /* Infinity*log(1) */
-	  if ( !arith_invalid(st1_ptr) )
-	    pop();
-	  return;
-	}
-      else if ( st1_tag == TW_NaN )
-	{
-	  if ( !real_2op_NaN(st0_ptr, st1_ptr, st1_ptr) )
-	    pop();
-	  return;
-	}
+	  if ( arith_invalid(1) < 0 )
+	    return;
+	  break;
+
+	case TW_NaN:
+	  if ( real_2op_NaN(st0_ptr, st0_tag, 1, st0_ptr) < 0 )
+	    return;
+	  break;
+
+	default:
 #ifdef PARANOID
-      else
-	{
 	  EXCEPTION(EX_INTERNAL | 0x116);
 	  return;
-	}
 #endif PARANOID
-      pop(); return;
+	}
     }
-  else if ( st0_tag == TW_Valid )
+  else if ( (st0_tag == TAG_Valid) || (st0_tag == TW_Denormal) )
     {
-      if ( st1_tag == TW_Zero )
+      switch ( st1_tag )
 	{
-	  if ( st0_ptr->sign == SIGN_NEG )
+	case TAG_Zero:
+	  if ( signnegative(st0_ptr) )
 	    {
-	      if ( st0_ptr->exp >= EXP_BIAS )
+	      if ( exponent(st0_ptr) >= 0 )
 		{
 		  /* st(0) holds <= -1.0 */
 #ifdef PECULIAR_486   /* Stupid 80486 doesn't worry about log(negative). */
-		  st1_ptr->sign ^= SIGN_POS^SIGN_NEG;
+		  changesign(st1_ptr);
 #else
-		  if ( arith_invalid(st1_ptr) ) return;
+		  if ( arith_invalid(1) < 0 )
+		    return;
 #endif PECULIAR_486
-		  pop(); return;
 		}
-#ifdef DENORM_OPERAND
-	      if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
+	      else if ( (st0_tag == TW_Denormal) && (denormal_operand() < 0) )
 		return;
-#endif DENORM_OPERAND
-	      st1_ptr->sign ^= SIGN_POS^SIGN_NEG;
-	      pop(); return;
+	      else
+		changesign(st1_ptr);
 	    }
-#ifdef DENORM_OPERAND
-	  if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
+	  else if ( (st0_tag == TW_Denormal) && (denormal_operand() < 0) )
 	    return;
-#endif DENORM_OPERAND
-	  pop(); return;
-	}
-      if ( st1_tag == TW_Infinity )
-	{
-	  if ( st0_ptr->sign == SIGN_NEG )
+	  break;
+
+	case TW_Infinity:
+	  if ( signnegative(st0_ptr) )
 	    {
-	      if ( (st0_ptr->exp >= EXP_BIAS) &&
+	      if ( (exponent(st0_ptr) >= 0) &&
 		  !((st0_ptr->sigh == 0x80000000) &&
 		    (st0_ptr->sigl == 0)) )
 		{
 		  /* st(0) holds < -1.0 */
 #ifdef PECULIAR_486   /* Stupid 80486 doesn't worry about log(negative). */
-		  st1_ptr->sign ^= SIGN_POS^SIGN_NEG;
+		  changesign(st1_ptr);
 #else
-		  if ( arith_invalid(st1_ptr) ) return;
+		  if ( arith_invalid(1) < 0 ) return;
 #endif PECULIAR_486
-		  pop(); return;
 		}
-#ifdef DENORM_OPERAND
-	      if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
+	      else if ( (st0_tag == TW_Denormal) && (denormal_operand() < 0) )
 		return;
-#endif DENORM_OPERAND
-	      st1_ptr->sign ^= SIGN_POS^SIGN_NEG;
-	      pop(); return;
+	      else
+		changesign(st1_ptr);
 	    }
-#ifdef DENORM_OPERAND
-	  if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
+	  else if ( (st0_tag == TW_Denormal) && (denormal_operand() < 0) )
+	    return;
+	  break;
+
+	case TW_NaN:
+	  if ( real_2op_NaN(st0_ptr, st0_tag, 1, st0_ptr) < 0 )
 	    return;
-#endif DENORM_OPERAND
-	  pop(); return;
-	}
-      if ( st1_tag == TW_NaN )
-	{
-	  if ( !real_2op_NaN(st0_ptr, st1_ptr, st1_ptr) )
-	    pop();
-	  return;
 	}
+
     }
   else if ( st0_tag == TW_NaN )
     {
-      if ( !real_2op_NaN(st0_ptr, st1_ptr, st1_ptr) )
-	pop();
-      return;
+      if ( real_2op_NaN(st0_ptr, st0_tag, 1, st0_ptr) < 0 )
+	return;
     }
   else if ( st0_tag == TW_Infinity )
     {
       if ( st1_tag == TW_NaN )
 	{
-	  if ( !real_2op_NaN(st0_ptr, st1_ptr, st1_ptr) )
-	    pop();
-	  return;
+	  if ( real_2op_NaN(st0_ptr, st0_tag, 1, st0_ptr) < 0 )
+	    return;
 	}
-      else if ( st0_ptr->sign == SIGN_NEG )
+      else if ( signnegative(st0_ptr) )
 	{
-	  int exponent = st1_ptr->exp;
 #ifndef PECULIAR_486
 	  /* This should have higher priority than denormals, but... */
-	  if ( arith_invalid(st1_ptr) )  /* log(-infinity) */
+	  if ( arith_invalid(1) < 0 )  /* log(-infinity) */
 	    return;
 #endif PECULIAR_486
-#ifdef DENORM_OPERAND
-	  if ( st1_tag != TW_Zero )
-	    {
-	      if ( (exponent <= EXP_UNDER) && (denormal_operand()) )
-		return;
-	    }
-#endif DENORM_OPERAND
+	  if ( (st1_tag == TW_Denormal) && (denormal_operand() < 0) )
+	    return;
 #ifdef PECULIAR_486
 	  /* Denormal operands actually get higher priority */
-	  if ( arith_invalid(st1_ptr) )  /* log(-infinity) */
+	  if ( arith_invalid(1) < 0 )  /* log(-infinity) */
 	    return;
 #endif PECULIAR_486
-	  pop();
-	  return;
 	}
-      else if ( st1_tag == TW_Zero )
+      else if ( st1_tag == TAG_Zero )
 	{
 	  /* log(infinity) */
-	  if ( !arith_invalid(st1_ptr) )
-	    pop();
-	  return;
+	  if ( arith_invalid(1) < 0 )
+	    return;
 	}
 	
       /* st(1) must be valid here. */
 
-#ifdef DENORM_OPERAND
-      if ( (st1_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
+      else if ( (st1_tag == TW_Denormal) && (denormal_operand() < 0) )
 	return;
-#endif DENORM_OPERAND
 
       /* The Manual says that log(Infinity) is invalid, but a real
 	 80486 sensibly says that it is o.k. */
-      { char sign = st1_ptr->sign;
-	reg_move(&CONST_INF, st1_ptr);
-	st1_ptr->sign = sign;
-      }
-      pop();
-      return;
+      else
+	{
+	  u_char sign = getsign(st1_ptr);
+	  FPU_copy_to_reg1(&CONST_INF, TAG_Special);
+	  setsign(st1_ptr, sign);
+	}
     }
 #ifdef PARANOID
   else
     {
       EXCEPTION(EX_INTERNAL | 0x117);
+      return;
     }
 #endif PARANOID
+
+  FPU_pop();
+  return;
+
 }
 
 
-static void fscale(FPU_REG *st0_ptr)
+static void fscale(FPU_REG *st0_ptr, u_char st0_tag)
 {
-  char st0_tag = st0_ptr->tag;
   FPU_REG *st1_ptr = &st(1);
-  char st1_tag = st1_ptr->tag;
+  u_char st1_tag = FPU_gettagi(1);
   int old_cw = control_word;
-  char sign = st0_ptr->sign;
+  u_char sign = getsign(st0_ptr);
 
   clear_C1();
-  if ( !((st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid)) )
+  if ( !((st0_tag ^ TAG_Valid) | (st1_tag ^ TAG_Valid)) )
     {
       long scale;
       FPU_REG tmp;
 
-#ifdef DENORM_OPERAND
-      if ( ((st0_ptr->exp <= EXP_UNDER) ||
-	    (st1_ptr->exp <= EXP_UNDER)) && (denormal_operand()) )
-	return;
-#endif DENORM_OPERAND
+      /* Convert register for internal use. */
+      setexponent16(st0_ptr, exponent(st0_ptr));
+
+    valid_scale:
 
-      if ( st1_ptr->exp > EXP_BIAS + 30 )
+      if ( exponent(st1_ptr) > 30 )
 	{
 	  /* 2^31 is far too large, would require 2^(2^30) or 2^(-2^30) */
-	  char sign;
 
-	  if ( st1_ptr->sign == SIGN_POS )
+	  if ( signpositive(st1_ptr) )
 	    {
 	      EXCEPTION(EX_Overflow);
-	      sign = st0_ptr->sign;
-	      reg_move(&CONST_INF, st0_ptr);
-	      st0_ptr->sign = sign;
+	      FPU_copy_to_reg0(&CONST_INF, TAG_Special);
 	    }
 	  else
 	    {
 	      EXCEPTION(EX_Underflow);
-	      sign = st0_ptr->sign;
-	      reg_move(&CONST_Z, st0_ptr);
-	      st0_ptr->sign = sign;
+	      FPU_copy_to_reg0(&CONST_Z, TAG_Zero);
 	    }
+	  setsign(st0_ptr, sign);
 	  return;
 	}
 
       control_word &= ~CW_RC;
       control_word |= RC_CHOP;
-      reg_move(st1_ptr, &tmp);
-      round_to_int(&tmp);               /* This can never overflow here */
+      reg_copy(st1_ptr, &tmp);
+      FPU_round_to_int(&tmp, st1_tag);      /* This can never overflow here */
       control_word = old_cw;
-      scale = st1_ptr->sign ? -tmp.sigl : tmp.sigl;
-      scale += st0_ptr->exp;
-      st0_ptr->exp = scale;
+      scale = signnegative(st1_ptr) ? -tmp.sigl : tmp.sigl;
+      scale += exponent16(st0_ptr);
 
-      /* Use round_reg() to properly detect under/overflow etc */
-      round_reg(st0_ptr, 0, control_word);
+      setexponent16(st0_ptr, scale);
+
+      /* Use FPU_round() to properly detect under/overflow etc */
+      FPU_round(st0_ptr, 0, 0, control_word, sign);
 
       return;
     }
-  else if ( st0_tag == TW_Valid )
+
+  if ( st0_tag == TAG_Special )
+    st0_tag = FPU_Special(st0_ptr);
+  if ( st1_tag == TAG_Special )
+    st1_tag = FPU_Special(st1_ptr);
+
+  if ( (st0_tag == TAG_Valid) || (st0_tag == TW_Denormal) )
     {
-      if ( st1_tag == TW_Zero )
+      switch ( st1_tag )
 	{
-
-#ifdef DENORM_OPERAND
-	  if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
+	case TAG_Valid:
+	  /* st(0) must be a denormal */
+	  if ( (st0_tag == TW_Denormal) && (denormal_operand() < 0) )
 	    return;
-#endif DENORM_OPERAND
 
+	  FPU_to_exp16(st0_ptr, st0_ptr);  /* Will not be left on stack */
+	  goto valid_scale;
+
+	case TAG_Zero:
+	  if ( st0_tag == TW_Denormal )
+	    denormal_operand();
 	  return;
-	}
-      if ( st1_tag == TW_Infinity )
-	{
-#ifdef DENORM_OPERAND
-	  if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
+
+	case TW_Denormal:
+	  denormal_operand();
+	  return;
+
+	case TW_Infinity:
+	  if ( (st0_tag == TW_Denormal) && (denormal_operand() < 0) )
 	    return;
-#endif DENORM_OPERAND
 
-	  if ( st1_ptr->sign == SIGN_POS )
-	    { reg_move(&CONST_INF, st0_ptr); }
+	  if ( signpositive(st1_ptr) )
+	    FPU_copy_to_reg0(&CONST_INF, TAG_Special);
 	  else
-	      reg_move(&CONST_Z, st0_ptr);
-	  st0_ptr->sign = sign;
+	    FPU_copy_to_reg0(&CONST_Z, TAG_Zero);
+	  setsign(st0_ptr, sign);
+	  return;
+
+	case TW_NaN:
+	  real_2op_NaN(st1_ptr, st1_tag, 0, st0_ptr);
 	  return;
 	}
-      if ( st1_tag == TW_NaN )
-	{ real_2op_NaN(st0_ptr, st1_ptr, st0_ptr); return; }
     }
-  else if ( st0_tag == TW_Zero )
+  else if ( st0_tag == TAG_Zero )
     {
-      if ( st1_tag == TW_Valid )
+      switch ( st1_tag )
 	{
+	case TAG_Valid:
+	case TAG_Zero:
+	  return;
 
-#ifdef DENORM_OPERAND
-	  if ( (st1_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
-	    return;
-#endif DENORM_OPERAND
+	case TW_Denormal:
+	  denormal_operand();
+	  return;
 
+	case TW_Infinity:
+	  if ( signpositive(st1_ptr) )
+	    arith_invalid(0); /* Zero scaled by +Infinity */
+	  return;
+
+	case TW_NaN:
+	  real_2op_NaN(st1_ptr, st1_tag, 0, st0_ptr);
 	  return;
 	}
-      else if ( st1_tag == TW_Zero ) { return; }
-      else if ( st1_tag == TW_Infinity )
-	{
-	  if ( st1_ptr->sign == SIGN_NEG )
-	    return;
-	  else
-	    {
-	      arith_invalid(st0_ptr); /* Zero scaled by +Infinity */
-	      return;
-	    }
-	}
-      else if ( st1_tag == TW_NaN )
-	{ real_2op_NaN(st0_ptr, st1_ptr, st0_ptr); return; }
     }
   else if ( st0_tag == TW_Infinity )
     {
-      if ( st1_tag == TW_Valid )
+      switch ( st1_tag )
 	{
+	case TAG_Valid:
+	case TAG_Zero:
+	  return;
 
-#ifdef DENORM_OPERAND
-	  if ( (st1_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
-	    return;
-#endif DENORM_OPERAND
+	case TW_Denormal:
+	  denormal_operand();
+	  return;
 
+	case TW_Infinity:
+	  if ( signnegative(st1_ptr) )
+	    arith_invalid(0); /* Infinity scaled by -Infinity */
 	  return;
-	}
-      if ( ((st1_tag == TW_Infinity) && (st1_ptr->sign == SIGN_POS))
-	  || (st1_tag == TW_Zero) )
-	return;
-      else if ( st1_tag == TW_Infinity )
-	{
-	  arith_invalid(st0_ptr); /* Infinity scaled by -Infinity */
+
+	case TW_NaN:
+	  real_2op_NaN(st1_ptr, st1_tag, 0, st0_ptr);
 	  return;
 	}
-      else if ( st1_tag == TW_NaN )
-	{ real_2op_NaN(st0_ptr, st1_ptr, st0_ptr); return; }
     }
   else if ( st0_tag == TW_NaN )
     {
-      if ( st1_tag != TW_Empty )
-	{ real_2op_NaN(st0_ptr, st1_ptr, st0_ptr); return; }
+      if ( st1_tag != TAG_Empty )
+	{ real_2op_NaN(st1_ptr, st1_tag, 0, st0_ptr); return; }
     }
 
 #ifdef PARANOID
-  if ( !((st0_tag == TW_Empty) || (st1_tag == TW_Empty)) )
+  if ( !((st0_tag == TAG_Empty) || (st1_tag == TAG_Empty)) )
     {
       EXCEPTION(EX_INTERNAL | 0x115);
       return;
@@ -1690,7 +1802,7 @@
 #endif
 
   /* At least one of st(0), st(1) must be empty */
-  stack_underflow();
+  FPU_stack_underflow();
 
 }
 
@@ -1698,21 +1810,22 @@
 /*---------------------------------------------------------------------------*/
 
 static FUNC_ST0 const trig_table_a[] = {
-  f2xm1, fyl2x, fptan, fpatan, fxtract, fprem1, fdecstp, fincstp
+  f2xm1, fyl2x, fptan, fpatan,
+  fxtract, fprem1, (FUNC_ST0)fdecstp, (FUNC_ST0)fincstp
 };
 
-void trig_a(void)
+void FPU_triga(void)
 {
-  (trig_table_a[FPU_rm])(&st(0));
+  (trig_table_a[FPU_rm])(&st(0), FPU_gettag0());
 }
 
 
 static FUNC_ST0 const trig_table_b[] =
   {
-    fprem, fyl2xp1, fsqrt_, fsincos, frndint_, fscale, fsin, fcos
+    fprem, fyl2xp1, fsqrt_, fsincos, frndint_, fscale, (FUNC_ST0)fsin, fcos
   };
 
-void trig_b(void)
+void FPU_trigb(void)
 {
-  (trig_table_b[FPU_rm])(&st(0));
+  (trig_table_b[FPU_rm])(&st(0), FPU_gettag0());
 }
diff -u --recursive --new-file v2.1.72/linux/arch/i386/math-emu/get_address.c linux/arch/i386/math-emu/get_address.c
--- v2.1.72/linux/arch/i386/math-emu/get_address.c	Mon Oct 28 04:41:15 1996
+++ linux/arch/i386/math-emu/get_address.c	Tue Dec  9 17:57:09 1997
@@ -3,9 +3,9 @@
  |                                                                           |
  | Get the effective address from an FPU instruction.                        |
  |                                                                           |
- | Copyright (C) 1992,1993,1994                                              |
+ | Copyright (C) 1992,1993,1994,1997                                         |
  |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
- |                       Australia.  E-mail   billm@vaxc.cc.monash.edu.au    |
+ |                       Australia.  E-mail   billm@suburbia.net             |
  |                                                                           |
  |                                                                           |
  +---------------------------------------------------------------------------*/
@@ -41,7 +41,7 @@
 	offsetof(struct info,___edi)
 };
 
-#define REG_(x) (*(long *)(reg_offset[(x)]+(char *) FPU_info))
+#define REG_(x) (*(long *)(reg_offset[(x)]+(u_char *) FPU_info))
 
 static int reg_offset_vm86[] = {
 	offsetof(struct info,___cs),
@@ -54,7 +54,7 @@
       };
 
 #define VM86_REG_(x) (*(unsigned short *) \
-		      (reg_offset_vm86[((unsigned)x)]+(char *) FPU_info))
+		      (reg_offset_vm86[((unsigned)x)]+(u_char *) FPU_info))
 
 /* These are dummy, fs and gs are not saved on the stack. */
 #define ___FS ___ds
@@ -71,18 +71,18 @@
       };
 
 #define PM_REG_(x) (*(unsigned short *) \
-		      (reg_offset_pm[((unsigned)x)]+(char *) FPU_info))
+		      (reg_offset_pm[((unsigned)x)]+(u_char *) FPU_info))
 
 
 /* Decode the SIB byte. This function assumes mod != 0 */
 static int sib(int mod, unsigned long *fpu_eip)
 {
-  unsigned char ss,index,base;
+  u_char ss,index,base;
   long offset;
 
   RE_ENTRANT_CHECK_OFF;
   FPU_code_verify_area(1);
-  get_user(base, (unsigned char *) (*fpu_eip));   /* The SIB byte */
+  FPU_get_user(base, (u_char *) (*fpu_eip));   /* The SIB byte */
   RE_ENTRANT_CHECK_ON;
   (*fpu_eip)++;
   ss = base >> 6;
@@ -112,7 +112,7 @@
       long displacement;
       RE_ENTRANT_CHECK_OFF;
       FPU_code_verify_area(1);
-      get_user(displacement, (signed char *) (*fpu_eip));
+      FPU_get_user(displacement, (signed char *) (*fpu_eip));
       offset += displacement;
       RE_ENTRANT_CHECK_ON;
       (*fpu_eip)++;
@@ -123,7 +123,7 @@
       long displacement;
       RE_ENTRANT_CHECK_OFF;
       FPU_code_verify_area(4);
-      get_user(displacement, (signed long *) (*fpu_eip));
+      FPU_get_user(displacement, (long *) (*fpu_eip));
       offset += displacement;
       RE_ENTRANT_CHECK_ON;
       (*fpu_eip) += 4;
@@ -133,7 +133,7 @@
 }
 
 
-static unsigned long vm86_segment(unsigned char segment,
+static unsigned long vm86_segment(u_char segment,
 				  unsigned short *selector)
 { 
   segment--;
@@ -150,7 +150,7 @@
 
 
 /* This should work for 16 and 32 bit protected mode. */
-static long pm_address(unsigned char FPU_modrm, unsigned char segment,
+static long pm_address(u_char FPU_modrm, u_char segment,
 		       unsigned short *selector, long offset)
 { 
   struct desc_struct descriptor;
@@ -233,12 +233,11 @@
 
 */
 
-void *get_address(unsigned char FPU_modrm, unsigned long *fpu_eip,
+void *FPU_get_address(u_char FPU_modrm, unsigned long *fpu_eip,
 		  struct address *addr,
-/*		  unsigned short *selector, unsigned long *offset, */
 		  fpu_addr_modes addr_modes)
 {
-  unsigned char mod;
+  u_char mod;
   unsigned rm = FPU_modrm & 7;
   long *cpu_reg_ptr;
   int address = 0;     /* Initialized just to stop compiler warnings. */
@@ -270,7 +269,7 @@
 	      /* Special case: disp32 */
 	      RE_ENTRANT_CHECK_OFF;
 	      FPU_code_verify_area(4);
-	      get_user(address, (unsigned long *) (*fpu_eip));
+	      FPU_get_user(address, (unsigned long *) (*fpu_eip));
 	      (*fpu_eip) += 4;
 	      RE_ENTRANT_CHECK_ON;
 	      addr->offset = address;
@@ -287,7 +286,7 @@
 	  /* 8 bit signed displacement */
 	  RE_ENTRANT_CHECK_OFF;
 	  FPU_code_verify_area(1);
-	  get_user(address, (signed char *) (*fpu_eip));
+	  FPU_get_user(address, (signed char *) (*fpu_eip));
 	  RE_ENTRANT_CHECK_ON;
 	  (*fpu_eip)++;
 	  break;
@@ -295,7 +294,7 @@
 	  /* 32 bit displacement */
 	  RE_ENTRANT_CHECK_OFF;
 	  FPU_code_verify_area(4);
-	  get_user(address, (long *) (*fpu_eip));
+	  FPU_get_user(address, (long *) (*fpu_eip));
 	  (*fpu_eip) += 4;
 	  RE_ENTRANT_CHECK_ON;
 	  break;
@@ -329,12 +328,11 @@
 }
 
 
-void *get_address_16(unsigned char FPU_modrm, unsigned long *fpu_eip,
+void *FPU_get_address_16(u_char FPU_modrm, unsigned long *fpu_eip,
 		     struct address *addr,
-/*		     unsigned short *selector, unsigned long *offset, */
 		     fpu_addr_modes addr_modes)
 {
-  unsigned char mod;
+  u_char mod;
   unsigned rm = FPU_modrm & 7;
   int address = 0;     /* Default used for mod == 0 */
 
@@ -358,7 +356,7 @@
 	  /* Special case: disp16 */
 	  RE_ENTRANT_CHECK_OFF;
 	  FPU_code_verify_area(2);
-	  get_user(address, (unsigned short *) (*fpu_eip));
+	  FPU_get_user(address, (unsigned short *) (*fpu_eip));
 	  (*fpu_eip) += 2;
 	  RE_ENTRANT_CHECK_ON;
 	  goto add_segment;
@@ -368,7 +366,7 @@
       /* 8 bit signed displacement */
       RE_ENTRANT_CHECK_OFF;
       FPU_code_verify_area(1);
-      get_user(address, (signed char *) (*fpu_eip));
+      FPU_get_user(address, (signed char *) (*fpu_eip));
       RE_ENTRANT_CHECK_ON;
       (*fpu_eip)++;
       break;
@@ -376,7 +374,7 @@
       /* 16 bit displacement */
       RE_ENTRANT_CHECK_OFF;
       FPU_code_verify_area(2);
-      get_user(address, (unsigned short *) (*fpu_eip));
+      FPU_get_user(address, (unsigned short *) (*fpu_eip));
       (*fpu_eip) += 2;
       RE_ENTRANT_CHECK_ON;
       break;
diff -u --recursive --new-file v2.1.72/linux/arch/i386/math-emu/load_store.c linux/arch/i386/math-emu/load_store.c
--- v2.1.72/linux/arch/i386/math-emu/load_store.c	Mon Oct 28 04:41:15 1996
+++ linux/arch/i386/math-emu/load_store.c	Tue Dec  9 17:57:09 1997
@@ -4,9 +4,9 @@
  | This file contains most of the code to interpret the FPU instructions     |
  | which load and store from user memory.                                    |
  |                                                                           |
- | Copyright (C) 1992,1993,1994                                              |
+ | Copyright (C) 1992,1993,1994,1997                                         |
  |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
- |                       Australia.  E-mail   billm@vaxc.cc.monash.edu.au    |
+ |                       Australia.  E-mail   billm@suburbia.net             |
  |                                                                           |
  |                                                                           |
  +---------------------------------------------------------------------------*/
@@ -32,10 +32,10 @@
 #define _PUSH_ 3   /* Need to check for space to push onto stack */
 #define _null_ 4   /* Function illegal or not implemented */
 
-#define pop_0()	{ st0_ptr->tag = TW_Empty; top++; }
+#define pop_0()	{ FPU_settag0(TAG_Empty); top++; }
 
 
-static unsigned char const type_table[32] = {
+static u_char const type_table[32] = {
   _PUSH_, _PUSH_, _PUSH_, _PUSH_,
   _null_, _null_, _null_, _null_,
   _REG0_, _REG0_, _REG0_, _REG0_,
@@ -46,25 +46,27 @@
   _NONE_, _REG0_, _NONE_, _REG0_
   };
 
-unsigned char const data_sizes_16[32] = {
+u_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] = {
+u_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,
+int FPU_load_store(u_char type, fpu_addr_modes addr_modes,
 		     void *data_address)
 {
   FPU_REG loaded_data;
   FPU_REG *st0_ptr;
+  u_char st0_tag = TAG_Empty;  /* This is just to stop a gcc warning. */
+  u_char loaded_tag;
 
   st0_ptr = NULL;    /* Initialized just to stop compiler warnings. */
 
@@ -93,13 +95,14 @@
     case _REG0_:
       st0_ptr = &st(0);       /* Some of these instructions pop after
 				 storing */
+      st0_tag = FPU_gettag0();
       break;
     case _PUSH_:
       {
-	st0_ptr = &st(-1);
-	if ( st0_ptr->tag != TW_Empty )
-	  { stack_overflow(); return 0; }
+	if ( FPU_gettagi(-1) != TAG_Empty )
+	  { FPU_stack_overflow(); return 0; }
 	top--;
+	st0_ptr = &st(0);
       }
       break;
     case _null_:
@@ -116,92 +119,97 @@
     {
     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) )
+      loaded_tag = FPU_load_single((float *)data_address, &loaded_data);
+      if ( (loaded_tag == TAG_Special)
+	   && isNaN(&loaded_data)
+	   && (real_1op_NaN(&loaded_data) < 0) )
 	{
 	  top++;
 	  break;
 	}
-      reg_move(&loaded_data, st0_ptr);
+      FPU_copy_to_reg0(&loaded_data, loaded_tag);
       break;
     case 001:      /* fild m32int */
       clear_C1();
-      reg_load_int32((long *)data_address, st0_ptr);
+      loaded_tag = FPU_load_int32((long *)data_address, &loaded_data);
+      FPU_copy_to_reg0(&loaded_data, loaded_tag);
       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) )
+      loaded_tag = FPU_load_double((double *)data_address, &loaded_data);
+      if ( (loaded_tag == TAG_Special)
+	   && isNaN(&loaded_data)
+	   && (real_1op_NaN(&loaded_data) < 0) )
 	{
 	  top++;
 	  break;
 	}
-      reg_move(&loaded_data, st0_ptr);
+      FPU_copy_to_reg0(&loaded_data, loaded_tag);
       break;
     case 003:      /* fild m16int */
       clear_C1();
-      reg_load_int16((short *)data_address, st0_ptr);
+      loaded_tag = FPU_load_int16((short *)data_address, &loaded_data);
+      FPU_copy_to_reg0(&loaded_data, loaded_tag);
       break;
     case 010:      /* fst m32real */
       clear_C1();
-      reg_store_single((float *)data_address, st0_ptr);
+      FPU_store_single(st0_ptr, st0_tag, (float *)data_address);
       break;
     case 011:      /* fist m32int */
       clear_C1();
-      reg_store_int32((long *)data_address, st0_ptr);
+      FPU_store_int32(st0_ptr, st0_tag, (long *)data_address);
       break;
     case 012:     /* fst m64real */
       clear_C1();
-      reg_store_double((double *)data_address, st0_ptr);
+      FPU_store_double(st0_ptr, st0_tag, (double *)data_address);
       break;
     case 013:     /* fist m16int */
       clear_C1();
-      reg_store_int16((short *)data_address, st0_ptr);
+      FPU_store_int16(st0_ptr, st0_tag, (short *)data_address);
       break;
     case 014:     /* fstp m32real */
       clear_C1();
-      if ( reg_store_single((float *)data_address, st0_ptr) )
+      if ( FPU_store_single(st0_ptr, st0_tag, (float *)data_address) )
 	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) )
+      if ( FPU_store_int32(st0_ptr, st0_tag, (long *)data_address) )
 	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) )
+      if ( FPU_store_double(st0_ptr, st0_tag, (double *)data_address) )
 	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) )
+      if ( FPU_store_int16(st0_ptr, st0_tag, (short *)data_address) )
 	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);
+      fldenv(addr_modes, (u_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);
+      frstor(addr_modes, (u_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);
+      loaded_tag = FPU_load_bcd((u_char *)data_address);
+      FPU_settag0(loaded_tag);
       break;
     case 024:     /* fldcw */
       RE_ENTRANT_CHECK_OFF;
       FPU_verify_area(VERIFY_READ, data_address, 2);
-      get_user(control_word, (unsigned short *) data_address);
+      FPU_get_user(control_word, (unsigned short *) data_address);
       RE_ENTRANT_CHECK_ON;
       if ( partial_status & ~control_word & CW_Exceptions )
 	partial_status |= (SW_Summary | SW_Backward);
@@ -213,45 +221,47 @@
       return 1;
     case 025:      /* fld m80real */
       clear_C1();
-      reg_load_extended((long double *)data_address, st0_ptr);
+      loaded_tag = FPU_load_extended((long double *)data_address, 0);
+      FPU_settag0(loaded_tag);
       break;
     case 027:      /* fild m64int */
       clear_C1();
-      reg_load_int64((long long *)data_address, st0_ptr);
+      loaded_tag = FPU_load_int64((long long *)data_address);
+      FPU_settag0(loaded_tag);
       break;
     case 030:     /* fstenv  m14/28byte */
-      fstenv(addr_modes, (char *)data_address);
+      fstenv(addr_modes, (u_char *)data_address);
       return 1;
     case 032:      /* fsave */
-      fsave(addr_modes, (char *)data_address);
+      fsave(addr_modes, (u_char *)data_address);
       return 1;
     case 033:      /* fbstp m80dec */
       clear_C1();
-      if ( reg_store_bcd((char *)data_address, st0_ptr) )
+      if ( FPU_store_bcd(st0_ptr, st0_tag, (u_char *)data_address) )
 	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_user(control_word, (unsigned short *) data_address);
+      FPU_put_user(control_word, (unsigned 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) )
+      if ( FPU_store_extended(st0_ptr, st0_tag, (long double *)data_address) )
 	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_user(status_word(),(unsigned short *) data_address);
+      FPU_put_user(status_word(),(unsigned 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) )
+      if ( FPU_store_int64(st0_ptr, st0_tag, (long long *)data_address) )
 	pop_0();  /* pop only if the number was actually stored
 		     (see the 80486 manual p16-28) */
       break;
diff -u --recursive --new-file v2.1.72/linux/arch/i386/math-emu/poly_2xm1.c linux/arch/i386/math-emu/poly_2xm1.c
--- v2.1.72/linux/arch/i386/math-emu/poly_2xm1.c	Sun Jul 31 22:19:14 1994
+++ linux/arch/i386/math-emu/poly_2xm1.c	Tue Dec  9 17:57:09 1997
@@ -3,9 +3,9 @@
  |                                                                           |
  | Function to compute 2^x-1 by a polynomial approximation.                  |
  |                                                                           |
- | Copyright (C) 1992,1993,1994                                              |
- |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
- |                       Australia.  E-mail   billm@vaxc.cc.monash.edu.au    |
+ | Copyright (C) 1992,1993,1994,1997                                         |
+ |                  W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
+ |                  E-mail   billm@suburbia.net                              |
  |                                                                           |
  |                                                                           |
  +---------------------------------------------------------------------------*/
@@ -13,6 +13,7 @@
 #include "exception.h"
 #include "reg_constant.h"
 #include "fpu_emu.h"
+#include "fpu_system.h"
 #include "control_w.h"
 #include "poly.h"
 
@@ -48,20 +49,19 @@
 
 
 /*--- poly_2xm1() -----------------------------------------------------------+
- | Requires an argument which is TW_Valid and < 1.                           |
+ | Requires st(0) which is TAG_Valid and < 1.                                |
  +---------------------------------------------------------------------------*/
-int	poly_2xm1(FPU_REG const *arg, FPU_REG *result)
+int	poly_2xm1(u_char sign, FPU_REG *arg, FPU_REG *result)
 {
-  long int               exponent, shift;
-  unsigned long long     Xll;
-  Xsig                   accumulator, Denom, argSignif;
+  long int              exponent, shift;
+  unsigned long long    Xll;
+  Xsig                  accumulator, Denom, argSignif;
+  u_char                tag;
 
-
-  exponent = arg->exp - EXP_BIAS;
+  exponent = exponent16(arg);
 
 #ifdef PARANOID
-  if (   (exponent >= 0)    	/* Don't want a |number| >= 1.0 */
-      || (arg->tag != TW_Valid) )
+  if ( exponent >= 0 )    	/* Don't want a |number| >= 1.0 */
     {
       /* Number negative, too large, or not Valid. */
       EXCEPTION(EX_INTERNAL|0x127);
@@ -94,7 +94,7 @@
   if ( exponent < -2 )
     {
       /* Shift the argument right by the required places. */
-      if ( shrx(&Xll, -2-exponent) >= 0x80000000U )
+      if ( FPU_shrx(&Xll, -2-exponent) >= 0x80000000U )
 	Xll++;	/* round up */
     }
 
@@ -118,7 +118,7 @@
       exponent = 1;
     }
 
-  if ( arg->sign != SIGN_POS )
+  if ( sign != SIGN_POS )
     {
       /* The argument is negative, use the identity:
 	     f(-x) = -f(x) / (1 + f(x))
@@ -142,10 +142,14 @@
   /* Convert to 64 bit signed-compatible */
   exponent += round_Xsig(&accumulator);
 
+  result = &st(0);
   significand(result) = XSIG_LL(accumulator);
-  result->tag = TW_Valid;
-  result->exp = exponent + EXP_BIAS;
-  result->sign = arg->sign;
+  setexponent16(result, exponent);
+
+  tag = FPU_round(result, 1, 0, FULL_PRECISION, sign);
+
+  setsign(result, sign);
+  FPU_settag0(tag);
 
   return 0;
 
diff -u --recursive --new-file v2.1.72/linux/arch/i386/math-emu/poly_atan.c linux/arch/i386/math-emu/poly_atan.c
--- v2.1.72/linux/arch/i386/math-emu/poly_atan.c	Sun Jul 31 22:19:14 1994
+++ linux/arch/i386/math-emu/poly_atan.c	Tue Dec  9 17:57:09 1997
@@ -3,9 +3,9 @@
  |                                                                           |
  | Compute the arctan of a FPU_REG, using a polynomial approximation.        |
  |                                                                           |
- | Copyright (C) 1992,1993,1994                                              |
- |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
- |                       Australia.  E-mail   billm@vaxc.cc.monash.edu.au    |
+ | Copyright (C) 1992,1993,1994,1997                                         |
+ |                  W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
+ |                  E-mail   billm@suburbia.net                              |
  |                                                                           |
  |                                                                           |
  +---------------------------------------------------------------------------*/
@@ -13,6 +13,7 @@
 #include "exception.h"
 #include "reg_constant.h"
 #include "fpu_emu.h"
+#include "fpu_system.h"
 #include "status_w.h"
 #include "control_w.h"
 #include "poly.h"
@@ -51,31 +52,57 @@
 /*--- poly_atan() -----------------------------------------------------------+
  |                                                                           |
  +---------------------------------------------------------------------------*/
-void	poly_atan(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *result)
+void	poly_atan(FPU_REG *st0_ptr, u_char st0_tag,
+		  FPU_REG *st1_ptr, u_char st1_tag)
 {
-  char		        transformed, inverted,
-                        sign1 = arg1->sign, sign2 = arg2->sign;
-  long int   		exponent, dummy_exp;
-  Xsig                  accumulator, Numer, Denom, accumulatore, argSignif,
-                        argSq, argSqSq;
+  u_char	transformed, inverted,
+                sign1, sign2;
+  int           exponent;
+  long int   	dummy_exp;
+  Xsig          accumulator, Numer, Denom, accumulatore, argSignif,
+                argSq, argSqSq;
+  u_char        tag;
   
+  sign1 = getsign(st0_ptr);
+  sign2 = getsign(st1_ptr);
+  if ( st0_tag == TAG_Valid )
+    {
+      exponent = exponent(st0_ptr);
+    }
+  else
+    {
+      /* This gives non-compatible stack contents... */
+      FPU_to_exp16(st0_ptr, st0_ptr);
+      exponent = exponent16(st0_ptr);
+    }
+  if ( st1_tag == TAG_Valid )
+    {
+      exponent -= exponent(st1_ptr);
+    }
+  else
+    {
+      /* This gives non-compatible stack contents... */
+      FPU_to_exp16(st1_ptr, st1_ptr);
+      exponent -= exponent16(st1_ptr);
+    }
 
-  arg1->sign = arg2->sign = SIGN_POS;
-  if ( (compare(arg2) & ~COMP_Denormal) == COMP_A_lt_B )
+  if ( (exponent < 0) || ((exponent == 0) &&
+			  ((st0_ptr->sigh < st1_ptr->sigh) ||
+			   ((st0_ptr->sigh == st1_ptr->sigh) &&
+			    (st0_ptr->sigl < st1_ptr->sigl))) ) )
     {
       inverted = 1;
-      exponent = arg1->exp - arg2->exp;
       Numer.lsw = Denom.lsw = 0;
-      XSIG_LL(Numer) = significand(arg1);
-      XSIG_LL(Denom) = significand(arg2);
+      XSIG_LL(Numer) = significand(st0_ptr);
+      XSIG_LL(Denom) = significand(st1_ptr);
     }
   else
     {
       inverted = 0;
-      exponent = arg2->exp - arg1->exp;
+      exponent = -exponent;
       Numer.lsw = Denom.lsw = 0;
-      XSIG_LL(Numer) = significand(arg2);
-      XSIG_LL(Denom) = significand(arg1);
+      XSIG_LL(Numer) = significand(st1_ptr);
+      XSIG_LL(Denom) = significand(st0_ptr);
      }
   div_Xsig(&Numer, &Denom, &argSignif);
   exponent += norm_Xsig(&argSignif);
@@ -189,9 +216,14 @@
     }
 
   exponent += round_Xsig(&accumulator);
-  significand(result) = XSIG_LL(accumulator);
-  result->exp = exponent + EXP_BIAS;
-  result->tag = TW_Valid;
-  result->sign = sign2;
+
+  significand(st1_ptr) = XSIG_LL(accumulator);
+  setexponent16(st1_ptr, exponent);
+
+  tag = FPU_round(st1_ptr, 1, 0, FULL_PRECISION, sign2);
+  FPU_settagi(1, tag);
+
+  set_precision_flag_up();  /* We do not really know if up or down,
+			       use this as the default. */
 
 }
diff -u --recursive --new-file v2.1.72/linux/arch/i386/math-emu/poly_l2.c linux/arch/i386/math-emu/poly_l2.c
--- v2.1.72/linux/arch/i386/math-emu/poly_l2.c	Sun Jul 31 22:19:14 1994
+++ linux/arch/i386/math-emu/poly_l2.c	Tue Dec  9 17:57:09 1997
@@ -3,9 +3,9 @@
  |                                                                           |
  | Compute the base 2 log of a FPU_REG, using a polynomial approximation.    |
  |                                                                           |
- | Copyright (C) 1992,1993,1994                                              |
- |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
- |                       Australia.  E-mail   billm@vaxc.cc.monash.edu.au    |
+ | Copyright (C) 1992,1993,1994,1997                                         |
+ |                  W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
+ |                  E-mail   billm@suburbia.net                              |
  |                                                                           |
  |                                                                           |
  +---------------------------------------------------------------------------*/
@@ -14,96 +14,101 @@
 #include "exception.h"
 #include "reg_constant.h"
 #include "fpu_emu.h"
+#include "fpu_system.h"
 #include "control_w.h"
 #include "poly.h"
 
 
-
-static void log2_kernel(FPU_REG const *arg,
+static void log2_kernel(FPU_REG const *arg, u_char argsign,
 			Xsig *accum_result, long int *expon);
 
 
 /*--- poly_l2() -------------------------------------------------------------+
  |   Base 2 logarithm by a polynomial approximation.                         |
  +---------------------------------------------------------------------------*/
-void	poly_l2(FPU_REG const *arg, FPU_REG const *y, FPU_REG *result)
+void	poly_l2(FPU_REG *st0_ptr, FPU_REG *st1_ptr, u_char st1_sign)
 {
   long int	       exponent, expon, expon_expon;
   Xsig                 accumulator, expon_accum, yaccum;
-  char		       sign;
+  u_char		       sign, argsign;
   FPU_REG              x;
+  int                  tag;
 
+  exponent = exponent16(st0_ptr);
 
-  exponent = arg->exp - EXP_BIAS;
-
-  /* From arg, make a number > sqrt(2)/2 and < sqrt(2) */
-  if ( arg->sigh > (unsigned)0xb504f334 )
+  /* From st0_ptr, make a number > sqrt(2)/2 and < sqrt(2) */
+  if ( st0_ptr->sigh > (unsigned)0xb504f334 )
     {
-      /* Treat as  sqrt(2)/2 < arg < 1 */
-      significand(&x) = - significand(arg);
-      x.sign = SIGN_NEG;
-      x.tag = TW_Valid;
-      x.exp = EXP_BIAS-1;
+      /* Treat as  sqrt(2)/2 < st0_ptr < 1 */
+      significand(&x) = - significand(st0_ptr);
+      setexponent16(&x, -1);
       exponent++;
-      normalize(&x);
+      argsign = SIGN_NEG;
     }
   else
     {
-      /* Treat as  1 <= arg < sqrt(2) */
-      x.sigh = arg->sigh - 0x80000000;
-      x.sigl = arg->sigl;
-      x.sign = SIGN_POS;
-      x.tag = TW_Valid;
-      x.exp = EXP_BIAS;
-      normalize(&x);
+      /* Treat as  1 <= st0_ptr < sqrt(2) */
+      x.sigh = st0_ptr->sigh - 0x80000000;
+      x.sigl = st0_ptr->sigl;
+      setexponent16(&x, 0);
+      argsign = SIGN_POS;
     }
+  tag = FPU_normalize_nuo(&x);
 
-  if ( x.tag == TW_Zero )
+  if ( tag == TAG_Zero )
     {
       expon = 0;
       accumulator.msw = accumulator.midw = accumulator.lsw = 0;
     }
   else
     {
-      log2_kernel(&x, &accumulator, &expon);
+      log2_kernel(&x, argsign, &accumulator, &expon);
     }
 
-  sign = exponent < 0;
-  if ( sign ) exponent = -exponent;
+  if ( exponent < 0 )
+    {
+      sign = SIGN_NEG;
+      exponent = -exponent;
+    }
+  else
+    sign = SIGN_POS;
   expon_accum.msw = exponent; expon_accum.midw = expon_accum.lsw = 0;
   if ( exponent )
     {
       expon_expon = 31 + norm_Xsig(&expon_accum);
       shr_Xsig(&accumulator, expon_expon - expon);
 
-      if ( sign ^ (x.sign == SIGN_NEG) )
+      if ( sign ^ argsign )
 	negate_Xsig(&accumulator);
       add_Xsig_Xsig(&accumulator, &expon_accum);
     }
   else
     {
       expon_expon = expon;
-      sign = x.sign;
+      sign = argsign;
     }
 
-  yaccum.lsw = 0; XSIG_LL(yaccum) = significand(y);
+  yaccum.lsw = 0; XSIG_LL(yaccum) = significand(st1_ptr);
   mul_Xsig_Xsig(&accumulator, &yaccum);
 
   expon_expon += round_Xsig(&accumulator);
 
   if ( accumulator.msw == 0 )
     {
-      reg_move(&CONST_Z, y);
-    }
-  else
-    {
-      result->exp = expon_expon + y->exp + 1;
-      significand(result) = XSIG_LL(accumulator);
-      result->tag = TW_Valid; /* set the tags to Valid */
-      result->sign = sign ^ y->sign;
+      FPU_copy_to_reg1(&CONST_Z, TAG_Zero);
+      return;
     }
 
+  significand(st1_ptr) = XSIG_LL(accumulator);
+  setexponent16(st1_ptr, expon_expon + exponent16(st1_ptr) + 1);
+
+  tag = FPU_round(st1_ptr, 1, 0, FULL_PRECISION, sign ^ st1_sign);
+  FPU_settagi(1, tag);
+
+  set_precision_flag_up();  /* 80486 appears to always do this */
+
   return;
+
 }
 
 
@@ -111,47 +116,62 @@
  |   Base 2 logarithm by a polynomial approximation.                         |
  |   log2(x+1)                                                               |
  +---------------------------------------------------------------------------*/
-int	poly_l2p1(FPU_REG const *arg, FPU_REG const *y, FPU_REG *result)
+int	poly_l2p1(u_char sign0, u_char sign1,
+		  FPU_REG *st0_ptr, FPU_REG *st1_ptr, FPU_REG *dest)
 {
-  char                 sign;
-  long int             exponent;
-  Xsig                 accumulator, yaccum;
+  u_char             	tag;
+  long int        	exponent;
+  Xsig              	accumulator, yaccum;
 
-
-  sign = arg->sign;
-
-  if ( arg->exp < EXP_BIAS )
+  if ( exponent16(st0_ptr) < 0 )
     {
-      log2_kernel(arg, &accumulator, &exponent);
+      log2_kernel(st0_ptr, sign0, &accumulator, &exponent);
 
       yaccum.lsw = 0;
-      XSIG_LL(yaccum) = significand(y);
+      XSIG_LL(yaccum) = significand(st1_ptr);
       mul_Xsig_Xsig(&accumulator, &yaccum);
 
       exponent += round_Xsig(&accumulator);
 
-      result->exp = exponent + y->exp + 1;
-      significand(result) = XSIG_LL(accumulator);
-      result->tag = TW_Valid; /* set the tags to Valid */
-      result->sign = sign ^ y->sign;
+      exponent += exponent16(st1_ptr) + 1;
+      if ( exponent < EXP_WAY_UNDER ) exponent = EXP_WAY_UNDER;
+
+      significand(dest) = XSIG_LL(accumulator);
+      setexponent16(dest, exponent);
 
-      return 0;
+      tag = FPU_round(dest, 1, 0, FULL_PRECISION, sign0 ^ sign1);
+      FPU_settagi(1, tag);
+
+      if ( tag == TAG_Valid )
+	set_precision_flag_up();   /* 80486 appears to always do this */
     }
   else
     {
-      /* The magnitude of arg is far too large. */
-      reg_move(y, result);
-      if ( sign != SIGN_POS )
+      /* The magnitude of st0_ptr is far too large. */
+
+      if ( sign0 != SIGN_POS )
 	{
 	  /* Trying to get the log of a negative number. */
-	  return 1;
+#ifdef PECULIAR_486   /* Stupid 80486 doesn't worry about log(negative). */
+	  changesign(st1_ptr);
+#else
+	  if ( arith_invalid(1) < 0 )
+	    return 1;
+#endif PECULIAR_486
 	}
+
+      /* 80486 appears to do this */
+      if ( sign0 == SIGN_NEG )
+	set_precision_flag_down();
       else
-	{
-	  return 0;
-	}
+	set_precision_flag_up();
     }
 
+  if ( exponent(dest) <= EXP_UNDER )
+    EXCEPTION(EX_Underflow);
+
+  return 0;
+
 }
 
 
@@ -180,20 +200,17 @@
  |   Base 2 logarithm by a polynomial approximation.                         |
  |   log2(x+1)                                                               |
  +---------------------------------------------------------------------------*/
-static void log2_kernel(FPU_REG const *arg, Xsig *accum_result,
+static void log2_kernel(FPU_REG const *arg, u_char argsign, Xsig *accum_result,
 			long int *expon)
 {
-  char                 sign;
   long int             exponent, adj;
   unsigned long long   Xsq;
   Xsig                 accumulator, Numer, Denom, argSignif, arg_signif;
 
-  sign = arg->sign;
-
-  exponent = arg->exp - EXP_BIAS;
+  exponent = exponent16(arg);
   Numer.lsw = Denom.lsw = 0;
   XSIG_LL(Numer) = XSIG_LL(Denom) = significand(arg);
-  if ( sign == SIGN_POS )
+  if ( argsign == SIGN_POS )
     {
       shr_Xsig(&Denom, 2 - (1 + exponent));
       Denom.msw |= 0x80000000;
diff -u --recursive --new-file v2.1.72/linux/arch/i386/math-emu/poly_sin.c linux/arch/i386/math-emu/poly_sin.c
--- v2.1.72/linux/arch/i386/math-emu/poly_sin.c	Sun Jul 31 22:19:15 1994
+++ linux/arch/i386/math-emu/poly_sin.c	Tue Dec  9 17:57:09 1997
@@ -4,9 +4,9 @@
  |  Computation of an approximation of the sin function and the cosine       |
  |  function by a polynomial.                                                |
  |                                                                           |
- | Copyright (C) 1992,1993,1994                                              |
- |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
- |                       Australia.  E-mail   billm@vaxc.cc.monash.edu.au    |
+ | Copyright (C) 1992,1993,1994,1997                                         |
+ |                  W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
+ |                  E-mail   billm@suburbia.net                              |
  |                                                                           |
  |                                                                           |
  +---------------------------------------------------------------------------*/
@@ -15,6 +15,7 @@
 #include "exception.h"
 #include "reg_constant.h"
 #include "fpu_emu.h"
+#include "fpu_system.h"
 #include "control_w.h"
 #include "poly.h"
 
@@ -62,35 +63,26 @@
 /*--- poly_sine() -----------------------------------------------------------+
  |                                                                           |
  +---------------------------------------------------------------------------*/
-void	poly_sine(FPU_REG const *arg, FPU_REG *result)
+void	poly_sine(FPU_REG *st0_ptr)
 {
   int                 exponent, echange;
   Xsig                accumulator, argSqrd, argTo4;
   unsigned long       fix_up, adj;
   unsigned long long  fixed_arg;
+  FPU_REG	      result;
 
-
-#ifdef PARANOID
-  if ( arg->tag == TW_Zero )
-    {
-      /* Return 0.0 */
-      reg_move(&CONST_Z, result);
-      return;
-    }
-#endif PARANOID
-
-  exponent = arg->exp - EXP_BIAS;
+  exponent = exponent(st0_ptr);
 
   accumulator.lsw = accumulator.midw = accumulator.msw = 0;
 
   /* Split into two ranges, for arguments below and above 1.0 */
   /* The boundary between upper and lower is approx 0.88309101259 */
-  if ( (exponent < -1) || ((exponent == -1) && (arg->sigh <= 0xe21240aa)) )
+  if ( (exponent < -1) || ((exponent == -1) && (st0_ptr->sigh <= 0xe21240aa)) )
     {
       /* The argument is <= 0.88309101259 */
 
-      argSqrd.msw = arg->sigh; argSqrd.midw = arg->sigl; argSqrd.lsw = 0;
-      mul64_Xsig(&argSqrd, &significand(arg));
+      argSqrd.msw = st0_ptr->sigh; argSqrd.midw = st0_ptr->sigl; argSqrd.lsw = 0;
+      mul64_Xsig(&argSqrd, &significand(st0_ptr));
       shr_Xsig(&argSqrd, 2*(-1-exponent));
       argTo4.msw = argSqrd.msw; argTo4.midw = argSqrd.midw;
       argTo4.lsw = argSqrd.lsw;
@@ -107,29 +99,29 @@
       shr_Xsig(&accumulator, 2);    /* Divide by four */
       accumulator.msw |= 0x80000000;  /* Add 1.0 */
 
-      mul64_Xsig(&accumulator, &significand(arg));
-      mul64_Xsig(&accumulator, &significand(arg));
-      mul64_Xsig(&accumulator, &significand(arg));
+      mul64_Xsig(&accumulator, &significand(st0_ptr));
+      mul64_Xsig(&accumulator, &significand(st0_ptr));
+      mul64_Xsig(&accumulator, &significand(st0_ptr));
 
       /* Divide by four, FPU_REG compatible, etc */
-      exponent = 3*exponent + EXP_BIAS;
+      exponent = 3*exponent;
 
       /* The minimum exponent difference is 3 */
-      shr_Xsig(&accumulator, arg->exp - exponent);
+      shr_Xsig(&accumulator, exponent(st0_ptr) - exponent);
 
       negate_Xsig(&accumulator);
-      XSIG_LL(accumulator) += significand(arg);
+      XSIG_LL(accumulator) += significand(st0_ptr);
 
       echange = round_Xsig(&accumulator);
 
-      result->exp = arg->exp + echange;
+      setexponentpos(&result, exponent(st0_ptr) + echange);
     }
   else
     {
       /* The argument is > 0.88309101259 */
-      /* We use sin(arg) = cos(pi/2-arg) */
+      /* We use sin(st(0)) = cos(pi/2-st(0)) */
 
-      fixed_arg = significand(arg);
+      fixed_arg = significand(st0_ptr);
 
       if ( exponent == 0 )
 	{
@@ -192,16 +184,16 @@
 
       echange = round_Xsig(&accumulator);
 
-      result->exp = EXP_BIAS - 1 + echange;
+      setexponentpos(&result, echange - 1);
     }
 
-  significand(result) = XSIG_LL(accumulator);
-  result->tag = TW_Valid;
-  result->sign = arg->sign;
+  significand(&result) = XSIG_LL(accumulator);
+  setsign(&result, getsign(st0_ptr));
+  FPU_copy_to_reg0(&result, TAG_Valid);
 
 #ifdef PARANOID
-  if ( (result->exp >= EXP_BIAS)
-      && (significand(result) > 0x8000000000000000LL) )
+  if ( (exponent(&result) >= 0)
+      && (significand(&result) > 0x8000000000000000LL) )
     {
       EXCEPTION(EX_INTERNAL|0x150);
     }
@@ -214,42 +206,36 @@
 /*--- poly_cos() ------------------------------------------------------------+
  |                                                                           |
  +---------------------------------------------------------------------------*/
-void	poly_cos(FPU_REG const *arg, FPU_REG *result)
+void	poly_cos(FPU_REG *st0_ptr)
 {
+  FPU_REG	      result;
   long int            exponent, exp2, echange;
   Xsig                accumulator, argSqrd, fix_up, argTo4;
   unsigned long       adj;
   unsigned long long  fixed_arg;
 
-
 #ifdef PARANOID
-  if ( arg->tag == TW_Zero )
-    {
-      /* Return 1.0 */
-      reg_move(&CONST_1, result);
-      return;
-    }
-
-  if ( (arg->exp > EXP_BIAS)
-      || ((arg->exp == EXP_BIAS)
-	  && (significand(arg) > 0xc90fdaa22168c234LL)) )
+  if ( (exponent(st0_ptr) > 0)
+      || ((exponent(st0_ptr) == 0)
+	  && (significand(st0_ptr) > 0xc90fdaa22168c234LL)) )
     {
       EXCEPTION(EX_Invalid);
-      reg_move(&CONST_QNaN, result);
+      FPU_copy_to_reg0(&CONST_QNaN, TAG_Special);
       return;
     }
 #endif PARANOID
 
-  exponent = arg->exp - EXP_BIAS;
+  exponent = exponent(st0_ptr);
 
   accumulator.lsw = accumulator.midw = accumulator.msw = 0;
 
-  if ( (exponent < -1) || ((exponent == -1) && (arg->sigh <= 0xb00d6f54)) )
+  if ( (exponent < -1) || ((exponent == -1) && (st0_ptr->sigh <= 0xb00d6f54)) )
     {
       /* arg is < 0.687705 */
 
-      argSqrd.msw = arg->sigh; argSqrd.midw = arg->sigl; argSqrd.lsw = 0;
-      mul64_Xsig(&argSqrd, &significand(arg));
+      argSqrd.msw = st0_ptr->sigh; argSqrd.midw = st0_ptr->sigl;
+      argSqrd.lsw = 0;
+      mul64_Xsig(&argSqrd, &significand(st0_ptr));
 
       if ( exponent < -1 )
 	{
@@ -270,8 +256,8 @@
 		      N_COEFF_PH-1);
       negate_Xsig(&accumulator);
 
-      mul64_Xsig(&accumulator, &significand(arg));
-      mul64_Xsig(&accumulator, &significand(arg));
+      mul64_Xsig(&accumulator, &significand(st0_ptr));
+      mul64_Xsig(&accumulator, &significand(st0_ptr));
       shr_Xsig(&accumulator, -2*(1+exponent));
 
       shr_Xsig(&accumulator, 3);
@@ -290,20 +276,20 @@
       if ( accumulator.msw == 0 )
 	{
 	  /* The result is 1.0 */
-	  reg_move(&CONST_1, result);
+	  FPU_copy_to_reg0(&CONST_1, TAG_Valid);
+	  return;
 	}
       else
 	{
-	  significand(result) = XSIG_LL(accumulator);
+	  significand(&result) = XSIG_LL(accumulator);
       
 	  /* will be a valid positive nr with expon = -1 */
-	  *(short *)&(result->sign) = 0;
-	  result->exp = EXP_BIAS - 1;
+	  setexponentpos(&result, -1);
 	}
     }
   else
     {
-      fixed_arg = significand(arg);
+      fixed_arg = significand(st0_ptr);
 
       if ( exponent == 0 )
 	{
@@ -392,14 +378,15 @@
 
       echange = round_Xsig(&accumulator);
 
-      result->exp = exp2 + EXP_BIAS + echange;
-      *(short *)&(result->sign) = 0;      /* Is a valid positive nr */
-      significand(result) = XSIG_LL(accumulator);
+      setexponentpos(&result, exp2 + echange);
+      significand(&result) = XSIG_LL(accumulator);
     }
 
+  FPU_copy_to_reg0(&result, TAG_Valid);
+
 #ifdef PARANOID
-  if ( (result->exp >= EXP_BIAS)
-      && (significand(result) > 0x8000000000000000LL) )
+  if ( (exponent(&result) >= 0)
+      && (significand(&result) > 0x8000000000000000LL) )
     {
       EXCEPTION(EX_INTERNAL|0x151);
     }
diff -u --recursive --new-file v2.1.72/linux/arch/i386/math-emu/poly_tan.c linux/arch/i386/math-emu/poly_tan.c
--- v2.1.72/linux/arch/i386/math-emu/poly_tan.c	Thu Aug 18 22:54:01 1994
+++ linux/arch/i386/math-emu/poly_tan.c	Tue Dec  9 17:57:09 1997
@@ -3,9 +3,9 @@
  |                                                                           |
  | Compute the tan of a FPU_REG, using a polynomial approximation.           |
  |                                                                           |
- | Copyright (C) 1992,1993,1994                                              |
+ | Copyright (C) 1992,1993,1994,1997                                         |
  |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
- |                       Australia.  E-mail   billm@vaxc.cc.monash.edu.au    |
+ |                       Australia.  E-mail   billm@suburbia.net             |
  |                                                                           |
  |                                                                           |
  +---------------------------------------------------------------------------*/
@@ -13,6 +13,7 @@
 #include "exception.h"
 #include "reg_constant.h"
 #include "fpu_emu.h"
+#include "fpu_system.h"
 #include "control_w.h"
 #include "poly.h"
 
@@ -52,7 +53,7 @@
 /*--- poly_tan() ------------------------------------------------------------+
  |                                                                           |
  +---------------------------------------------------------------------------*/
-void	poly_tan(FPU_REG const *arg, FPU_REG *result)
+void	poly_tan(FPU_REG *st0_ptr)
 {
   long int    		exponent;
   int                   invert;
@@ -60,20 +61,20 @@
                         argSignif, fix_up;
   unsigned long         adj;
 
-  exponent = arg->exp - EXP_BIAS;
+  exponent = exponent(st0_ptr);
 
 #ifdef PARANOID
-  if ( arg->sign != 0 )	/* Can't hack a number < 0.0 */
-    { arith_invalid(result); return; }  /* Need a positive number */
+  if ( signnegative(st0_ptr) )	/* Can't hack a number < 0.0 */
+    { arith_invalid(0); return; }  /* Need a positive number */
 #endif PARANOID
 
   /* Split the problem into two domains, smaller and larger than pi/4 */
-  if ( (exponent == 0) || ((exponent == -1) && (arg->sigh > 0xc90fdaa2)) )
+  if ( (exponent == 0) || ((exponent == -1) && (st0_ptr->sigh > 0xc90fdaa2)) )
     {
       /* The argument is greater than (approx) pi/4 */
       invert = 1;
       accum.lsw = 0;
-      XSIG_LL(accum) = significand(arg);
+      XSIG_LL(accum) = significand(st0_ptr);
  
       if ( exponent == 0 )
 	{
@@ -92,12 +93,12 @@
     {
       invert = 0;
       argSignif.lsw = 0;
-      XSIG_LL(accum) = XSIG_LL(argSignif) = significand(arg);
+      XSIG_LL(accum) = XSIG_LL(argSignif) = significand(st0_ptr);
  
       if ( exponent < -1 )
 	{
 	  /* shift the argument right by the required places */
-	  if ( shrx(&XSIG_LL(accum), -1-exponent) >= 0x80000000U )
+	  if ( FPU_shrx(&XSIG_LL(accum), -1-exponent) >= 0x80000000U )
 	    XSIG_LL(accum) ++;	/* round up */
 	}
     }
@@ -206,8 +207,8 @@
 
   /* Transfer the result */
   round_Xsig(&accum);
-  *(short *)&(result->sign) = 0;
-  significand(result) = XSIG_LL(accum);
-  result->exp = EXP_BIAS + exponent;
+  FPU_settag0(TAG_Valid);
+  significand(st0_ptr) = XSIG_LL(accum);
+  setexponent16(st0_ptr, exponent + EXTENDED_Ebias);  /* Result is positive. */
 
 }
diff -u --recursive --new-file v2.1.72/linux/arch/i386/math-emu/reg_add_sub.c linux/arch/i386/math-emu/reg_add_sub.c
--- v2.1.72/linux/arch/i386/math-emu/reg_add_sub.c	Wed Dec  1 04:44:16 1993
+++ linux/arch/i386/math-emu/reg_add_sub.c	Tue Dec  9 17:57:09 1997
@@ -3,16 +3,19 @@
  |                                                                           |
  | Functions to add or subtract two registers and put the result in a third. |
  |                                                                           |
- | Copyright (C) 1992,1993                                                   |
- |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
- |                       Australia.  E-mail   billm@vaxc.cc.monash.edu.au    |
+ | Copyright (C) 1992,1993,1997                                              |
+ |                  W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
+ |                  E-mail   billm@suburbia.net                              |
  |                                                                           |
  |                                                                           |
  +---------------------------------------------------------------------------*/
 
 /*---------------------------------------------------------------------------+
- | For each function, the destination may be any FPU_REG, including one of   |
+ |  For each function, the destination may be any FPU_REG, including one of  |
  | the source FPU_REGs.                                                      |
+ |  Each function returns 0 if the answer is o.k., otherwise a non-zero      |
+ | value is returned, indicating either an exception condition or an         |
+ | internal error.                                                           |
  +---------------------------------------------------------------------------*/
 
 #include "exception.h"
@@ -21,156 +24,164 @@
 #include "control_w.h"
 #include "fpu_system.h"
 
+static
+int add_sub_specials(FPU_REG const *a, u_char taga, u_char signa,
+		     FPU_REG const *b, u_char tagb, u_char signb,
+		     FPU_REG *dest, int deststnr, int control_w);
 
-int reg_add(FPU_REG const *a, FPU_REG const *b, FPU_REG *dest, int control_w)
+/*
+  Operates on st(0) and st(n), or on st(0) and temporary data.
+  The destination must be one of the source st(x).
+  */
+int FPU_add(FPU_REG const *b, u_char tagb, int deststnr, int control_w)
 {
-  char saved_sign = dest->sign;
-  int diff;
+  FPU_REG *a = &st(0);
+  FPU_REG *dest = &st(deststnr);
+  u_char signb = getsign(b);
+  u_char taga = FPU_gettag0();
+  u_char signa = getsign(a);
+  u_char saved_sign = getsign(dest);
+  int diff, tag, expa, expb;
   
-  if ( !(a->tag | b->tag) )
+  if ( !(taga | tagb) )
     {
+      expa = exponent(a);
+      expb = exponent(b);
+
+    valid_add:
       /* Both registers are valid */
-      if (!(a->sign ^ b->sign))
+      if (!(signa ^ signb))
 	{
 	  /* signs are the same */
-	  dest->sign = a->sign;
-	  if ( reg_u_add(a, b, dest, control_w) )
-	    {
-	      dest->sign = saved_sign;
-	      return 1;
-	    }
-	  return 0;
+	  tag = FPU_u_add(a, b, dest, control_w, signa, expa, expb);
 	}
-      
-      /* The signs are different, so do a subtraction */
-      diff = a->exp - b->exp;
-      if (!diff)
+      else
 	{
-	  diff = a->sigh - b->sigh;  /* Works only if ms bits are identical */
+	  /* The signs are different, so do a subtraction */
+	  diff = expa - expb;
 	  if (!diff)
 	    {
-	      diff = a->sigl > b->sigl;
+	      diff = a->sigh - b->sigh;  /* This works only if the ms bits
+					    are identical. */
 	      if (!diff)
-		diff = -(a->sigl < b->sigl);
-	    }
-	}
-      
-      if (diff > 0)
-	{
-	  dest->sign = a->sign;
-	  if ( reg_u_sub(a, b, dest, control_w) )
-	    {
-	      dest->sign = saved_sign;
-	      return 1;
-	    }
-	}
-      else if ( diff == 0 )
-	{
-#ifdef DENORM_OPERAND
-	  if ( (b->tag == TW_Valid) && (b->exp <= EXP_UNDER) &&
-	      denormal_operand() )
-	    return 1;
-#endif DENORM_OPERAND
-	  reg_move(&CONST_Z, dest);
-	  /* sign depends upon rounding mode */
-	  dest->sign = ((control_w & CW_RC) != RC_DOWN)
-	    ? SIGN_POS : SIGN_NEG;
-	}
-      else
-	{
-	  dest->sign = b->sign;
-	  if ( reg_u_sub(b, a, dest, control_w) )
-	    {
-	      dest->sign = saved_sign;
-	      return 1;
-	    }
-	}
-      return 0;
-    }
-  else
-    {
-      if ( (a->tag == TW_NaN) || (b->tag == TW_NaN) )
-	{ return real_2op_NaN(a, b, dest); }
-      else if (a->tag == TW_Zero)
-	{
-	  if (b->tag == TW_Zero)
-	    {
-	      char different_signs = a->sign ^ b->sign;
-	      /* Both are zero, result will be zero. */
-	      reg_move(a, dest);
-	      if (different_signs)
 		{
-		  /* Signs are different. */
-		  /* Sign of answer depends upon rounding mode. */
-		  dest->sign = ((control_w & CW_RC) != RC_DOWN)
-		    ? SIGN_POS : SIGN_NEG;
+		  diff = a->sigl > b->sigl;
+		  if (!diff)
+		    diff = -(a->sigl < b->sigl);
 		}
 	    }
-	  else
+      
+	  if (diff > 0)
 	    {
-#ifdef DENORM_OPERAND
-	      if ( (b->tag == TW_Valid) && (b->exp <= EXP_UNDER) &&
-		  denormal_operand() )
-		return 1;
-#endif DENORM_OPERAND
-	      reg_move(b, dest);
+	      tag = FPU_u_sub(a, b, dest, control_w, signa, expa, expb);
 	    }
-	  return 0;
-	}
-      else if (b->tag == TW_Zero)
-	{
-#ifdef DENORM_OPERAND
-	  if ( (a->tag == TW_Valid) && (a->exp <= EXP_UNDER) &&
-	      denormal_operand() )
-	    return 1;
-#endif DENORM_OPERAND
-	  reg_move(a, dest); return 0;
-	}
-      else if (a->tag == TW_Infinity)
-	{
-	  if (b->tag != TW_Infinity)
+	  else if ( diff < 0 )
 	    {
-#ifdef DENORM_OPERAND
-	      if ( (b->tag == TW_Valid) && (b->exp <= EXP_UNDER) &&
-		  denormal_operand() )
-		return 1;
-#endif DENORM_OPERAND
-	      reg_move(a, dest); return 0;
+	      tag = FPU_u_sub(b, a, dest, control_w, signb, expb, expa);
 	    }
-	  if (a->sign == b->sign)
+	  else
 	    {
-	      /* They are both + or - infinity */
-	      reg_move(a, dest); return 0;
+	      FPU_copy_to_regi(&CONST_Z, TAG_Zero, deststnr);
+	      /* sign depends upon rounding mode */
+	      setsign(dest, ((control_w & CW_RC) != RC_DOWN)
+		      ? SIGN_POS : SIGN_NEG);
+	      return TAG_Zero;
 	    }
-	  return arith_invalid(dest);	/* Infinity-Infinity is undefined. */
 	}
-      else if (b->tag == TW_Infinity)
+
+      if ( tag < 0 )
 	{
-#ifdef DENORM_OPERAND
-	  if ( (a->tag == TW_Valid) && (a->exp <= EXP_UNDER) &&
-	      denormal_operand() )
-	    return 1;
-#endif DENORM_OPERAND
-	  reg_move(b, dest); return 0;
+	  setsign(dest, saved_sign);
+	  return tag;
 	}
+      FPU_settagi(deststnr, tag);
+      return tag;
     }
-#ifdef PARANOID
-  EXCEPTION(EX_INTERNAL|0x101);
-#endif
-  return 1;
+
+  if ( taga == TAG_Special )
+    taga = FPU_Special(a);
+  if ( tagb == TAG_Special )
+    tagb = FPU_Special(b);
+
+  if ( ((taga == TAG_Valid) && (tagb == TW_Denormal))
+	    || ((taga == TW_Denormal) && (tagb == TAG_Valid))
+	    || ((taga == TW_Denormal) && (tagb == TW_Denormal)) )
+    {
+      FPU_REG x, y;
+
+      if ( denormal_operand() < 0 )
+	return FPU_Exception;
+
+      FPU_to_exp16(a, &x);
+      FPU_to_exp16(b, &y);
+      a = &x;
+      b = &y;
+      expa = exponent16(a);
+      expb = exponent16(b);
+      goto valid_add;
+    }
+
+  if ( (taga == TW_NaN) || (tagb == TW_NaN) )
+    {
+      if ( deststnr == 0 )
+	return real_2op_NaN(b, tagb, deststnr, a);
+      else
+	return real_2op_NaN(a, taga, deststnr, a);
+    }
+
+  return add_sub_specials(a, taga, signa, b, tagb, signb,
+			  dest, deststnr, control_w);
 }
 
 
 /* Subtract b from a.  (a-b) -> dest */
-int reg_sub(FPU_REG const *a, FPU_REG const *b, FPU_REG *dest, int control_w)
+int FPU_sub(int flags, int rm, int control_w)
 {
-  char saved_sign = dest->sign;
-  int diff;
+  FPU_REG const *a, *b;
+  FPU_REG *dest;
+  u_char taga, tagb, signa, signb, saved_sign, sign;
+  int diff, tag, expa, expb, deststnr;
+
+  a = &st(0);
+  taga = FPU_gettag0();
+
+  deststnr = 0;
+  if ( flags & LOADED )
+    {
+      b = (FPU_REG *)rm;
+      tagb = flags & 0x0f;
+    }
+  else
+    {
+      b = &st(rm);
+      tagb = FPU_gettagi(rm);
+
+      if ( flags & DEST_RM )
+	deststnr = rm;
+    }
+
+  signa = getsign(a);
+  signb = getsign(b);
+
+  if ( flags & REV )
+    {
+      signa ^= SIGN_NEG;
+      signb ^= SIGN_NEG;
+    }
 
-  if ( !(a->tag | b->tag) )
+  dest = &st(deststnr);
+  saved_sign = getsign(dest);
+
+  if ( !(taga | tagb) )
     {
+      expa = exponent(a);
+      expb = exponent(b);
+
+    valid_subtract:
       /* Both registers are valid */
-      diff = a->exp - b->exp;
+
+      diff = expa - expb;
+
       if (!diff)
 	{
 	  diff = a->sigh - b->sigh;  /* Works only if ms bits are identical */
@@ -182,137 +193,182 @@
 	    }
 	}
 
-      switch (a->sign*2 + b->sign)
+      switch ( (((int)signa)*2 + signb) / SIGN_NEG )
 	{
 	case 0: /* P - P */
 	case 3: /* N - N */
 	  if (diff > 0)
 	    {
 	      /* |a| > |b| */
-	      dest->sign = a->sign;
-	      if ( reg_u_sub(a, b, dest, control_w) )
-		{
-		  dest->sign = saved_sign;
-		  return 1;
-		}
-	      return 0;
+	      tag = FPU_u_sub(a, b, dest, control_w, signa, expa, expb);
 	    }
 	  else if ( diff == 0 )
 	    {
-#ifdef DENORM_OPERAND
-	      if ( (b->tag == TW_Valid) && (b->exp <= EXP_UNDER) &&
-		  denormal_operand() )
-		return 1;
-#endif DENORM_OPERAND
-	      reg_move(&CONST_Z, dest);
+	      FPU_copy_to_regi(&CONST_Z, TAG_Zero, deststnr);
+
 	      /* sign depends upon rounding mode */
-	      dest->sign = ((control_w & CW_RC) != RC_DOWN)
-		? SIGN_POS : SIGN_NEG;
+	      setsign(dest, ((control_w & CW_RC) != RC_DOWN)
+		? SIGN_POS : SIGN_NEG);
+	      return TAG_Zero;
 	    }
 	  else
 	    {
-	      dest->sign = a->sign ^ SIGN_POS^SIGN_NEG;
-	      if ( reg_u_sub(b, a, dest, control_w) )
-		{
-		  dest->sign = saved_sign;
-		  return 1;
-		}
+	      sign = signa ^ SIGN_NEG;
+	      tag = FPU_u_sub(b, a, dest, control_w, sign, expb, expa);
 	    }
 	  break;
 	case 1: /* P - N */
-	  dest->sign = SIGN_POS;
-	  if ( reg_u_add(a, b, dest, control_w) )
-	    {
-	      dest->sign = saved_sign;
-	      return 1;
-	    }
+	  tag = FPU_u_add(a, b, dest, control_w, SIGN_POS, expa, expb);
 	  break;
 	case 2: /* N - P */
-	  dest->sign = SIGN_NEG;
-	  if ( reg_u_add(a, b, dest, control_w) )
-	    {
-	      dest->sign = saved_sign;
-	      return 1;
-	    }
+	  tag = FPU_u_add(a, b, dest, control_w, SIGN_NEG, expa, expb);
 	  break;
+#ifdef PARANOID
+	default:
+	  EXCEPTION(EX_INTERNAL|0x111);
+	  return -1;
+#endif
+	}
+      if ( tag < 0 )
+	{
+	  setsign(dest, saved_sign);
+	  return tag;
 	}
-      return 0;
+      FPU_settagi(deststnr, tag);
+      return tag;
     }
-  else
+
+  if ( taga == TAG_Special )
+    taga = FPU_Special(a);
+  if ( tagb == TAG_Special )
+    tagb = FPU_Special(b);
+
+  if ( ((taga == TAG_Valid) && (tagb == TW_Denormal))
+	    || ((taga == TW_Denormal) && (tagb == TAG_Valid))
+	    || ((taga == TW_Denormal) && (tagb == TW_Denormal)) )
     {
-      if ( (a->tag == TW_NaN) || (b->tag == TW_NaN) )
-	{ return real_2op_NaN(b, a, dest); }
-      else if (b->tag == TW_Zero)
-	{ 
-	  if (a->tag == TW_Zero)
-	    {
-	      char same_signs = !(a->sign ^ b->sign);
-	      /* Both are zero, result will be zero. */
-	      reg_move(a, dest); /* Answer for different signs. */
-	      if (same_signs)
-		{
-		  /* Sign depends upon rounding mode */
-		  dest->sign = ((control_w & CW_RC) != RC_DOWN)
-		    ? SIGN_POS : SIGN_NEG;
-		}
-	    }
-	  else
-	    {
-#ifdef DENORM_OPERAND
-	      if ( (a->tag == TW_Valid) && (a->exp <= EXP_UNDER) &&
-		  denormal_operand() )
-		return 1;
-#endif DENORM_OPERAND
-	      reg_move(a, dest);
-	    }
-	  return 0;
+      FPU_REG x, y;
+
+      if ( denormal_operand() < 0 )
+	return FPU_Exception;
+
+      FPU_to_exp16(a, &x);
+      FPU_to_exp16(b, &y);
+      a = &x;
+      b = &y;
+      expa = exponent16(a);
+      expb = exponent16(b);
+
+      goto valid_subtract;
+    }
+
+  if ( (taga == TW_NaN) || (tagb == TW_NaN) )
+    {
+      FPU_REG const *d1, *d2;
+      if ( flags & REV )
+	{
+	  d1 = b;
+	  d2 = a;
 	}
-      else if (a->tag == TW_Zero)
+      else
 	{
-#ifdef DENORM_OPERAND
-	  if ( (b->tag == TW_Valid) && (b->exp <= EXP_UNDER) &&
-	      denormal_operand() )
-	    return 1;
-#endif DENORM_OPERAND
-	  reg_move(b, dest);
-	  dest->sign ^= SIGN_POS^SIGN_NEG;
-	  return 0;
+	  d1 = a;
+	  d2 = b;
 	}
-      else if (a->tag == TW_Infinity)
+      if ( flags & LOADED )
+	return real_2op_NaN(b, tagb, deststnr, d1);
+      if ( flags & DEST_RM )
+	return real_2op_NaN(a, taga, deststnr, d2);
+      else
+	return real_2op_NaN(b, tagb, deststnr, d2);
+    }
+
+    return add_sub_specials(a, taga, signa, b, tagb, signb ^ SIGN_NEG,
+			    dest, deststnr, control_w);
+}
+
+
+static
+int add_sub_specials(FPU_REG const *a, u_char taga, u_char signa,
+		     FPU_REG const *b, u_char tagb, u_char signb,
+		     FPU_REG *dest, int deststnr, int control_w)
+{
+  if ( ((taga == TW_Denormal) || (tagb == TW_Denormal))
+       && (denormal_operand() < 0) )
+    return FPU_Exception;
+
+  if (taga == TAG_Zero)
+    {
+      if (tagb == TAG_Zero)
 	{
-	  if (b->tag != TW_Infinity)
+	  /* Both are zero, result will be zero. */
+	  u_char different_signs = signa ^ signb;
+
+	  FPU_copy_to_regi(a, TAG_Zero, deststnr);
+	  if ( different_signs )
 	    {
-#ifdef DENORM_OPERAND
-	      if ( (b->tag == TW_Valid) && (b->exp <= EXP_UNDER) &&
-		  denormal_operand() )
-		return 1;
-#endif DENORM_OPERAND
-	      reg_move(a, dest); return 0;
+	      /* Signs are different. */
+	      /* Sign of answer depends upon rounding mode. */
+	      setsign(dest, ((control_w & CW_RC) != RC_DOWN)
+		      ? SIGN_POS : SIGN_NEG);
 	    }
-	  /* Both args are Infinity */
-	  if (a->sign == b->sign)
+	  else
+	    setsign(dest, signa);  /* signa may differ from the sign of a. */
+	  return TAG_Zero;
+	}
+      else
+	{
+	  reg_copy(b, dest);
+	  if ( (tagb == TW_Denormal) && (b->sigh & 0x80000000) )
 	    {
-	      /* Infinity-Infinity is undefined. */
-	      return arith_invalid(dest);
-	    }
-	  reg_move(a, dest);
-	  return 0;
+	      /* A pseudoDenormal, convert it. */
+	      addexponent(dest, 1);
+	      tagb = TAG_Valid;
+	    }
+	  else if ( tagb > TAG_Empty )
+	    tagb = TAG_Special;
+	  setsign(dest, signb);  /* signb may differ from the sign of b. */
+	  FPU_settagi(deststnr, tagb);
+	  return tagb;
 	}
-      else if (b->tag == TW_Infinity)
+    }
+  else if (tagb == TAG_Zero)
+    {
+      reg_copy(a, dest);
+      if ( (taga == TW_Denormal) && (a->sigh & 0x80000000) )
 	{
-#ifdef DENORM_OPERAND
-	  if ( (a->tag == TW_Valid) && (a->exp <= EXP_UNDER) &&
-	      denormal_operand() )
-	    return 1;
-#endif DENORM_OPERAND
-	  reg_move(b, dest);
-	  dest->sign ^= SIGN_POS^SIGN_NEG;
-	  return 0;
+	  /* A pseudoDenormal */
+	  addexponent(dest, 1);
+	  taga = TAG_Valid;
+	}
+      else if ( taga > TAG_Empty )
+	taga = TAG_Special;
+      setsign(dest, signa);  /* signa may differ from the sign of a. */
+      FPU_settagi(deststnr, taga);
+      return taga;
+    }
+  else if (taga == TW_Infinity)
+    {
+      if ( (tagb != TW_Infinity) || (signa == signb) )
+	{
+	  FPU_copy_to_regi(a, TAG_Special, deststnr);
+	  setsign(dest, signa);  /* signa may differ from the sign of a. */
+	  return taga;
 	}
+      /* Infinity-Infinity is undefined. */
+      return arith_invalid(deststnr);
+    }
+  else if (tagb == TW_Infinity)
+    {
+      FPU_copy_to_regi(b, TAG_Special, deststnr);
+      setsign(dest, signb);  /* signb may differ from the sign of b. */
+      return tagb;
     }
+
 #ifdef PARANOID
-  EXCEPTION(EX_INTERNAL|0x110);
+  EXCEPTION(EX_INTERNAL|0x101);
 #endif
-  return 1;
+
+  return FPU_Exception;
 }
 
diff -u --recursive --new-file v2.1.72/linux/arch/i386/math-emu/reg_compare.c linux/arch/i386/math-emu/reg_compare.c
--- v2.1.72/linux/arch/i386/math-emu/reg_compare.c	Thu Jun  2 00:28:27 1994
+++ linux/arch/i386/math-emu/reg_compare.c	Tue Dec  9 17:57:09 1997
@@ -3,9 +3,9 @@
  |                                                                           |
  | Compare two floating point registers                                      |
  |                                                                           |
- | Copyright (C) 1992,1993,1994                                              |
- |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
- |                       Australia.  E-mail   billm@vaxc.cc.monash.edu.au    |
+ | Copyright (C) 1992,1993,1994,1997                                         |
+ |                  W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
+ |                  E-mail   billm@suburbia.net                              |
  |                                                                           |
  |                                                                           |
  +---------------------------------------------------------------------------*/
@@ -21,86 +21,87 @@
 #include "status_w.h"
 
 
-int compare(FPU_REG const *b)
+static int compare(FPU_REG const *b, int tagb)
 {
-  int diff;
-  char	       st0_tag;
-  FPU_REG      *st0_ptr;
+  int diff, exp0, expb;
+  u_char	  	st0_tag;
+  FPU_REG  	*st0_ptr;
+  FPU_REG	x, y;
+  u_char		st0_sign, signb = getsign(b);
 
   st0_ptr = &st(0);
-  st0_tag = st0_ptr->tag;
+  st0_tag = FPU_gettag0();
+  st0_sign = getsign(st0_ptr);
 
-  if ( st0_tag | b->tag )
+  if ( tagb == TAG_Special )
+    tagb = FPU_Special(b);
+  if ( st0_tag == TAG_Special )
+    st0_tag = FPU_Special(st0_ptr);
+
+  if ( ((st0_tag != TAG_Valid) && (st0_tag != TW_Denormal))
+       || ((tagb != TAG_Valid) && (tagb != TW_Denormal)) )
     {
-      if ( st0_tag == TW_Zero )
+      if ( st0_tag == TAG_Zero )
 	{
-	  if ( b->tag == TW_Zero ) return COMP_A_eq_B;
-	  if ( b->tag == TW_Valid )
-	    {
-	      return ((b->sign == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B)
-#ifdef DENORM_OPERAND
-		| ((b->exp <= EXP_UNDER) ?
-		   COMP_Denormal : 0)
-#endif DENORM_OPERAND
-		  ;
-	    }
+	  if ( tagb == TAG_Zero ) return COMP_A_eq_B;
+	  if ( tagb == TAG_Valid )
+	    return ((signb == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B);
+	  if ( tagb == TW_Denormal )
+	    return ((signb == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B)
+	    | COMP_Denormal;
 	}
-      else if ( b->tag == TW_Zero )
+      else if ( tagb == TAG_Zero )
 	{
-	  if ( st0_tag == TW_Valid )
-	    {
-	      return ((st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B
-		      : COMP_A_lt_B)
-#ifdef DENORM_OPERAND
-		| ((st0_ptr->exp <= EXP_UNDER )
-		   ? COMP_Denormal : 0 )
-#endif DENORM_OPERAND
-		  ;
-	    }
+	  if ( st0_tag == TAG_Valid )
+	    return ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B);
+	  if ( st0_tag == TW_Denormal )
+	    return ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
+	    | COMP_Denormal;
 	}
 
       if ( st0_tag == TW_Infinity )
 	{
-	  if ( (b->tag == TW_Valid) || (b->tag == TW_Zero) )
-	    {
-	      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)) ?
-		COMP_Denormal : 0 )
-#endif DENORM_OPERAND
-;
-	    }
-	  else if ( b->tag == TW_Infinity )
+	  if ( (tagb == TAG_Valid) || (tagb == TAG_Zero) )
+	    return ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B);
+	  else if ( tagb == TW_Denormal )
+	    return ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
+	      | COMP_Denormal;
+	  else if ( tagb == TW_Infinity )
 	    {
 	      /* The 80486 book says that infinities can be equal! */
-	      return (st0_ptr->sign == b->sign) ? COMP_A_eq_B :
-		((st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B);
+	      return (st0_sign == signb) ? COMP_A_eq_B :
+		((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B);
 	    }
 	  /* Fall through to the NaN code */
 	}
-      else if ( b->tag == TW_Infinity )
+      else if ( tagb == TW_Infinity )
 	{
-	  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
-		| (((st0_tag == TW_Valid)
-		    && (st0_ptr->exp <= EXP_UNDER)) ?
-		   COMP_Denormal : 0)
-#endif DENORM_OPERAND
-		  ;
-	    }
+	  if ( (st0_tag == TAG_Valid) || (st0_tag == TAG_Zero) )
+	    return ((signb == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B);
+	  if ( st0_tag == TW_Denormal )
+	    return ((signb == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B)
+		| COMP_Denormal;
 	  /* Fall through to the NaN code */
 	}
 
       /* The only possibility now should be that one of the arguments
 	 is a NaN */
-      if ( (st0_tag == TW_NaN) || (b->tag == TW_NaN) )
+      if ( (st0_tag == TW_NaN) || (tagb == TW_NaN) )
 	{
-	  if ( ((st0_tag == TW_NaN) && !(st0_ptr->sigh & 0x40000000))
-	      || ((b->tag == TW_NaN) && !(b->sigh & 0x40000000)) )
-	    /* At least one arg is a signaling NaN */
+	  int signalling = 0, unsupported = 0;
+	  if ( st0_tag == TW_NaN )
+	    {
+	      signalling = (st0_ptr->sigh & 0xc0000000) == 0x80000000;
+	      unsupported = !((exponent(st0_ptr) == EXP_OVER)
+			      && (st0_ptr->sigh & 0x80000000));
+	    }
+	  if ( tagb == TW_NaN )
+	    {
+	      signalling |= (b->sigh & 0xc0000000) == 0x80000000;
+	      unsupported |= !((exponent(b) == EXP_OVER)
+			       && (b->sigh & 0x80000000));
+	    }
+	  if ( signalling || unsupported )
 	    return COMP_No_Comp | COMP_SNaN | COMP_NaN;
 	  else
 	    /* Neither is a signaling NaN */
@@ -110,24 +111,34 @@
       EXCEPTION(EX_Invalid);
     }
   
+  if (st0_sign != signb)
+    {
+      return ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
+	| ( ((st0_tag == TW_Denormal) || (tagb == TW_Denormal)) ?
+	    COMP_Denormal : 0);
+    }
+
+  if ( (st0_tag == TW_Denormal) || (tagb == TW_Denormal) )
+    {
+      FPU_to_exp16(st0_ptr, &x);
+      FPU_to_exp16(b, &y);
+      st0_ptr = &x;
+      b = &y;
+      exp0 = exponent16(st0_ptr);
+      expb = exponent16(b);
+    }
+  else
+    {
+      exp0 = exponent(st0_ptr);
+      expb = exponent(b);
+    }
+
 #ifdef PARANOID
   if (!(st0_ptr->sigh & 0x80000000)) EXCEPTION(EX_Invalid);
   if (!(b->sigh & 0x80000000)) EXCEPTION(EX_Invalid);
 #endif PARANOID
 
-  
-  if (st0_ptr->sign != b->sign)
-    {
-      return ((st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
-#ifdef DENORM_OPERAND
-	|
-	  ( ((st0_ptr->exp <= EXP_UNDER) || (b->exp <= EXP_UNDER)) ?
-	   COMP_Denormal : 0)
-#endif DENORM_OPERAND
-	    ;
-    }
-
-  diff = st0_ptr->exp - b->exp;
+  diff = exp0 - expb;
   if ( diff == 0 )
     {
       diff = st0_ptr->sigh - b->sigh;  /* Works only if ms bits are
@@ -142,42 +153,30 @@
 
   if ( diff > 0 )
     {
-      return ((st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
-#ifdef DENORM_OPERAND
-	|
-	  ( ((st0_ptr->exp <= EXP_UNDER) || (b->exp <= EXP_UNDER)) ?
-	   COMP_Denormal : 0)
-#endif DENORM_OPERAND
-	    ;
+      return ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
+	| ( ((st0_tag == TW_Denormal) || (tagb == TW_Denormal)) ?
+	    COMP_Denormal : 0);
     }
   if ( diff < 0 )
     {
-      return ((st0_ptr->sign == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B)
-#ifdef DENORM_OPERAND
-	|
-	  ( ((st0_ptr->exp <= EXP_UNDER) || (b->exp <= EXP_UNDER)) ?
-	   COMP_Denormal : 0)
-#endif DENORM_OPERAND
-	    ;
+      return ((st0_sign == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B)
+	| ( ((st0_tag == TW_Denormal) || (tagb == TW_Denormal)) ?
+	    COMP_Denormal : 0);
     }
 
   return COMP_A_eq_B
-#ifdef DENORM_OPERAND
-    |
-      ( ((st0_ptr->exp <= EXP_UNDER) || (b->exp <= EXP_UNDER)) ?
-       COMP_Denormal : 0)
-#endif DENORM_OPERAND
-	;
+    | ( ((st0_tag == TW_Denormal) || (tagb == TW_Denormal)) ?
+	COMP_Denormal : 0);
 
 }
 
 
 /* This function requires that st(0) is not empty */
-int compare_st_data(FPU_REG const *loaded_data)
+int FPU_compare_st_data(FPU_REG const *loaded_data, u_char loaded_tag)
 {
   int f, c;
 
-  c = compare(loaded_data);
+  c = compare(loaded_data, loaded_tag);
 
   if (c & COMP_NaN)
     {
@@ -209,7 +208,7 @@
   setcc(f);
   if (c & COMP_Denormal)
     {
-      return denormal_operand();
+      return denormal_operand() < 0;
     }
   return 0;
 }
@@ -218,6 +217,7 @@
 static int compare_st_st(int nr)
 {
   int f, c;
+  FPU_REG *st_ptr;
 
   if ( !NOT_EMPTY(0) || !NOT_EMPTY(nr) )
     {
@@ -227,7 +227,8 @@
       return !(control_word & CW_Invalid);
     }
 
-  c = compare(&st(nr));
+  st_ptr = &st(nr);
+  c = compare(st_ptr, FPU_gettagi(nr));
   if (c & COMP_NaN)
     {
       setcc(SW_C3 | SW_C2 | SW_C0);
@@ -259,7 +260,7 @@
   setcc(f);
   if (c & COMP_Denormal)
     {
-      return denormal_operand();
+      return denormal_operand() < 0;
     }
   return 0;
 }
@@ -268,6 +269,7 @@
 static int compare_u_st_st(int nr)
 {
   int f, c;
+  FPU_REG *st_ptr;
 
   if ( !NOT_EMPTY(0) || !NOT_EMPTY(nr) )
     {
@@ -277,7 +279,8 @@
       return !(control_word & CW_Invalid);
     }
 
-  c = compare(&st(nr));
+  st_ptr = &st(nr);
+  c = compare(st_ptr, FPU_gettagi(nr));
   if (c & COMP_NaN)
     {
       setcc(SW_C3 | SW_C2 | SW_C0);
@@ -314,7 +317,7 @@
   setcc(f);
   if (c & COMP_Denormal)
     {
-      return denormal_operand();
+      return denormal_operand() < 0;
     }
   return 0;
 }
@@ -332,7 +335,7 @@
 {
   /* fcomp st(i) */
   if ( !compare_st_st(FPU_rm) )
-    pop();
+    FPU_pop();
 }
 
 
@@ -361,7 +364,7 @@
 {
   /* fucomp st(i) */
   if ( !compare_u_st_st(FPU_rm) )
-    pop();
+    FPU_pop();
 }
 
 
diff -u --recursive --new-file v2.1.72/linux/arch/i386/math-emu/reg_constant.c linux/arch/i386/math-emu/reg_constant.c
--- v2.1.72/linux/arch/i386/math-emu/reg_constant.c	Tue Mar 19 03:45:01 1996
+++ linux/arch/i386/math-emu/reg_constant.c	Tue Dec  9 17:57:09 1997
@@ -3,9 +3,9 @@
  |                                                                           |
  | All of the constant FPU_REGs                                              |
  |                                                                           |
- | Copyright (C) 1992,1993,1994,1996                                         |
+ | Copyright (C) 1992,1993,1994,1997                                         |
  |                     W. Metzenthen, 22 Parker St, Ormond, Vic 3163,        |
- |                     Australia.  E-mail   billm@jacobi.maths.monash.edu.au |
+ |                     Australia.  E-mail   billm@suburbia.net               |
  |                                                                           |
  |                                                                           |
  +---------------------------------------------------------------------------*/
@@ -17,59 +17,52 @@
 #include "control_w.h"
 
 
-FPU_REG const CONST_1    = { SIGN_POS, TW_Valid, EXP_BIAS,
-			    0x00000000, 0x80000000 };
-FPU_REG const CONST_2    = { SIGN_POS, TW_Valid, EXP_BIAS+1,
-			    0x00000000, 0x80000000 };
-FPU_REG const CONST_HALF = { SIGN_POS, TW_Valid, EXP_BIAS-1,
-			    0x00000000, 0x80000000 };
-FPU_REG const CONST_L2T  = { SIGN_POS, TW_Valid, EXP_BIAS+1,
-			    0xcd1b8afe, 0xd49a784b };
-FPU_REG const CONST_L2E  = { SIGN_POS, TW_Valid, EXP_BIAS,
-			    0x5c17f0bc, 0xb8aa3b29 };
-FPU_REG const CONST_PI   = { SIGN_POS, TW_Valid, EXP_BIAS+1,
-			    0x2168c235, 0xc90fdaa2 };
-FPU_REG const CONST_PI2  = { SIGN_POS, TW_Valid, EXP_BIAS,
-			    0x2168c235, 0xc90fdaa2 };
-FPU_REG const CONST_PI4  = { SIGN_POS, TW_Valid, EXP_BIAS-1,
-			    0x2168c235, 0xc90fdaa2 };
-FPU_REG const CONST_LG2  = { SIGN_POS, TW_Valid, EXP_BIAS-2,
-			    0xfbcff799, 0x9a209a84 };
-FPU_REG const CONST_LN2  = { SIGN_POS, TW_Valid, EXP_BIAS-1,
-			    0xd1cf79ac, 0xb17217f7 };
+#define MAKE_REG(s,e,l,h) { l, h, \
+                            ((EXTENDED_Ebias+(e)) | ((SIGN_##s != 0)*0x8000)) }
+
+FPU_REG const CONST_1    = MAKE_REG(POS, 0, 0x00000000, 0x80000000);
+FPU_REG const CONST_2    = MAKE_REG(POS, 1, 0x00000000, 0x80000000);
+FPU_REG const CONST_HALF = MAKE_REG(POS, -1, 0x00000000, 0x80000000);
+FPU_REG const CONST_L2T  = MAKE_REG(POS, 1, 0xcd1b8afe, 0xd49a784b);
+FPU_REG const CONST_L2E  = MAKE_REG(POS, 0, 0x5c17f0bc, 0xb8aa3b29);
+FPU_REG const CONST_PI   = MAKE_REG(POS, 1, 0x2168c235, 0xc90fdaa2);
+FPU_REG const CONST_PI2  = MAKE_REG(POS, 0, 0x2168c235, 0xc90fdaa2);
+FPU_REG const CONST_PI4  = MAKE_REG(POS, -1, 0x2168c235, 0xc90fdaa2);
+FPU_REG const CONST_LG2  = MAKE_REG(POS, -2, 0xfbcff799, 0x9a209a84);
+FPU_REG const CONST_LN2  = MAKE_REG(POS, -1, 0xd1cf79ac, 0xb17217f7);
 
 /* Extra bits to take pi/2 to more than 128 bits precision. */
-FPU_REG const CONST_PI2extra = { SIGN_NEG, TW_Valid, EXP_BIAS-66,
-			    0xfc8f8cbb, 0xece675d1 };
+FPU_REG const CONST_PI2extra = MAKE_REG(NEG, -66,
+					 0xfc8f8cbb, 0xece675d1);
 
 /* Only the sign (and tag) is used in internal zeroes */
-FPU_REG const CONST_Z    = { SIGN_POS, TW_Zero, EXP_UNDER, 0x0, 0x0 };
+FPU_REG const CONST_Z    = MAKE_REG(POS, EXP_UNDER, 0x0, 0x0);
 
 /* Only the sign and significand (and tag) are used in internal NaNs */
 /* The 80486 never generates one of these 
-FPU_REG const CONST_SNAN = { SIGN_POS, TW_NaN, EXP_OVER, 0x00000001, 0x80000000 };
+FPU_REG const CONST_SNAN = MAKE_REG(POS, EXP_OVER, 0x00000001, 0x80000000);
  */
 /* This is the real indefinite QNaN */
-FPU_REG const CONST_QNaN = { SIGN_NEG, TW_NaN, EXP_OVER, 0x00000000, 0xC0000000 };
+FPU_REG const CONST_QNaN = MAKE_REG(NEG, EXP_OVER, 0x00000000, 0xC0000000);
 
 /* Only the sign (and tag) is used in internal infinities */
-FPU_REG const CONST_INF  = { SIGN_POS, TW_Infinity, EXP_OVER, 0x00000000, 0x80000000 };
-
+FPU_REG const CONST_INF  = MAKE_REG(POS, EXP_OVER, 0x00000000, 0x80000000);
 
 
-static void fld_const(FPU_REG const *c, int adj)
+static void fld_const(FPU_REG const *c, int adj, u_char tag)
 {
   FPU_REG *st_new_ptr;
 
   if ( STACK_OVERFLOW )
     {
-      stack_overflow();
+      FPU_stack_overflow();
       return;
     }
   push();
-  reg_move(c, st_new_ptr);
+  reg_copy(c, st_new_ptr);
   st_new_ptr->sigl += adj;  /* For all our fldxxx constants, we don't need to
 			       borrow or carry. */
+  FPU_settag0(tag);
   clear_C1();
 }
 
@@ -80,37 +73,37 @@
 
 static void fld1(int rc)
 {
-  fld_const(&CONST_1, 0);
+  fld_const(&CONST_1, 0, TAG_Valid);
 }
 
 static void fldl2t(int rc)
 {
-  fld_const(&CONST_L2T, (rc == RC_UP) ? 1 : 0);
+  fld_const(&CONST_L2T, (rc == RC_UP) ? 1 : 0, TAG_Valid);
 }
 
 static void fldl2e(int rc)
 {
-  fld_const(&CONST_L2E, DOWN_OR_CHOP(rc) ? -1 : 0);
+  fld_const(&CONST_L2E, DOWN_OR_CHOP(rc) ? -1 : 0, TAG_Valid);
 }
 
 static void fldpi(int rc)
 {
-  fld_const(&CONST_PI, DOWN_OR_CHOP(rc) ? -1 : 0);
+  fld_const(&CONST_PI, DOWN_OR_CHOP(rc) ? -1 : 0, TAG_Valid);
 }
 
 static void fldlg2(int rc)
 {
-  fld_const(&CONST_LG2, DOWN_OR_CHOP(rc) ? -1 : 0);
+  fld_const(&CONST_LG2, DOWN_OR_CHOP(rc) ? -1 : 0, TAG_Valid);
 }
 
 static void fldln2(int rc)
 {
-  fld_const(&CONST_LN2, DOWN_OR_CHOP(rc) ? -1 : 0);
+  fld_const(&CONST_LN2, DOWN_OR_CHOP(rc) ? -1 : 0, TAG_Valid);
 }
 
 static void fldz(int rc)
 {
-  fld_const(&CONST_Z, 0);
+  fld_const(&CONST_Z, 0, TAG_Zero);
 }
 
 typedef void (*FUNC_RC)(int);
diff -u --recursive --new-file v2.1.72/linux/arch/i386/math-emu/reg_convert.c linux/arch/i386/math-emu/reg_convert.c
--- v2.1.72/linux/arch/i386/math-emu/reg_convert.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/i386/math-emu/reg_convert.c	Tue Dec  9 17:57:09 1997
@@ -0,0 +1,53 @@
+/*---------------------------------------------------------------------------+
+ |  reg_convert.c                                                            |
+ |                                                                           |
+ |  Convert register representation.                                         |
+ |                                                                           |
+ | Copyright (C) 1992,1993,1994,1996,1997                                    |
+ |                  W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
+ |                  E-mail   billm@suburbia.net                              |
+ |                                                                           |
+ |                                                                           |
+ +---------------------------------------------------------------------------*/
+
+#include "exception.h"
+#include "fpu_emu.h"
+
+
+int FPU_to_exp16(FPU_REG const *a, FPU_REG *x)
+{
+  int sign = getsign(a);
+
+  *(long long *)&(x->sigl) = *(const long long *)&(a->sigl);
+
+  /* Set up the exponent as a 16 bit quantity. */
+  setexponent16(x, exponent(a));
+
+  if ( exponent16(x) == EXP_UNDER )
+    {
+      /* The number is a de-normal or pseudodenormal. */
+      /* We only deal with the significand and exponent. */
+
+      if (x->sigh & 0x80000000)
+	{
+	  /* Is a pseudodenormal. */
+	  /* This is non-80486 behaviour because the number
+	     loses its 'denormal' identity. */
+	  addexponent(x, 1);
+	}
+      else
+	{
+	  /* Is a denormal. */
+	  addexponent(x, 1);
+	  FPU_normalize_nuo(x);
+	}
+    }
+
+  if ( !(x->sigh & 0x80000000) )
+    {
+      EXCEPTION(EX_INTERNAL | 0x180);
+    }
+
+  return sign;
+}
+
diff -u --recursive --new-file v2.1.72/linux/arch/i386/math-emu/reg_div.S linux/arch/i386/math-emu/reg_div.S
--- v2.1.72/linux/arch/i386/math-emu/reg_div.S	Thu Oct  5 06:30:43 1995
+++ linux/arch/i386/math-emu/reg_div.S	Wed Dec 31 16:00:00 1969
@@ -1,248 +0,0 @@
-	.file	"reg_div.S"
-/*---------------------------------------------------------------------------+
- |  reg_div.S                                                                |
- |                                                                           |
- | Divide one FPU_REG by another and put the result in a destination FPU_REG.|
- |                                                                           |
- | Copyright (C) 1992,1993,1994,1995                                         |
- |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
- |                       Australia.  E-mail billm@jacobi.maths.monash.edu.au |
- |                                                                           |
- | Call from C as:                                                           |
- |   void reg_div(FPU_REG *a, FPU_REG *b, FPU_REG *dest,                     |
- |                                    unsigned int control_word)             |
- |                                                                           |
- +---------------------------------------------------------------------------*/
-
-#include "exception.h"
-#include "fpu_emu.h"
-
-
-.text
-ENTRY(reg_div)
-	pushl	%ebp
-	movl	%esp,%ebp
-#ifndef NON_REENTRANT_FPU
-	subl	$28,%esp	/* Needed by divide_kernel */
-#endif NON_REENTRANT_FPU
-
-	pushl	%esi
-	pushl	%edi
-	pushl	%ebx
-
-	movl	PARAM1,%esi
-	movl	PARAM2,%ebx
-	movl	PARAM3,%edi
-
-	movb	TAG(%esi),%al
-	orb	TAG(%ebx),%al
-
-	jne	L_div_special		/* Not (both numbers TW_Valid) */
-
-#ifdef DENORM_OPERAND
-/* Check for denormals */
-	cmpl	EXP_UNDER,EXP(%esi)
-	jg	xL_arg1_not_denormal
-
-	call	SYMBOL_NAME(denormal_operand)
-	orl	%eax,%eax
-	jnz	fpu_Arith_exit
-
-xL_arg1_not_denormal:
-	cmpl	EXP_UNDER,EXP(%ebx)
-	jg	xL_arg2_not_denormal
-
-	call	SYMBOL_NAME(denormal_operand)
-	orl	%eax,%eax
-	jnz	fpu_Arith_exit
-
-xL_arg2_not_denormal:
-#endif DENORM_OPERAND
-
-/* Both arguments are TW_Valid */
-	movb	TW_Valid,TAG(%edi)
-
-	movb	SIGN(%esi),%cl
-	cmpb	%cl,SIGN(%ebx)
-	setne	(%edi)	      /* Set the sign, requires SIGN_NEG=1, SIGN_POS=0 */
-
-	movl	EXP(%esi),%edx
-	movl	EXP(%ebx),%eax
-	subl	%eax,%edx
-	addl	EXP_BIAS,%edx
-	movl	%edx,EXP(%edi)
-
-	jmp	SYMBOL_NAME(divide_kernel)
-
-
-/*-----------------------------------------------------------------------*/
-L_div_special:
-	cmpb	TW_NaN,TAG(%esi)	/* A NaN with anything to give NaN */
-	je	L_arg1_NaN
-
-	cmpb	TW_NaN,TAG(%ebx)	/* A NaN with anything to give NaN */
-	jne	L_no_NaN_arg
-
-/* Operations on NaNs */
-L_arg1_NaN:
-L_arg2_NaN:
-	pushl	%edi			/* Destination */
-	pushl	%esi
-	pushl	%ebx			/* Ordering is important here */
-	call	SYMBOL_NAME(real_2op_NaN)
-	jmp	LDiv_exit
-
-/* Invalid operations */
-L_zero_zero:
-L_inf_inf:
-	pushl	%edi			/* Destination */
-	call	SYMBOL_NAME(arith_invalid) /* 0/0 or Infinity/Infinity */
-	jmp	LDiv_exit
-
-L_no_NaN_arg:
-	cmpb	TW_Infinity,TAG(%esi)
-	jne	L_arg1_not_inf
-
-	cmpb	TW_Infinity,TAG(%ebx)
-	je	L_inf_inf		/* invalid operation */
-
-	cmpb	TW_Valid,TAG(%ebx)
-	je	L_inf_valid
-
-#ifdef PARANOID
-	/* arg2 must be zero or valid */
-	cmpb	TW_Zero,TAG(%ebx)
-	ja	L_unknown_tags
-#endif PARANOID
-
-	/* Note that p16-9 says that infinity/0 returns infinity */
-	jmp	L_copy_arg1		/* Answer is Inf */
-
-L_inf_valid:
-#ifdef DENORM_OPERAND
-	cmpl	EXP_UNDER,EXP(%ebx)
-	jg	L_copy_arg1		/* Answer is Inf */
-
-	call	SYMBOL_NAME(denormal_operand)
-	orl	%eax,%eax
-	jnz	fpu_Arith_exit
-#endif DENORM_OPERAND
-
-	jmp	L_copy_arg1		/* Answer is Inf */
-
-L_arg1_not_inf:
-	cmpb	TW_Zero,TAG(%ebx)	/* Priority to div-by-zero error */
-	jne	L_arg2_not_zero
-
-	cmpb	TW_Zero,TAG(%esi)
-	je	L_zero_zero		/* invalid operation */
-
-#ifdef PARANOID
-	/* arg1 must be valid */
-	cmpb	TW_Valid,TAG(%esi)
-	ja	L_unknown_tags
-#endif PARANOID
-
-/* Division by zero error */
-	pushl	%edi			/* destination */
-	movb	SIGN(%esi),%al
-	xorb	SIGN(%ebx),%al
-	pushl	%eax			/* lower 8 bits have the sign */
-	call	SYMBOL_NAME(divide_by_zero)
-	jmp	LDiv_exit
-
-L_arg2_not_zero:
-	cmpb	TW_Infinity,TAG(%ebx)
-	jne	L_arg2_not_inf
-
-#ifdef DENORM_OPERAND
-	cmpb	TW_Valid,TAG(%esi)
-	jne	L_return_zero
-
-	cmpl	EXP_UNDER,EXP(%esi)
-	jg	L_return_zero		/* Answer is zero */
-
-	call	SYMBOL_NAME(denormal_operand)
-	orl	%eax,%eax
-	jnz	fpu_Arith_exit
-#endif DENORM_OPERAND
-
-	jmp	L_return_zero		/* Answer is zero */
-
-L_arg2_not_inf:
-
-#ifdef PARANOID
-	cmpb	TW_Zero,TAG(%esi)
-	jne	L_unknown_tags
-#endif PARANOID
-
-	/* arg1 is zero, arg2 is not Infinity or a NaN */
-
-#ifdef DENORM_OPERAND
-	cmpl	EXP_UNDER,EXP(%ebx)
-	jg	L_copy_arg1		/* Answer is zero */
-
-	call	SYMBOL_NAME(denormal_operand)
-	orl	%eax,%eax
-	jnz	fpu_Arith_exit
-#endif DENORM_OPERAND
-
-L_copy_arg1:
-	movb	TAG(%esi),%ax
-	movb	%ax,TAG(%edi)
-	movl	EXP(%esi),%eax
-	movl	%eax,EXP(%edi)
-	movl	SIGL(%esi),%eax
-	movl	%eax,SIGL(%edi)
-	movl	SIGH(%esi),%eax
-	movl	%eax,SIGH(%edi)
-
-LDiv_set_result_sign:
-	movb	SIGN(%esi),%cl
-	cmpb	%cl,SIGN(%ebx)
-	jne	LDiv_negative_result
-
-	movb	SIGN_POS,SIGN(%edi)
-	xorl	%eax,%eax		/* Valid result */
-	jmp	LDiv_exit
-
-LDiv_negative_result:
-	movb	SIGN_NEG,SIGN(%edi)
-	xorl	%eax,%eax		/* Valid result */
-
-LDiv_exit:
-#ifndef NON_REENTRANT_FPU
-	leal	-40(%ebp),%esp
-#else
-	leal	-12(%ebp),%esp
-#endif NON_REENTRANT_FPU
-
-	popl	%ebx
-	popl	%edi
-	popl	%esi
-	leave
-	ret
-
-
-L_return_zero:
-	xorl	%eax,%eax
-	movl	%eax,SIGH(%edi)
-	movl	%eax,SIGL(%edi)
-	movl	EXP_UNDER,EXP(%edi)
-	movb	TW_Zero,TAG(%edi)
-	jmp	LDiv_set_result_sign
-
-#ifdef PARANOID
-L_unknown_tags:
-	pushl	EX_INTERNAL | 0x208
-	call	EXCEPTION
-
-	/* Generate a NaN for unknown tags */
-	movl	SYMBOL_NAME(CONST_QNaN),%eax
-	movl	%eax,(%edi)
-	movl	SYMBOL_NAME(CONST_QNaN)+4,%eax
-	movl	%eax,SIGL(%edi)
-	movl	SYMBOL_NAME(CONST_QNaN)+8,%eax
-	movl	%eax,SIGH(%edi)
-	jmp	LDiv_exit		/* %eax is nz */
-#endif PARANOID
diff -u --recursive --new-file v2.1.72/linux/arch/i386/math-emu/reg_divide.c linux/arch/i386/math-emu/reg_divide.c
--- v2.1.72/linux/arch/i386/math-emu/reg_divide.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/i386/math-emu/reg_divide.c	Tue Dec  9 17:57:09 1997
@@ -0,0 +1,206 @@
+/*---------------------------------------------------------------------------+
+ |  reg_divide.c                                                             |
+ |                                                                           |
+ | Divide one FPU_REG by another and put the result in a destination FPU_REG.|
+ |                                                                           |
+ | Copyright (C) 1996                                                        |
+ |                  W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
+ |                  E-mail   billm@jacobi.maths.monash.edu.au                |
+ |                                                                           |
+ |    Return value is the tag of the answer, or-ed with FPU_Exception if     |
+ |    one was raised, or -1 on internal error.                               |
+ |                                                                           |
+ +---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------+
+ | The destination may be any FPU_REG, including one of the source FPU_REGs. |
+ +---------------------------------------------------------------------------*/
+
+#include "exception.h"
+#include "reg_constant.h"
+#include "fpu_emu.h"
+#include "fpu_system.h"
+
+/*
+  Divide one register by another and put the result into a third register.
+  */
+int FPU_div(int flags, int rm, int control_w)
+{
+  FPU_REG x, y;
+  FPU_REG const *a, *b, *st0_ptr, *st_ptr;
+  FPU_REG *dest;
+  u_char taga, tagb, signa, signb, sign, saved_sign;
+  int tag, deststnr;
+
+  if ( flags & DEST_RM )
+    deststnr = rm;
+  else
+    deststnr = 0;
+
+  if ( flags & REV )
+    {
+      b = &st(0);
+      st0_ptr = b;
+      tagb = FPU_gettag0();
+      if ( flags & LOADED )
+	{
+	  a = (FPU_REG *)rm;
+	  taga = flags & 0x0f;
+	}
+      else
+	{
+	  a = &st(rm);
+	  st_ptr = a;
+	  taga = FPU_gettagi(rm);
+	}
+    }
+  else
+    {
+      a = &st(0);
+      st0_ptr = a;
+      taga = FPU_gettag0();
+      if ( flags & LOADED )
+	{
+	  b = (FPU_REG *)rm;
+	  tagb = flags & 0x0f;
+	}
+      else
+	{
+	  b = &st(rm);
+	  st_ptr = b;
+	  tagb = FPU_gettagi(rm);
+	}
+    }
+
+  signa = getsign(a);
+  signb = getsign(b);
+
+  sign = signa ^ signb;
+
+  dest = &st(deststnr);
+  saved_sign = getsign(dest);
+
+  if ( !(taga | tagb) )
+    {
+      /* Both regs Valid, this should be the most common case. */
+      reg_copy(a, &x);
+      reg_copy(b, &y);
+      setpositive(&x);
+      setpositive(&y);
+      tag = FPU_u_div(&x, &y, dest, control_w, sign);
+
+      if ( tag < 0 )
+	return tag;
+
+      FPU_settagi(deststnr, tag);
+      return tag;
+    }
+
+  if ( taga == TAG_Special )
+    taga = FPU_Special(a);
+  if ( tagb == TAG_Special )
+    tagb = FPU_Special(b);
+
+  if ( ((taga == TAG_Valid) && (tagb == TW_Denormal))
+	    || ((taga == TW_Denormal) && (tagb == TAG_Valid))
+	    || ((taga == TW_Denormal) && (tagb == TW_Denormal)) )
+    {
+      if ( denormal_operand() < 0 )
+	return FPU_Exception;
+
+      FPU_to_exp16(a, &x);
+      FPU_to_exp16(b, &y);
+      tag = FPU_u_div(&x, &y, dest, control_w, sign);
+      if ( tag < 0 )
+	return tag;
+
+      FPU_settagi(deststnr, tag);
+      return tag;
+    }
+  else if ( (taga <= TW_Denormal) && (tagb <= TW_Denormal) )
+    {
+      if ( tagb != TAG_Zero )
+	{
+	  /* Want to find Zero/Valid */
+	  if ( tagb == TW_Denormal )
+	    {
+	      if ( denormal_operand() < 0 )
+		return FPU_Exception;
+	    }
+
+	  /* The result is zero. */
+	  FPU_copy_to_regi(&CONST_Z, TAG_Zero, deststnr);
+	  setsign(dest, sign);
+	  return TAG_Zero;
+	}
+      /* We have an exception condition, either 0/0 or Valid/Zero. */
+      if ( taga == TAG_Zero )
+	{
+	  /* 0/0 */
+	  return arith_invalid(deststnr);
+	}
+      /* Valid/Zero */
+      return FPU_divide_by_zero(deststnr, sign);
+    }
+  /* Must have infinities, NaNs, etc */
+  else if ( (taga == TW_NaN) || (tagb == TW_NaN) )
+    {
+      if ( flags & LOADED )
+	return real_2op_NaN((FPU_REG *)rm, flags & 0x0f, 0, st0_ptr);
+
+      if ( flags & DEST_RM )
+	{
+	  int tag;
+	  tag = FPU_gettag0();
+	  if ( tag == TAG_Special )
+	    tag = FPU_Special(st0_ptr);
+	  return real_2op_NaN(st0_ptr, tag, rm, (flags & REV) ? st0_ptr : &st(rm));
+	}
+      else
+	{
+	  int tag;
+	  tag = FPU_gettagi(rm);
+	  if ( tag == TAG_Special )
+	    tag = FPU_Special(&st(rm));
+	  return real_2op_NaN(&st(rm), tag, 0, (flags & REV) ? st0_ptr : &st(rm));
+	}
+    }
+  else if (taga == TW_Infinity)
+    {
+      if (tagb == TW_Infinity)
+	{
+	  /* infinity/infinity */
+	  return arith_invalid(deststnr);
+	}
+      else
+	{
+	  /* tagb must be Valid or Zero */
+	  if ( (tagb == TW_Denormal) && (denormal_operand() < 0) )
+	    return FPU_Exception;
+	  
+	  /* Infinity divided by Zero or Valid does
+	     not raise and exception, but returns Infinity */
+	  FPU_copy_to_regi(a, TAG_Special, deststnr);
+	  setsign(dest, sign);
+	  return taga;
+	}
+    }
+  else if (tagb == TW_Infinity)
+    {
+      if ( (taga == TW_Denormal) && (denormal_operand() < 0) )
+	return FPU_Exception;
+
+      /* The result is zero. */
+      FPU_copy_to_regi(&CONST_Z, TAG_Zero, deststnr);
+      setsign(dest, sign);
+      return TAG_Zero;
+    }
+#ifdef PARANOID
+  else
+    {
+      EXCEPTION(EX_INTERNAL|0x102);
+      return FPU_Exception;
+    }
+#endif PARANOID
+
+}
diff -u --recursive --new-file v2.1.72/linux/arch/i386/math-emu/reg_ld_str.c linux/arch/i386/math-emu/reg_ld_str.c
--- v2.1.72/linux/arch/i386/math-emu/reg_ld_str.c	Mon Oct 28 04:41:15 1996
+++ linux/arch/i386/math-emu/reg_ld_str.c	Tue Dec  9 17:57:09 1997
@@ -3,9 +3,9 @@
  |                                                                           |
  | All of the functions which transfer data between user memory and FPU_REGs.|
  |                                                                           |
- | Copyright (C) 1992,1993,1994,1996                                         |
+ | Copyright (C) 1992,1993,1994,1996,1997                                    |
  |                  W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
- |                  E-mail   billm@jacobi.maths.monash.edu.au                |
+ |                  E-mail   billm@suburbia.net                              |
  |                                                                           |
  |                                                                           |
  +---------------------------------------------------------------------------*/
@@ -17,19 +17,17 @@
  |    other processes using the emulator while swapping is in progress.      |
  +---------------------------------------------------------------------------*/
 
+#include "fpu_emu.h"
+
 #include <asm/uaccess.h>
 
 #include "fpu_system.h"
 #include "exception.h"
 #include "reg_constant.h"
-#include "fpu_emu.h"
 #include "control_w.h"
 #include "status_w.h"
 
 
-#define EXTENDED_Ebias 0x3fff
-#define EXTENDED_Emin (-0x3ffe)  /* smallest valid exponent */
-
 #define DOUBLE_Emax 1023         /* largest valid exponent */
 #define DOUBLE_Ebias 1023
 #define DOUBLE_Emin (-1022)      /* smallest valid exponent */
@@ -38,123 +36,85 @@
 #define SINGLE_Ebias 127
 #define SINGLE_Emin (-126)       /* smallest valid exponent */
 
-static void write_to_extended(FPU_REG *rp, char *d);
 
-
-/* Get a long double from user memory */
-int reg_load_extended(long double *s, FPU_REG *loaded_data)
+static u_char normalize_no_excep(FPU_REG *r, int exp, int sign)
 {
-  unsigned long sigl, sigh, exp;
+  u_char tag;
 
-  RE_ENTRANT_CHECK_OFF;
-  FPU_verify_area(VERIFY_READ, s, 10);
-  get_user(sigl, (unsigned long *) s);
-  get_user(sigh, 1 + (unsigned long *) s);
-  get_user(exp, 4 + (unsigned short *) s);
-  RE_ENTRANT_CHECK_ON;
+  setexponent16(r, exp);
 
-  loaded_data->tag = TW_Valid;   /* Default */
-  loaded_data->sigl = sigl;
-  loaded_data->sigh = sigh;
-  if (exp & 0x8000)
-    loaded_data->sign = SIGN_NEG;
-  else
-    loaded_data->sign = SIGN_POS;
-  exp &= 0x7fff;
-  loaded_data->exp = exp - EXTENDED_Ebias + EXP_BIAS;
+  tag = FPU_normalize_nuo(r);
+  stdexp(r);
+  if ( sign )
+    setnegative(r);
+
+  return tag;
+}
+
+
+int FPU_tagof(FPU_REG *ptr)
+{
+  int exp;
 
+  exp = exponent16(ptr) & 0x7fff;
   if ( exp == 0 )
     {
-      if ( !(sigh | sigl) )
+      if ( !(ptr->sigh | ptr->sigl) )
 	{
-	  loaded_data->tag = TW_Zero;
-	  return 0;
+	  return TAG_Zero;
 	}
       /* The number is a de-normal or pseudodenormal. */
-      if (sigh & 0x80000000)
-	{
-	  /* Is a pseudodenormal. */
-	  /* Convert it for internal use. */
-	  /* This is non-80486 behaviour because the number
-	     loses its 'denormal' identity. */
-	  loaded_data->exp++;
-	  return 1;
-	}
-      else
-	{
-	  /* Is a denormal. */
-	  /* Convert it for internal use. */
-	  loaded_data->exp++;
-	  normalize_nuo(loaded_data);
-	  return 0;
-	}
+      return TAG_Special;
     }
-  else if ( exp == 0x7fff )
-    {
-      if ( !((sigh ^ 0x80000000) | sigl) )
-	{
-	  /* Matches the bit pattern for Infinity. */
-	  loaded_data->exp = EXP_Infinity;
-	  loaded_data->tag = TW_Infinity;
-	  return 0;
-	}
 
-      loaded_data->exp = EXP_NaN;
-      loaded_data->tag = TW_NaN;
-      if ( !(sigh & 0x80000000) )
-	{
-	  /* NaNs have the ms bit set to 1. */
-	  /* This is therefore an Unsupported NaN data type. */
-	  /* This is non 80486 behaviour */
-	  /* This should generate an Invalid Operand exception
-	     later, so we convert it to a SNaN */
-	  loaded_data->sigh = 0x80000000;
-	  loaded_data->sigl = 0x00000001;
-	  loaded_data->sign = SIGN_NEG;
-	  return 1;
-	}
-      return 0;
+  if ( exp == 0x7fff )
+    {
+      /* Is an Infinity, a NaN, or an unsupported data type. */
+      return TAG_Special;
     }
 
-  if ( !(sigh & 0x80000000) )
+  if ( !(ptr->sigh & 0x80000000) )
     {
       /* Unsupported data type. */
       /* Valid numbers have the ms bit set to 1. */
       /* Unnormal. */
-      /* Convert it for internal use. */
-      /* This is non-80486 behaviour */
-      /* This should generate an Invalid Operand exception
-	 later, so we convert it to a SNaN */
-      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 TAG_Special;
     }
-  return 0;
+
+  return TAG_Valid;
+}
+
+
+/* Get a long double from user memory */
+int FPU_load_extended(long double *s, int stnr)
+{
+  FPU_REG *sti_ptr = &st(stnr);
+
+  RE_ENTRANT_CHECK_OFF;
+  FPU_verify_area(VERIFY_READ, s, 10);
+  __copy_from_user(sti_ptr, s, 10);
+  RE_ENTRANT_CHECK_ON;
+
+  return FPU_tagof(sti_ptr);
 }
 
 
 /* Get a double from user memory */
-int reg_load_double(double *dfloat, FPU_REG *loaded_data)
+int FPU_load_double(double *dfloat, FPU_REG *loaded_data)
 {
-  int exp;
+  int exp, tag, negative;
   unsigned m64, l64;
 
   RE_ENTRANT_CHECK_OFF;
   FPU_verify_area(VERIFY_READ, dfloat, 8);
-  get_user(m64, 1 + (unsigned long *) dfloat);
-  get_user(l64, (unsigned long *) dfloat);
+  FPU_get_user(m64, 1 + (unsigned long *) dfloat);
+  FPU_get_user(l64, (unsigned long *) dfloat);
   RE_ENTRANT_CHECK_ON;
 
-  if (m64 & 0x80000000)
-    loaded_data->sign = SIGN_NEG;
-  else
-    loaded_data->sign = SIGN_POS;
-  exp = ((m64 & 0x7ff00000) >> 20) - DOUBLE_Ebias;
+  negative = (m64 & 0x80000000) ? SIGN_Negative : SIGN_Positive;
+  exp = ((m64 & 0x7ff00000) >> 20) - DOUBLE_Ebias + EXTENDED_Ebias;
   m64 &= 0xfffff;
-  if (exp > DOUBLE_Emax)
+  if ( exp > DOUBLE_Emax + EXTENDED_Ebias )
     {
       /* Infinity or NaN */
       if ((m64 == 0) && (l64 == 0))
@@ -162,93 +122,87 @@
 	  /* +- infinity */
 	  loaded_data->sigh = 0x80000000;
 	  loaded_data->sigl = 0x00000000;
-	  loaded_data->exp = EXP_Infinity;
-	  loaded_data->tag = TW_Infinity;
-	  return 0;
+	  exp = EXP_Infinity + EXTENDED_Ebias;
+	  tag = TAG_Special;
 	}
       else
 	{
 	  /* Must be a signaling or quiet NaN */
-	  loaded_data->exp = EXP_NaN;
-	  loaded_data->tag = TW_NaN;
+	  exp = EXP_NaN + EXTENDED_Ebias;
 	  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 */
+	  tag = TAG_Special;    /* The calling function must look for NaNs */
 	}
     }
-  else if ( exp < DOUBLE_Emin )
+  else if ( exp < DOUBLE_Emin + EXTENDED_Ebias )
     {
       /* Zero or de-normal */
       if ((m64 == 0) && (l64 == 0))
 	{
 	  /* Zero */
-	  int c = loaded_data->sign;
-	  reg_move(&CONST_Z, loaded_data);
-	  loaded_data->sign = c;
-	  return 0;
+	  reg_copy(&CONST_Z, loaded_data);
+	  exp = 0;
+	  tag = TAG_Zero;
 	}
       else
 	{
 	  /* De-normal */
-	  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();
+
+	  return normalize_no_excep(loaded_data, DOUBLE_Emin, negative)
+	    | (denormal_operand() < 0 ? FPU_Exception : 0);
 	}
     }
   else
     {
-      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;
+      tag = TAG_Valid;
     }
+
+  setexponent16(loaded_data, exp | negative);
+
+  return tag;
 }
 
 
 /* Get a float from user memory */
-int reg_load_single(float *single, FPU_REG *loaded_data)
+int FPU_load_single(float *single, FPU_REG *loaded_data)
 {
   unsigned m32;
-  int exp;
+  int exp, tag, negative;
 
   RE_ENTRANT_CHECK_OFF;
   FPU_verify_area(VERIFY_READ, single, 4);
-  get_user(m32, (unsigned long *) single);
+  FPU_get_user(m32, (unsigned long *) single);
   RE_ENTRANT_CHECK_ON;
 
-  if (m32 & 0x80000000)
-    loaded_data->sign = SIGN_NEG;
-  else
-    loaded_data->sign = SIGN_POS;
+  negative = (m32 & 0x80000000) ? SIGN_Negative : SIGN_Positive;
+
   if (!(m32 & 0x7fffffff))
     {
       /* Zero */
-      int c = loaded_data->sign;
-      reg_move(&CONST_Z, loaded_data);
-      loaded_data->sign = c;
-      return 0;
+      reg_copy(&CONST_Z, loaded_data);
+      addexponent(loaded_data, negative);
+      return TAG_Zero;
     }
-  exp = ((m32 & 0x7f800000) >> 23) - SINGLE_Ebias;
+  exp = ((m32 & 0x7f800000) >> 23) - SINGLE_Ebias + EXTENDED_Ebias;
   m32 = (m32 & 0x7fffff) << 8;
-  if ( exp < SINGLE_Emin )
+  if ( exp < SINGLE_Emin + EXTENDED_Ebias )
     {
       /* De-normals */
-      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();
+
+      return normalize_no_excep(loaded_data, SINGLE_Emin, negative)
+	| (denormal_operand() < 0 ? FPU_Exception : 0);
     }
-  else if ( exp > SINGLE_Emax )
+  else if ( exp > SINGLE_Emax + EXTENDED_Ebias )
     {
     /* Infinity or NaN */
       if ( m32 == 0 )
@@ -256,36 +210,37 @@
 	  /* +- infinity */
 	  loaded_data->sigh = 0x80000000;
 	  loaded_data->sigl = 0x00000000;
-	  loaded_data->exp = EXP_Infinity;
-	  loaded_data->tag = TW_Infinity;
-	  return 0;
+	  exp = EXP_Infinity + EXTENDED_Ebias;
+	  tag = TAG_Special;
 	}
       else
 	{
 	  /* Must be a signaling or quiet NaN */
-	  loaded_data->exp = EXP_NaN;
-	  loaded_data->tag = TW_NaN;
+	  exp = EXP_NaN + EXTENDED_Ebias;
 	  loaded_data->sigh = m32 | 0x80000000;
 	  loaded_data->sigl = 0;
-	  return 0; /* The calling function must look for NaNs */
+	  tag = TAG_Special;  /* The calling function must look for NaNs */
 	}
     }
   else
     {
-      loaded_data->exp = exp + EXP_BIAS;
       loaded_data->sigh = m32 | 0x80000000;
       loaded_data->sigl = 0;
-      loaded_data->tag = TW_Valid;
-      return 0;
+      tag = TAG_Valid;
     }
+
+  setexponent16(loaded_data, exp | negative);  /* Set the sign. */
+
+  return tag;
 }
 
 
 /* Get a long long from user memory */
-void reg_load_int64(long long *_s, FPU_REG *loaded_data)
+int FPU_load_int64(long long *_s)
 {
-  int e;
   long long s;
+  int sign;
+  FPU_REG *st0_ptr = &st(0);
 
   RE_ENTRANT_CHECK_OFF;
   FPU_verify_area(VERIFY_READ, _s, 8);
@@ -293,93 +248,91 @@
   RE_ENTRANT_CHECK_ON;
 
   if (s == 0)
-    { reg_move(&CONST_Z, loaded_data); return; }
+    {
+      reg_copy(&CONST_Z, st0_ptr);
+      return TAG_Zero;
+    }
 
   if (s > 0)
-    loaded_data->sign = SIGN_POS;
+    sign = SIGN_Positive;
   else
   {
     s = -s;
-    loaded_data->sign = SIGN_NEG;
+    sign = SIGN_Negative;
   }
 
-  e = EXP_BIAS + 63;
-  significand(loaded_data) = s;
-  loaded_data->exp = e;
-  loaded_data->tag = TW_Valid;
-  normalize_nuo(loaded_data);
+  significand(st0_ptr) = s;
+
+  return normalize_no_excep(st0_ptr, 63, sign);
 }
 
 
 /* Get a long from user memory */
-void reg_load_int32(long *_s, FPU_REG *loaded_data)
+int FPU_load_int32(long *_s, FPU_REG *loaded_data)
 {
   long s;
-  int e;
+  int negative;
 
   RE_ENTRANT_CHECK_OFF;
   FPU_verify_area(VERIFY_READ, _s, 4);
-  get_user(s, _s);
+  FPU_get_user(s, _s);
   RE_ENTRANT_CHECK_ON;
 
   if (s == 0)
-    { reg_move(&CONST_Z, loaded_data); return; }
+    { reg_copy(&CONST_Z, loaded_data); return TAG_Zero; }
 
   if (s > 0)
-    loaded_data->sign = SIGN_POS;
+    negative = SIGN_Positive;
   else
-  {
-    s = -s;
-    loaded_data->sign = SIGN_NEG;
-  }
+    {
+      s = -s;
+      negative = SIGN_Negative;
+    }
 
-  e = EXP_BIAS + 31;
   loaded_data->sigh = s;
   loaded_data->sigl = 0;
-  loaded_data->exp = e;
-  loaded_data->tag = TW_Valid;
-  normalize_nuo(loaded_data);
+
+  return normalize_no_excep(loaded_data, 31, negative);
 }
 
 
 /* Get a short from user memory */
-void reg_load_int16(short *_s, FPU_REG *loaded_data)
+int FPU_load_int16(short *_s, FPU_REG *loaded_data)
 {
-  int s, e;
+  int s, negative;
 
   RE_ENTRANT_CHECK_OFF;
   FPU_verify_area(VERIFY_READ, _s, 2);
   /* Cast as short to get the sign extended. */
-  get_user(s, _s);
+  FPU_get_user(s, _s);
   RE_ENTRANT_CHECK_ON;
 
   if (s == 0)
-    { reg_move(&CONST_Z, loaded_data); return; }
+    { reg_copy(&CONST_Z, loaded_data); return TAG_Zero; }
 
   if (s > 0)
-    loaded_data->sign = SIGN_POS;
+    negative = SIGN_Positive;
   else
-  {
-    s = -s;
-    loaded_data->sign = SIGN_NEG;
-  }
+    {
+      s = -s;
+      negative = SIGN_Negative;
+    }
 
-  e = EXP_BIAS + 15;
   loaded_data->sigh = s << 16;
-
   loaded_data->sigl = 0;
-  loaded_data->exp = e;
-  loaded_data->tag = TW_Valid;
-  normalize_nuo(loaded_data);
+
+  return normalize_no_excep(loaded_data, 15, negative);
 }
 
 
 /* Get a packed bcd array from user memory */
-void reg_load_bcd(char *s, FPU_REG *loaded_data)
+int FPU_load_bcd(u_char *s)
 {
+  FPU_REG *st0_ptr = &st(0);
   int pos;
-  unsigned char bcd;
+  u_char bcd;
   long long l=0;
+  int sign;
 
   RE_ENTRANT_CHECK_OFF;
   FPU_verify_area(VERIFY_READ, s, 10);
@@ -388,7 +341,7 @@
     {
       l *= 10;
       RE_ENTRANT_CHECK_OFF;
-      get_user(bcd, (unsigned char *) s+pos);
+      FPU_get_user(bcd, (u_char *) s+pos);
       RE_ENTRANT_CHECK_ON;
       l += bcd >> 4;
       l *= 10;
@@ -396,32 +349,27 @@
     }
  
   RE_ENTRANT_CHECK_OFF;
-  {
-    unsigned char sign;
-    get_user(sign, (unsigned char *) s+9);
-    loaded_data->sign = (sign & 0x80) ? SIGN_NEG : SIGN_POS;
-  }
+  FPU_get_user(sign, (u_char *) s+9);
+  sign = sign & 0x80 ? SIGN_Negative : SIGN_Positive;
   RE_ENTRANT_CHECK_ON;
 
-  if (l == 0)
+  if ( l == 0 )
     {
-      char sign = loaded_data->sign;
-      reg_move(&CONST_Z, loaded_data);
-      loaded_data->sign = sign;
+      reg_copy(&CONST_Z, st0_ptr);
+      addexponent(st0_ptr, sign);   /* Set the sign. */
+      return TAG_Zero;
     }
   else
     {
-      significand(loaded_data) = l;
-      loaded_data->exp = EXP_BIAS + 63;
-      loaded_data->tag = TW_Valid;
-      normalize_nuo(loaded_data);
+      significand(st0_ptr) = l;
+      return normalize_no_excep(st0_ptr, 63, sign);
     }
 }
 
 /*===========================================================================*/
 
 /* Put a long double into user memory */
-int reg_store_extended(long double *d, FPU_REG *st0_ptr)
+int FPU_store_extended(FPU_REG *st0_ptr, u_char st0_tag, long double *d)
 {
   /*
     The only exception raised by an attempt to store to an
@@ -429,12 +377,16 @@
     attempting to store from an empty register.
    */
 
-  if ( st0_ptr->tag != TW_Empty )
+  if ( st0_tag != TAG_Empty )
     {
       RE_ENTRANT_CHECK_OFF;
       FPU_verify_area(VERIFY_WRITE, d, 10);
+
+      FPU_put_user(st0_ptr->sigl, (unsigned long *) d);
+      FPU_put_user(st0_ptr->sigh, (unsigned long *) ((u_char *)d + 4));
+      FPU_put_user(exponent16(st0_ptr), (unsigned short *) ((u_char *)d + 8));
       RE_ENTRANT_CHECK_ON;
-      write_to_extended(st0_ptr, (char *) d);
+
       return 1;
     }
 
@@ -446,9 +398,9 @@
       /* Put out the QNaN indefinite */
       RE_ENTRANT_CHECK_OFF;
       FPU_verify_area(VERIFY_WRITE,d,10);
-      put_user(0, (unsigned long *) d);
-      put_user(0xc0000000, 1 + (unsigned long *) d);
-      put_user(0xffff, 4 + (short *) d);
+      FPU_put_user(0, (unsigned long *) d);
+      FPU_put_user(0xc0000000, 1 + (unsigned long *) d);
+      FPU_put_user(0xffff, 4 + (short *) d);
       RE_ENTRANT_CHECK_ON;
       return 1;
     }
@@ -459,38 +411,26 @@
 
 
 /* Put a double into user memory */
-int reg_store_double(double *dfloat, FPU_REG *st0_ptr)
+int FPU_store_double(FPU_REG *st0_ptr, u_char st0_tag, double *dfloat)
 {
   unsigned long l[2];
   unsigned long increment = 0;	/* avoid gcc warnings */
-  char st0_tag = st0_ptr->tag;
+  int precision_loss;
+  int exp;
+  FPU_REG tmp;
 
-  if (st0_tag == TW_Valid)
+  if ( st0_tag == TAG_Valid )
     {
-      int precision_loss;
-      int exp;
-      FPU_REG tmp;
-
-      reg_move(st0_ptr, &tmp);
-      exp = tmp.exp - EXP_BIAS;
+      reg_copy(st0_ptr, &tmp);
+      exp = exponent(&tmp);
 
       if ( exp < DOUBLE_Emin )     /* It may be a denormal */
 	{
-	  /* A denormal will always underflow. */
-#ifndef PECULIAR_486
-	  /* An 80486 is supposed to be able to generate
-	     a denormal exception here, but... */
-	  if ( st0_ptr->exp <= EXP_UNDER )
-	    {
-	      /* Underflow has priority. */
-	      if ( control_word & CW_Underflow )
-		denormal_operand();
-	    }
-#endif PECULIAR_486
+	  addexponent(&tmp, -DOUBLE_Emin + 52);  /* largest exp to be 51 */
 
-	  tmp.exp += -DOUBLE_Emin + 52;  /* largest exp to be 51 */
+	denormal_arg:
 
-	  if ( (precision_loss = round_to_int(&tmp)) )
+	  if ( (precision_loss = FPU_round_to_int(&tmp, st0_tag)) )
 	    {
 #ifdef PECULIAR_486
 	      /* Did it round to a non-denormal ? */
@@ -527,10 +467,10 @@
 		    ((tmp.sigl & 0xc00) == 0xc00);            /* odd -> even */
 		  break;
 		case RC_DOWN:   /* towards -infinity */
-		  increment = (tmp.sign == SIGN_POS) ? 0 : tmp.sigl & 0x7ff;
+		  increment = signpositive(&tmp) ? 0 : tmp.sigl & 0x7ff;
 		  break;
 		case RC_UP:     /* towards +infinity */
-		  increment = (tmp.sign == SIGN_POS) ? tmp.sigl & 0x7ff : 0;
+		  increment = signpositive(&tmp) ? tmp.sigl & 0x7ff : 0;
 		  break;
 		case RC_CHOP:
 		  increment = 0;
@@ -601,33 +541,64 @@
 	    }
 	}
     }
-  else if (st0_tag == TW_Zero)
+  else if (st0_tag == TAG_Zero)
     {
       /* Number is zero */
       l[0] = 0;
       l[1] = 0;
     }
-  else if (st0_tag == TW_Infinity)
+  else if ( st0_tag == TAG_Special )
     {
-      l[0] = 0;
-      l[1] = 0x7ff00000;
-    }
-  else if (st0_tag == TW_NaN)
-    {
-      /* See if we can get a valid NaN from the FPU_REG */
-      l[0] = (st0_ptr->sigl >> 11) | (st0_ptr->sigh << 21);
-      l[1] = ((st0_ptr->sigh >> 11) & 0xfffff);
-      if ( !(st0_ptr->sigh & 0x40000000) )
+      st0_tag = FPU_Special(st0_ptr);
+      if ( st0_tag == TW_Denormal )
 	{
-	  /* It is a signalling NaN */
-	  EXCEPTION(EX_Invalid);
-	  if ( !(control_word & CW_Invalid) )
-	    return 0;
-	  l[1] |= (0x40000000 >> 11);
+	  /* A denormal will always underflow. */
+#ifndef PECULIAR_486
+	  /* An 80486 is supposed to be able to generate
+	     a denormal exception here, but... */
+	  /* Underflow has priority. */
+	  if ( control_word & CW_Underflow )
+	    denormal_operand();
+#endif PECULIAR_486
+	  reg_copy(st0_ptr, &tmp);
+	  goto denormal_arg;
+	}
+      else if (st0_tag == TW_Infinity)
+	{
+	  l[0] = 0;
+	  l[1] = 0x7ff00000;
+	}
+      else if (st0_tag == TW_NaN)
+	{
+	  /* Is it really a NaN ? */
+	  if ( (exponent(st0_ptr) == EXP_OVER)
+	       && (st0_ptr->sigh & 0x80000000) )
+	    {
+	      /* See if we can get a valid NaN from the FPU_REG */
+	      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);
+		  if ( !(control_word & CW_Invalid) )
+		    return 0;
+		  l[1] |= (0x40000000 >> 11);
+		}
+	      l[1] |= 0x7ff00000;
+	    }
+	  else
+	    {
+	      /* It is an unsupported data type */
+	      EXCEPTION(EX_Invalid);
+	      if ( !(control_word & CW_Invalid) )
+		return 0;
+	      l[0] = 0;
+	      l[1] = 0xfff80000;
+	    }
 	}
-      l[1] |= 0x7ff00000;
     }
-  else if ( st0_tag == TW_Empty )
+  else if ( st0_tag == TAG_Empty )
     {
       /* Empty register (stack underflow) */
       EXCEPTION(EX_StackUnder);
@@ -637,21 +608,21 @@
 	  /* Put out the QNaN indefinite */
 	  RE_ENTRANT_CHECK_OFF;
 	  FPU_verify_area(VERIFY_WRITE,(void *)dfloat,8);
-	  put_user(0, (unsigned long *) dfloat);
-	  put_user(0xfff80000, 1 + (unsigned long *) dfloat);
+	  FPU_put_user(0, (unsigned long *) dfloat);
+	  FPU_put_user(0xfff80000, 1 + (unsigned long *) dfloat);
 	  RE_ENTRANT_CHECK_ON;
 	  return 1;
 	}
       else
 	return 0;
     }
-  if ( st0_ptr->sign )
+  if ( getsign(st0_ptr) )
     l[1] |= 0x80000000;
 
   RE_ENTRANT_CHECK_OFF;
   FPU_verify_area(VERIFY_WRITE,(void *)dfloat,8);
-  put_user(l[0], (unsigned long *)dfloat);
-  put_user(l[1], 1 + (unsigned long *)dfloat);
+  FPU_put_user(l[0], (unsigned long *)dfloat);
+  FPU_put_user(l[1], 1 + (unsigned long *)dfloat);
   RE_ENTRANT_CHECK_ON;
 
   return 1;
@@ -659,38 +630,27 @@
 
 
 /* Put a float into user memory */
-int reg_store_single(float *single, FPU_REG *st0_ptr)
+int FPU_store_single(FPU_REG *st0_ptr, u_char st0_tag, float *single)
 {
   long templ;
   unsigned long increment = 0;     	/* avoid gcc warnings */
-  char st0_tag = st0_ptr->tag;
+  int precision_loss;
+  int exp;
+  FPU_REG tmp;
 
-  if (st0_tag == TW_Valid)
+  if ( st0_tag == TAG_Valid )
     {
-      int precision_loss;
-      int exp;
-      FPU_REG tmp;
 
-      reg_move(st0_ptr, &tmp);
-      exp = tmp.exp - EXP_BIAS;
+      reg_copy(st0_ptr, &tmp);
+      exp = exponent(&tmp);
 
       if ( exp < SINGLE_Emin )
 	{
-	  /* A denormal will always underflow. */
-#ifndef PECULIAR_486
-	  /* An 80486 is supposed to be able to generate
-	     a denormal exception here, but... */
-	  if ( st0_ptr->exp <= EXP_UNDER )
-	    {
-	      /* Underflow has priority. */
-	      if ( control_word & CW_Underflow )
-		denormal_operand();
-	    }
-#endif PECULIAR_486
+	  addexponent(&tmp, -SINGLE_Emin + 23);  /* largest exp to be 22 */
 
-	  tmp.exp += -SINGLE_Emin + 23;  /* largest exp to be 22 */
+	denormal_arg:
 
-	  if ( (precision_loss = round_to_int(&tmp)) )
+	  if ( (precision_loss = FPU_round_to_int(&tmp, st0_tag)) )
 	    {
 #ifdef PECULIAR_486
 	      /* Did it round to a non-denormal ? */
@@ -704,15 +664,15 @@
 		  EXCEPTION(EX_Underflow);
 		  /* This is a special case: see sec 16.2.5.1 of
 		     the 80486 book */
-		  if ( !(control_word & EX_Underflow) )
+		  if ( !(control_word & CW_Underflow) )
 		    return 0;
 		}
 	      EXCEPTION(precision_loss);
-	      if ( !(control_word & EX_Precision) )
+	      if ( !(control_word & CW_Precision) )
 		return 0;
 	    }
 	  templ = tmp.sigl;
-	}
+      }
       else
 	{
 	  if ( tmp.sigl | (tmp.sigh & 0x000000ff) )
@@ -726,15 +686,15 @@
 		case RC_RND:
 		  increment = ((sigh & 0xff) > 0x80)       /* more than half */
 		    || (((sigh & 0xff) == 0x80) && sigl)   /* more than half */
-		      || ((sigh & 0x180) == 0x180);        /* round to even */
+		    || ((sigh & 0x180) == 0x180);        /* round to even */
 		  break;
 		case RC_DOWN:   /* towards -infinity */
-		  increment = (tmp.sign == SIGN_POS)
-		              ? 0 : (sigl | (sigh & 0xff));
+		  increment = signpositive(&tmp)
+		    ? 0 : (sigl | (sigh & 0xff));
 		  break;
 		case RC_UP:     /* towards +infinity */
-		  increment = (tmp.sign == SIGN_POS)
-		              ? (sigl | (sigh & 0xff)) : 0;
+		  increment = signpositive(&tmp)
+		    ? (sigl | (sigh & 0xff)) : 0;
 		  break;
 		case RC_CHOP:
 		  increment = 0;
@@ -767,7 +727,7 @@
 	    }
 	  else
 	    precision_loss = 0;
-
+      
 	  templ = (tmp.sigh >> 8) & 0x007fffff;
 
 	  if ( exp > SINGLE_Emax )
@@ -798,29 +758,66 @@
 	    }
 	}
     }
-  else if (st0_tag == TW_Zero)
+  else if (st0_tag == TAG_Zero)
     {
       templ = 0;
     }
-  else if (st0_tag == TW_Infinity)
+  else if ( st0_tag == TAG_Special )
     {
-      templ = 0x7f800000;
-    }
-  else if (st0_tag == TW_NaN)
-    {
-      /* See if we can get a valid NaN from the FPU_REG */
-      templ = st0_ptr->sigh >> 8;
-      if ( !(st0_ptr->sigh & 0x40000000) )
+      st0_tag = FPU_Special(st0_ptr);
+      if (st0_tag == TW_Denormal)
 	{
-	  /* It is a signalling NaN */
-	  EXCEPTION(EX_Invalid);
-	  if ( !(control_word & CW_Invalid) )
-	    return 0;
-	  templ |= (0x40000000 >> 8);
+	  reg_copy(st0_ptr, &tmp);
+
+	  /* A denormal will always underflow. */
+#ifndef PECULIAR_486
+	  /* An 80486 is supposed to be able to generate
+	     a denormal exception here, but... */
+	  /* Underflow has priority. */
+	  if ( control_word & CW_Underflow )
+	    denormal_operand();
+#endif PECULIAR_486
+	  goto denormal_arg;
+	}
+      else if (st0_tag == TW_Infinity)
+	{
+	  templ = 0x7f800000;
 	}
-      templ |= 0x7f800000;
+      else if (st0_tag == TW_NaN)
+	{
+	  /* Is it really a NaN ? */
+	  if ( (exponent(st0_ptr) == EXP_OVER) && (st0_ptr->sigh & 0x80000000) )
+	    {
+	      /* See if we can get a valid NaN from the FPU_REG */
+	      templ = st0_ptr->sigh >> 8;
+	      if ( !(st0_ptr->sigh & 0x40000000) )
+		{
+		  /* It is a signalling NaN */
+		  EXCEPTION(EX_Invalid);
+		  if ( !(control_word & CW_Invalid) )
+		    return 0;
+		  templ |= (0x40000000 >> 8);
+		}
+	      templ |= 0x7f800000;
+	    }
+	  else
+	    {
+	      /* It is an unsupported data type */
+	      EXCEPTION(EX_Invalid);
+	      if ( !(control_word & CW_Invalid) )
+		return 0;
+	      templ = 0xffc00000;
+	    }
+	}
+#ifdef PARANOID
+      else
+	{
+	  EXCEPTION(EX_INTERNAL|0x164);
+	  return 0;
+	}
+#endif
     }
-  else if ( st0_tag == TW_Empty )
+  else if ( st0_tag == TAG_Empty )
     {
       /* Empty register (stack underflow) */
       EXCEPTION(EX_StackUnder);
@@ -830,7 +827,7 @@
 	  /* Put out the QNaN indefinite */
 	  RE_ENTRANT_CHECK_OFF;
 	  FPU_verify_area(VERIFY_WRITE,(void *)single,4);
-	  put_user(0xffc00000, (unsigned long *) single);
+	  FPU_put_user(0xffc00000, (unsigned long *) single);
 	  RE_ENTRANT_CHECK_ON;
 	  return 1;
 	}
@@ -844,12 +841,12 @@
       return 0;
     }
 #endif
-  if (st0_ptr->sign)
+  if ( getsign(st0_ptr) )
     templ |= 0x80000000;
 
   RE_ENTRANT_CHECK_OFF;
   FPU_verify_area(VERIFY_WRITE,(void *)single,4);
-  put_user(templ,(unsigned long *) single);
+  FPU_put_user(templ,(unsigned long *) single);
   RE_ENTRANT_CHECK_ON;
 
   return 1;
@@ -857,34 +854,37 @@
 
 
 /* Put a long long into user memory */
-int reg_store_int64(long long *d, FPU_REG *st0_ptr)
+int FPU_store_int64(FPU_REG *st0_ptr, u_char st0_tag, long long *d)
 {
   FPU_REG t;
   long long tll;
   int precision_loss;
-  char st0_tag = st0_ptr->tag;
 
-  if ( st0_tag == TW_Empty )
+  if ( st0_tag == TAG_Empty )
     {
       /* Empty register (stack underflow) */
       EXCEPTION(EX_StackUnder);
       goto invalid_operand;
     }
-  else if ( (st0_tag == TW_Infinity) ||
-	   (st0_tag == TW_NaN) )
+  else if ( st0_tag == TAG_Special )
     {
-      EXCEPTION(EX_Invalid);
-      goto invalid_operand;
+      st0_tag = FPU_Special(st0_ptr);
+      if ( (st0_tag == TW_Infinity) ||
+	   (st0_tag == TW_NaN) )
+	{
+	  EXCEPTION(EX_Invalid);
+	  goto invalid_operand;
+	}
     }
 
-  reg_move(st0_ptr, &t);
-  precision_loss = round_to_int(&t);
+  reg_copy(st0_ptr, &t);
+  precision_loss = FPU_round_to_int(&t, st0_tag);
   ((long *)&tll)[0] = t.sigl;
   ((long *)&tll)[1] = t.sigh;
   if ( (precision_loss == 1) ||
       ((t.sigh & 0x80000000) &&
        !((t.sigh == 0x80000000) && (t.sigl == 0) &&
-	 (t.sign == SIGN_NEG))) )
+	 signnegative(&t))) )
     {
       EXCEPTION(EX_Invalid);
       /* This is a special case: see sec 16.2.5.1 of the 80486 book */
@@ -901,7 +901,7 @@
     {
       if ( precision_loss )
 	set_precision_flag(precision_loss);
-      if ( t.sign )
+      if ( signnegative(&t) )
 	tll = - tll;
     }
 
@@ -915,30 +915,33 @@
 
 
 /* Put a long into user memory */
-int reg_store_int32(long *d, FPU_REG *st0_ptr)
+int FPU_store_int32(FPU_REG *st0_ptr, u_char st0_tag, long *d)
 {
   FPU_REG t;
   int precision_loss;
-  char st0_tag = st0_ptr->tag;
 
-  if ( st0_tag == TW_Empty )
+  if ( st0_tag == TAG_Empty )
     {
       /* Empty register (stack underflow) */
       EXCEPTION(EX_StackUnder);
       goto invalid_operand;
     }
-  else if ( (st0_tag == TW_Infinity) ||
-	   (st0_tag == TW_NaN) )
+  else if ( st0_tag == TAG_Special )
     {
-      EXCEPTION(EX_Invalid);
-      goto invalid_operand;
+      st0_tag = FPU_Special(st0_ptr);
+      if ( (st0_tag == TW_Infinity) ||
+	   (st0_tag == TW_NaN) )
+	{
+	  EXCEPTION(EX_Invalid);
+	  goto invalid_operand;
+	}
     }
 
-  reg_move(st0_ptr, &t);
-  precision_loss = round_to_int(&t);
+  reg_copy(st0_ptr, &t);
+  precision_loss = FPU_round_to_int(&t, st0_tag);
   if (t.sigh ||
       ((t.sigl & 0x80000000) &&
-       !((t.sigl == 0x80000000) && (t.sign == SIGN_NEG))) )
+       !((t.sigl == 0x80000000) && signnegative(&t))) )
     {
       EXCEPTION(EX_Invalid);
       /* This is a special case: see sec 16.2.5.1 of the 80486 book */
@@ -955,13 +958,13 @@
     {
       if ( precision_loss )
 	set_precision_flag(precision_loss);
-      if ( t.sign )
+      if ( signnegative(&t) )
 	t.sigl = -(long)t.sigl;
     }
 
   RE_ENTRANT_CHECK_OFF;
   FPU_verify_area(VERIFY_WRITE,d,4);
-  put_user(t.sigl, (unsigned long *) d);
+  FPU_put_user(t.sigl, (unsigned long *) d);
   RE_ENTRANT_CHECK_ON;
 
   return 1;
@@ -969,30 +972,33 @@
 
 
 /* Put a short into user memory */
-int reg_store_int16(short *d, FPU_REG *st0_ptr)
+int FPU_store_int16(FPU_REG *st0_ptr, u_char st0_tag, short *d)
 {
   FPU_REG t;
   int precision_loss;
-  char st0_tag = st0_ptr->tag;
 
-  if ( st0_tag == TW_Empty )
+  if ( st0_tag == TAG_Empty )
     {
       /* Empty register (stack underflow) */
       EXCEPTION(EX_StackUnder);
       goto invalid_operand;
     }
-  else if ( (st0_tag == TW_Infinity) ||
-	   (st0_tag == TW_NaN) )
+  else if ( st0_tag == TAG_Special )
     {
-      EXCEPTION(EX_Invalid);
-      goto invalid_operand;
+      st0_tag = FPU_Special(st0_ptr);
+      if ( (st0_tag == TW_Infinity) ||
+	   (st0_tag == TW_NaN) )
+	{
+	  EXCEPTION(EX_Invalid);
+	  goto invalid_operand;
+	}
     }
 
-  reg_move(st0_ptr, &t);
-  precision_loss = round_to_int(&t);
+  reg_copy(st0_ptr, &t);
+  precision_loss = FPU_round_to_int(&t, st0_tag);
   if (t.sigh ||
       ((t.sigl & 0xffff8000) &&
-       !((t.sigl == 0x8000) && (t.sign == SIGN_NEG))) )
+       !((t.sigl == 0x8000) && signnegative(&t))) )
     {
       EXCEPTION(EX_Invalid);
       /* This is a special case: see sec 16.2.5.1 of the 80486 book */
@@ -1009,13 +1015,13 @@
     {
       if ( precision_loss )
 	set_precision_flag(precision_loss);
-      if ( t.sign )
+      if ( signnegative(&t) )
 	t.sigl = -t.sigl;
     }
 
   RE_ENTRANT_CHECK_OFF;
   FPU_verify_area(VERIFY_WRITE,d,2);
-  put_user((short)t.sigl,(short *) d);
+  FPU_put_user((short)t.sigl,(short *) d);
   RE_ENTRANT_CHECK_ON;
 
   return 1;
@@ -1023,24 +1029,33 @@
 
 
 /* Put a packed bcd array into user memory */
-int reg_store_bcd(char *d, FPU_REG *st0_ptr)
+int FPU_store_bcd(FPU_REG *st0_ptr, u_char st0_tag, u_char *d)
 {
   FPU_REG t;
   unsigned long long ll;
-  unsigned char b;
+  u_char b;
   int i, precision_loss;
-  unsigned char sign = (st0_ptr->sign == SIGN_NEG) ? 0x80 : 0;
-  char st0_tag = st0_ptr->tag;
+  u_char sign = (getsign(st0_ptr) == SIGN_NEG) ? 0x80 : 0;
 
-  if ( st0_tag == TW_Empty )
+  if ( st0_tag == TAG_Empty )
     {
       /* Empty register (stack underflow) */
       EXCEPTION(EX_StackUnder);
       goto invalid_operand;
     }
+  else if ( st0_tag == TAG_Special )
+    {
+      st0_tag = FPU_Special(st0_ptr);
+      if ( (st0_tag == TW_Infinity) ||
+	   (st0_tag == TW_NaN) )
+	{
+	  EXCEPTION(EX_Invalid);
+	  goto invalid_operand;
+	}
+    }
 
-  reg_move(st0_ptr, &t);
-  precision_loss = round_to_int(&t);
+  reg_copy(st0_ptr, &t);
+  precision_loss = FPU_round_to_int(&t, st0_tag);
   ll = significand(&t);
 
   /* Check for overflow, by comparing with 999999999999999999 decimal. */
@@ -1056,10 +1071,10 @@
 	  RE_ENTRANT_CHECK_OFF;
 	  FPU_verify_area(VERIFY_WRITE,d,10);
 	  for ( i = 0; i < 7; i++)
-	    put_user(0, (unsigned char *) d+i); /* These bytes "undefined" */
-	  put_user(0xc0, (unsigned char *) d+7); /* This byte "undefined" */
-	  put_user(0xff, (unsigned char *) d+8);
-	  put_user(0xff, (unsigned char *) d+9);
+	    FPU_put_user(0, (u_char *) d+i); /* These bytes "undefined" */
+	  FPU_put_user(0xc0, (u_char *) d+7); /* This byte "undefined" */
+	  FPU_put_user(0xff, (u_char *) d+8);
+	  FPU_put_user(0xff, (u_char *) d+9);
 	  RE_ENTRANT_CHECK_ON;
 	  return 1;
 	}
@@ -1077,14 +1092,14 @@
   RE_ENTRANT_CHECK_ON;
   for ( i = 0; i < 9; i++)
     {
-      b = div_small(&ll, 10);
-      b |= (div_small(&ll, 10)) << 4;
+      b = FPU_div_small(&ll, 10);
+      b |= (FPU_div_small(&ll, 10)) << 4;
       RE_ENTRANT_CHECK_OFF;
-      put_user(b,(unsigned char *) d+i);
+      FPU_put_user(b,(u_char *) d+i);
       RE_ENTRANT_CHECK_ON;
     }
   RE_ENTRANT_CHECK_OFF;
-  put_user(sign,(unsigned char *) d+9);
+  FPU_put_user(sign,(u_char *) d+9);
   RE_ENTRANT_CHECK_ON;
 
   return 1;
@@ -1100,25 +1115,25 @@
 /* Overflow is signalled by a non-zero return value (in eax).
    In the case of overflow, the returned significand always has the
    largest possible value */
-int round_to_int(FPU_REG *r)
+int FPU_round_to_int(FPU_REG *r, u_char tag)
 {
-  char     very_big;
+  u_char     very_big;
   unsigned eax;
 
-  if (r->tag == TW_Zero)
+  if (tag == TAG_Zero)
     {
       /* Make sure that zero is returned */
       significand(r) = 0;
       return 0;        /* o.k. */
     }
-  
-  if (r->exp > EXP_BIAS + 63)
+
+  if (exponent(r) > 63)
     {
       r->sigl = r->sigh = ~0;      /* The largest representable number */
       return 1;        /* overflow */
     }
 
-  eax = shrxs(&r->sigl, EXP_BIAS + 63 - r->exp);
+  eax = FPU_shrxs(&r->sigl, 63 - exponent(r));
   very_big = !(~(r->sigh) | ~(r->sigl));  /* test for 0xfff...fff */
 #define	half_or_more	(eax & 0x80000000)
 #define	frac_part	(eax)
@@ -1135,7 +1150,7 @@
 	}
       break;
     case RC_DOWN:
-      if (frac_part && r->sign)
+      if (frac_part && getsign(r))
 	{
 	  if ( very_big ) return 1;        /* overflow */
 	  significand(r) ++;
@@ -1143,7 +1158,7 @@
 	}
       break;
     case RC_UP:
-      if (frac_part && !r->sign)
+      if (frac_part && !getsign(r))
 	{
 	  if ( very_big ) return 1;        /* overflow */
 	  significand(r) ++;
@@ -1160,10 +1175,10 @@
 
 /*===========================================================================*/
 
-char *fldenv(fpu_addr_modes addr_modes, char *s)
+u_char *fldenv(fpu_addr_modes addr_modes, u_char *s)
 {
   unsigned short tag_word = 0;
-  unsigned char tag;
+  u_char tag;
   int i;
 
   if ( (addr_modes.default_mode == VM86) ||
@@ -1172,13 +1187,13 @@
     {
       RE_ENTRANT_CHECK_OFF;
       FPU_verify_area(VERIFY_READ, s, 0x0e);
-      get_user(control_word, (unsigned short *) s);
-      get_user(partial_status, (unsigned short *) (s+2));
-      get_user(tag_word, (unsigned short *) (s+4));
-      get_user(instruction_address.offset, (unsigned short *) (s+6));
-      get_user(instruction_address.selector, (unsigned short *) (s+8));
-      get_user(operand_address.offset, (unsigned short *) (s+0x0a));
-      get_user(operand_address.selector, (unsigned short *) (s+0x0c));
+      FPU_get_user(control_word, (unsigned short *) s);
+      FPU_get_user(partial_status, (unsigned short *) (s+2));
+      FPU_get_user(tag_word, (unsigned short *) (s+4));
+      FPU_get_user(instruction_address.offset, (unsigned short *) (s+6));
+      FPU_get_user(instruction_address.selector, (unsigned short *) (s+8));
+      FPU_get_user(operand_address.offset, (unsigned short *) (s+0x0a));
+      FPU_get_user(operand_address.selector, (unsigned short *) (s+0x0c));
       RE_ENTRANT_CHECK_ON;
       s += 0x0e;
       if ( addr_modes.default_mode == VM86 )
@@ -1192,14 +1207,14 @@
     {
       RE_ENTRANT_CHECK_OFF;
       FPU_verify_area(VERIFY_READ, s, 0x1c);
-      get_user(control_word, (unsigned short *) s);
-      get_user(partial_status, (unsigned short *) (s+4));
-      get_user(tag_word, (unsigned short *) (s+8));
-      get_user(instruction_address.offset, (unsigned long *) (s+0x0c));
-      get_user(instruction_address.selector, (unsigned short *) (s+0x10));
-      get_user(instruction_address.opcode, (unsigned short *) (s+0x12));
-      get_user(operand_address.offset, (unsigned long *) (s+0x14));
-      get_user(operand_address.selector, (unsigned long *) (s+0x18));
+      FPU_get_user(control_word, (unsigned short *) s);
+      FPU_get_user(partial_status, (unsigned short *) (s+4));
+      FPU_get_user(tag_word, (unsigned short *) (s+8));
+      FPU_get_user(instruction_address.offset, (unsigned long *) (s+0x0c));
+      FPU_get_user(instruction_address.selector, (unsigned short *) (s+0x10));
+      FPU_get_user(instruction_address.opcode, (unsigned short *) (s+0x12));
+      FPU_get_user(operand_address.offset, (unsigned long *) (s+0x14));
+      FPU_get_user(operand_address.selector, (unsigned long *) (s+0x18));
       RE_ENTRANT_CHECK_ON;
       s += 0x1c;
     }
@@ -1220,29 +1235,28 @@
       tag = tag_word & 3;
       tag_word >>= 2;
 
-      if ( tag == 3 )
+      if ( tag == TAG_Empty )
 	/* New tag is empty.  Accept it */
-	regs[i].tag = TW_Empty;
-      else if ( regs[i].tag == TW_Empty )
+	FPU_settag(i, TAG_Empty);
+      else if ( FPU_gettag(i) == TAG_Empty )
 	{
 	  /* Old tag is empty and new tag is not empty.  New tag is determined
 	     by old reg contents */
-	  if ( regs[i].exp == EXP_BIAS - EXTENDED_Ebias )
+	  if ( exponent(&fpu_register(i)) == - EXTENDED_Ebias )
 	    {
-	      if ( !(regs[i].sigl | regs[i].sigh) )
-		regs[i].tag = TW_Zero;
+	      if ( !(fpu_register(i).sigl | fpu_register(i).sigh) )
+		FPU_settag(i, TAG_Zero);
 	      else
-		regs[i].tag = TW_Valid;
+		FPU_settag(i, TAG_Special);
 	    }
-	  else if ( regs[i].exp == 0x7fff + EXP_BIAS - EXTENDED_Ebias )
+	  else if ( exponent(&fpu_register(i)) == 0x7fff - EXTENDED_Ebias )
 	    {
-	      if ( !((regs[i].sigh & ~0x80000000) | regs[i].sigl) )
-		regs[i].tag = TW_Infinity;
-	      else
-		regs[i].tag = TW_NaN;
+	      FPU_settag(i, TAG_Special);
 	    }
+	  else if ( fpu_register(i).sigh & 0x80000000 )
+	    FPU_settag(i, TAG_Valid);
 	  else
-	    regs[i].tag = TW_Valid;
+	    FPU_settag(i, TAG_Special);   /* An Un-normal */
   	}
       /* Else old tag is not empty and new tag is not empty.  Old tag
 	 remains correct */
@@ -1252,56 +1266,32 @@
 }
 
 
-void frstor(fpu_addr_modes addr_modes, char *data_address)
+void frstor(fpu_addr_modes addr_modes, u_char *data_address)
 {
-  int i, stnr;
-  unsigned char tag;
-  char *s = fldenv(addr_modes, data_address);
+  int i, regnr;
+  u_char *s = fldenv(addr_modes, data_address);
+  int offset = (top & 7) * 10, other = 80 - offset;
+
+  /* Copy all registers in stack order. */
+  RE_ENTRANT_CHECK_OFF;
+  FPU_verify_area(VERIFY_READ,s,80);
+  __copy_from_user(register_base+offset, s, other);
+  if ( offset )
+    __copy_from_user(register_base, s+other, offset);
+  RE_ENTRANT_CHECK_ON;
 
   for ( i = 0; i < 8; i++ )
     {
-      /* Load each register. */
-      stnr = (i+top) & 7;
-      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;
+      regnr = (i+top) & 7;
+      if ( FPU_gettag(regnr) != TAG_Empty )
+	/* The loaded data over-rides all other cases. */
+	FPU_settag(regnr, FPU_tagof(&st(i)));
     }
 
 }
 
 
-unsigned short tag_word(void)
-{
-  unsigned short word = 0;
-  unsigned char tag;
-  int i;
-
-  for ( i = 7; i >= 0; i-- )
-    {
-      switch ( tag = regs[i].tag )
-	{
-	case TW_Valid:
-	  if ( regs[i].exp <= (EXP_BIAS - EXTENDED_Ebias) )
-	    tag = 2;
-	  break;
-	case TW_Infinity:
-	case TW_NaN:
-	  tag = 2;
-	  break;
-	case TW_Empty:
-	  tag = 3;
-	  break;
-	  /* TW_Zero already has the correct value */
-	}
-      word <<= 2;
-      word |= tag;
-    }
-  return word;
-}
-
-
-char *fstenv(fpu_addr_modes addr_modes, char *d)
+u_char *fstenv(fpu_addr_modes addr_modes, u_char *d)
 {
   if ( (addr_modes.default_mode == VM86) ||
       ((addr_modes.default_mode == PM16)
@@ -1310,25 +1300,25 @@
       RE_ENTRANT_CHECK_OFF;
       FPU_verify_area(VERIFY_WRITE,d,14);
 #ifdef PECULIAR_486
-      put_user(control_word & ~0xe080, (unsigned long *) d);
+      FPU_put_user(control_word & ~0xe080, (unsigned long *) d);
 #else
-      put_user(control_word, (unsigned short *) d);
+      FPU_put_user(control_word, (unsigned short *) d);
 #endif PECULIAR_486
-      put_user(status_word(), (unsigned short *) (d+2));
-      put_user(tag_word(), (unsigned short *) (d+4));
-      put_user(instruction_address.offset, (unsigned short *) (d+6));
-      put_user(operand_address.offset, (unsigned short *) (d+0x0a));
+      FPU_put_user(status_word(), (unsigned short *) (d+2));
+      FPU_put_user(fpu_tag_word, (unsigned short *) (d+4));
+      FPU_put_user(instruction_address.offset, (unsigned short *) (d+6));
+      FPU_put_user(operand_address.offset, (unsigned short *) (d+0x0a));
       if ( addr_modes.default_mode == VM86 )
 	{
-	  put_user((instruction_address.offset & 0xf0000) >> 4,
+	  FPU_put_user((instruction_address.offset & 0xf0000) >> 4,
 		      (unsigned short *) (d+8));
-	  put_user((operand_address.offset & 0xf0000) >> 4,
+	  FPU_put_user((operand_address.offset & 0xf0000) >> 4,
 		      (unsigned short *) (d+0x0c));
 	}
       else
 	{
-	  put_user(instruction_address.selector, (unsigned short *) (d+8));
-	  put_user(operand_address.selector, (unsigned short *) (d+0x0c));
+	  FPU_put_user(instruction_address.selector, (unsigned short *) (d+8));
+	  FPU_put_user(operand_address.selector, (unsigned short *) (d+0x0c));
 	}
       RE_ENTRANT_CHECK_ON;
       d += 0x0e;
@@ -1336,28 +1326,17 @@
   else
     {
       RE_ENTRANT_CHECK_OFF;
-      FPU_verify_area(VERIFY_WRITE,d,28);
+      FPU_verify_area(VERIFY_WRITE, d, 7*4);
 #ifdef PECULIAR_486
+      control_word &= ~0xe080;
       /* An 80486 sets all the reserved bits to 1. */
-      put_user(0xffff0040 | (control_word & ~0xe080), (unsigned long *) d);
-      put_user(0xffff0000 | status_word(), (unsigned long *) (d+4));
-      put_user(0xffff0000 | tag_word(), (unsigned long *) (d+8));
-#else
-      put_user(control_word, (unsigned short *) d);
-      put_user(status_word(), (unsigned short *) (d+4));
-      put_user(tag_word(), (unsigned short *) (d+8));
-#endif PECULIAR_486
-      put_user(instruction_address.offset, (unsigned long *) (d+0x0c));
-      put_user(instruction_address.selector, (unsigned short *) (d+0x10));
-      put_user(instruction_address.opcode, (unsigned short *) (d+0x12));
-      put_user(operand_address.offset, (unsigned long *) (d+0x14));
-#ifdef PECULIAR_486
-      /* An 80486 sets all the reserved bits to 1. */
-      put_user(operand_address.selector, (unsigned short *) (d+0x18));
-      put_user(0xffff, (unsigned short *) (d+0x1a));
-#else
-      put_user(operand_address.selector, (unsigned long *) (d+0x18));
+      control_word |= 0xffff0000;
+      partial_status = status_word() | 0xffff0000;
+      fpu_tag_word |= 0xffff0000;
+      I387.soft.fcs |= 0xf8000000;
+      I387.soft.fos |= 0xffff0000;
 #endif PECULIAR_486
+      __copy_to_user(d, &control_word, 7*4);
       RE_ENTRANT_CHECK_ON;
       d += 0x1c;
     }
@@ -1369,84 +1348,23 @@
 }
 
 
-void fsave(fpu_addr_modes addr_modes, char *data_address)
+void fsave(fpu_addr_modes addr_modes, u_char *data_address)
 {
-  char *d;
-  int i;
+  u_char *d;
+  int offset = (top & 7) * 10, other = 80 - offset;
 
   d = fstenv(addr_modes, data_address);
+
   RE_ENTRANT_CHECK_OFF;
   FPU_verify_area(VERIFY_WRITE,d,80);
+
+  /* Copy all registers in stack order. */
+  __copy_to_user(d, register_base+offset, other);
+  if ( offset )
+    __copy_to_user(d+other, register_base, offset);
   RE_ENTRANT_CHECK_ON;
-  for ( i = 0; i < 8; i++ )
-    write_to_extended(&regs[(top + i) & 7], d + 10 * i);
 
   finit();
-
 }
 
 /*===========================================================================*/
-
-/*
-  A call to this function must be preceded by a call to
-  FPU_verify_area() to verify access to the 10 bytes at d
-  */
-static void write_to_extended(FPU_REG *rp, char *d)
-{
-  long e;
-  FPU_REG tmp;
-  
-  e = rp->exp - EXP_BIAS + EXTENDED_Ebias;
-
-#ifdef PARANOID
-  switch ( rp->tag )
-    {
-    case TW_Zero:
-      if ( rp->sigh | rp->sigl | e )
-	EXCEPTION(EX_INTERNAL | 0x160);
-      break;
-    case TW_Infinity:
-    case TW_NaN:
-      if ( (e ^ 0x7fff) | !(rp->sigh & 0x80000000) )
-	EXCEPTION(EX_INTERNAL | 0x161);
-      break;
-    default:
-      if (e > 0x7fff || e < -63)
-	EXCEPTION(EX_INTERNAL | 0x162);
-    }
-#endif PARANOID
-
-  /*
-    All numbers except denormals are stored internally in a
-    format which is compatible with the extended real number
-    format.
-   */
-  if ( e > 0 )
-    {
-      /* just copy the reg */
-      RE_ENTRANT_CHECK_OFF;
-      put_user(rp->sigl, (unsigned long *) d);
-      put_user(rp->sigh, (unsigned long *) (d + 4));
-      RE_ENTRANT_CHECK_ON;
-    }
-  else
-    {
-      /*
-	The number is a de-normal stored as a normal using our
-	extra exponent range, or is Zero.
-	Convert it back to a de-normal, or leave it as Zero.
-       */
-      reg_move(rp, &tmp);
-      tmp.exp += -EXTENDED_Emin + 63;  /* largest exp to be 63 */
-      round_to_int(&tmp);
-      e = 0;
-      RE_ENTRANT_CHECK_OFF;
-      put_user(tmp.sigl, (unsigned long *) d);
-      put_user(tmp.sigh, (unsigned long *) (d + 4));
-      RE_ENTRANT_CHECK_ON;
-    }
-  e |= rp->sign == SIGN_POS ? 0 : 0x8000;
-  RE_ENTRANT_CHECK_OFF;
-  put_user(e, (unsigned short *) (d + 8));
-  RE_ENTRANT_CHECK_ON;
-}
diff -u --recursive --new-file v2.1.72/linux/arch/i386/math-emu/reg_mul.c linux/arch/i386/math-emu/reg_mul.c
--- v2.1.72/linux/arch/i386/math-emu/reg_mul.c	Fri Feb 25 04:42:46 1994
+++ linux/arch/i386/math-emu/reg_mul.c	Tue Dec  9 17:57:09 1997
@@ -3,10 +3,11 @@
  |                                                                           |
  | Multiply one FPU_REG by another, put the result in a destination FPU_REG. |
  |                                                                           |
- | Copyright (C) 1992,1993                                                   |
- |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
- |                       Australia.  E-mail   billm@vaxc.cc.monash.edu.au    |
+ | Copyright (C) 1992,1993,1997                                              |
+ |                  W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
+ |                  E-mail   billm@suburbia.net                              |
  |                                                                           |
+ | Returns the tag of the result if no exceptions or errors occured.         |
  |                                                                           |
  +---------------------------------------------------------------------------*/
 
@@ -14,92 +15,117 @@
  | The destination may be any FPU_REG, including one of the source FPU_REGs. |
  +---------------------------------------------------------------------------*/
 
+#include "fpu_emu.h"
 #include "exception.h"
 #include "reg_constant.h"
-#include "fpu_emu.h"
 #include "fpu_system.h"
 
 
+/*
+  Multiply two registers to give a register result.
+  The sources are st(deststnr) and (b,tagb,signb).
+  The destination is st(deststnr).
+  */
 /* This routine must be called with non-empty source registers */
-int reg_mul(FPU_REG const *a, FPU_REG const *b,
-	    FPU_REG *dest, unsigned int control_w)
+int FPU_mul(FPU_REG const *b, u_char tagb, int deststnr, int control_w)
 {
-  char saved_sign = dest->sign;
-  char sign = (a->sign ^ b->sign);
+  FPU_REG *a = &st(deststnr);
+  FPU_REG *dest = a;
+  u_char taga = FPU_gettagi(deststnr);
+  u_char saved_sign = getsign(dest);
+  u_char sign = (getsign(a) ^ getsign(b));
+  int tag;
+
 
-  if (!(a->tag | b->tag))
+  if ( !(taga | tagb) )
     {
       /* Both regs Valid, this should be the most common case. */
-      dest->sign = sign;
-      if ( reg_u_mul(a, b, dest, control_w) )
+
+      tag = FPU_u_mul(a, b, dest, control_w, sign, exponent(a) + exponent(b));
+      if ( tag < 0 )
 	{
-	  dest->sign = saved_sign;
-	  return 1;
+	  setsign(dest, saved_sign);
+	  return tag;
 	}
-      return 0;
+      FPU_settagi(deststnr, tag);
+      return tag;
     }
-  else if ((a->tag <= TW_Zero) && (b->tag <= TW_Zero))
+
+  if ( taga == TAG_Special )
+    taga = FPU_Special(a);
+  if ( tagb == TAG_Special )
+    tagb = FPU_Special(b);
+
+  if ( ((taga == TAG_Valid) && (tagb == TW_Denormal))
+	    || ((taga == TW_Denormal) && (tagb == TAG_Valid))
+	    || ((taga == TW_Denormal) && (tagb == TW_Denormal)) )
     {
-#ifdef DENORM_OPERAND
-      if ( ((b->tag == TW_Valid) && (b->exp <= EXP_UNDER)) ||
-	  ((a->tag == TW_Valid) && (a->exp <= EXP_UNDER)) )
+      FPU_REG x, y;
+      if ( denormal_operand() < 0 )
+	return FPU_Exception;
+
+      FPU_to_exp16(a, &x);
+      FPU_to_exp16(b, &y);
+      tag = FPU_u_mul(&x, &y, dest, control_w, sign,
+		      exponent16(&x) + exponent16(&y));
+      if ( tag < 0 )
 	{
-	  if ( denormal_operand() ) return 1;
+	  setsign(dest, saved_sign);
+	  return tag;
 	}
-#endif DENORM_OPERAND
+      FPU_settagi(deststnr, tag);
+      return tag;
+    }
+  else if ( (taga <= TW_Denormal) && (tagb <= TW_Denormal) )
+    {
+      if ( ((tagb == TW_Denormal) || (taga == TW_Denormal))
+	   && (denormal_operand() < 0) )
+	return FPU_Exception;
+
       /* Must have either both arguments == zero, or
 	 one valid and the other zero.
 	 The result is therefore zero. */
-      reg_move(&CONST_Z, dest);
+      FPU_copy_to_regi(&CONST_Z, TAG_Zero, deststnr);
       /* The 80486 book says that the answer is +0, but a real
 	 80486 behaves this way.
 	 IEEE-754 apparently says it should be this way. */
-      dest->sign = sign;
-      return 0;
+      setsign(dest, sign);
+      return TAG_Zero;
     }
-  else
-    {
       /* Must have infinities, NaNs, etc */
-      if ( (a->tag == TW_NaN) || (b->tag == TW_NaN) )
-	{ return real_2op_NaN(a, b, dest); }
-      else if (a->tag == TW_Infinity)
-	{
-	  if (b->tag == TW_Zero)
-	    { return arith_invalid(dest); }  /* Zero*Infinity is invalid */
-	  else
-	    {
-#ifdef DENORM_OPERAND
-	      if ( (b->tag == TW_Valid) && (b->exp <= EXP_UNDER) &&
-		  denormal_operand() )
-		return 1;
-#endif DENORM_OPERAND
-	      reg_move(a, dest);
-	      dest->sign = sign;
-	    }
-	  return 0;
-	}
-      else if (b->tag == TW_Infinity)
-	{
-	  if (a->tag == TW_Zero)
-	    { return arith_invalid(dest); }  /* Zero*Infinity is invalid */
-	  else
-	    {
-#ifdef DENORM_OPERAND
-	      if ( (a->tag == TW_Valid) && (a->exp <= EXP_UNDER) &&
-		  denormal_operand() )
-		return 1;
-#endif DENORM_OPERAND
-	      reg_move(b, dest);
-	      dest->sign = sign;
-	    }
-	  return 0;
-	}
+  else if ( (taga == TW_NaN) || (tagb == TW_NaN) )
+    {
+      return real_2op_NaN(b, tagb, deststnr, &st(0));
+    }
+  else if ( ((taga == TW_Infinity) && (tagb == TAG_Zero))
+	    || ((tagb == TW_Infinity) && (taga == TAG_Zero)) )
+    {
+      return arith_invalid(deststnr);  /* Zero*Infinity is invalid */
+    }
+  else if ( ((taga == TW_Denormal) || (tagb == TW_Denormal))
+	    && (denormal_operand() < 0) )
+    {
+      return FPU_Exception;
+    }
+  else if (taga == TW_Infinity)
+    {
+      FPU_copy_to_regi(a, TAG_Special, deststnr);
+      setsign(dest, sign);
+      return TAG_Special;
+    }
+  else if (tagb == TW_Infinity)
+    {
+      FPU_copy_to_regi(b, TAG_Special, deststnr);
+      setsign(dest, sign);
+      return TAG_Special;
+    }
+
 #ifdef PARANOID
-      else
-	{
-	  EXCEPTION(EX_INTERNAL|0x102);
-	  return 1;
-	}
-#endif PARANOID
+  else
+    {
+      EXCEPTION(EX_INTERNAL|0x102);
+      return FPU_Exception;
     }
+#endif PARANOID
+
 }
diff -u --recursive --new-file v2.1.72/linux/arch/i386/math-emu/reg_norm.S linux/arch/i386/math-emu/reg_norm.S
--- v2.1.72/linux/arch/i386/math-emu/reg_norm.S	Thu Oct 10 06:01:12 1996
+++ linux/arch/i386/math-emu/reg_norm.S	Tue Dec  9 17:57:09 1997
@@ -1,16 +1,19 @@
 /*---------------------------------------------------------------------------+
  |  reg_norm.S                                                               |
  |                                                                           |
- | Copyright (C) 1992,1993,1994,1995                                         |
+ | Copyright (C) 1992,1993,1994,1995,1997                                    |
  |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
- |                       Australia.  E-mail billm@jacobi.maths.monash.edu.au |
+ |                       Australia.  E-mail billm@suburbia.net               |
  |                                                                           |
  | Normalize the value in a FPU_REG.                                         |
  |                                                                           |
  | Call from C as:                                                           |
- |   void normalize(FPU_REG *n)                                              |
+ |    int FPU_normalize(FPU_REG *n)                                          |
  |                                                                           |
- |   void normalize_nuo(FPU_REG *n)                                          |
+ |    int FPU_normalize_nuo(FPU_REG *n)                                      |
+ |                                                                           |
+ |    Return value is the tag of the answer, or-ed with FPU_Exception if     |
+ |    one was raised, or -1 on internal error.                               |
  |                                                                           |
  +---------------------------------------------------------------------------*/
 
@@ -18,24 +21,13 @@
 
 
 .text
-ENTRY(normalize)
+ENTRY(FPU_normalize)
 	pushl	%ebp
 	movl	%esp,%ebp
 	pushl	%ebx
 
 	movl	PARAM1,%ebx
 
-#ifdef PARANOID
-	cmpb	TW_Valid,TAG(%ebx)
-	je	L_ok
-
-	pushl	$0x220
-	call	SYMBOL_NAME(FPU_exception)
-	addl	$4,%esp
-
-L_ok:
-#endif PARANOID
-
 	movl	SIGH(%ebx),%edx
 	movl	SIGL(%ebx),%eax
 
@@ -48,7 +40,7 @@
 
 	movl	%eax,%edx
 	xorl	%eax,%eax
-	subl	$32,EXP(%ebx)	/* This can cause an underflow */
+	subw	$32,EXP(%ebx)	/* This can cause an underflow */
 
 /* We need to shift left by 1 - 31 bits */
 L_shift_1:
@@ -57,18 +49,25 @@
 	negl	%ecx
 	shld	%cl,%eax,%edx
 	shl	%cl,%eax
-	subl	%ecx,EXP(%ebx)	/* This can cause an underflow */
+	subw	%cx,EXP(%ebx)	/* This can cause an underflow */
 
 	movl	%edx,SIGH(%ebx)
 	movl	%eax,SIGL(%ebx)
 
 L_done:
-	cmpl	EXP_OVER,EXP(%ebx)
+	cmpw	EXP_OVER,EXP(%ebx)
 	jge	L_overflow
 
-	cmpl	EXP_UNDER,EXP(%ebx)
+	cmpw	EXP_UNDER,EXP(%ebx)
 	jle	L_underflow
 
+L_exit_valid:
+	movl	TAG_Valid,%eax
+
+	/* Convert the exponent to 80x87 form. */
+	addw	EXTENDED_Ebias,EXP(%ebx)
+	andw	$0x7fff,EXP(%ebx)
+
 L_exit:
 	popl	%ebx
 	leave
@@ -76,17 +75,21 @@
 
 
 L_zero:
-	movl	EXP_UNDER,EXP(%ebx)
-	movb	TW_Zero,TAG(%ebx)
+	movw	$0,EXP(%ebx)
+	movl	TAG_Zero,%eax
 	jmp	L_exit
 
 L_underflow:
+	/* Convert the exponent to 80x87 form. */
+	addw	EXTENDED_Ebias,EXP(%ebx)
 	push	%ebx
 	call	SYMBOL_NAME(arith_underflow)
 	pop	%ebx
 	jmp	L_exit
 
 L_overflow:
+	/* Convert the exponent to 80x87 form. */
+	addw	EXTENDED_Ebias,EXP(%ebx)
 	push	%ebx
 	call	SYMBOL_NAME(arith_overflow)
 	pop	%ebx
@@ -95,37 +98,26 @@
 
 
 /* Normalise without reporting underflow or overflow */
-ENTRY(normalize_nuo)
+ENTRY(FPU_normalize_nuo)
 	pushl	%ebp
 	movl	%esp,%ebp
 	pushl	%ebx
 
 	movl	PARAM1,%ebx
 
-#ifdef PARANOID
-	cmpb	TW_Valid,TAG(%ebx)
-	je	L_ok_nuo
-
-	pushl	$0x221
-	call	SYMBOL_NAME(FPU_exception)
-	addl	$4,%esp
-
-L_ok_nuo:
-#endif PARANOID
-
 	movl	SIGH(%ebx),%edx
 	movl	SIGL(%ebx),%eax
 
 	orl	%edx,%edx	/* ms bits */
-	js	L_exit		/* Already normalized */
+	js	L_exit_nuo_valid	/* Already normalized */
 	jnz	L_nuo_shift_1	/* Shift left 1 - 31 bits */
 
 	orl	%eax,%eax
-	jz	L_zero		/* The contents are zero */
+	jz	L_exit_nuo_zero		/* The contents are zero */
 
 	movl	%eax,%edx
 	xorl	%eax,%eax
-	subl	$32,EXP(%ebx)	/* This can cause an underflow */
+	subw	$32,EXP(%ebx)	/* This can cause an underflow */
 
 /* We need to shift left by 1 - 31 bits */
 L_nuo_shift_1:
@@ -134,10 +126,22 @@
 	negl	%ecx
 	shld	%cl,%eax,%edx
 	shl	%cl,%eax
-	subl	%ecx,EXP(%ebx)	/* This can cause an underflow */
+	subw	%cx,EXP(%ebx)	/* This can cause an underflow */
 
 	movl	%edx,SIGH(%ebx)
 	movl	%eax,SIGL(%ebx)
-	jmp	L_exit
 
+L_exit_nuo_valid:
+	movl	TAG_Valid,%eax
 
+	popl	%ebx
+	leave
+	ret
+
+L_exit_nuo_zero:
+	movl	TAG_Zero,%eax
+	movw	EXP_UNDER,EXP(%ebx)
+
+	popl	%ebx
+	leave
+	ret
diff -u --recursive --new-file v2.1.72/linux/arch/i386/math-emu/reg_round.S linux/arch/i386/math-emu/reg_round.S
--- v2.1.72/linux/arch/i386/math-emu/reg_round.S	Thu Oct 10 06:01:12 1996
+++ linux/arch/i386/math-emu/reg_round.S	Tue Dec  9 17:57:09 1997
@@ -4,17 +4,20 @@
  |                                                                           |
  | Rounding/truncation/etc for FPU basic arithmetic functions.               |
  |                                                                           |
- | Copyright (C) 1993,1995                                                   |
+ | Copyright (C) 1993,1995,1997                                              |
  |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
- |                       Australia.  E-mail billm@jacobi.maths.monash.edu.au |
+ |                       Australia.  E-mail billm@suburbia.net               |
  |                                                                           |
  | This code has four possible entry points.                                 |
  | The following must be entered by a jmp instruction:                       |
  |   fpu_reg_round, fpu_reg_round_sqrt, and fpu_Arith_exit.                  |
  |                                                                           |
- | The _round_reg entry point is intended to be used by C code.              |
+ | The FPU_round entry point is intended to be used by C code.               |
  | From C, call as:                                                          |
- | void round_reg(FPU_REG *arg, unsigned int extent, unsigned int control_w) |
+ |  int FPU_round(FPU_REG *arg, unsigned int extent, unsigned int control_w) |
+ |                                                                           |
+ |    Return value is the tag of the answer, or-ed with FPU_Exception if     |
+ |    one was raised, or -1 on internal error.                               |
  |                                                                           |
  | For correct "up" and "down" rounding, the argument must have the correct  |
  | sign.                                                                     |
@@ -106,7 +109,7 @@
 .globl fpu_Arith_exit
 
 /* Entry point when called from C */
-ENTRY(round_reg)
+ENTRY(FPU_round)
 	pushl	%ebp
 	movl	%esp,%ebp
 	pushl	%esi
@@ -117,14 +120,10 @@
 	movl	SIGH(%edi),%eax
 	movl	SIGL(%edi),%ebx
 	movl	PARAM2,%edx
-	movl	PARAM3,%ecx
-	jmp	fpu_reg_round_sqrt
 
 fpu_reg_round:			/* Normal entry point */
 	movl	PARAM4,%ecx
 
-fpu_reg_round_sqrt:		/* Entry point from wm_sqrt.S */
-
 #ifndef NON_REENTRANT_FPU
 	pushl	%ebx		/* adjust the stack pointer */
 #endif NON_REENTRANT_FPU
@@ -135,12 +134,12 @@
 /*	jns	L_entry_bugged */
 #endif PARANOID
 
-	cmpl	EXP_UNDER,EXP(%edi)
-	jle	xMake_denorm			/* The number is a de-normal */
+	cmpw	EXP_UNDER,EXP(%edi)
+	jle	L_Make_denorm			/* The number is a de-normal */
 
 	movb	$0,FPU_denormal			/* 0 -> not a de-normal */
 
-xDenorm_done:
+Denorm_done:
 	movb	$0,FPU_bits_lost		/* No bits yet lost in rounding */
 
 	movl	%ecx,%esi
@@ -190,13 +189,13 @@
 #endif PARANOID
 
 LUp_24:
-	cmpb	SIGN_POS,SIGN(%edi)
+	cmpb	SIGN_POS,PARAM5
 	jne	LCheck_truncate_24	/* If negative then  up==truncate */
 
 	jmp	LCheck_24_round_up
 
 LDown_24:
-	cmpb	SIGN_POS,SIGN(%edi)
+	cmpb	SIGN_POS,PARAM5
 	je	LCheck_truncate_24	/* If positive then  down==truncate */
 
 LCheck_24_round_up:
@@ -205,7 +204,7 @@
 	orl	%ebx,%ecx
 	orl	%edx,%ecx
 	jnz	LDo_24_round_up
-	jmp	LRe_normalise
+	jmp	L_Re_normalise
 
 LRound_nearest_24:
 	/* Do rounding of the 24th bit if needed (nearest or even) */
@@ -240,13 +239,13 @@
 	andl	$0x000000ff,%ecx
 	orl	%ebx,%ecx
 	orl	%edx,%ecx
-	jz	LRe_normalise		/* No truncation needed */
+	jz	L_Re_normalise		/* No truncation needed */
 
 LDo_truncate_24:
 	andl	$0xffffff00,%eax	/* Truncate to 24 bits */
 	xorl	%ebx,%ebx
 	movb	LOST_DOWN,FPU_bits_lost
-	jmp	LRe_normalise
+	jmp	L_Re_normalise
 
 
 /* Round etc to 53 bit precision */
@@ -270,13 +269,13 @@
 #endif PARANOID
 
 LUp_53:
-	cmpb	SIGN_POS,SIGN(%edi)
+	cmpb	SIGN_POS,PARAM5
 	jne	LCheck_truncate_53	/* If negative then  up==truncate */
 
 	jmp	LCheck_53_round_up
 
 LDown_53:
-	cmpb	SIGN_POS,SIGN(%edi)
+	cmpb	SIGN_POS,PARAM5
 	je	LCheck_truncate_53	/* If positive then  down==truncate */
 
 LCheck_53_round_up:
@@ -284,7 +283,7 @@
 	andl	$0x000007ff,%ecx
 	orl	%edx,%ecx
 	jnz	LDo_53_round_up
-	jmp	LRe_normalise
+	jmp	L_Re_normalise
 
 LRound_nearest_53:
 	/* Do rounding of the 53rd bit if needed (nearest or even) */
@@ -315,12 +314,12 @@
 	movl	%ebx,%ecx
 	andl	$0x000007ff,%ecx
 	orl	%edx,%ecx
-	jz	LRe_normalise
+	jz	L_Re_normalise
 
 LTruncate_53:
 	movb	LOST_DOWN,FPU_bits_lost
 	andl	$0xfffff800,%ebx	/* Truncate to 53 bits */
-	jmp	LRe_normalise
+	jmp	L_Re_normalise
 
 
 /* Round etc to 64 bit precision */
@@ -344,20 +343,20 @@
 #endif PARANOID
 
 LUp_64:
-	cmpb	SIGN_POS,SIGN(%edi)
+	cmpb	SIGN_POS,PARAM5
 	jne	LCheck_truncate_64	/* If negative then  up==truncate */
 
 	orl	%edx,%edx
 	jnz	LDo_64_round_up
-	jmp	LRe_normalise
+	jmp	L_Re_normalise
 
 LDown_64:
-	cmpb	SIGN_POS,SIGN(%edi)
+	cmpb	SIGN_POS,PARAM5
 	je	LCheck_truncate_64	/* If positive then  down==truncate */
 
 	orl	%edx,%edx
 	jnz	LDo_64_round_up
-	jmp	LRe_normalise
+	jmp	L_Re_normalise
 
 LRound_nearest_64:
 	cmpl	$0x80000000,%edx
@@ -375,46 +374,60 @@
 	adcl	$0,%eax
 
 LCheck_Round_Overflow:
-	jnc	LRe_normalise
+	jnc	L_Re_normalise
 
 	/* Overflow, adjust the result (significand to 1.0) */
 	rcrl	$1,%eax
 	rcrl	$1,%ebx
-	incl	EXP(%edi)
-	jmp	LRe_normalise
+	incw	EXP(%edi)
+	jmp	L_Re_normalise
 
 LCheck_truncate_64:
 	orl	%edx,%edx
-	jz	LRe_normalise
+	jz	L_Re_normalise
 
 LTruncate_64:
 	movb	LOST_DOWN,FPU_bits_lost
 
-LRe_normalise:
+L_Re_normalise:
 	testb	$0xff,FPU_denormal
-	jnz	xNormalise_result
+	jnz	Normalise_result
+
+L_Normalised:
+	movl	TAG_Valid,%edx
 
-xL_Normalised:
+L_deNormalised:
 	cmpb	LOST_UP,FPU_bits_lost
-	je	xL_precision_lost_up
+	je	L_precision_lost_up
 
 	cmpb	LOST_DOWN,FPU_bits_lost
-	je	xL_precision_lost_down
+	je	L_precision_lost_down
 
-xL_no_precision_loss:
+L_no_precision_loss:
 	/* store the result */
-	movb	TW_Valid,TAG(%edi)
 
-xL_Store_significand:
+L_Store_significand:
 	movl	%eax,SIGH(%edi)
 	movl	%ebx,SIGL(%edi)
 
-	xorl	%eax,%eax	/* No errors detected. */
-
-	cmpl	EXP_OVER,EXP(%edi)
+	cmpw	EXP_OVER,EXP(%edi)
 	jge	L_overflow
 
-fpu_reg_round_exit:
+	movl	%edx,%eax
+
+	/* Convert the exponent to 80x87 form. */
+	addw	EXTENDED_Ebias,EXP(%edi)
+	andw	$0x7fff,EXP(%edi)
+
+fpu_reg_round_signed_special_exit:
+
+	cmpb	SIGN_POS,PARAM5
+	je	fpu_reg_round_special_exit
+
+	orw	$0x8000,EXP(%edi)	/* Negative sign for the result. */
+
+fpu_reg_round_special_exit:
+
 #ifndef NON_REENTRANT_FPU
 	popl	%ebx		/* adjust the stack pointer */
 #endif NON_REENTRANT_FPU
@@ -431,21 +444,25 @@
  * Set the FPU status flags to represent precision loss due to
  * round-up.
  */
-xL_precision_lost_up:
+L_precision_lost_up:
+	push	%edx
 	push	%eax
 	call	SYMBOL_NAME(set_precision_flag_up)
 	popl	%eax
-	jmp	xL_no_precision_loss
+	popl	%edx
+	jmp	L_no_precision_loss
 
 /*
  * Set the FPU status flags to represent precision loss due to
  * truncation.
  */
-xL_precision_lost_down:
+L_precision_lost_down:
+	push	%edx
 	push	%eax
 	call	SYMBOL_NAME(set_precision_flag_down)
 	popl	%eax
-	jmp	xL_no_precision_loss
+	popl	%edx
+	jmp	L_no_precision_loss
 
 
 /*
@@ -453,30 +470,30 @@
  * Shift the number right the required number of bits, which will
  * have to be undone later...
  */
-xMake_denorm:
+L_Make_denorm:
 	/* The action to be taken depends upon whether the underflow
 	   exception is masked */
 	testb	CW_Underflow,%cl		/* Underflow mask. */
-	jz	xUnmasked_underflow		/* Do not make a denormal. */
+	jz	Unmasked_underflow		/* Do not make a denormal. */
 
 	movb	DENORMAL,FPU_denormal
 
 	pushl	%ecx		/* Save */
-	movl	EXP_UNDER+1,%ecx
-	subl	EXP(%edi),%ecx
+	movw	EXP_UNDER+1,%cx
+	subw	EXP(%edi),%cx
 
-	cmpl	$64,%ecx	/* shrd only works for 0..31 bits */
-	jnc	xDenorm_shift_more_than_63
+	cmpw	$64,%cx	/* shrd only works for 0..31 bits */
+	jnc	Denorm_shift_more_than_63
 
-	cmpl	$32,%ecx	/* shrd only works for 0..31 bits */
-	jnc	xDenorm_shift_more_than_32
+	cmpw	$32,%cx	/* shrd only works for 0..31 bits */
+	jnc	Denorm_shift_more_than_32
 
 /*
  * We got here without jumps by assuming that the most common requirement
  *   is for a small de-normalising shift.
  * Shift by [1..31] bits
  */
-	addl	%ecx,EXP(%edi)
+	addw	%cx,EXP(%edi)
 	orl	%edx,%edx	/* extension */
 	setne	%ch		/* Save whether %edx is non-zero */
 	xorl	%edx,%edx
@@ -485,11 +502,11 @@
 	shr	%cl,%eax
 	orb	%ch,%dl
 	popl	%ecx
-	jmp	xDenorm_done
+	jmp	Denorm_done
 
 /* Shift by [32..63] bits */
-xDenorm_shift_more_than_32:
-	addl	%ecx,EXP(%edi)
+Denorm_shift_more_than_32:
+	addw	%cx,EXP(%edi)
 	subb	$32,%cl
 	orl	%edx,%edx
 	setne	%ch
@@ -506,15 +523,15 @@
 	movl	%eax,%ebx
 	xorl	%eax,%eax
 	popl	%ecx
-	jmp	xDenorm_done
+	jmp	Denorm_done
 
 /* Shift by [64..) bits */
-xDenorm_shift_more_than_63:
-	cmpl	$64,%ecx
-	jne	xDenorm_shift_more_than_64
+Denorm_shift_more_than_63:
+	cmpw	$64,%cx
+	jne	Denorm_shift_more_than_64
 
 /* Exactly 64 bit shift */
-	addl	%ecx,EXP(%edi)
+	addw	%cx,EXP(%edi)
 	xorl	%ecx,%ecx
 	orl	%edx,%edx
 	setne	%cl
@@ -526,32 +543,32 @@
 	xorl	%eax,%eax
 	xorl	%ebx,%ebx
 	popl	%ecx
-	jmp	xDenorm_done
+	jmp	Denorm_done
 
-xDenorm_shift_more_than_64:
-	movl	EXP_UNDER+1,EXP(%edi)
+Denorm_shift_more_than_64:
+	movw	EXP_UNDER+1,EXP(%edi)
 /* This is easy, %eax must be non-zero, so.. */
 	movl	$1,%edx
 	xorl	%eax,%eax
 	xorl	%ebx,%ebx
 	popl	%ecx
-	jmp	xDenorm_done
+	jmp	Denorm_done
 
 
-xUnmasked_underflow:
+Unmasked_underflow:
 	movb	UNMASKED_UNDERFLOW,FPU_denormal
-	jmp	xDenorm_done
+	jmp	Denorm_done
 
 
 /* Undo the de-normalisation. */
-xNormalise_result:
+Normalise_result:
 	cmpb	UNMASKED_UNDERFLOW,FPU_denormal
-	je	xSignal_underflow
+	je	Signal_underflow
 
 /* The number must be a denormal if we got here. */
 #ifdef PARANOID
 	/* But check it... just in case. */
-	cmpl	EXP_UNDER+1,EXP(%edi)
+	cmpw	EXP_UNDER+1,EXP(%edi)
 	jne	L_norm_bugged
 #endif PARANOID
 
@@ -565,41 +582,33 @@
 	 * Actual 80486 behaviour differs from this in some circumstances.
 	 */
 	orl	%eax,%eax		/* ms bits */
-	js	LNormalise_shift_done	/* Will be masked underflow */
-#endif PECULIAR_486
-
+	js	LPseudoDenormal		/* Will be masked underflow */
+#else
 	orl	%eax,%eax		/* ms bits */
-	js	xL_Normalised		/* No longer a denormal */
+	js	L_Normalised		/* No longer a denormal */
+#endif PECULIAR_486
 
-	jnz	LNormalise_shift_up_to_31	/* Shift left 0 - 31 bits */
+	jnz	LDenormal_adj_exponent
 
 	orl	%ebx,%ebx
 	jz	L_underflow_to_zero	/* The contents are zero */
 
-/* Shift left 32 - 63 bits */
-	movl	%ebx,%eax
-	xorl	%ebx,%ebx
-	subl	$32,EXP(%edi)
-
-LNormalise_shift_up_to_31:
-	bsrl	%eax,%ecx	/* get the required shift in %ecx */
-	subl	$31,%ecx
-	negl	%ecx
-	shld	%cl,%ebx,%eax
-	shl	%cl,%ebx
-	subl	%ecx,EXP(%edi)
+LDenormal_adj_exponent:
+	decw	EXP(%edi)
 
-LNormalise_shift_done:
+LPseudoDenormal:
 	testb	$0xff,FPU_bits_lost	/* bits lost == underflow */
-	jz	xL_Normalised
+	movl	TAG_Special,%edx
+	jz	L_deNormalised
 
 	/* There must be a masked underflow */
 	push	%eax
 	pushl	EX_Underflow
-	call	SYMBOL_NAME(FPU_exception)
+	call	EXCEPTION
 	popl	%eax
 	popl	%eax
-	jmp	xL_Normalised
+	movl	TAG_Special,%edx
+	jmp	L_deNormalised
 
 
 /*
@@ -613,41 +622,42 @@
 
 	push	%eax
 	pushl	EX_Underflow
-	call	SYMBOL_NAME(FPU_exception)
+	call	EXCEPTION
 	popl	%eax
 	popl	%eax
 
 /* Reduce the exponent to EXP_UNDER */
-	movl	EXP_UNDER,EXP(%edi)
-	movb	TW_Zero,TAG(%edi)
-	jmp	xL_Store_significand
+	movw	EXP_UNDER,EXP(%edi)
+	movl	TAG_Zero,%edx
+	jmp	L_Store_significand
 
 
 /* The operations resulted in a number too large to represent. */
 L_overflow:
+	addw	EXTENDED_Ebias,EXP(%edi)	/* Set for unmasked response. */
 	push	%edi
 	call	SYMBOL_NAME(arith_overflow)
 	pop	%edi
-	jmp	fpu_reg_round_exit
+	jmp	fpu_reg_round_signed_special_exit
 
 
-xSignal_underflow:
+Signal_underflow:
 	/* The number may have been changed to a non-denormal */
 	/* by the rounding operations. */
-	cmpl	EXP_UNDER,EXP(%edi)
-	jle	xDo_unmasked_underflow
+	cmpw	EXP_UNDER,EXP(%edi)
+	jle	Do_unmasked_underflow
 
-	jmp	xL_Normalised
+	jmp	L_Normalised
 
-xDo_unmasked_underflow:
+Do_unmasked_underflow:
 	/* Increase the exponent by the magic number */
-	addl	$(3*(1<<13)),EXP(%edi)
+	addw	$(3*(1<<13)),EXP(%edi)
 	push	%eax
 	pushl	EX_Underflow
 	call	EXCEPTION
 	popl	%eax
 	popl	%eax
-	jmp	xL_Normalised
+	jmp	L_Normalised
 
 
 #ifdef PARANOID
@@ -694,6 +704,6 @@
 	call	EXCEPTION
 	popl	%ebx
 L_exception_exit:
-	mov	$1,%eax
-	jmp	fpu_reg_round_exit
+	mov	$-1,%eax
+	jmp	fpu_reg_round_special_exit
 #endif PARANOID
diff -u --recursive --new-file v2.1.72/linux/arch/i386/math-emu/reg_u_add.S linux/arch/i386/math-emu/reg_u_add.S
--- v2.1.72/linux/arch/i386/math-emu/reg_u_add.S	Thu Oct  5 06:30:43 1995
+++ linux/arch/i386/math-emu/reg_u_add.S	Tue Dec  9 17:57:09 1997
@@ -2,24 +2,26 @@
 /*---------------------------------------------------------------------------+
  |  reg_u_add.S                                                              |
  |                                                                           |
- | Add two valid (TW_Valid) FPU_REG numbers, of the same sign, and put the   |
+ | Add two valid (TAG_Valid) FPU_REG numbers, of the same sign, and put the  |
  |   result in a destination FPU_REG.                                        |
  |                                                                           |
- | Copyright (C) 1992,1993,1995                                              |
- |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
- |                       Australia.  E-mail billm@jacobi.maths.monash.edu.au |
+ | Copyright (C) 1992,1993,1995,1997                                         |
+ |                  W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
+ |                  E-mail   billm@suburbia.net                              |
  |                                                                           |
  | Call from C as:                                                           |
- |   void reg_u_add(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *answ,             |
+ |   int  FPU_u_add(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *answ,             |
  |                                                int control_w)             |
+ |    Return value is the tag of the answer, or-ed with FPU_Exception if     |
+ |    one was raised, or -1 on internal error.                               |
  |                                                                           |
  +---------------------------------------------------------------------------*/
 
 /*
- |    Kernel addition routine reg_u_add(reg *arg1, reg *arg2, reg *answ).
- |    Takes two valid reg f.p. numbers (TW_Valid), which are
+ |    Kernel addition routine FPU_u_add(reg *arg1, reg *arg2, reg *answ).
+ |    Takes two valid reg f.p. numbers (TAG_Valid), which are
  |    treated as unsigned numbers,
- |    and returns their sum as a TW_Valid or TW_S f.p. number.
+ |    and returns their sum as a TAG_Valid or TAG_Special f.p. number.
  |    The returned number is normalized.
  |    Basic checks are performed if PARANOID is defined.
  */
@@ -29,7 +31,7 @@
 #include "control_w.h"
 
 .text
-ENTRY(reg_u_add)
+ENTRY(FPU_u_add)
 	pushl	%ebp
 	movl	%esp,%ebp
 	pushl	%esi
@@ -39,27 +41,9 @@
 	movl	PARAM1,%esi		/* source 1 */
 	movl	PARAM2,%edi		/* source 2 */
 
-#ifdef DENORM_OPERAND
-	cmpl	EXP_UNDER,EXP(%esi)
-	jg	xOp1_not_denorm
-
-	call	SYMBOL_NAME(denormal_operand)
-	orl	%eax,%eax
-	jnz	fpu_Arith_exit
-
-xOp1_not_denorm:
-	cmpl	EXP_UNDER,EXP(%edi)
-	jg	xOp2_not_denorm
-
-	call	SYMBOL_NAME(denormal_operand)
-	orl	%eax,%eax
-	jnz	fpu_Arith_exit
-
-xOp2_not_denorm:
-#endif DENORM_OPERAND
-
-	movl	EXP(%esi),%ecx
-	subl	EXP(%edi),%ecx		/* exp1 - exp2 */
+	movl	PARAM6,%ecx
+	movl	%ecx,%edx
+	subl	PARAM7,%ecx			/* exp1 - exp2 */
 	jge	L_arg1_larger
 
 	/* num1 is smaller */
@@ -67,6 +51,7 @@
 	movl	SIGH(%esi),%eax
 
 	movl	%edi,%esi
+	movl	PARAM7,%edx
 	negw	%cx
 	jmp	L_accum_loaded
 
@@ -77,12 +62,7 @@
 
 L_accum_loaded:
 	movl	PARAM3,%edi		/* destination */
-/*	movb	SIGN(%esi),%dl
-	movb	%dl,SIGN(%edi) */	/* Copy the sign from the first arg */
-
-
-	movl	EXP(%esi),%edx
-	movl	%edx,EXP(%edi)		/* Copy exponent to destination */
+	movw	%dx,EXP(%edi)		/* Copy exponent to destination */
 
 	xorl	%edx,%edx		/* clear the extension */
 
@@ -162,7 +142,7 @@
 	orl	$1,%edx
 
 L_no_bit_lost:
-	incl	EXP(%edi)
+	incw	EXP(%edi)
 
 L_round_the_result:
 	jmp	fpu_reg_round	/* Round the result */
@@ -175,9 +155,8 @@
 	pushl	EX_INTERNAL|0x201
 	call	EXCEPTION
 	pop	%ebx
+	movl	$-1,%eax
 	jmp	L_exit
-#endif PARANOID
-
 
 L_exit:
 	popl	%ebx
@@ -185,3 +164,4 @@
 	popl	%esi
 	leave
 	ret
+#endif PARANOID
diff -u --recursive --new-file v2.1.72/linux/arch/i386/math-emu/reg_u_div.S linux/arch/i386/math-emu/reg_u_div.S
--- v2.1.72/linux/arch/i386/math-emu/reg_u_div.S	Thu Oct  5 06:30:43 1995
+++ linux/arch/i386/math-emu/reg_u_div.S	Tue Dec  9 17:57:09 1997
@@ -2,22 +2,24 @@
 /*---------------------------------------------------------------------------+
  |  reg_u_div.S                                                              |
  |                                                                           |
- | Core division routines                                                    |
+ | Divide one FPU_REG by another and put the result in a destination FPU_REG.|
  |                                                                           |
- | Copyright (C) 1992,1993,1995                                              |
- |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
- |                       Australia.  E-mail billm@jacobi.maths.monash.edu.au |
+ | Copyright (C) 1992,1993,1995,1997                                         |
+ |                  W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
+ |                  E-mail   billm@suburbia.net                              |
  |                                                                           |
  |                                                                           |
  +---------------------------------------------------------------------------*/
 
 /*---------------------------------------------------------------------------+
- |  Kernel for the division routines.                                        |
- |                                                                           |
- |  void reg_u_div(FPU_REG *a, FPU_REG *a,                                   |
- |                 FPU_REG *dest, unsigned int control_word)                 |
+ | Call from C as:                                                           |
+ |    int FPU_u_div(FPU_REG *a, FPU_REG *b, FPU_REG *dest,                   |
+ |                unsigned int control_word, char *sign)                     |
  |                                                                           |
  |  Does not compute the destination exponent, but does adjust it.           |
+ |                                                                           |
+ |    Return value is the tag of the answer, or-ed with FPU_Exception if     |
+ |    one was raised, or -1 on internal error.                               |
  +---------------------------------------------------------------------------*/
 
 #include "exception.h"
@@ -67,9 +69,12 @@
 	.byte	0
 #endif NON_REENTRANT_FPU
 
+#define REGA	PARAM1
+#define REGB	PARAM2
+#define DEST	PARAM3
 
 .text
-ENTRY(reg_u_div)
+ENTRY(FPU_u_div)
 	pushl	%ebp
 	movl	%esp,%ebp
 #ifndef NON_REENTRANT_FPU
@@ -80,32 +85,28 @@
 	pushl	%edi
 	pushl	%ebx
 
-	movl	PARAM1,%esi	/* pointer to num */
-	movl	PARAM2,%ebx	/* pointer to denom */
-	movl	PARAM3,%edi	/* pointer to answer */
-
-#ifdef DENORM_OPERAND
-	movl	EXP(%esi),%eax
-	cmpl	EXP_UNDER,%eax
-	jg	xOp1_not_denorm
-
-	call	SYMBOL_NAME(denormal_operand)
-	orl	%eax,%eax
-	jnz	fpu_Arith_exit
-
-xOp1_not_denorm:
-	movl	EXP(%ebx),%eax
-	cmpl	EXP_UNDER,%eax
-	jg	xOp2_not_denorm
-
-	call	SYMBOL_NAME(denormal_operand)
-	orl	%eax,%eax
-	jnz	fpu_Arith_exit
+	movl	REGA,%esi
+	movl	REGB,%ebx
+	movl	DEST,%edi
+
+	movw	EXP(%esi),%dx
+	movw	EXP(%ebx),%ax
+	.byte	0x0f,0xbf,0xc0	/* movsx	%ax,%eax */
+	.byte	0x0f,0xbf,0xd2	/* movsx	%dx,%edx */
+	subl	%eax,%edx
+	addl	EXP_BIAS,%edx
+
+	/* A denormal and a large number can cause an exponent underflow */
+	cmpl	EXP_WAY_UNDER,%edx
+	jg	xExp_not_underflow
+
+	/* Set to a really low value allow correct handling */
+	movl	EXP_WAY_UNDER,%edx
+
+xExp_not_underflow:
 
-xOp2_not_denorm:
-#endif DENORM_OPERAND
+	movw    %dx,EXP(%edi)
 
-ENTRY(divide_kernel)
 #ifdef PARANOID
 /*	testl	$0x80000000, SIGH(%esi)	// Dividend */
 /*	je	L_bugged */
@@ -147,7 +148,7 @@
 
 	/* Do the shifting here */
 	/* increase the exponent */
-	incl	EXP(%edi)
+	incw	EXP(%edi)
 
 	/* shift the mantissa right one bit */
 	stc			/* To set the ms bit */
@@ -423,7 +424,7 @@
 	testb	$255,FPU_ovfl_flag	/* was the num > denom ? */
 	je	LRound_precision
 
-	incl	EXP(%edi)
+	incw	EXP(%edi)
 
 	/* shift the mantissa right one bit */
 	stc			/* Will set the ms bit */
@@ -433,7 +434,7 @@
 
 /* Round the result as required */
 LRound_precision:
-	decl	EXP(%edi)	/* binary point between 1st & 2nd bits */
+	decw	EXP(%edi)	/* binary point between 1st & 2nd bits */
 
 	movl	%eax,%edx
 	movl	FPU_result_1,%ebx
@@ -462,6 +463,7 @@
 	jmp	L_exit
 
 L_exit:
+	movl	$-1,%eax
 	popl	%ebx
 	popl	%edi
 	popl	%esi
diff -u --recursive --new-file v2.1.72/linux/arch/i386/math-emu/reg_u_mul.S linux/arch/i386/math-emu/reg_u_mul.S
--- v2.1.72/linux/arch/i386/math-emu/reg_u_mul.S	Thu Oct  5 06:30:43 1995
+++ linux/arch/i386/math-emu/reg_u_mul.S	Tue Dec  9 17:57:09 1997
@@ -4,9 +4,9 @@
  |                                                                           |
  | Core multiplication routine                                               |
  |                                                                           |
- | Copyright (C) 1992,1993,1995                                              |
- |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
- |                       Australia.  E-mail billm@jacobi.maths.monash.edu.au |
+ | Copyright (C) 1992,1993,1995,1997                                         |
+ |                  W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
+ |                  E-mail   billm@suburbia.net                              |
  |                                                                           |
  |                                                                           |
  +---------------------------------------------------------------------------*/
@@ -15,7 +15,7 @@
  |   Basic multiplication routine.                                           |
  |   Does not check the resulting exponent for overflow/underflow            |
  |                                                                           |
- |   reg_u_mul(FPU_REG *a, FPU_REG *b, FPU_REG *c, unsigned int cw);         |
+ |   FPU_u_mul(FPU_REG *a, FPU_REG *b, FPU_REG *c, unsigned int cw);         |
  |                                                                           |
  |   Internal working is at approx 128 bits.                                 |
  |   Result is rounded to nearest 53 or 64 bits, using "nearest or even".    |
@@ -44,7 +44,7 @@
 
 
 .text
-ENTRY(reg_u_mul)
+ENTRY(FPU_u_mul)
 	pushl	%ebp
 	movl	%esp,%ebp
 #ifndef NON_REENTRANT_FPU
@@ -65,27 +65,6 @@
 	jz	L_bugged
 #endif PARANOID
 
-#ifdef DENORM_OPERAND
-	movl	EXP(%esi),%eax
-	cmpl	EXP_UNDER,%eax
-	jg	xOp1_not_denorm
-
-	call	SYMBOL_NAME(denormal_operand)
-	orl	%eax,%eax
-	jnz	fpu_Arith_exit
-
-xOp1_not_denorm:
-	movl	EXP(%edi),%eax
-	cmpl	EXP_UNDER,%eax
-	jg	xOp2_not_denorm
-
-	call	SYMBOL_NAME(denormal_operand)
-	orl	%eax,%eax
-	jnz	fpu_Arith_exit
-
-xOp2_not_denorm:
-#endif DENORM_OPERAND
-
 	xorl	%ecx,%ecx
 	xorl	%ebx,%ebx
 
@@ -111,13 +90,22 @@
 	addl	%eax,%ebx
 	adcl	%edx,%ecx
 
-	movl	EXP(%esi),%eax	/* Compute the exponent */
-	addl	EXP(%edi),%eax
+	/* Get the sum of the exponents. */
+	movl	PARAM6,%eax
 	subl	EXP_BIAS-1,%eax
 
+	/* Two denormals can cause an exponent underflow */
+	cmpl	EXP_WAY_UNDER,%eax
+	jg	Exp_not_underflow
+
+	/* Set to a really low value allow correct handling */
+	movl	EXP_WAY_UNDER,%eax
+
+Exp_not_underflow:
+
 /*  Have now finished with the sources */
 	movl	PARAM3,%edi	/* Point to the destination */
-	movl	%eax,EXP(%edi)
+	movw	%ax,EXP(%edi)
 
 /*  Now make sure that the result is normalized */
 	testl	$0x80000000,%ecx
@@ -128,7 +116,7 @@
 	rcll	$1,FPU_accum_1
 	rcll	$1,%ebx
 	rcll	$1,%ecx
-	decl	EXP(%edi)
+	decw	EXP(%edi)
 
 LResult_Normalised:
 	movl	FPU_accum_0,%eax
diff -u --recursive --new-file v2.1.72/linux/arch/i386/math-emu/reg_u_sub.S linux/arch/i386/math-emu/reg_u_sub.S
--- v2.1.72/linux/arch/i386/math-emu/reg_u_sub.S	Thu Oct  5 06:30:43 1995
+++ linux/arch/i386/math-emu/reg_u_sub.S	Tue Dec  9 17:57:09 1997
@@ -4,21 +4,23 @@
  |                                                                           |
  | Core floating point subtraction routine.                                  |
  |                                                                           |
- | Copyright (C) 1992,1993,1995                                              |
- |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
- |                       Australia.  E-mail billm@jacobi.maths.monash.edu.au |
+ | Copyright (C) 1992,1993,1995,1997                                         |
+ |                  W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
+ |                  E-mail   billm@suburbia.net                              |
  |                                                                           |
  | Call from C as:                                                           |
- |   void reg_u_sub(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *answ,             |
+ |    int FPU_u_sub(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *answ,             |
  |                                                int control_w)             |
+ |    Return value is the tag of the answer, or-ed with FPU_Exception if     |
+ |    one was raised, or -1 on internal error.                               |
  |                                                                           |
  +---------------------------------------------------------------------------*/
 
 /*
- |    Kernel subtraction routine reg_u_sub(reg *arg1, reg *arg2, reg *answ).
- |    Takes two valid reg f.p. numbers (TW_Valid), which are
+ |    Kernel subtraction routine FPU_u_sub(reg *arg1, reg *arg2, reg *answ).
+ |    Takes two valid reg f.p. numbers (TAG_Valid), which are
  |    treated as unsigned numbers,
- |    and returns their difference as a TW_Valid or TW_Zero f.p.
+ |    and returns their difference as a TAG_Valid or TAG_Zero f.p.
  |    number.
  |    The first number (arg1) must be the larger.
  |    The returned number is normalized.
@@ -30,7 +32,7 @@
 #include "control_w.h"
 
 .text
-ENTRY(reg_u_sub)
+ENTRY(FPU_u_sub)
 	pushl	%ebp
 	movl	%esp,%ebp
 	pushl	%esi
@@ -39,28 +41,9 @@
 
 	movl	PARAM1,%esi	/* source 1 */
 	movl	PARAM2,%edi	/* source 2 */
-
-#ifdef DENORM_OPERAND
-	cmpl	EXP_UNDER,EXP(%esi)
-	jg	xOp1_not_denorm
-
-	call	SYMBOL_NAME(denormal_operand)
-	orl	%eax,%eax
-	jnz	fpu_Arith_exit
-
-xOp1_not_denorm:
-	cmpl	EXP_UNDER,EXP(%edi)
-	jg	xOp2_not_denorm
-
-	call	SYMBOL_NAME(denormal_operand)
-	orl	%eax,%eax
-	jnz	fpu_Arith_exit
-
-xOp2_not_denorm:
-#endif DENORM_OPERAND
-
-	movl	EXP(%esi),%ecx
-	subl	EXP(%edi),%ecx	/* exp1 - exp2 */
+	
+	movl	PARAM6,%ecx
+	subl	PARAM7,%ecx	/* exp1 - exp2 */
 
 #ifdef PARANOID
 	/* source 2 is always smaller than source 1 */
@@ -81,10 +64,8 @@
 	movl	SIGL(%edi),%ebx	/* register ls word */
 
 	movl	PARAM3,%edi	/* destination */
-	movl	EXP(%esi),%edx
-	movl	%edx,EXP(%edi)	/* Copy exponent to destination */
-/*	movb	SIGN(%esi),%dl
-	movb	%dl,SIGN(%edi) */	/* Copy the sign from the first arg */
+	movl	PARAM6,%edx
+	movw	%dx,EXP(%edi)	/* Copy exponent to destination */
 
 	xorl	%edx,%edx	/* register extension */
 
@@ -93,8 +74,8 @@
  |      right the required number of	|
  |	places.				|
  +--------------------------------------*/
-L_shift_r:
-	cmpl	$32,%ecx		/* shrd only works for 0..31 bits */
+
+	cmpw	$32,%cx		/* shrd only works for 0..31 bits */
 	jnc	L_more_than_31
 
 /* less than 32 bits */
@@ -104,7 +85,7 @@
 	jmp	L_shift_done
 
 L_more_than_31:
-	cmpl	$64,%ecx
+	cmpw	$64,%cx
 	jnc	L_more_than_63
 
 	subb	$32,%cl
@@ -210,7 +191,7 @@
 	jnz	L_must_be_zero
 
 	/* Shift left 64 bits */
-	subl	$64,EXP(%edi)
+	subw	$64,EXP(%edi)
 	xchg	%edx,%eax
 	jmp	fpu_reg_round
 
@@ -221,17 +202,17 @@
 #endif PARANOID
 
 	/* The result is zero */
-	movb	TW_Zero,TAG(%edi)
-	movl	$0,EXP(%edi)		/* exponent */
+	movw	$0,EXP(%edi)		/* exponent */
 	movl	$0,SIGL(%edi)
 	movl	$0,SIGH(%edi)
-	jmp	L_exit		/* %eax contains zero */
+	movl	TAG_Zero,%eax
+	jmp	L_exit
 
 L_shift_32:
 	movl	%ebx,%eax
 	movl	%edx,%ebx
 	movl	$0,%edx
-	subl	$32,EXP(%edi)	/* Can get underflow here */
+	subw	$32,EXP(%edi)	/* Can get underflow here */
 
 /* We need to shift left by 1 - 31 bits */
 L_shift_1:
@@ -241,7 +222,7 @@
 	shld	%cl,%ebx,%eax
 	shld	%cl,%edx,%ebx
 	shl	%cl,%edx
-	subl	%ecx,EXP(%edi)	/* Can get underflow here */
+	subw	%cx,EXP(%edi)	/* Can get underflow here */
 
 L_round:
 	jmp	fpu_reg_round	/* Round the result */
@@ -277,11 +258,12 @@
 	call	EXCEPTION
 	pop	%ebx
 	jmp	L_error_exit
-#endif PARANOID
-
 
 L_error_exit:
-	movl	$1,%eax
+	movl	$-1,%eax
+
+#endif PARANOID
+
 L_exit:
 	popl	%ebx
 	popl	%edi
diff -u --recursive --new-file v2.1.72/linux/arch/i386/math-emu/version.h linux/arch/i386/math-emu/version.h
--- v2.1.72/linux/arch/i386/math-emu/version.h	Mon May  6 06:31:17 1996
+++ linux/arch/i386/math-emu/version.h	Tue Dec  9 17:57:09 1997
@@ -2,11 +2,11 @@
  |  version.h                                                                |
  |                                                                           |
  |                                                                           |
- | Copyright (C) 1992,1993,1994,1996                                         |
+ | Copyright (C) 1992,1993,1994,1996,1997                                    |
  |                  W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
- |                  E-mail   billm@jacobi.maths.monash.edu.au                |
+ |                  E-mail   billm@suburbia.net                              |
  |                                                                           |
  |                                                                           |
  +---------------------------------------------------------------------------*/
 
-#define FPU_VERSION "wm-FPU-emu version 1.22"
+#define FPU_VERSION "wm-FPU-emu version 2.00"
diff -u --recursive --new-file v2.1.72/linux/arch/i386/math-emu/wm_shrx.S linux/arch/i386/math-emu/wm_shrx.S
--- v2.1.72/linux/arch/i386/math-emu/wm_shrx.S	Thu Oct  5 06:30:43 1995
+++ linux/arch/i386/math-emu/wm_shrx.S	Tue Dec  9 17:57:09 1997
@@ -9,9 +9,9 @@
  |                       Australia.  E-mail billm@jacobi.maths.monash.edu.au |
  |                                                                           |
  | Call from C as:                                                           |
- |   unsigned shrx(void *arg1, unsigned arg2)                                |
+ |   unsigned FPU_shrx(void *arg1, unsigned arg2)                            |
  | and                                                                       |
- |   unsigned shrxs(void *arg1, unsigned arg2)                               |
+ |   unsigned FPU_shrxs(void *arg1, unsigned arg2)                           |
  |                                                                           |
  +---------------------------------------------------------------------------*/
 
@@ -19,7 +19,7 @@
 
 .text
 /*---------------------------------------------------------------------------+
- |   unsigned shrx(void *arg1, unsigned arg2)                                |
+ |   unsigned FPU_shrx(void *arg1, unsigned arg2)                            |
  |                                                                           |
  |   Extended shift right function.                                          |
  |   Fastest for small shifts.                                               |
@@ -32,7 +32,7 @@
  |   Results returned in the 64 bit arg and eax.                             |
  +---------------------------------------------------------------------------*/
 
-ENTRY(shrx)
+ENTRY(FPU_shrx)
 	push	%ebp
 	movl	%esp,%ebp
 	pushl	%esi
@@ -95,7 +95,7 @@
 
 
 /*---------------------------------------------------------------------------+
- |   unsigned shrxs(void *arg1, unsigned arg2)                               |
+ |   unsigned FPU_shrxs(void *arg1, unsigned arg2)                           |
  |                                                                           |
  |   Extended shift right function (optimized for small floating point       |
  |   integers).                                                              |
@@ -110,7 +110,7 @@
  |   part which has been shifted out of the arg.                             |
  |   Results returned in the 64 bit arg and eax.                             |
  +---------------------------------------------------------------------------*/
-ENTRY(shrxs)
+ENTRY(FPU_shrxs)
 	push	%ebp
 	movl	%esp,%ebp
 	pushl	%esi
diff -u --recursive --new-file v2.1.72/linux/arch/i386/math-emu/wm_sqrt.S linux/arch/i386/math-emu/wm_sqrt.S
--- v2.1.72/linux/arch/i386/math-emu/wm_sqrt.S	Thu Oct  5 06:30:43 1995
+++ linux/arch/i386/math-emu/wm_sqrt.S	Tue Dec  9 17:57:09 1997
@@ -4,12 +4,12 @@
  |                                                                           |
  | Fixed point arithmetic square root evaluation.                            |
  |                                                                           |
- | Copyright (C) 1992,1993,1995                                              |
+ | Copyright (C) 1992,1993,1995,1997                                         |
  |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
- |                       Australia.  E-mail billm@jacobi.maths.monash.edu.au |
+ |                       Australia.  E-mail billm@suburbia.net               |
  |                                                                           |
  | Call from C as:                                                           |
- |   void wm_sqrt(FPU_REG *n, unsigned int control_word)                     |
+ |    int wm_sqrt(FPU_REG *n, unsigned int control_word)                     |
  |                                                                           |
  +---------------------------------------------------------------------------*/
 
@@ -92,7 +92,7 @@
 
 /* We use a rough linear estimate for the first guess.. */
 
-	cmpl	EXP_BIAS,EXP(%esi)
+	cmpw	EXP_BIAS,EXP(%esi)
 	jnz	sqrt_arg_ge_2
 
 	shrl	$1,%eax			/* arg is in the range  [1.0 .. 2.0) */
@@ -347,9 +347,8 @@
 	movl	%esi,%eax
 	movl	%edi,%ebx
 	movl	PARAM1,%edi
-	movl	EXP_BIAS,EXP(%edi)	/* Result is in  [1.0 .. 2.0) */
-	movl	PARAM2,%ecx
-	jmp	fpu_reg_round_sqrt
+	movw	EXP_BIAS,EXP(%edi)	/* Result is in  [1.0 .. 2.0) */
+	jmp	fpu_reg_round
 
 
 sqrt_near_exact_x:
diff -u --recursive --new-file v2.1.72/linux/arch/m68k/amiga/amifb.c linux/arch/m68k/amiga/amifb.c
--- v2.1.72/linux/arch/m68k/amiga/amifb.c	Mon Jul  7 08:18:53 1997
+++ linux/arch/m68k/amiga/amifb.c	Wed Dec 31 16:00:00 1969
@@ -1,3633 +0,0 @@
-/*
- * linux/arch/m68k/amiga/amifb.c -- Low level implementation of the Amiga frame
- *                                  buffer device
- *
- *    Copyright (C) 1995 Geert Uytterhoeven
- *
- *          with work by Roman Zippel
- *
- *
- * This file is based on the Atari frame buffer device (atafb.c):
- *
- *    Copyright (C) 1994 Martin Schaller
- *                       Roman Hodek
- *
- *          with work by Andreas Schwab
- *                       Guenther Kelleter
- *
- * and on the original Amiga console driver (amicon.c):
- *
- *    Copyright (C) 1993 Hamish Macdonald
- *                       Greg Harp
- *    Copyright (C) 1994 David Carter [carter@compsci.bristol.ac.uk]
- *
- *          with work by William Rucklidge (wjr@cs.cornell.edu)
- *                       Geert Uytterhoeven
- *                       Jes Sorensen (jds@kom.auc.dk)
- *
- *
- * History:
- *
- *   - 24 Jul 96: Copper generates now vblank interrupt and
- *                VESA Power Saving Protocol is fully implemented
- *   - 14 Jul 96: Rework and hopefully last ECS bugs fixed
- *   -  7 Mar 96: Hardware sprite support by Roman Zippel
- *   - 18 Feb 96: OCS and ECS support by Roman Zippel
- *                Hardware functions completely rewritten
- *   -  2 Dec 95: AGA version by Geert Uytterhoeven
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file COPYING in the main directory of this archive
- * for more details.
- */
-
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/tty.h>
-#include <linux/malloc.h>
-#include <linux/delay.h>
-#include <linux/config.h>
-#include <linux/interrupt.h>
-#include <linux/fb.h>
-#include <linux/init.h>
-
-#include <asm/uaccess.h>
-#include <asm/system.h>
-#include <asm/irq.h>
-#include <asm/amigahw.h>
-#include <asm/amigaints.h>
-
-#define DEBUG
-
-#if !defined(CONFIG_AMIFB_OCS) && !defined(CONFIG_AMIFB_ECS) && !defined(CONFIG_AMIFB_AGA)
-#define CONFIG_AMIFB_OCS   /* define at least one fb driver, this will change later */
-#endif
-
-#if !defined(CONFIG_AMIFB_OCS)
-#  define IS_OCS (0)
-#elif defined(CONFIG_AMIFB_ECS) || defined(CONFIG_AMIFB_AGA)
-#  define IS_OCS (chipset == TAG_OCS)
-#else
-#  define CONFIG_AMIFB_OCS_ONLY
-#  define IS_OCS (1)
-#endif
-
-#if !defined(CONFIG_AMIFB_ECS)
-#  define IS_ECS (0)
-#elif defined(CONFIG_AMIFB_OCS) || defined(CONFIG_AMIFB_AGA)
-#  define IS_ECS (chipset == TAG_ECS)
-#else
-#  define CONFIG_AMIFB_ECS_ONLY
-#  define IS_ECS (1)
-#endif
-
-#if !defined(CONFIG_AMIFB_AGA)
-#  define IS_AGA (0)
-#elif defined(CONFIG_AMIFB_OCS) || defined(CONFIG_AMIFB_ECS)
-#  define IS_AGA (chipset == TAG_AGA)
-#else
-#  define CONFIG_AMIFB_AGA_ONLY
-#  define IS_AGA (1)
-#endif
-
-/*******************************************************************************
-
-
-   Generic video timings
-   ---------------------
-
-   Timings used by the frame buffer interface:
-
-   +----------+---------------------------------------------+----------+-------+
-   |          |                ^                            |          |       |
-   |          |                |upper_margin                |          |       |
-   |          |                ¥                            |          |       |
-   +----------###############################################----------+-------+
-   |          #                ^                            #          |       |
-   |          #                |                            #          |       |
-   |          #                |                            #          |       |
-   |          #                |                            #          |       |
-   |   left   #                |                            #  right   | hsync |
-   |  margin  #                |       xres                 #  margin  |  len  |
-   |<-------->#<---------------+--------------------------->#<-------->|<----->|
-   |          #                |                            #          |       |
-   |          #                |                            #          |       |
-   |          #                |                            #          |       |
-   |          #                |yres                        #          |       |
-   |          #                |                            #          |       |
-   |          #                |                            #          |       |
-   |          #                |                            #          |       |
-   |          #                |                            #          |       |
-   |          #                |                            #          |       |
-   |          #                |                            #          |       |
-   |          #                |                            #          |       |
-   |          #                |                            #          |       |
-   |          #                ¥                            #          |       |
-   +----------###############################################----------+-------+
-   |          |                ^                            |          |       |
-   |          |                |lower_margin                |          |       |
-   |          |                ¥                            |          |       |
-   +----------+---------------------------------------------+----------+-------+
-   |          |                ^                            |          |       |
-   |          |                |vsync_len                   |          |       |
-   |          |                ¥                            |          |       |
-   +----------+---------------------------------------------+----------+-------+
-
-
-   Amiga video timings
-   -------------------
-
-   The Amiga native chipsets uses another timing scheme:
-
-      - hsstrt:   Start of horizontal synchronization pulse
-      - hsstop:   End of horizontal synchronization pulse
-      - htotal:   Last value on the line (i.e. line length = htotal+1)
-      - vsstrt:   Start of vertical synchronization pulse
-      - vsstop:   End of vertical synchronization pulse
-      - vtotal:   Last line value (i.e. number of lines = vtotal+1)
-      - hcenter:  Start of vertical retrace for interlace
-
-   You can specify the blanking timings independently. Currently I just set
-   them equal to the respective synchronization values:
-
-      - hbstrt:   Start of horizontal blank
-      - hbstop:   End of horizontal blank
-      - vbstrt:   Start of vertical blank
-      - vbstop:   End of vertical blank
-
-   Horizontal values are in color clock cycles (280 ns), vertical values are in
-   scanlines.
-
-   (0, 0) is somewhere in the upper-left corner :-)
-
-
-   Amiga visible window definitions
-   --------------------------------
-
-   Currently I only have values for AGA, SHRES (28 MHz dotclock). Feel free to
-   make corrections and/or additions.
-
-   Within the above synchronization specifications, the visible window is
-   defined by the following parameters (actual register resolutions may be
-   different; all horizontal values are normalized with respect to the pixel
-   clock):
-
-      - diwstrt_h:   Horizontal start of the visible window
-      - diwstop_h:   Horizontal stop+1(*) of the visible window
-      - diwstrt_v:   Vertical start of the visible window
-      - diwstop_v:   Vertical stop of the visible window
-      - ddfstrt:     Horizontal start of display DMA
-      - ddfstop:     Horizontal stop of display DMA
-      - hscroll:     Horizontal display output delay
-
-   Sprite positioning:
-
-      - sprstrt_h:   Horizontal start-4 of sprite
-      - sprstrt_v:   Vertical start of sprite
-
-   (*) Even Commodore did it wrong in the AGA monitor drivers by not adding 1.
-
-   Horizontal values are in dotclock cycles (35 ns), vertical values are in
-   scanlines.
-
-   (0, 0) is somewhere in the upper-left corner :-)
-
-
-   Dependencies (AGA, SHRES (35 ns dotclock))
-   -------------------------------------------
-
-   Since there are much more parameters for the Amiga display than for the
-   frame buffer interface, there must be some dependencies among the Amiga
-   display parameters. Here's what I found out:
-
-      - ddfstrt and ddfstop are best aligned to 64 pixels.
-      - the chipset needs 64+4 horizontal pixels after the DMA start before the
-        first pixel is output, so diwstrt_h = ddfstrt+64+4 if you want to
-        display the first pixel on the line too. Increase diwstrt_h for virtual
-        screen panning.
-      - the display DMA always fetches 64 pixels at a time (fmode = 3).
-      - ddfstop is ddfstrt+#pixels-64.
-      - diwstop_h = diwstrt_h+xres+1. Because of the additional 1 this can be 1
-        more than htotal.
-      - hscroll simply adds a delay to the display output. Smooth horizontal
-        panning needs an extra 64 pixels on the left to prefetch the pixels that
-        `fall off' on the left.
-      - if ddfstrt < 192, the sprite DMA cycles are all stolen by the bitplane
-        DMA, so it's best to make the DMA start as late as possible.
-      - you really don't want to make ddfstrt < 128, since this will steal DMA
-        cycles from the other DMA channels (audio, floppy and Chip RAM refresh).
-      - I make diwstop_h and diwstop_v as large as possible.
-
-   General dependencies
-   --------------------
-
-      - all values are SHRES pixel (35ns)
-
-                  table 1:fetchstart  table 2:prefetch    table 3:fetchsize
-                  ------------------  ----------------    -----------------
-   Pixclock     # SHRES|HIRES|LORES # SHRES|HIRES|LORES # SHRES|HIRES|LORES
-   -------------#------+-----+------#------+-----+------#------+-----+------
-   Bus width 1x #   16 |  32 |  64  #   16 |  32 |  64  #   64 |  64 |  64
-   Bus width 2x #   32 |  64 | 128  #   32 |  64 |  64  #   64 |  64 | 128
-   Bus width 4x #   64 | 128 | 256  #   64 |  64 |  64  #   64 | 128 | 256
-
-      - chipset needs 4 pixels before the first pixel is output
-      - ddfstrt must be aligned to fetchstart (table 1)
-      - chipset needs also prefetch (table 2) to get first pixel data, so
-        ddfstrt = ((diwstrt_h-4) & -fetchstart) - prefetch
-      - for horizontal panning decrease diwstrt_h
-      - the length of a fetchline must be aligned to fetchsize (table 3)
-      - if fetchstart is smaller than fetchsize, then ddfstrt can a little bit
-        moved to optimize use of dma (usefull for OCS/ECS overscan displays)
-      - ddfstop is ddfstrt+ddfsize-fetchsize
-      - If C= didn't change anything for AGA, then at following positions the
-        dma bus is allready used:
-        ddfstrt <  48 -> memory refresh
-                <  96 -> disk dma
-                < 160 -> audio dma
-                < 192 -> sprite 0 dma
-                < 416 -> sprite dma (32 per sprite)
-      - in accordance with the hardware reference manual a hardware stop is at
-        192, but AGA (ECS?) can go below this.
-
-   DMA priorities
-   --------------
-
-   Since there are limits on the earliest start value for display DMA and the
-   display of sprites, I use the following policy on horizontal panning and
-   the hardware cursor:
-
-      - if you want to start display DMA too early, you loose the ability to
-        do smooth horizontal panning (xpanstep 1 -> 64).
-      - if you want to go even further, you loose the hardware cursor too.
-
-   IMHO a hardware cursor is more important for X than horizontal scrolling,
-   so that's my motivation.
-
-
-   Implementation
-   --------------
-
-   ami_decode_var() converts the frame buffer values to the Amiga values. It's
-   just a `straightforward' implementation of the above rules.
-
-
-   Standard VGA timings
-   --------------------
-
-               xres  yres    left  right  upper  lower    hsync    vsync
-               ----  ----    ----  -----  -----  -----    -----    -----
-      80x25     720   400      27     45     35     12      108        2
-      80x30     720   480      27     45     30      9      108        2
-
-   These were taken from a XFree86 configuration file, recalculated for a 28 MHz
-   dotclock (Amigas don't have a 25 MHz dotclock) and converted to frame buffer
-   generic timings.
-
-   As a comparison, graphics/monitor.h suggests the following:
-
-               xres  yres    left  right  upper  lower    hsync    vsync
-               ----  ----    ----  -----  -----  -----    -----    -----
-
-      VGA       640   480      52    112     24     19    112 -      2 +
-      VGA70     640   400      52    112     27     21    112 -      2 -
-
-
-   Sync polarities
-   ---------------
-
-      VSYNC    HSYNC    Vertical size    Vertical total
-      -----    -----    -------------    --------------
-        +        +           Reserved          Reserved
-        +        -                400               414
-        -        +                350               362
-        -        -                480               496
-
-   Source: CL-GD542X Technical Reference Manual, Cirrus Logic, Oct 1992
-
-
-   Broadcast video timings
-   -----------------------
-
-   According to the CCIR and RETMA specifications, we have the following values:
-
-   CCIR -> PAL
-   -----------
-
-      - a scanline is 64 µs long, of which 52.48 µs are visible. This is about
-        736 visible 70 ns pixels per line.
-      - we have 625 scanlines, of which 575 are visible (interlaced); after
-        rounding this becomes 576.
-
-   RETMA -> NTSC
-   -------------
-
-      - a scanline is 63.5 µs long, of which 53.5 µs are visible.  This is about
-        736 visible 70 ns pixels per line.
-      - we have 525 scanlines, of which 485 are visible (interlaced); after
-        rounding this becomes 484.
-
-   Thus if you want a PAL compatible display, you have to do the following:
-
-      - set the FB_SYNC_BROADCAST flag to indicate that standard broadcast
-        timings are to be used.
-      - make sure upper_margin+yres+lower_margin+vsync_len = 625 for an
-        interlaced, 312 for a non-interlaced and 156 for a doublescanned
-        display.
-      - make sure left_margin+xres+right_margin+hsync_len = 1816 for a SHRES,
-        908 for a HIRES and 454 for a LORES display.
-      - the left visible part begins at 360 (SHRES; HIRES:180, LORES:90),
-        left_margin+2*hsync_len must be greater or equal.
-      - the upper visible part begins at 48 (interlaced; non-interlaced:24,
-        doublescanned:12), upper_margin+2*vsync_len must be greater or equal.
-      - ami_encode_var() calculates margins with a hsync of 5320 ns and a vsync
-        of 4 scanlines
-
-   The settings for a NTSC compatible display are straightforward.
-
-   Note that in a strict sense the PAL and NTSC standards only define the
-   encoding of the color part (chrominance) of the video signal and don't say
-   anything about horizontal/vertical synchronization nor refresh rates.
-
-
-                                                            -- Geert --
-
-*******************************************************************************/
-
-
-	/*
-	 * Custom Chipset Definitions
-	 */
-
-#define CUSTOM_OFS(fld) ((long)&((struct CUSTOM*)0)->fld)
-
-	/*
-	 * BPLCON0 -- Bitplane Control Register 0
-	 */
-
-#define BPC0_HIRES	(0x8000)
-#define BPC0_BPU2	(0x4000) /* Bit plane used count */
-#define BPC0_BPU1	(0x2000)
-#define BPC0_BPU0	(0x1000)
-#define BPC0_HAM	(0x0800) /* HAM mode */
-#define BPC0_DPF	(0x0400) /* Double playfield */
-#define BPC0_COLOR	(0x0200) /* Enable colorburst */
-#define BPC0_GAUD	(0x0100) /* Genlock audio enable */
-#define BPC0_UHRES	(0x0080) /* Ultrahi res enable */
-#define BPC0_SHRES	(0x0040) /* Super hi res mode */
-#define BPC0_BYPASS	(0x0020) /* Bypass LUT - AGA */
-#define BPC0_BPU3	(0x0010) /* AGA */
-#define BPC0_LPEN	(0x0008) /* Light pen enable */
-#define BPC0_LACE	(0x0004) /* Interlace */
-#define BPC0_ERSY	(0x0002) /* External resync */
-#define BPC0_ECSENA	(0x0001) /* ECS enable */
-
-	/*
-	 * BPLCON2 -- Bitplane Control Register 2
-	 */
-
-#define BPC2_ZDBPSEL2	(0x4000) /* Bitplane to be used for ZD - AGA */
-#define BPC2_ZDBPSEL1	(0x2000)
-#define BPC2_ZDBPSEL0	(0x1000)
-#define BPC2_ZDBPEN	(0x0800) /* Enable ZD with ZDBPSELx - AGA */
-#define BPC2_ZDCTEN	(0x0400) /* Enable ZD with palette bit #31 - AGA */
-#define BPC2_KILLEHB	(0x0200) /* Kill EHB mode - AGA */
-#define BPC2_RDRAM	(0x0100) /* Color table accesses read, not write - AGA */
-#define BPC2_SOGEN	(0x0080) /* SOG output pin high - AGA */
-#define BPC2_PF2PRI	(0x0040) /* PF2 priority over PF1 */
-#define BPC2_PF2P2	(0x0020) /* PF2 priority wrt sprites */
-#define BPC2_PF2P1	(0x0010)
-#define BPC2_PF2P0	(0x0008)
-#define BPC2_PF1P2	(0x0004) /* ditto PF1 */
-#define BPC2_PF1P1	(0x0002)
-#define BPC2_PF1P0	(0x0001)
-
-	/*
-	 * BPLCON3 -- Bitplane Control Register 3 (AGA)
-	 */
-
-#define BPC3_BANK2	(0x8000) /* Bits to select color register bank */
-#define BPC3_BANK1	(0x4000)
-#define BPC3_BANK0	(0x2000)
-#define BPC3_PF2OF2	(0x1000) /* Bits for color table offset when PF2 */
-#define BPC3_PF2OF1	(0x0800)
-#define BPC3_PF2OF0	(0x0400)
-#define BPC3_LOCT	(0x0200) /* Color register writes go to low bits */
-#define BPC3_SPRES1	(0x0080) /* Sprite resolution bits */
-#define BPC3_SPRES0	(0x0040)
-#define BPC3_BRDRBLNK	(0x0020) /* Border blanked? */
-#define BPC3_BRDRTRAN	(0x0010) /* Border transparent? */
-#define BPC3_ZDCLKEN	(0x0004) /* ZD pin is 14 MHz (HIRES) clock output */
-#define BPC3_BRDRSPRT	(0x0002) /* Sprites in border? */
-#define BPC3_EXTBLKEN	(0x0001) /* BLANK programmable */
-
-	/*
-	 * BPLCON4 -- Bitplane Control Register 4 (AGA)
-	 */
-
-#define BPC4_BPLAM7	(0x8000) /* bitplane color XOR field */
-#define BPC4_BPLAM6	(0x4000)
-#define BPC4_BPLAM5	(0x2000)
-#define BPC4_BPLAM4	(0x1000)
-#define BPC4_BPLAM3	(0x0800)
-#define BPC4_BPLAM2	(0x0400)
-#define BPC4_BPLAM1	(0x0200)
-#define BPC4_BPLAM0	(0x0100)
-#define BPC4_ESPRM7	(0x0080) /* 4 high bits for even sprite colors */
-#define BPC4_ESPRM6	(0x0040)
-#define BPC4_ESPRM5	(0x0020)
-#define BPC4_ESPRM4	(0x0010)
-#define BPC4_OSPRM7	(0x0008) /* 4 high bits for odd sprite colors */
-#define BPC4_OSPRM6	(0x0004)
-#define BPC4_OSPRM5	(0x0002)
-#define BPC4_OSPRM4	(0x0001)
-
-	/*
-	 * BEAMCON0 -- Beam Control Register
-	 */
-
-#define BMC0_HARDDIS	(0x4000) /* Disable hardware limits */
-#define BMC0_LPENDIS	(0x2000) /* Disable light pen latch */
-#define BMC0_VARVBEN	(0x1000) /* Enable variable vertical blank */
-#define BMC0_LOLDIS	(0x0800) /* Disable long/short line toggle */
-#define BMC0_CSCBEN	(0x0400) /* Composite sync/blank */
-#define BMC0_VARVSYEN	(0x0200) /* Enable variable vertical sync */
-#define BMC0_VARHSYEN	(0x0100) /* Enable variable horizontal sync */
-#define BMC0_VARBEAMEN	(0x0080) /* Enable variable beam counters */
-#define BMC0_DUAL	(0x0040) /* Enable alternate horizontal beam counter */
-#define BMC0_PAL	(0x0020) /* Set decodes for PAL */
-#define BMC0_VARCSYEN	(0x0010) /* Enable variable composite sync */
-#define BMC0_BLANKEN	(0x0008) /* Blank enable (no longer used on AGA) */
-#define BMC0_CSYTRUE	(0x0004) /* CSY polarity */
-#define BMC0_VSYTRUE	(0x0002) /* VSY polarity */
-#define BMC0_HSYTRUE	(0x0001) /* HSY polarity */
-
-
-	/*
-	 * FMODE -- Fetch Mode Control Register (AGA)
-	 */
-
-#define FMODE_SSCAN2	(0x8000) /* Sprite scan-doubling */
-#define FMODE_BSCAN2	(0x4000) /* Use PF2 modulus every other line */
-#define FMODE_SPAGEM	(0x0008) /* Sprite page mode */
-#define FMODE_SPR32	(0x0004) /* Sprite 32 bit fetch */
-#define FMODE_BPAGEM	(0x0002) /* Bitplane page mode */
-#define FMODE_BPL32	(0x0001) /* Bitplane 32 bit fetch */
-
-	/*
-	 * Tags used to indicate a specific Pixel Clock
-	 *
-	 * clk_shift is the shift value to get the timings in 35 ns units
-	 */
-
-enum { TAG_SHRES, TAG_HIRES, TAG_LORES };
-
-	/*
-	 * Tags used to indicate the specific chipset
-	 */
-
-enum { TAG_OCS, TAG_ECS, TAG_AGA };
-
-	/*
-	 * Tags used to indicate the memory bandwidth
-	 */
-
-enum { TAG_FMODE_1, TAG_FMODE_2, TAG_FMODE_4 };
-
-
-	/*
-	 * Clock Definitions, Maximum Display Depth
-	 *
-	 * These depend on the E-Clock or the Chipset, so they are filled in
-	 * dynamically
-	 */
-
-static u_long pixclock[3];	/* SHRES/HIRES/LORES: index = clk_shift */
-static u_short maxdepth[3];	/* SHRES/HIRES/LORES: index = clk_shift */
-static u_short maxfmode, chipset;
-
-
-	/*
-	 * Broadcast Video Timings
-	 *
-	 * Horizontal values are in 35 ns (SHRES) units
-	 * Vertical values are in interlaced scanlines
-	 */
-
-#define PAL_DIWSTRT_H	(360)	/* PAL Window Limits */
-#define PAL_DIWSTRT_V	(48)
-#define PAL_HTOTAL	(1816)
-#define PAL_VTOTAL	(625)
-
-#define NTSC_DIWSTRT_H	(360)	/* NTSC Window Limits */
-#define NTSC_DIWSTRT_V	(40)
-#define NTSC_HTOTAL	(1816)
-#define NTSC_VTOTAL	(525)
-
-
-	/*
-	 * Monitor Specifications
-	 *
-	 * These are typical for a `generic' Amiga monitor (e.g. A1960)
-	 */
-
-static long vfmin = 50, vfmax = 90, hfmin = 15000, hfmax = 38000;
-
-
-	/*
-	 * Various macros
-	 */
-
-#define up2(v)		(((v)+1) & -2)
-#define down2(v)	((v) & -2)
-#define div2(v)		((v)>>1)
-#define mod2(v)		((v) & 1)
-
-#define up4(v)		(((v)+3) & -4)
-#define down4(v)	((v) & -4)
-#define mul4(v)		((v)<<2)
-#define div4(v)		((v)>>2)
-#define mod4(v)		((v) & 3)
-
-#define up8(v)		(((v)+7) & -8)
-#define down8(v)	((v) & -8)
-#define div8(v)		((v)>>3)
-#define mod8(v)		((v) & 7)
-
-#define up16(v)		(((v)+15) & -16)
-#define down16(v)	((v) & -16)
-#define div16(v)	((v)>>4)
-#define mod16(v)	((v) & 15)
-
-#define up32(v)		(((v)+31) & -32)
-#define down32(v)	((v) & -32)
-#define div32(v)	((v)>>5)
-#define mod32(v)	((v) & 31)
-
-#define up64(v)		(((v)+63) & -64)
-#define down64(v)	((v) & -64)
-#define div64(v)	((v)>>6)
-#define mod64(v)	((v) & 63)
-
-#define upx(x,v)	(((v)+(x)-1) & -(x))
-#define downx(x,v)	((v) & -(x))
-#define modx(x,v)	((v) & ((x)-1))
-
-/* if x1 is not a constant, this macro won't make real sense :-) */
-#define DIVUL(x1, x2) ({int res; asm("divul %1,%2,%3": "=d" (res): \
-	"d" (x2), "d" ((long)((x1)/0x100000000ULL)), "0" ((long)(x1))); res;})
-
-#define min(a, b)	((a) < (b) ? (a) : (b))
-#define max(a, b)	((a) > (b) ? (a) : (b))
-
-#define highw(x)	((u_long)(x)>>16 & 0xffff)
-#define loww(x)		((u_long)(x) & 0xffff)
-
-#define arraysize(x)	(sizeof(x)/sizeof(*(x)))
-
-#define VBlankOn()	custom.intena = IF_SETCLR|IF_COPER
-#define VBlankOff()	custom.intena = IF_COPER
-
-
-	/*
-	 * Chip RAM we reserve for the Frame Buffer
-	 *
-	 * This defines the Maximum Virtual Screen Size
-	 * (Setable per kernel options?)
-	 */
-
-#define VIDEOMEMSIZE_AGA_2M	(1310720) /* AGA (2MB) : max 1280*1024*256  */
-#define VIDEOMEMSIZE_AGA_1M	(786432)  /* AGA (1MB) : max 1024*768*256   */
-#define VIDEOMEMSIZE_ECS_2M	(655360)  /* ECS (2MB) : max 1280*1024*16   */
-#define VIDEOMEMSIZE_ECS_1M	(393216)  /* ECS (1MB) : max 1024*768*16    */
-#define VIDEOMEMSIZE_OCS	(262144)  /* OCS       : max ca. 800*600*16 */
-
-#define SPRITEMEMSIZE		(64*64/4) /* max 64*64*4 */
-#define DUMMYSPRITEMEMSIZE	(8)
-
-#define CHIPRAM_SAFETY_LIMIT	(16384)
-
-static u_long videomemory, spritememory;
-static u_long videomemorysize;
-
-	/*
-	 * This is the earliest allowed start of fetching display data.
-	 * Only if you really want no hardware cursor and audio,
-	 * set this to 128, but let it better at 192
-	 */
-
-static u_long min_fstrt = 192;
-
-#define assignchunk(name, type, ptr, size) \
-{ \
-	(name) = (type)(ptr); \
-	ptr += size; \
-}
-
-
-	/*
-	 * Copper Instructions
-	 */
-
-#define CMOVE(val, reg)		(CUSTOM_OFS(reg)<<16 | (val))
-#define CMOVE2(val, reg)	((CUSTOM_OFS(reg)+2)<<16 | (val))
-#define CWAIT(x, y)		(((y) & 0x1fe)<<23 | ((x) & 0x7f0)<<13 | 0x0001fffe)
-#define CEND			(0xfffffffe)
-
-
-typedef union {
-	u_long l;
-	u_short w[2];
-} copins;
-
-static struct copdisplay {
-	copins *init;
-	copins *wait;
-	copins *list[2][2];
-	copins *rebuild[2];
-} copdisplay;
-
-static u_short currentcop = 0;
-
-	/*
-	 * Hardware Cursor
-	 */
-
-static int cursorrate = 20;	/* Number of frames/flash toggle */
-static u_short cursorstate = -1;
-static u_short cursormode = FB_CURSOR_OFF;
-
-static u_short *lofsprite, *shfsprite, *dummysprite;
-
-	/*
-	 * Current Video Mode
-	 */
-
-static struct amiga_fb_par {
-
-	/* General Values */
-
-	int xres;		/* vmode */
-	int yres;		/* vmode */
-	int vxres;		/* vmode */
-	int vyres;		/* vmode */
-	int xoffset;		/* vmode */
-	int yoffset;		/* vmode */
-	u_short bpp;		/* vmode */
-	u_short clk_shift;	/* vmode */
-	u_short line_shift;	/* vmode */
-	int vmode;		/* vmode */
-	u_short diwstrt_h;	/* vmode */
-	u_short diwstop_h;	/* vmode */
-	u_short diwstrt_v;	/* vmode */
-	u_short diwstop_v;	/* vmode */
-	u_long next_line;	/* modulo for next line */
-	u_long next_plane;	/* modulo for next plane */
-
-	/* Cursor Values */
-
-	struct {
-		short crsr_x;	/* movecursor */
-		short crsr_y;	/* movecursor */
-		short spot_x;
-		short spot_y;
-		u_short height;
-		u_short width;
-		u_short fmode;
-	} crsr;
-
-	/* OCS Hardware Registers */
-
-	u_long bplpt0;		/* vmode, pan (Note: physical address) */
-	u_long bplpt0wrap;	/* vmode, pan (Note: physical address) */
-	u_short ddfstrt;
-	u_short ddfstop;
-	u_short bpl1mod;
-	u_short bpl2mod;
-	u_short bplcon0;	/* vmode */
-	u_short bplcon1;	/* vmode */
-	u_short htotal;		/* vmode */
-	u_short vtotal;		/* vmode */
-
-	/* Additional ECS Hardware Registers */
-
-	u_short bplcon3;	/* vmode */
-	u_short beamcon0;	/* vmode */
-	u_short hsstrt;		/* vmode */
-	u_short hsstop;		/* vmode */
-	u_short hbstrt;		/* vmode */
-	u_short hbstop;		/* vmode */
-	u_short vsstrt;		/* vmode */
-	u_short vsstop;		/* vmode */
-	u_short vbstrt;		/* vmode */
-	u_short vbstop;		/* vmode */
-	u_short hcenter;	/* vmode */
-
-	/* Additional AGA Hardware Registers */
-
-	u_short fmode;		/* vmode */
-} currentpar;
-
-static int currcon = 0;
-
-static struct display disp[MAX_NR_CONSOLES];
-static struct fb_info fb_info;
-
-static int node;		/* node of the /dev/fb?current file */
-
-	/*
-	 * The minimum period for audio depends on htotal (for OCS/ECS/AGA)
-	 * (Imported from arch/m68k/amiga/amisound.c)
-	 */
-
-extern volatile u_short amiga_audio_min_period;
-
-	/*
-	 * Since we can't read the palette on OCS/ECS, and since reading one
-	 * single color palette entry require 5 expensive custom chip bus accesses
-	 * on AGA, we keep a copy of the current palette.
-	 */
-
-#if defined(CONFIG_AMIFB_AGA)
-static struct { u_char red, green, blue, pad; } palette[256];
-#else
-static struct { u_char red, green, blue, pad; } palette[32];
-#endif
-
-#if defined(CONFIG_AMIFB_ECS)
-static u_short ecs_palette[32];
-#endif
-
-	/*
-	 * Latches for Display Changes during VBlank
-	 */
-
-static u_short do_vmode_full = 0;	/* Change the Video Mode */
-static u_short do_vmode_pan = 0;	/* Update the Video Mode */
-static short do_blank = 0;		/* (Un)Blank the Screen (±1) */
-static u_short do_cursor = 0;		/* Move the Cursor */
-
-
-	/*
-	 * Various Flags
-	 */
-
-static u_short is_blanked = 0;		/* Screen is Blanked */
-static u_short is_lace = 0;		/* Screen is laced */
-
-	/*
-	 * Frame Buffer Name
-	 *
-	 * The rest of the name is filled in during initialization
-	 */
-
-static char amiga_fb_name[16] = "Amiga ";
-
-	/*
-	 * Predefined Video Mode Names
-	 *
-	 * The a2024-?? modes don't work yet because there's no A2024 driver.
-	 */
-
-static char *amiga_fb_modenames[] = {
-
-	/*
-	 * Autodetect (Default) Video Mode
-	 */
-
-	"default",
-
-	/*
-	 * AmigaOS Video Modes
-	 */
-
-	"ntsc",			/* 640x200, 15 kHz, 60 Hz (NTSC) */
-	"ntsc-lace",		/* 640x400, 15 kHz, 60 Hz interlaced (NTSC) */
-	"pal",			/* 640x256, 15 kHz, 50 Hz (PAL) */
-	"pal-lace",		/* 640x512, 15 kHz, 50 Hz interlaced (PAL) */
-	"multiscan",		/* 640x480, 29 kHz, 57 Hz */
-	"multiscan-lace",	/* 640x960, 29 kHz, 57 Hz interlaced */
-	"a2024-10",		/* 1024x800, 10 Hz (Not yet supported) */
-	"a2024-15",		/* 1024x800, 15 Hz (Not yet supported) */
-	"euro36",		/* 640x200, 15 kHz, 72 Hz */
-	"euro36-lace",		/* 640x400, 15 kHz, 72 Hz interlaced */
-	"euro72",		/* 640x400, 29 kHz, 68 Hz */
-	"euro72-lace",		/* 640x800, 29 kHz, 68 Hz interlaced */
-	"super72",		/* 800x300, 23 kHz, 70 Hz */
-	"super72-lace",		/* 800x600, 23 kHz, 70 Hz interlaced */
-	"dblntsc",		/* 640x200, 27 kHz, 57 Hz doublescan */
-	"dblntsc-ff",		/* 640x400, 27 kHz, 57 Hz */
-	"dblntsc-lace",		/* 640x800, 27 kHz, 57 Hz interlaced */
-	"dblpal",		/* 640x256, 27 kHz, 47 Hz doublescan */
-	"dblpal-ff",		/* 640x512, 27 kHz, 47 Hz */
-	"dblpal-lace",		/* 640x1024, 27 kHz, 47 Hz interlaced */
-
-	/*
-	 * VGA Video Modes
-	 */
-
-	"vga",			/* 640x480, 31 kHz, 60 Hz (VGA) */
-	"vga70",		/* 640x400, 31 kHz, 70 Hz (VGA) */
-
-	/*
-	 * User Defined Video Modes: to be set after boot up using e.g. fbset
-	 */
-
-	"user0", "user1", "user2", "user3", "user4", "user5", "user6", "user7"
-};
-
-static struct fb_var_screeninfo amiga_fb_predefined[] = {
-
-	/*
-	 * Autodetect (Default) Video Mode
-	 */
-
-	{ 0, },
-
-	/*
-	 * AmigaOS Video Modes
-	 */
-
-	{
-		/* ntsc */
-		640, 200, 640, 200, 0, 0, 4, 0,
-		{0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
-		0, 0, -1, -1, FB_ACCEL_NONE, TAG_HIRES, 106, 86, 44, 16, 76, 2,
-		FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
-	}, {
-		/* ntsc-lace */
-		640, 400, 640, 400, 0, 0, 4, 0,
-		{0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
-		0, 0, -1, -1, FB_ACCEL_NONE, TAG_HIRES, 106, 86, 88, 33, 76, 4,
-		FB_SYNC_BROADCAST, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
-	}, {
-		/* pal */
-		640, 256, 640, 256, 0, 0, 4, 0,
-		{0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
-		0, 0, -1, -1, FB_ACCEL_NONE, TAG_HIRES, 106, 86, 40, 14, 76, 2,
-		FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
-	}, {
-		/* pal-lace */
-		640, 512, 640, 512, 0, 0, 4, 0,
-		{0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
-		0, 0, -1, -1, FB_ACCEL_NONE, TAG_HIRES, 106, 86, 80, 29, 76, 4,
-		FB_SYNC_BROADCAST, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
-	}, {
-		/* multiscan */
-		640, 480, 640, 480, 0, 0, 4, 0,
-		{0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
-		0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 96, 112, 29, 8, 72, 8,
-		0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
-
-	}, {
-		/* multiscan-lace */
-		640, 960, 640, 960, 0, 0, 4, 0,
-		{0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
-		0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 96, 112, 58, 16, 72, 16,
-		0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
-	}, {
-		/* a2024-10 (Not yet supported) */
-		1024, 800, 1024, 800, 0, 0, 2, 0,
-		{0, 2, 0}, {0, 2, 0}, {0, 2, 0}, {0, 0, 0},
-		0, 0, -1, -1, FB_ACCEL_NONE, TAG_HIRES, 0, 0, 0, 0, 0, 0,
-		0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
-	}, {
-		/* a2024-15 (Not yet supported) */
-		1024, 800, 1024, 800, 0, 0, 2, 0,
-		{0, 2, 0}, {0, 2, 0}, {0, 2, 0}, {0, 0, 0},
-		0, 0, -1, -1, FB_ACCEL_NONE, TAG_HIRES, 0, 0, 0, 0, 0, 0,
-		0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
-	}, {
-		/* euro36 */
-		640, 200, 640, 200, 0, 0, 4, 0,
-		{0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
-		0, 0, -1, -1, FB_ACCEL_NONE, TAG_HIRES, 92, 124, 6, 6, 52, 5,
-		0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
-	}, {
-		/* euro36-lace */
-		640, 400, 640, 400, 0, 0, 4, 0,
-		{0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
-		0, 0, -1, -1, FB_ACCEL_NONE, TAG_HIRES, 92, 124, 12, 12, 52, 10,
-		0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
-	}, {
-		/* euro72 */
-		640, 400, 640, 400, 0, 0, 4, 0,
-		{0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
-		0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 164, 92, 9, 9, 80, 8,
-		0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
-	}, {
-		/* euro72-lace */
-		640, 800, 640, 800, 0, 0, 4, 0,
-		{0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
-		0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 164, 92, 18, 18, 80, 16,
-		0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
-	}, {
-		/* super72 */
-		800, 300, 800, 300, 0, 0, 4, 0,
-		{0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
-		0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 212, 140, 10, 11, 80, 7,
-		0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
-	}, {
-		/* super72-lace */
-		800, 600, 800, 600, 0, 0, 4, 0,
-		{0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
-		0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 212, 140, 20, 22, 80, 14,
-		0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
-	}, {
-		/* dblntsc */
-		640, 200, 640, 200, 0, 0, 4, 0,
-		{0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
-		0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 196, 124, 18, 17, 80, 4,
-		0, FB_VMODE_DOUBLE | FB_VMODE_YWRAP
-	}, {
-		/* dblntsc-ff */
-		640, 400, 640, 400, 0, 0, 4, 0,
-		{0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
-		0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 196, 124, 36, 35, 80, 7,
-		0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
-	}, {
-		/* dblntsc-lace */
-		640, 800, 640, 800, 0, 0, 4, 0,
-		{0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
-		0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 196, 124, 72, 70, 80, 14,
-		0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
-	}, {
-		/* dblpal */
-		640, 256, 640, 256, 0, 0, 4, 0,
-		{0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
-		0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 196, 124, 14, 13, 80, 4,
-		0, FB_VMODE_DOUBLE | FB_VMODE_YWRAP
-	}, {
-		/* dblpal-ff */
-		640, 512, 640, 512, 0, 0, 4, 0,
-		{0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
-		0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 196, 124, 28, 27, 80, 7,
-		0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
-	}, {
-		/* dblpal-lace */
-		640, 1024, 640, 1024, 0, 0, 4, 0,
-		{0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
-		0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 196, 124, 56, 54, 80, 14,
-		0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
-	},
-
-	/*
-	 * VGA Video Modes
-	 */
-
-	{
-		/* vga */
-		640, 480, 640, 480, 0, 0, 4, 0,
-		{0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
-		0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 64, 96, 30, 9, 112, 2,
-		0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
-	}, {
-		/* vga70 */
-		640, 400, 640, 400, 0, 0, 4, 0,
-		{0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
-		0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 64, 96, 35, 12, 112, 2,
-		FB_SYNC_VERT_HIGH_ACT | FB_SYNC_COMP_HIGH_ACT, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
-	},
-
-	/*
-	 * User Defined Video Modes
-	 */
-
-	{ 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }
-};
-
-#define NUM_USER_MODES   (8)
-#define NUM_TOTAL_MODES  arraysize(amiga_fb_predefined)
-#define NUM_PREDEF_MODES (NUM_TOTAL_MODES-NUM_USER_MODES)
-
-static int amifb_ilbm = 0;	/* interleaved or normal bitplanes */
-
-static int amifb_inverse = 0;
-static int amifb_usermode = 0;
-
-	/*
-	 * Some default modes
-	 */
-
-#define DEFMODE_PAL        "pal"	/* for PAL OCS/ECS */
-#define DEFMODE_NTSC       "ntsc"	/* for NTSC OCS/ECS */
-#define DEFMODE_AMBER_PAL  "pal-lace"	/* for flicker fixed PAL (A3000) */
-#define DEFMODE_AMBER_NTSC "ntsc-lace"	/* for flicker fixed NTSC (A3000) */
-#define DEFMODE_AGA        "vga70"	/* for AGA */
-
-	/*
-	 * Macros for the conversion from real world values to hardware register
-	 * values
-	 *
-	 * This helps us to keep our attention on the real stuff...
-	 *
-	 * Hardware limits for AGA:
-	 *
-	 *	parameter  min    max  step
-	 *	---------  ---   ----  ----
-	 *	diwstrt_h    0   2047     1
-	 *	diwstrt_v    0   2047     1
-	 *	diwstop_h    0   4095     1
-	 *	diwstop_v    0   4095     1
-	 *
-	 *	ddfstrt      0   2032    16
-	 *	ddfstop      0   2032    16
-	 *
-	 *	htotal       8   2048     8
-	 *	hsstrt       0   2040     8
-	 *	hsstop       0   2040     8
-	 *	vtotal       1   4096     1
-	 *	vsstrt       0   4095     1
-	 *	vsstop       0   4095     1
-	 *	hcenter      0   2040     8
-	 *
-	 *	hbstrt       0   2047     1
-	 *	hbstop       0   2047     1
-	 *	vbstrt       0   4095     1
-	 *	vbstop       0   4095     1
-	 *
-	 * Horizontal values are in 35 ns (SHRES) pixels
-	 * Vertical values are in half scanlines
-	 */
-
-/* bplcon1 (smooth scrolling) */
-
-#define hscroll2hw(hscroll) \
-	(((hscroll)<<12 & 0x3000) | ((hscroll)<<8 & 0xc300) | \
-	 ((hscroll)<<4 & 0x0c00) | ((hscroll)<<2 & 0x00f0) | ((hscroll)>>2 & 0x000f))
-
-/* diwstrt/diwstop/diwhigh (visible display window) */
-
-#define diwstrt2hw(diwstrt_h, diwstrt_v) \
-	(((diwstrt_v)<<7 & 0xff00) | ((diwstrt_h)>>2 & 0x00ff))
-#define diwstop2hw(diwstop_h, diwstop_v) \
-	(((diwstop_v)<<7 & 0xff00) | ((diwstop_h)>>2 & 0x00ff))
-#define diwhigh2hw(diwstrt_h, diwstrt_v, diwstop_h, diwstop_v) \
-	(((diwstop_h)<<3 & 0x2000) | ((diwstop_h)<<11 & 0x1800) | \
-	 ((diwstop_v)>>1 & 0x0700) | ((diwstrt_h)>>5 & 0x0020) | \
-	 ((diwstrt_h)<<3 & 0x0018) | ((diwstrt_v)>>9 & 0x0007))
-
-/* ddfstrt/ddfstop (display DMA) */
-
-#define ddfstrt2hw(ddfstrt)	div8(ddfstrt)
-#define ddfstop2hw(ddfstop)	div8(ddfstop)
-
-/* hsstrt/hsstop/htotal/vsstrt/vsstop/vtotal/hcenter (sync timings) */
-
-#define hsstrt2hw(hsstrt)	(div8(hsstrt))
-#define hsstop2hw(hsstop)	(div8(hsstop))
-#define htotal2hw(htotal)	(div8(htotal)-1)
-#define vsstrt2hw(vsstrt)	(div2(vsstrt))
-#define vsstop2hw(vsstop)	(div2(vsstop))
-#define vtotal2hw(vtotal)	(div2(vtotal)-1)
-#define hcenter2hw(htotal)	(div8(htotal))
-
-/* hbstrt/hbstop/vbstrt/vbstop (blanking timings) */
-
-#define hbstrt2hw(hbstrt)	(((hbstrt)<<8 & 0x0700) | ((hbstrt)>>3 & 0x00ff))
-#define hbstop2hw(hbstop)	(((hbstop)<<8 & 0x0700) | ((hbstop)>>3 & 0x00ff))
-#define vbstrt2hw(vbstrt)	(div2(vbstrt))
-#define vbstop2hw(vbstop)	(div2(vbstop))
-
-/* colour */
-
-#define rgb2hw8_high(red, green, blue) \
-	(((red)<<4 & 0xf00) | ((green) & 0x0f0) | ((blue)>>4 & 0x00f))
-#define rgb2hw8_low(red, green, blue) \
-	(((red)<<8 & 0xf00) | ((green)<<4 & 0x0f0) | ((blue) & 0x00f))
-#define rgb2hw4(red, green, blue) \
-	(((red)<<8 & 0xf00) | ((green)<<4 & 0x0f0) | ((blue) & 0x00f))
-#define rgb2hw2(red, green, blue) \
-	(((red)<<10 & 0xc00) | ((green)<<6 & 0x0c0) | ((blue)<<2 & 0x00c))
-
-/* sprpos/sprctl (sprite positioning) */
-
-#define spr2hw_pos(start_v, start_h) \
-	(((start_v)<<7&0xff00) | ((start_h)>>3&0x00ff))
-#define spr2hw_ctl(start_v, start_h, stop_v) \
-	(((stop_v)<<7&0xff00) | ((start_v)>>4&0x0040) | ((stop_v)>>5&0x0020) | \
-	 ((start_h)<<3&0x0018) | ((start_v)>>7&0x0004) | ((stop_v)>>8&0x0002) | \
-	 ((start_h)>>2&0x0001))
-
-/* get current vertical position of beam */
-#define get_vbpos()	((u_short)((*(u_long volatile *)&custom.vposr >> 7) & 0xffe))
-
-	/*
-	 * Copper Initialisation List
-	 */
-
-#define COPINITSIZE (sizeof(copins)*40)
-
-enum {
-	cip_bplcon0
-};
-
-	/*
-	 * Long Frame/Short Frame Copper List
-	 * Don't change the order, build_copper()/rebuild_copper() rely on this
-	 */
-
-#define COPLISTSIZE (sizeof(copins)*64)
-
-enum {
-	cop_wait, cop_bplcon0,
-	cop_spr0ptrh, cop_spr0ptrl,
-	cop_diwstrt, cop_diwstop,
-	cop_diwhigh,
-};
-
-	/*
-	 * Pixel modes for Bitplanes and Sprites
-	 */
-
-static u_short bplpixmode[3] = {
-	BPC0_SHRES,			/*  35 ns */
-	BPC0_HIRES,			/*  70 ns */
-	0				/* 140 ns */
-};
-
-static u_short sprpixmode[3] = {
-	BPC3_SPRES1 | BPC3_SPRES0,	/*  35 ns */
-	BPC3_SPRES1,			/*  70 ns */
-	BPC3_SPRES0			/* 140 ns */
-};
-
-	/*
-	 * Fetch modes for Bitplanes and Sprites
-	 */
-
-static u_short bplfetchmode[3] = {
-	0,				/* 1x */
-	FMODE_BPL32,			/* 2x */
-	FMODE_BPAGEM | FMODE_BPL32	/* 4x */
-};
-
-static u_short sprfetchmode[3] = {
-	0,				/* 1x */
-	FMODE_SPR32,			/* 2x */
-	FMODE_SPAGEM | FMODE_SPR32	/* 4x */
-};
-
-	/*
-	 * Default Colormaps
-	 */
-
-static u_short red2[] =
-	{ 0x0000, 0xc000 };
-static u_short green2[] =
-	{ 0x0000, 0xc000 };
-static u_short blue2[] =
-	{ 0x0000, 0xc000 };
-
-static u_short red4[] =
-	{ 0x0000, 0xc000, 0x8000, 0xffff };
-static u_short green4[] =
-	{ 0x0000, 0xc000, 0x8000, 0xffff };
-static u_short blue4[] =
-	{ 0x0000, 0xc000, 0x8000, 0xffff };
-
-static u_short red8[] =
-	{ 0x0000, 0x0000, 0x0000, 0x0000, 0xc000, 0xc000, 0xc000, 0xc000 };
-static u_short green8[] =
-	{ 0x0000, 0x0000, 0xc000, 0xc000, 0x0000, 0x0000, 0xc000, 0xc000 };
-static u_short blue8[] =
-	{ 0x0000, 0xc000, 0x0000, 0xc000, 0x0000, 0xc000, 0x0000, 0xc000 };
-
-static u_short red16[] =
-	{ 0x0000, 0x0000, 0x0000, 0x0000, 0xc000, 0xc000, 0xc000, 0xc000,
-	  0x8000, 0x0000, 0x0000, 0x0000, 0xffff, 0xffff, 0xffff, 0xffff };
-static u_short green16[] =
-	{ 0x0000, 0x0000, 0xc000, 0xc000, 0x0000, 0x0000, 0xc000, 0xc000,
-	  0x8000, 0x0000, 0xffff, 0xffff, 0x0000, 0x0000, 0xffff, 0xffff };
-static u_short blue16[] =
-	{ 0x0000, 0xc000, 0x0000, 0xc000, 0x0000, 0xc000, 0x0000, 0xc000,
-	  0x8000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff };
-
-
-static struct fb_cmap default_2_colors =
-	{ 0, 2, red2, green2, blue2, NULL };
-static struct fb_cmap default_8_colors =
-	{ 0, 8, red8, green8, blue8, NULL };
-static struct fb_cmap default_4_colors =
-	{ 0, 4, red4, green4, blue4, NULL };
-static struct fb_cmap default_16_colors =
-	{ 0, 16, red16, green16, blue16, NULL };
-
-	/*
-	 * Interface used by the world
-	 */
-
-void amiga_video_setup(char *options, int *ints);
-
-static int amiga_fb_get_fix(struct fb_fix_screeninfo *fix, int con);
-static int amiga_fb_get_var(struct fb_var_screeninfo *var, int con);
-static int amiga_fb_set_var(struct fb_var_screeninfo *var, int con);
-static int amiga_fb_pan_display(struct fb_var_screeninfo *var, int con);
-static int amiga_fb_get_cmap(struct fb_cmap *cmap, int kspc, int con);
-static int amiga_fb_set_cmap(struct fb_cmap *cmap, int kspc, int con);
-static int amiga_fb_ioctl(struct inode *inode, struct file *file, u_int cmd,
-                          u_long arg, int con);
-
-static int amiga_fb_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix, int con);
-static int amiga_fb_get_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data, int con);
-static int amiga_fb_set_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data, int con);
-static int amiga_fb_get_cursorstate(struct fb_cursorstate *state, int con);
-static int amiga_fb_set_cursorstate(struct fb_cursorstate *state, int con);
-
-	/*
-	 * Interface to the low level console driver
-	 */
-
-struct fb_info *amiga_fb_init(long *mem_start);
-static int amifbcon_switch(int con);
-static int amifbcon_updatevar(int con);
-static void amifbcon_blank(int blank);
-static int amifbcon_setcmap(struct fb_cmap *cmap, int con);
-
-	/*
-	 * Internal routines
-	 */
-
-static struct fb_cmap *get_default_colormap(int bpp);
-static int do_fb_get_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var,
-                          int kspc);
-static int do_fb_set_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var,
-                          int kspc);
-static void do_install_cmap(int con);
-static void memcpy_fs(int fsfromto, void *to, void *from, int len);
-static void copy_cmap(struct fb_cmap *from, struct fb_cmap *to, int fsfromto);
-static int alloc_cmap(struct fb_cmap *cmap, int len, int transp);
-static int flash_cursor(void);
-static void amifb_interrupt(int irq, void *dev_id, struct pt_regs *fp);
-static void get_video_mode(const char *name);
-static void check_default_mode(void);
-static u_long chipalloc(u_long size);
-static char *strtoke(char *s,const char *ct);
-
-	/*
-	 * Hardware routines
-	 */
-
-static int ami_encode_fix(struct fb_fix_screeninfo *fix,
-                          struct amiga_fb_par *par);
-static int ami_decode_var(struct fb_var_screeninfo *var,
-                          struct amiga_fb_par *par);
-static int ami_encode_var(struct fb_var_screeninfo *var,
-                          struct amiga_fb_par *par);
-static void ami_get_par(struct amiga_fb_par *par);
-static void ami_set_var(struct fb_var_screeninfo *var);
-#ifdef DEBUG
-static void ami_set_par(struct amiga_fb_par *par);
-#endif
-static void ami_pan_var(struct fb_var_screeninfo *var);
-static int ami_update_par(void);
-static int ami_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
-                         u_int *transp);
-static int ami_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
-                         u_int transp);
-static void ami_update_display(void);
-static void ami_init_display(void);
-static void ami_do_blank(void);
-static int ami_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix, int con);
-static int ami_get_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data, int con);
-static int ami_set_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data, int con);
-static int ami_get_cursorstate(struct fb_cursorstate *state, int con);
-static int ami_set_cursorstate(struct fb_cursorstate *state, int con);
-static void ami_set_sprite(void);
-static void ami_init_copper(void);
-static void ami_reinit_copper(void);
-static void ami_build_copper(void);
-static void ami_rebuild_copper(void);
-
-
-	/*
-	 * External references
-	 */
-
-extern unsigned short ami_intena_vals[];
-
-	/*
-	 * Support for Graphics Boards
-	 */
-
-#ifdef CONFIG_FB_CYBER			/* Cybervision */
-extern int Cyber_probe(void);
-extern void Cyber_video_setup(char *options, int *ints);
-extern struct fb_info *Cyber_fb_init(long *mem_start);
-
-static int amifb_Cyber = 0;
-#endif
-
-#ifdef CONFIG_FB_RETINAZ3			/* RetinaZ3 */
-extern int retz3_probe(void);
-extern void retz3_video_setup(char *options, int *ints);
-extern struct fb_info *retz3_fb_init(long *mem_start);
-
-static int amifb_retz3 = 0;
-#endif
-
-#ifdef CONFIG_GSP_RESOLVER			/* DMI Resolver */
-extern int resolver_probe(void);
-extern void resolver_video_setup(char *options, int *ints);
-extern struct fb_info *resolver_fb_init(long *mem_start);
-
-static int amifb_resolver = 0;
-#endif
-
-static struct fb_ops amiga_fb_ops = {
-	amiga_fb_get_fix, amiga_fb_get_var, amiga_fb_set_var, amiga_fb_get_cmap,
-	amiga_fb_set_cmap, amiga_fb_pan_display, amiga_fb_ioctl
-};
-
-void amiga_video_setup(char *options, int *ints)
-{
-	char *this_opt;
-	int i;
-	char mcap_spec[80];
-
-	/*
-	 * Check for a Graphics Board
-	 */
-
-#ifdef CONFIG_FB_CYBER
-	if (options && *options)
-		if (!strncmp(options, "cyber", 5) && Cyber_probe()) {
-			amifb_Cyber = 1;
-			Cyber_video_setup(options, ints);
-			return;
-		}
-#endif
-#ifdef CONFIG_FB_RETINAZ3
-	if (options && *options)
-		if (!strncmp(options, "retz3", 5) && retz3_probe()) {
-			amifb_retz3 = 1;
-			retz3_video_setup(options, ints);
-			return;
-		}
-#endif
-#ifdef CONFIG_GSP_RESOLVER
-	if (options && *options)
-		if (!strncmp(options, "resolver", 5) && resolver_probe()) {
-			amifb_resolver = 1;
-			resolver_video_setup(options, ints);
-			return;
-		}
-#endif
-
-	mcap_spec[0] = '\0';
-	fb_info.fontname[0] = '\0';
-
-	if (!options || !*options)
-		return;
-
-	for (this_opt = strtok(options, ","); this_opt; this_opt = strtok(NULL, ",")) {
-		char *p;
-
-		if (!strcmp(this_opt, "inverse")) {
-			amifb_inverse = 1;
-			for (i = 0; i < 16; i++) {
-				red16[i] = ~red16[i];
-				green16[i] = ~green16[i];
-				blue16[i] = ~blue16[i];
-			}
-			for (i = 0; i < 8; i++) {
-				red8[i] = ~red8[i];
-				green8[i] = ~green8[i];
-				blue8[i] = ~blue8[i];
-			}
-			for (i = 0; i < 4; i++) {
-				red4[i] = ~red4[i];
-				green4[i] = ~green4[i];
-				blue4[i] = ~blue4[i];
-			}
-			for (i = 0; i < 2; i++) {
-				red2[i] = ~red2[i];
-				green2[i] = ~green2[i];
-				blue2[i] = ~blue2[i];
-			}
-		} else if (!strcmp(this_opt, "ilbm"))
-			amifb_ilbm = 1;
-		else if (!strncmp(this_opt, "monitorcap:", 11))
-			strcpy(mcap_spec, this_opt+11);
-		else if (!strncmp(this_opt, "font:", 5))
-			strcpy(fb_info.fontname, this_opt+5);
-		else if (!strncmp(this_opt, "fstart:", 7))
-			min_fstrt = simple_strtoul(this_opt+7, NULL, 0);
-		else if (!strncmp(this_opt, "depth:", 6))
-			amiga_fb_predefined[0].bits_per_pixel =
-				simple_strtoul(this_opt+6, NULL, 0);
-		else if (!strncmp(this_opt, "size:", 5)) {
-			p = this_opt + 5;
-			if (*p != ';')
-				amiga_fb_predefined[0].xres =
-					simple_strtoul(p, NULL, 0);
-			if (!(p = strchr(p, ';')))
-				continue;
-			if (*++p != ';')
-				amiga_fb_predefined[0].yres =
-					simple_strtoul(p, NULL, 0);
-			if (!(p = strchr(p, ';')))
-				continue;
-			if (*++p != ';')
-				amiga_fb_predefined[0].xres_virtual =
-					simple_strtoul(p, NULL, 0);
-			if (!(p = strchr(p, ';')))
-				continue;
-			if (*++p != ';')
-				amiga_fb_predefined[0].yres_virtual =
-					simple_strtoul(p, NULL, 0);
-			if (!(p = strchr(p, ';')))
-				continue;
-			if (*++p)
-				amiga_fb_predefined[0].bits_per_pixel =
-					simple_strtoul(p, NULL, 0);
-		} else if (!strncmp(this_opt, "timing:", 7)) {
-			p = this_opt + 7;
-			if (*p != ';')
-				amiga_fb_predefined[0].left_margin =
-					simple_strtoul(p, NULL, 0);
-			if (!(p = strchr(p, ';')))
-				continue;
-			if (*++p != ';')
-				amiga_fb_predefined[0].right_margin =
-					simple_strtoul(p, NULL, 0);
-			if (!(p = strchr(p, ';')))
-				continue;
-			if (*++p != ';')
-				amiga_fb_predefined[0].upper_margin =
-					simple_strtoul(p, NULL, 0);
-			if (!(p = strchr(p, ';')))
-				continue;
-			if (*++p)
-				amiga_fb_predefined[0].lower_margin =
-					simple_strtoul(p, NULL, 0);
-		} else if (!strncmp(this_opt, "sync:", 5)) {
-			p = this_opt + 5;
-			if (*p != ';')
-				amiga_fb_predefined[0].hsync_len =
-					simple_strtoul(p, NULL, 0);
-			if (!(p = strchr(p, ';')))
-				continue;
-			if (*++p)
-				amiga_fb_predefined[0].vsync_len =
-					simple_strtoul(p, NULL, 0);
-		} else
-			get_video_mode(this_opt);
-	}
-
-	if (min_fstrt < 48)
-		min_fstrt = 48;
-
-	if (*mcap_spec) {
-		char *p;
-		int vmin, vmax, hmin, hmax;
-
-	/* Format for monitor capabilities is: <Vmin>;<Vmax>;<Hmin>;<Hmax>
-	 * <V*> vertical freq. in Hz
-	 * <H*> horizontal freq. in kHz
-	 */
-
-		if (!(p = strtoke(mcap_spec, ";")) || !*p)
-			goto cap_invalid;
-		vmin = simple_strtoul(p, NULL, 10);
-		if (vmin <= 0)
-			goto cap_invalid;
-		if (!(p = strtoke(NULL, ";")) || !*p)
-			goto cap_invalid;
-		vmax = simple_strtoul(p, NULL, 10);
-		if (vmax <= 0 || vmax <= vmin)
-			goto cap_invalid;
-		if (!(p = strtoke(NULL, ";")) || !*p)
-			goto cap_invalid;
-		hmin = 1000 * simple_strtoul(p, NULL, 10);
-		if (hmin <= 0)
-			goto cap_invalid;
-		if (!(p = strtoke(NULL, "")) || !*p)
-			goto cap_invalid;
-		hmax = 1000 * simple_strtoul(p, NULL, 10);
-		if (hmax <= 0 || hmax <= hmin)
-			goto cap_invalid;
-
-		vfmin = vmin;
-		vfmax = vmax;
-		hfmin = hmin;
-		hfmax = hmax;
-cap_invalid:
-		;
-	}
-}
-
-	/*
-	 * Get the Fixed Part of the Display
-	 */
-
-static int amiga_fb_get_fix(struct fb_fix_screeninfo *fix, int con)
-{
-	struct amiga_fb_par par;
-
-	if (con == -1)
-		ami_get_par(&par);
-	else {
-		int err;
-
-		if ((err = ami_decode_var(&disp[con].var, &par)))
-			return err;
-	}
-	return ami_encode_fix(fix, &par);
-}
-
-	/*
-	 * Get the User Defined Part of the Display
-	 */
-
-static int amiga_fb_get_var(struct fb_var_screeninfo *var, int con)
-{
-	int err = 0;
-
-	if (con == -1) {
-		struct amiga_fb_par par;
-
-		ami_get_par(&par);
-		err = ami_encode_var(var, &par);
-	} else
-		*var = disp[con].var;
-	return err;
-}
-
-	/*
-	 * Set the User Defined Part of the Display
-	 */
-
-static int amiga_fb_set_var(struct fb_var_screeninfo *var, int con)
-{
-	int err, activate = var->activate;
-	int oldxres, oldyres, oldvxres, oldvyres, oldbpp;
-	struct amiga_fb_par par;
-
-
-	/*
-	 * FB_VMODE_CONUPDATE and FB_VMODE_SMOOTH_XPAN are equal!
-	 * as FB_VMODE_SMOOTH_XPAN is only used internally
-	 */
-
-	if (var->vmode & FB_VMODE_CONUPDATE) {
-		var->vmode |= FB_VMODE_YWRAP;
-		var->xoffset = disp[con].var.xoffset;
-		var->yoffset = disp[con].var.yoffset;
-	}
-	if ((err = ami_decode_var(var, &par)))
-		return err;
-	ami_encode_var(var, &par);
-	if ((activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
-		oldxres = disp[con].var.xres;
-		oldyres = disp[con].var.yres;
-		oldvxres = disp[con].var.xres_virtual;
-		oldvyres = disp[con].var.yres_virtual;
-		oldbpp = disp[con].var.bits_per_pixel;
-		disp[con].var = *var;
-		if (oldxres != var->xres || oldyres != var->yres ||
-		    oldvxres != var->xres_virtual || oldvyres != var->yres_virtual ||
-		    oldbpp != var->bits_per_pixel) {
-			struct fb_fix_screeninfo fix;
-
-			ami_encode_fix(&fix, &par);
-			disp[con].screen_base = (u_char *)fix.smem_start;
-			disp[con].visual = fix.visual;
-			disp[con].type = fix.type;
-			disp[con].type_aux = fix.type_aux;
-			disp[con].ypanstep = fix.ypanstep;
-			disp[con].ywrapstep = fix.ywrapstep;
-			disp[con].line_length = fix.line_length;
-			disp[con].can_soft_blank = 1;
-			disp[con].inverse = amifb_inverse;
-			if (fb_info.changevar)
-				(*fb_info.changevar)(con);
-		}
-		if (oldbpp != var->bits_per_pixel) {
-			if ((err = alloc_cmap(&disp[con].cmap, 0, 0)))
-				return err;
-			do_install_cmap(con);
-		}
-		if (con == currcon)
-			ami_set_var(&disp[con].var);
-	}
-	return 0;
-}
-
-	/*
-	 * Pan or Wrap the Display
-	 *
-	 * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
-	 */
-
-static int amiga_fb_pan_display(struct fb_var_screeninfo *var, int con)
-{
-	if (var->vmode & FB_VMODE_YWRAP) {
-		if (var->yoffset<0 || var->yoffset >= disp[con].var.yres_virtual || var->xoffset)
-			return -EINVAL;
-	} else {
-		/*
-		 * TODO: There will be problems when xpan!=1, so some columns
-		 * on the right side will never be seen
-		 */
-		if (var->xoffset+disp[con].var.xres > upx(16<<maxfmode, disp[con].var.xres_virtual) ||
-		    var->yoffset+disp[con].var.yres > disp[con].var.yres_virtual)
-			return -EINVAL;
-	}
-	if (con == currcon)
-		ami_pan_var(var);
-	disp[con].var.xoffset = var->xoffset;
-	disp[con].var.yoffset = var->yoffset;
-	if (var->vmode & FB_VMODE_YWRAP)
-		disp[con].var.vmode |= FB_VMODE_YWRAP;
-	else
-		disp[con].var.vmode &= ~FB_VMODE_YWRAP;
-	return 0;
-}
-
-	/*
-	 * Get the Colormap
-	 */
-
-static int amiga_fb_get_cmap(struct fb_cmap *cmap, int kspc, int con)
-{
-	if (con == currcon) /* current console? */
-		return do_fb_get_cmap(cmap, &disp[con].var, kspc);
-	else if (disp[con].cmap.len) /* non default colormap? */
-		copy_cmap(&disp[con].cmap, cmap, kspc ? 0 : 2);
-	else
-		copy_cmap(get_default_colormap(disp[con].var.bits_per_pixel),
-		          cmap, kspc ? 0 : 2);
-	return 0;
-}
-
-	/*
-	 * Set the Colormap
-	 */
-
-static int amiga_fb_set_cmap(struct fb_cmap *cmap, int kspc, int con)
-{
-	int err;
-
-	if (!disp[con].cmap.len) {		/* no colormap allocated? */
-		if ((err = alloc_cmap(&disp[con].cmap,
-		                      1<<disp[con].var.bits_per_pixel, 0)))
-			return err;
-	}
-	if (con == currcon)			/* current console? */
-		return do_fb_set_cmap(cmap, &disp[con].var, kspc);
-	else
-		copy_cmap(cmap, &disp[con].cmap, kspc ? 0 : 1);
-	return 0;
-}
-
-	/*
-	 * Amiga Frame Buffer Specific ioctls
-	 */
-
-static int amiga_fb_ioctl(struct inode *inode, struct file *file,
-                          u_int cmd, u_long arg, int con)
-{
-	int i;
-
-	switch (cmd) {
-		case FBIOGET_FCURSORINFO : {
-			struct fb_fix_cursorinfo crsrfix;
-			
-			i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(crsrfix));
-			if (!i) {
-				i = amiga_fb_get_fix_cursorinfo(&crsrfix, con);
-				copy_to_user((void *)arg, &crsrfix, sizeof(crsrfix));
-			}
-			return i;
-		}
-		case FBIOGET_VCURSORINFO : {
-			struct fb_var_cursorinfo crsrvar;
-
-			i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(crsrvar));
-			if (!i) {
-				i = amiga_fb_get_var_cursorinfo(&crsrvar,
-					((struct fb_var_cursorinfo *)arg)->data, con);
-				copy_to_user((void *)arg, &crsrvar, sizeof(crsrvar));
-			}
-			return i;
-		}
-		case FBIOPUT_VCURSORINFO : {
-			struct fb_var_cursorinfo crsrvar;
-
-			i = verify_area(VERIFY_READ, (void *)arg, sizeof(crsrvar));
-			if (!i) {
-				copy_from_user(&crsrvar, (void *)arg, sizeof(crsrvar));
-				i = amiga_fb_set_var_cursorinfo(&crsrvar,
-					((struct fb_var_cursorinfo *)arg)->data, con);
-			}
-			return i;
-		}
-		case FBIOGET_CURSORSTATE : {
-			struct fb_cursorstate crsrstate;
-
-			i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(crsrstate));
-			if (!i) {
-				i = amiga_fb_get_cursorstate(&crsrstate, con);
-				copy_to_user((void *)arg, &crsrstate, sizeof(crsrstate));
-			}
-			return i;
-		}
-		case FBIOPUT_CURSORSTATE : {
-			struct fb_cursorstate crsrstate;
-
-			i = verify_area(VERIFY_READ, (void *)arg, sizeof(crsrstate));
-			if (!i) {
-				copy_from_user(&crsrstate, (void *)arg, sizeof(crsrstate));
-				i = amiga_fb_set_cursorstate(&crsrstate, con);
-			}
-			return i;
-		}
-#ifdef DEBUG
-		case FBCMD_GET_CURRENTPAR : {
-			struct amiga_fb_par par;
-
-			i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(struct amiga_fb_par));
-			if (!i) {
-				ami_get_par(&par);
-				copy_to_user((void *)arg, &par, sizeof(struct amiga_fb_par));
-			}
-			return i;
-		}
-		case FBCMD_SET_CURRENTPAR : {
-			struct amiga_fb_par par;
-
-			i = verify_area(VERIFY_READ, (void *)arg, sizeof(struct amiga_fb_par));
-			if (!i) {
-				copy_from_user(&par, (void *)arg, sizeof(struct amiga_fb_par));
-				ami_set_par(&par);
-			}
-			return i;
-		}
-#endif */ DEBUG */
-	}
-	return -EINVAL;
-}
-
-	/*
-	 * Hardware Cursor
-	 */
-
-static int amiga_fb_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix, int con)
-{
-	return ami_get_fix_cursorinfo(fix, con);
-}
-
-static int amiga_fb_get_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data, int con)
-{
-	return ami_get_var_cursorinfo(var, data, con);
-}
-
-static int amiga_fb_set_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data, int con)
-{
-	return ami_set_var_cursorinfo(var, data, con);
-}
-
-static int amiga_fb_get_cursorstate(struct fb_cursorstate *state, int con)
-{
-	return ami_get_cursorstate(state, con);
-}
-
-static int amiga_fb_set_cursorstate(struct fb_cursorstate *state, int con)
-{
-	return ami_set_cursorstate(state, con);
-}
-
-	/*
-	 * Initialisation
-	 */
-
-__initfunc(struct fb_info *amiga_fb_init(long *mem_start))
-{
-	int err, tag, i;
-	u_long chipptr;
-
-	/*
-	 * Check for a Graphics Board
-	 */
-
-#ifdef CONFIG_FB_CYBER
-	if (amifb_Cyber)
-		return Cyber_fb_init(mem_start);
-#endif
-#ifdef CONFIG_FB_RETINAZ3
-	if (amifb_retz3){
-		custom.dmacon = DMAF_MASTER | DMAF_RASTER | DMAF_COPPER |
-				DMAF_BLITTER | DMAF_SPRITE;
-		return retz3_fb_init(mem_start);
-	}
-#endif
-#ifdef CONFIG_GSP_RESOLVER
-	if (amifb_resolver){
-		custom.dmacon = DMAF_MASTER | DMAF_RASTER | DMAF_COPPER |
-				DMAF_BLITTER | DMAF_SPRITE;
-		return NULL;
-	}
-#endif
-
-	/*
-	 * Use the Builtin Chipset
-	 */
-
-	if (!AMIGAHW_PRESENT(AMI_VIDEO))
-		return NULL;
-
-	custom.dmacon = DMAF_ALL | DMAF_MASTER;
-
-	switch (amiga_chipset) {
-#ifdef CONFIG_AMIFB_OCS
-		case CS_OCS:
-			strcat(amiga_fb_name, "OCS");
-default_chipset:
-			chipset = TAG_OCS;
-			maxdepth[TAG_SHRES] = 0;	/* OCS means no SHRES */
-			maxdepth[TAG_HIRES] = 4;
-			maxdepth[TAG_LORES] = 6;
-			maxfmode = TAG_FMODE_1;
-			if (!amifb_usermode)		/* Set the Default Video Mode */
-				get_video_mode(amiga_vblank == 50 ?
-				               DEFMODE_PAL : DEFMODE_NTSC);
-			videomemorysize = VIDEOMEMSIZE_OCS;
-			break;
-#endif /* CONFIG_AMIFB_OCS */
-
-#ifdef CONFIG_AMIFB_ECS
-		case CS_ECS:
-			strcat(amiga_fb_name, "ECS");
-			chipset = TAG_ECS;
-			maxdepth[TAG_SHRES] = 2;
-			maxdepth[TAG_HIRES] = 4;
-			maxdepth[TAG_LORES] = 6;
-			maxfmode = TAG_FMODE_1;
-			if (!amifb_usermode) {		/* Set the Default Video Mode */
-				if (AMIGAHW_PRESENT(AMBER_FF))
-					get_video_mode(amiga_vblank == 50 ?
-					               DEFMODE_AMBER_PAL : DEFMODE_AMBER_NTSC);
-				else
-					get_video_mode(amiga_vblank == 50 ?
-					               DEFMODE_PAL : DEFMODE_NTSC);
-			}
-			if (amiga_chip_avail()-CHIPRAM_SAFETY_LIMIT >
-			    VIDEOMEMSIZE_ECS_1M)
-				videomemorysize = VIDEOMEMSIZE_ECS_2M;
-			else
-				videomemorysize = VIDEOMEMSIZE_ECS_1M;
-			break;
-#endif /* CONFIG_AMIFB_ECS */
-
-#ifdef CONFIG_AMIFB_AGA
-		case CS_AGA:
-			strcat(amiga_fb_name, "AGA");
-			chipset = TAG_AGA;
-			maxdepth[TAG_SHRES] = 8;
-			maxdepth[TAG_HIRES] = 8;
-			maxdepth[TAG_LORES] = 8;
-			maxfmode = TAG_FMODE_4;
-			if (!amifb_usermode)		/* Set the Default Video Mode */
-				get_video_mode(DEFMODE_AGA);
-			if (amiga_chip_avail()-CHIPRAM_SAFETY_LIMIT >
-			    VIDEOMEMSIZE_AGA_1M)
-				videomemorysize = VIDEOMEMSIZE_AGA_2M;
-			else
-				videomemorysize = VIDEOMEMSIZE_AGA_1M;
-			break;
-#endif /* CONFIG_AMIFB_AGA */
-
-		default:
-#ifdef CONFIG_AMIFB_OCS
-			printk("Unknown graphics chipset, defaulting to OCS\n");
-			strcat(amiga_fb_name, "Unknown");
-			goto default_chipset;
-#else /* CONFIG_AMIFB_OCS */
-			panic("Unknown graphics chipset, no default driver");
-#endif /* CONFIG_AMIFB_OCS */
-			break;
-	}
-
-	/*
-	 * Calculate the Pixel Clock Values for this Machine
-	 */
-
-	pixclock[TAG_SHRES] = DIVUL(25E9, amiga_eclock);	/* SHRES:  35 ns / 28 MHz */
-	pixclock[TAG_HIRES] = DIVUL(50E9, amiga_eclock);	/* HIRES:  70 ns / 14 MHz */
-	pixclock[TAG_LORES] = DIVUL(100E9, amiga_eclock); 	/* LORES: 140 ns /  7 MHz */
-
-	/*
-	 * Replace the Tag Values with the Real Pixel Clock Values
-	 */
-
-	for (i = 0; i < NUM_PREDEF_MODES; i++) {
-		tag = amiga_fb_predefined[i].pixclock;
-		if (tag == TAG_SHRES || tag == TAG_HIRES || tag == TAG_LORES) {
-			amiga_fb_predefined[i].pixclock = pixclock[tag];
-			if (amiga_fb_predefined[i].bits_per_pixel > maxdepth[tag])
-				amiga_fb_predefined[i].bits_per_pixel = maxdepth[tag];
-		}
-	}
-
-	err = register_framebuffer(amiga_fb_name, &node, &amiga_fb_ops,
-	                           NUM_TOTAL_MODES, amiga_fb_predefined);
-	if (err < 0)
-		panic("Cannot register frame buffer");
-
-	chipptr = chipalloc(videomemorysize+
-	                    SPRITEMEMSIZE+
-	                    DUMMYSPRITEMEMSIZE+
-	                    COPINITSIZE+
-	                    4*COPLISTSIZE);
-
-	assignchunk(videomemory, u_long, chipptr, videomemorysize);
-	assignchunk(spritememory, u_long, chipptr, SPRITEMEMSIZE);
-	assignchunk(dummysprite, u_short *, chipptr, DUMMYSPRITEMEMSIZE);
-	assignchunk(copdisplay.init, copins *, chipptr, COPINITSIZE);
-	assignchunk(copdisplay.list[0][0], copins *, chipptr, COPLISTSIZE);
-	assignchunk(copdisplay.list[0][1], copins *, chipptr, COPLISTSIZE);
-	assignchunk(copdisplay.list[1][0], copins *, chipptr, COPLISTSIZE);
-	assignchunk(copdisplay.list[1][1], copins *, chipptr, COPLISTSIZE);
-
-	memset(dummysprite, 0, DUMMYSPRITEMEMSIZE);
-
-	/*
-	 * Enable Display DMA
-	 */
-
-	custom.dmacon = DMAF_SETCLR | DMAF_MASTER | DMAF_RASTER | DMAF_COPPER |
-	                DMAF_BLITTER | DMAF_SPRITE;
-
-	/*
-	 * Make sure the Copper has something to do
-	 */
-
-	ami_init_copper();
-
-	check_default_mode();
-
-	if (request_irq(IRQ_AMIGA_AUTO_3, amifb_interrupt, IRQ_FLG_LOCK,
-	                "fb vertb handler", NULL))
-		panic("Couldn't add vblank interrupt\n");
-	ami_intena_vals[IRQ_AMIGA_VERTB] = IF_COPER;
-	ami_intena_vals[IRQ_AMIGA_COPPER] = 0;
-	custom.intena = IF_VERTB;
-	custom.intena = IF_SETCLR | IF_COPER;
-
-	strcpy(fb_info.modename, amiga_fb_name);
-	fb_info.changevar = NULL;
-	fb_info.disp = disp;
-	fb_info.switch_con = &amifbcon_switch;
-	fb_info.updatevar = &amifbcon_updatevar;
-	fb_info.blank = &amifbcon_blank;
-	fb_info.setcmap = &amifbcon_setcmap;
-
-	amiga_fb_set_var(&amiga_fb_predefined[0], 0);
-
-	return &fb_info;
-}
-
-static int amifbcon_switch(int con)
-{
-	/* Do we have to save the colormap? */
-	if (disp[currcon].cmap.len)
-		do_fb_get_cmap(&disp[currcon].cmap, &disp[currcon].var, 1);
-
-	currcon = con;
-	ami_set_var(&disp[con].var);
-	/* Install new colormap */
-	do_install_cmap(con);
-	return 0;
-}
-
-	/*
-	 * Update the `var' structure (called by amicon.c)
-	 */
-
-static int amifbcon_updatevar(int con)
-{
-	ami_pan_var(&disp[con].var);
-	return 0;
-}
-
-	/*
-	 * Blank the display.
-	 */
-
-static void amifbcon_blank(int blank)
-{
-	do_blank = blank ? blank : -1;
-}
-
-	/*
-	 * Set the colormap
-	 */
-
-static int amifbcon_setcmap(struct fb_cmap *cmap, int con)
-{
-	return(amiga_fb_set_cmap(cmap, 1, con));
-}
-
-/* ---------------------------- Generic routines ---------------------------- */
-
-static struct fb_cmap *get_default_colormap(int bpp)
-{
-	switch (bpp) {
-		case 1:
-			return &default_2_colors;
-			break;
-		case 2:
-			return &default_4_colors;
-			break;
-		case 3:
-			return &default_8_colors;
-			break;
-		default:
-			return &default_16_colors;
-			break;
-	}
-}
-
-#define CNVT_TOHW(val,width)	((((val)<<(width))+0x7fff-(val))>>16)
-#define CNVT_FROMHW(val,width)	(((width) ? ((((val)<<16)-(val)) / \
-                                            ((1<<(width))-1)) : 0))
-
-static int do_fb_get_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var,
-                          int kspc)
-{
-	int i, start;
-	u_short *red, *green, *blue, *transp;
-	u_int hred, hgreen, hblue, htransp;
-
-	red = cmap->red;
-	green = cmap->green;
-	blue = cmap->blue;
-	transp = cmap->transp;
-	start = cmap->start;
-	if (start < 0)
-		return -EINVAL;
-	for (i = 0; i < cmap->len; i++) {
-		if (ami_getcolreg(start++, &hred, &hgreen, &hblue, &htransp))
-			return 0;
-		hred = CNVT_FROMHW(hred, var->red.length);
-		hgreen = CNVT_FROMHW(hgreen, var->green.length);
-		hblue = CNVT_FROMHW(hblue, var->blue.length);
-		htransp = CNVT_FROMHW(htransp, var->transp.length);
-		if (kspc) {
-			*red = hred;
-			*green = hgreen;
-			*blue = hblue;
-			if (transp)
-				*transp = htransp;
-		} else {
-			put_user(hred, red);
-			put_user(hgreen, green);
-			put_user(hblue, blue);
-			if (transp)
-				put_user(htransp, transp);
-		}
-		red++;
-		green++;
-		blue++;
-		if (transp)
-			transp++;
-	}
-	return 0;
-}
-
-static int do_fb_set_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var,
-                          int kspc)
-{
-	int i, start;
-	u_short *red, *green, *blue, *transp;
-	u_int hred, hgreen, hblue, htransp;
-
-	red = cmap->red;
-	green = cmap->green;
-	blue = cmap->blue;
-	transp = cmap->transp;
-	start = cmap->start;
-
-	if (start < 0)
-		return -EINVAL;
-	for (i = 0; i < cmap->len; i++) {
-		if (kspc) {
-			hred = *red;
-			hgreen = *green;
-			hblue = *blue;
-			htransp = transp ? *transp : 0;
-		} else {
-			get_user(hred, red);
-			get_user(hgreen, green);
-			get_user(hblue, blue);
-			if (transp)
-				get_user(htransp, transp);
-			else
-				htransp = 0;
-		}
-		hred = CNVT_TOHW(hred, var->red.length);
-		hgreen = CNVT_TOHW(hgreen, var->green.length);
-		hblue = CNVT_TOHW(hblue, var->blue.length);
-		htransp = CNVT_TOHW(htransp, var->transp.length);
-		red++;
-		green++;
-		blue++;
-		if (transp)
-			transp++;
-		if (ami_setcolreg(start++, hred, hgreen, hblue, htransp))
-			return 0;
-	}
-	return 0;
-}
-
-static void do_install_cmap(int con)
-{
-	if (con != currcon)
-		return;
-	if (disp[con].cmap.len)
-		do_fb_set_cmap(&disp[con].cmap, &disp[con].var, 1);
-	else
-		do_fb_set_cmap(get_default_colormap(disp[con].var.bits_per_pixel),
-		                                    &disp[con].var, 1);
-}
-
-static void memcpy_fs(int fsfromto, void *to, void *from, int len)
-{
-	switch (fsfromto) {
-		case 0:
-			memcpy(to, from, len);
-			return;
-		case 1:
-			copy_from_user(to, from, len);
-			return;
-		case 2:
-			copy_to_user(to, from, len);
-			return;
-	}
-}
-
-static void copy_cmap(struct fb_cmap *from, struct fb_cmap *to, int fsfromto)
-{
-	int size;
-	int tooff = 0, fromoff = 0;
-
-	if (to->start > from->start)
-		fromoff = to->start-from->start;
-	else
-		tooff = from->start-to->start;
-	size = to->len-tooff;
-	if (size > from->len-fromoff)
-		size = from->len-fromoff;
-	if (size < 0)
-		return;
-	size *= sizeof(u_short);
-	memcpy_fs(fsfromto, to->red+tooff, from->red+fromoff, size);
-	memcpy_fs(fsfromto, to->green+tooff, from->green+fromoff, size);
-	memcpy_fs(fsfromto, to->blue+tooff, from->blue+fromoff, size);
-	if (from->transp && to->transp)
-		memcpy_fs(fsfromto, to->transp+tooff, from->transp+fromoff, size);
-}
-
-static int alloc_cmap(struct fb_cmap *cmap, int len, int transp)
-{
-	int size = len*sizeof(u_short);
-
-	if (cmap->len != len) {
-		if (cmap->red)
-			kfree(cmap->red);
-		if (cmap->green)
-			kfree(cmap->green);
-		if (cmap->blue)
-			kfree(cmap->blue);
-		if (cmap->transp)
-			kfree(cmap->transp);
-		cmap->red = cmap->green = cmap->blue = cmap->transp = NULL;
-		cmap->len = 0;
-		if (!len)
-			return 0;
-		if (!(cmap->red = kmalloc(size, GFP_ATOMIC)))
-			return -1;
-		if (!(cmap->green = kmalloc(size, GFP_ATOMIC)))
-			return -1;
-		if (!(cmap->blue = kmalloc(size, GFP_ATOMIC)))
-			return -1;
-		if (transp) {
-			if (!(cmap->transp = kmalloc(size, GFP_ATOMIC)))
-				return -1;
-		} else
-			cmap->transp = NULL;
-	}
-	cmap->start = 0;
-	cmap->len = len;
-	copy_cmap(get_default_colormap(len), cmap, 0);
-	return 0;
-}
-
-static int flash_cursor(void)
-{
-	static int cursorcount = 1;
-
-	if (cursormode == FB_CURSOR_FLASH) {
-		if (!--cursorcount) {
-			cursorstate = -cursorstate;
-			cursorcount = cursorrate;
-			if (!is_blanked)
-				return 1;
-		}
-	}
-	return 0;
-}
-
-	/*
-	 * VBlank Display Interrupt
-	 */
-
-static void amifb_interrupt(int irq, void *dev_id, struct pt_regs *fp)
-{
-	u_short ints = custom.intreqr & custom.intenar;
-	static struct irq_server server = {0, 0};
-	unsigned long flags;
-
-	if (ints & IF_BLIT) {
-		custom.intreq = IF_BLIT;
-		amiga_do_irq(IRQ_AMIGA_BLIT, fp);
-	}
-
-	if (ints & IF_COPER) {
-		custom.intreq = IF_COPER;
-		if (do_vmode_pan || do_vmode_full)
-			ami_update_display();
-
-		if (do_vmode_full)
-			ami_init_display();
-
-		if (do_vmode_pan) {
-			flash_cursor();
-			ami_rebuild_copper();
-			do_cursor = do_vmode_pan = 0;
-		} else if (do_cursor) {
-			flash_cursor();
-			ami_set_sprite();
-			do_cursor = 0;
-		} else {
-			if (flash_cursor())
-				ami_set_sprite();
-		}
-
-		save_flags(flags);
-		cli();
-		if (get_vbpos() < down2(currentpar.diwstrt_v - 6))
-			custom.copjmp2 = 0;
-		restore_flags(flags);
-
-		if (do_blank) {
-			ami_do_blank();
-			do_blank = 0;
-		}
-
-		if (do_vmode_full) {
-			ami_reinit_copper();
-			do_vmode_full = 0;
-		}
-		amiga_do_irq_list(IRQ_AMIGA_VERTB, fp, &server);
-	}
-
-	if (ints & IF_VERTB) {
-		printk("%s: Warning: IF_VERTB was enabled\n", __FUNCTION__);
-		custom.intena = IF_VERTB;
-	}
-}
-
-	/*
-	 * Get a Video Mode
-	 */
-
-static void get_video_mode(const char *name)
-{
-	int i;
-
-	for (i = 1; i < NUM_PREDEF_MODES; i++) {
-		if (!strcmp(name, amiga_fb_modenames[i])) {
-			amiga_fb_predefined[0] = amiga_fb_predefined[i];
-			amifb_usermode = i;
-			return;
-		}
-	}
-}
-
-	/*
-	 * Probe the  Video Modes
-	 */
-
-static void check_default_mode(void)
-{
-	struct amiga_fb_par par;
-	int mode;
-
-	for (mode = 0; mode < NUM_PREDEF_MODES; mode++) {
-		if (!ami_decode_var(&amiga_fb_predefined[mode], &par)) {
-			if (mode)
-				amiga_fb_predefined[0] = amiga_fb_predefined[mode];
-			return;
-		}
-		if (!mode)
-			printk("Can't use default video mode. Probing video modes...\n");
-	}
-	panic("Can't find any usable video mode");
-}
-
-	/*
-	 * Allocate, Clear and Align a Block of Chip Memory
-	 */
-
-static u_long chipalloc(u_long size)
-{
-	u_long ptr;
-
-	size += PAGE_SIZE-1;
-	if (!(ptr = (u_long)amiga_chip_alloc(size)))
-		panic("No Chip RAM for frame buffer");
-	memset((void *)ptr, 0, size);
-	ptr = PAGE_ALIGN(ptr);
-
-	return ptr;
-}
-
-	/*
-	 * A strtok which returns empty strings, too
-	 */
-
-static char *strtoke(char *s,const char *ct)
-{
-	char *sbegin, *send;
-	static char *ssave = NULL;
-
-	sbegin  = s ? s : ssave;
-	if (!sbegin)
-		return NULL;
-	if (*sbegin == '\0') {
-		ssave = NULL;
-		return NULL;
-	}
-	send = strpbrk(sbegin, ct);
-	if (send && *send != '\0')
-		*send++ = '\0';
-	ssave = send;
-	return sbegin;
-}
-
-/* --------------------------- Hardware routines --------------------------- */
-
-	/*
-	 * This function should fill in the `fix' structure based on the
-	 * values in the `par' structure.
-	 */
-
-static int ami_encode_fix(struct fb_fix_screeninfo *fix,
-                          struct amiga_fb_par *par)
-{
-	int i;
-
-	strcpy(fix->id, amiga_fb_name);
-	fix->smem_start = videomemory;
-	fix->smem_len = videomemorysize;
-
-	if (amifb_ilbm) {
-		fix->type = FB_TYPE_INTERLEAVED_PLANES;
-		fix->type_aux = par->next_line;
-	} else {
-		fix->type = FB_TYPE_PLANES;
-		fix->type_aux = 0;
-	}
-	fix->line_length = div8(upx(16<<maxfmode, par->vxres));
-	fix->visual = FB_VISUAL_PSEUDOCOLOR;
-
-	if (par->vmode & FB_VMODE_YWRAP) {
-		fix->ywrapstep = 1;
-		fix->xpanstep = fix->ypanstep = 0;
-	} else {
-		fix->ywrapstep = 0;
-		if (par->vmode &= FB_VMODE_SMOOTH_XPAN)
-			fix->xpanstep = 1;
-		else
-			fix->xpanstep = 16<<maxfmode;
-		fix->ypanstep = 1;
-	}
-
-	for (i = 0; i < arraysize(fix->reserved); i++)
-		fix->reserved[i] = 0;
-
-	return 0;
-}
-
-	/*
-	 * Get the video params out of `var'. If a value doesn't fit, round
-	 * it up, if it's too big, return -EINVAL.
-	 */
-
-static int ami_decode_var(struct fb_var_screeninfo *var,
-                          struct amiga_fb_par *par)
-{
-	u_short clk_shift, line_shift;
-	u_long maxfetchstop, fstrt, fsize, fconst, xres_n, yres_n;
-	u_long hrate = 0, vrate = 0;
-
-	/*
-	 * Find a matching Pixel Clock
-	 */
-
-	for (clk_shift = TAG_SHRES; clk_shift < TAG_LORES; clk_shift++)
-		if (var->pixclock <= pixclock[clk_shift])
-			break;
-	if (clk_shift >= TAG_LORES)
-		return -EINVAL;
-	par->clk_shift = clk_shift;
-
-	/*
-	 * Check the Geometry Values
-	 */
-
-	if ((par->xres = var->xres) < 64)
-		return -EINVAL;
-	if ((par->yres = var->yres) < 64)
-		return -EINVAL;
-	if ((par->vxres = var->xres_virtual) < 64)
-		return -EINVAL;
-	if ((par->vyres = var->yres_virtual) < 64)
-		return -EINVAL;
-
-	par->bpp = var->bits_per_pixel;
-	if (!var->nonstd) {
-		if (par->bpp <= 0 || par->bpp > maxdepth[clk_shift])
-			return -EINVAL;
-	} else if (var->nonstd == FB_NONSTD_HAM) {
-		if (par->bpp != 6)
-			if (par->bpp != 8 || !IS_AGA)
-				return -EINVAL;
-	} else
-		return -EINVAL;
-
-	/*
-	 * FB_VMODE_SMOOTH_XPAN will be cleared, if one of the folloing
-	 * checks failed and smooth scrolling is not possible
-	 */
-
-	par->vmode = var->vmode | FB_VMODE_SMOOTH_XPAN;
-	switch (par->vmode & FB_VMODE_MASK) {
-		case FB_VMODE_INTERLACED:
-			line_shift = 0;
-			break;
-		case FB_VMODE_NONINTERLACED:
-			line_shift = 1;
-			break;
-		case FB_VMODE_DOUBLE:
-			if (!IS_AGA)
-				return -EINVAL;
-			line_shift = 2;
-			break;
-		default:
-			return -EINVAL;
-			break;
-	}
-	par->line_shift = line_shift;
-
-	/*
-	 * Vertical and Horizontal Timings
-	 */
-
-	xres_n = par->xres<<clk_shift;
-	yres_n = par->yres<<line_shift;
-	par->htotal = down8((var->left_margin+par->xres+var->right_margin+var->hsync_len)<<clk_shift);
-	par->vtotal = down2(((var->upper_margin+par->yres+var->lower_margin+var->vsync_len)<<line_shift)+1);
-
-	if (IS_AGA)
-		par->bplcon3 = sprpixmode[clk_shift];
-	else
-		par->bplcon3 = 0;
-	if (var->sync & FB_SYNC_BROADCAST) {
-		par->diwstop_h = par->htotal-((var->right_margin-var->hsync_len)<<clk_shift);
-		if (IS_AGA)
-			par->diwstop_h += mod4(var->hsync_len);
-		else
-			par->diwstop_h = down4(par->diwstop_h);
-		par->diwstrt_h = par->diwstop_h - xres_n;
-		par->diwstop_v = par->vtotal-((var->lower_margin-var->vsync_len)<<line_shift);
-		par->diwstrt_v = par->diwstop_v - yres_n;
-		if (par->diwstop_h >= par->htotal+8 || par->diwstop_v > par->vtotal)
-			return -EINVAL;
-		if (!IS_OCS) {
-			/* Initialize sync with some reasonable values for pwrsave */
-			par->hsstrt = 160;
-			par->hsstop = 320;
-			par->vsstrt = 30;
-			par->vsstop = 34;
-		} else {
-			par->hsstrt = 0;
-			par->hsstop = 0;
-			par->vsstrt = 0;
-			par->vsstop = 0;
-		}
-		if (par->vtotal > (PAL_VTOTAL+NTSC_VTOTAL)/2) {
-			/* PAL video mode */
-			if (par->htotal != PAL_HTOTAL)
-				return -EINVAL;
-			if (par->diwstrt_h < PAL_DIWSTRT_H)
-				return -EINVAL;
-			if (par->diwstrt_v < PAL_DIWSTRT_V)
-				return -EINVAL;
-			hrate = 15625;
-			vrate = 50;
-			if (!IS_OCS) {
-				par->beamcon0 = BMC0_PAL;
-				par->bplcon3 |= BPC3_BRDRBLNK;
-			} else if (AMIGAHW_PRESENT(AGNUS_HR_PAL) || 
-			           AMIGAHW_PRESENT(AGNUS_HR_NTSC)) {
-				par->beamcon0 = BMC0_PAL;
-				par->hsstop = 1;
-			} else if (amiga_vblank != 50)
-				return -EINVAL;
-		} else {
-			/* NTSC video mode
-			 * In the AGA chipset seems to be hardware bug with BPC3_BRDRBLNK
-			 * and NTSC activated, so than better let diwstop_h <= 1812
-			 */
-			if (par->htotal != NTSC_HTOTAL)
-				return -EINVAL;
-			if (par->diwstrt_h < NTSC_DIWSTRT_H)
-				return -EINVAL;
-			if (par->diwstrt_v < NTSC_DIWSTRT_V)
-				return -EINVAL;
-			hrate = 15750;
-			vrate = 60;
-			if (!IS_OCS) {
-				par->beamcon0 = 0;
-				par->bplcon3 |= BPC3_BRDRBLNK;
-			} else if (AMIGAHW_PRESENT(AGNUS_HR_PAL) || 
-			           AMIGAHW_PRESENT(AGNUS_HR_NTSC)) {
-				par->beamcon0 = 0;
-				par->hsstop = 1;
-			} else if (amiga_vblank != 60)
-				return -EINVAL;
-		}
-		if (IS_OCS) {
-			if (par->diwstrt_h >= 1024 || par->diwstop_h < 1024 ||
-			    par->diwstrt_v >=  512 || par->diwstop_v <  256)
-				return -EINVAL;
-		}
-	} else if (!IS_OCS) {
-		/* Programmable video mode */
-		par->hsstrt = var->right_margin<<clk_shift;
-		par->hsstop = (var->right_margin+var->hsync_len)<<clk_shift;
-		par->diwstop_h = par->htotal - mod8(par->hsstrt) + 8 - (1 << clk_shift);
-		if (!IS_AGA)
-			par->diwstop_h = down4(par->diwstop_h) - 16;
-		par->diwstrt_h = par->diwstop_h - xres_n;
-		par->hbstop = par->diwstrt_h + 4;
-		par->hbstrt = par->diwstop_h + 4;
-		if (par->hbstrt >= par->htotal + 8)
-			par->hbstrt -= par->htotal;
-		par->hcenter = par->hsstrt + (par->htotal >> 1);
-		par->vsstrt = var->lower_margin<<line_shift;
-		par->vsstop = (var->lower_margin+var->vsync_len)<<line_shift;
-		par->diwstop_v = par->vtotal;
-		if ((par->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED)
-			par->diwstop_v -= 2;
-		par->diwstrt_v = par->diwstop_v - yres_n;
-		par->vbstop = par->diwstrt_v - 2;
-		par->vbstrt = par->diwstop_v - 2;
-		if (par->vtotal > 2048 || par->htotal > 2048)
-			return -EINVAL;
-		par->bplcon3 |= BPC3_EXTBLKEN;
-		par->beamcon0 = BMC0_HARDDIS | BMC0_VARVBEN | BMC0_LOLDIS |
-		                BMC0_VARVSYEN | BMC0_VARHSYEN | BMC0_VARBEAMEN |
-		                BMC0_PAL | BMC0_VARCSYEN;
-		if (var->sync & FB_SYNC_HOR_HIGH_ACT)
-			par->beamcon0 |= BMC0_HSYTRUE;
-		if (var->sync & FB_SYNC_VERT_HIGH_ACT)
-			par->beamcon0 |= BMC0_VSYTRUE;
-		if (var->sync & FB_SYNC_COMP_HIGH_ACT)
-			par->beamcon0 |= BMC0_CSYTRUE;
-		hrate = (amiga_masterclock+par->htotal/2)/par->htotal;
-		vrate = div2(par->vtotal) * par->htotal;
-		vrate = (amiga_masterclock+vrate/2)/vrate;
-	} else
-		return -EINVAL;
-
-	/*
-	 * Checking the DMA timing
-	 */
-
-	fconst = 16<<maxfmode<<clk_shift;
-
-	/*
-	 * smallest window start value without turn off other dma cycles
-	 * than sprite1-7, unless you change min_fstrt
-	 */
-
-
-	fsize = ((maxfmode+clk_shift <= 1) ? fconst : 64);
-	fstrt = downx(fconst, par->diwstrt_h-4) - fsize;
-	if (fstrt < min_fstrt)
-		return -EINVAL;
-
-	/*
-	 * smallest window start value where smooth scrolling is possible
-	 */
-
-	fstrt = downx(fconst, par->diwstrt_h-fconst+(1<<clk_shift)-4) - fsize;
-	if (fstrt < min_fstrt)
-		par->vmode &= ~FB_VMODE_SMOOTH_XPAN;
-
-	maxfetchstop = down16(par->htotal - 80);
-
-	fstrt = downx(fconst, par->diwstrt_h-4) - 64 - fconst;
-	fsize = upx(fconst, xres_n + modx(fconst, downx(1<<clk_shift, par->diwstrt_h-4)));
-	if (fstrt + fsize > maxfetchstop)
-		par->vmode &= ~FB_VMODE_SMOOTH_XPAN;
-
-	fsize = upx(fconst, xres_n);
-	if (fstrt + fsize > maxfetchstop)
-		return -EINVAL;
-
-	if (maxfmode + clk_shift <= 1) {
-		fsize = up64(xres_n + fconst - 1);
-		if (min_fstrt + fsize - 64 > maxfetchstop)
-			par->vmode &= ~FB_VMODE_SMOOTH_XPAN;
-
-		fsize = up64(xres_n);
-		if (min_fstrt + fsize - 64 > maxfetchstop)
-			return -EINVAL;
-
-		fsize -= 64;
-	} else
-		fsize -= fconst;
-
-	/*
-	 * Check if there is enough time to update the bitplane pointers for ywrap
-	 */
-
-	if (par->htotal-fsize-64 < par->bpp*64)
-		par->vmode &= ~FB_VMODE_YWRAP;
-
-	/*
-	 * Bitplane calculations and check the Memory Requirements
-	 */
-
-	if (amifb_ilbm) {
-		par->next_plane = div8(upx(16<<maxfmode, par->vxres));
-		par->next_line = par->bpp*par->next_plane;
-		if (par->next_line * par->vyres > videomemorysize)
-			return -EINVAL;
-	} else {
-		par->next_line = div8(upx(16<<maxfmode, par->vxres));
-		par->next_plane = par->vyres*par->next_line;
-		if (par->next_plane * par->bpp > videomemorysize)
-			return -EINVAL;
-	}
-
-	/*
-	 * Hardware Register Values
-	 */
-
-	par->bplcon0 = BPC0_COLOR | bplpixmode[clk_shift];
-	if (!IS_OCS)
-		par->bplcon0 |= BPC0_ECSENA;
-	if (par->bpp == 8)
-		par->bplcon0 |= BPC0_BPU3;
-	else
-		par->bplcon0 |= par->bpp<<12;
-	if (var->nonstd == FB_NONSTD_HAM)
-		par->bplcon0 |= BPC0_HAM;
-	if (var->sync & FB_SYNC_EXT)
-		par->bplcon0 |= BPC0_ERSY;
-
-	if (IS_AGA)
-		par->fmode = bplfetchmode[maxfmode];
-
-	switch (par->vmode & FB_VMODE_MASK) {
-		case FB_VMODE_INTERLACED:
-			par->bplcon0 |= BPC0_LACE;
-			break;
-		case FB_VMODE_DOUBLE:
-			if (IS_AGA)
-				par->fmode |= FMODE_SSCAN2 | FMODE_BSCAN2;
-			break;
-	}
-
-	if (!((par->vmode ^ var->vmode) & FB_VMODE_YWRAP)) {
-		par->xoffset = var->xoffset;
-		par->yoffset = var->yoffset;
-		if (par->vmode & FB_VMODE_YWRAP) {
-			if (par->xoffset || par->yoffset < 0 || par->yoffset >= par->vyres)
-				par->xoffset = par->yoffset = 0;
-		} else {
-			if (par->xoffset < 0 || par->xoffset > upx(16<<maxfmode, par->vxres-par->xres) ||
-			    par->yoffset < 0 || par->yoffset > par->vyres-par->yres)
-				par->xoffset = par->yoffset = 0;
-		}
-	} else
-		par->xoffset = par->yoffset = 0;
-
-	par->crsr.crsr_x = par->crsr.crsr_y = 0;
-	par->crsr.spot_x = par->crsr.spot_y = 0;
-	par->crsr.height = par->crsr.width = 0;
-
-	if (hrate < hfmin || hrate > hfmax || vrate < vfmin || vrate > vfmax)
-		return -EINVAL;
-
-	return 0;
-}
-
-	/*
-	 * Fill the `var' structure based on the values in `par' and maybe
-	 * other values read out of the hardware.
-	 */
-
-static int ami_encode_var(struct fb_var_screeninfo *var,
-                          struct amiga_fb_par *par)
-{
-	u_short clk_shift, line_shift;
-	int i;
-
-	clk_shift = par->clk_shift;
-	line_shift = par->line_shift;
-
-	var->xres = par->xres;
-	var->yres = par->yres;
-	var->xres_virtual = par->vxres;
-	var->yres_virtual = par->vyres;
-	var->xoffset = par->xoffset;
-	var->yoffset = par->yoffset;
-
-	var->bits_per_pixel = par->bpp;
-	var->grayscale = 0;
-
-	if (IS_AGA) {
-		var->red.offset = 0;
-		var->red.length = 8;
-		var->red.msb_right = 0;
-	} else {
-		if (clk_shift == TAG_SHRES) {
-			var->red.offset = 0;
-			var->red.length = 2;
-			var->red.msb_right = 0;
-		} else {
-			var->red.offset = 0;
-			var->red.length = 4;
-			var->red.msb_right = 0;
-		}
-	}
-	var->blue = var->green = var->red;
-	var->transp.offset = 0;
-	var->transp.length = 0;
-	var->transp.msb_right = 0;
-
-	if (par->bplcon0 & BPC0_HAM)
-		var->nonstd = FB_NONSTD_HAM;
-	else
-		var->nonstd = 0;
-	var->activate = 0;
-
-	var->height = -1;
-	var->width = -1;
-	var->accel = 0;
-
-	var->pixclock = pixclock[clk_shift];
-
-	if (IS_AGA && par->fmode & FMODE_BSCAN2)
-		var->vmode = FB_VMODE_DOUBLE;
-	else if (par->bplcon0 & BPC0_LACE)
-		var->vmode = FB_VMODE_INTERLACED;
-	else
-		var->vmode = FB_VMODE_NONINTERLACED;
-
-	if (!IS_OCS && par->beamcon0 & BMC0_VARBEAMEN) {
-		var->hsync_len = (par->hsstop-par->hsstrt)>>clk_shift;
-		var->right_margin = par->hsstrt>>clk_shift;
-		var->left_margin = (par->htotal>>clk_shift) - var->xres - var->right_margin - var->hsync_len;
-		var->vsync_len = (par->vsstop-par->vsstrt)>>line_shift;
-		var->lower_margin = par->vsstrt>>line_shift;
-		var->upper_margin = (par->vtotal>>line_shift) - var->yres - var->lower_margin - var->vsync_len;
-		var->sync = 0;
-		if (par->beamcon0 & BMC0_HSYTRUE)
-			var->sync |= FB_SYNC_HOR_HIGH_ACT;
-		if (par->beamcon0 & BMC0_VSYTRUE)
-			var->sync |= FB_SYNC_VERT_HIGH_ACT;
-		if (par->beamcon0 & BMC0_CSYTRUE)
-			var->sync |= FB_SYNC_COMP_HIGH_ACT;
-	} else {
-		var->sync = FB_SYNC_BROADCAST;
-		var->hsync_len = (152>>clk_shift) + mod4(par->diwstop_h);
-		var->right_margin = ((par->htotal - down4(par->diwstop_h))>>clk_shift) + var->hsync_len;
-		var->left_margin = (par->htotal>>clk_shift) - var->xres - var->right_margin - var->hsync_len;
-		var->vsync_len = 4>>line_shift;
-		var->lower_margin = ((par->vtotal - par->diwstop_v)>>line_shift) + var->vsync_len;
-		var->upper_margin = (((par->vtotal - 2)>>line_shift) + 1) - var->yres -
-		                    var->lower_margin - var->vsync_len;
-	}
-
-	if (par->bplcon0 & BPC0_ERSY)
-		var->sync |= FB_SYNC_EXT;
-	if (par->vmode & FB_VMODE_YWRAP)
-		var->vmode |= FB_VMODE_YWRAP;
-
-	for (i = 0; i < arraysize(var->reserved); i++)
-		var->reserved[i] = 0;
-
-	return 0;
-}
-
-	/*
-	 * Get current hardware setting
-	 */
-
-static void ami_get_par(struct amiga_fb_par *par)
-{
-	*par = currentpar;
-}
-
-	/*
-	 * Set new videomode
-	 */
-
-static void ami_set_var(struct fb_var_screeninfo *var)
-{
-	do_vmode_pan = 0;
-	do_vmode_full = 0;
-	ami_decode_var(var, &currentpar);
-	ami_build_copper();
-	do_vmode_full = 1;
-}
-
-#ifdef DEBUG
-static void ami_set_par(struct amiga_fb_par *par)
-{
-	do_vmode_pan = 0;
-	do_vmode_full = 0;
-	currentpar = *par;
-	ami_build_copper();
-	do_vmode_full = 1;
-}
-#endif
-
-	/*
-	 * Pan or Wrap the Display
-	 *
-	 * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
-	 * in `var'.
-	 */
-
-static void ami_pan_var(struct fb_var_screeninfo *var)
-{
-	struct amiga_fb_par *par = &currentpar;
-
-	par->xoffset = var->xoffset;
-	par->yoffset = var->yoffset;
-	if (var->vmode & FB_VMODE_YWRAP)
-		par->vmode |= FB_VMODE_YWRAP;
-	else
-		par->vmode &= ~FB_VMODE_YWRAP;
-
-	do_vmode_pan = 0;
-	ami_update_par();
-	do_vmode_pan = 1;
-}
-
-	/*
-	 * Update hardware
-	 */
-
-static int ami_update_par(void)
-{
-	struct amiga_fb_par *par = &currentpar;
-	short clk_shift, vshift, fstrt, fsize, fstop, fconst,  shift, move, mod;
-
-	clk_shift = par->clk_shift;
-
-	if (!(par->vmode & FB_VMODE_SMOOTH_XPAN))
-		par->xoffset = upx(16<<maxfmode, par->xoffset);
-
-	fconst = 16<<maxfmode<<clk_shift;
-	vshift = modx(16<<maxfmode, par->xoffset);
-	fstrt = par->diwstrt_h - (vshift<<clk_shift) - 4;
-	fsize = (par->xres+vshift)<<clk_shift;
-	shift = modx(fconst, fstrt);
-	move = downx(2<<maxfmode, div8(par->xoffset));
-	if (maxfmode + clk_shift > 1) {
-		fstrt = downx(fconst, fstrt) - 64;
-		fsize = upx(fconst, fsize);
-		fstop = fstrt + fsize - fconst;
-	} else {
-		mod = fstrt = downx(fconst, fstrt) - fconst;
-		fstop = fstrt + upx(fconst, fsize) - 64;
-		fsize = up64(fsize);
-		fstrt = fstop - fsize + 64;
-		if (fstrt < min_fstrt) {
-			fstop += min_fstrt - fstrt;
-			fstrt = min_fstrt;
-		}
-		move = move - div8((mod-fstrt)>>clk_shift);
-	}
-	mod = par->next_line - div8(fsize>>clk_shift);
-	par->ddfstrt = fstrt;
-	par->ddfstop = fstop;
-	par->bplcon1 = hscroll2hw(shift);
-	par->bpl2mod = mod;
-	if (par->bplcon0 & BPC0_LACE)
-		par->bpl2mod += par->next_line;
-	if (IS_AGA && (par->fmode & FMODE_BSCAN2))
-		par->bpl1mod = -div8(fsize>>clk_shift);
-	else
-		par->bpl1mod = par->bpl2mod;
-
-	if (par->yoffset) {
-		par->bplpt0 = ZTWO_PADDR((u_long)videomemory + par->next_line*par->yoffset + move);
-		if (par->vmode & FB_VMODE_YWRAP) {
-			if (par->yoffset > par->vyres-par->yres) {
-				par->bplpt0wrap = ZTWO_PADDR((u_long)videomemory + move);
-				if (par->bplcon0 & BPC0_LACE && mod2(par->diwstrt_v+par->vyres-par->yoffset))
-					par->bplpt0wrap += par->next_line;
-			}
-		}
-	} else
-		par->bplpt0 = ZTWO_PADDR((u_long)videomemory + move);
-
-	if (par->bplcon0 & BPC0_LACE && mod2(par->diwstrt_v))
-		par->bplpt0 += par->next_line;
-
-	return 0;
-}
-
-	/*
-	 * Read a single color register and split it into
-	 * colors/transparent. Return != 0 for invalid regno.
-	 */
-
-static int ami_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
-                         u_int *transp)
-{
-	if (IS_AGA) {
-		if (regno > 255)
-			return 1;
-	} else {
-		if (regno > 31)
-			return 1;
-	}
-
-	*red = palette[regno].red;
-	*green = palette[regno].green;
-	*blue = palette[regno].blue;
-	return 0;
-}
-
-
-	/*
-	 * Set a single color register. The values supplied are already
-	 * rounded down to the hardware's capabilities (according to the
-	 * entries in the var structure). Return != 0 for invalid regno.
-	 */
-
-static int ami_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
-                         u_int transp)
-{
-#if defined(CONFIG_AMIFB_AGA)
-	u_short bplcon3 = currentpar.bplcon3;
-
-	if (IS_AGA) {
-		if (regno > 255)
-			return 1;
-	} else
-#endif
-		if (regno > 31)
-			return 1;
-
-	/*
-	 * Update the corresponding Hardware Color Register, unless it's Color
-	 * Register 0 and the screen is blanked.
-	 *
-	 * VBlank is switched off to protect bplcon3 or ecs_palette[] from
-	 * being changed by ami_do_blank() during the VBlank.
-	 */
-
-	palette[regno].red = red;
-	palette[regno].green = green;
-	palette[regno].blue = blue;
-
-	if (regno || !is_blanked) {
-#if defined(CONFIG_AMIFB_AGA)
-		if (IS_AGA) {
-			VBlankOff();
-			custom.bplcon3 = bplcon3 | (regno<<8 & 0xe000);
-			custom.color[regno&31] = rgb2hw8_high(red, green, blue);
-			custom.bplcon3 = bplcon3 | (regno<<8 & 0xe000) | BPC3_LOCT;
-			custom.color[regno&31] = rgb2hw8_low(red, green, blue);
-			custom.bplcon3 = bplcon3;
-			VBlankOn();
-		} else
-#endif
-		{
-#if defined(CONFIG_AMIFB_ECS)
-			if (currentpar.bplcon0 & BPC0_SHRES) {
-				u_short color, mask;
-				int i;
-
-				mask = 0x3333;
-				color = rgb2hw2(red, green, blue);
-				VBlankOff();
-				for (i = regno+12; i >= (int)regno; i -= 4)
-					custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color;
-				mask <<=2; color >>= 2;
-				regno = down16(regno)+mul4(mod4(regno));
-				for (i = regno+3; i >= (int)regno; i--)
-					custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color;
-				VBlankOn();
-			} else
-#endif
-				custom.color[regno] = rgb2hw4(red, green, blue);
-		}
-	}
-	return 0;
-}
-
-static void ami_update_display(void)
-{
-	struct amiga_fb_par *par = &currentpar;
-
-	custom.bplcon1 = par->bplcon1;
-	custom.bpl1mod = par->bpl1mod;
-	custom.bpl2mod = par->bpl2mod;
-	custom.ddfstrt = ddfstrt2hw(par->ddfstrt);
-	custom.ddfstop = ddfstop2hw(par->ddfstop);
-}
-
-	/*
-	 * Change the video mode (called by VBlank interrupt)
-	 */
-
-static void ami_init_display(void)
-{
-	struct amiga_fb_par *par = &currentpar;
-
-	custom.bplcon0 = par->bplcon0 & ~BPC0_LACE;
-	custom.bplcon2 = (IS_OCS ? 0 : BPC2_KILLEHB) | BPC2_PF2P2 | BPC2_PF1P2;
-	if (!IS_OCS) {
-		custom.bplcon3 = par->bplcon3;
-		if (IS_AGA)
-			custom.bplcon4 = BPC4_ESPRM4 | BPC4_OSPRM4;
-		if (par->beamcon0 & BMC0_VARBEAMEN) {
-			custom.htotal = htotal2hw(par->htotal);
-			custom.hbstrt = hbstrt2hw(par->hbstrt);
-			custom.hbstop = hbstop2hw(par->hbstop);
-			custom.hsstrt = hsstrt2hw(par->hsstrt);
-			custom.hsstop = hsstop2hw(par->hsstop);
-			custom.hcenter = hcenter2hw(par->hcenter);
-			custom.vtotal = vtotal2hw(par->vtotal);
-			custom.vbstrt = vbstrt2hw(par->vbstrt);
-			custom.vbstop = vbstop2hw(par->vbstop);
-			custom.vsstrt = vsstrt2hw(par->vsstrt);
-			custom.vsstop = vsstop2hw(par->vsstop);
-		}
-	}
-	if (!IS_OCS || par->hsstop)
-		custom.beamcon0 = par->beamcon0;
-	if (IS_AGA)
-		custom.fmode = par->fmode;
-
-	/*
-	 * The minimum period for audio depends on htotal
-	 */
-
-	amiga_audio_min_period = div16(par->htotal);
-
-	is_lace = par->bplcon0 & BPC0_LACE ? 1 : 0;
-#if 1
-	if (is_lace) {
-		if (custom.vposr & 0x8000)
-			custom.cop2lc = (u_short *)ZTWO_PADDR(copdisplay.list[currentcop][1]);
-		else
-			custom.cop2lc = (u_short *)ZTWO_PADDR(copdisplay.list[currentcop][0]);
-	} else {
-		custom.vposw = custom.vposr | 0x8000;
-		custom.cop2lc = (u_short *)ZTWO_PADDR(copdisplay.list[currentcop][1]);
-	}
-#else
-	custom.vposw = custom.vposr | 0x8000;
-	custom.cop2lc = (u_short *)ZTWO_PADDR(copdisplay.list[currentcop][1]);
-#endif
-}
-
-	/*
-	 * (Un)Blank the screen (called by VBlank interrupt)
-	 */
-
-static void ami_do_blank(void)
-{
-	struct amiga_fb_par *par = &currentpar;
-#if defined(CONFIG_AMIFB_AGA)
-	u_short bplcon3 = par->bplcon3;
-#endif
-	u_char red, green, blue;
-
-	if (do_blank > 0) {
-		custom.dmacon = DMAF_RASTER | DMAF_SPRITE;
-		red = green = blue = 0;
-		if (!IS_OCS && do_blank > 1) {
-			switch (do_blank) {
-				case 2 : /* suspend vsync */
-					custom.hsstrt = hsstrt2hw(par->hsstrt);
-					custom.hsstop = hsstop2hw(par->hsstop);
-					custom.vsstrt = vsstrt2hw(par->vtotal+4);
-					custom.vsstop = vsstop2hw(par->vtotal+4);
-					break;
-				case 3 : /* suspend hsync */
-					custom.hsstrt = hsstrt2hw(par->htotal+16);
-					custom.hsstop = hsstop2hw(par->htotal+16);
-					custom.vsstrt = vsstrt2hw(par->vsstrt);
-					custom.vsstop = vsstrt2hw(par->vsstop);
-					break;
-				case 4 : /* powerdown */
-					custom.hsstrt = hsstrt2hw(par->htotal+16);
-					custom.hsstop = hsstop2hw(par->htotal+16);
-					custom.vsstrt = vsstrt2hw(par->vtotal+4);
-					custom.vsstop = vsstop2hw(par->vtotal+4);
-					break;
-			}
-			if (!(par->beamcon0 & BMC0_VARBEAMEN)) {
-				custom.htotal = htotal2hw(par->htotal);
-				custom.vtotal = vtotal2hw(par->vtotal);
-				custom.beamcon0 = BMC0_HARDDIS | BMC0_VARBEAMEN |
-				                  BMC0_VARVSYEN | BMC0_VARHSYEN | BMC0_VARCSYEN;
-			}
-		}
-	} else {
-		custom.dmacon = DMAF_SETCLR | DMAF_RASTER | DMAF_SPRITE;
-		red = palette[0].red;
-		green = palette[0].green;
-		blue = palette[0].blue;
-		if (!IS_OCS) {
-			custom.hsstrt = hsstrt2hw(par->hsstrt);
-			custom.hsstop = hsstop2hw(par->hsstop);
-			custom.vsstrt = vsstrt2hw(par->vsstrt);
-			custom.vsstop = vsstop2hw(par->vsstop);
-			custom.beamcon0 = par->beamcon0;
-		}
-	}
-#if defined(CONFIG_AMIFB_AGA)
-	if (IS_AGA) {
-		custom.bplcon3 = bplcon3;
-		custom.color[0] = rgb2hw8_high(red, green, blue);
-		custom.bplcon3 = bplcon3 | BPC3_LOCT;
-		custom.color[0] = rgb2hw8_low(red, green, blue);
-		custom.bplcon3 = bplcon3;
-	} else
-#endif
-	{
-#if defined(CONFIG_AMIFB_ECS)
-		if (par->bplcon0 & BPC0_SHRES) {
-			u_short color, mask;
-			int i;
-
-			mask = 0x3333;
-			color = rgb2hw2(red, green, blue);
-			for (i = 12; i >= 0; i -= 4)
-				custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color;
-			mask <<=2; color >>= 2;
-			for (i = 3; i >= 0; i--)
-				custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color;
-		} else
-#endif
-			custom.color[0] = rgb2hw4(red, green, blue);
-	}
-	is_blanked = do_blank > 0 ? do_blank : 0;
-}
-
-	/*
-	 * Flash the cursor (called by VBlank interrupt)
-	 */
-
-static int ami_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix, int con)
-{
-	struct amiga_fb_par *par = &currentpar;
-
-	fix->crsr_width = fix->crsr_xsize = par->crsr.width;
-	fix->crsr_height = fix->crsr_ysize = par->crsr.height;
-	fix->crsr_color1 = 17;
-	fix->crsr_color2 = 18;
-	return 0;
-}
-
-static int ami_get_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data, int con)
-{
-	struct amiga_fb_par *par = &currentpar;
-	register u_short *lspr, *sspr;
-	register u_long datawords asm ("d2");
-	register short delta;
-	register u_char color;
-	short height, width, bits, words;
-	int i, size, alloc;
-
-	size = par->crsr.height*par->crsr.width;
-	alloc = var->height*var->width;
-	var->height = par->crsr.height;
-	var->width = par->crsr.width;
-	var->xspot = par->crsr.spot_x;
-	var->yspot = par->crsr.spot_y;
-	if (size > var->height*var->width)
-		return -ENAMETOOLONG;
-	if ((i = verify_area(VERIFY_WRITE, (void *)data, size)))
-		return i;
-	delta = 1<<par->crsr.fmode;
-	lspr = lofsprite + (delta<<1);
-	if (par->bplcon0 & BPC0_LACE)
-		sspr = shfsprite + (delta<<1);
-	else
-		sspr = 0;
-	for (height = (short)var->height-1; height >= 0; height--) {
-		bits = 0; words = delta; datawords = 0;
-		for (width = (short)var->width-1; width >= 0; width--) {
-			if (bits == 0) {
-				bits = 16; --words;
-				asm volatile ("movew %1@(%3:w:2),%0 ; swap %0 ; movew %1@+,%0"
-					: "=d" (datawords), "=a" (lspr) : "1" (lspr), "d" (delta));
-			}
-			--bits;
-			asm volatile (
-				"clrb %0 ; swap %1 ; lslw #1,%1 ; roxlb #1,%0 ; "
-				"swap %1 ; lslw #1,%1 ; roxlb #1,%0"
-				: "=d" (color), "=d" (datawords) : "1" (datawords));
-			put_user(color, data++);
-		}
-		if (bits > 0) {
-			--words; ++lspr;
-		}
-		while (--words >= 0)
-			++lspr;
-		asm volatile ("lea %0@(%4:w:2),%0 ; tstl %1 ; jeq 1f ; exg %0,%1\n1:"
-			: "=a" (lspr), "=a" (sspr) : "0" (lspr), "1" (sspr), "d" (delta));
-	}
-	return 0;
-}
-
-static int ami_set_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data, int con)
-{
-	struct amiga_fb_par *par = &currentpar;
-	register u_short *lspr, *sspr;
-	register u_long datawords asm ("d2");
-	register short delta;
-	u_short fmode;
-	short height, width, bits, words;
-	int i;
-
-	if (!var->width)
-		return -EINVAL;
-	else if (var->width <= 16)
-		fmode = TAG_FMODE_1;
-	else if (var->width <= 32)
-		fmode = TAG_FMODE_2;
-	else if (var->width <= 64)
-		fmode = TAG_FMODE_4;
-	else
-		return -EINVAL;
-	if (fmode > maxfmode)
-		return -EINVAL;
-	if (!var->height)
-		return -EINVAL;
-	if ((i = verify_area(VERIFY_READ, (void *)data, var->width*var->height)))
-		return i;
-	delta = 1<<fmode;
-	lofsprite = shfsprite = (u_short *)spritememory;
-	lspr = lofsprite + (delta<<1);
-	if (par->bplcon0 & BPC0_LACE) {
-		if (((var->height+4)<<fmode<<2) > SPRITEMEMSIZE)
-			return -EINVAL;
-		memset(lspr, 0, (var->height+4)<<fmode<<2);
-		shfsprite += ((var->height+5)&-2)<<fmode;
-		sspr = shfsprite + (delta<<1);
-	} else {
-		if (((var->height+2)<<fmode<<2) > SPRITEMEMSIZE)
-			return -EINVAL;
-		memset(lspr, 0, (var->height+2)<<fmode<<2);
-		sspr = 0;
-	}
-	for (height = (short)var->height-1; height >= 0; height--) {
-		bits = 16; words = delta; datawords = 0;
-		for (width = (short)var->width-1; width >= 0; width--) {
-			unsigned long tdata = 0;
-			get_user(tdata, (char *)data);
-			data++;
-			asm volatile (
-				"lsrb #1,%2 ; roxlw #1,%0 ; swap %0 ; "
-				"lsrb #1,%2 ; roxlw #1,%0 ; swap %0"
-				: "=d" (datawords)
-				: "0" (datawords), "d" (tdata));
-			if (--bits == 0) {
-				bits = 16; --words;
-				asm volatile ("swap %2 ; movew %2,%0@(%3:w:2) ; swap %2 ; movew %2,%0@+"
-					: "=a" (lspr) : "0" (lspr), "d" (datawords), "d" (delta));
-			}
-		}
-		if (bits < 16) {
-			--words;
-			asm volatile (
-				"swap %2 ; lslw %4,%2 ; movew %2,%0@(%3:w:2) ; "
-				"swap %2 ; lslw %4,%2 ; movew %2,%0@+"
-				: "=a" (lspr) : "0" (lspr), "d" (datawords), "d" (delta), "d" (bits));
-		}
-		while (--words >= 0)
-			asm volatile ("moveql #0,%%d0 ; movew %%d0,%0@(%2:w:2) ; movew %%d0,%0@+"
-				: "=a" (lspr) : "0" (lspr), "d" (delta) : "d0");
-		asm volatile ("lea %0@(%4:w:2),%0 ; tstl %1 ; jeq 1f ; exg %0,%1\n1:"
-			: "=a" (lspr), "=a" (sspr) : "0" (lspr), "1" (sspr), "d" (delta));
-	}
-	par->crsr.height = var->height;
-	par->crsr.width = var->width;
-	par->crsr.spot_x = var->xspot;
-	par->crsr.spot_y = var->yspot;
-	par->crsr.fmode = fmode;
-	if (IS_AGA) {
-		par->fmode &= ~(FMODE_SPAGEM | FMODE_SPR32);
-		par->fmode |= sprfetchmode[fmode];
-		custom.fmode = par->fmode;
-	}
-	return 0;
-}
-
-static int ami_get_cursorstate(struct fb_cursorstate *state, int con)
-{
-	struct amiga_fb_par *par = &currentpar;
-
-	state->xoffset = par->crsr.crsr_x;
-	state->yoffset = par->crsr.crsr_y;
-	state->mode = cursormode;
-	return 0;
-}
-
-static int ami_set_cursorstate(struct fb_cursorstate *state, int con)
-{
-	struct amiga_fb_par *par = &currentpar;
-
-	par->crsr.crsr_x = state->xoffset;
-	par->crsr.crsr_y = state->yoffset;
-	if ((cursormode = state->mode) == FB_CURSOR_OFF)
-		cursorstate = -1;
-	do_cursor = 1;
-	return 0;
-}
-
-static void ami_set_sprite(void)
-{
-	struct amiga_fb_par *par = &currentpar;
-	copins *copl, *cops;
-	u_short hs, vs, ve;
-	u_long pl, ps, pt;
-	short mx, my;
-
-	cops = copdisplay.list[currentcop][0];
-	copl = copdisplay.list[currentcop][1];
-	ps = pl = ZTWO_PADDR(dummysprite);
-	mx = par->crsr.crsr_x-par->crsr.spot_x;
-	my = par->crsr.crsr_y-par->crsr.spot_y;
-	if (!(par->vmode & FB_VMODE_YWRAP)) {
-		mx -= par->xoffset;
-		my -= par->yoffset;
-	}
-	if (!is_blanked && cursorstate > 0 && par->crsr.height > 0 &&
-	    mx > -(short)par->crsr.width && mx < par->xres &&
-	    my > -(short)par->crsr.height && my < par->yres) {
-		pl = ZTWO_PADDR(lofsprite);
-		hs = par->diwstrt_h + (mx<<par->clk_shift) - 4;
-		vs = par->diwstrt_v + (my<<par->line_shift);
-		ve = vs + (par->crsr.height<<par->line_shift);
-		if (par->bplcon0 & BPC0_LACE) {
-			ps = ZTWO_PADDR(shfsprite);
-			lofsprite[0] = spr2hw_pos(vs, hs);
-			shfsprite[0] = spr2hw_pos(vs+1, hs);
-			if (mod2(vs)) {
-				lofsprite[1<<par->crsr.fmode] = spr2hw_ctl(vs, hs, ve);
-				shfsprite[1<<par->crsr.fmode] = spr2hw_ctl(vs+1, hs, ve+1);
-				pt = pl; pl = ps; ps = pt;
-			} else {
-				lofsprite[1<<par->crsr.fmode] = spr2hw_ctl(vs, hs, ve+1);
-				shfsprite[1<<par->crsr.fmode] = spr2hw_ctl(vs+1, hs, ve);
-			}
-		} else {
-			lofsprite[0] = spr2hw_pos(vs, hs) | (IS_AGA && (par->fmode & FMODE_BSCAN2) ? 0x80 : 0);
-			lofsprite[1<<par->crsr.fmode] = spr2hw_ctl(vs, hs, ve);
-		}
-	}
-	copl[cop_spr0ptrh].w[1] = highw(pl);
-	copl[cop_spr0ptrl].w[1] = loww(pl);
-	if (par->bplcon0 & BPC0_LACE) {
-		cops[cop_spr0ptrh].w[1] = highw(ps);
-		cops[cop_spr0ptrl].w[1] = loww(ps);
-	}
-}
-
-	/*
-	 * Initialise the Copper Initialisation List
-	 */
-
-static void ami_init_copper(void)
-{
-	copins *cop = copdisplay.init;
-	u_long p;
-	int i;
-
-	if (!IS_OCS) {
-		(cop++)->l = CMOVE(BPC0_COLOR | BPC0_SHRES | BPC0_ECSENA, bplcon0);
-		(cop++)->l = CMOVE(0x0181, diwstrt);
-		(cop++)->l = CMOVE(0x0281, diwstop);
-		(cop++)->l = CMOVE(0x0000, diwhigh);
-	} else
-		(cop++)->l = CMOVE(BPC0_COLOR, bplcon0);
-	p = ZTWO_PADDR(dummysprite);
-	for (i = 0; i < 8; i++) {
-		(cop++)->l = CMOVE(0, spr[i].pos);
-		(cop++)->l = CMOVE(highw(p), sprpt[i]);
-		(cop++)->l = CMOVE2(loww(p), sprpt[i]);
-	}
-
-	(cop++)->l = CMOVE(IF_SETCLR | IF_COPER, intreq);
-	copdisplay.wait = cop;
-	(cop++)->l = CEND;
-	(cop++)->l = CMOVE(0, copjmp2);
-	cop->l = CEND;
-
-	custom.cop1lc = (u_short *)ZTWO_PADDR(copdisplay.init);
-	custom.copjmp1 = 0;
-}
-
-static void ami_reinit_copper(void)
-{
-	struct amiga_fb_par *par = &currentpar;
-
-	copdisplay.init[cip_bplcon0].w[1] = ~(BPC0_BPU3 | BPC0_BPU2 | BPC0_BPU1 | BPC0_BPU0) & par->bplcon0;
-	copdisplay.wait->l = CWAIT(32, par->diwstrt_v-4);
-}
-
-	/*
-	 * Build the Copper List
-	 */
-
-static void ami_build_copper(void)
-{
-	struct amiga_fb_par *par = &currentpar;
-	copins *copl, *cops;
-	u_long p;
-
-	currentcop = 1 - currentcop;
-
-	copl = copdisplay.list[currentcop][1];
-
-	(copl++)->l = CWAIT(0, 10);
-	(copl++)->l = CMOVE(par->bplcon0, bplcon0);
-	(copl++)->l = CMOVE(0, sprpt[0]);
-	(copl++)->l = CMOVE2(0, sprpt[0]);
-
-	if (par->bplcon0 & BPC0_LACE) {
-		cops = copdisplay.list[currentcop][0];
-
-		(cops++)->l = CWAIT(0, 10);
-		(cops++)->l = CMOVE(par->bplcon0, bplcon0);
-		(cops++)->l = CMOVE(0, sprpt[0]);
-		(cops++)->l = CMOVE2(0, sprpt[0]);
-
-		(copl++)->l = CMOVE(diwstrt2hw(par->diwstrt_h, par->diwstrt_v+1), diwstrt);
-		(copl++)->l = CMOVE(diwstop2hw(par->diwstop_h, par->diwstop_v+1), diwstop);
-		(cops++)->l = CMOVE(diwstrt2hw(par->diwstrt_h, par->diwstrt_v), diwstrt);
-		(cops++)->l = CMOVE(diwstop2hw(par->diwstop_h, par->diwstop_v), diwstop);
-		if (!IS_OCS) {
-			(copl++)->l = CMOVE(diwhigh2hw(par->diwstrt_h, par->diwstrt_v+1,
-			                    par->diwstop_h, par->diwstop_v+1), diwhigh);
-			(cops++)->l = CMOVE(diwhigh2hw(par->diwstrt_h, par->diwstrt_v,
-			                    par->diwstop_h, par->diwstop_v), diwhigh);
-#if 0
-			if (par->beamcon0 & BMC0_VARBEAMEN) {
-				(copl++)->l = CMOVE(vtotal2hw(par->vtotal), vtotal);
-				(copl++)->l = CMOVE(vbstrt2hw(par->vbstrt+1), vbstrt);
-				(copl++)->l = CMOVE(vbstop2hw(par->vbstop+1), vbstop);
-				(cops++)->l = CMOVE(vtotal2hw(par->vtotal), vtotal);
-				(cops++)->l = CMOVE(vbstrt2hw(par->vbstrt), vbstrt);
-				(cops++)->l = CMOVE(vbstop2hw(par->vbstop), vbstop);
-			}
-#endif
-		}
-		p = ZTWO_PADDR(copdisplay.list[currentcop][0]);
-		(copl++)->l = CMOVE(highw(p), cop2lc);
-		(copl++)->l = CMOVE2(loww(p), cop2lc);
-		p = ZTWO_PADDR(copdisplay.list[currentcop][1]);
-		(cops++)->l = CMOVE(highw(p), cop2lc);
-		(cops++)->l = CMOVE2(loww(p), cop2lc);
-		copdisplay.rebuild[0] = cops;
-	} else {
-		(copl++)->l = CMOVE(diwstrt2hw(par->diwstrt_h, par->diwstrt_v), diwstrt);
-		(copl++)->l = CMOVE(diwstop2hw(par->diwstop_h, par->diwstop_v), diwstop);
-		if (!IS_OCS) {
-			(copl++)->l = CMOVE(diwhigh2hw(par->diwstrt_h, par->diwstrt_v,
-			                    par->diwstop_h, par->diwstop_v), diwhigh);
-#if 0
-			if (par->beamcon0 & BMC0_VARBEAMEN) {
-				(copl++)->l = CMOVE(vtotal2hw(par->vtotal), vtotal);
-				(copl++)->l = CMOVE(vbstrt2hw(par->vbstrt), vbstrt);
-				(copl++)->l = CMOVE(vbstop2hw(par->vbstop), vbstop);
-			}
-#endif
-		}
-	}
-	copdisplay.rebuild[1] = copl;
-
-	ami_update_par();
-	ami_rebuild_copper();
-}
-
-	/*
-	 * Rebuild the Copper List
-	 *
-	 * We only change the things that are not static
-	 */
-
-static void ami_rebuild_copper(void)
-{
-	struct amiga_fb_par *par = &currentpar;
-	copins *copl, *cops;
-	u_short line, h_end1, h_end2;
-	short i;
-	u_long p;
-
-	if (IS_AGA && maxfmode + par->clk_shift == 0)
-		h_end1 = par->diwstrt_h-64;
-	else
-		h_end1 = par->htotal-32;
-	h_end2 = par->ddfstop+64;
-
-	ami_set_sprite();
-
-	copl = copdisplay.rebuild[1];
-	p = par->bplpt0;
-	if (par->vmode & FB_VMODE_YWRAP) {
-		if ((par->vyres-par->yoffset) != 1 || !mod2(par->diwstrt_v)) {
-			if (par->yoffset > par->vyres-par->yres) {
-				for (i = 0; i < (short)par->bpp; i++, p += par->next_plane) {
-					(copl++)->l = CMOVE(highw(p), bplpt[i]);
-					(copl++)->l = CMOVE2(loww(p), bplpt[i]);
-				}
-				line = par->diwstrt_v + ((par->vyres-par->yoffset)<<par->line_shift) - 1;
-				while (line >= 512) {
-					(copl++)->l = CWAIT(h_end1, 510);
-					line -= 512;
-				}
-				if (line >= 510 && IS_AGA && maxfmode + par->clk_shift == 0)
-					(copl++)->l = CWAIT(h_end1, line);
-				else
-					(copl++)->l = CWAIT(h_end2, line);
-				p = par->bplpt0wrap;
-			}
-		} else p = par->bplpt0wrap;
-	}
-	for (i = 0; i < (short)par->bpp; i++, p += par->next_plane) {
-		(copl++)->l = CMOVE(highw(p), bplpt[i]);
-		(copl++)->l = CMOVE2(loww(p), bplpt[i]);
-	}
-	copl->l = CEND;
-
-	if (par->bplcon0 & BPC0_LACE) {
-		cops = copdisplay.rebuild[0];
-		p = par->bplpt0;
-		if (mod2(par->diwstrt_v))
-			p -= par->next_line;
-		else
-			p += par->next_line;
-		if (par->vmode & FB_VMODE_YWRAP) {
-			if ((par->vyres-par->yoffset) != 1 || mod2(par->diwstrt_v)) {
-				if (par->yoffset > par->vyres-par->yres+1) {
-					for (i = 0; i < (short)par->bpp; i++, p += par->next_plane) {
-						(cops++)->l = CMOVE(highw(p), bplpt[i]);
-						(cops++)->l = CMOVE2(loww(p), bplpt[i]);
-					}
-					line = par->diwstrt_v + ((par->vyres-par->yoffset)<<par->line_shift) - 2;
-					while (line >= 512) {
-						(cops++)->l = CWAIT(h_end1, 510);
-						line -= 512;
-					}
-					if (line > 510 && IS_AGA && maxfmode + par->clk_shift == 0)
-						(cops++)->l = CWAIT(h_end1, line);
-					else
-						(cops++)->l = CWAIT(h_end2, line);
-					p = par->bplpt0wrap;
-					if (mod2(par->diwstrt_v+par->vyres-par->yoffset))
-						p -= par->next_line;
-					else
-						p += par->next_line;
-				}
-			} else p = par->bplpt0wrap - par->next_line;
-		}
-		for (i = 0; i < (short)par->bpp; i++, p += par->next_plane) {
-			(cops++)->l = CMOVE(highw(p), bplpt[i]);
-			(cops++)->l = CMOVE2(loww(p), bplpt[i]);
-		}
-		cops->l = CEND;
-	}
-}
diff -u --recursive --new-file v2.1.72/linux/arch/m68k/amiga/amikeyb.c linux/arch/m68k/amiga/amikeyb.c
--- v2.1.72/linux/arch/m68k/amiga/amikeyb.c	Mon Aug  4 16:25:36 1997
+++ linux/arch/m68k/amiga/amikeyb.c	Wed Dec 31 16:00:00 1969
@@ -1,343 +0,0 @@
-/*
- * linux/arch/m68k/amiga/amikeyb.c
- *
- * Amiga Keyboard driver for Linux/m68k
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file COPYING in the main directory of this archive
- * for more details.
- */
-
-/*
- * Amiga support by Hamish Macdonald
- */
-
-#include <linux/types.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/errno.h>
-#include <linux/keyboard.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/kd.h>
-#include <linux/random.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/kbd_ll.h>
-
-#include <asm/amigaints.h>
-#include <asm/amigahw.h>
-#include <asm/irq.h>
-
-#define AMIKEY_CAPS	(0x62)
-#define BREAK_MASK	(0x80)
-#define RESET_WARNING	(0xf0)	/* before rotation */
-
-static u_short amiplain_map[NR_KEYS] __initdata = {
-	0xf060, 0xf031, 0xf032, 0xf033, 0xf034, 0xf035, 0xf036, 0xf037,
-	0xf038, 0xf039, 0xf030, 0xf02d, 0xf03d, 0xf05c, 0xf200, 0xf300,
-	0xfb71, 0xfb77, 0xfb65, 0xfb72, 0xfb74, 0xfb79, 0xfb75, 0xfb69,
-	0xfb6f, 0xfb70, 0xf05b, 0xf05d, 0xf200, 0xf301, 0xf302, 0xf303,
-	0xfb61, 0xfb73, 0xfb64, 0xfb66, 0xfb67, 0xfb68, 0xfb6a, 0xfb6b,
-	0xfb6c, 0xf03b, 0xf027, 0xf200, 0xf200, 0xf304, 0xf305, 0xf306,
-	0xf200, 0xfb7a, 0xfb78, 0xfb63, 0xfb76, 0xfb62, 0xfb6e, 0xfb6d,
-	0xf02c, 0xf02e, 0xf02f, 0xf200, 0xf310, 0xf307, 0xf308, 0xf309,
-	0xf020, 0xf07f, 0xf009, 0xf30e, 0xf201, 0xf01b, 0xf07f, 0xf200,
-	0xf200, 0xf200, 0xf30b, 0xf200, 0xf603, 0xf600, 0xf602, 0xf601,
-	0xf100, 0xf101, 0xf102, 0xf103, 0xf104, 0xf105, 0xf106, 0xf107,
-	0xf108, 0xf109, 0xf312, 0xf313, 0xf30d, 0xf30c, 0xf30a, 0xf11b,
-	0xf700, 0xf700, 0xf207, 0xf702, 0xf703, 0xf701, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-};
-
-static u_short amishift_map[NR_KEYS] = {
-	0xf07e, 0xf021, 0xf040, 0xf023, 0xf024, 0xf025, 0xf05e, 0xf026,
-	0xf02a, 0xf028, 0xf029, 0xf05f, 0xf02b, 0xf07c, 0xf200, 0xf300,
-	0xfb51, 0xfb57, 0xfb45, 0xfb52, 0xfb54, 0xfb59, 0xfb55, 0xfb49,
-	0xfb4f, 0xfb50, 0xf07b, 0xf07d, 0xf200, 0xf301, 0xf302, 0xf303,
-	0xfb41, 0xfb53, 0xfb44, 0xfb46, 0xfb47, 0xfb48, 0xfb4a, 0xfb4b,
-	0xfb4c, 0xf03a, 0xf022, 0xf200, 0xf200, 0xf304, 0xf305, 0xf306,
-	0xf200, 0xfb5a, 0xfb58, 0xfb43, 0xfb56, 0xfb42, 0xfb4e, 0xfb4d,
-	0xf03c, 0xf03e, 0xf03f, 0xf200, 0xf310, 0xf307, 0xf308, 0xf309,
-	0xf020, 0xf07f, 0xf009, 0xf30e, 0xf201, 0xf01b, 0xf07f, 0xf200,
-	0xf200, 0xf200, 0xf30b, 0xf200, 0xf603, 0xf600, 0xf602, 0xf601,
-	0xf10a, 0xf10b, 0xf10c, 0xf10d, 0xf10e, 0xf10f, 0xf110, 0xf111,
-	0xf112, 0xf113, 0xf208, 0xf209, 0xf30d, 0xf30c, 0xf30a, 0xf203,
-	0xf700, 0xf700, 0xf207, 0xf702, 0xf703, 0xf701, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-};
-
-static u_short amialtgr_map[NR_KEYS] = {
-	0xf200, 0xf200, 0xf040, 0xf200, 0xf024, 0xf200, 0xf200, 0xf07b,
-	0xf05b, 0xf05d, 0xf07d, 0xf05c, 0xf200, 0xf200, 0xf200, 0xf300,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf07e, 0xf200, 0xf301, 0xf302, 0xf303,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf304, 0xf305, 0xf306,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf310, 0xf307, 0xf308, 0xf309,
-	0xf200, 0xf07f, 0xf200, 0xf30e, 0xf201, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf30b, 0xf200, 0xf603, 0xf600, 0xf602, 0xf601,
-	0xf50c, 0xf50d, 0xf50e, 0xf50f, 0xf510, 0xf511, 0xf512, 0xf513,
-	0xf514, 0xf515, 0xf208, 0xf209, 0xf30d, 0xf30c, 0xf30a, 0xf204,
-	0xf700, 0xf700, 0xf207, 0xf702, 0xf703, 0xf701, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-};
-
-static u_short amictrl_map[NR_KEYS] = {
-	0xf000, 0xf200, 0xf000, 0xf01b, 0xf01c, 0xf01d, 0xf01e, 0xf01f,
-	0xf07f, 0xf200, 0xf200, 0xf01f, 0xf200, 0xf01c, 0xf200, 0xf300,
-	0xf011, 0xf017, 0xf005, 0xf012, 0xf014, 0xf019, 0xf015, 0xf009,
-	0xf00f, 0xf010, 0xf01b, 0xf01d, 0xf200, 0xf301, 0xf302, 0xf303,
-	0xf001, 0xf013, 0xf004, 0xf006, 0xf007, 0xf008, 0xf00a, 0xf00b,
-	0xf00c, 0xf200, 0xf007, 0xf200, 0xf200, 0xf304, 0xf305, 0xf306,
-	0xf200, 0xf01a, 0xf018, 0xf003, 0xf016, 0xf002, 0xf00e, 0xf00d,
-	0xf200, 0xf200, 0xf07f, 0xf200, 0xf310, 0xf307, 0xf308, 0xf309,
-	0xf000, 0xf07f, 0xf200, 0xf30e, 0xf201, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf30b, 0xf200, 0xf603, 0xf600, 0xf602, 0xf601,
-	0xf100, 0xf101, 0xf102, 0xf103, 0xf104, 0xf105, 0xf106, 0xf107,
-	0xf108, 0xf109, 0xf208, 0xf209, 0xf30d, 0xf30c, 0xf30a, 0xf202,
-	0xf700, 0xf700, 0xf207, 0xf702, 0xf703, 0xf701, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-};
-
-static u_short amishift_ctrl_map[NR_KEYS] = {
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf300,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf301, 0xf302, 0xf303,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf304, 0xf305, 0xf306,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf310, 0xf307, 0xf308, 0xf309,
-	0xf200, 0xf07f, 0xf200, 0xf30e, 0xf201, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf30b, 0xf200, 0xf603, 0xf600, 0xf602, 0xf601,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf208, 0xf209, 0xf30d, 0xf30c, 0xf30a, 0xf200,
-	0xf700, 0xf700, 0xf207, 0xf702, 0xf703, 0xf701, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-};
-
-static u_short amialt_map[NR_KEYS] = {
-	0xf860, 0xf831, 0xf832, 0xf833, 0xf834, 0xf835, 0xf836, 0xf837,
-	0xf838, 0xf839, 0xf830, 0xf82d, 0xf83d, 0xf85c, 0xf200, 0xf900,
-	0xf871, 0xf877, 0xf865, 0xf872, 0xf874, 0xf879, 0xf875, 0xf869,
-	0xf86f, 0xf870, 0xf85b, 0xf85d, 0xf200, 0xf901, 0xf902, 0xf903,
-	0xf861, 0xf873, 0xf864, 0xf866, 0xf867, 0xf868, 0xf86a, 0xf86b,
-	0xf86c, 0xf83b, 0xf827, 0xf200, 0xf200, 0xf904, 0xf905, 0xf906,
-	0xf200, 0xf87a, 0xf878, 0xf863, 0xf876, 0xf862, 0xf86e, 0xf86d,
-	0xf82c, 0xf82e, 0xf82f, 0xf200, 0xf310, 0xf907, 0xf908, 0xf909,
-	0xf820, 0xf87f, 0xf809, 0xf30e, 0xf80d, 0xf81b, 0xf87f, 0xf200,
-	0xf200, 0xf200, 0xf30b, 0xf200, 0xf603, 0xf600, 0xf602, 0xf601,
-	0xf500, 0xf501, 0xf502, 0xf503, 0xf504, 0xf505, 0xf506, 0xf507,
-	0xf508, 0xf509, 0xf208, 0xf209, 0xf30d, 0xf30c, 0xf30a, 0xf204,
-	0xf700, 0xf700, 0xf207, 0xf702, 0xf703, 0xf701, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-};
-
-static u_short amictrl_alt_map[NR_KEYS] = {
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf300,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf301, 0xf302, 0xf303,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf304, 0xf305, 0xf306,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf20c, 0xf307, 0xf308, 0xf309,
-	0xf200, 0xf07f, 0xf200, 0xf30e, 0xf201, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf30b, 0xf200, 0xf603, 0xf600, 0xf602, 0xf601,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf208, 0xf209, 0xf30d, 0xf30c, 0xf30a, 0xf200,
-	0xf700, 0xf700, 0xf207, 0xf702, 0xf703, 0xf701, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-};
-
-#define	DEFAULT_KEYB_REP_DELAY	(HZ/4)
-#define	DEFAULT_KEYB_REP_RATE	(HZ/25)
-
-/* These could be settable by some ioctl() in future... */
-static unsigned int key_repeat_delay = DEFAULT_KEYB_REP_DELAY;
-static unsigned int key_repeat_rate  = DEFAULT_KEYB_REP_RATE;
-
-static unsigned char rep_scancode;
-static void amikeyb_rep(unsigned long ignore);
-static struct timer_list amikeyb_rep_timer = {NULL, NULL, 0, 0, amikeyb_rep};
-
-static void amikeyb_rep(unsigned long ignore)
-{
-    unsigned long flags;
-    save_flags(flags);
-    cli();
-
-    kbd_pt_regs = NULL;
-
-    amikeyb_rep_timer.expires = jiffies + key_repeat_rate;
-    amikeyb_rep_timer.prev = amikeyb_rep_timer.next = NULL;
-    add_timer(&amikeyb_rep_timer);
-    handle_scancode(rep_scancode);
-
-    restore_flags(flags);
-}
-
-static void keyboard_interrupt(int irq, void *dummy, struct pt_regs *fp)
-{
-    unsigned char scancode, break_flag, keycode;
-    static int reset_warning = 0;
-
-    /* save frame for register dump */
-    kbd_pt_regs = fp;
-
-    /* get and invert scancode (keyboard is active low) */
-    scancode = ~ciaa.sdr;
-
-    /* switch SP pin to output for handshake */
-    ciaa.cra |= 0x40;
-
-#if 0 // No longer used
-    /*
-     *  On receipt of the second RESET_WARNING, we must not pull KDAT high
-     *  again to delay the hard reset as long as possible.
-     *
-     *  Note that not all keyboards send reset warnings...
-     */
-    if (reset_warning)
-	if (scancode == RESET_WARNING) {
-	    printk(KERN_ALERT "amikeyb: Ctrl-Amiga-Amiga reset warning!!\n"
-		   "The system will be reset within 10 seconds!!\n");
-	    /* Panic doesn't sync from within an interrupt, so we do nothing */
-	    return;
-	} else
-	    /* Probably a mistake, cancel the alert */
-	    reset_warning = 0;
-#endif
-
-    /* wait until 85 us have expired */
-    udelay(85);
-    /* switch CIA serial port to input mode */
-    ciaa.cra &= ~0x40;
-
-    mark_bh(KEYBOARD_BH);
-
-    /* rotate scan code to get up/down bit in proper position */
-    __asm__ __volatile__ ("rorb #1,%0" : "=g" (scancode) : "0" (scancode));
-
-    /*
-     * Check make/break first
-     */
-    break_flag = scancode & BREAK_MASK;
-    keycode = scancode & (unsigned char)~BREAK_MASK;
-
-    if (keycode == AMIKEY_CAPS) {
-	/* if the key is CAPS, fake a press/release. */
-	handle_scancode(AMIKEY_CAPS);
-	handle_scancode(BREAK_MASK | AMIKEY_CAPS);
-    } else if (keycode < 0x78) {
-	/* handle repeat */
-	if (break_flag) {
-	    del_timer(&amikeyb_rep_timer);
-	    rep_scancode = 0;
-	} else {
-	    del_timer(&amikeyb_rep_timer);
-	    rep_scancode = keycode;
-	    amikeyb_rep_timer.expires = jiffies + key_repeat_delay;
-	    amikeyb_rep_timer.prev = amikeyb_rep_timer.next = NULL;
-	    add_timer(&amikeyb_rep_timer);
-	}
-	handle_scancode(scancode);
-    } else
-	switch (keycode) {
-	    case 0x78:
-		reset_warning = 1;
-		break;
-	    case 0x79:
-		printk(KERN_WARNING "amikeyb: keyboard lost sync\n");
-		break;
-	    case 0x7a:
-		printk(KERN_WARNING "amikeyb: keyboard buffer overflow\n");
-		break;
-#if 0 /* obsolete according to the HRM */
-	    case 0x7b:
-		printk(KERN_WARNING "amikeyb: keyboard controller failure\n");
-		break;
-#endif
-	    case 0x7c:
-		printk(KERN_ERR "amikeyb: keyboard selftest failure\n");
-		break;
-	    case 0x7d:
-		printk(KERN_INFO "amikeyb: initiate power-up key stream\n");
-		break;
-	    case 0x7e:
-		printk(KERN_INFO "amikeyb: terminate power-up key stream\n");
-		break;
-#if 0 /* obsolete according to the HRM */
-	    case 0x7f:
-		printk(KERN_WARNING "amikeyb: keyboard interrupt\n");
-		break;
-#endif
-	    default:
-		printk(KERN_WARNING "amikeyb: unknown keyboard communication code 0x%02x\n",
-		       scancode);
-		break;
-	}
-}
-
-__initfunc(int amiga_keyb_init(void))
-{
-    if (!AMIGAHW_PRESENT(AMI_KEYBOARD))
-        return -EIO;
-
-    /* setup key map */
-    memcpy(plain_map, amiplain_map, sizeof(plain_map));
-    key_maps[1]  = amishift_map;
-    key_maps[2]  = amialtgr_map;
-    key_maps[4]  = amictrl_map;
-    key_maps[5]  = amishift_ctrl_map;
-    key_maps[8]  = amialt_map;
-    key_maps[12] = amictrl_alt_map;
-
-    /*
-     * Initialize serial data direction.
-     */
-    ciaa.cra &= ~0x41;	     /* serial data in, turn off TA */
-
-    /*
-     * arrange for processing of keyboard interrupt
-     */
-    request_irq(IRQ_AMIGA_CIAA_SP, keyboard_interrupt, 0, "keyboard", NULL);
-
-    return 0;
-}
-
-int amiga_kbdrate( struct kbd_repeat *k )
-{
-    if (k->delay > 0) {
-	/* convert from msec to jiffies */
-	key_repeat_delay = (k->delay * HZ + 500) / 1000;
-	if (key_repeat_delay < 1)
-            key_repeat_delay = 1;
-    }
-    if (k->rate > 0) {
-	key_repeat_rate = (k->rate * HZ + 500) / 1000;
-	if (key_repeat_rate < 1)
-            key_repeat_rate = 1;
-    }
-
-    k->delay = key_repeat_delay * 1000 / HZ;
-    k->rate  = key_repeat_rate  * 1000 / HZ;
-    
-    return( 0 );
-}
diff -u --recursive --new-file v2.1.72/linux/arch/m68k/amiga/cyberfb.c linux/arch/m68k/amiga/cyberfb.c
--- v2.1.72/linux/arch/m68k/amiga/cyberfb.c	Mon Jul  7 08:18:53 1997
+++ linux/arch/m68k/amiga/cyberfb.c	Wed Dec 31 16:00:00 1969
@@ -1,1253 +0,0 @@
-/*
- * linux/arch/m68k/amiga/cyberfb.c -- Low level implementation of the
- *                                    Cybervision frame buffer device
- *
- *    Copyright (C) 1996 Martin Apel
- *                       Geert Uytterhoeven
- *
- *
- * This file is based on the Amiga frame buffer device (amifb.c):
- *
- *    Copyright (C) 1995 Geert Uytterhoeven
- *
- *
- * History:
- *   - 22 Dec 95: Original version by Martin Apel
- *   - 05 Jan 96: Geert: integration into the current source tree
- *
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file COPYING in the main directory of this archive
- * for more details.
- */
-
-
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/tty.h>
-#include <linux/malloc.h>
-#include <linux/delay.h>
-#include <linux/zorro.h>
-#include <linux/fb.h>
-#include <linux/init.h>
-#include <asm/uaccess.h>
-#include <asm/system.h>
-#include <asm/irq.h>
-#include <asm/pgtable.h>
-#include "s3blit.h"
-
-
-#define arraysize(x)    (sizeof(x)/sizeof(*(x)))
-
-struct Cyber_fb_par {
-   int xres;
-   int yres;
-   int bpp;
-};
-
-static struct Cyber_fb_par current_par;
-
-static int current_par_valid = 0;
-static int currcon = 0;
-
-static struct display disp[MAX_NR_CONSOLES];
-static struct fb_info fb_info;
-
-static int node;        /* node of the /dev/fb?current file */
-
-
-   /*
-    *    Switch for Chipset Independency
-    */
-
-static struct fb_hwswitch {
-
-   /* Initialisation */
-
-   int (*init)(void);
-
-   /* Display Control */
-
-   int (*encode_fix)(struct fb_fix_screeninfo *fix, struct Cyber_fb_par *par);
-   int (*decode_var)(struct fb_var_screeninfo *var, struct Cyber_fb_par *par);
-   int (*encode_var)(struct fb_var_screeninfo *var, struct Cyber_fb_par *par);
-   int (*getcolreg)(u_int regno, u_int *red, u_int *green, u_int *blue,
-                    u_int *transp);
-   int (*setcolreg)(u_int regno, u_int red, u_int green, u_int blue,
-                    u_int transp);
-   void (*blank)(int blank);
-} *fbhw;
-
-
-   /*
-    *    Frame Buffer Name
-    */
-
-static char Cyber_fb_name[16] = "Cybervision";
-
-
-   /*
-    *    Cybervision Graphics Board
-    */
-
-#define CYBER8_WIDTH 1152
-#define CYBER8_HEIGHT 886
-#define CYBER8_PIXCLOCK 12500    /* ++Geert: Just a guess */
-
-#define CYBER16_WIDTH 800
-#define CYBER16_HEIGHT 600
-#define CYBER16_PIXCLOCK 25000   /* ++Geert: Just a guess */
-
-
-static int CyberKey = 0;
-static u_char Cyber_colour_table [256][4];
-static unsigned long CyberMem;
-static unsigned long CyberSize;
-static volatile char *CyberRegs;
-
-static long *memstart;
-
-
-   /*
-    *    Predefined Video Mode Names
-    */
-
-static char *Cyber_fb_modenames[] = {
-
-   /*
-    *    Autodetect (Default) Video Mode
-    */
-
-   "default",
-
-   /*
-    *    Predefined Video Modes
-    */
-    
-   "cyber8",            /* Cybervision 8 bpp */
-   "cyber16",           /* Cybervision 16 bpp */
-
-   /*
-    *    Dummy Video Modes
-    */
-
-   "dummy", "dummy", "dummy", "dummy", "dummy", "dummy", "dummy", "dummy",
-   "dummy", "dummy", "dummy", "dummy", "dummy", "dummy", "dummy", "dummy",
-   "dummy", "dummy", "dummy", "dummy",
-
-   /*
-    *    User Defined Video Modes
-    *
-    *    This doesn't work yet!!
-    */
-
-   "user0", "user1", "user2", "user3", "user4", "user5", "user6", "user7"
-};
-
-
-   /*
-    *    Predefined Video Mode Definitions
-    */
-
-static struct fb_var_screeninfo Cyber_fb_predefined[] = {
-
-   /*
-    *    Autodetect (Default) Video Mode
-    */
-
-   { 0, },
-
-   /*
-    *    Predefined Video Modes
-    */
-    
-   {
-      /* Cybervision 8 bpp */
-      CYBER8_WIDTH, CYBER8_HEIGHT, CYBER8_WIDTH, CYBER8_HEIGHT, 0, 0, 8, 0,
-      {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
-      0, 0, -1, -1, FB_ACCEL_NONE, CYBER8_PIXCLOCK, 64, 96, 35, 12, 112, 2,
-      FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
-   }, {
-      /* Cybervision 16 bpp */
-      CYBER16_WIDTH, CYBER16_HEIGHT, CYBER16_WIDTH, CYBER16_HEIGHT, 0, 0, 16, 0,
-      {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0},
-      0, 0, -1, -1, FB_ACCEL_NONE, CYBER16_PIXCLOCK, 64, 96, 35, 12, 112, 2,
-      FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
-   },
-
-   /*
-    *    Dummy Video Modes
-    */
-
-   { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, },
-   { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, },
-   { 0, }, { 0, },
-
-   /*
-    *    User Defined Video Modes
-    */
-
-   { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }
-};
-
-
-#define NUM_TOTAL_MODES    arraysize(Cyber_fb_predefined)
-#define NUM_PREDEF_MODES   (3)
-
-
-static int Cyberfb_inverse = 0;
-static int Cyberfb_Cyber8 = 0;        /* Use Cybervision board */
-static int Cyberfb_Cyber16 = 0;       /* Use Cybervision board */
-static int Cyberfb_mode = 0;
-
-
-   /*
-    *    Some default modes
-    */
-
-#define CYBER8_DEFMODE     (1)
-#define CYBER16_DEFMODE    (2)
-
-
-   /*
-    *    Interface used by the world
-    */
-
-int Cyber_probe(void);
-void Cyber_video_setup(char *options, int *ints);
-
-static int Cyber_fb_get_fix(struct fb_fix_screeninfo *fix, int con);
-static int Cyber_fb_get_var(struct fb_var_screeninfo *var, int con);
-static int Cyber_fb_set_var(struct fb_var_screeninfo *var, int con);
-static int Cyber_fb_get_cmap(struct fb_cmap *cmap, int kspc, int con);
-static int Cyber_fb_set_cmap(struct fb_cmap *cmap, int kspc, int con);
-static int Cyber_fb_pan_display(struct fb_var_screeninfo *var, int con);
-static int Cyber_fb_ioctl(struct inode *inode, struct file *file, u_int cmd,
-                          u_long arg, int con);
-
-
-   /*
-    *    Interface to the low level console driver
-    */
-
-struct fb_info *Cyber_fb_init(long *mem_start); /* Through amiga_fb_init() */
-static int Cyberfb_switch(int con);
-static int Cyberfb_updatevar(int con);
-static void Cyberfb_blank(int blank);
-static int Cyberfb_setcmap(struct fb_cmap *cmap, int con);
-
-
-   /*
-    *    Accelerated Functions used by the low level console driver
-    */
-
-void Cyber_WaitQueue(u_short fifo);
-void Cyber_WaitBlit(void);
-void Cyber_BitBLT(u_short curx, u_short cury, u_short destx, u_short desty,
-                  u_short width, u_short height, u_short mode);
-void Cyber_RectFill(u_short x, u_short y, u_short width, u_short height,
-                    u_short mode, u_short color);
-void Cyber_MoveCursor(u_short x, u_short y);
-
-
-   /*
-    *   Hardware Specific Routines
-    */
-
-static int Cyber_init(void);
-static int Cyber_encode_fix(struct fb_fix_screeninfo *fix,
-                          struct Cyber_fb_par *par);
-static int Cyber_decode_var(struct fb_var_screeninfo *var,
-                          struct Cyber_fb_par *par);
-static int Cyber_encode_var(struct fb_var_screeninfo *var,
-                          struct Cyber_fb_par *par);
-static int Cyber_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
-                         u_int *transp);
-static int Cyber_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
-                         u_int transp);
-static void Cyber_blank(int blank);
-
-
-   /*
-    *    Internal routines
-    */
-
-static void Cyber_fb_get_par(struct Cyber_fb_par *par);
-static void Cyber_fb_set_par(struct Cyber_fb_par *par);
-static int do_fb_set_var(struct fb_var_screeninfo *var, int isactive);
-static struct fb_cmap *get_default_colormap(int bpp);
-static int do_fb_get_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var,
-                          int kspc);
-static int do_fb_set_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var,
-                          int kspc);
-static void do_install_cmap(int con);
-static void memcpy_fs(int fsfromto, void *to, void *from, int len);
-static void copy_cmap(struct fb_cmap *from, struct fb_cmap *to, int fsfromto);
-static int alloc_cmap(struct fb_cmap *cmap, int len, int transp);
-static void Cyber_fb_set_disp(int con);
-static int get_video_mode(const char *name);
-
-
-/* -------------------- Hardware specific routines -------------------------- */
-
-
-   /*
-    *    Initialization
-    *
-    *    Set the default video mode for this chipset. If a video mode was
-    *    specified on the command line, it will override the default mode.
-    */
-
-static int Cyber_init(void)
-{
-int i;
-char size;
-volatile u_long *CursorBase;
-unsigned long board_addr;
-struct ConfigDev *cd;
-
-if (Cyberfb_mode == -1)
-  {
-  if (Cyberfb_Cyber8)
-    Cyberfb_mode = CYBER8_DEFMODE;
-  else
-    Cyberfb_mode = CYBER16_DEFMODE;
-  }
-
-cd = zorro_get_board (CyberKey);
-zorro_config_board (CyberKey, 0);
-board_addr = (unsigned long)cd->cd_BoardAddr;
-
-for (i = 0; i < 256; i++)
-
-for (i = 0; i < 256; i++)
-  {
-  Cyber_colour_table [i][0] = i;
-  Cyber_colour_table [i][1] = i;
-  Cyber_colour_table [i][2] = i;
-  Cyber_colour_table [i][3] = 0;
-  }
-
-*memstart = (*memstart + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
-/* This includes the video memory as well as the S3 register set */
-CyberMem = kernel_map (board_addr + 0x01400000, 0x01000000,
-                       KERNELMAP_NOCACHE_SER, memstart);
-
-if (Cyberfb_Cyber8)
-  memset ((char*)CyberMem, 0, CYBER8_WIDTH * CYBER8_HEIGHT);
-else
-  memset ((char*)CyberMem, 0, CYBER16_WIDTH * CYBER16_HEIGHT);
-
-CyberRegs = (char*) (CyberMem + 0x00c00000);
-
-/* Disable hardware cursor */
-*(CyberRegs + S3_CRTC_ADR)  = S3_REG_LOCK2;
-*(CyberRegs + S3_CRTC_DATA) = 0xa0;
-*(CyberRegs + S3_CRTC_ADR)  = S3_HGC_MODE;
-*(CyberRegs + S3_CRTC_DATA) = 0x00;
-*(CyberRegs + S3_CRTC_ADR)  = S3_HWGC_DX;
-*(CyberRegs + S3_CRTC_DATA) = 0x00;
-*(CyberRegs + S3_CRTC_ADR)  = S3_HWGC_DY;
-*(CyberRegs + S3_CRTC_DATA) = 0x00;
-
-/* Set clipping rectangle to current screen size */
-*((u_short volatile *)(CyberRegs + 0xbee8)) = 0x1000;
-*((u_short volatile *)(CyberRegs + 0xbee8)) = 0x2000;
-if (Cyberfb_Cyber8)
-  {
-  *((u_short volatile *)(CyberRegs + 0xbee8)) = 0x3000 | (CYBER8_HEIGHT - 1);
-  *((u_short volatile *)(CyberRegs + 0xbee8)) = 0x4000 | (CYBER8_WIDTH - 1);
-  }
-else
-  {
-  *((u_short volatile *)(CyberRegs + 0xbee8)) = 0x3000 | (CYBER16_HEIGHT - 1);
-  *((u_short volatile *)(CyberRegs + 0xbee8)) = 0x4000 | (CYBER16_WIDTH - 1);
-  }
-
-/* Get memory size (if not 2MB it is 4MB) */
-*(CyberRegs + S3_CRTC_ADR) = S3_LAW_CTL;
-size = *(CyberRegs + S3_CRTC_DATA);
-if ((size & 0x03) == 0x02)
-  CyberSize = 0x00200000; /* 2 MB */
-else
-  CyberSize = 0x00400000; /* 4 MB */
-
-/* Initialize hardware cursor */
-CursorBase = (u_long *)((char *)(CyberMem) + CyberSize - 0x400);
-for (i=0; i < 8; i++)
-  {
-  *(CursorBase  +(i*4)) = 0xffffff00;
-  *(CursorBase+1+(i*4)) = 0xffff0000;
-  *(CursorBase+2+(i*4)) = 0xffff0000;
-  *(CursorBase+3+(i*4)) = 0xffff0000;
-  }
-for (i=8; i < 64; i++)
-  {
-  *(CursorBase  +(i*4)) = 0xffff0000;
-  *(CursorBase+1+(i*4)) = 0xffff0000;
-  *(CursorBase+2+(i*4)) = 0xffff0000;
-  *(CursorBase+3+(i*4)) = 0xffff0000;
-  }
-
-Cyber_setcolreg (255, 56, 100, 160, 0);
-Cyber_setcolreg (254, 0, 0, 0, 0);
-
-return (0);
-}
-
-
-   /*
-    *    This function should fill in the `fix' structure based on the
-    *    values in the `par' structure.
-    */
-
-static int Cyber_encode_fix(struct fb_fix_screeninfo *fix,
-                          struct Cyber_fb_par *par)
-{
-   int i;
-
-   strcpy(fix->id, Cyber_fb_name);
-   fix->smem_start = CyberMem;
-#if 0
-   fix->smem_len = CyberSize;
-#else
-   fix->smem_len = 0x01000000;
-#endif
-
-   fix->type = FB_TYPE_PACKED_PIXELS;
-   fix->type_aux = 0;
-   if (par->bpp == 8)
-      fix->visual = FB_VISUAL_PSEUDOCOLOR;
-   else
-      fix->visual = FB_VISUAL_DIRECTCOLOR;
-
-   fix->xpanstep = 0;
-   fix->ypanstep = 0;
-   fix->ywrapstep = 0;
-   fix->line_length = 0;
-
-   for (i = 0; i < arraysize(fix->reserved); i++)
-      fix->reserved[i] = 0;
-
-   return(0);
-}
-
-
-   /*
-    *    Get the video params out of `var'. If a value doesn't fit, round
-    *    it up, if it's too big, return -EINVAL.
-    */
-
-static int Cyber_decode_var(struct fb_var_screeninfo *var,
-                          struct Cyber_fb_par *par)
-{
-   if (Cyberfb_Cyber8) {
-      par->xres = CYBER8_WIDTH;
-      par->yres = CYBER8_HEIGHT;
-      par->bpp = 8;
-   } else {
-      par->xres = CYBER16_WIDTH;
-      par->yres = CYBER16_HEIGHT;
-      par->bpp = 16;
-   }
-   return(0);
-}
-
-
-   /*
-    *    Fill the `var' structure based on the values in `par' and maybe
-    *    other values read out of the hardware.
-    */
-
-static int Cyber_encode_var(struct fb_var_screeninfo *var,
-                          struct Cyber_fb_par *par)
-{
-   int i;
-
-   var->xres = par->xres;
-   var->yres = par->yres;
-   var->xres_virtual = par->xres;
-   var->yres_virtual = par->yres;
-   var->xoffset = 0;
-   var->yoffset = 0;
-
-   var->bits_per_pixel = par->bpp;
-   var->grayscale = 0;
-
-   if (par->bpp == 8) {
-      var->red.offset = 0;
-      var->red.length = 8;
-      var->red.msb_right = 0;
-      var->blue = var->green = var->red;
-   } else {
-      var->red.offset = 11;
-      var->red.length = 5;
-      var->red.msb_right = 0;
-      var->green.offset = 5;
-      var->green.length = 6;
-      var->green.msb_right = 0;
-      var->blue.offset = 0;
-      var->blue.length = 5;
-      var->blue.msb_right = 0;
-   }
-   var->transp.offset = 0;
-   var->transp.length = 0;
-   var->transp.msb_right = 0;
-
-   var->nonstd = 0;
-   var->activate = 0;
-
-   var->height = -1;
-   var->width = -1;
-   var->accel = FB_ACCEL_CYBERVISION;
-   var->vmode = FB_VMODE_NONINTERLACED;
-
-   /* Dummy values */
-
-   if (par->bpp == 8)
-      var->pixclock = CYBER8_PIXCLOCK;
-   else
-      var->pixclock = CYBER16_PIXCLOCK;
-   var->sync = 0;
-   var->left_margin = 64;
-   var->right_margin = 96;
-   var->upper_margin = 35;
-   var->lower_margin = 12;
-   var->hsync_len = 112;
-   var->vsync_len = 2;
-
-   for (i = 0; i < arraysize(var->reserved); i++)
-      var->reserved[i] = 0;
-
-   return(0);
-}
-
-
-   /*
-    *    Set a single color register. The values supplied are already
-    *    rounded down to the hardware's capabilities (according to the
-    *    entries in the var structure). Return != 0 for invalid regno.
-    */
-
-static int Cyber_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
-                         u_int transp)
-{
-if (regno > 255)
-  return (1);
-
-*(CyberRegs + 0x3c8) = (char)regno;
-Cyber_colour_table [regno][0] = red & 0xff;
-Cyber_colour_table [regno][1] = green & 0xff;
-Cyber_colour_table [regno][2] = blue & 0xff;
-Cyber_colour_table [regno][3] = transp;
-
-*(CyberRegs + 0x3c9) = (red & 0xff) >> 2;
-*(CyberRegs + 0x3c9) = (green & 0xff) >> 2;
-*(CyberRegs + 0x3c9) = (blue & 0xff) >> 2;
-
-return (0);
-}
-
-
-   /*
-    *    Read a single color register and split it into
-    *    colors/transparent. Return != 0 for invalid regno.
-    */
-
-static int Cyber_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
-                         u_int *transp)
-{
-if (regno >= 256)
-  return (1);
-*red    = Cyber_colour_table [regno][0];
-*green  = Cyber_colour_table [regno][1];
-*blue   = Cyber_colour_table [regno][2];
-*transp = Cyber_colour_table [regno][3];
-return (0);
-}
-
-
-   /*
-    *    (Un)Blank the screen
-    */
-
-void Cyber_blank(int blank)
-{
-int i;
-
-if (blank)
-  for (i = 0; i < 256; i++)
-    {
-    *(CyberRegs + 0x3c8) = i;
-    *(CyberRegs + 0x3c9) = 0;
-    *(CyberRegs + 0x3c9) = 0;
-    *(CyberRegs + 0x3c9) = 0;
-    }
-else
-  for (i = 0; i < 256; i++)
-    {
-    *(CyberRegs + 0x3c8) = i;
-    *(CyberRegs + 0x3c9) = Cyber_colour_table [i][0] >> 2;
-    *(CyberRegs + 0x3c9) = Cyber_colour_table [i][1] >> 2;
-    *(CyberRegs + 0x3c9) = Cyber_colour_table [i][2] >> 2;
-    }
-}
-
-
-/**************************************************************
- * We are waiting for "fifo" FIFO-slots empty
- */
-void Cyber_WaitQueue (u_short fifo)
-{
-u_short status;
-
-do
-  {
-  status = *((u_short volatile *)(CyberRegs + S3_GP_STAT));
-  }
-while (status & fifo);
-}
-
-/**************************************************************
- * We are waiting for Hardware (Graphics Engine) not busy
- */
-void Cyber_WaitBlit (void)
-{
-u_short status;
-
-do
-  {
-  status = *((u_short volatile *)(CyberRegs + S3_GP_STAT));
-  }
-while (status & S3_HDW_BUSY);
-}
-
-/**************************************************************
- * BitBLT - Through the Plane
- */
-void Cyber_BitBLT (u_short curx, u_short cury, u_short destx, u_short desty,
-                   u_short width, u_short height, u_short mode)
-{
-u_short blitcmd = S3_BITBLT;
-
-/* Set drawing direction */
-/* -Y, X maj, -X (default) */
-if (curx > destx)
-  blitcmd |= 0x0020;  /* Drawing direction +X */
-else
-  {
-  curx  += (width - 1);
-  destx += (width - 1);
-  }
-
-if (cury > desty)
-  blitcmd |= 0x0080;  /* Drawing direction +Y */
-else
-  {
-  cury  += (height - 1);
-  desty += (height - 1);
-  }
-
-Cyber_WaitQueue (0x8000);
-
-*((u_short volatile *)(CyberRegs + S3_PIXEL_CNTL)) = 0xa000;
-*((u_short volatile *)(CyberRegs + S3_FRGD_MIX)) = (0x0060 | mode);
-
-*((u_short volatile *)(CyberRegs + S3_CUR_X)) = curx;
-*((u_short volatile *)(CyberRegs + S3_CUR_Y)) = cury;
-
-*((u_short volatile *)(CyberRegs + S3_DESTX_DIASTP)) = destx;
-*((u_short volatile *)(CyberRegs + S3_DESTY_AXSTP)) = desty;
-
-*((u_short volatile *)(CyberRegs + S3_MIN_AXIS_PCNT)) = height - 1;
-*((u_short volatile *)(CyberRegs + S3_MAJ_AXIS_PCNT)) = width  - 1;
-
-*((u_short volatile *)(CyberRegs + S3_CMD)) = blitcmd;
-}
-
-/**************************************************************
- * Rectangle Fill Solid
- */
-void Cyber_RectFill (u_short x, u_short y, u_short width, u_short height,
-                     u_short mode, u_short fcolor)
-{
-u_short blitcmd = S3_FILLEDRECT;
-
-Cyber_WaitQueue (0x8000);
-
-*((u_short volatile *)(CyberRegs + S3_PIXEL_CNTL)) = 0xa000;
-*((u_short volatile *)(CyberRegs + S3_FRGD_MIX)) = (0x0020 | mode);
-
-*((u_short volatile *)(CyberRegs + S3_MULT_MISC)) = 0xe000;
-*((u_short volatile *)(CyberRegs + S3_FRGD_COLOR)) = color;
-
-*((u_short volatile *)(CyberRegs + S3_CUR_X)) = x;
-*((u_short volatile *)(CyberRegs + S3_CUR_Y)) = y;
-
-*((u_short volatile *)(CyberRegs + S3_MIN_AXIS_PCNT)) = height - 1;
-*((u_short volatile *)(CyberRegs + S3_MAJ_AXIS_PCNT)) = width  - 1;
-
-*((u_short volatile *)(CyberRegs + S3_CMD)) = blitcmd;
-}
-
-
-/**************************************************************
- * Move cursor to x, y
- */
-void Cyber_MoveCursor (u_short x, u_short y)
-{
-*(CyberRegs + S3_CRTC_ADR)  = 0x39;
-*(CyberRegs + S3_CRTC_DATA) = 0xa0;
-
-*(CyberRegs + S3_CRTC_ADR)  = S3_HWGC_ORGX_H;
-*(CyberRegs + S3_CRTC_DATA) = (char)((x & 0x0700) >> 8);
-*(CyberRegs + S3_CRTC_ADR)  = S3_HWGC_ORGX_L;
-*(CyberRegs + S3_CRTC_DATA) = (char)(x & 0x00ff);
-
-*(CyberRegs + S3_CRTC_ADR)  = S3_HWGC_ORGY_H;
-*(CyberRegs + S3_CRTC_DATA) = (char)((y & 0x0700) >> 8);
-*(CyberRegs + S3_CRTC_ADR)  = S3_HWGC_ORGY_L;
-*(CyberRegs + S3_CRTC_DATA) = (char)(y & 0x00ff);
-}
-
-
-/* -------------------- Interfaces to hardware functions -------------------- */
-
-
-static struct fb_hwswitch Cyber_switch = {
-   Cyber_init, Cyber_encode_fix, Cyber_decode_var, Cyber_encode_var,
-   Cyber_getcolreg, Cyber_setcolreg, Cyber_blank
-};
-
-
-/* -------------------- Generic routines ------------------------------------ */
-
-
-   /*
-    *    Fill the hardware's `par' structure.
-    */
-
-static void Cyber_fb_get_par(struct Cyber_fb_par *par)
-{
-   if (current_par_valid)
-      *par = current_par;
-   else
-      fbhw->decode_var(&Cyber_fb_predefined[Cyberfb_mode], par);
-}
-
-
-static void Cyber_fb_set_par(struct Cyber_fb_par *par)
-{
-   current_par = *par;
-   current_par_valid = 1;
-}
-
-
-static int do_fb_set_var(struct fb_var_screeninfo *var, int isactive)
-{
-   int err, activate;
-   struct Cyber_fb_par par;
-
-   if ((err = fbhw->decode_var(var, &par)))
-      return(err);
-   activate = var->activate;
-   if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW && isactive)
-      Cyber_fb_set_par(&par);
-   fbhw->encode_var(var, &par);
-   var->activate = activate;
-   return(0);
-}
-
-
-   /*
-    *    Default Colormaps
-    */
-
-static u_short red16[] =
-   { 0xc000, 0x0000, 0x0000, 0x0000, 0xc000, 0xc000, 0xc000, 0x0000,
-     0x8000, 0x0000, 0x0000, 0x0000, 0xffff, 0xffff, 0xffff, 0xffff};
-static u_short green16[] =
-   { 0xc000, 0x0000, 0xc000, 0xc000, 0x0000, 0x0000, 0xc000, 0x0000,
-     0x8000, 0x0000, 0xffff, 0xffff, 0x0000, 0x0000, 0xffff, 0xffff};
-static u_short blue16[] =
-   { 0xc000, 0x0000, 0x0000, 0xc000, 0x0000, 0xc000, 0x0000, 0x0000,
-     0x8000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff};
-
-
-static struct fb_cmap default_16_colors =
-   { 0, 16, red16, green16, blue16, NULL };
-
-
-static struct fb_cmap *get_default_colormap(int bpp)
-{
-   return(&default_16_colors);
-}
-
-
-#define CNVT_TOHW(val,width)     ((((val)<<(width))+0x7fff-(val))>>16)
-#define CNVT_FROMHW(val,width)   (((width) ? ((((val)<<16)-(val)) / \
-                                              ((1<<(width))-1)) : 0))
-
-static int do_fb_get_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var,
-                          int kspc)
-{
-   int i, start;
-   u_short *red, *green, *blue, *transp;
-   u_int hred, hgreen, hblue, htransp;
-
-   red = cmap->red;
-   green = cmap->green;
-   blue = cmap->blue;
-   transp = cmap->transp;
-   start = cmap->start;
-   if (start < 0)
-      return(-EINVAL);
-   for (i = 0; i < cmap->len; i++) {
-      if (fbhw->getcolreg(start++, &hred, &hgreen, &hblue, &htransp))
-         return(0);
-      hred = CNVT_FROMHW(hred, var->red.length);
-      hgreen = CNVT_FROMHW(hgreen, var->green.length);
-      hblue = CNVT_FROMHW(hblue, var->blue.length);
-      htransp = CNVT_FROMHW(htransp, var->transp.length);
-      if (kspc) {
-         *red = hred;
-         *green = hgreen;
-         *blue = hblue;
-         if (transp)
-            *transp = htransp;
-      } else {
-         put_user(hred, red);
-         put_user(hgreen, green);
-         put_user(hblue, blue);
-         if (transp)
-            put_user(htransp, transp);
-      }
-      red++;
-      green++;
-      blue++;
-      if (transp)
-         transp++;
-   }
-   return(0);
-}
-
-
-static int do_fb_set_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var,
-                          int kspc)
-{
-   int i, start;
-   u_short *red, *green, *blue, *transp;
-   u_int hred, hgreen, hblue, htransp;
-
-   red = cmap->red;
-   green = cmap->green;
-   blue = cmap->blue;
-   transp = cmap->transp;
-   start = cmap->start;
-
-   if (start < 0)
-      return(-EINVAL);
-   for (i = 0; i < cmap->len; i++) {
-      if (kspc) {
-         hred = *red;
-         hgreen = *green;
-         hblue = *blue;
-         htransp = transp ? *transp : 0;
-      } else {
-         get_user(hred, red);
-         get_user(hgreen, green);
-         get_user(hblue, blue);
-	 if (transp)
-		 get_user(htransp, transp);
-	 else
-		 htransp = 0;
-      }
-      hred = CNVT_TOHW(hred, var->red.length);
-      hgreen = CNVT_TOHW(hgreen, var->green.length);
-      hblue = CNVT_TOHW(hblue, var->blue.length);
-      htransp = CNVT_TOHW(htransp, var->transp.length);
-      red++;
-      green++;
-      blue++;
-      if (transp)
-         transp++;
-      if (fbhw->setcolreg(start++, hred, hgreen, hblue, htransp))
-         return(0);
-   }
-   return(0);
-}
-
-
-static void do_install_cmap(int con)
-{
-   if (con != currcon)
-      return;
-   if (disp[con].cmap.len)
-      do_fb_set_cmap(&disp[con].cmap, &disp[con].var, 1);
-   else
-      do_fb_set_cmap(get_default_colormap(disp[con].var.bits_per_pixel),
-                                          &disp[con].var, 1);
-}
-
-
-static void memcpy_fs(int fsfromto, void *to, void *from, int len)
-{
-   switch (fsfromto) {
-      case 0:
-         memcpy(to, from, len);
-         return;
-      case 1:
-         copy_from_user(to, from, len);
-         return;
-      case 2:
-         copy_to_user(to, from, len);
-         return;
-   }
-}
-
-
-static void copy_cmap(struct fb_cmap *from, struct fb_cmap *to, int fsfromto)
-{
-   int size;
-   int tooff = 0, fromoff = 0;
-
-   if (to->start > from->start)
-      fromoff = to->start-from->start;
-   else
-      tooff = from->start-to->start;
-   size = to->len-tooff;
-   if (size > from->len-fromoff)
-      size = from->len-fromoff;
-   if (size < 0)
-      return;
-   size *= sizeof(u_short);
-   memcpy_fs(fsfromto, to->red+tooff, from->red+fromoff, size);
-   memcpy_fs(fsfromto, to->green+tooff, from->green+fromoff, size);
-   memcpy_fs(fsfromto, to->blue+tooff, from->blue+fromoff, size);
-   if (from->transp && to->transp)
-      memcpy_fs(fsfromto, to->transp+tooff, from->transp+fromoff, size);
-}
-
-
-static int alloc_cmap(struct fb_cmap *cmap, int len, int transp)
-{
-   int size = len*sizeof(u_short);
-
-   if (cmap->len != len) {
-      if (cmap->red)
-         kfree(cmap->red);
-      if (cmap->green)
-         kfree(cmap->green);
-      if (cmap->blue)
-         kfree(cmap->blue);
-      if (cmap->transp)
-         kfree(cmap->transp);
-      cmap->red = cmap->green = cmap->blue = cmap->transp = NULL;
-      cmap->len = 0;
-      if (!len)
-         return(0);
-      if (!(cmap->red = kmalloc(size, GFP_ATOMIC)))
-         return(-1);
-      if (!(cmap->green = kmalloc(size, GFP_ATOMIC)))
-         return(-1);
-      if (!(cmap->blue = kmalloc(size, GFP_ATOMIC)))
-         return(-1);
-      if (transp) {
-         if (!(cmap->transp = kmalloc(size, GFP_ATOMIC)))
-            return(-1);
-      } else
-         cmap->transp = NULL;
-   }
-   cmap->start = 0;
-   cmap->len = len;
-   copy_cmap(get_default_colormap(len), cmap, 0);
-   return(0);
-}
-
-
-   /*
-    *    Get the Fixed Part of the Display
-    */
-
-static int Cyber_fb_get_fix(struct fb_fix_screeninfo *fix, int con)
-{
-   struct Cyber_fb_par par;
-   int error = 0;
-
-   if (con == -1)
-      Cyber_fb_get_par(&par);
-   else
-      error = fbhw->decode_var(&disp[con].var, &par);
-   return(error ? error : fbhw->encode_fix(fix, &par));
-}
-
-
-   /*
-    *    Get the User Defined Part of the Display
-    */
-
-static int Cyber_fb_get_var(struct fb_var_screeninfo *var, int con)
-{
-   struct Cyber_fb_par par;
-   int error = 0;
-
-   if (con == -1) {
-      Cyber_fb_get_par(&par);
-      error = fbhw->encode_var(var, &par);
-   } else
-      *var = disp[con].var;
-   return(error);
-}
-
-
-static void Cyber_fb_set_disp(int con)
-{
-   struct fb_fix_screeninfo fix;
-
-   Cyber_fb_get_fix(&fix, con);
-   if (con == -1)
-      con = 0;
-   disp[con].screen_base = (u_char *)fix.smem_start;
-   disp[con].visual = fix.visual;
-   disp[con].type = fix.type;
-   disp[con].type_aux = fix.type_aux;
-   disp[con].ypanstep = fix.ypanstep;
-   disp[con].ywrapstep = fix.ywrapstep;
-   disp[con].can_soft_blank = 1;
-   disp[con].inverse = Cyberfb_inverse;
-}
-
-
-   /*
-    *    Set the User Defined Part of the Display
-    */
-
-static int Cyber_fb_set_var(struct fb_var_screeninfo *var, int con)
-{
-   int err, oldxres, oldyres, oldvxres, oldvyres, oldbpp;
-
-   if ((err = do_fb_set_var(var, con == currcon)))
-      return(err);
-   if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
-      oldxres = disp[con].var.xres;
-      oldyres = disp[con].var.yres;
-      oldvxres = disp[con].var.xres_virtual;
-      oldvyres = disp[con].var.yres_virtual;
-      oldbpp = disp[con].var.bits_per_pixel;
-      disp[con].var = *var;
-      if (oldxres != var->xres || oldyres != var->yres ||
-          oldvxres != var->xres_virtual || oldvyres != var->yres_virtual ||
-          oldbpp != var->bits_per_pixel) {
-         Cyber_fb_set_disp(con);
-         (*fb_info.changevar)(con);
-         alloc_cmap(&disp[con].cmap, 0, 0);
-         do_install_cmap(con);
-      }
-   }
-   var->activate = 0;
-   return(0);
-}
-
-
-   /*
-    *    Get the Colormap
-    */
-
-static int Cyber_fb_get_cmap(struct fb_cmap *cmap, int kspc, int con)
-{
-   if (con == currcon) /* current console? */
-      return(do_fb_get_cmap(cmap, &disp[con].var, kspc));
-   else if (disp[con].cmap.len) /* non default colormap? */
-      copy_cmap(&disp[con].cmap, cmap, kspc ? 0 : 2);
-   else
-      copy_cmap(get_default_colormap(disp[con].var.bits_per_pixel), cmap,
-                kspc ? 0 : 2);
-   return(0);
-}
-
-
-   /*
-    *    Set the Colormap
-    */
-
-static int Cyber_fb_set_cmap(struct fb_cmap *cmap, int kspc, int con)
-{
-   int err;
-
-   if (!disp[con].cmap.len) {       /* no colormap allocated? */
-      if ((err = alloc_cmap(&disp[con].cmap, 1<<disp[con].var.bits_per_pixel,
-                            0)))
-         return(err);
-   }
-   if (con == currcon)              /* current console? */
-      return(do_fb_set_cmap(cmap, &disp[con].var, kspc));
-   else
-      copy_cmap(cmap, &disp[con].cmap, kspc ? 0 : 1);
-   return(0);
-}
-
-
-   /*
-    *    Pan or Wrap the Display
-    *
-    *    This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
-    */
-
-static int Cyber_fb_pan_display(struct fb_var_screeninfo *var, int con)
-{
-   return(-EINVAL);
-}
-
-
-   /*
-    *    Cybervision Frame Buffer Specific ioctls
-    */
-
-static int Cyber_fb_ioctl(struct inode *inode, struct file *file,
-                          u_int cmd, u_long arg, int con)
-{
-   return(-EINVAL);
-}
-
-
-static struct fb_ops Cyber_fb_ops = {
-   Cyber_fb_get_fix, Cyber_fb_get_var, Cyber_fb_set_var, Cyber_fb_get_cmap,
-   Cyber_fb_set_cmap, Cyber_fb_pan_display, Cyber_fb_ioctl
-};
-
-
-int Cyber_probe(void)
-{
-   CyberKey = zorro_find(MANUF_PHASE5, PROD_CYBERVISION, 0, 0);
-   return(CyberKey);
-}
-
-
-void Cyber_video_setup(char *options, int *ints)
-{
-   char *this_opt;
-   int i;
-
-   fb_info.fontname[0] = '\0';
-
-   if (!options || !*options)
-      return;
-
-   for (this_opt = strtok(options, ","); this_opt; this_opt = strtok(NULL, ","))
-      if (!strcmp(this_opt, "inverse")) {
-         Cyberfb_inverse = 1;
-         for (i = 0; i < 16; i++) {
-            red16[i] = ~red16[i];
-            green16[i] = ~green16[i];
-            blue16[i] = ~blue16[i];
-         }
-      } else if (!strncmp(this_opt, "font:", 5))
-         strcpy(fb_info.fontname, this_opt+5);
-      else if (!strcmp (this_opt, "cyber8"))
-         Cyberfb_Cyber8 = 1;
-      else if (!strcmp (this_opt, "cyber16"))
-         Cyberfb_Cyber16 = 1;
-      else
-         Cyberfb_mode = get_video_mode(this_opt);
-}
-
-
-   /*
-    *    Initialization
-    */
-
-__initfunc(struct fb_info *Cyber_fb_init(long *mem_start))
-{
-   int err;
-   struct Cyber_fb_par par;
-
-   memstart = mem_start;
-
-   fbhw = &Cyber_switch;
-
-   err = register_framebuffer(Cyber_fb_name, &node, &Cyber_fb_ops,
-                              NUM_TOTAL_MODES, Cyber_fb_predefined);
-   if (err < 0)
-      panic("Cannot register frame buffer\n");
-
-   fbhw->init();
-   fbhw->decode_var(&Cyber_fb_predefined[Cyberfb_mode], &par);
-   fbhw->encode_var(&Cyber_fb_predefined[0], &par);
-
-   strcpy(fb_info.modename, Cyber_fb_name);
-   fb_info.disp = disp;
-   fb_info.switch_con = &Cyberfb_switch;
-   fb_info.updatevar = &Cyberfb_updatevar;
-   fb_info.blank = &Cyberfb_blank;
-   fb_info.setcmap = &Cyberfb_setcmap;
-
-   do_fb_set_var(&Cyber_fb_predefined[0], 1);
-   Cyber_fb_get_var(&disp[0].var, -1);
-   Cyber_fb_set_disp(-1);
-   do_install_cmap(0);
-   return(&fb_info);
-}
-
-
-static int Cyberfb_switch(int con)
-{
-   /* Do we have to save the colormap? */
-   if (disp[currcon].cmap.len)
-      do_fb_get_cmap(&disp[currcon].cmap, &disp[currcon].var, 1);
-
-   do_fb_set_var(&disp[con].var, 1);
-   currcon = con;
-   /* Install new colormap */
-   do_install_cmap(con);
-   return(0);
-}
-
-
-   /*
-    *    Update the `var' structure (called by fbcon.c)
-    *
-    *    This call looks only at yoffset and the FB_VMODE_YWRAP flag in `var'.
-    *    Since it's called by a kernel driver, no range checking is done.
-    */
-
-static int Cyberfb_updatevar(int con)
-{
-   return(0);
-}
-
-
-   /*
-    *    Blank the display.
-    */
-
-static void Cyberfb_blank(int blank)
-{
-   fbhw->blank(blank);
-}
-
-
-   /*
-    *    Set the colormap
-    */
-
-static int Cyberfb_setcmap(struct fb_cmap *cmap, int con)
-{
-   return(Cyber_fb_set_cmap(cmap, 1, con));
-}
-
-
-   /*
-    *    Get a Video Mode
-    */
-
-static int get_video_mode(const char *name)
-{
-   int i;
-
-   for (i = 1; i < NUM_PREDEF_MODES; i++)
-      if (!strcmp(name, Cyber_fb_modenames[i]))
-         return(i);
-   return(0);
-}
diff -u --recursive --new-file v2.1.72/linux/arch/m68k/amiga/retz3fb.c linux/arch/m68k/amiga/retz3fb.c
--- v2.1.72/linux/arch/m68k/amiga/retz3fb.c	Sat May 24 09:10:22 1997
+++ linux/arch/m68k/amiga/retz3fb.c	Wed Dec 31 16:00:00 1969
@@ -1,1754 +0,0 @@
-/*
- * Linux/arch/m68k/amiga/retz3fb.c -- Low level implementation of the
- *                                    RetinaZ3 frame buffer device
- *
- *    Copyright (C) 1997 Jes Sorensen
- *
- * This file is based on the CyberVision64 frame buffer device and
- * the generic Cirrus Logic driver.
- *
- * cyberfb.c: Copyright (C) 1996 Martin Apel,
- *                               Geert Uytterhoeven
- * clgen.c:   Copyright (C) 1996 Frank Neumann
- *
- * History:
- *   - 22 Jan 97: Initial work
- *   - 14 Feb 97: Screen initialization works somewhat, still only
- *                8-bit packed pixel is supported.
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file COPYING in the main directory of this archive
- * for more details.
- */
-
-
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/tty.h>
-#include <linux/malloc.h>
-#include <linux/delay.h>
-#include <linux/fb.h>
-#include <linux/zorro.h>
-#include <linux/init.h>
-
-#include <asm/uaccess.h>
-#include <asm/system.h>
-#include <asm/irq.h>
-#include <asm/pgtable.h>
-
-#include "retz3fb.h"
-
-/* #define DEBUG if(1) */
-#define DEBUG if(0)
-
-/*
- * Reserve space for one pattern line.
- *
- * For the time being we only support 4MB boards!
- */
-
-#define PAT_MEM_SIZE 16*3
-#define PAT_MEM_OFF  (4*1024*1024 - PAT_MEM_SIZE)
-
-#define arraysize(x)    (sizeof(x)/sizeof(*(x)))
-
-struct retz3_fb_par {
-	int xres;
-	int yres;
-	int xres_vir;
-	int yres_vir;
-	int xoffset;
-	int yoffset;
-	int bpp;
-
-	struct fb_bitfield red;
-	struct fb_bitfield green;
-	struct fb_bitfield blue;
-	struct fb_bitfield transp;
-
-	int pixclock;
-	int left_margin;	/* time from sync to picture	*/
-	int right_margin;	/* time from picture to sync	*/
-	int upper_margin;	/* time from sync to picture	*/
-	int lower_margin;
-	int hsync_len;	/* length of horizontal sync	*/
-	int vsync_len;	/* length of vertical sync	*/
-	int vmode;
-};
-
-struct display_data {
-	long h_total;		/* Horizontal Total */
-	long h_sstart;		/* Horizontal Sync Start */
-	long h_sstop;		/* Horizontal Sync Stop */
-	long h_bstart;		/* Horizontal Blank Start */
-	long h_bstop;		/* Horizontal Blank Stop */
-	long h_dispend;		/* Horizontal Display End */
-	long v_total;		/* Vertical Total */
-	long v_sstart;		/* Vertical Sync Start */
-	long v_sstop;		/* Vertical Sync Stop */
-	long v_bstart;		/* Vertical Blank Start */
-	long v_bstop;		/* Vertical Blank Stop */
-	long v_dispend;		/* Horizontal Display End */
-};
-
-static struct retz3_fb_par current_par;
-
-static int current_par_valid = 0;
-static int currcon = 0;
-
-static struct display disp[MAX_NR_CONSOLES];
-static struct fb_info fb_info;
-
-static int node;        /* node of the /dev/fb?current file */
-
-
-/*
- *    Switch for Chipset Independency
- */
-
-static struct fb_hwswitch {
-
-   /* Initialisation */
-
-   int (*init)(void);
-
-   /* Display Control */
-
-   int (*encode_fix)(struct fb_fix_screeninfo *fix, struct retz3_fb_par *par);
-   int (*decode_var)(struct fb_var_screeninfo *var, struct retz3_fb_par *par);
-   int (*encode_var)(struct fb_var_screeninfo *var, struct retz3_fb_par *par);
-   int (*getcolreg)(unsigned int regno, unsigned int *red, unsigned
-		    int *green, unsigned int *blue, unsigned int *transp);
-   int (*setcolreg)(unsigned int regno, unsigned int red, unsigned int
-		    green, unsigned int blue, unsigned int transp);
-   void (*blank)(int blank);
-} *fbhw;
-
-
-/*
- *    Frame Buffer Name
- */
-
-static char retz3_fb_name[16] = "RetinaZ3";
-
-
-static int z3_key = 0;
-static unsigned char retz3_color_table [256][4];
-static unsigned long z3_mem;
-static unsigned long z3_fbmem;
-static unsigned long z3_size;
-static volatile unsigned char *z3_regs;
-
-static long *memstart;
-
-
-/*
- *    Predefined Video Mode Names
- */
-
-static char *retz3_fb_modenames[] = {
-
-	/*
-	 *    Autodetect (Default) Video Mode
-	 */
-
-	"default",
-
-	/*
-	 *    Predefined Video Modes
-	 */
-
-	"640x480",		/* RetinaZ3 8 bpp */
-	"800x600",		/* RetinaZ3 8 bpp */
-	"1024x768i",
-	"640x480-16",		/* RetinaZ3 16 bpp */
-	"640x480-24",		/* RetinaZ3 24 bpp */
-	
-	/*
-	 *    Dummy Video Modes
-	 */
-
-	"dummy", "dummy", "dummy", "dummy", "dummy", "dummy", "dummy",
-	"dummy", "dummy", "dummy", "dummy", "dummy", "dummy", "dummy",
-	"dummy", "dummy", "dummy", "dummy", "dummy", "dummy",
-
-	/*
-	 *    User Defined Video Modes
-	 *
-	 *    This doesn't work yet!!
-	 */
-
-	"user0", "user1", "user2", "user3",
-	"user4", "user5", "user6", "user7"
-};
-
-/*
- * A small info on how to convert XFree86 timing values into fb
- * timings - by Frank Neumann:
- *
-An XFree86 mode line consists of the following fields:
- "800x600"     50      800  856  976 1040    600  637  643  666
- < name >     DCF       HR  SH1  SH2  HFL     VR  SV1  SV2  VFL
-
-The fields in the fb_var_screeninfo structure are:
-        unsigned long pixclock;         * pixel clock in ps (pico seconds) *
-        unsigned long left_margin;      * time from sync to picture    *
-        unsigned long right_margin;     * time from picture to sync    *
-        unsigned long upper_margin;     * time from sync to picture    *
-        unsigned long lower_margin;
-        unsigned long hsync_len;        * length of horizontal sync    *
-        unsigned long vsync_len;        * length of vertical sync      *
-
-1) Pixelclock:
-   xfree: in MHz
-   fb: In Picoseconds (ps)
-
-   pixclock = 1000000 / DCF
-
-2) horizontal timings:
-   left_margin = HFL - SH2
-   right_margin = SH1 - HR
-   hsync_len = SH2 - SH1
-
-3) vertical timings:
-   upper_margin = VFL - SV2
-   lower_margin = SV1 - VR
-   vsync_len = SV2 - SV1
-
-Good examples for VESA timings can be found in the XFree86 source tree,
-under "programs/Xserver/hw/xfree86/doc/modeDB.txt".
-*/
-
-/*
- *    Predefined Video Mode Definitions
- */
-
-static struct fb_var_screeninfo retz3_fb_predefined[] = {
-
-   /*
-    *    Autodetect (Default) Video Mode
-    */
-
-   { 0, },
-
-   /*
-    *    Predefined Video Modes
-    */
-
-   /*
-    * NB: it is very important to adjust the pixel-clock to the color-depth.
-    */
-
-   {
-	   640, 480, 640, 480, 0, 0, 8, 0,
-	   {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
-	   0, 0, -1, -1, FB_ACCEL_RETINAZ3, 38461, 28, 32, 12, 10, 96, 2,
-	   FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
-   },
-   /*
-    ModeLine "800x600" 36 800 824 896 1024 600 601 603 625
-             < name > DCF HR  SH1 SH2  HFL VR  SV1 SV2 VFL
-    */
-   {
-	   /* 800 x 600, 8 bpp */
-	   800, 600, 800, 600, 0, 0, 8, 0,
-	   {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
-	   0, 0, -1, -1, FB_ACCEL_RETINAZ3, 27778, 64, 24, 22, 1, 120, 2,
-	   FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
-   },
-   /*
-    ModeLine "1024x768i" 45 1024 1064 1224 1264 768 777 785 817 interlace
-              < name >   DCF HR  SH1  SH2  HFL  VR  SV1 SV2 VFL
-    */
-   {
-	   /* 1024 x 768, 8 bpp, interlaced */
-	   1024, 768, 1024, 768, 0, 0, 8, 0,
-	   {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
-	   0, 0, -1, -1, FB_ACCEL_RETINAZ3, 22222, 40, 40, 32, 9, 160, 8,
-	   FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_INTERLACED
-   },
-   {
-	   640, 480, 640, 480, 0, 0, 16, 0,
-	   {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0},
-	   0, 0, -1, -1, FB_ACCEL_RETINAZ3, 38461/2, 28, 32, 12, 10, 96, 2,
-	   FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
-   },
-   {
-	   640, 480, 640, 480, 0, 0, 24, 0,
-	   {8, 8, 8}, {8, 8, 8}, {8, 8, 8}, {0, 0, 0}, 
-	   0, 0, -1, -1, FB_ACCEL_RETINAZ3, 38461/3, 28, 32, 12, 10, 96, 2,
-	   FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
-   },
-
-   /*
-    *    Dummy Video Modes
-    */
-
-   { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, },
-   { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, },
-   { 0, }, { 0, },
-
-   /*
-    *    User Defined Video Modes
-    */
-
-   { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }
-};
-
-
-#define NUM_TOTAL_MODES    arraysize(retz3_fb_predefined)
-#define NUM_PREDEF_MODES   (5)
-
-
-static int z3fb_inverse = 0;
-static int z3fb_mode = 0;
-
-
-/*
- *    Interface used by the world
- */
-
-int retz3_probe(void);
-void retz3_video_setup(char *options, int *ints);
-
-static int retz3_fb_get_fix(struct fb_fix_screeninfo *fix, int con);
-static int retz3_fb_get_var(struct fb_var_screeninfo *var, int con);
-static int retz3_fb_set_var(struct fb_var_screeninfo *var, int con);
-static int retz3_fb_get_cmap(struct fb_cmap *cmap, int kspc, int con);
-static int retz3_fb_set_cmap(struct fb_cmap *cmap, int kspc, int con);
-static int retz3_fb_pan_display(struct fb_var_screeninfo *var, int con);
-static int retz3_fb_ioctl(struct inode *inode, struct file *file,
-			  unsigned int cmd, unsigned long arg, int con);
-
-
-/*
- *    Interface to the low level console driver
- */
-
-struct fb_info *retz3_fb_init(long *mem_start); /* Through amiga_fb_init() */
-static int z3fb_switch(int con);
-static int z3fb_updatevar(int con);
-static void z3fb_blank(int blank);
-static int z3fb_setcmap(struct fb_cmap *cmap, int con);
-
-
-/*
- *    Accelerated Functions used by the low level console driver
- */
-
-void retz3_bitblt(struct fb_var_screeninfo *scr,
-		  unsigned short curx, unsigned short cury, unsigned
-		  short destx, unsigned short desty, unsigned short
-		  width, unsigned short height, unsigned short cmd,
-		  unsigned short mask);
-void retz3_fill(unsigned short x, unsigned short y, unsigned short
-		width, unsigned short height, unsigned short mode,
-		unsigned short color);
-
-/*
- *   Hardware Specific Routines
- */
-
-static int retz3_init(void);
-static int retz3_encode_fix(struct fb_fix_screeninfo *fix,
-                          struct retz3_fb_par *par);
-static int retz3_decode_var(struct fb_var_screeninfo *var,
-                          struct retz3_fb_par *par);
-static int retz3_encode_var(struct fb_var_screeninfo *var,
-                          struct retz3_fb_par *par);
-static int retz3_getcolreg(unsigned int regno, unsigned int *red,
-			   unsigned int *green, unsigned int *blue,
-			   unsigned int *transp);
-static int retz3_setcolreg(unsigned int regno, unsigned int red,
-			   unsigned int green, unsigned int blue,
-			   unsigned int transp);
-static void retz3_blank(int blank);
-
-
-/*
- *    Internal routines
- */
-
-static void retz3_fb_get_par(struct retz3_fb_par *par);
-static void retz3_fb_set_par(struct retz3_fb_par *par);
-static int do_fb_set_var(struct fb_var_screeninfo *var, int isactive);
-static struct fb_cmap *get_default_colormap(int bpp);
-static int do_fb_get_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var,
-                          int kspc);
-static int do_fb_set_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var,
-                          int kspc);
-static void do_install_cmap(int con);
-static void memcpy_fs(int fsfromto, void *to, void *from, int len);
-static void copy_cmap(struct fb_cmap *from, struct fb_cmap *to, int fsfromto);
-static int alloc_cmap(struct fb_cmap *cmap, int len, int transp);
-static void retz3_fb_set_disp(int con);
-static int get_video_mode(const char *name);
-
-
-/* -------------------- Hardware specific routines -------------------------- */
-
-static unsigned short find_fq(unsigned int freq)
-{
-	unsigned long f;
-	long tmp;
-	long prev = 0x7fffffff;
-	long n2, n1 = 3;
-	unsigned long m;
-	unsigned short res = 0;
-
-	if (freq <= 31250000)
-		n2 = 3;
-	else if (freq <= 62500000)
-		n2 = 2;
-	else if (freq <= 125000000)
-		n2 = 1;
-	else if (freq <= 250000000)
-		n2 = 0;
-	else
-		return(0);
-
-
-	do {
-		f = freq >> (10 - n2);
-
-		m = (f * n1) / (14318180/1024);
-
-		if (m > 129)
-			break;
-
-		tmp =  (((m * 14318180) >> n2) / n1) - freq;
-		if (tmp < 0)
-			tmp = -tmp;
-
-		if (tmp < prev) {
-			prev = tmp;
-			res = (((n2 << 5) | (n1-2)) << 8) | (m-2);
-		}
-
-	} while ( (++n1) <= 21);
-
-	return res;
-}
-
-
-static int retz3_set_video(struct fb_var_screeninfo *var,
-			   struct retz3_fb_par *par)
-{
-	float freq_f;
-	long freq;
-
-	int xres, hfront, hsync, hback;
-	int yres, vfront, vsync, vback;
-	unsigned char tmp;
-	unsigned short best_freq;
-	struct display_data data;
-
-	short clocksel = 0; /* Apparantly this is always zero */
-
-	int bpp = var->bits_per_pixel;
-
-	/*
-	 * XXX
-	 */
-	if (bpp == 24)
-		return 0;
-
-	if ((bpp != 8) && (bpp != 16) && (bpp != 24))
-		return -EFAULT;
-
-	par->xoffset = 0;
-	par->yoffset = 0;
-
-	xres   = var->xres * bpp / 4;
-	hfront = var->right_margin * bpp / 4;
-	hsync  = var->hsync_len * bpp / 4;
-	hback  = var->left_margin * bpp / 4;
-
-	if (var->vmode & FB_VMODE_DOUBLE)
-	{
-		yres = var->yres * 2;
-		vfront = var->lower_margin * 2;
-		vsync  = var->vsync_len * 2;
-		vback  = var->upper_margin * 2;
-	}
-	else if (var->vmode & FB_VMODE_INTERLACED)
-	{
-		yres   = (var->yres + 1) / 2;
-		vfront = (var->lower_margin + 1) / 2;
-		vsync  = (var->vsync_len + 1) / 2;
-		vback  = (var->upper_margin + 1) / 2;
-	}
-	else
-	{
-		yres   = var->yres; /* -1 ? */
-		vfront = var->lower_margin;
-		vsync  = var->vsync_len;
-		vback  = var->upper_margin;
-	}
-
-	data.h_total	= (hback / 8) + (xres / 8) 
-			+ (hfront / 8) + (hsync / 8) - 1 /* + 1 */;
-	data.h_dispend	= ((xres + bpp - 1)/ 8) - 1;
-	data.h_bstart	= xres / 8 /* + 1 */;
-
-	data.h_bstop	= data.h_total+1 + 2 + 1;
-	data.h_sstart	= (xres / 8) + (hfront / 8) + 1;
-	data.h_sstop	= (xres / 8) + (hfront / 8) + (hsync / 8) + 1;
-
-	data.v_total	= yres + vfront + vsync + vback - 1;
-
-	data.v_dispend	= yres - 1;
-	data.v_bstart	= yres;
-
-	data.v_bstop	= data.v_total;
-	data.v_sstart	= yres + vfront - 1 - 2;
-	data.v_sstop	= yres + vfront + vsync - 1;
-
-#if 0 /* testing */
-
-	printk("HBS: %i\n", data.h_bstart);
-	printk("HSS: %i\n", data.h_sstart);
-	printk("HSE: %i\n", data.h_sstop);
-	printk("HBE: %i\n", data.h_bstop);
-	printk("HT: %i\n", data.h_total);
-
-	printk("hsync: %i\n", hsync);
-	printk("hfront: %i\n", hfront);
-	printk("hback: %i\n", hback);
-
-	printk("VBS: %i\n", data.v_bstart);
-	printk("VSS: %i\n", data.v_sstart);
-	printk("VSE: %i\n", data.v_sstop);
-	printk("VBE: %i\n", data.v_bstop);
-	printk("VT: %i\n", data.v_total);
-
-	printk("vsync: %i\n", vsync);
-	printk("vfront: %i\n", vfront);
-	printk("vback: %i\n", vback);
-#endif
-
-	if (data.v_total >= 1024)
-		printk("MAYDAY: v_total >= 1024; bailing out!\n");
-
-	reg_w(GREG_MISC_OUTPUT_W, 0xe3 | ((clocksel & 3) * 0x04));
-	reg_w(GREG_FEATURE_CONTROL_W, 0x00);
-
-	seq_w(SEQ_RESET, 0x00);
-	seq_w(SEQ_RESET, 0x03);	/* reset sequencer logic */
-
-	/*
-	 * CLOCKING_MODE bits:
-	 * 2: This one is only set for certain text-modes, wonder if
-	 *    it may be for EGA-lines? (it was referred to as CLKDIV2)
-	 * (The CL drivers sets it to 0x21 with the comment:
-	 *  FullBandwidth (video off) and 8/9 dot clock)
-	 */
-	seq_w(SEQ_CLOCKING_MODE, 0x01 | 0x00 /* 0x08 */);
-
-	seq_w(SEQ_MAP_MASK, 0x0f);        /* enable writing to plane 0-3 */
-	seq_w(SEQ_CHAR_MAP_SELECT, 0x00); /* doesn't matter in gfx-mode */
-	seq_w(SEQ_MEMORY_MODE, 0x06); /* CL driver says 0x0e for 256 col mode*/
-	seq_w(SEQ_RESET, 0x01);
-	seq_w(SEQ_RESET, 0x03);
-
-	seq_w(SEQ_EXTENDED_ENABLE, 0x05);
-
-	seq_w(SEQ_CURSOR_CONTROL, 0x00);	/* disable cursor */
-	seq_w(SEQ_PRIM_HOST_OFF_HI, 0x00);
-	seq_w(SEQ_PRIM_HOST_OFF_HI, 0x00);
-	seq_w(SEQ_LINEAR_0, 0x4a);
-	seq_w(SEQ_LINEAR_1, 0x00);
-
-	seq_w(SEQ_SEC_HOST_OFF_HI, 0x00);
-	seq_w(SEQ_SEC_HOST_OFF_LO, 0x00);
-	seq_w(SEQ_EXTENDED_MEM_ENA, 0x3 | 0x4 | 0x10 | 0x40);
-
-	/*
-	 * The lower 4 bits (0-3) are used to set the font-width for
-	 * text-mode - DON'T try to set this for gfx-mode.
-	 */
-	seq_w(SEQ_EXT_CLOCK_MODE, 0x10);
-	seq_w(SEQ_EXT_VIDEO_ADDR, 0x03);
-
-	/*
-	 * Extended Pixel Control:
-	 * bit 0:   text-mode=0, gfx-mode=1 (Graphics Byte ?)
-	 * bit 1: (Packed/Nibble Pixel Format ?)
-	 * bit 4-5: depth, 0=1-8bpp, 1=9-16bpp, 2=17-24bpp
-	 */
-	seq_w(SEQ_EXT_PIXEL_CNTL, 0x01 | (((bpp / 8) - 1) << 4));
-
-	seq_w(SEQ_BUS_WIDTH_FEEDB, 0x04);
-	seq_w(SEQ_COLOR_EXP_WFG, 0x01);
-	seq_w(SEQ_COLOR_EXP_WBG, 0x00);
-	seq_w(SEQ_EXT_RW_CONTROL, 0x00);
-	seq_w(SEQ_MISC_FEATURE_SEL, (0x51 | (clocksel & 8)));
-	seq_w(SEQ_COLOR_KEY_CNTL, 0x40);
-	seq_w(SEQ_COLOR_KEY_MATCH0, 0x00);
-	seq_w(SEQ_COLOR_KEY_MATCH1, 0x00);
-	seq_w(SEQ_COLOR_KEY_MATCH2, 0x00);
-	seq_w(SEQ_CRC_CONTROL, 0x00);
-	seq_w(SEQ_PERF_SELECT, 0x10);
-	seq_w(SEQ_ACM_APERTURE_1, 0x00);
-	seq_w(SEQ_ACM_APERTURE_2, 0x30);
-	seq_w(SEQ_ACM_APERTURE_3, 0x00);
-	seq_w(SEQ_MEMORY_MAP_CNTL, 0x03);
-
-
-	/* unlock register CRT0..CRT7 */
-	crt_w(CRT_END_VER_RETR, (data.v_sstop & 0x0f) | 0x20);
-
-	/* Zuerst zu schreibende Werte nur per printk ausgeben */
-	DEBUG printk("CRT_HOR_TOTAL: %ld\n", data.h_total);
-	crt_w(CRT_HOR_TOTAL, data.h_total & 0xff);
-
-	DEBUG printk("CRT_HOR_DISP_ENA_END: %ld\n", data.h_dispend);
-	crt_w(CRT_HOR_DISP_ENA_END, (data.h_dispend) & 0xff);
-
-	DEBUG printk("CRT_START_HOR_BLANK: %ld\n", data.h_bstart);
-	crt_w(CRT_START_HOR_BLANK, data.h_bstart & 0xff);
-
-	DEBUG printk("CRT_END_HOR_BLANK: 128+%ld\n", data.h_bstop % 32);
-	crt_w(CRT_END_HOR_BLANK,  0x80 | (data.h_bstop & 0x1f));
-
-	DEBUG printk("CRT_START_HOR_RETR: %ld\n", data.h_sstart);
-	crt_w(CRT_START_HOR_RETR, data.h_sstart & 0xff);
-
-	tmp = (data.h_sstop & 0x1f);
-	if (data.h_bstop & 0x20)
-		tmp |= 0x80;
-	DEBUG printk("CRT_END_HOR_RETR: %d\n", tmp);
-	crt_w(CRT_END_HOR_RETR, tmp);
-
-	DEBUG printk("CRT_VER_TOTAL: %ld\n", data.v_total & 0xff);
-	crt_w(CRT_VER_TOTAL, (data.v_total & 0xff));
-
-	tmp = 0x10;  /* LineCompare bit #9 */
-	if (data.v_total & 256)
-		tmp |= 0x01;
-	if (data.v_dispend & 256)
-		tmp |= 0x02;
-	if (data.v_sstart & 256)
-		tmp |= 0x04;
-	if (data.v_bstart & 256)
-		tmp |= 0x08;
-	if (data.v_total & 512)
-		tmp |= 0x20;
-	if (data.v_dispend & 512)
-		tmp |= 0x40;
-	if (data.v_sstart & 512)
-		tmp |= 0x80;
-	DEBUG printk("CRT_OVERFLOW: %d\n", tmp);
-	crt_w(CRT_OVERFLOW, tmp);
-
-	crt_w(CRT_PRESET_ROW_SCAN, 0x00); /* not CL !!! */
-
-	tmp = 0x40; /* LineCompare bit #8 */
-	if (data.v_bstart & 512)
-		tmp |= 0x20;
-	if (var->vmode & FB_VMODE_DOUBLE)
-		tmp |= 0x80;
- 	DEBUG printk("CRT_MAX_SCAN_LINE: %d\n", tmp);
-	crt_w(CRT_MAX_SCAN_LINE, tmp);
-
-	crt_w(CRT_CURSOR_START, 0x00);
-	crt_w(CRT_CURSOR_END, 8 & 0x1f); /* font height */
-
-	crt_w(CRT_START_ADDR_HIGH, 0x00);
-	crt_w(CRT_START_ADDR_LOW, 0x00);
-
-	crt_w(CRT_CURSOR_LOC_HIGH, 0x00);
-	crt_w(CRT_CURSOR_LOC_LOW, 0x00);
-
- 	DEBUG printk("CRT_START_VER_RETR: %ld\n", data.v_sstart & 0xff);
-	crt_w(CRT_START_VER_RETR, (data.v_sstart & 0xff));
-
-#if 1
-	/* 5 refresh cycles per scanline */
-	DEBUG printk("CRT_END_VER_RETR: 64+32+%ld\n", data.v_sstop % 16);
-	crt_w(CRT_END_VER_RETR, ((data.v_sstop & 0x0f) | 0x40 | 0x20));
-#else
-	DEBUG printk("CRT_END_VER_RETR: 128+32+%ld\n", data.v_sstop % 16);
-	crt_w(CRT_END_VER_RETR, ((data.v_sstop & 0x0f) | 128 | 32));
-#endif
-	DEBUG printk("CRT_VER_DISP_ENA_END: %ld\n", data.v_dispend & 0xff);
-	crt_w(CRT_VER_DISP_ENA_END, (data.v_dispend & 0xff));
-
-	DEBUG printk("CRT_START_VER_BLANK: %ld\n", data.v_bstart & 0xff);
-	crt_w(CRT_START_VER_BLANK, (data.v_bstart & 0xff));
-
-	DEBUG printk("CRT_END_VER_BLANK: %ld\n", data.v_bstop & 0xff);
-	crt_w(CRT_END_VER_BLANK, (data.v_bstop & 0xff));
-
-	DEBUG printk("CRT_MODE_CONTROL: 0xe3\n");
-	crt_w(CRT_MODE_CONTROL, 0xe3);
-
-	DEBUG printk("CRT_LINE_COMPARE: 0xff\n");
-	crt_w(CRT_LINE_COMPARE, 0xff);
-
-	tmp = (var->xres_virtual / 8) * (bpp / 8);
-	crt_w(CRT_OFFSET, tmp);
-
-	crt_w(CRT_UNDERLINE_LOC, 0x07); /* probably font-height - 1 */
-
-	tmp = 0x20;			/* Enable extended end bits */
-	if (data.h_total & 0x100)
-		tmp |= 0x01;
-	if ((data.h_dispend) & 0x100)
-		tmp |= 0x02;
-	if (data.h_bstart & 0x100)
-		tmp |= 0x04;
-	if (data.h_sstart & 0x100)
-		tmp |= 0x08;
-	if (var->vmode & FB_VMODE_INTERLACED)
-		tmp |= 0x10;
- 	DEBUG printk("CRT_EXT_HOR_TIMING1: %d\n", tmp);
-	crt_w(CRT_EXT_HOR_TIMING1, tmp);
-
-	tmp = 0x00;
-	if (((var->xres_virtual / 8) * (bpp / 8)) & 0x100)
-		tmp |= 0x10;
-	crt_w(CRT_EXT_START_ADDR, tmp);
-
-	tmp = 0x00;
-	if (data.h_total & 0x200)
-		tmp |= 0x01;
-	if ((data.h_dispend) & 0x200)
-		tmp |= 0x02;
-	if (data.h_bstart & 0x200)
-		tmp |= 0x04;
-	if (data.h_sstart & 0x200)
-		tmp |= 0x08;
-	tmp |= ((data.h_bstop & 0xc0) >> 2);
-	tmp |= ((data.h_sstop & 0x60) << 1);
-	crt_w(CRT_EXT_HOR_TIMING2, tmp);
- 	DEBUG printk("CRT_EXT_HOR_TIMING2: %d\n", tmp);
-
-	tmp = 0x10;			/* Line compare bit 10 */
-	if (data.v_total & 0x400)
-		tmp |= 0x01;
-	if ((data.v_dispend) & 0x400)
-		tmp |= 0x02;
-	if (data.v_bstart & 0x400)
-		tmp |= 0x04;
-	if (data.v_sstart & 0x400)
-		tmp |= 0x08;
-	tmp |= ((data.v_bstop & 0x300) >> 3);
-	if (data.v_sstop & 0x10)
-		tmp |= 0x80;
-	crt_w(CRT_EXT_VER_TIMING, tmp);
- 	DEBUG printk("CRT_EXT_VER_TIMING: %d\n", tmp);
-
-	crt_w(CRT_MONITOR_POWER, 0x00);
-
-	/*
-	 * Convert from ps to Hz.
-	 */
-	freq_f = (1.0/(float)var->pixclock) * 1000000000;
-	freq = ((long)freq_f) * 1000;
-
-	best_freq = find_fq(freq);
-	pll_w(0x02, best_freq);
-	best_freq = find_fq(61000000);
-	pll_w(0x0a, best_freq);
-	pll_w(0x0e, 0x22);
-
-	gfx_w(GFX_SET_RESET, 0x00);
-	gfx_w(GFX_ENABLE_SET_RESET, 0x00);
-	gfx_w(GFX_COLOR_COMPARE, 0x00);
-	gfx_w(GFX_DATA_ROTATE, 0x00);
-	gfx_w(GFX_READ_MAP_SELECT, 0x00);
-	gfx_w(GFX_GRAPHICS_MODE, 0x00);
-	gfx_w(GFX_MISC, 0x05);
-	gfx_w(GFX_COLOR_XCARE, 0x0f);
-	gfx_w(GFX_BITMASK, 0xff);
-
-	reg_r(ACT_ADDRESS_RESET);
-	attr_w(ACT_PALETTE0 , 0x00);
-	attr_w(ACT_PALETTE1 , 0x01);
-	attr_w(ACT_PALETTE2 , 0x02);
-	attr_w(ACT_PALETTE3 , 0x03);
-	attr_w(ACT_PALETTE4 , 0x04);
-	attr_w(ACT_PALETTE5 , 0x05);
-	attr_w(ACT_PALETTE6 , 0x06);
-	attr_w(ACT_PALETTE7 , 0x07);
-	attr_w(ACT_PALETTE8 , 0x08);
-	attr_w(ACT_PALETTE9 , 0x09);
-	attr_w(ACT_PALETTE10, 0x0a);
-	attr_w(ACT_PALETTE11, 0x0b);
-	attr_w(ACT_PALETTE12, 0x0c);
-	attr_w(ACT_PALETTE13, 0x0d);
-	attr_w(ACT_PALETTE14, 0x0e);
-	attr_w(ACT_PALETTE15, 0x0f);
-	reg_r(ACT_ADDRESS_RESET);
-
-	attr_w(ACT_ATTR_MODE_CNTL, 0x09); /* 0x01 for CL */
-
-	attr_w(ACT_OVERSCAN_COLOR, 0x00);
-	attr_w(ACT_COLOR_PLANE_ENA, 0x0f);
-	attr_w(ACT_HOR_PEL_PANNING, 0x00);
-	attr_w(ACT_COLOR_SELECT, 0x00);
-
-	reg_r(ACT_ADDRESS_RESET);
-	reg_w(ACT_DATA, 0x20);
-
-	reg_w(VDAC_MASK, 0xff);
-
-	/*
-	 * Extended palette adressing ???
-	 */
-	switch (bpp){
-	case 8:
-		reg_w(0x83c6, 0x00); 
-		break;
-	case 16:
-		reg_w(0x83c6, 0x60);
-		break;
-	case 24:
-		reg_w(0x83c6, 0xe0);
-		break;
-	default:
-		printk("Illegal color-depth: %i\n", bpp);
-	}
-
-	reg_w(VDAC_ADDRESS, 0x00);
-
-	seq_w(SEQ_MAP_MASK, 0x0f );  
-
-	return 0;
-}
-
-/*
- *    Initialization
- *
- *    Set the default video mode for this chipset. If a video mode was
- *    specified on the command line, it will override the default mode.
- */
-
-static int retz3_init(void)
-{
-	int i;
-#if 0
-	volatile unsigned long *CursorBase;
-#endif
-	unsigned long board_addr, board_size;
-	struct ConfigDev *cd;
-
-	cd = zorro_get_board (z3_key);
-	zorro_config_board (z3_key, 0);
-	board_addr = (unsigned long)cd->cd_BoardAddr;
-	board_size = (unsigned long)cd->cd_BoardSize;
-
-	for (i = 0; i < 256; i++){
-		for (i = 0; i < 256; i++){
-			retz3_color_table [i][0] = i;
-			retz3_color_table [i][1] = i;
-			retz3_color_table [i][2] = i;
-			retz3_color_table [i][3] = 0;
-		}
-	}
-
-	*memstart = (*memstart + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
-
-	z3_mem = kernel_map (board_addr, board_size,
-			     KERNELMAP_NOCACHE_SER, memstart);
-
-	z3_regs = (char*) z3_mem;
-	z3_fbmem = z3_mem + VIDEO_MEM_OFFSET;
-
-	/* Get memory size - for now we asume its a 4MB board */
-
-	z3_size = 0x00400000; /* 4 MB */
-
-	memset ((char*)z3_fbmem, 0, z3_size);
-
-	/* Disable hardware cursor */
-
-	seq_w(SEQ_CURSOR_Y_INDEX, 0x00);
-
-
-#if 0
-	/* Initialize hardware cursor */
-	CursorBase = (unsigned long *)((char *)(z3_mem) + z3_size - 0x400);
-	for (i=0; i < 8; i++){
-		*(CursorBase  +(i*4)) = 0xffffff00;
-		*(CursorBase+1+(i*4)) = 0xffff0000;
-		*(CursorBase+2+(i*4)) = 0xffff0000;
-		*(CursorBase+3+(i*4)) = 0xffff0000;
-	}
-	for (i=8; i < 64; i++){
-		*(CursorBase  +(i*4)) = 0xffff0000;
-		*(CursorBase+1+(i*4)) = 0xffff0000;
-		*(CursorBase+2+(i*4)) = 0xffff0000;
-		*(CursorBase+3+(i*4)) = 0xffff0000;
-	}
-#endif
-
-	retz3_setcolreg (255, 56, 100, 160, 0);
-	retz3_setcolreg (254, 0, 0, 0, 0);
-
-	return 0;
-}
-
-
-/*
- *    This function should fill in the `fix' structure based on the
- *    values in the `par' structure.
- */
-
-static int retz3_encode_fix(struct fb_fix_screeninfo *fix,
-                          struct retz3_fb_par *par)
-{
-	int i;
-
-	strcpy(fix->id, retz3_fb_name);
-	fix->smem_start = z3_fbmem;
-	fix->smem_len = z3_size;
-
-	fix->type = FB_TYPE_PACKED_PIXELS;
-	fix->type_aux = 0;
-	if (par->bpp == 8)
-		fix->visual = FB_VISUAL_PSEUDOCOLOR;
-	else
-		fix->visual = FB_VISUAL_DIRECTCOLOR;
-
-	fix->xpanstep = 0;
-	fix->ypanstep = 0;
-	fix->ywrapstep = 0;
-	fix->line_length = 0;
-
-	for (i = 0; i < arraysize(fix->reserved); i++)
-		fix->reserved[i] = 0;
-
-	return 0;
-}
-
-
-/*
- *    Get the video params out of `var'. If a value doesn't fit, round
- *    it up, if it's too big, return -EINVAL.
- */
-
-static int retz3_decode_var(struct fb_var_screeninfo *var,
-			    struct retz3_fb_par *par)
-{
-	par->xres = var->xres;
-	par->yres = var->yres;
-	par->xres_vir = var->xres_virtual;
-	par->yres_vir = var->yres_virtual;
-	par->bpp = var->bits_per_pixel;
-	par->pixclock = var->pixclock;
-	par->vmode = var->vmode;
-
-	par->red = var->red;
-	par->green = var->green;
-	par->blue = var->blue;
-	par->transp = var->transp;
-
-	par->left_margin = var->left_margin;
-	par->right_margin = var->right_margin;
-	par->upper_margin = var->upper_margin;
-	par->lower_margin = var->lower_margin;
-	par->hsync_len = var->hsync_len;
-	par->vsync_len = var->vsync_len;
-
-	return 0;
-}
-
-
-/*
- *    Fill the `var' structure based on the values in `par' and maybe
- *    other values read out of the hardware.
- */
-
-static int retz3_encode_var(struct fb_var_screeninfo *var,
-			    struct retz3_fb_par *par)
-{
-	int i;
-
-	var->xres = par->xres;
-	var->yres = par->yres;
-	var->xres_virtual = par->xres_vir;
-	var->yres_virtual = par->yres_vir;
-	var->xoffset = 0;
-	var->yoffset = 0;
-
-	var->bits_per_pixel = par->bpp;
-	var->grayscale = 0;
-
-	var->red = par->red;
-	var->green = par->green;
-	var->blue = par->blue;
-	var->transp = par->transp;
-
-	var->nonstd = 0;
-	var->activate = 0;
-
-	var->height = -1;
-	var->width = -1;
-
-	var->accel = FB_ACCEL_RETINAZ3;
-
-	var->pixclock = par->pixclock;
-
-	var->sync = 0;				/* ??? */
-	var->left_margin = par->left_margin;
-	var->right_margin = par->right_margin;
-	var->upper_margin = par->upper_margin;
-	var->lower_margin = par->lower_margin;
-	var->hsync_len = par->hsync_len;
-	var->vsync_len = par->vsync_len;
-
-	for (i = 0; i < arraysize(var->reserved); i++)
-		var->reserved[i] = 0;
-
-	var->vmode = par->vmode;
-	return 0;
-}
-
-
-/*
- *    Set a single color register. The values supplied are already
- *    rounded down to the hardware's capabilities (according to the
- *    entries in the var structure). Return != 0 for invalid regno.
- */
-
-static int retz3_setcolreg(unsigned int regno, unsigned int red,
-			   unsigned int green, unsigned int blue,
-			   unsigned int transp)
-{
-	/* We'll get to this */
-
-	if (regno > 255)
-		return 1;
-
-	retz3_color_table [regno][0] = red & 0xff;
-	retz3_color_table [regno][1] = green & 0xff;
-	retz3_color_table [regno][2] = blue & 0xff;
-	retz3_color_table [regno][3] = transp;
-
-	reg_w(VDAC_ADDRESS_W, regno);
-	reg_w(VDAC_DATA, (red & 0xff) >> 2);
-	reg_w(VDAC_DATA, (green & 0xff) >> 2);
-	reg_w(VDAC_DATA, (blue & 0xff) >> 2);
-
-	return 0;
-}
-
-
-/*
- *    Read a single color register and split it into
- *    colors/transparent. Return != 0 for invalid regno.
- */
-
-static int retz3_getcolreg(unsigned int regno, unsigned int *red,
-			   unsigned int *green, unsigned int *blue,
-			   unsigned int *transp)
-{
-	if (regno > 255)
-		return 1;
-	*red    = retz3_color_table [regno][0];
-	*green  = retz3_color_table [regno][1];
-	*blue   = retz3_color_table [regno][2];
-	*transp = retz3_color_table [regno][3];
-	return 0;
-}
-
-
-/*
- *    (Un)Blank the screen
- */
-
-void retz3_blank(int blank)
-{
-	int i;
-
-	if (blank)
-		for (i = 0; i < 256; i++){
-			reg_w(VDAC_ADDRESS_W, i);
-			reg_w(VDAC_DATA, 0);
-			reg_w(VDAC_DATA, 0);
-			reg_w(VDAC_DATA, 0);
-		}
-	else
-		for (i = 0; i < 256; i++){
-			reg_w(VDAC_ADDRESS_W, i);
-			reg_w(VDAC_DATA, retz3_color_table [i][0] >> 2);
-			reg_w(VDAC_DATA, retz3_color_table [i][1] >> 2);
-			reg_w(VDAC_DATA, retz3_color_table [i][2] >> 2);
-		}
-}
-
-
-void retz3_bitblt (struct fb_var_screeninfo *var,
-		   unsigned short srcx, unsigned short srcy, unsigned
-		   short destx, unsigned short desty, unsigned short
-		   width, unsigned short height, unsigned short cmd,
-		   unsigned short mask)
-{
-
-	volatile unsigned long *acm = (unsigned long *) (z3_mem + ACM_OFFSET);
-	unsigned long *pattern = (unsigned long *)(z3_fbmem + PAT_MEM_OFF);
-
-	unsigned short mod;
-	unsigned long tmp;
-	unsigned long pat, src, dst;
-	unsigned char blt_status;
-
-	int i, xres_virtual = var->xres_virtual;
-	short bpp = (var->bits_per_pixel & 0xff);
-
-	if (bpp < 8)
-		bpp = 8;
-
-	tmp = mask | (mask << 16);
-
-#if 0
-	/*
-	 * Check for blitter finished before we start messing with the
-	 * pattern.
-	 */
-	do{
-		blt_status = *(((volatile unsigned char *)acm) +
-			       (ACM_START_STATUS + 2));
-	}while ((blt_status & 1) == 0);
-#endif
-
-	i = 0;
-	do{
-		*pattern++ = tmp;
-	}while(i++ < bpp/4);
-
-	tmp = cmd << 8;
-	*(acm + ACM_RASTEROP_ROTATION/4) = tmp;
-
-	mod = 0xc0c2;
-
-	pat = 8 * PAT_MEM_OFF;
-	dst = bpp * (destx + desty * xres_virtual);
-
-	/*
-	 * Source is not set for clear.
-	 */
-	if ((cmd != Z3BLTclear) && (cmd != Z3BLTset)) {
-		src = bpp * (srcx + srcy * xres_virtual);
-
-		if (destx > srcx) {
-			mod &= ~0x8000;
-			src += bpp * (width - 1);
-			dst += bpp * (width - 1);
-			pat += bpp * 2;
-		}
-		if (desty > srcy) {
-			mod &= ~0x4000;
-			src += bpp * (height - 1) * xres_virtual;
-			dst += bpp * (height - 1) * xres_virtual;
-			pat += bpp * 4;
-		}
-
-		*(acm + ACM_SOURCE/4) = cpu_to_le32(src);
-	}
-
-	*(acm + ACM_PATTERN/4) = cpu_to_le32(pat);
-
-	*(acm + ACM_DESTINATION/4) = cpu_to_le32(dst);
-
-	tmp = mod << 16;
-	*(acm + ACM_CONTROL/4) = tmp;
-
-	tmp  = width | (height << 16);
-	
-	*(acm + ACM_BITMAP_DIMENSION/4) = cpu_to_le32(tmp);
-
-	*(((volatile unsigned char *)acm) + ACM_START_STATUS) = 0x00;
-	*(((volatile unsigned char *)acm) + ACM_START_STATUS) = 0x01;
-
-	/*
-	 * No reason to wait for the blitter to finish, it is better
-	 * just to check if it has finished before we use it again.
-	 */
-#if 1
-#if 0
-	while ((*(((volatile unsigned char *)acm) +
-		  (ACM_START_STATUS + 2)) & 1) == 0);
-#else
-	do{
-		blt_status = *(((volatile unsigned char *)acm) +
-			       (ACM_START_STATUS + 2));
-	}
-	while ((blt_status & 1) == 0);
-#endif
-#endif
-}
-
-#if 0
-void retz3_fill (unsigned short x, unsigned short y, unsigned
-		 short width, unsigned short height,
-		 unsigned short mode, unsigned short color)
-{
-
-}
-#endif
-
-
-/**************************************************************
- * Move cursor to x, y
- */
-void retz3_MoveCursor (unsigned short x, unsigned short y)
-{
-	/* Guess we gotta deal with the cursor at some point */
-}
-
-
-/* -------------------- Interfaces to hardware functions -------------------- */
-
-
-static struct fb_hwswitch retz3_switch = {
-	retz3_init, retz3_encode_fix, retz3_decode_var, retz3_encode_var,
-	retz3_getcolreg, retz3_setcolreg, retz3_blank
-};
-
-
-/* -------------------- Generic routines ------------------------------------ */
-
-
-/*
- *    Fill the hardware's `par' structure.
- */
-
-static void retz3_fb_get_par(struct retz3_fb_par *par)
-{
-	if (current_par_valid)
-		*par = current_par;
-	else
-		fbhw->decode_var(&retz3_fb_predefined[z3fb_mode], par);
-}
-
-
-static void retz3_fb_set_par(struct retz3_fb_par *par)
-{
-	current_par = *par;
-	current_par_valid = 1;
-}
-
-
-static int do_fb_set_var(struct fb_var_screeninfo *var, int isactive)
-{
-	int err, activate;
-	struct retz3_fb_par par;
-
-	if ((err = fbhw->decode_var(var, &par)))
-		return err;
-	activate = var->activate;
-	if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW && isactive)
-		retz3_fb_set_par(&par);
-	fbhw->encode_var(var, &par);
-	var->activate = activate;
-
-#if 1
-	retz3_set_video(var, &current_par);
-#endif
-	return 0;
-}
-
-
-/*
- *    Default Colormaps
- */
-
-static unsigned short red16[] =
-	{ 0x0000, 0x0000, 0x0000, 0x0000, 0xc000, 0xc000, 0xc000, 0xc000,
-	  0x8000, 0x0000, 0x0000, 0x0000, 0xffff, 0xffff, 0xffff, 0xffff };
-static unsigned short green16[] =
-	{ 0x0000, 0x0000, 0xc000, 0xc000, 0x0000, 0x0000, 0xc000, 0xc000,
-	  0x8000, 0x0000, 0xffff, 0xffff, 0x0000, 0x0000, 0xffff, 0xffff };
-static unsigned short blue16[] =
-	{ 0x0000, 0xc000, 0x0000, 0xc000, 0x0000, 0xc000, 0x0000, 0xc000,
-	  0x8000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff };
-
-
-static struct fb_cmap default_16_colors =
-   { 0, 16, red16, green16, blue16, NULL };
-
-
-static struct fb_cmap *get_default_colormap(int bpp)
-{
-	return &default_16_colors;
-}
-
-
-#define CNVT_TOHW(val,width)     ((((val)<<(width))+0x7fff-(val))>>16)
-#define CNVT_FROMHW(val,width)   (((width) ? ((((val)<<16)-(val)) / \
-                                              ((1<<(width))-1)) : 0))
-
-static int do_fb_get_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var,
-                          int kspc)
-{
-	int i, start;
-	unsigned short *red, *green, *blue, *transp;
-	unsigned int hred, hgreen, hblue, htransp;
-
-	red = cmap->red;
-	green = cmap->green;
-	blue = cmap->blue;
-	transp = cmap->transp;
-	start = cmap->start;
-
-	if (start < 0)
-		return -EINVAL;
-	for (i = 0; i < cmap->len; i++) {
-		if (fbhw->getcolreg(start++, &hred, &hgreen, &hblue, &htransp))
-			return 0;
-		hred = CNVT_FROMHW(hred, var->red.length);
-		hgreen = CNVT_FROMHW(hgreen, var->green.length);
-		hblue = CNVT_FROMHW(hblue, var->blue.length);
-		htransp = CNVT_FROMHW(htransp, var->transp.length);
-		if (kspc) {
-			*red = hred;
-			*green = hgreen;
-			*blue = hblue;
-			if (transp)
-				*transp = htransp;
-		} else {
-			put_user(hred, red);
-			put_user(hgreen, green);
-			put_user(hblue, blue);
-			if (transp)
-				put_user(htransp, transp);
-		}
-		red++;
-		green++;
-		blue++;
-		if (transp)
-			transp++;
-	}
-	return 0;
-}
-
-
-static int do_fb_set_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var,
-                          int kspc)
-{
-	int i, start;
-	unsigned short *red, *green, *blue, *transp;
-	unsigned int hred, hgreen, hblue, htransp;
-
-	red = cmap->red;
-	green = cmap->green;
-	blue = cmap->blue;
-	transp = cmap->transp;
-	start = cmap->start;
-
-	if (start < 0)
-		return -EINVAL;
-	for (i = 0; i < cmap->len; i++) {
-		if (kspc) {
-			hred = *red;
-			hgreen = *green;
-			hblue = *blue;
-			htransp = transp ? *transp : 0;
-		} else {
-			get_user(hred, red);
-			get_user(hgreen, green);
-			get_user(hblue, blue);
-			if (transp)
-				get_user(htransp, transp);
-			else
-				htransp = 0;
-		}
-		hred = CNVT_TOHW(hred, var->red.length);
-		hgreen = CNVT_TOHW(hgreen, var->green.length);
-		hblue = CNVT_TOHW(hblue, var->blue.length);
-		htransp = CNVT_TOHW(htransp, var->transp.length);
-		red++;
-		green++;
-		blue++;
-		if (transp)
-			transp++;
-		if (fbhw->setcolreg(start++, hred, hgreen, hblue, htransp))
-			return 0;
-	}
-	return 0;
-}
-
-
-static void do_install_cmap(int con)
-{
-	if (con != currcon)
-		return;
-	if (disp[con].cmap.len)
-		do_fb_set_cmap(&disp[con].cmap, &disp[con].var, 1);
-	else
-		do_fb_set_cmap(get_default_colormap(disp[con].var.bits_per_pixel),
-                                          &disp[con].var, 1);
-}
-
-
-static void memcpy_fs(int fsfromto, void *to, void *from, int len)
-{
-	switch (fsfromto) {
-	case 0:
-		memcpy(to, from, len);
-		return;
-	case 1:
-		copy_from_user(to, from, len);
-		return;
-	case 2:
-		copy_to_user(to, from, len);
-		return;
-	}
-}
-
-
-static void copy_cmap(struct fb_cmap *from, struct fb_cmap *to, int fsfromto)
-{
-	int size;
-	int tooff = 0, fromoff = 0;
-
-	if (to->start > from->start)
-		fromoff = to->start-from->start;
-	else
-		tooff = from->start-to->start;
-	size = to->len-tooff;
-	if (size > from->len-fromoff)
-		size = from->len-fromoff;
-	if (size < 0)
-		return;
-	size *= sizeof(unsigned short);
-	memcpy_fs(fsfromto, to->red+tooff, from->red+fromoff, size);
-	memcpy_fs(fsfromto, to->green+tooff, from->green+fromoff, size);
-	memcpy_fs(fsfromto, to->blue+tooff, from->blue+fromoff, size);
-	if (from->transp && to->transp)
-		memcpy_fs(fsfromto, to->transp+tooff,
-			  from->transp+fromoff, size);
-}
-
-
-static int alloc_cmap(struct fb_cmap *cmap, int len, int transp)
-{
-	int size = len*sizeof(unsigned short);
-
-	if (cmap->len != len) {
-		if (cmap->red)
-			kfree(cmap->red);
-		if (cmap->green)
-			kfree(cmap->green);
-		if (cmap->blue)
-			kfree(cmap->blue);
-		if (cmap->transp)
-			kfree(cmap->transp);
-		cmap->red = cmap->green = cmap->blue = cmap->transp = NULL;
-		cmap->len = 0;
-		if (!len)
-			return 0;
-		if (!(cmap->red = kmalloc(size, GFP_ATOMIC)))
-			return -1;
-		if (!(cmap->green = kmalloc(size, GFP_ATOMIC)))
-			return -1;
-		if (!(cmap->blue = kmalloc(size, GFP_ATOMIC)))
-			return -1;
-		if (transp) {
-			if (!(cmap->transp = kmalloc(size, GFP_ATOMIC)))
-				return -1;
-		} else
-			cmap->transp = NULL;
-	}
-	cmap->start = 0;
-	cmap->len = len;
-	copy_cmap(get_default_colormap(len), cmap, 0);
-	return 0;
-}
-
-
-/*
- *    Get the Fixed Part of the Display
- */
-
-static int retz3_fb_get_fix(struct fb_fix_screeninfo *fix, int con)
-{
-	struct retz3_fb_par par;
-	int error = 0;
-
-	if (con == -1)
-		retz3_fb_get_par(&par);
-	else
-		error = fbhw->decode_var(&disp[con].var, &par);
-	return(error ? error : fbhw->encode_fix(fix, &par));
-}
-
-
-/*
- *    Get the User Defined Part of the Display
- */
-
-static int retz3_fb_get_var(struct fb_var_screeninfo *var, int con)
-{
-	struct retz3_fb_par par;
-	int error = 0;
-
-	if (con == -1) {
-		retz3_fb_get_par(&par);
-		error = fbhw->encode_var(var, &par);
-	} else
-		*var = disp[con].var;
-	return error;
-}
-
-
-static void retz3_fb_set_disp(int con)
-{
-	struct fb_fix_screeninfo fix;
-
-	retz3_fb_get_fix(&fix, con);
-	if (con == -1)
-		con = 0;
-	disp[con].screen_base = (unsigned char *)fix.smem_start;
-	disp[con].visual = fix.visual;
-	disp[con].type = fix.type;
-	disp[con].type_aux = fix.type_aux;
-	disp[con].ypanstep = fix.ypanstep;
-	disp[con].ywrapstep = fix.ywrapstep;
-	disp[con].can_soft_blank = 1;
-	disp[con].inverse = z3fb_inverse;
-}
-
-
-/*
- *    Set the User Defined Part of the Display
- */
-
-static int retz3_fb_set_var(struct fb_var_screeninfo *var, int con)
-{
-	int err, oldxres, oldyres, oldvxres, oldvyres, oldbpp;
-
-	if ((err = do_fb_set_var(var, con == currcon)))
-		return err;
-	if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
-		oldxres = disp[con].var.xres;
-		oldyres = disp[con].var.yres;
-		oldvxres = disp[con].var.xres_virtual;
-		oldvyres = disp[con].var.yres_virtual;
-		oldbpp = disp[con].var.bits_per_pixel;
-		disp[con].var = *var;
-		if (oldxres != var->xres || oldyres != var->yres ||
-		    oldvxres != var->xres_virtual ||
-		    oldvyres != var->yres_virtual ||
-		    oldbpp != var->bits_per_pixel) {
-			retz3_fb_set_disp(con);
-			(*fb_info.changevar)(con);
-			alloc_cmap(&disp[con].cmap, 0, 0);
-			do_install_cmap(con);
-		}
-	}
-	var->activate = 0;
-	return 0;
-}
-
-
-/*
- *    Get the Colormap
- */
-
-static int retz3_fb_get_cmap(struct fb_cmap *cmap, int kspc, int con)
-{
-	if (con == currcon) /* current console? */
-		return(do_fb_get_cmap(cmap, &disp[con].var, kspc));
-	else if (disp[con].cmap.len) /* non default colormap? */
-		copy_cmap(&disp[con].cmap, cmap, kspc ? 0 : 2);
-	else
-		copy_cmap(get_default_colormap(disp[con].var.bits_per_pixel),
-			  cmap, kspc ? 0 : 2);
-	return 0;
-}
-
-
-/*
- *    Set the Colormap
- */
-
-static int retz3_fb_set_cmap(struct fb_cmap *cmap, int kspc, int con)
-{
-	int err;
-
-	if (!disp[con].cmap.len) {       /* no colormap allocated? */
-		if ((err = alloc_cmap(&disp[con].cmap,
-				      1<<disp[con].var.bits_per_pixel, 0)))
-			return err;
-	}
-	if (con == currcon)              /* current console? */
-		return(do_fb_set_cmap(cmap, &disp[con].var, kspc));
-	else
-		copy_cmap(cmap, &disp[con].cmap, kspc ? 0 : 1);
-	return 0;
-}
-
-
-/*
- *    Pan or Wrap the Display
- *
- *    This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
- */
-
-static int retz3_fb_pan_display(struct fb_var_screeninfo *var, int con)
-{
-	return -EINVAL;
-}
-
-
-/*
- *    RetinaZ3 Frame Buffer Specific ioctls
- */
-
-static int retz3_fb_ioctl(struct inode *inode, struct file *file,
-                          unsigned int cmd, unsigned long arg, int con)
-{
-	return -EINVAL;
-}
-
-
-static struct fb_ops retz3_fb_ops = {
-   retz3_fb_get_fix, retz3_fb_get_var, retz3_fb_set_var, retz3_fb_get_cmap,
-   retz3_fb_set_cmap, retz3_fb_pan_display, retz3_fb_ioctl
-};
-
-
-int retz3_probe(void)
-{
-	z3_key = zorro_find(MANUF_MACROSYSTEMS2, PROD_RETINA_Z3, 0, 0);
-	return(z3_key);
-}
-
-
-void retz3_video_setup(char *options, int *ints)
-{
-	char *this_opt;
-	int i;
-
-	fb_info.fontname[0] = '\0';
-
-	if (!options || !*options)
-		return;
-
-	for (this_opt = strtok(options, ","); this_opt; 
-	     this_opt = strtok(NULL, ",")){
-		if (!strcmp(this_opt, "inverse")) {
-			z3fb_inverse = 1;
-			for (i = 0; i < 16; i++) {
-				red16[i] = ~red16[i];
-				green16[i] = ~green16[i];
-				blue16[i] = ~blue16[i];
-			}
-		} else if (!strncmp(this_opt, "font:", 5))
-			strcpy(fb_info.fontname, this_opt+5);
-		else
-			z3fb_mode = get_video_mode(this_opt);
-	}
-}
-
-
-/*
- *    Initialization
- */
-
-__initfunc(struct fb_info *retz3_fb_init(long *mem_start))
-{
-	int err;
-	struct retz3_fb_par par;
-
-	memstart = mem_start;
-
-	fbhw = &retz3_switch;
-
-	err = register_framebuffer(retz3_fb_name, &node, &retz3_fb_ops,
-				   NUM_TOTAL_MODES, retz3_fb_predefined);
-	if (err < 0)
-		panic("Cannot register frame buffer\n");
-
-	fbhw->init();
-
-	if (z3fb_mode == -1)
-		z3fb_mode = 1;
-
-	fbhw->decode_var(&retz3_fb_predefined[z3fb_mode], &par);
-	fbhw->encode_var(&retz3_fb_predefined[0], &par);
-
-	strcpy(fb_info.modename, retz3_fb_name);
-	fb_info.disp = disp;
-	fb_info.switch_con = &z3fb_switch;
-	fb_info.updatevar = &z3fb_updatevar;
-	fb_info.blank = &z3fb_blank;
-	fb_info.setcmap = &z3fb_setcmap;
-
-	do_fb_set_var(&retz3_fb_predefined[0], 0);
-	retz3_fb_get_var(&disp[0].var, -1);
-	retz3_fb_set_disp(-1);
-	do_install_cmap(0);
-
-	return &fb_info;
-}
-
-
-static int z3fb_switch(int con)
-{
-	/* Do we have to save the colormap? */
-	if (disp[currcon].cmap.len)
-		do_fb_get_cmap(&disp[currcon].cmap, &disp[currcon].var, 1);
-
-	do_fb_set_var(&disp[con].var, 1);
-	currcon = con;
-	/* Install new colormap */
-	do_install_cmap(con);
-	return 0;
-}
-
-
-/*
- *    Update the `var' structure (called by fbcon.c)
- *
- *    This call looks only at yoffset and the FB_VMODE_YWRAP flag in `var'.
- *    Since it's called by a kernel driver, no range checking is done.
- */
-
-static int z3fb_updatevar(int con)
-{
-	return 0;
-}
-
-
-/*
- *    Blank the display.
- */
-
-static void z3fb_blank(int blank)
-{
-	fbhw->blank(blank);
-}
-
-
-/*
- *    Set the colormap
- */
-
-static int z3fb_setcmap(struct fb_cmap *cmap, int con)
-{
-	return(retz3_fb_set_cmap(cmap, 1, con));
-}
-
-
-/*
- *    Get a Video Mode
- */
-
-static int get_video_mode(const char *name)
-{
-	int i;
-
-	for (i = 1; i <= NUM_PREDEF_MODES; i++)
-		if (!strcmp(name, retz3_fb_modenames[i])){
-			retz3_fb_predefined[0] = retz3_fb_predefined[i];
-			return i;
-		}
-	return -1;
-}
diff -u --recursive --new-file v2.1.72/linux/arch/m68k/amiga/retz3fb.h linux/arch/m68k/amiga/retz3fb.h
--- v2.1.72/linux/arch/m68k/amiga/retz3fb.h	Tue May 13 22:41:02 1997
+++ linux/arch/m68k/amiga/retz3fb.h	Wed Dec 31 16:00:00 1969
@@ -1,286 +0,0 @@
-/*
- * Linux/arch/m68k/amiga/retz3fb.h -- Defines and macros for the
- *                                    RetinaZ3 frame buffer device
- *
- *    Copyright (C) 1997 Jes Sorensen
- *
- * History:
- *   - 22 Jan 97: Initial work
- *
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file COPYING in the main directory of this archive
- * for more details.
- */
-
-/*
- * Macros to read and write to registers.
- */
-#define reg_w(reg,dat) (*(z3_regs + reg) = dat)
-#define reg_r(reg) (*(z3_regs + reg))
-
-/*
- * Macro to access the sequencer.
- */
-#define seq_w(sreg,sdat) \
-	do{ reg_w(SEQ_IDX, sreg); reg_w(SEQ_DATA, sdat); } while(0)
-
-/*
- * Macro to access the CRT controller.
- */
-#define crt_w(creg,cdat) \
-	do{ reg_w(CRT_IDX, creg); reg_w(CRT_DATA, cdat); } while(0)
-
-/*
- * Macro to access the graphics controller.
- */
-#define gfx_w(greg,gdat) \
-	do{ reg_w(GFX_IDX, greg); reg_w(GFX_DATA, gdat); } while(0)
-
-/*
- * Macro to access the attribute controller.
- */
-#define attr_w(areg,adat) \
-	do{ reg_w(ACT_IDX, areg); reg_w(ACT_DATA, adat); } while(0)
-
-/*
- * Macro to access the pll.
- */
-#define pll_w(preg,pdat) \
-	do{ reg_w(PLL_IDX, preg); \
-	    reg_w(PLL_DATA, (pdat & 0xff)); \
-	    reg_w(PLL_DATA, (pdat >> 8));\
-	} while(0)
-
-/*
- * Offsets
- */
-#define VIDEO_MEM_OFFSET	0x00c00000
-#define ACM_OFFSET		0x00b00000
-
-/*
- * Accelerator Control Menu
- */
-#define ACM_PRIMARY_OFFSET	0x00
-#define ACM_SECONDARY_OFFSET	0x04
-#define ACM_MODE_CONTROL	0x08
-#define ACM_CURSOR_POSITION	0x0c
-#define ACM_START_STATUS	0x30
-#define ACM_CONTROL		0x34
-#define ACM_RASTEROP_ROTATION	0x38
-#define ACM_BITMAP_DIMENSION	0x3c
-#define ACM_DESTINATION		0x40
-#define ACM_SOURCE		0x44
-#define ACM_PATTERN		0x48
-#define ACM_FOREGROUND		0x4c
-#define ACM_BACKGROUND		0x50
-
-/*
- * Video DAC addresses
- */
-#define VDAC_ADDRESS		0x03c8
-#define VDAC_ADDRESS_W		0x03c8
-#define VDAC_ADDRESS_R		0x03c7
-#define VDAC_STATE		0x03c7
-#define VDAC_DATA		0x03c9
-#define VDAC_MASK		0x03c6
-
-/*
- * Sequencer
- */
-#define SEQ_IDX			0x03c4	/* Sequencer Index */
-#define SEQ_DATA		0x03c5
-#define SEQ_RESET		0x00
-#define SEQ_CLOCKING_MODE	0x01
-#define SEQ_MAP_MASK		0x02
-#define SEQ_CHAR_MAP_SELECT	0x03
-#define SEQ_MEMORY_MODE		0x04
-#define SEQ_EXTENDED_ENABLE	0x05	/* NCR extensions */
-#define SEQ_UNKNOWN1         	0x06
-#define SEQ_UNKNOWN2         	0x07
-#define SEQ_CHIP_ID		0x08
-#define SEQ_UNKNOWN3         	0x09
-#define SEQ_CURSOR_COLOR1	0x0a
-#define SEQ_CURSOR_COLOR0	0x0b
-#define SEQ_CURSOR_CONTROL	0x0c
-#define SEQ_CURSOR_X_LOC_HI	0x0d
-#define SEQ_CURSOR_X_LOC_LO	0x0e
-#define SEQ_CURSOR_Y_LOC_HI	0x0f
-#define SEQ_CURSOR_Y_LOC_LO	0x10
-#define SEQ_CURSOR_X_INDEX	0x11
-#define SEQ_CURSOR_Y_INDEX	0x12
-#define SEQ_CURSOR_STORE_HI	0x13
-#define SEQ_CURSOR_STORE_LO	0x14
-#define SEQ_CURSOR_ST_OFF_HI	0x15
-#define SEQ_CURSOR_ST_OFF_LO	0x16
-#define SEQ_CURSOR_PIXELMASK	0x17
-#define SEQ_PRIM_HOST_OFF_HI	0x18
-#define SEQ_PRIM_HOST_OFF_LO	0x19
-#define SEQ_LINEAR_0		0x1a
-#define SEQ_LINEAR_1		0x1b
-#define SEQ_SEC_HOST_OFF_HI	0x1c
-#define SEQ_SEC_HOST_OFF_LO	0x1d
-#define SEQ_EXTENDED_MEM_ENA	0x1e
-#define SEQ_EXT_CLOCK_MODE	0x1f
-#define SEQ_EXT_VIDEO_ADDR	0x20
-#define SEQ_EXT_PIXEL_CNTL	0x21
-#define SEQ_BUS_WIDTH_FEEDB	0x22
-#define SEQ_PERF_SELECT		0x23
-#define SEQ_COLOR_EXP_WFG	0x24
-#define SEQ_COLOR_EXP_WBG	0x25
-#define SEQ_EXT_RW_CONTROL	0x26
-#define SEQ_MISC_FEATURE_SEL	0x27
-#define SEQ_COLOR_KEY_CNTL	0x28
-#define SEQ_COLOR_KEY_MATCH0	0x29
-#define SEQ_COLOR_KEY_MATCH1 	0x2a
-#define SEQ_COLOR_KEY_MATCH2 	0x2b
-#define SEQ_UNKNOWN6         	0x2c
-#define SEQ_CRC_CONTROL		0x2d
-#define SEQ_CRC_DATA_LOW	0x2e
-#define SEQ_CRC_DATA_HIGH	0x2f
-#define SEQ_MEMORY_MAP_CNTL	0x30
-#define SEQ_ACM_APERTURE_1	0x31
-#define SEQ_ACM_APERTURE_2	0x32
-#define SEQ_ACM_APERTURE_3	0x33
-#define SEQ_BIOS_UTILITY_0	0x3e
-#define SEQ_BIOS_UTILITY_1	0x3f
-
-/*
- * Graphics Controller
- */
-#define GFX_IDX			0x03ce
-#define GFX_DATA		0x03cf
-#define GFX_SET_RESET		0x00
-#define GFX_ENABLE_SET_RESET	0x01
-#define GFX_COLOR_COMPARE	0x02
-#define GFX_DATA_ROTATE		0x03
-#define GFX_READ_MAP_SELECT	0x04
-#define GFX_GRAPHICS_MODE	0x05
-#define GFX_MISC		0x06
-#define GFX_COLOR_XCARE		0x07
-#define GFX_BITMASK		0x08
-
-/*
- * CRT Controller
- */
-#define CRT_IDX			0x03d4
-#define CRT_DATA		0x03d5
-#define CRT_HOR_TOTAL		0x00
-#define CRT_HOR_DISP_ENA_END	0x01
-#define CRT_START_HOR_BLANK	0x02
-#define CRT_END_HOR_BLANK	0x03
-#define CRT_START_HOR_RETR	0x04
-#define CRT_END_HOR_RETR	0x05
-#define CRT_VER_TOTAL		0x06
-#define CRT_OVERFLOW		0x07
-#define CRT_PRESET_ROW_SCAN	0x08
-#define CRT_MAX_SCAN_LINE	0x09
-#define CRT_CURSOR_START	0x0a
-#define CRT_CURSOR_END		0x0b
-#define CRT_START_ADDR_HIGH	0x0c
-#define CRT_START_ADDR_LOW	0x0d
-#define CRT_CURSOR_LOC_HIGH	0x0e
-#define CRT_CURSOR_LOC_LOW	0x0f
-#define CRT_START_VER_RETR	0x10
-#define CRT_END_VER_RETR	0x11
-#define CRT_VER_DISP_ENA_END	0x12
-#define CRT_OFFSET		0x13
-#define CRT_UNDERLINE_LOC	0x14
-#define CRT_START_VER_BLANK	0x15
-#define CRT_END_VER_BLANK	0x16
-#define CRT_MODE_CONTROL	0x17
-#define CRT_LINE_COMPARE	0x18
-#define CRT_UNKNOWN1         	0x19
-#define CRT_UNKNOWN2         	0x1a
-#define CRT_UNKNOWN3         	0x1b
-#define CRT_UNKNOWN4         	0x1c
-#define CRT_UNKNOWN5         	0x1d
-#define CRT_UNKNOWN6         	0x1e
-#define CRT_UNKNOWN7         	0x1f
-#define CRT_UNKNOWN8         	0x20
-#define CRT_UNKNOWN9		0x21
-#define CRT_UNKNOWN10		0x22
-#define CRT_UNKNOWN11      	0x23
-#define CRT_UNKNOWN12      	0x24
-#define CRT_UNKNOWN13      	0x25
-#define CRT_UNKNOWN14      	0x26
-#define CRT_UNKNOWN15      	0x27
-#define CRT_UNKNOWN16      	0x28
-#define CRT_UNKNOWN17      	0x29
-#define CRT_UNKNOWN18      	0x2a
-#define CRT_UNKNOWN19      	0x2b
-#define CRT_UNKNOWN20      	0x2c
-#define CRT_UNKNOWN21      	0x2d
-#define CRT_UNKNOWN22      	0x2e
-#define CRT_UNKNOWN23      	0x2f
-#define CRT_EXT_HOR_TIMING1	0x30	/* NCR crt extensions */
-#define CRT_EXT_START_ADDR	0x31
-#define CRT_EXT_HOR_TIMING2	0x32
-#define CRT_EXT_VER_TIMING	0x33
-#define CRT_MONITOR_POWER	0x34
-
-/*
- * General Registers
- */
-#define GREG_STATUS0_R		0x03c2
-#define GREG_STATUS1_R		0x03da
-#define GREG_MISC_OUTPUT_R	0x03cc
-#define GREG_MISC_OUTPUT_W	0x03c2	
-#define GREG_FEATURE_CONTROL_R	0x03ca
-#define GREG_FEATURE_CONTROL_W	0x03da
-#define GREG_POS		0x0102
-
-/*
- * Attribute Controller
- */
-#define ACT_IDX			0x03C0
-#define ACT_ADDRESS_R		0x03C0
-#define ACT_DATA		0x03C0
-#define ACT_ADDRESS_RESET	0x03DA
-#define ACT_PALETTE0		0x00
-#define ACT_PALETTE1		0x01
-#define ACT_PALETTE2		0x02
-#define ACT_PALETTE3		0x03
-#define ACT_PALETTE4		0x04
-#define ACT_PALETTE5		0x05
-#define ACT_PALETTE6		0x06
-#define ACT_PALETTE7		0x07
-#define ACT_PALETTE8		0x08
-#define ACT_PALETTE9		0x09
-#define ACT_PALETTE10		0x0A
-#define ACT_PALETTE11		0x0B
-#define ACT_PALETTE12		0x0C
-#define ACT_PALETTE13		0x0D
-#define ACT_PALETTE14		0x0E
-#define ACT_PALETTE15		0x0F
-#define ACT_ATTR_MODE_CNTL	0x10
-#define ACT_OVERSCAN_COLOR	0x11
-#define ACT_COLOR_PLANE_ENA	0x12
-#define ACT_HOR_PEL_PANNING	0x13
-#define ACT_COLOR_SELECT	0x14
-
-/*
- * PLL
- */
-#define PLL_IDX			0x83c8
-#define PLL_DATA		0x83c9
-
-/*
- * Blitter operations
- */
-#define	Z3BLTclear		0x00	/* 0 */
-#define Z3BLTand		0x80	/* src AND dst */
-#define Z3BLTandReverse		0x40	/* src AND NOT dst */
-#define Z3BLTcopy		0xc0	/* src */
-#define Z3BLTandInverted	0x20	/* NOT src AND dst */
-#define	Z3BLTnoop		0xa0	/* dst */
-#define Z3BLTxor		0x60	/* src XOR dst */
-#define Z3BLTor			0xe0	/* src OR dst */
-#define Z3BLTnor		0x10	/* NOT src AND NOT dst */
-#define Z3BLTequiv		0x90	/* NOT src XOR dst */
-#define Z3BLTinvert		0x50	/* NOT dst */
-#define Z3BLTorReverse		0xd0	/* src OR NOT dst */
-#define Z3BLTcopyInverted	0x30	/* NOT src */
-#define Z3BLTorInverted		0xb0	/* NOT src OR dst */
-#define Z3BLTnand		0x70	/* NOT src OR NOT dst */
-#define Z3BLTset		0xf0	/* 1 */
diff -u --recursive --new-file v2.1.72/linux/arch/m68k/atari/atafb.c linux/arch/m68k/atari/atafb.c
--- v2.1.72/linux/arch/m68k/atari/atafb.c	Tue May 13 22:41:02 1997
+++ linux/arch/m68k/atari/atafb.c	Wed Dec 31 16:00:00 1969
@@ -1,3292 +0,0 @@
-/*
- * atari/atafb.c -- Low level implementation of Atari frame buffer device
- *
- *  Copyright (C) 1994 Martin Schaller & Roman Hodek
- *  
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file COPYING in the main directory of this archive
- * for more details.
- *
- * History:
- *   - 03 Jan 95: Original version by Martin Schaller: The TT driver and
- *                all the device independent stuff
- *   - 09 Jan 95: Roman: I've added the hardware abstraction (hw_switch)
- *                and wrote the Falcon, ST(E), and External drivers
- *                based on the original TT driver.
- *   - 07 May 95: Martin: Added colormap operations for the external driver
- *   - 21 May 95: Martin: Added support for overscan
- *		  Andreas: some bug fixes for this
- *   -    Jul 95: Guenther Kelleter <guenther@pool.informatik.rwth-aachen.de>:
- *                Programmable Falcon video modes
- *                (thanks to Christian Cartus for documentation
- *                of VIDEL registers).
- *   - 27 Dec 95: Guenther: Implemented user definable video modes "user[0-7]"
- *                on minor 24...31. "user0" may be set on commandline by
- *                "R<x>;<y>;<depth>". (Makes sense only on Falcon)
- *                Video mode switch on Falcon now done at next VBL interrupt
- *                to avoid the annoying right shift of the screen.
- *
- *
- * To do:
- *   - For the Falcon it is not possible to set random video modes on
- *     SM124 and SC/TV, only the bootup resolution is supported.
- *
- */
-
-#define ATAFB_TT
-#define ATAFB_STE
-#define ATAFB_EXT
-#define ATAFB_FALCON
-
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/tty.h>
-#include <linux/malloc.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-
-#include <asm/setup.h>
-#include <asm/uaccess.h>
-#include <asm/pgtable.h>
-#include <asm/irq.h>
-
-#include <asm/atarihw.h>
-#include <asm/atariints.h>
-
-#include <linux/fb.h>
-#include <asm/atarikb.h>
-
-#define SWITCH_ACIA 0x01		/* modes for switch on OverScan */
-#define SWITCH_SND6 0x40
-#define SWITCH_SND7 0x80
-#define SWITCH_NONE 0x00
-
-
-#define arraysize(x)			(sizeof(x)/sizeof(*(x)))
-
-#define up(x, r) (((x) + (r) - 1) & ~((r)-1))
-
-
-static int default_par=0;	/* default resolution (0=none) */
-
-static int node;		/* node of the /dev/fb?current file */
-
-static unsigned long default_mem_req=0;
-
-static int hwscroll=-1;
-
-static int use_hwscroll = 1;
-
-static int sttt_xres=640,st_yres=400,tt_yres=480;
-static int sttt_xres_virtual=640,sttt_yres_virtual=400;
-static int ovsc_offset=0, ovsc_addlen=0;
-int        ovsc_switchmode=0;
-
-static struct atari_fb_par {
-	unsigned long screen_base;
-	int yres_virtual;
-	union {
-		struct {
-			int mode;
-			int sync;
-		} tt, st;
-		struct falcon_hw {
-			/* Here are fields for storing a video mode, as direct
-			 * parameters for the hardware.
-			 */
-			short sync;
-			short line_width;
-			short line_offset;
-			short st_shift;
-			short f_shift;
-			short vid_control;
-			short vid_mode;
-			short xoffset;
-			short hht, hbb, hbe, hdb, hde, hss;
-			short vft, vbb, vbe, vdb, vde, vss;
-			/* auxiliary information */
-			short mono;
-			short ste_mode;
-			short bpp;
-		} falcon;
-		/* Nothing needed for external mode */
-	} hw;
-} current_par;
-
-/* Don't calculate an own resolution, and thus don't change the one found when
- * booting (currently used for the Falcon to keep settings for internal video
- * hardware extensions (e.g. ScreenBlaster)  */
-static int DontCalcRes = 0; 
-
-#define HHT hw.falcon.hht
-#define HBB hw.falcon.hbb
-#define HBE hw.falcon.hbe
-#define HDB hw.falcon.hdb
-#define HDE hw.falcon.hde
-#define HSS hw.falcon.hss
-#define VFT hw.falcon.vft
-#define VBB hw.falcon.vbb
-#define VBE hw.falcon.vbe
-#define VDB hw.falcon.vdb
-#define VDE hw.falcon.vde
-#define VSS hw.falcon.vss
-#define VCO_CLOCK25		0x04
-#define VCO_CSYPOS		0x10
-#define VCO_VSYPOS		0x20
-#define VCO_HSYPOS		0x40
-#define VCO_SHORTOFFS	0x100
-#define VMO_DOUBLE		0x01
-#define VMO_INTER		0x02
-#define VMO_PREMASK		0x0c
-
-static struct fb_info fb_info;
-
-static unsigned long screen_base;	/* base address of screen */
-static unsigned long real_screen_base;	/* (only for Overscan) */
-
-static int screen_len;
-
-static int current_par_valid=0; 
-
-static int currcon=0;
-
-static int mono_moni=0;
-
-static struct display disp[MAX_NR_CONSOLES];
-
-
-#ifdef ATAFB_EXT
-/* external video handling */
-
-static unsigned			external_xres;
-static unsigned			external_yres;
-static unsigned			external_depth;
-static int				external_pmode;
-static unsigned long	external_addr = 0;
-static unsigned long	external_len;
-static unsigned long	external_vgaiobase = 0;
-static unsigned int		external_bitspercol = 6;
-
-/* 
-++JOE <joe@amber.dinoco.de>: 
-added card type for external driver, is only needed for
-colormap handling.
-*/
-
-enum cardtype { IS_VGA, IS_MV300 };
-static enum cardtype external_card_type = IS_VGA;
-
-/*
-The MV300 mixes the color registers. So we need an array of munged
-indices in order to acces the correct reg.
-*/
-static int MV300_reg_1bit[2]={0,1};
-static int MV300_reg_4bit[16]={
-0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15 };
-static int MV300_reg_8bit[256]={
-0, 128, 64, 192, 32, 160, 96, 224, 16, 144, 80, 208, 48, 176, 112, 240, 
-8, 136, 72, 200, 40, 168, 104, 232, 24, 152, 88, 216, 56, 184, 120, 248, 
-4, 132, 68, 196, 36, 164, 100, 228, 20, 148, 84, 212, 52, 180, 116, 244, 
-12, 140, 76, 204, 44, 172, 108, 236, 28, 156, 92, 220, 60, 188, 124, 252, 
-2, 130, 66, 194, 34, 162, 98, 226, 18, 146, 82, 210, 50, 178, 114, 242, 
-10, 138, 74, 202, 42, 170, 106, 234, 26, 154, 90, 218, 58, 186, 122, 250, 
-6, 134, 70, 198, 38, 166, 102, 230, 22, 150, 86, 214, 54, 182, 118, 246, 
-14, 142, 78, 206, 46, 174, 110, 238, 30, 158, 94, 222, 62, 190, 126, 254, 
-1, 129, 65, 193, 33, 161, 97, 225, 17, 145, 81, 209, 49, 177, 113, 241, 
-9, 137, 73, 201, 41, 169, 105, 233, 25, 153, 89, 217, 57, 185, 121, 249, 
-5, 133, 69, 197, 37, 165, 101, 229, 21, 149, 85, 213, 53, 181, 117, 245, 
-13, 141, 77, 205, 45, 173, 109, 237, 29, 157, 93, 221, 61, 189, 125, 253, 
-3, 131, 67, 195, 35, 163, 99, 227, 19, 147, 83, 211, 51, 179, 115, 243, 
-11, 139, 75, 203, 43, 171, 107, 235, 27, 155, 91, 219, 59, 187, 123, 251, 
-7, 135, 71, 199, 39, 167, 103, 231, 23, 151, 87, 215, 55, 183, 119, 247, 
-15, 143, 79, 207, 47, 175, 111, 239, 31, 159, 95, 223, 63, 191, 127, 255 }; 
-
-static int *MV300_reg = MV300_reg_8bit;
-
-/*
-And on the MV300 it's difficult to read out the hardware palette. So we
-just keep track of the set colors in our own array here, and use that!
-*/
-
-static struct { unsigned char red,green,blue,pad; } MV300_color[256];
-#endif /* ATAFB_EXT */
-
-
-static int inverse=0;
-
-extern int fontheight_8x8;
-extern int fontwidth_8x8;
-extern unsigned char fontdata_8x8[];
-
-extern int fontheight_8x16;
-extern int fontwidth_8x16;
-extern unsigned char fontdata_8x16[];
-
-/* import first 16 colors from fbcon.c */
-extern unsigned short packed16_cmap[16];
-
-
-/* ++roman: This structure abstracts from the underlying hardware (ST(e),
- * TT, or Falcon.
- *
- * int (*detect)( void )
- *   This function should detect the current video mode settings and
- *   store them in atari_fb_predefined[0] for later reference by the
- *   user. Return the index+1 of an equivalent predefined mode or 0
- *   if there is no such.
- * 
- * int (*encode_fix)( struct fb_fix_screeninfo *fix,
- *                    struct atari_fb_par *par )
- *   This function should fill in the 'fix' structure based on the
- *   values in the 'par' structure.
- *   
- * int (*decode_var)( struct fb_var_screeninfo *var,
- *                    struct atari_fb_par *par )
- *   Get the video params out of 'var'. If a value doesn't fit, round
- *   it up, if it's too big, return EINVAL.
- *   Round up in the following order: bits_per_pixel, xres, yres, 
- *   xres_virtual, yres_virtual, xoffset, yoffset, grayscale, bitfields, 
- *   horizontal timing, vertical timing.
- *
- * int (*encode_var)( struct fb_var_screeninfo *var,
- *                    struct atari_fb_par *par );
- *   Fill the 'var' structure based on the values in 'par' and maybe
- *   other values read out of the hardware.
- *   
- * void (*get_par)( struct atari_fb_par *par )
- *   Fill the hardware's 'par' structure.
- *   
- * void (*set_par)( struct atari_fb_par *par )
- *   Set the hardware according to 'par'.
- *   
- * int (*setcolreg)( unsigned regno, unsigned red,
- *                   unsigned green, unsigned blue,
- *                   unsigned transp )
- *   Set a single color register. The values supplied are already
- *   rounded down to the hardware's capabilities (according to the
- *   entries in the var structure). Return != 0 for invalid regno.
- *
- * int (*getcolreg)( unsigned regno, unsigned *red,
- *                   unsigned *green, unsigned *blue,
- *                   unsigned *transp )
- *   Read a single color register and split it into
- *   colors/transparent. Return != 0 for invalid regno.
- *
- * void (*set_screen_base)( unsigned long s_base )
- *   Set the base address of the displayed frame buffer. Only called
- *   if yres_virtual > yres or xres_virtual > xres.
- *
- * int (*blank)( int blank_mode )
- *   Blank the screen if blank_mode!=0, else unblank. If blank==NULL then
- *   the caller blanks by setting the CLUT to all black. Return 0 if blanking
- *   succeeded, !=0 if un-/blanking failed due to e.g. a video mode which
- *   doesn't support it. Implements VESA suspend and powerdown modes on
- *   hardware that supports disabling hsync/vsync:
- *       blank_mode==2: suspend vsync, 3:suspend hsync, 4: powerdown.
- */
-
-static struct fb_hwswitch {
-	int  (*detect)( void );
-	int  (*encode_fix)( struct fb_fix_screeninfo *fix,
-						struct atari_fb_par *par );
-	int  (*decode_var)( struct fb_var_screeninfo *var,
-						struct atari_fb_par *par );
-	int  (*encode_var)( struct fb_var_screeninfo *var,
-						struct atari_fb_par *par );
-	void (*get_par)( struct atari_fb_par *par );
-	void (*set_par)( struct atari_fb_par *par );
-	int  (*getcolreg)( unsigned regno, unsigned *red,
-					   unsigned *green, unsigned *blue,
-					   unsigned *transp );
-	int  (*setcolreg)( unsigned regno, unsigned red,
-					   unsigned green, unsigned blue,
-					   unsigned transp );
-	void (*set_screen_base)( unsigned long s_base );
-	int  (*blank)( int blank_mode );
-	int  (*pan_display)( struct fb_var_screeninfo *var,
-						 struct atari_fb_par *par);
-} *fbhw;
-
-static char *autodetect_names[] = {"autodetect", NULL};
-static char *stlow_names[] = {"stlow", NULL};
-static char *stmid_names[] = {"stmid", "default5", NULL};
-static char *sthigh_names[] = {"sthigh", "default4", NULL};
-static char *ttlow_names[] = {"ttlow", NULL};
-static char *ttmid_names[]= {"ttmid", "default1", NULL};
-static char *tthigh_names[]= {"tthigh", "default2", NULL};
-static char *vga2_names[] = {"vga2", NULL};
-static char *vga4_names[] = {"vga4", NULL};
-static char *vga16_names[] = {"vga16", "default3", NULL};
-static char *vga256_names[] = {"vga256", NULL};
-static char *falh2_names[] = {"falh2", NULL};
-static char *falh16_names[] = {"falh16", NULL};
-static char *user0_names[] = {"user0", NULL};
-static char *user1_names[] = {"user1", NULL};
-static char *user2_names[] = {"user2", NULL};
-static char *user3_names[] = {"user3", NULL};
-static char *user4_names[] = {"user4", NULL};
-static char *user5_names[] = {"user5", NULL};
-static char *user6_names[] = {"user6", NULL};
-static char *user7_names[] = {"user7", NULL};
-static char *dummy_names[] = {"dummy", NULL};
-
-static char **fb_var_names[] = {
-	/* Writing the name arrays directly in this array (via "(char *[]){...}")
-	 * crashes gcc 2.5.8 (sigsegv) if the inner array
-	 * contains more than two items. I've also seen that all elements
-	 * were identical to the last (my cross-gcc) :-(*/
-	autodetect_names,
-	stlow_names,
-	stmid_names,
-	sthigh_names,
-	ttlow_names,
-	ttmid_names,
-	tthigh_names,
-	vga2_names,
-	vga4_names,
-	vga16_names,
-	vga256_names,
-	falh2_names,
-	falh16_names,
-	dummy_names, dummy_names, dummy_names, dummy_names,
-	dummy_names, dummy_names, dummy_names, dummy_names,
-	dummy_names, dummy_names,
-	user0_names,
-	user1_names,
-	user2_names,
-	user3_names,
-	user4_names,
-	user5_names,
-	user6_names,
-	user7_names,
-	NULL
-	/* ,NULL */ /* this causes a sigsegv on my gcc-2.5.8 */
-};
-
-static struct fb_var_screeninfo atari_fb_predefined[] = {
- 	/*
- 	 * yres_virtual==0 means use hw-scrolling if possible, else yres
- 	 */
- 	{ /* autodetect */
-	  0, 0, 0, 0, 0, 0, 0, 0,   		/* xres-grayscale */
-	  {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, 	/* red green blue tran*/
-	  0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
- 	{ /* st low */
-	  320, 200, 320, 0, 0, 0, 4, 0,
-	  {0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {0, 0, 0},
-	  0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
-	{ /* st mid */
-	  640, 200, 640, 0, 0, 0, 2, 0,
-	  {0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {0, 0, 0},
-	  0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
-	{ /* st high */
-	  640, 400, 640, 0, 0, 0, 1, 0,
-	  {0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {0, 0, 0},
-	  0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
-	{ /* tt low */
-	  320, 480, 320, 0, 0, 0, 8, 0,
-	  {0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {0, 0, 0},
-	  0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
-	{ /* tt mid */
-	  640, 480, 640, 0, 0, 0, 4, 0,
-	  {0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {0, 0, 0},
-	  0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
-	{ /* tt high */
-	  1280, 960, 1280, 0, 0, 0, 1, 0,
-	  {0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {0, 0, 0},
-	  0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
-	{ /* vga2 */
-	  640, 480, 640, 0, 0, 0, 1, 0,
-	  {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0},
-	  0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
-	{ /* vga4 */
-	  640, 480, 640, 0, 0, 0, 2, 0,
-	  {0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {0, 0, 0},
-	  0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
-	{ /* vga16 */
-	  640, 480, 640, 0, 0, 0, 4, 0,
-	  {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0},
-	  0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
-	{ /* vga256 */
-	  640, 480, 640, 0, 0, 0, 8, 0,
-	  {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0},
-	  0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
-	{ /* falh2 */
-	  896, 608, 896, 0, 0, 0, 1, 0,
-	  {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0},
-	  0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
-	{ /* falh16 */
-	  896, 608, 896, 0, 0, 0, 4, 0,
-	  {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0},
-	  0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
-	/* Minor 14..23 free for more standard video modes */
-	{ 0, },
-	{ 0, },
-	{ 0, },
-	{ 0, },
-	{ 0, },
-	{ 0, },
-	{ 0, },
-	{ 0, },
-	{ 0, },
-	{ 0, },
-	/* Minor 24..31 reserved for user defined video modes */
-	{ /* user0, initialized to Rx;y;d from commandline, if supplied */
-	  0, 0, 0, 0, 0, 0, 0, 0,
-	  {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0},
-	  0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
-	{ /* user1 */
-	  0, 0, 0, 0, 0, 0, 0, 0,
-	  {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0},
-	  0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
-	{ /* user2 */
-	  0, 0, 0, 0, 0, 0, 0, 0,
-	  {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0},
-	  0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
-	{ /* user3 */
-	  0, 0, 0, 0, 0, 0, 0, 0,
-	  {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0},
-	  0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
-	{ /* user4 */
-	  0, 0, 0, 0, 0, 0, 0, 0,
-	  {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0},
-	  0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
-	{ /* user5 */
-	  0, 0, 0, 0, 0, 0, 0, 0,
-	  {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0},
-	  0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
-	{ /* user6 */
-	  0, 0, 0, 0, 0, 0, 0, 0,
-	  {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0},
-	  0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
-	{ /* user7 */
-	  0, 0, 0, 0, 0, 0, 0, 0,
-	  {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0},
-	  0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 }
-};
-
-static int num_atari_fb_predefined=arraysize(atari_fb_predefined);
-
-
-static int
-get_video_mode(char *vname)
-{
-    char ***name_list;
-    char **name;
-    int i;
-    name_list=fb_var_names;
-    for (i = 0 ; i < num_atari_fb_predefined ; i++) {
-	name=*(name_list++);
-	if (! name || ! *name)
-	    break;
-	while (*name) {
-	    if (! strcmp(vname, *name))
-		return i+1;
-	    name++;
-	}
-    }
-    return 0;
-}
-
-
-
-/* ------------------- TT specific functions ---------------------- */
-
-#ifdef ATAFB_TT
-
-static int tt_encode_fix( struct fb_fix_screeninfo *fix,
-						  struct atari_fb_par *par )
-
-{
-	int mode, i;
-
-	strcpy(fix->id,"Atari Builtin");
-	fix->smem_start=real_screen_base;
-	fix->smem_len = screen_len;
-	fix->type=FB_TYPE_INTERLEAVED_PLANES;
-	fix->type_aux=2;
-	fix->visual=FB_VISUAL_PSEUDOCOLOR;
-	mode = par->hw.tt.mode & TT_SHIFTER_MODEMASK;
-	if (mode == TT_SHIFTER_TTHIGH || mode == TT_SHIFTER_STHIGH) {
-		fix->type=FB_TYPE_PACKED_PIXELS;
-		fix->type_aux=0;
-		if (mode == TT_SHIFTER_TTHIGH)
-			fix->visual=FB_VISUAL_MONO01;
-	}
-	fix->xpanstep=0;
-	fix->ypanstep=1;
-	fix->ywrapstep=0;
-	fix->line_length = 0;
-	for (i=0; i<arraysize(fix->reserved); i++)
-		fix->reserved[i]=0;
-	return 0;
-}
-
-
-static int tt_decode_var( struct fb_var_screeninfo *var,
-						  struct atari_fb_par *par )
-{
-	int xres=var->xres;
-	int yres=var->yres;
-	int bpp=var->bits_per_pixel;
-	int linelen;
-	int yres_virtual = var->yres_virtual;
-
-	if (mono_moni) {
-		if (bpp > 1 || xres > sttt_xres*2 || yres >tt_yres*2)
-			return -EINVAL;
-		par->hw.tt.mode=TT_SHIFTER_TTHIGH;
-		xres=sttt_xres*2;
-		yres=tt_yres*2;
-		bpp=1;
-	} else {
-		if (bpp > 8 || xres > sttt_xres || yres > tt_yres)
-			return -EINVAL;
-		if (bpp > 4) {
-			if (xres > sttt_xres/2 || yres > tt_yres)
-				return -EINVAL;
-			par->hw.tt.mode=TT_SHIFTER_TTLOW;
-			xres=sttt_xres/2;
-			yres=tt_yres;
-			bpp=8;
-		}
-		else if (bpp > 2) {
-			if (xres > sttt_xres || yres > tt_yres)
-				return -EINVAL;
-			if (xres > sttt_xres/2 || yres > st_yres/2) {
-				par->hw.tt.mode=TT_SHIFTER_TTMID;
-				xres=sttt_xres;
-				yres=tt_yres;
-				bpp=4;
-			}
-			else {
-				par->hw.tt.mode=TT_SHIFTER_STLOW;
-				xres=sttt_xres/2;
-				yres=st_yres/2;
-				bpp=4;
-			}
-		}
-		else if (bpp > 1) {
-			if (xres > sttt_xres || yres > st_yres/2)
-				return -EINVAL;
-			par->hw.tt.mode=TT_SHIFTER_STMID;
-			xres=sttt_xres;
-			yres=st_yres/2;
-			bpp=2;
-		}
-		else if (var->xres > sttt_xres || var->yres > st_yres) {
-			return -EINVAL;
-		}
-		else {
-			par->hw.tt.mode=TT_SHIFTER_STHIGH;
-			xres=sttt_xres;
-			yres=st_yres;
-			bpp=1;
-		}
-	}
-	if (yres_virtual <= 0)
-		yres_virtual = 0;
-	else if (yres_virtual < yres)
-		yres_virtual = yres;
-	if (var->sync & FB_SYNC_EXT)
-		par->hw.tt.sync=0;
-	else
-		par->hw.tt.sync=1;
-	linelen=xres*bpp/8;
-	if (yres_virtual * linelen > screen_len && screen_len)
-		return -EINVAL;
-	if (yres * linelen > screen_len && screen_len)
-		return -EINVAL;
-	if (var->yoffset + yres > yres_virtual && yres_virtual)
-		return -EINVAL;
-	par->yres_virtual = yres_virtual;
-	par->screen_base = screen_base + var->yoffset * linelen;
-	return 0;
-}
-
-static int tt_encode_var( struct fb_var_screeninfo *var,
-						  struct atari_fb_par *par )
-{
-	int linelen, i;
-	var->red.offset=0;
-	var->red.length=4;
-	var->red.msb_right=0;
-	var->grayscale=0;
-
-	var->pixclock=31041;
-	var->left_margin=120;		/* these may be incorrect 	*/
-	var->right_margin=100;
-	var->upper_margin=8;
-	var->lower_margin=16;
-	var->hsync_len=140;
-	var->vsync_len=30;
-
-	var->height=-1;
-	var->width=-1;
-
-	if (par->hw.tt.sync & 1)
-		var->sync=0;
-	else
-		var->sync=FB_SYNC_EXT;
-
-	switch (par->hw.tt.mode & TT_SHIFTER_MODEMASK) {
-	case TT_SHIFTER_STLOW:
-		var->xres=sttt_xres/2;
-		var->xres_virtual=sttt_xres_virtual/2;
-		var->yres=st_yres/2;
-		var->bits_per_pixel=4;
-		break;
-	case TT_SHIFTER_STMID:
-		var->xres=sttt_xres;
-		var->xres_virtual=sttt_xres_virtual;
-		var->yres=st_yres/2;
-		var->bits_per_pixel=2;
-		break;
-	case TT_SHIFTER_STHIGH:
-		var->xres=sttt_xres;
-		var->xres_virtual=sttt_xres_virtual;
-		var->yres=st_yres;
-		var->bits_per_pixel=1;
-		break;
-	case TT_SHIFTER_TTLOW:
-		var->xres=sttt_xres/2;
-		var->xres_virtual=sttt_xres_virtual/2;
-		var->yres=tt_yres;
-		var->bits_per_pixel=8;
-		break;
-	case TT_SHIFTER_TTMID:
-		var->xres=sttt_xres;
-		var->xres_virtual=sttt_xres_virtual;
-		var->yres=tt_yres;
-		var->bits_per_pixel=4;
-		break;
-	case TT_SHIFTER_TTHIGH:
-		var->red.length=0;
-		var->xres=sttt_xres*2;
-		var->xres_virtual=sttt_xres_virtual*2;
-		var->yres=tt_yres*2;
-		var->bits_per_pixel=1;
-		break;
-	}		
-	var->blue=var->green=var->red;
-	var->transp.offset=0;
-	var->transp.length=0;
-	var->transp.msb_right=0;
-	linelen=var->xres_virtual * var->bits_per_pixel / 8;
-	if (! use_hwscroll)
-		var->yres_virtual=var->yres;
-	else if (screen_len)
-		if (par->yres_virtual)
-			var->yres_virtual = par->yres_virtual;
-		else
-			/* yres_virtual==0 means use maximum */
-			var->yres_virtual = screen_len / linelen;
-	else {
-		if (hwscroll < 0)
-			var->yres_virtual = 2 * var->yres;
-		else
-			var->yres_virtual=var->yres+hwscroll * 16;
-	}
-	var->xoffset=0;
-	if (screen_base)
-		var->yoffset=(par->screen_base - screen_base)/linelen;
-	else
-		var->yoffset=0;
-	var->nonstd=0;
-	var->activate=0;
-	var->vmode=FB_VMODE_NONINTERLACED;
-	for (i=0; i<arraysize(var->reserved); i++)
-		var->reserved[i]=0;
-	return 0;
-}
-
-
-static void tt_get_par( struct atari_fb_par *par )
-{
-	unsigned long addr;
-	par->hw.tt.mode=shifter_tt.tt_shiftmode;
-	par->hw.tt.sync=shifter.syncmode;
-	addr = ((shifter.bas_hi & 0xff) << 16) |
-	       ((shifter.bas_md & 0xff) << 8)  |
-	       ((shifter.bas_lo & 0xff));
-	par->screen_base = PTOV(addr);
-}
-
-static void tt_set_par( struct atari_fb_par *par )
-{
-	shifter_tt.tt_shiftmode=par->hw.tt.mode;
-	shifter.syncmode=par->hw.tt.sync;
-	/* only set screen_base if really necessary */
-	if (current_par.screen_base != par->screen_base)
-		fbhw->set_screen_base(par->screen_base);
-}
-
-
-static int tt_getcolreg( unsigned regno, unsigned *red,
-						 unsigned *green, unsigned *blue,
-						 unsigned *transp )
-{
-	if ((shifter_tt.tt_shiftmode & TT_SHIFTER_MODEMASK) == TT_SHIFTER_STHIGH)
-		regno += 254;
-	if (regno > 255)
-		return 1;
-	*blue = tt_palette[regno];
-	*green = (*blue >> 4) & 0xf;
-	*red = (*blue >> 8) & 0xf;
-	*blue &= 0xf;
-	*transp = 0;
-	return 0;
-}
-
-
-static int tt_setcolreg( unsigned regno, unsigned red,
-						 unsigned green, unsigned blue,
-						 unsigned transp )
-{
-	if ((shifter_tt.tt_shiftmode & TT_SHIFTER_MODEMASK) == TT_SHIFTER_STHIGH)
-		regno += 254;
-	if (regno > 255)
-		return 1;
-	tt_palette[regno] = (red << 8) | (green << 4) | blue;
-	if ((shifter_tt.tt_shiftmode & TT_SHIFTER_MODEMASK) ==
-		TT_SHIFTER_STHIGH && regno == 254)
-		tt_palette[0] = 0;
-	return 0;
-}
-
-						  
-static int tt_detect( void )
-
-{	struct atari_fb_par par;
-
-	/* Determine the connected monitor: The DMA sound must be
-	 * disabled before reading the MFP GPIP, because the Sound
-	 * Done Signal and the Monochrome Detect are XORed together!
-	 *
-	 * Even on a TT, we should look if there is a DMA sound. It was
-	 * announced that the Eagle is TT compatible, but only the PCM is
-	 * missing...
-	 */
-	if (ATARIHW_PRESENT(PCM_8BIT)) { 
-		tt_dmasnd.ctrl = DMASND_CTRL_OFF;
-		udelay(20);	/* wait a while for things to settle down */
-	}
-	mono_moni = (mfp.par_dt_reg & 0x80) == 0;
-
-	tt_get_par(&par);
-	tt_encode_var(&atari_fb_predefined[0], &par);
-
-	return 1;
-}
-
-#endif /* ATAFB_TT */
-
-/* ------------------- Falcon specific functions ---------------------- */
-
-#ifdef ATAFB_FALCON
-
-static int mon_type;		/* Falcon connected monitor */
-static int f030_bus_width;	/* Falcon ram bus width (for vid_control) */
-#define F_MON_SM	0
-#define F_MON_SC	1
-#define F_MON_VGA	2
-#define F_MON_TV	3
-
-/* Multisync monitor capabilities */
-/* Atari-TOS defaults if no boot option present */
-static long vfmin=58, vfmax=62, hfmin=31000, hfmax=32000;
-
-static struct pixel_clock {
-	unsigned long f;	/* f/[Hz] */
-	unsigned long t;	/* t/[ps] (=1/f) */
-	int right, hsync, left;	/* standard timing in clock cycles, not pixel */
-		/* hsync initialized in falcon_detect() */
-	int sync_mask;		/* or-mask for hw.falcon.sync to set this clock */
-	int control_mask;	/* ditto, for hw.falcon.vid_control */
-}
-f25  = {25175000, 39721, 18, 0, 42, 0x0, VCO_CLOCK25},
-f32  = {32000000, 31250, 18, 0, 42, 0x0, 0},
-fext = {       0,     0, 18, 0, 42, 0x1, 0};
-
-/* VIDEL-prescale values [mon_type][pixel_length from VCO] */
-static int vdl_prescale[4][3] = {{4,2,1}, {4,2,1}, {4,2,2}, {4,2,1}};
-
-/* Default hsync timing [mon_type] in picoseconds */
-static long h_syncs[4] = {3000000, 4875000, 4000000, 4875000};
-
-
-static inline int hxx_prescale(struct falcon_hw *hw)
-{
-	return hw->ste_mode ? 16 :
-		   vdl_prescale[mon_type][hw->vid_mode >> 2 & 0x3];
-}
-
-static int falcon_encode_fix( struct fb_fix_screeninfo *fix,
-							  struct atari_fb_par *par )
-{
-	int i;
-
-	strcpy(fix->id, "Atari Builtin");
-	fix->smem_start = real_screen_base;
-	fix->smem_len = screen_len;
-	fix->type = FB_TYPE_INTERLEAVED_PLANES;
-	fix->type_aux = 2;
-	fix->visual = FB_VISUAL_PSEUDOCOLOR;
-	fix->xpanstep = 1;
-	fix->ypanstep = 1;
-	fix->ywrapstep = 0;
-	if (par->hw.falcon.mono) {
-		fix->type = FB_TYPE_PACKED_PIXELS;
-		fix->type_aux = 0;
-		/* no smooth scrolling with longword aligned video mem */
-		fix->xpanstep = 32;
-	}
-	else if (par->hw.falcon.f_shift & 0x100) {
-		fix->type = FB_TYPE_PACKED_PIXELS;
-		fix->type_aux = 0;
-		/* Is this ok or should it be DIRECTCOLOR? */
-		fix->visual = FB_VISUAL_TRUECOLOR;
-		fix->xpanstep = 2;
-	}
-	fix->line_length = 0;
-	for (i=0; i<arraysize(fix->reserved); i++)
-		fix->reserved[i]=0;
-	return 0;
-}
-
-
-static int falcon_decode_var( struct fb_var_screeninfo *var,
-							  struct atari_fb_par *par )
-{
-	int bpp = var->bits_per_pixel;
-	int xres = var->xres;
-	int yres = var->yres;
-	int xres_virtual = var->xres_virtual;
-	int yres_virtual = var->yres_virtual;
-	int left_margin, right_margin, hsync_len;
-	int upper_margin, lower_margin, vsync_len;
-	int linelen;
-	int interlace = 0, doubleline = 0;
-	struct pixel_clock *pclock;
-	int plen; /* width of pixel in clock cycles */
-	int xstretch;
-	int prescale;
-	int longoffset = 0;
-	int hfreq, vfreq;
-
-/*
-	Get the video params out of 'var'. If a value doesn't fit, round
-	it up, if it's too big, return EINVAL.
-	Round up in the following order: bits_per_pixel, xres, yres, 
-	xres_virtual, yres_virtual, xoffset, yoffset, grayscale, bitfields, 
-	horizontal timing, vertical timing.
-
-	There is a maximum of screen resolution determined by pixelclock
-	and minimum frame rate -- (X+hmarg.)*(Y+vmarg.)*vfmin <= pixelclock.
-	In interlace mode this is     "     *    "     *vfmin <= pixelclock.
-	Additional constraints: hfreq.
-	Frequency range for multisync monitors is given via command line.
-	For TV and SM124 both frequencies are fixed.
-
-	X % 16 == 0 to fit 8x?? font (except 1 bitplane modes must use X%32==0)
-	Y % 16 == 0 to fit 8x16 font
-	Y % 8 == 0 if Y<400
-
-	Currently interlace and doubleline mode in var are ignored. 
-	On SM124 and TV only the standard resolutions can be used.
-*/
-
-	/* Reject uninitialized mode */
-	if (!xres || !yres || !bpp)
-		return -EINVAL;
-
-	if (mon_type == F_MON_SM && bpp != 1) {
-		return -EINVAL;
-	}
-	else if (bpp <= 1) {
-		bpp = 1;
-		par->hw.falcon.f_shift = 0x400;
-		par->hw.falcon.st_shift = 0x200;
-	}
-	else if (bpp <= 2) {
-		bpp = 2;
-		par->hw.falcon.f_shift = 0x000;
-		par->hw.falcon.st_shift = 0x100;
-	}
-	else if (bpp <= 4) {
-		bpp = 4;
-		par->hw.falcon.f_shift = 0x000;
-		par->hw.falcon.st_shift = 0x000;
-	}
-	else if (bpp <= 8) {
-		bpp = 8;
-		par->hw.falcon.f_shift = 0x010;
-	}
-	else if (bpp <= 16) {
-		bpp = 16; /* packed pixel mode */
-		par->hw.falcon.f_shift = 0x100; /* hicolor, no overlay */
-	}
-	else
-		return -EINVAL;
-	par->hw.falcon.bpp = bpp;
-
-	if (mon_type == F_MON_SM || DontCalcRes) {
-		/* Skip all calculations. VGA/TV/SC1224 only supported. */
-		struct fb_var_screeninfo *myvar = &atari_fb_predefined[0];
-		
-		if (bpp > myvar->bits_per_pixel ||
-			var->xres > myvar->xres ||
-			var->yres > myvar->yres)
-			return -EINVAL;
-		fbhw->get_par(par);	/* Current par will be new par */
-		goto set_screen_base;	/* Don't forget this */
-	}
-
-	/* Only some fixed resolutions < 640x400 */
-	if (xres <= 320)
-		xres = 320;
-	else if (xres <= 640 && bpp != 16)
-		xres = 640;
-	if (yres <= 200)
-		yres = 200;
-	else if (yres <= 240)
-		yres = 240;
-	else if (yres <= 400)
-		yres = 400;
-
-	/* 2 planes must use STE compatibility mode */
-	par->hw.falcon.ste_mode = bpp==2;
-	par->hw.falcon.mono = bpp==1;
-
-	/* Total and visible scanline length must be a multiple of one longword,
-	 * this and the console fontwidth yields the alignment for xres and
-	 * xres_virtual.
-	 * TODO: this way "odd" fontheights are not supported
-	 *
-	 * Special case in STE mode: blank and graphic positions don't align,
-	 * avoid trash at right margin
-	 */
-	if (par->hw.falcon.ste_mode)
-		xres = (xres + 63) & ~63;
-	else if (bpp == 1)
-		xres = (xres + 31) & ~31;
-	else
-		xres = (xres + 15) & ~15;
-	if (yres >= 400)
-		yres = (yres + 15) & ~15;
-	else
-		yres = (yres + 7) & ~7;
-
-	if (xres_virtual < xres)
-		xres_virtual = xres;
-	else if (bpp == 1)
-		xres_virtual = (xres_virtual + 31) & ~31;
-	else
-		xres_virtual = (xres_virtual + 15) & ~15;
-
-	if (yres_virtual <= 0)
-		yres_virtual = 0;
-	else if (yres_virtual < yres)
-		yres_virtual = yres;
-
-	/* backward bug-compatibility */
-	if (var->pixclock > 1)
-		var->pixclock -= 1;
-
-	par->hw.falcon.line_width = bpp * xres / 16;
-	par->hw.falcon.line_offset = bpp * (xres_virtual - xres) / 16;
-
-	/* single or double pixel width */
-	xstretch = (xres < 640) ? 2 : 1;
-
-#if 0 /* SM124 supports only 640x400, this is rejected above */
-	if (mon_type == F_MON_SM) {
-		if (xres != 640 && yres != 400)
-			return -EINVAL;
-		plen = 1;
-		pclock = &f32;
-		/* SM124-mode is special */
-		par->hw.falcon.ste_mode = 1;
-		par->hw.falcon.f_shift = 0x000;
-		par->hw.falcon.st_shift = 0x200;
-		left_margin = hsync_len = 128 / plen;
-		right_margin = 0;
-		/* TODO set all margins */
-	}
-	else
-#endif
-	if (mon_type == F_MON_SC || mon_type == F_MON_TV) {
-		plen = 2 * xstretch;
-		if (var->pixclock > f32.t * plen)
-			return -EINVAL;
-		pclock = &f32;
-		if (yres > 240)
-			interlace = 1;
-		if (var->pixclock == 0) {
-			/* set some minimal margins which center the screen */
-			left_margin = 32;
-			right_margin = 18;
-			hsync_len = pclock->hsync / plen;
-			upper_margin = 31;
-			lower_margin = 14;
-			vsync_len = interlace ? 3 : 4;
-		} else {
-			left_margin = var->left_margin;
-			right_margin = var->right_margin;
-			hsync_len = var->hsync_len;
-			upper_margin = var->upper_margin;
-			lower_margin = var->lower_margin;
-			vsync_len = var->vsync_len;
-			if (var->vmode & FB_VMODE_INTERLACED) {
-				upper_margin = (upper_margin + 1) / 2;
-				lower_margin = (lower_margin + 1) / 2;
-				vsync_len = (vsync_len + 1) / 2;
-			} else if (var->vmode & FB_VMODE_DOUBLE) {
-				upper_margin *= 2;
-				lower_margin *= 2;
-				vsync_len *= 2;
-			}
-		}
-	}
-	else
-	{	/* F_MON_VGA */
-		if (bpp == 16)
-			xstretch = 2; /* Double pixel width only for hicolor */
-		/* Default values are used for vert./hor. timing if no pixelclock given. */
-		if (var->pixclock == 0) {
-			int linesize;
-
-			/* Choose master pixelclock depending on hor. timing */
-			plen = 1 * xstretch;
-			if ((plen * xres + f25.right+f25.hsync+f25.left) * hfmin < f25.f)
-				pclock = &f25;
-			else if ((plen * xres + f32.right+f32.hsync+f32.left) * hfmin < f32.f)
-				pclock = &f32;
-			else if ((plen * xres + fext.right+fext.hsync+fext.left) * hfmin < fext.f
-			         && fext.f)
-				pclock = &fext;
-			else
-				return -EINVAL;
-
-			left_margin = pclock->left / plen;
-			right_margin = pclock->right / plen;
-			hsync_len = pclock->hsync / plen;
-			linesize = left_margin + xres + right_margin + hsync_len;
-			upper_margin = 31;
-			lower_margin = 11;
-			vsync_len = 3;
-		}
-		else {
-			/* Choose largest pixelclock <= wanted clock */
-			int i;
-			unsigned long pcl = ULONG_MAX;
-			pclock = 0;
-			for (i=1; i <= 4; i *= 2) {
-				if (f25.t*i >= var->pixclock && f25.t*i < pcl) {
-					pcl = f25.t * i;
-					pclock = &f25;
-				}
-				if (f32.t*i >= var->pixclock && f32.t*i < pcl) {
-					pcl = f32.t * i;
-					pclock = &f32;
-				}
-				if (fext.t && fext.t*i >= var->pixclock && fext.t*i < pcl) {
-					pcl = fext.t * i;
-					pclock = &fext;
-				}
-			}
-			if (!pclock)
-				return -EINVAL;
-			plen = pcl / pclock->t;
-
-			left_margin = var->left_margin;
-			right_margin = var->right_margin;
-			hsync_len = var->hsync_len;
-			upper_margin = var->upper_margin;
-			lower_margin = var->lower_margin;
-			vsync_len = var->vsync_len;
-			/* Internal unit is [single lines per (half-)frame] */
-			if (var->vmode & FB_VMODE_INTERLACED) {
-				/* # lines in half frame */
-				/* External unit is [lines per full frame] */
-				upper_margin = (upper_margin + 1) / 2;
-				lower_margin = (lower_margin + 1) / 2;
-				vsync_len = (vsync_len + 1) / 2;
-			}
-			else if (var->vmode & FB_VMODE_DOUBLE) {
-				/* External unit is [double lines per frame] */
-				upper_margin *= 2;
-				lower_margin *= 2;
-				vsync_len *= 2;
-			}
-		}
-		if (pclock == &fext)
-			longoffset = 1; /* VIDEL doesn't synchronize on short offset */
-	}
-	/* Is video bus bandwidth (32MB/s) too low for this resolution? */
-	/* this is definitely wrong if bus clock != 32MHz */
-	if (pclock->f / plen / 8 * bpp > 32000000L)
-		return -EINVAL;
-
-	if (vsync_len < 1)
-		vsync_len = 1;
-
-	/* include sync lengths in right/lower margin for all calculations */
-	right_margin += hsync_len;
-	lower_margin += vsync_len;
-
-	/* ! In all calculations of margins we use # of lines in half frame
-	 * (which is a full frame in non-interlace mode), so we can switch
-	 * between interlace and non-interlace without messing around
-	 * with these.
-	 */
-  again:
-	/* Set base_offset 128 and video bus width */
-	par->hw.falcon.vid_control = mon_type | f030_bus_width;
-	if (!longoffset)
-		par->hw.falcon.vid_control |= VCO_SHORTOFFS;	/* base_offset 64 */
-	if (var->sync & FB_SYNC_HOR_HIGH_ACT)
-		par->hw.falcon.vid_control |= VCO_HSYPOS;
-	if (var->sync & FB_SYNC_VERT_HIGH_ACT)
-		par->hw.falcon.vid_control |= VCO_VSYPOS;
-	/* Pixelclock */
-	par->hw.falcon.vid_control |= pclock->control_mask;
-	/* External or internal clock */
-	par->hw.falcon.sync = pclock->sync_mask | 0x2;
-	/* Pixellength and prescale */
-	par->hw.falcon.vid_mode = (2/plen) << 2;
-	if (doubleline)
-		par->hw.falcon.vid_mode |= VMO_DOUBLE;
-	if (interlace)
-		par->hw.falcon.vid_mode |= VMO_INTER;
-
-	/*********************
-	Horizontal timing: unit = [master clock cycles]
-	unit of hxx-registers: [master clock cycles * prescale]
-	Hxx-registers are 9 bit wide
-
-	1 line = ((hht + 2) * 2 * prescale) clock cycles
-
-	graphic output = hdb & 0x200 ?
-	       ((hht+2)*2 - hdb + hde) * prescale - hdboff + hdeoff:
-	       ( hht + 2  - hdb + hde) * prescale - hdboff + hdeoff
-	(this must be a multiple of plen*128/bpp, on VGA pixels
-	 to the right may be cut off with a bigger right margin)
-
-	start of graphics relative to start of 1st halfline = hdb & 0x200 ?
-	       (hdb - hht - 2) * prescale + hdboff :
-	       hdb * prescale + hdboff
-
-	end of graphics relative to start of 1st halfline =
-	       (hde + hht + 2) * prescale + hdeoff
-	*********************/
-	/* Calculate VIDEL registers */
-	{
-	int hdb_off, hde_off, base_off;
-	int gstart, gend1, gend2, align;
-
-	prescale = hxx_prescale(&par->hw.falcon);
-	base_off = par->hw.falcon.vid_control & VCO_SHORTOFFS ? 64 : 128;
-
-	/* Offsets depend on video mode */
-	/* Offsets are in clock cycles, divide by prescale to
-	 * calculate hd[be]-registers
-	 */
-	if (par->hw.falcon.f_shift & 0x100) {
-		align = 1;
-		hde_off = 0;
-		hdb_off = (base_off + 16 * plen) + prescale;
-	}
-	else {
-		align = 128 / bpp;
-		hde_off = ((128 / bpp + 2) * plen);
-		if (par->hw.falcon.ste_mode)
-			hdb_off = (64 + base_off + (128 / bpp + 2) * plen) + prescale;
-		else
-			hdb_off = (base_off + (128 / bpp + 18) * plen) + prescale;
-	}
-
-	gstart = (prescale/2 + plen * left_margin) / prescale;
-	/* gend1 is for hde (gend-gstart multiple of align), shifter's xres */
-	gend1 = gstart + ((xres + align-1) / align)*align * plen / prescale;
-	/* gend2 is for hbb, visible xres (rest to gend1 is cut off by hblank) */
-	gend2 = gstart + xres * plen / prescale;
-	par->HHT = plen * (left_margin + xres + right_margin) /
-			   (2 * prescale) - 2;
-/*	par->HHT = (gend2 + plen * right_margin / prescale) / 2 - 2;*/
-
-	par->HDB = gstart - hdb_off/prescale;
-	par->HBE = gstart;
-	if (par->HDB < 0) par->HDB += par->HHT + 2 + 0x200;
-	par->HDE = gend1 - par->HHT - 2 - hde_off/prescale;
-	par->HBB = gend2 - par->HHT - 2;
-#if 0
-	/* One more Videl constraint: data fetch of two lines must not overlap */
-	if (par->HDB & 0x200  &&  par->HDB & ~0x200 - par->HDE <= 5) {
-		/* if this happens increase margins, decrease hfreq. */
-	}
-#endif
-	if (hde_off % prescale)
-		par->HBB++;		/* compensate for non matching hde and hbb */
-	par->HSS = par->HHT + 2 - plen * hsync_len / prescale;
-	if (par->HSS < par->HBB)
-		par->HSS = par->HBB;
-	}
-
-	/*  check hor. frequency */
-	hfreq = pclock->f / ((par->HHT+2)*prescale*2);
-	if (hfreq > hfmax && mon_type!=F_MON_VGA) {
-		/* ++guenther:   ^^^^^^^^^^^^^^^^^^^ can't remember why I did this */
-		/* Too high -> enlarge margin */
-		left_margin += 1;
-		right_margin += 1;
-		goto again;
-	}
-	if (hfreq > hfmax || hfreq < hfmin)
-		return -EINVAL;
-
-	/* Vxx-registers */
-	/* All Vxx must be odd in non-interlace, since frame starts in the middle
-	 * of the first displayed line!
-	 * One frame consists of VFT+1 half lines. VFT+1 must be even in
-	 * non-interlace, odd in interlace mode for synchronisation.
-	 * Vxx-registers are 11 bit wide
-	 */
-	par->VBE = (upper_margin * 2 + 1); /* must begin on odd halfline */
-	par->VDB = par->VBE;
-	par->VDE = yres;
-	if (!interlace) par->VDE <<= 1;
-	if (doubleline) par->VDE <<= 1;  /* VDE now half lines per (half-)frame */
-	par->VDE += par->VDB;
-	par->VBB = par->VDE;
-	par->VFT = par->VBB + (lower_margin * 2 - 1) - 1;
-	par->VSS = par->VFT+1 - (vsync_len * 2 - 1);
-	/* vbb,vss,vft must be even in interlace mode */
-	if (interlace) {
-		par->VBB++;
-		par->VSS++;
-		par->VFT++;
-	}
-
-	/* V-frequency check, hope I didn't create any loop here. */
-	/* Interlace and doubleline are mutually exclusive. */
-	vfreq = (hfreq * 2) / (par->VFT + 1);
-	if      (vfreq > vfmax && !doubleline && !interlace) {
-		/* Too high -> try again with doubleline */
-		doubleline = 1;
-		goto again;
-	}
-	else if (vfreq < vfmin && !interlace && !doubleline) {
-		/* Too low -> try again with interlace */
-		interlace = 1;
-		goto again;
-	}
-	else if (vfreq < vfmin && doubleline) {
-		/* Doubleline too low -> clear doubleline and enlarge margins */
-		int lines;
-		doubleline = 0;
-		for (lines=0; (hfreq*2)/(par->VFT+1+4*lines-2*yres)>vfmax; lines++)
-			;
-		upper_margin += lines;
-		lower_margin += lines;
-		goto again;
-	}
-	else if (vfreq > vfmax && doubleline) {
-		/* Doubleline too high -> enlarge margins */
-		int lines;
-		for (lines=0; (hfreq*2)/(par->VFT+1+4*lines)>vfmax; lines+=2)
-			;
-		upper_margin += lines;
-		lower_margin += lines;
-		goto again;
-	}
-	else if (vfreq > vfmax && interlace) {
-		/* Interlace, too high -> enlarge margins */
-		int lines;
-		for (lines=0; (hfreq*2)/(par->VFT+1+4*lines)>vfmax; lines++)
-			;
-		upper_margin += lines;
-		lower_margin += lines;
-		goto again;
-	}
-	else if (vfreq < vfmin || vfreq > vfmax)
-		return -EINVAL;
-
-  set_screen_base:
-	linelen = xres_virtual * bpp / 8;
-	if (yres_virtual * linelen > screen_len && screen_len)
-		return -EINVAL;
-	if (yres * linelen > screen_len && screen_len)
-		return -EINVAL;
-	if (var->yoffset + yres > yres_virtual && yres_virtual)
-		return -EINVAL;
-	par->yres_virtual = yres_virtual;
-	par->screen_base = screen_base + var->yoffset * linelen;
-	par->hw.falcon.xoffset = 0;
-
-	return 0;
-}
-
-static int falcon_encode_var( struct fb_var_screeninfo *var,
-							  struct atari_fb_par *par )
-{
-/* !!! only for VGA !!! */
-	int linelen, i;
-	int prescale, plen;
-	int hdb_off, hde_off, base_off;
-	struct falcon_hw *hw = &par->hw.falcon;
-
-	/* possible frequencies: 25.175 or 32MHz */
-	var->pixclock = hw->sync & 0x1 ? fext.t :
-	                hw->vid_control & VCO_CLOCK25 ? f25.t : f32.t;
-
-	var->height=-1;
-	var->width=-1;
-
-	var->sync=0;
-	if (hw->vid_control & VCO_HSYPOS)
-		var->sync |= FB_SYNC_HOR_HIGH_ACT;
-	if (hw->vid_control & VCO_VSYPOS)
-		var->sync |= FB_SYNC_VERT_HIGH_ACT;
-
-	var->vmode = FB_VMODE_NONINTERLACED;
-	if (hw->vid_mode & VMO_INTER)
-		var->vmode |= FB_VMODE_INTERLACED;
-	if (hw->vid_mode & VMO_DOUBLE)
-		var->vmode |= FB_VMODE_DOUBLE;
-	
-	/* visible y resolution:
-	 * Graphics display starts at line VDB and ends at line
-	 * VDE. If interlace mode off unit of VC-registers is
-	 * half lines, else lines.
-	 */
-	var->yres = hw->vde - hw->vdb;
-	if (!(var->vmode & FB_VMODE_INTERLACED))
-		var->yres >>= 1;
-	if (var->vmode & FB_VMODE_DOUBLE)
-		var->yres >>= 1;
-
-	/* to get bpp, we must examine f_shift and st_shift.
-	 * f_shift is valid if any of bits no. 10, 8 or 4
-	 * is set. Priority in f_shift is: 10 ">" 8 ">" 4, i.e.
-	 * if bit 10 set then bit 8 and bit 4 don't care...
-	 * If all these bits are 0 get display depth from st_shift
-	 * (as for ST and STE)
-	 */
-	if (hw->f_shift & 0x400)		/* 2 colors */
-		var->bits_per_pixel = 1;
-	else if (hw->f_shift & 0x100)	/* hicolor */
-		var->bits_per_pixel = 16;
-	else if (hw->f_shift & 0x010)	/* 8 bitplanes */
-		var->bits_per_pixel = 8;
-	else if (hw->st_shift == 0)
-		var->bits_per_pixel = 4;
-	else if (hw->st_shift == 0x100)
-		var->bits_per_pixel = 2;
-	else /* if (hw->st_shift == 0x200) */
-		var->bits_per_pixel = 1;
-
-	var->xres = hw->line_width * 16 / var->bits_per_pixel;
-	var->xres_virtual = var->xres + hw->line_offset * 16 / var->bits_per_pixel;
-	if (hw->xoffset)
-		var->xres_virtual += 16;
-
-	if (var->bits_per_pixel == 16) {
-		var->red.offset=11;
-		var->red.length=5;
-		var->red.msb_right=0;
-		var->green.offset=5;
-		var->green.length=6;
-		var->green.msb_right=0;
-		var->blue.offset=0;
-		var->blue.length=5;
-		var->blue.msb_right=0;
-	}
-	else {
-		var->red.offset=0;
-		var->red.length = hw->ste_mode ? 4 : 6;
-		var->red.msb_right=0;
-		var->grayscale=0;
-		var->blue=var->green=var->red;
-	}
-	var->transp.offset=0;
-	var->transp.length=0;
-	var->transp.msb_right=0;
-
-	linelen = var->xres_virtual * var->bits_per_pixel / 8;
-	if (screen_len)
-		if (par->yres_virtual)
-			var->yres_virtual = par->yres_virtual;
-		else
-			/* yres_virtual==0 means use maximum */
-			var->yres_virtual = screen_len / linelen;
-	else {
-		if (hwscroll < 0)
-			var->yres_virtual = 2 * var->yres;
-		else
-			var->yres_virtual=var->yres+hwscroll * 16;
-	}
-	var->xoffset=0; /* TODO change this */
-
-	/* hdX-offsets */
-	prescale = hxx_prescale(hw);
-	plen = 4 >> (hw->vid_mode >> 2 & 0x3);
-	base_off = hw->vid_control & VCO_SHORTOFFS ? 64 : 128;
-	if (hw->f_shift & 0x100) {
-		hde_off = 0;
-		hdb_off = (base_off + 16 * plen) + prescale;
-	}
-	else {
-		hde_off = ((128 / var->bits_per_pixel + 2) * plen);
-		if (hw->ste_mode)
-			hdb_off = (64 + base_off + (128 / var->bits_per_pixel + 2) * plen)
-					 + prescale;
-		else
-			hdb_off = (base_off + (128 / var->bits_per_pixel + 18) * plen)
-					 + prescale;
-	}
-
-	/* Right margin includes hsync */
-	var->left_margin = hdb_off + prescale * ((hw->hdb & 0x1ff) -
-					   (hw->hdb & 0x200 ? 2+hw->hht : 0));
-	if (hw->ste_mode || mon_type!=F_MON_VGA)
-		var->right_margin = prescale * (hw->hht + 2 - hw->hde) - hde_off;
-	else
-		/* can't use this in ste_mode, because hbb is +1 off */
-		var->right_margin = prescale * (hw->hht + 2 - hw->hbb);
-	var->hsync_len = prescale * (hw->hht + 2 - hw->hss);
-
-	/* Lower margin includes vsync */
-	var->upper_margin = hw->vdb / 2 ;  /* round down to full lines */
-	var->lower_margin = (hw->vft+1 - hw->vde + 1) / 2; /* round up */
-	var->vsync_len    = (hw->vft+1 - hw->vss + 1) / 2; /* round up */
-	if (var->vmode & FB_VMODE_INTERLACED) {
-		var->upper_margin *= 2;
-		var->lower_margin *= 2;
-		var->vsync_len *= 2;
-	}
-	else if (var->vmode & FB_VMODE_DOUBLE) {
-		var->upper_margin = (var->upper_margin + 1) / 2;
-		var->lower_margin = (var->lower_margin + 1) / 2;
-		var->vsync_len = (var->vsync_len + 1) / 2;
-	}
-
-	var->pixclock *= plen;
-	var->left_margin /= plen;
-	var->right_margin /= plen;
-	var->hsync_len /= plen;
-
-	var->right_margin -= var->hsync_len;
-	var->lower_margin -= var->vsync_len;
-
-	if (screen_base)
-		var->yoffset=(par->screen_base - screen_base)/linelen;
-	else
-		var->yoffset=0;
-	var->nonstd=0;	/* what is this for? */
-	var->activate=0;
-	for (i=0; i<arraysize(var->reserved); i++)
-		var->reserved[i]=0;
-	return 0;
-}
-
-
-static int f_change_mode = 0;
-static struct falcon_hw f_new_mode;
-static int f_pan_display = 0;
-
-static void falcon_get_par( struct atari_fb_par *par )
-{
-	unsigned long addr;
-	struct falcon_hw *hw = &par->hw.falcon;
-
-	hw->line_width = shifter_f030.scn_width;
-	hw->line_offset = shifter_f030.off_next;
-	hw->st_shift = videl.st_shift & 0x300;
-	hw->f_shift = videl.f_shift;
-	hw->vid_control = videl.control;
-	hw->vid_mode = videl.mode;
-	hw->sync = shifter.syncmode & 0x1;
-	hw->xoffset = videl.xoffset & 0xf;
-	hw->hht = videl.hht;
-	hw->hbb = videl.hbb;
-	hw->hbe = videl.hbe;
-	hw->hdb = videl.hdb;
-	hw->hde = videl.hde;
-	hw->hss = videl.hss;
-	hw->vft = videl.vft;
-	hw->vbb = videl.vbb;
-	hw->vbe = videl.vbe;
-	hw->vdb = videl.vdb;
-	hw->vde = videl.vde;
-	hw->vss = videl.vss;
-
-	addr = (shifter.bas_hi & 0xff) << 16 |
-	       (shifter.bas_md & 0xff) << 8  |
-	       (shifter.bas_lo & 0xff);
-	par->screen_base = PTOV(addr);
-
-	/* derived parameters */
-	hw->ste_mode = (hw->f_shift & 0x510)==0 && hw->st_shift==0x100;
-	hw->mono = (hw->f_shift & 0x400) ||
-	           ((hw->f_shift & 0x510)==0 && hw->st_shift==0x200);
-}
-
-static void falcon_set_par( struct atari_fb_par *par )
-{
-	f_change_mode = 0;
-
-	/* only set screen_base if really necessary */
-	if (current_par.screen_base != par->screen_base)
-		fbhw->set_screen_base(par->screen_base);
-
-	/* Don't touch any other registers if we keep the default resolution */
-	if (DontCalcRes)
-		return;
-
-	/* Tell vbl-handler to change video mode.
-	 * We change modes only on next VBL, to avoid desynchronisation
-	 * (a shift to the right and wrap around by a random number of pixels
-	 * in all monochrome modes).
-	 * This seems to work on my Falcon.
-	 */
-	f_new_mode = par->hw.falcon;
-	f_change_mode = 1;
-}
-
-
-static void falcon_vbl_switcher( int irq, void *dummy, struct pt_regs *fp )
-{
-	struct falcon_hw *hw = &f_new_mode;
-
-	if (f_change_mode) {
-		f_change_mode = 0;
-
-		if (hw->sync & 0x1) {
-			/* Enable external pixelclock. This code only for ScreenWonder */
-			*(volatile unsigned short*)0xffff9202 = 0xffbf;
-		}
-		else {
-			/* Turn off external clocks. Read sets all output bits to 1. */
-			*(volatile unsigned short*)0xffff9202;
-		}
-		shifter.syncmode = hw->sync;
-
-		videl.hht = hw->hht;
-		videl.hbb = hw->hbb;
-		videl.hbe = hw->hbe;
-		videl.hdb = hw->hdb;
-		videl.hde = hw->hde;
-		videl.hss = hw->hss;
-		videl.vft = hw->vft;
-		videl.vbb = hw->vbb;
-		videl.vbe = hw->vbe;
-		videl.vdb = hw->vdb;
-		videl.vde = hw->vde;
-		videl.vss = hw->vss;
-
-		videl.f_shift = 0; /* write enables Falcon palette, 0: 4 planes */
-		if (hw->ste_mode) {
-			videl.st_shift = hw->st_shift; /* write enables STE palette */
-		}
-		else {
-			/* IMPORTANT:
-			 * set st_shift 0, so we can tell the screen-depth if f_shift==0.
-			 * Writing 0 to f_shift enables 4 plane Falcon mode but
-			 * doesn't set st_shift. st_shift!=0 (!=4planes) is impossible
-			 * with Falcon palette.
-			 */
-			videl.st_shift = 0;
-			/* now back to Falcon palette mode */
-			videl.f_shift = hw->f_shift;
-		}
-		/* writing to st_shift changed scn_width and vid_mode */
-		videl.xoffset = hw->xoffset;
-		shifter_f030.scn_width = hw->line_width;
-		shifter_f030.off_next = hw->line_offset;
-		videl.control = hw->vid_control;
-		videl.mode = hw->vid_mode;
-	}
-	if (f_pan_display) {
-		f_pan_display = 0;
-		videl.xoffset = current_par.hw.falcon.xoffset;
-		shifter_f030.off_next = current_par.hw.falcon.line_offset;
-	}
-}
-
-
-static int falcon_pan_display( struct fb_var_screeninfo *var,
-							   struct atari_fb_par *par )
-{
-	int xoffset;
-	int bpp = disp[currcon].var.bits_per_pixel;
-
-	if (bpp == 1)
-		var->xoffset = up(var->xoffset, 32);
-	if (bpp != 16)
-		par->hw.falcon.xoffset = var->xoffset & 15;
-	else {
-		par->hw.falcon.xoffset = 0;
-		var->xoffset = up(var->xoffset, 2);
-	}
-	par->hw.falcon.line_offset = bpp *
-	       	(disp[currcon].var.xres_virtual - disp[currcon].var.xres) / 16;
-	if (par->hw.falcon.xoffset)
-		par->hw.falcon.line_offset -= bpp;
-	xoffset = var->xoffset - par->hw.falcon.xoffset;
-
-	par->screen_base = screen_base +
-	        (var->yoffset * disp[currcon].var.xres_virtual + xoffset) * bpp / 8;
-	if (fbhw->set_screen_base)
-		fbhw->set_screen_base (par->screen_base);
-	else
-		return -EINVAL; /* shouldn't happen */
-	f_pan_display = 1;
-	return 0;
-}
-
-
-static int falcon_getcolreg( unsigned regno, unsigned *red,
-				 unsigned *green, unsigned *blue,
-				 unsigned *transp )
-{	unsigned long col;
-	
-	if (regno > 255)
-		return 1;
-	/* This works in STE-mode (with 4bit/color) since f030_col-registers
-	 * hold up to 6bit/color.
-	 * Even with hicolor r/g/b=5/6/5 bit!
-	 */
-	col = f030_col[regno];
-	*red = (col >> 26) & 0x3f;
-	*green = (col >> 18) & 0x3f;
-	*blue = (col >> 2) & 0x3f;
-	*transp = 0;
-	return 0;
-}
-
-
-static int falcon_setcolreg( unsigned regno, unsigned red,
-							 unsigned green, unsigned blue,
-							 unsigned transp )
-{
-	if (regno > 255)
-		return 1;
-	f030_col[regno] = (red << 26) | (green << 18) | (blue << 2);
-	if (regno < 16) {
-		shifter_tt.color_reg[regno] =
-			(((red & 0xe) >> 1) | ((red & 1) << 3) << 8) |
-			(((green & 0xe) >> 1) | ((green & 1) << 3) << 4) |
-			((blue & 0xe) >> 1) | ((blue & 1) << 3);
-		packed16_cmap[regno] = (red << 11) | (green << 5) | blue;
-	}
-	return 0;
-}
-
-
-static int falcon_blank( int blank_mode )
-{
-/* ++guenther: we can switch off graphics by changing VDB and VDE,
- * so VIDEL doesn't hog the bus while saving.
- * (this may affect usleep()).
- */
-	int vdb, vss, hbe, hss;
-
-	if (mon_type == F_MON_SM)	/* this doesn't work on SM124 */
-		return 1;
-
-	vdb = current_par.VDB;
-	vss = current_par.VSS;
-	hbe = current_par.HBE;
-	hss = current_par.HSS;
-
-	if (blank_mode >= 1) {
-		/* disable graphics output (this speeds up the CPU) ... */
-		vdb = current_par.VFT + 1;
-		/* ... and blank all lines */
-		hbe = current_par.HHT + 2;
-	}
-	/* use VESA suspend modes on VGA monitors */
-	if (mon_type == F_MON_VGA) {
-		if (blank_mode == 2 || blank_mode == 4)
-			vss = current_par.VFT + 1;
-		if (blank_mode == 3 || blank_mode == 4)
-			hss = current_par.HHT + 2;
-	}
-
-	videl.vdb = vdb;
-	videl.vss = vss;
-	videl.hbe = hbe;
-	videl.hss = hss;
-
-	return 0;
-}
-
- 
-static int falcon_detect( void )
-{
-	struct atari_fb_par par;
-	unsigned char fhw;
-
-	/* Determine connected monitor and set monitor parameters */
-	fhw = *(unsigned char*)0xffff8006;
-	mon_type = fhw >> 6 & 0x3;
-	/* bit 1 of fhw: 1=32 bit ram bus, 0=16 bit */
-	f030_bus_width = fhw << 6 & 0x80;
-	switch (mon_type) {
-	case F_MON_SM:
-		vfmin = 70;
-		vfmax = 72;
-		hfmin = 35713;
-		hfmax = 35715;
-		break;
-	case F_MON_SC:
-	case F_MON_TV:
-		/* PAL...NTSC */
-		vfmin = 49; /* not 50, since TOS defaults to 49.9x Hz */
-		vfmax = 60;
-		hfmin = 15620;
-		hfmax = 15755;
-		break;
-	}
-	/* initialize hsync-len */
-	f25.hsync = h_syncs[mon_type] / f25.t;
-	f32.hsync = h_syncs[mon_type] / f32.t;
-	if (fext.t)
-		fext.hsync = h_syncs[mon_type] / fext.t;
-
-	falcon_get_par(&par);
-	falcon_encode_var(&atari_fb_predefined[0], &par);
-
-	/* Detected mode is always the "autodetect" slot */
-	return 1;
-}
-
-#endif /* ATAFB_FALCON */
-
-/* ------------------- ST(E) specific functions ---------------------- */
-
-#ifdef ATAFB_STE
-
-static int stste_encode_fix( struct fb_fix_screeninfo *fix,
-							 struct atari_fb_par *par )
-
-{
-	int mode, i;
-
-	strcpy(fix->id,"Atari Builtin");
-	fix->smem_start=real_screen_base;
-	fix->smem_len=screen_len;
-	fix->type=FB_TYPE_INTERLEAVED_PLANES;
-	fix->type_aux=2;
-	fix->visual=FB_VISUAL_PSEUDOCOLOR;
-	mode = par->hw.st.mode & 3;
-	if (mode == ST_HIGH) {
-		fix->type=FB_TYPE_PACKED_PIXELS;
-		fix->type_aux=0;
-		fix->visual=FB_VISUAL_MONO10;
-	}
-	if (ATARIHW_PRESENT(EXTD_SHIFTER)) {
-		fix->xpanstep = 16;
-		fix->ypanstep = 1;
-	} else {
-		fix->xpanstep = 0;
-		fix->ypanstep = 0;
-	}
-	fix->ywrapstep = 0;
-	fix->line_length = 0;
-	for (i=0; i<arraysize(fix->reserved); i++)
-		fix->reserved[i]=0;
-	return 0;
-}
-
-
-static int stste_decode_var( struct fb_var_screeninfo *var,
-						  struct atari_fb_par *par )
-{
-	int xres=var->xres;
-	int yres=var->yres;
-	int bpp=var->bits_per_pixel;
-	int linelen;
-	int yres_virtual = var->yres_virtual;
-
-	if (mono_moni) {
-		if (bpp > 1 || xres > sttt_xres || yres > st_yres)
-			return -EINVAL;
-		par->hw.st.mode=ST_HIGH;
-		xres=sttt_xres;
-		yres=st_yres;
-		bpp=1;
-	} else {
-		if (bpp > 4 || xres > sttt_xres || yres > st_yres)
-			return -EINVAL;
-		if (bpp > 2) {
-			if (xres > sttt_xres/2 || yres > st_yres/2)
-				return -EINVAL;
-			par->hw.st.mode=ST_LOW;
-			xres=sttt_xres/2;
-			yres=st_yres/2;
-			bpp=4;
-		}
-		else if (bpp > 1) {
-			if (xres > sttt_xres || yres > st_yres/2)
-				return -EINVAL;
-			par->hw.st.mode=ST_MID;
-			xres=sttt_xres;
-			yres=st_yres/2;
-			bpp=2;
-		}
-		else
-			return -EINVAL;
-	}
-	if (yres_virtual <= 0)
-		yres_virtual = 0;
-	else if (yres_virtual < yres)
-		yres_virtual = yres;
-	if (var->sync & FB_SYNC_EXT)
-		par->hw.st.sync=(par->hw.st.sync & ~1) | 1;
-	else
-		par->hw.st.sync=(par->hw.st.sync & ~1);
-	linelen=xres*bpp/8;
-	if (yres_virtual * linelen > screen_len && screen_len)
-		return -EINVAL;
-	if (yres * linelen > screen_len && screen_len)
-		return -EINVAL;
-	if (var->yoffset + yres > yres_virtual && yres_virtual)
-		return -EINVAL;
-	par->yres_virtual = yres_virtual;
-	par->screen_base=screen_base+ var->yoffset*linelen;
-	return 0;
-}
-
-static int stste_encode_var( struct fb_var_screeninfo *var,
-						  struct atari_fb_par *par )
-{
-	int linelen, i;
-	var->red.offset=0;
-	var->red.length = ATARIHW_PRESENT(EXTD_SHIFTER) ? 4 : 3;
-	var->red.msb_right=0;
-	var->grayscale=0;
-
-	var->pixclock=31041;
-	var->left_margin=120;		/* these are incorrect */
-	var->right_margin=100;
-	var->upper_margin=8;
-	var->lower_margin=16;
-	var->hsync_len=140;
-	var->vsync_len=30;
-
-	var->height=-1;
-	var->width=-1;
-
-	if (!(par->hw.st.sync & 1))
-		var->sync=0;
-	else
-		var->sync=FB_SYNC_EXT;
-
-	switch (par->hw.st.mode & 3) {
-	case ST_LOW:
-		var->xres=sttt_xres/2;
-		var->yres=st_yres/2;
-		var->bits_per_pixel=4;
-		break;
-	case ST_MID:
-		var->xres=sttt_xres;
-		var->yres=st_yres/2;
-		var->bits_per_pixel=2;
-		break;
-	case ST_HIGH:
-		var->xres=sttt_xres;
-		var->yres=st_yres;
-		var->bits_per_pixel=1;
-		break;
-	}		
-	var->blue=var->green=var->red;
-	var->transp.offset=0;
-	var->transp.length=0;
-	var->transp.msb_right=0;
-	var->xres_virtual=sttt_xres_virtual;
-	linelen=var->xres_virtual * var->bits_per_pixel / 8;
-	ovsc_addlen=linelen*(sttt_yres_virtual - st_yres);
-	
-	if (! use_hwscroll)
-		var->yres_virtual=var->yres;
-	else if (screen_len)
-		if (par->yres_virtual)
-			var->yres_virtual = par->yres_virtual;
-		else
-			/* yres_virtual==0 means use maximum */
-			var->yres_virtual = screen_len / linelen;
-	else {
-		if (hwscroll < 0)
-			var->yres_virtual = 2 * var->yres;
-		else
-			var->yres_virtual=var->yres+hwscroll * 16;
-	}
-	var->xoffset=0;
-	if (screen_base)
-		var->yoffset=(par->screen_base - screen_base)/linelen;
-	else
-		var->yoffset=0;
-	var->nonstd=0;
-	var->activate=0;
-	var->vmode=FB_VMODE_NONINTERLACED;
-	for (i=0; i<arraysize(var->reserved); i++)
-		var->reserved[i]=0;
-	return 0;
-}
-
-
-static void stste_get_par( struct atari_fb_par *par )
-{
-	unsigned long addr;
-	par->hw.st.mode=shifter_tt.st_shiftmode;
-	par->hw.st.sync=shifter.syncmode;
-	addr = ((shifter.bas_hi & 0xff) << 16) |
-	       ((shifter.bas_md & 0xff) << 8);
-	if (ATARIHW_PRESENT(EXTD_SHIFTER))
-		addr |= (shifter.bas_lo & 0xff);
-	par->screen_base = PTOV(addr);
-}
-
-static void stste_set_par( struct atari_fb_par *par )
-{
-	shifter_tt.st_shiftmode=par->hw.st.mode;
-	shifter.syncmode=par->hw.st.sync;
-	/* only set screen_base if really necessary */
-	if (current_par.screen_base != par->screen_base)
-		fbhw->set_screen_base(par->screen_base);
-}
-
-
-static int stste_getcolreg( unsigned regno, unsigned *red,
-							unsigned *green, unsigned *blue,
-							unsigned *transp )
-{	unsigned col;
-	
-	if (regno > 15)
-		return 1;
-	col = shifter_tt.color_reg[regno];
-	if (ATARIHW_PRESENT(EXTD_SHIFTER)) {
-		*red = ((col >> 7) & 0xe) | ((col >> 11) & 1);
-		*green = ((col >> 3) & 0xe) | ((col >> 7) & 1);
-		*blue = ((col << 1) & 0xe) | ((col >> 3) & 1);
-	}
-	else {
-		*red = (col >> 8) & 0x7;
-		*green = (col >> 4) & 0x7;
-		*blue = col & 0x7;
-	}
-	*transp = 0;
-	return 0;
-}
-
-
-static int stste_setcolreg( unsigned regno, unsigned red,
-						 unsigned green, unsigned blue,
-						 unsigned transp )
-{
-	if (regno > 15)
-		return 1;
-	if (ATARIHW_PRESENT(EXTD_SHIFTER))
-		shifter_tt.color_reg[regno] =
-			(((red & 0xe) >> 1) | ((red & 1) << 3) << 8) |
-			(((green & 0xe) >> 1) | ((green & 1) << 3) << 4) |
-			((blue & 0xe) >> 1) | ((blue & 1) << 3);
-	else
-		shifter_tt.color_reg[regno] =
-			((red & 0x7) << 8) |
-			((green & 0x7) << 4) |
-			(blue & 0x7);
-	return 0;
-}
-
-						  
-static int stste_detect( void )
-
-{	struct atari_fb_par par;
-
-	/* Determine the connected monitor: The DMA sound must be
-	 * disabled before reading the MFP GPIP, because the Sound
-	 * Done Signal and the Monochrome Detect are XORed together!
-	 */
-	if (ATARIHW_PRESENT(PCM_8BIT)) {
-		tt_dmasnd.ctrl = DMASND_CTRL_OFF;
-		udelay(20);	/* wait a while for things to settle down */
-	}
-	mono_moni = (mfp.par_dt_reg & 0x80) == 0;
-
-	stste_get_par(&par);
-	stste_encode_var(&atari_fb_predefined[0], &par);
-
-	if (!ATARIHW_PRESENT(EXTD_SHIFTER))
-		use_hwscroll = 0;
-	return 1;
-}
-
-static void stste_set_screen_base(unsigned long s_base)
-{
-	unsigned long addr;
-	addr= VTOP(s_base);
-	/* Setup Screen Memory */
-	shifter.bas_hi=(unsigned char) ((addr & 0xff0000) >> 16);
-  	shifter.bas_md=(unsigned char) ((addr & 0x00ff00) >> 8);
-	if (ATARIHW_PRESENT(EXTD_SHIFTER))
-		shifter.bas_lo=(unsigned char)  (addr & 0x0000ff);
-}
-
-#endif /* ATAFB_STE */
-
-/* Switching the screen size should be done during vsync, otherwise
- * the margins may get messed up. This is a well known problem of
- * the ST's video system.
- *
- * Unfortunately there is hardly any way to find the vsync, as the
- * vertical blank interrupt is no longer in time on machines with
- * overscan type modifications.
- *
- * We can, however, use Timer B to safely detect the black shoulder,
- * but then we've got to guess an appropriate delay to find the vsync.
- * This might not work on every machine.
- *
- * martin_rogge @ ki.maus.de, 8th Aug 1995
- */
-
-#define LINE_DELAY  (mono_moni ? 30 : 70)
-#define SYNC_DELAY  (mono_moni ? 1500 : 2000)
-
-/* SWITCH_ACIA may be used for Falcon (ScreenBlaster III internal!) */
-static void st_ovsc_switch(int switchmode)
-{
-    unsigned long flags;
-    register unsigned char old, new;
-
-    if ((switchmode & (SWITCH_ACIA | SWITCH_SND6 | SWITCH_SND7)) == 0)
-	return;
-    save_flags(flags);
-    cli();
-
-    mfp.tim_ct_b = 0x10;
-    mfp.active_edge |= 8;
-    mfp.tim_ct_b = 0;
-    mfp.tim_dt_b = 0xf0;
-    mfp.tim_ct_b = 8;
-    while (mfp.tim_dt_b > 1)	/* TOS does it this way, don't ask why */
-	;
-    new = mfp.tim_dt_b;
-    do {
-	udelay(LINE_DELAY);
-	old = new;
-	new = mfp.tim_dt_b;
-    } while (old != new);
-    mfp.tim_ct_b = 0x10;
-    udelay(SYNC_DELAY);
-
-    if (switchmode == SWITCH_ACIA)
-	acia.key_ctrl = (ACIA_DIV64|ACIA_D8N1S|ACIA_RHTID|ACIA_RIE);
-    else {
-	sound_ym.rd_data_reg_sel = 14;
-	sound_ym.wd_data = sound_ym.rd_data_reg_sel | switchmode;
-    }
-    restore_flags(flags);
-}
-
-/* ------------------- External Video ---------------------- */
-
-#ifdef ATAFB_EXT
-
-static int ext_encode_fix( struct fb_fix_screeninfo *fix,
-						   struct atari_fb_par *par )
-
-{
-	int i;
-
-	strcpy(fix->id,"Unknown Extern");
-	fix->smem_start=external_addr;
-	fix->smem_len=(external_len + PAGE_SIZE -1) & PAGE_MASK;
-	if (external_depth == 1) {
-		fix->type = FB_TYPE_PACKED_PIXELS;
-		/* The letters 'n' and 'i' in the "atavideo=external:" stand
-		 * for "normal" and "inverted", rsp., in the monochrome case */
-		fix->visual =
-			(external_pmode == FB_TYPE_INTERLEAVED_PLANES ||
-			 external_pmode == FB_TYPE_PACKED_PIXELS) ?
-				FB_VISUAL_MONO10 :
-					FB_VISUAL_MONO01;
-	}
-	else {
-		switch (external_pmode) {
-			/* All visuals are STATIC, because we don't know how to change
-			 * colors :-(
-			 */
-		    case -1:              /* truecolor */
-			fix->type=FB_TYPE_PACKED_PIXELS;
-			fix->visual=FB_VISUAL_TRUECOLOR;
-			break;
-		    case FB_TYPE_PACKED_PIXELS:
-			fix->type=FB_TYPE_PACKED_PIXELS;
-			fix->visual=FB_VISUAL_STATIC_PSEUDOCOLOR;
-			break;
-		    case FB_TYPE_PLANES:
-			fix->type=FB_TYPE_PLANES;
-			fix->visual=FB_VISUAL_STATIC_PSEUDOCOLOR;
-			break;
-		    case FB_TYPE_INTERLEAVED_PLANES:
-			fix->type=FB_TYPE_INTERLEAVED_PLANES;
-			fix->type_aux=2;
-			fix->visual=FB_VISUAL_STATIC_PSEUDOCOLOR;
-			break;
-		}
-	}
-	fix->xpanstep = 0;
-	fix->ypanstep = 0;
-	fix->ywrapstep = 0;
-	fix->line_length = 0;
-	for (i=0; i<arraysize(fix->reserved); i++)
-		fix->reserved[i]=0;
-	return 0;
-}
-
-
-static int ext_decode_var( struct fb_var_screeninfo *var,
-						   struct atari_fb_par *par )
-{
-	struct fb_var_screeninfo *myvar = &atari_fb_predefined[0];
-	
-	if (var->bits_per_pixel > myvar->bits_per_pixel ||
-		var->xres > myvar->xres ||
-		var->yres > myvar->yres ||
-		var->xoffset > 0 ||
-		var->yoffset > 0)
-		return -EINVAL;
-	return 0;
-}
-
-
-static int ext_encode_var( struct fb_var_screeninfo *var,
-						   struct atari_fb_par *par )
-{
-	int i;
-
-	var->red.offset=0;
-	var->red.length=(external_pmode == -1) ? external_depth/3 : 
-			(external_vgaiobase ? external_bitspercol : 0);
-	var->red.msb_right=0;
-	var->grayscale=0;
-
-	var->pixclock=31041;
-	var->left_margin=120;		/* these are surely incorrect 	*/
-	var->right_margin=100;
-	var->upper_margin=8;
-	var->lower_margin=16;
-	var->hsync_len=140;
-	var->vsync_len=30;
-
-	var->height=-1;
-	var->width=-1;
-
-	var->sync=0;
-
-	var->xres = external_xres;
-	var->yres = external_yres;
-	var->bits_per_pixel = external_depth;
-	
-	var->blue=var->green=var->red;
-	var->transp.offset=0;
-	var->transp.length=0;
-	var->transp.msb_right=0;
-	var->xres_virtual=var->xres;
-	var->yres_virtual=var->yres;
-	var->xoffset=0;
-	var->yoffset=0;
-	var->nonstd=0;
-	var->activate=0;
-	var->vmode=FB_VMODE_NONINTERLACED;
-	for (i=0; i<arraysize(var->reserved); i++)
-		var->reserved[i]=0;
-	return 0;
-}
-
-
-static void ext_get_par( struct atari_fb_par *par )
-{
-	par->screen_base = external_addr;
-}
-
-static void ext_set_par( struct atari_fb_par *par )
-{
-}
-
-#define OUTB(port,val) \
-	*((unsigned volatile char *) ((port)+external_vgaiobase))=(val)
-#define INB(port) \
-	(*((unsigned volatile char *) ((port)+external_vgaiobase)))
-#define DACDelay 				\
-	do {					\
-		unsigned char tmp=INB(0x3da);	\
-		tmp=INB(0x3da);			\
-	} while (0)
-
-static int ext_getcolreg( unsigned regno, unsigned *red,
-						  unsigned *green, unsigned *blue,
-						  unsigned *transp )
-
-{	unsigned char colmask = (1 << external_bitspercol) - 1;
-		
-	if (! external_vgaiobase)
-		return 1;
-
-	switch (external_card_type) {
-	  case IS_VGA:
-	    OUTB(0x3c7, regno);
-	    DACDelay;
-	    *red=INB(0x3c9) & colmask;
-	    DACDelay;
-	    *green=INB(0x3c9) & colmask;
-	    DACDelay;
-	    *blue=INB(0x3c9) & colmask;
-	    DACDelay;
-	    return 0;
-	    
-	  case IS_MV300:
-	    *red = MV300_color[regno].red;
-	    *green = MV300_color[regno].green;
-	    *blue = MV300_color[regno].blue;
-	    *transp=0;
-	    return 0;
-
-	  default:
-	    return 1;
-	  }
-}
-	
-static int ext_setcolreg( unsigned regno, unsigned red,
-						  unsigned green, unsigned blue,
-						  unsigned transp )
-
-{	unsigned char colmask = (1 << external_bitspercol) - 1;
-
-	if (! external_vgaiobase)
-		return 1;
-
-	switch (external_card_type) {
-	  case IS_VGA:
-	    OUTB(0x3c8, regno);
-	    DACDelay;
-	    OUTB(0x3c9, red & colmask);
-	    DACDelay;
-	    OUTB(0x3c9, green & colmask);
-	    DACDelay;
-	    OUTB(0x3c9, blue & colmask);
-	    DACDelay;
-	    return 0;
-
-	  case IS_MV300:
-	    MV300_color[regno].red = red;
-	    MV300_color[regno].green = green;
-	    MV300_color[regno].blue = blue;
-	    OUTB((MV300_reg[regno] << 2)+1, red);
-	    OUTB((MV300_reg[regno] << 2)+1, green);
-	    OUTB((MV300_reg[regno] << 2)+1, blue);
-	    return 0;
-
-	  default:
-	    return 1;
-	  }
-}
-	
-
-static int ext_detect( void )
-
-{
-	struct fb_var_screeninfo *myvar = &atari_fb_predefined[0];
-	struct atari_fb_par dummy_par;
-
-	myvar->xres = external_xres;
-	myvar->yres = external_yres;
-	myvar->bits_per_pixel = external_depth;
-	ext_encode_var(myvar, &dummy_par);
-	return 1;
-}
-
-#endif /* ATAFB_EXT */
-
-/* ------ This is the same for most hardware types -------- */
-
-static void set_screen_base(unsigned long s_base)
-{
-	unsigned long addr;
-	addr= VTOP(s_base);
-	/* Setup Screen Memory */
-	shifter.bas_hi=(unsigned char) ((addr & 0xff0000) >> 16);
-  	shifter.bas_md=(unsigned char) ((addr & 0x00ff00) >> 8);
-  	shifter.bas_lo=(unsigned char)  (addr & 0x0000ff);
-}
-
-
-static int pan_display( struct fb_var_screeninfo *var,
-                        struct atari_fb_par *par )
-{
-	if (!ATARIHW_PRESENT(EXTD_SHIFTER) && var->xoffset)
-		return -EINVAL;
-	else
-		var->xoffset = up(var->xoffset, 16);
-	par->screen_base = screen_base +
-	        (var->yoffset * disp[currcon].var.xres_virtual + var->xoffset)
-	        * disp[currcon].var.bits_per_pixel / 8;
-	if (fbhw->set_screen_base)
-		fbhw->set_screen_base (par->screen_base);
-	else
-		return -EINVAL;
-	return 0;
-}
-
-
-/* ------------ Interfaces to hardware functions ------------ */
-
-
-#ifdef ATAFB_TT
-static struct fb_hwswitch tt_switch = {
-	tt_detect, tt_encode_fix, tt_decode_var, tt_encode_var,
-	tt_get_par, tt_set_par, tt_getcolreg, tt_setcolreg,
-	set_screen_base, NULL, pan_display
-};
-#endif
-
-#ifdef ATAFB_FALCON
-static struct fb_hwswitch falcon_switch = {
-	falcon_detect, falcon_encode_fix, falcon_decode_var, falcon_encode_var,
-	falcon_get_par, falcon_set_par, falcon_getcolreg,
-	falcon_setcolreg, set_screen_base, falcon_blank, falcon_pan_display
-};
-#endif
-
-#ifdef ATAFB_STE
-static struct fb_hwswitch st_switch = {
-	stste_detect, stste_encode_fix, stste_decode_var, stste_encode_var,
-	stste_get_par, stste_set_par, stste_getcolreg, stste_setcolreg,
-	stste_set_screen_base, NULL, pan_display
-};
-#endif
-
-#ifdef ATAFB_EXT
-static struct fb_hwswitch ext_switch = {
-	ext_detect, ext_encode_fix, ext_decode_var, ext_encode_var,
-	ext_get_par, ext_set_par, ext_getcolreg, ext_setcolreg, NULL, NULL, NULL
-};
-#endif
-
-
-
-static void atari_fb_get_par( struct atari_fb_par *par )
-{
-	if (current_par_valid) {
-		*par=current_par;
-	}
-	else
-		fbhw->get_par(par);
-}
-
-
-static void atari_fb_set_par( struct atari_fb_par *par )
-{
-	fbhw->set_par(par);
-	current_par=*par;
-	current_par_valid=1;
-}
-
-
-
-/* =========================================================== */
-/* ============== Hardware Independent Functions ============= */
-/* =========================================================== */
-
-
-/* used for hardware scrolling */
-
-static int
-fb_update_var(int con)
-{
-	int off=disp[con].var.yoffset*disp[con].var.xres_virtual*
-			disp[con].var.bits_per_pixel>>3;
-
-	current_par.screen_base=screen_base + off;
-
-	if (fbhw->set_screen_base)
-		fbhw->set_screen_base(current_par.screen_base);
-	return 0;
-}
-
-static int
-do_fb_set_var(struct fb_var_screeninfo *var, int isactive)
-{
-	int err,activate;
-	struct atari_fb_par par;
-	if ((err=fbhw->decode_var(var, &par)))
-		return err;
-	activate=var->activate;
-	if (((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) && isactive)
-		atari_fb_set_par(&par);
-	fbhw->encode_var(var, &par);
-	var->activate=activate;
-	return 0;
-}
-
-/* Functions for handling colormap */
-
-/* there seems to be a bug in gcc 2.5.8 which inhibits using an other solution */
-/* I always get a sigsegv */
-
-static short red16[]=
-	{ 0x0000,0x0000,0x0000,0x0000,0xc000,0xc000,0xc000,0xc000,
-	  0x8000,0x0000,0x0000,0x0000,0xffff,0xffff,0xffff,0xffff};
-static short green16[]=
-	{ 0x0000,0x0000,0xc000,0xc000,0x0000,0x0000,0xc000,0xc000,
-	  0x8000,0x0000,0xffff,0xffff,0x0000,0x0000,0xffff,0xffff};
-static short blue16[]=
-	{ 0x0000,0xc000,0x0000,0xc000,0x0000,0xc000,0x0000,0xc000,
-	  0x8000,0xffff,0x0000,0xffff,0x0000,0xffff,0x0000,0xffff};
-
-static short red4[]=
-	{ 0x0000,0xc000,0x8000,0xffff};
-static short green4[]=
-	{ 0x0000,0xc000,0x8000,0xffff};
-static short blue4[]=
-	{ 0x0000,0xc000,0x8000,0xffff};
-
-static short red2[]=
-	{ 0x0000,0xffff};
-static short green2[]=
-	{ 0x0000,0xffff};
-static short blue2[]=
-	{ 0x0000,0xffff};
-
-static struct fb_cmap default_16_colors = {
-    0, 16, red16, green16, blue16, NULL
-};
-static struct fb_cmap default_4_colors = {
-    0, 4, red4, green4, blue4, NULL
-};
-static struct fb_cmap default_2_colors = {
-    0, 2, red2, green2, blue2, NULL
-};
-
-static struct fb_cmap *
-get_default_colormap(int bpp)
-{
-	if (bpp == 1)
-		return &default_2_colors;
-	if (bpp == 2)
-		return &default_4_colors;
-	return &default_16_colors;
-}
-
-#define CNVT_TOHW(val,width)	(((val) << (width)) + 0x7fff - (val)) >> 16
-#define CNVT_FROMHW(val,width) ((width)?((((val) << 16) - (val)) / ((1<<(width))-1)):0)
-
-
-static int
-do_fb_get_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var, int kspc)
-{
-	int i,start;
-	unsigned short *red,*green,*blue,*transp;
-	unsigned int hred,hgreen,hblue,htransp;
-
-	red=cmap->red;
-	green=cmap->green;
-	blue=cmap->blue;
-	transp=cmap->transp;
-	start=cmap->start;
-	if (start < 0)
-		return EINVAL;
-	for (i=0 ; i < cmap->len ; i++) {
-		if (fbhw->getcolreg(start++, &hred, &hgreen, &hblue, &htransp))
-			return 0;
-		hred=CNVT_FROMHW(hred,var->red.length);
-		hgreen=CNVT_FROMHW(hgreen,var->green.length);
-		hblue=CNVT_FROMHW(hblue,var->blue.length);
-		htransp=CNVT_FROMHW(htransp,var->transp.length);
-		if (kspc) {
-			*red=hred;
-			*green=hgreen;
-			*blue=hblue;
-			if (transp) *transp=htransp;
-		}
-		else {
-			put_user(hred, red);
-			put_user(hgreen, green);
-			put_user(hblue, blue);
-			if (transp) put_user(htransp, transp);
-		}
-		red++;
-		green++;
-		blue++;
-		if (transp) transp++;
-	}
-	return 0;
-}
-
-static int
-do_fb_set_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var, int kspc)
-{
-	int i,start;
-	unsigned short *red,*green,*blue,*transp;
-	unsigned int hred,hgreen,hblue,htransp;
-
-	red=cmap->red;
-	green=cmap->green;
-	blue=cmap->blue;
-	transp=cmap->transp;
-	start=cmap->start;
-
-	if (start < 0)
-		return -EINVAL;
-	for (i=0 ; i < cmap->len ; i++) {
-		if (kspc) {
-			hred=*red;
-			hgreen=*green;
-			hblue=*blue;
-			htransp=(transp) ? *transp : 0;
-		}
-		else {
-			get_user(hred, red);
-			get_user(hgreen, green);
-			get_user(hblue, blue);
-			if (transp)
-				get_user(htransp, transp);
-			else
-				htransp = 0;
-		}
-		hred=CNVT_TOHW(hred,var->red.length);
-		hgreen=CNVT_TOHW(hgreen,var->green.length);
-		hblue=CNVT_TOHW(hblue,var->blue.length);
-		htransp=CNVT_TOHW(htransp,var->transp.length);
-		red++;
-		green++;
-		blue++;
-		if (transp) transp++;
-		if (fbhw->setcolreg(start++, hred, hgreen, hblue, htransp))
-			return 0;
-	}
-	return 0;
-}
-
-static void
-do_install_cmap(int con)
-{
-	if (con != currcon)
-		return;
-	if (disp[con].cmap.len)
-		do_fb_set_cmap(&disp[con].cmap, &(disp[con].var), 1);
-	else
-		do_fb_set_cmap(get_default_colormap(
-				disp[con].var.bits_per_pixel), &(disp[con].var), 1);		
-}
-
-static void
-memcpy_fs(int fsfromto, void *to, void *from, int len)
-{
-	switch (fsfromto) {
-	case 0:
-		memcpy(to,from,len);
-		return;
-	case 1:
-		copy_from_user(to,from,len);
-		return;
-	case 2:
-		copy_to_user(to,from,len);
-		return;
-	}
-}
-
-static void
-copy_cmap(struct fb_cmap *from, struct fb_cmap *to, int fsfromto)
-{
-	int size;
-	int tooff=0, fromoff=0;
-
-	if (to->start > from->start)
-		fromoff=to->start-from->start;
-	else
-		tooff=from->start-to->start;			
-	size=to->len-tooff;
-	if (size > from->len-fromoff)
-		size=from->len-fromoff;
-	if (size < 0)
-		return;
-	size*=sizeof(unsigned short);
-	memcpy_fs(fsfromto, to->red+tooff, from->red+fromoff, size);
-	memcpy_fs(fsfromto, to->green+tooff, from->green+fromoff, size);
-	memcpy_fs(fsfromto, to->blue+tooff, from->blue+fromoff, size);
-	if (from->transp && to->transp)
-		memcpy_fs(fsfromto, to->transp+tooff, from->transp+fromoff, size);
-}
- 
-static int
-alloc_cmap(struct fb_cmap *cmap,int len,int transp)
-{
-	int size=len*sizeof(unsigned short);
-	if (cmap->len != len) {
-		if (cmap->red)
-			kfree(cmap->red);
-		if (cmap->green)
-			kfree(cmap->green);
-		if (cmap->blue)
-			kfree(cmap->blue);
-		if (cmap->transp)
-			kfree(cmap->transp);
-		cmap->red=cmap->green=cmap->blue=cmap->transp=NULL;
-		cmap->len=0;
-		if (! len)
-			return 0;
-		if (! (cmap->red=kmalloc(size, GFP_ATOMIC)))
-			return -1;
-		if (! (cmap->green=kmalloc(size, GFP_ATOMIC)))
-			return -1;
-		if (! (cmap->blue=kmalloc(size, GFP_ATOMIC)))
-			return -1;
-		if (transp) {
-			if (! (cmap->transp=kmalloc(size, GFP_ATOMIC)))
-				return -1;
-		}
-		else
-			cmap->transp=NULL;
-	}
-	cmap->start=0;
-	cmap->len=len;
-	copy_cmap(get_default_colormap(len), cmap, 0);
-	return 0;
-}	
-
-static int
-atari_fb_get_fix(struct fb_fix_screeninfo *fix, int con)
-{
-	struct atari_fb_par par;
-	if (con == -1)
-		atari_fb_get_par(&par);
-	else
-		fbhw->decode_var(&disp[con].var,&par);
-	return fbhw->encode_fix(fix, &par);
-}
-	
-static int
-atari_fb_get_var(struct fb_var_screeninfo *var, int con)
-{
-	struct atari_fb_par par;
-	if (con == -1) {
-		atari_fb_get_par(&par);
-		fbhw->encode_var(var, &par);
-	}
-	else
-		*var=disp[con].var;
-	return 0;
-}
-
-static void
-atari_fb_set_disp(int con)
-{
-	struct fb_fix_screeninfo fix;
-
-	atari_fb_get_fix(&fix, con);
-	if (con == -1)
-		con=0;
-	disp[con].screen_base = (u_char *)fix.smem_start;
-	disp[con].visual = fix.visual;
-	disp[con].type = fix.type;
-	disp[con].type_aux = fix.type_aux;
-	disp[con].ypanstep = fix.ypanstep;
-	disp[con].ywrapstep = fix.ywrapstep;
-	disp[con].line_length = fix.line_length;
-	if (fix.visual != FB_VISUAL_PSEUDOCOLOR &&
-		fix.visual != FB_VISUAL_DIRECTCOLOR)
-		disp[con].can_soft_blank = 0;
-	else
-		disp[con].can_soft_blank = 1;
-	disp[con].inverse =
-	    (fix.visual == FB_VISUAL_MONO01 ? !inverse : inverse);
-}
-
-static int
-atari_fb_set_var(struct fb_var_screeninfo *var, int con)
-{
-	int err,oldxres,oldyres,oldbpp,oldxres_virtual,
-	    oldyres_virtual,oldyoffset;
-	if ((err=do_fb_set_var(var, con==currcon)))
-		return err;
-	if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
-		oldxres=disp[con].var.xres;
-		oldyres=disp[con].var.yres;
-		oldxres_virtual=disp[con].var.xres_virtual;
-		oldyres_virtual=disp[con].var.yres_virtual;
-		oldbpp=disp[con].var.bits_per_pixel;
-		oldyoffset=disp[con].var.yoffset;
-		disp[con].var=*var;
-		if (oldxres != var->xres || oldyres != var->yres 
-		    || oldxres_virtual != var->xres_virtual
-		    || oldyres_virtual != var->yres_virtual
-		    || oldbpp != var->bits_per_pixel
-		    || oldyoffset != var->yoffset) {
-			atari_fb_set_disp(con);
-			(*fb_info.changevar)(con);
-			alloc_cmap(&disp[con].cmap, 0, 0);
-			do_install_cmap(con);
-		}
-	}
-	var->activate=0;
-	return 0;
-}
-
-
-
-static int
-atari_fb_get_cmap(struct fb_cmap *cmap, int kspc, int con)
-{
-	if (con == currcon) /* current console ? */
-		return do_fb_get_cmap(cmap, &(disp[con].var), kspc);
-	else
-		if (disp[con].cmap.len) /* non default colormap ? */
-			copy_cmap(&disp[con].cmap, cmap, kspc ? 0 : 2);
-		else
-			copy_cmap(get_default_colormap(
-			    disp[con].var.bits_per_pixel), cmap, kspc ? 0 : 2);
-	return 0;
-}
-
-static int
-atari_fb_set_cmap(struct fb_cmap *cmap, int kspc, int con)
-{
-	int err;
-	if (! disp[con].cmap.len) { /* no colormap allocated ? */
-		if ((err = alloc_cmap(&disp[con].cmap, 
-					1 << disp[con].var.bits_per_pixel, 0)))
-		return err;
-	}
-	if (con == currcon) /* current console ? */
-		return do_fb_set_cmap(cmap, &(disp[con].var), kspc);
-	else
-		copy_cmap(cmap, &disp[con].cmap, kspc ? 0 : 1);
-	return 0;
-}
-
-static int
-atari_fb_pan_display(struct fb_var_screeninfo *var, int con)
-{
-	int xoffset = var->xoffset;
-	int yoffset = var->yoffset;
-	int err;
-
-	if (   xoffset < 0 || xoffset + disp[con].var.xres > disp[con].var.xres_virtual
-	    || yoffset < 0 || yoffset + disp[con].var.yres > disp[con].var.yres_virtual)
-		return -EINVAL;
-
-	if (con == currcon) {
-		if (fbhw->pan_display) {
-			if ((err = fbhw->pan_display(var, &current_par)))
-				return err;
-		}
-		else
-			return -EINVAL;
-	}
-	disp[con].var.xoffset = var->xoffset;
-	disp[con].var.yoffset = var->yoffset;
-	return 0;
-}
-
-static int
-atari_fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
-	       unsigned long arg, int con)
-{
-	switch (cmd) {
-#ifdef FBCMD_GET_CURRENTPAR
-	case FBCMD_GET_CURRENTPAR:
-		if (copy_to_user((void *)arg, (void *)&current_par,
-				 sizeof(struct atari_fb_par)))
-			return -EFAULT;
-		return 0;
-#endif
-#ifdef FBCMD_SET_CURRENTPAR
-	case FBCMD_SET_CURRENTPAR:
-		if (copy_from_user((void *)&current_par, (void *)arg,
-				   sizeof(struct atari_fb_par)))
-			return -EFAULT;
-		atari_fb_set_par(&current_par);
-		return 0;
-#endif
-	}
-	return -EINVAL;
-}
-
-static struct fb_ops atari_fb_ops = {
-	atari_fb_get_fix, atari_fb_get_var, atari_fb_set_var, atari_fb_get_cmap,
-	atari_fb_set_cmap, atari_fb_pan_display, atari_fb_ioctl	
-};
-
-static void
-check_default_par( int detected_mode )
-{
-	char default_name[10];
-	int i;
-	struct fb_var_screeninfo var;
-	unsigned long min_mem;
-
-	/* First try the user supplied mode */
-	if (default_par) {
-		var=atari_fb_predefined[default_par-1];
-		var.activate = FB_ACTIVATE_TEST;
-		if (do_fb_set_var(&var,1))
-			default_par=0;		/* failed */
-	}
-	/* Next is the autodetected one */
-	if (! default_par) {
-		var=atari_fb_predefined[detected_mode-1]; /* autodetect */
-		var.activate = FB_ACTIVATE_TEST;
-		if (!do_fb_set_var(&var,1))
-			default_par=detected_mode;
-	}
-	/* If that also failed, try some default modes... */
-	if (! default_par) {
-		/* try default1, default2... */
-		for (i=1 ; i < 10 ; i++) {
-			sprintf(default_name,"default%d",i);
-			default_par=get_video_mode(default_name);
-			if (! default_par)
-				panic("can't set default video mode\n");
-			var=atari_fb_predefined[default_par-1];
-			var.activate = FB_ACTIVATE_TEST;
-			if (! do_fb_set_var(&var,1))
-				break;	/* ok */
-		}
-	}
-	min_mem=var.xres_virtual * var.yres_virtual * var.bits_per_pixel/8;
-	if (default_mem_req < min_mem)
-		default_mem_req=min_mem;
-}
-
-static int
-atafb_switch(int con)
-{
-	/* Do we have to save the colormap ? */
-	if (disp[currcon].cmap.len)
-		do_fb_get_cmap(&disp[currcon].cmap, &(disp[currcon].var), 1);
-	do_fb_set_var(&disp[con].var,1);
-	currcon=con;
-	/* Install new colormap */
-	do_install_cmap(con);
-	return 0;
-}
-
-/* (un)blank/poweroff
- * 0 = unblank
- * 1 = blank
- * 2 = suspend vsync
- * 3 = suspend hsync
- * 4 = off
- */
-static void
-atafb_blank(int blank)
-{
-	unsigned short black[16];
-	struct fb_cmap cmap;
-	if (fbhw->blank && !fbhw->blank(blank))
-		return;
-	if (blank) {
-		memset(black, 0, 16*sizeof(unsigned short));
-		cmap.red=black;
-		cmap.green=black;
-		cmap.blue=black;
-		cmap.transp=NULL;
-		cmap.start=0;
-		cmap.len=16;
-		do_fb_set_cmap(&cmap, &(disp[currcon].var), 1);
-	}
-	else
-		do_install_cmap(currcon);
-}
-
-static int
-atafb_setcmap(struct fb_cmap *cmap, int con)
-{
-	return(atari_fb_set_cmap(cmap, 1, con));
-}
-
-__initfunc(struct fb_info *
-atari_fb_init(long *mem_start))
-{
-	int err;
-	int pad;
-	int detected_mode;
-	unsigned long mem_req;
-	struct fb_var_screeninfo *var;
-	
-	err=register_framebuffer("Atari Builtin", &node, &atari_fb_ops, 
-			num_atari_fb_predefined, atari_fb_predefined);
-	if (err < 0)
-		panic ("Cannot register frame buffer\n");
-	do {
-#ifdef ATAFB_EXT
-		if (external_addr) {
-			fbhw = &ext_switch;
-			break;
-		}
-#endif
-#ifdef ATAFB_TT
-		if (ATARIHW_PRESENT(TT_SHIFTER)) {
-			fbhw = &tt_switch;
-			break;
-		}
-#endif
-#ifdef ATAFB_FALCON
-		if (ATARIHW_PRESENT(VIDEL_SHIFTER)) {
-			fbhw = &falcon_switch;
-			request_irq(IRQ_AUTO_4, falcon_vbl_switcher, IRQ_TYPE_PRIO,
-			            "framebuffer/modeswitch", falcon_vbl_switcher);
-			break;
-		}
-#endif
-#ifdef ATAFB_STE
-		if (ATARIHW_PRESENT(STND_SHIFTER) ||
-		    ATARIHW_PRESENT(EXTD_SHIFTER)) {
-			fbhw = &st_switch;
-			break;
-		}
-		fbhw = &st_switch;
-		printk("Cannot determine video hardware; defaulting to ST(e)\n");
-#else /* ATAFB_STE */
-		/* no default driver included */
-		/* Nobody will ever see this message :-) */
-		panic("Cannot initialize video hardware\n");
-#endif
-	} while (0);
-	detected_mode = fbhw->detect();
-	check_default_par(detected_mode);
-#ifdef ATAFB_EXT
-	if (!external_addr) {
-#endif /* ATAFB_EXT */
-		mem_req = default_mem_req + ovsc_offset +
-			ovsc_addlen;
-		mem_req = ((mem_req + PAGE_SIZE - 1) & PAGE_MASK) + PAGE_SIZE;
-		screen_base = (unsigned long) atari_stram_alloc(mem_req, mem_start);
-		memset((char *) screen_base, 0, mem_req);
-		pad = ((screen_base + PAGE_SIZE-1) & PAGE_MASK) - screen_base;
-		screen_base+=pad;
-		real_screen_base=screen_base+ovsc_offset;
-		screen_len = (mem_req - pad - ovsc_offset) & PAGE_MASK;
-		st_ovsc_switch(ovsc_switchmode);
-		if (CPU_IS_040_OR_060) {
-			/* On a '040+, the cache mode of video RAM must be set to
-			 * write-through also for internal video hardware! */
-			cache_push( VTOP(screen_base), screen_len );
-			kernel_set_cachemode( screen_base, screen_len,
-								  KERNELMAP_NO_COPYBACK );
-		}
-#ifdef ATAFB_EXT
-	}
-	else {
-		/* Map the video memory (physical address given) to somewhere
-		 * in the kernel address space.
-		 */
-		*mem_start = (*mem_start+PAGE_SIZE-1) & ~(PAGE_SIZE-1);
-		external_addr = kernel_map(external_addr, external_len,
-									KERNELMAP_NO_COPYBACK, mem_start);
-		if (external_vgaiobase)
-			external_vgaiobase = kernel_map(external_vgaiobase,
-				0x10000, KERNELMAP_NOCACHE_SER, mem_start);
-		screen_base      =
-		real_screen_base = external_addr;
-		screen_len       = external_len & PAGE_MASK;
-		memset ((char *) screen_base, 0, external_len);
-	}
-#endif /* ATAFB_EXT */
-
-	strcpy(fb_info.modename, "Atari Builtin ");
-	fb_info.disp=disp;
-	fb_info.switch_con=&atafb_switch;
-	fb_info.updatevar=&fb_update_var;
-	fb_info.blank=&atafb_blank;
-	fb_info.setcmap=&atafb_setcmap;
-	var=atari_fb_predefined+default_par-1;
-	do_fb_set_var(var,1);
-	strcat(fb_info.modename,fb_var_names[default_par-1][0]);
-
-	atari_fb_get_var(&disp[0].var, -1);
-	atari_fb_set_disp(-1);
-	printk("Determined %dx%d, depth %d\n",
-	       disp[0].var.xres, disp[0].var.yres, disp[0].var.bits_per_pixel );
-	do_install_cmap(0);
-	return &fb_info;
-}
-
-/* a strtok which returns empty strings, too */
-
-static char * strtoke(char * s,const char * ct)
-{
-  char *sbegin, *send;
-  static char *ssave = NULL;
-  
-  sbegin  = s ? s : ssave;
-  if (!sbegin) {
-	  return NULL;
-  }
-  if (*sbegin == '\0') {
-    ssave = NULL;
-    return NULL;
-  }
-  send = strpbrk(sbegin, ct);
-  if (send && *send != '\0')
-    *send++ = '\0';
-  ssave = send;
-  return sbegin;
-}
-
-void atari_video_setup( char *options, int *ints )
-{
-    char *this_opt;
-    int temp;
-    char ext_str[80], int_str[100];
-    char mcap_spec[80];
-    char user_mode[80];
-
-	ext_str[0]          =
-	int_str[0]          =
-	mcap_spec[0]        =
-	user_mode[0]        =
-	fb_info.fontname[0] = '\0';
-
-    if (!options || !*options)
-		return;
-     
-    for(this_opt=strtok(options,","); this_opt; this_opt=strtok(NULL,",")) {
-	if (!*this_opt) continue;
-	if ((temp=get_video_mode(this_opt)))
-		default_par=temp;
-	else if (! strcmp(this_opt, "inverse"))
-		inverse=1;
-	else if (!strncmp(this_opt, "font:", 5))
-	   strcpy(fb_info.fontname, this_opt+5);
-	else if (! strncmp(this_opt, "hwscroll_",9)) {
-		hwscroll=simple_strtoul(this_opt+9, NULL, 10);
-		if (hwscroll < 0)
-			hwscroll = 0;
-		if (hwscroll > 200)
-			hwscroll = 200;
-	}
-	else if (! strncmp(this_opt, "sw_",3)) {
-		if (! strcmp(this_opt+3, "acia"))
-			ovsc_switchmode = SWITCH_ACIA;
-		else if (! strcmp(this_opt+3, "snd6"))
-			ovsc_switchmode = SWITCH_SND6;
-		else if (! strcmp(this_opt+3, "snd7"))
-			ovsc_switchmode = SWITCH_SND7;
-		else ovsc_switchmode = SWITCH_NONE;
-	}
-#ifdef ATAFB_EXT
-	else if (!strcmp(this_opt,"mv300")) {
-		external_bitspercol = 8;
-		external_card_type = IS_MV300;
-	}
-	else if (!strncmp(this_opt,"external:",9))
-		strcpy(ext_str, this_opt+9);
-#endif
-	else if (!strncmp(this_opt,"internal:",9))
-		strcpy(int_str, this_opt+9);
-#ifdef ATAFB_FALCON
-	else if (!strncmp(this_opt, "eclock:", 7)) {
-		fext.f = simple_strtoul(this_opt+7, NULL, 10);
-		/* external pixelclock in kHz --> ps */
-		fext.t = 1000000000/fext.f;
-		fext.f *= 1000;
-	}
-	else if (!strncmp(this_opt, "monitorcap:", 11))
-		strcpy(mcap_spec, this_opt+11);
-#endif
-	else if (!strcmp(this_opt, "keep"))
-		DontCalcRes = 1;
-	else if (!strncmp(this_opt, "R", 1))
-		strcpy(user_mode, this_opt+1);
-    }
-
-    if (*int_str) {
-	/* Format to config extended internal video hardware like OverScan:
-	"<switch-type>,internal:<xres>;<yres>;<xres_max>;<yres_max>;<offset>"
-	Explanation:
-	<switch-type> type to switch on higher resolution
-			sw_acia : via keyboard ACIA
-			sw_snd6 : via bit 6 of the soundchip port
-			sw_snd7 : via bit 7 of the soundchip port
-	<xres>: x-resolution 
-	<yres>: y-resolution
-	The following are only needed if you have an overscan which
-	needs a black border:
-	<xres_max>: max. length of a line in pixels your OverScan hardware would allow
-	<yres_max>: max. number of lines your OverScan hardware would allow
-	<offset>: Offset from physical beginning to visible beginning
-		  of screen in bytes
-	*/
-	int xres;
-	char *p;
-
-	if (!(p = strtoke(int_str, ";")) ||!*p) goto int_invalid;
-	xres = simple_strtoul(p, NULL, 10);
-	if (!(p = strtoke(NULL, ";")) || !*p) goto int_invalid;
-	sttt_xres=xres;
-	tt_yres=st_yres=simple_strtoul(p, NULL, 10);
-	if ((p=strtoke(NULL, ";")) && *p) {
-		sttt_xres_virtual=simple_strtoul(p, NULL, 10);
-	}
-	if ((p=strtoke(NULL, ";")) && *p) {
-		sttt_yres_virtual=simple_strtoul(p, NULL, 0);
-	}
-	if ((p=strtoke(NULL, ";")) && *p) {
-		ovsc_offset=simple_strtoul(p, NULL, 0);
-	}
-
-	if (ovsc_offset || (sttt_yres_virtual != st_yres))
-		use_hwscroll=0;
-    }
-    else 
-      int_invalid:	ovsc_switchmode = SWITCH_NONE;
-
-#ifdef ATAFB_EXT
-    if (*ext_str) {
-	int		xres, yres, depth, planes;
-	unsigned long addr, len;
-	char *p;
-
-	/* Format is: <xres>;<yres>;<depth>;<plane organ.>;
-	 *            <screen mem addr>
-	 *	      [;<screen mem length>[;<vgaiobase>[;<colorreg-type>]]]
-	 */
-	if (!(p = strtoke(ext_str, ";")) ||!*p) goto ext_invalid;
-	xres = simple_strtoul(p, NULL, 10);
-	if (xres <= 0) goto ext_invalid;
-
-	if (!(p = strtoke(NULL, ";")) ||!*p) goto ext_invalid;
-	yres = simple_strtoul(p, NULL, 10);
-	if (yres <= 0) goto ext_invalid;
-
-	if (!(p = strtoke(NULL, ";")) ||!*p) goto ext_invalid;
-	depth = simple_strtoul(p, NULL, 10);
-	if (depth != 1 && depth != 2 && depth != 4 && depth != 8 &&
-		depth != 16 && depth != 24) goto ext_invalid;
-
-	if (!(p = strtoke(NULL, ";")) ||!*p) goto ext_invalid;
-	if (*p == 'i')
-		planes = FB_TYPE_INTERLEAVED_PLANES;
-	else if (*p == 'p')
-		planes = FB_TYPE_PACKED_PIXELS;
-	else if (*p == 'n')
-		planes = FB_TYPE_PLANES;
-	else if (*p == 't')
-		planes = -1; /* true color */
-	else
-		goto ext_invalid;
-
-
-	if (!(p = strtoke(NULL, ";")) ||!*p) goto ext_invalid;
-	addr = simple_strtoul(p, NULL, 0);
-
-	if (!(p = strtoke(NULL, ";")) ||!*p)
-		len = xres*yres*depth/8;
-	else
-		len = simple_strtoul(p, NULL, 0);
-
-	if ((p = strtoke(NULL, ";")) && *p)
-		external_vgaiobase=simple_strtoul(p, NULL, 0);
-
-	if ((p = strtoke(NULL, ";")) && *p) {
-		external_bitspercol = simple_strtoul(p, NULL, 0);
-		if (external_bitspercol > 8)
-			external_bitspercol = 8;
-		else if (external_bitspercol < 1)
-			external_bitspercol = 1;
-	}
-	
-	if ((p = strtoke(NULL, ";")) && *p) {
-		if (!strcmp(this_opt, "vga"))
-			external_card_type = IS_VGA;
-		if (!strcmp(this_opt, "mv300"))
-			external_card_type = IS_MV300;
-	}
-
-	external_xres  = xres;
-	external_yres  = yres;
-	external_depth = depth;
-	external_pmode = planes;
-	external_addr  = addr;
-	external_len   = len;
-		
-	if (external_card_type == IS_MV300)
-	  switch (external_depth) {
-	    case 1:
-	      MV300_reg = MV300_reg_1bit;
-	      break;
-	    case 4:
-	      MV300_reg = MV300_reg_4bit;
-	      break;
-	    case 8:
-	      MV300_reg = MV300_reg_8bit;
-	      break;
-	    }
-
-      ext_invalid:
-	;
-    }
-#endif /* ATAFB_EXT */
-
-#ifdef ATAFB_FALCON
-    if (*mcap_spec) {
-	char *p;
-	int vmin, vmax, hmin, hmax;
-
-	/* Format for monitor capabilities is: <Vmin>;<Vmax>;<Hmin>;<Hmax>
-	 * <V*> vertical freq. in Hz
-	 * <H*> horizontal freq. in kHz
-	 */
-	if (!(p = strtoke(mcap_spec, ";")) || !*p) goto cap_invalid;
-	vmin = simple_strtoul(p, NULL, 10);
-	if (vmin <= 0) goto cap_invalid;
-	if (!(p = strtoke(NULL, ";")) || !*p) goto cap_invalid;
-	vmax = simple_strtoul(p, NULL, 10);
-	if (vmax <= 0 || vmax <= vmin) goto cap_invalid;
-	if (!(p = strtoke(NULL, ";")) || !*p) goto cap_invalid;
-	hmin = 1000 * simple_strtoul(p, NULL, 10);
-	if (hmin <= 0) goto cap_invalid;
-	if (!(p = strtoke(NULL, "")) || !*p) goto cap_invalid;
-	hmax = 1000 * simple_strtoul(p, NULL, 10);
-	if (hmax <= 0 || hmax <= hmin) goto cap_invalid;
-
-	vfmin = vmin;
-	vfmax = vmax;
-	hfmin = hmin;
-	hfmax = hmax;
-      cap_invalid:
-	;
-    }
-#endif
-
-	if (*user_mode) {
-		/* Format of user defined video mode is: <xres>;<yres>;<depth>
-		 */
-		char *p;
-		int xres, yres, depth, temp;
-
-		if (!(p = strtoke(user_mode, ";")) || !*p) goto user_invalid;
-		xres = simple_strtoul(p, NULL, 10);
-		if (!(p = strtoke(NULL, ";")) || !*p) goto user_invalid;
-		yres = simple_strtoul(p, NULL, 10);
-		if (!(p = strtoke(NULL, "")) || !*p) goto user_invalid;
-		depth = simple_strtoul(p, NULL, 10);
-		if ((temp=get_video_mode("user0"))) {
-			default_par=temp;
-			atari_fb_predefined[default_par-1].xres = xres;
-			atari_fb_predefined[default_par-1].yres = yres;
-			atari_fb_predefined[default_par-1].bits_per_pixel = depth;
-		}
-
-	  user_invalid:
-		;
-	}
-}
diff -u --recursive --new-file v2.1.72/linux/arch/m68k/atari/atafb.h linux/arch/m68k/atari/atafb.h
--- v2.1.72/linux/arch/m68k/atari/atafb.h	Wed Dec 27 12:43:49 1995
+++ linux/arch/m68k/atari/atafb.h	Wed Dec 31 16:00:00 1969
@@ -1,48 +0,0 @@
-#include <linux/fb.h>
-#include <linux/console.h>
-
-
-struct display
-{
-    int bytes_per_row;		/* offset to one line below */
-
-    int cursor_x;		/* current cursor position */
-    int cursor_y;
-
-    int fgcol;			/* text colors */
-    int bgcol;
-
-    struct fb_var_screeninfo var;	/* variable infos */
-    struct fb_cmap	cmap;		/* colormap */
-  
-    /* the following three are copies from fb_fix_screeninfo */
-    int visual;
-    int type;
-    int type_aux;
-
-    u_char *bitplane;	        /* pointer to top of physical screen */
-
-    u_char *screen_base;	/* pointer to top of virtual screen */    
-
-    u_char *fontdata;           /* Font associated to this display */
-    int fontheight;
-    int fontwidth;
-
-    int inverse;		/* != 0 text black on white as default */
-    struct vc_data *conp;	/* pointer to console data */
-    struct display_switch *dispsw; /* pointers to depth specific functions */
-}; 
-
-struct fb_info
-{
-    char modename[40];		/* name of the at boottime detected video mode */
-    struct display *disp;	/* pointer to display variables */
-    int (*changevar)(int);	/* tell the console var has changed */
-    int (*switch_con)(int);	/* tell the framebuffer to switch consoles */
-    int (*updatevar)(int);	/* tell the framebuffer to update the vars */
-    void (*blank)(int);		/* tell the framebuffer to (un)blank the screen */
-};
-
-struct fb_info *atafb_init(long *);
-
-
diff -u --recursive --new-file v2.1.72/linux/arch/m68k/console/Makefile linux/arch/m68k/console/Makefile
--- v2.1.72/linux/arch/m68k/console/Makefile	Wed Sep 25 00:47:39 1996
+++ linux/arch/m68k/console/Makefile	Wed Dec 31 16:00:00 1969
@@ -1,24 +0,0 @@
-#
-# Makefile for Linux arch/m68k/console source directory
-#
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
-#
-
-GSPA = gspa
-GSPH2C = gspahextoc
-
-L_TARGET = console.a
-L_OBJS = fbcon.o fonts.o font_8x16.o font_8x8.o pearl_8x8.o
-M_OBJS =
-
-ifdef CONFIG_AMIGA_GSP
-L_OBJS := $(L_OBJS) gspcon.o gspcore.o
-endif
-
-include $(TOPDIR)/Rules.make
-
-gspcore.c: gspcore.gsp
-	$(GSPA) $< > $*.hex
-	$(GSPH2C) $*.hex > gspcore.c
diff -u --recursive --new-file v2.1.72/linux/arch/m68k/console/fbcon.c linux/arch/m68k/console/fbcon.c
--- v2.1.72/linux/arch/m68k/console/fbcon.c	Mon Jul  7 08:18:53 1997
+++ linux/arch/m68k/console/fbcon.c	Wed Dec 31 16:00:00 1969
@@ -1,4126 +0,0 @@
-/*
- * linux/arch/m68k/console/fbcon.c -- Low level frame buffer based console
- *                                    driver
- *
- *    Copyright (C) 1995 Geert Uytterhoeven
- *
- *
- * This file is based on the original Amiga console driver (amicon.c):
- *
- *    Copyright (C) 1993 Hamish Macdonald
- *                       Greg Harp
- *    Copyright (C) 1994 David Carter [carter@compsci.bristol.ac.uk]
- *
- *          with work by William Rucklidge (wjr@cs.cornell.edu)
- *                       Geert Uytterhoeven
- *                       Jes Sorensen (jds@kom.auc.dk)
- *                       Martin Apel
- *
- * and on the original Atari console driver (atacon.c):
- *
- *    Copyright (C) 1993 Bjoern Brauel
- *                       Roman Hodek
- *
- *          with work by Guenther Kelleter
- *                       Martin Schaller
- *                       Andreas Schwab
- *
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file COPYING in the main directory of this archive
- * for more details.
- */
-
-/*
- * To do:
- *  - Implement 16 plane mode.
- *  - Add support for 16/24/32 bit packed pixels
- *  - Hardware cursor
- */
-
-
-#include <linux/types.h>
-#include <linux/sched.h>
-#include <linux/fs.h>
-#include <linux/kernel.h>
-#include <linux/tty.h>
-#include <linux/console.h>
-#include <linux/string.h>
-#include <linux/config.h>
-#include <linux/kd.h>
-#include <linux/malloc.h>
-
-#include <asm/setup.h>
-#include <asm/irq.h>
-#ifdef CONFIG_AMIGA
-#include <asm/amigahw.h>
-#include <asm/amigaints.h>
-#endif /* CONFIG_AMIGA */
-#ifdef CONFIG_ATARI
-#include <asm/atariints.h>
-#endif
-#ifdef CONFIG_FB_CYBER
-#include "../amiga/s3blit.h"
-#endif
-#include <linux/fb.h>
-#include <asm/font.h>
-#include <asm/machdep.h>
-
-#include <asm/system.h>
-#include <asm/uaccess.h>
-
-#include <linux/vt_kern.h>
-#include <linux/console_struct.h>
-
-/* Import console_blanked from console.c */
-
-extern int console_blanked;
-
-
-   /*
-    *    The following symbols select what modes are supported. They should
-    *    be settable by the user ("make config") later.
-    */
-
-/* Clear all definitions */
-
-#undef CONFIG_FBCON_MONO
-#undef CONFIG_FBCON_ILBM
-#undef CONFIG_FBCON_PLANES
-#undef CONFIG_FBCON_2PLANE
-#undef CONFIG_FBCON_4PLANE
-#undef CONFIG_FBCON_8PLANE
-#undef CONFIG_FBCON_8PACKED
-#undef CONFIG_FBCON_16PACKED
-#undef CONFIG_FBCON_24PACKED
-#undef CONFIG_FBCON_32PACKED
-#undef CONFIG_FBCON_CYBER
-#undef CONFIG_FBCON_RETINAZ3
-
-/* Monochrome is default */
-
-#define CONFIG_FBCON_MONO
-
-/* Amiga support */
-
-#ifdef CONFIG_AMIGA
-#ifndef CONFIG_FBCON_ILBM
-#define CONFIG_FBCON_ILBM
-#endif
-#ifndef CONFIG_FBCON_PLANES
-#define CONFIG_FBCON_PLANES
-#endif
-
-/* Cybervision Graphics Board */
-
-#ifdef CONFIG_FB_CYBER
-#ifndef CONFIG_FBCON_CYBER
-#define CONFIG_FBCON_CYBER
-#endif
-#endif
-
-/* RetinaZ3 Graphics Board */
-
-#ifdef CONFIG_FB_RETINAZ3
-#ifndef CONFIG_FBCON_RETINAZ3
-#define CONFIG_FBCON_RETINAZ3
-#endif
-#ifndef CONFIG_FBCON_8PACKED
-#define CONFIG_FBCON_8PACKED
-#endif
-#endif
-
-#endif /* CONFIG_AMIGA */
-
-/* Atari support */
-
-#ifdef CONFIG_ATARI
-#ifndef CONFIG_FBCON_2PLANE
-#define CONFIG_FBCON_2PLANE
-#endif
-#ifndef CONFIG_FBCON_4PLANE
-#define CONFIG_FBCON_4PLANE
-#endif
-#ifndef CONFIG_FBCON_8PLANE
-#define CONFIG_FBCON_8PLANE
-#endif
-#ifndef CONFIG_FBCON_8PACKED
-#define CONFIG_FBCON_8PACKED
-#endif
-#ifndef CONFIG_FBCON_16PACKED
-#define CONFIG_FBCON_16PACKED
-#endif
-#endif /* CONFIG_ATARI */
-
-
-/* Extra definitions to make the code more readable */
-
-#if defined(CONFIG_FBCON_2PLANE) || defined(CONFIG_FBCON_4PLANE) || \
-    defined(CONFIG_FBCON_8PLANE)
-#define CONFIG_FBCON_IPLAN2
-#else
-#undef CONFIG_FBCON_IPLAN2
-#endif
-
-#if defined(CONFIG_FBCON_CYBER) || defined(CONFIG_FBCON_RETINAZ3) || \
-    defined(CONFIG_FBCON_8PACKED) || defined(CONFIG_FBCON_16PACKED) || \
-    defined(CONFIG_FBCON_24PACKED) || defined(CONFIG_FBCON_32PACKED)
-#define CONFIG_FBCON_PACKED
-#else
-#undef CONFIG_FBCON_PACKED
-#endif
-
-
-static struct fb_info *fb_info;
-static struct display *disp;
-
-
-/* ++Geert: Sorry, no hardware cursor support at the moment;
-   use Atari alike software cursor */
-
-static int cursor_drawn = 0;
-
-#define CURSOR_DRAW_DELAY           (2)
-
-/* # VBL ints between cursor state changes */
-#define AMIGA_CURSOR_BLINK_RATE   (20)
-#define ATARI_CURSOR_BLINK_RATE   (42)
-
-static int vbl_cursor_cnt = 0;
-static int cursor_on = 0;
-static int cursor_blink_rate;
-
-static __inline__ int CURSOR_UNDRAWN(void)
-{
-   int cursor_was_drawn;
-   vbl_cursor_cnt = 0;
-   cursor_was_drawn = cursor_drawn;
-   cursor_drawn = 0;
-   return(cursor_was_drawn);
-}
-
-   /*
-    *    Attribute Decoding
-    */
-
-/* Color */
-#define attr_fgcol(p,conp)    \
-	(((conp)->vc_attr >> ((p)->inverse ? 4 : 0)) & 0x0f)
-#define attr_bgcol(p,conp)    \
-	(((conp)->vc_attr >> ((p)->inverse ? 0 : 4)) & 0x0f)
-#define	attr_bgcol_ec(p,conp) \
-	(((conp)->vc_video_erase_char >> ((p)->inverse ? 8 : 12)) & 0x0f)
-
-/* Monochrome */
-#define attr_bold(p,conp)     \
-	(((conp)->vc_attr & 3) == 2)
-#define attr_reverse(p,conp)  \
-	(((conp)->vc_attr & 8) ^ ((p)->inverse ? 8 : 0))
-#define attr_underline(p,conp) \
-	(((conp)->vc_attr) & 4)
-
-
-   /*
-    *    Scroll Method
-    */
-
-#define SCROLL_YWRAP          (0)
-#define SCROLL_YPAN           (1)
-#define SCROLL_YMOVE          (2)
-
-#define divides(a, b)         ((!(a) || (b)%(a)) ? 0 : 1)
-
-
-   /*
-    *    Interface used by the world
-    */
-
-static u_long fbcon_startup(u_long kmem_start, const char **display_desc);
-static void fbcon_init(struct vc_data *conp);
-static int fbcon_deinit(struct vc_data *conp);
-static int fbcon_changevar(int con);
-static int fbcon_clear(struct vc_data *conp, int sy, int sx, int height,
-                       int width);
-static int fbcon_putc(struct vc_data *conp, int c, int yy, int xx);
-static int fbcon_putcs(struct vc_data *conp, const char *s, int count, int yy,
-                       int xx);
-static int fbcon_cursor(struct vc_data *conp, int mode);
-static int fbcon_scroll(struct vc_data *conp, int t, int b, int dir, int count);
-static int fbcon_bmove(struct vc_data *conp, int sy, int sx, int dy, int dx,
-                       int height, int width);
-static int fbcon_switch(struct vc_data *conp);
-static int fbcon_blank(int blank);
-static int fbcon_get_font(struct vc_data *conp, int *w, int *h, char *data);
-static int fbcon_set_font(struct vc_data *conp, int w, int h, char *data);
-static int fbcon_set_palette(struct vc_data *conp, unsigned char *table);
-
-
-   /*
-    *    Internal routines
-    */
-
-static void fbcon_setup(int con, int setcol, int init);
-static __inline__ void *mymemclear_small(void *s, size_t count);
-static __inline__ void *mymemclear(void *s, size_t count);
-static __inline__ void *mymemset(void *s, size_t count);
-static __inline__ void *mymemmove(void *d, void *s, size_t count);
-static __inline__ void fast_memmove(char *dst, char *src, size_t size);
-static __inline__ void memclear_4p_col(void *d, size_t h, u_long val, int bpr);
-static __inline__ void memset_even_4p(void *d, size_t count, u_long val1,
-                                      u_long val2);
-static __inline__ void memmove_4p_col(void *d, void *s, int h, int bpr);
-static __inline__ u_long expand4l(u_char c);
-static __inline__ void expand4dl(u_char c, u_long *ret1, u_long *ret2);
-static __inline__ u_long dup4l(u_char c);
-static __inline__ void memclear_8p_col(void *d, size_t h, u_long val1,
-                                       u_long val2, int bpr);
-static __inline__ void memset_even_8p(void *d, size_t count, u_long val1,
-                                      u_long val2, u_long val3, u_long val4);
-static __inline__ void memmove_8p_col(void *d, void *s, int h, int bpr);
-static __inline__ void expand8dl(u_char c, u_long *ret1, u_long *ret2);
-static __inline__ void memclear_2p_col(void *d, size_t h, u_short val,
-				       int bpr);
-static __inline__ void memset_even_2p(void *d, size_t count, u_long val);
-static __inline__ void memmove_2p_col(void *d, void *s, int h, int bpr);
-static __inline__ u_short expand2w(u_char c);
-static __inline__ u_long expand2l(u_char c);
-static __inline__ u_short dup2w(u_char c);
-static __inline__ int real_y(struct display *p, int yy);
-static void fbcon_vbl_handler(int irq, void *dummy, struct pt_regs *fp);
-static __inline__ void updatescrollmode(struct display *p);
-static __inline__ void ywrap_up(int unit, struct display *p, int count);
-static __inline__ void ywrap_down(int unit, struct display *p, int count);
-static __inline__ void ypan_up(int unit, struct vc_data *conp,
-			       struct display *p, int count);
-static __inline__ void ypan_down(int unit, struct vc_data *conp,
-				 struct display *p, int count);
-static void fbcon_bmove_rec(struct display *p, int sy, int sx, int dy, int dx,
-                            int height, int width, u_int y_break);
-
-
-   /*
-    *    Monochrome
-    */
-
-#ifdef CONFIG_FBCON_MONO
-static void bmove_mono(struct display *p, int sy, int sx, int dy, int dx,
-                       int height, int width);
-static void clear_mono(struct vc_data *conp, struct display *p, int sy, int sx,
-                       int height, int width);
-static void putc_mono(struct vc_data *conp, struct display *p, int c, int yy,
-                      int xx);
-static void putcs_mono(struct vc_data *conp, struct display *p, const char *s,
-                       int count, int yy, int xx);
-static void rev_char_mono(struct display *p, int xx, int yy);
-#endif /* CONFIG_FBCON_MONO */
-
-
-   /*
-    *    Color Interleaved Planes
-    */
-
-#ifdef CONFIG_FBCON_ILBM
-static void bmove_ilbm(struct display *p, int sy, int sx, int dy, int dx,
-                       int height, int width);
-static void clear_ilbm(struct vc_data *conp, struct display *p, int sy, int sx,
-                       int height, int width);
-static void putc_ilbm(struct vc_data *conp, struct display *p, int c, int yy,
-                      int xx);
-static void putcs_ilbm(struct vc_data *conp, struct display *p, const char *s,
-                       int count, int yy, int xx);
-static void rev_char_ilbm(struct display *p, int xx, int yy);
-#endif /* CONFIG_FBCON_ILBM */
-
-
-   /*
-    *    Color Planes
-    */
-
-#ifdef CONFIG_FBCON_PLANES
-static void bmove_plan(struct display *p, int sy, int sx, int dy, int dx,
-                       int height, int width);
-static void clear_plan(struct vc_data *conp, struct display *p, int sy, int sx,
-                       int height, int width);
-static void putc_plan(struct vc_data *conp, struct display *p, int c, int yy,
-                      int xx);
-static void putcs_plan(struct vc_data *conp, struct display *p, const char *s,
-                       int count, int yy, int xx);
-static void rev_char_plan(struct display *p, int xx, int yy);
-#endif /* CONFIG_FBCON_PLANES */
-
-
-   /*
-    *    2 Planes (2-bytes interleave)
-    */
-
-#ifdef CONFIG_FBCON_2PLANE
-static void bmove_2_plane(struct display *p, int sy, int sx, int dy, int dx,
-                          int height, int width);
-static void clear_2_plane(struct vc_data *conp, struct display *p, int sy,
-                          int sx, int height, int width);
-static void putc_2_plane(struct vc_data *conp, struct display *p, int c, int yy,
-                         int xx);
-static void putcs_2_plane(struct vc_data *conp, struct display *p,
-                          const char *s, int count, int yy, int xx);
-static void rev_char_2_plane(struct display *display, int xx, int yy);
-#endif /* CONFIG_FBCON_2PLANE */
-
-
-   /*
-    *    4 Planes (2-bytes interleave)
-    */
-
-#ifdef CONFIG_FBCON_4PLANE
-static void bmove_4_plane(struct display *p, int sy, int sx, int dy, int dx,
-                          int height, int width);
-static void clear_4_plane(struct vc_data *conp, struct display *p, int sy,
-                          int sx, int height, int width);
-static void putc_4_plane(struct vc_data *conp, struct display *p, int c, int yy,
-                         int xx);
-static void putcs_4_plane(struct vc_data *conp, struct display *p,
-                          const char *s, int count, int yy, int xx);
-static void rev_char_4_plane(struct display *p, int xx, int yy);
-#endif /* CONFIG_FBCON_4PLANE */
-
-
-   /*
-    *    8 Planes (2-bytes interleave)
-    */
-
-#ifdef CONFIG_FBCON_8PLANE
-static void bmove_8_plane(struct display *p, int sy, int sx, int dy, int dx,
-                          int height, int width);
-static void clear_8_plane(struct vc_data *conp, struct display *p, int sy,
-                          int sx, int height, int width);
-static void putc_8_plane(struct vc_data *conp, struct display *p, int c, int yy,
-                         int xx);
-static void putcs_8_plane(struct vc_data *conp, struct display *p,
-                          const char *s, int count, int yy, int xx);
-static void rev_char_8_plane(struct display *display, int xx, int yy);
-#endif /* CONFIG_FBCON_8PLANE */
-
-
-   /*
-    *    8 bpp Packed Pixels
-    */
-
-#ifdef CONFIG_FBCON_8PACKED
-static void bmove_8_packed(struct display *p, int sy, int sx, int dy, int dx,
-                           int height, int width);
-static void clear_8_packed(struct vc_data *conp, struct display *p, int sy,
-                           int sx, int height, int width);
-static void putc_8_packed(struct vc_data *conp, struct display *p, int c, int yy,
-                          int xx);
-static void putcs_8_packed(struct vc_data *conp, struct display *p,
-                           const char *s, int count, int yy, int xx);
-static void rev_char_8_packed(struct display *p, int xx, int yy);
-#endif /* CONFIG_FBCON_8PACKED */
-
-
-   /*
-    *    16 bpp Packed Pixels
-    */
-
-#ifdef CONFIG_FBCON_16PACKED
-static void bmove_16_packed(struct display *p, int sy, int sx, int dy, int dx,
-                            int height, int width);
-static void clear_16_packed(struct vc_data *conp, struct display *p, int sy,
-                            int sx, int height, int width);
-static void putc_16_packed(struct vc_data *conp, struct display *p, int c,
-                           int yy, int xx);
-static void putcs_16_packed(struct vc_data *conp, struct display *p,
-                            const char *s, int count, int yy, int xx);
-static void rev_char_16_packed(struct display *p, int xx, int yy);
-#endif */ CONFIG_FBCON_8PACKED */
-
-
-   /*
-    *    Cybervision (accelerated)
-    */
-
-#ifdef CONFIG_FBCON_CYBER
-static void bmove_cyber(struct display *p, int sy, int sx, int dy, int dx,
-                        int height, int width);
-static void clear_cyber(struct vc_data *conp, struct display *p, int sy, int sx,
-                        int height, int width);
-static void putc_cyber(struct vc_data *conp, struct display *p, int c, int yy,
-                       int xx);
-static void putcs_cyber(struct vc_data *conp, struct display *p, const char *s,
-                        int count, int yy, int xx);
-static void rev_char_cyber(struct display *p, int xx, int yy);
-
-extern void Cyber_WaitQueue(unsigned short fifo);
-extern void Cyber_WaitBlit(void);
-extern void Cyber_BitBLT(unsigned short curx, unsigned short cury,
-			 unsigned short destx, unsigned short desty,
-			 unsigned short width, unsigned short height,
-                         unsigned short mode);
-extern void Cyber_RectFill(unsigned short xx, unsigned short yy,
-			   unsigned short width, unsigned short
-			   height, unsigned short mode,
-			   unsigned short fcolor); 
-extern void Cyber_MoveCursor(unsigned short xx, unsigned short yy);
-#endif /* CONFIG_FBCON_CYBER */
-
-#ifdef CONFIG_FBCON_RETINAZ3
-static void clear_retz3(struct vc_data *conp, struct display *p, int
-			sy, int sx, int height, int width);
-static void bmove_retz3(struct display *p, int sy, int sx, int dy, int dx,
-                        int height, int width);
-extern void retz3_bitblt(struct fb_var_screeninfo *scr,
-			 unsigned short srcx, unsigned short srcy, unsigned
-			 short destx, unsigned short desty, unsigned short
-			 width, unsigned short height, unsigned short cmd,
-			 unsigned short mask);
-static void putc_retz3(struct vc_data *conp, struct display *p, int c,
-		       int yy, int xx);
-static void putcs_retz3(struct vc_data *conp, struct display *p, const
-			char *s, int count, int yy, int xx);
-static void rev_char_retz3(struct display *p, int xx, int yy);
-#endif
-
-   /*
-    *    `switch' for the Low Level Operations
-    */
-
-struct display_switch {
-    void (*bmove)(struct display *p, int sy, int sx, int dy, int dx, int height,
-                  int width);
-    void (*clear)(struct vc_data *conp, struct display *p, int sy, int sx,
-                  int height, int width);
-    void (*putc)(struct vc_data *conp, struct display *p, int c, int yy, int xx);
-    void (*putcs)(struct vc_data *conp, struct display *p, const char *s,
-                  int count, int yy, int xx);
-    void (*rev_char)(struct display *p, int xx, int yy);
-};
-
-
-#ifdef CONFIG_FBCON_MONO
-static struct display_switch dispsw_mono = {
-   bmove_mono, clear_mono, putc_mono, putcs_mono, rev_char_mono
-};
-#endif /* CONFIG_FBCON_MONO */
-
-#ifdef CONFIG_FBCON_ILBM
-static struct display_switch dispsw_ilbm = {
-   bmove_ilbm, clear_ilbm, putc_ilbm, putcs_ilbm, rev_char_ilbm
-};
-#endif /* CONFIG_FBCON_ILBM */
-
-#ifdef CONFIG_FBCON_PLANES
-static struct display_switch dispsw_plan = {
-   bmove_plan, clear_plan, putc_plan, putcs_plan, rev_char_plan
-};
-#endif /* CONFIG_FBCON_PLANES */
-
-#ifdef CONFIG_FBCON_2PLANE
-static struct display_switch dispsw_2_plane = {
-   bmove_2_plane, clear_2_plane, putc_2_plane, putcs_2_plane, rev_char_2_plane
-};
-#endif /* CONFIG_FBCON_2PLANE */
-
-#ifdef CONFIG_FBCON_4PLANE
-static struct display_switch dispsw_4_plane = {
-   bmove_4_plane, clear_4_plane, putc_4_plane, putcs_4_plane, rev_char_4_plane
-};
-#endif /* CONFIG_FBCON_4PLANE */
-
-#ifdef CONFIG_FBCON_8PLANE
-static struct display_switch dispsw_8_plane = {
-   bmove_8_plane, clear_8_plane, putc_8_plane, putcs_8_plane, rev_char_8_plane
-};
-#endif /* CONFIG_FBCON_8PLANE */
-
-#ifdef CONFIG_FBCON_8PACKED
-static struct display_switch dispsw_8_packed = {
-   bmove_8_packed, clear_8_packed, putc_8_packed, putcs_8_packed, rev_char_8_packed
-};
-#endif /* CONFIG_FBCON_8PACKED */
-
-#ifdef CONFIG_FBCON_16PACKED
-static struct display_switch dispsw_16_packed = {
-   bmove_16_packed, clear_16_packed, putc_16_packed, putcs_16_packed,
-   rev_char_16_packed
-};
-#endif /* CONFIG_FBCON_16PACKED */
-
-#ifdef CONFIG_FBCON_CYBER
-static struct display_switch dispsw_cyber = {
-   bmove_cyber, clear_cyber, putc_cyber, putcs_cyber, rev_char_cyber
-};
-#endif /* CONFIG_FBCON_CYBER */
-
-#ifdef CONFIG_FBCON_RETINAZ3
-static struct display_switch dispsw_retz3 = {
-   bmove_retz3, clear_retz3, putc_retz3,
-   putcs_retz3, rev_char_retz3
-};
-#endif
-
-
-static u_long fbcon_startup(u_long kmem_start, const char **display_desc)
-{
-   int irqres = 0;
-
-   fb_info = mach_fb_init(&kmem_start);
-   disp = fb_info->disp;
-   *display_desc = fb_info->modename;
-   fb_info->changevar = &fbcon_changevar;
-
-#ifdef CONFIG_AMIGA
-   if (MACH_IS_AMIGA) {
-      cursor_blink_rate = AMIGA_CURSOR_BLINK_RATE;
-      irqres = request_irq(IRQ_AMIGA_VERTB, fbcon_vbl_handler, 0,
-                           "console/cursor", fbcon_vbl_handler);
-   }
-#endif /* CONFIG_AMIGA */
-#ifdef CONFIG_ATARI
-   if (MACH_IS_ATARI) {
-      cursor_blink_rate = ATARI_CURSOR_BLINK_RATE;
-      irqres = request_irq(IRQ_AUTO_4, fbcon_vbl_handler, IRQ_TYPE_PRIO,
-                           "console/cursor", fbcon_vbl_handler);
-   }
-#endif /* CONFIG_ATARI */
-
-   if (irqres)
-      panic("fbcon_startup: Couldn't add vblank interrupt");
-
-   return(kmem_start);
-}
-
-
-static void fbcon_init(struct vc_data *conp)
-{
-   int unit = conp->vc_num;
-
-   if (unit)
-      disp[unit] = disp[0];
-   disp[unit].conp = conp;
-   fbcon_setup(unit, 1, 1);
-}
-
-
-static int fbcon_deinit(struct vc_data *conp)
-{
-   disp[conp->vc_num].conp = 0;
-   return(0);
-}
-
-
-static int fbcon_changevar(int con)
-{
-   fbcon_setup(con, 1, 0);
-   return(0);
-}
-
-
-static __inline__ void updatescrollmode(struct display *p)
-{
-   if (divides(p->ywrapstep, p->fontheight) &&
-       divides(p->fontheight, p->var.yres_virtual))
-      p->scrollmode = SCROLL_YWRAP;
-   else if (divides(p->ypanstep, p->fontheight) &&
-            p->var.yres_virtual >= p->var.yres+p->fontheight)
-      p->scrollmode = SCROLL_YPAN;
-   else
-      p->scrollmode = SCROLL_YMOVE;
-}
-
-
-static void fbcon_setup(int con, int setcol, int init)
-{
-   struct display *p = &disp[con];
-   struct vc_data *conp = p->conp;
-   int nr_rows, nr_cols;
-
-   p->var.xoffset = p->var.yoffset = p->yscroll = 0;  /* reset wrap/pan */
-
-   if (!fb_info->fontname[0] ||
-       !findsoftfont(fb_info->fontname, &p->fontwidth, &p->fontheight,
-                     &p->fontdata) || p->fontwidth != 8)
-	   getdefaultfont(p->var.xres, p->var.yres, NULL, &p->fontwidth,
-	                  &p->fontheight, &p->fontdata);
-   if (p->fontwidth != 8) {
-      /* ++Geert: changed from panic() to `correct and continue' */
-      printk("fbcon_setup: No support for fontwidth != 8");
-      p->fontwidth = 8;
-   }
-   updatescrollmode(p);
-
-   nr_cols = p->var.xres/p->fontwidth;
-   nr_rows = p->var.yres/p->fontheight;
-   /* ++guenther: console.c:vc_allocate() relies on initializing vc_{cols,rows},
-    * but we must not set those if we are only resizing the console.
-    */
-   if (init) {
-      conp->vc_cols = nr_cols;
-      conp->vc_rows = nr_rows;
-   }
-   p->vrows = p->var.yres_virtual/p->fontheight;
-   conp->vc_can_do_color = p->var.bits_per_pixel != 1;
-
-#ifdef CONFIG_FBCON_MONO
-   if (p->var.bits_per_pixel == 1) {
-      if (p->line_length)
-         p->next_line = p->line_length;
-      else
-         p->next_line = p->var.xres_virtual>>3;
-      p->next_plane = 0;
-      p->dispsw = &dispsw_mono;
-   } else
-#endif /* CONFIG_FBCON_MONO */
-#ifdef CONFIG_FBCON_IPLAN2
-   if (p->type == FB_TYPE_INTERLEAVED_PLANES && p->type_aux == 2) {
-      p->next_line = p->var.xres_virtual*p->var.bits_per_pixel>>3;
-      p->next_plane = 0;
-#ifdef CONFIG_FBCON_2PLANE
-      if (p->var.bits_per_pixel == 2)
-         p->dispsw = &dispsw_2_plane;
-      else
-#endif /* CONFIG_FBCON_2PLANE */
-#ifdef CONFIG_FBCON_4PLANE
-      if (p->var.bits_per_pixel == 4)
-         p->dispsw = &dispsw_4_plane;
-      else
-#endif /* CONFIG_FBCON_4PLANE */
-#ifdef CONFIG_FBCON_8PLANE
-      if (p->var.bits_per_pixel == 8)
-         p->dispsw = &dispsw_8_plane;
-      else
-#endif /* CONFIG_FBCON_8PLANE */
-      goto fail;
-   } else
-#endif /* CONFIG_FBCON_IPLAN2 */
-#ifdef CONFIG_FBCON_ILBM
-   if (p->type == FB_TYPE_INTERLEAVED_PLANES && p->type_aux != 2) {
-      if (p->line_length) {
-         p->next_line = p->line_length*p->var.bits_per_pixel;
-         p->next_plane = p->line_length
-;
-      } else {
-         p->next_line = p->type_aux;
-         p->next_plane = p->type_aux/p->var.bits_per_pixel;
-      }
-      p->dispsw = &dispsw_ilbm;
-   } else
-#endif /* CONFIG_FBCON_ILBM */
-#ifdef CONFIG_FBCON_PLANES
-   if (p->type == FB_TYPE_PLANES) {
-      if (p->line_length)
-         p->next_line = p->line_length;
-      else
-         p->next_line = p->var.xres_virtual>>3;
-      p->next_plane = p->var.yres_virtual*p->next_line;
-      p->dispsw = &dispsw_plan;
-   } else
-#endif /* CONFIG_FBCON_PLANES */
-#ifdef CONFIG_FBCON_PACKED
-   if (p->type == FB_TYPE_PACKED_PIXELS) {
-      p->next_line = (p->var.xres_virtual*p->var.bits_per_pixel)>>3;
-      p->next_plane = 0;
-#ifdef CONFIG_FBCON_CYBER
-      if (p->var.accel == FB_ACCEL_CYBERVISION)
-         p->dispsw = &dispsw_cyber;
-      else
-#endif
-#ifdef CONFIG_FBCON_RETINAZ3
-      if (p->var.accel == FB_ACCEL_RETINAZ3)
-         p->dispsw = &dispsw_retz3;
-      else
-#endif
-#ifdef CONFIG_FBCON_8PACKED
-      if (p->var.bits_per_pixel == 8)
-         p->dispsw = &dispsw_8_packed;
-      else
-#endif /* CONFIG_FBCON_8PACKED */
-#ifdef CONFIG_FBCON_16PACKED
-      if (p->var.bits_per_pixel == 16)
-         p->dispsw = &dispsw_16_packed;
-      else
-#endif /* CONFIG_FBCON_16PACKED */
-#ifdef CONFIG_FBCON_24PACKED
-      if (p->var.bits_per_pixel == 24)
-         p->dispsw = &dispsw_24_packed;
-      else
-#endif /* CONFIG_FBCON_24PACKED */
-#ifdef CONFIG_FBCON_32PACKED
-      if (p->var.bits_per_pixel == 32)
-         p->dispsw = &dispsw_32_packed;
-      else
-#endif /* CONFIG_FBCON_32PACKED */
-      goto fail;
-   } else
-#endif /* CONFIG_FBCON_PACKED */
-   {
-fail:
-#ifdef CONFIG_FBCON_MONO
-      printk("fbcon_setup: type %d (aux %d) not supported, trying mono\n",
-             p->type, p->type_aux);
-      if (p->line_length)
-         p->next_line = p->line_length;
-      else
-         p->next_line = p->var.xres_virtual>>3;
-      p->next_plane = 0;
-      p->var.bits_per_pixel = 1;
-      p->dispsw = &dispsw_mono;
-#else /* CONFIG_FBCON_MONO */
-      panic("fbcon_setup: no default driver");
-#endif /* CONFIG_FBCON_MONO */
-   }
-
-   if (setcol) {
-      p->fgcol = p->var.bits_per_pixel > 2 ? 7 : (1<<p->var.bits_per_pixel)-1;
-      p->bgcol = 0;
-   }
-
-   if (!init)
-      vc_resize_con(nr_rows, nr_cols, con);
-}
-
-
-/* ================================================================= */
-/*                      Utility Assembler Functions                  */
-/* ================================================================= */
-
-
-/* ====================================================================== */
-
-/* Those of a delicate disposition might like to skip the next couple of
- * pages.
- *
- * These functions are drop in replacements for memmove and
- * memset(_, 0, _). However their five instances add at least a kilobyte
- * to the object file. You have been warned.
- *
- * Not a great fan of assembler for the sake of it, but I think
- * that these routines are at least 10 times faster than their C
- * equivalents for large blits, and that's important to the lowest level of
- * a graphics driver. Question is whether some scheme with the blitter
- * would be faster. I suspect not for simple text system - not much
- * asynchrony.
- *
- * Code is very simple, just gruesome expansion. Basic strategy is to
- * increase data moved/cleared at each step to 16 bytes to reduce
- * instruction per data move overhead. movem might be faster still
- * For more than 15 bytes, we try to align the write direction on a
- * longword boundary to get maximum speed. This is even more gruesome.
- * Unaligned read/write used requires 68020+ - think this is a problem?
- *
- * Sorry!
- */
-
-
-/* ++roman: I've optimized Robert's original versions in some minor
- * aspects, e.g. moveq instead of movel, let gcc choose the registers,
- * use movem in some places...
- * For other modes than 1 plane, lots of more such assembler functions
- * were needed (e.g. the ones using movep or expanding color values).
- */
-
-/* ++andreas: more optimizations:
-   subl #65536,d0 replaced by clrw d0; subql #1,d0 for dbcc
-   addal is faster than addaw
-   movep is rather expensive compared to ordinary move's
-   some functions rewritten in C for clarity, no speed loss */
-
-static __inline__ void *mymemclear_small(void *s, size_t count)
-{
-   if (!count)
-      return(0);
-
-   __asm__ __volatile__(
-         "lsrl   #1,%1 ; jcc 1f ; moveb %2,%0@-\n\t"
-      "1: lsrl   #1,%1 ; jcc 1f ; movew %2,%0@-\n\t"
-      "1: lsrl   #1,%1 ; jcc 1f ; movel %2,%0@-\n\t"
-      "1: lsrl   #1,%1 ; jcc 1f ; movel %2,%0@- ; movel %2,%0@-\n\t"
-      "1: subql  #1,%1 ; jcs 3f\n\t"
-      "2: moveml %2/%3/%4/%5,%0@-\n\t"
-         "dbra %1,2b\n\t"
-      "3:"
-         : "=a" (s), "=d" (count)
-         :  "d" (0), "d" (0), "d" (0), "d" (0),
-            "0" ((char *)s+count), "1" (count)
-  );
-
-   return(0);
-}
-
-
-static __inline__ void *mymemclear(void *s, size_t count)
-{
-   if (!count)
-      return(0);
-
-   if (count < 16) {
-      __asm__ __volatile__(
-            "lsrl   #1,%1 ; jcc 1f ; clrb %0@+\n\t"
-         "1: lsrl   #1,%1 ; jcc 1f ; clrw %0@+\n\t"
-         "1: lsrl   #1,%1 ; jcc 1f ; clrl %0@+\n\t"
-         "1: lsrl   #1,%1 ; jcc 1f ; clrl %0@+ ; clrl %0@+\n\t"
-         "1:"
-            : "=a" (s), "=d" (count)
-            : "0" (s), "1" (count)
-     );
-   } else {
-      long tmp;
-      __asm__ __volatile__(
-            "movel %1,%2\n\t"
-            "lsrl   #1,%2 ; jcc 1f ; clrb %0@+ ; subqw #1,%1\n\t"
-            "lsrl   #1,%2 ; jcs 2f\n\t"  /* %0 increased=>bit 2 switched*/
-            "clrw   %0@+  ; subqw  #2,%1 ; jra 2f\n\t"
-         "1: lsrl   #1,%2 ; jcc 2f\n\t"
-            "clrw   %0@+  ; subqw  #2,%1\n\t"
-         "2: movew %1,%2; lsrl #2,%1 ; jeq 6f\n\t"
-            "lsrl   #1,%1 ; jcc 3f ; clrl %0@+\n\t"
-         "3: lsrl   #1,%1 ; jcc 4f ; clrl %0@+ ; clrl %0@+\n\t"
-         "4: subql  #1,%1 ; jcs 6f\n\t"
-         "5: clrl %0@+; clrl %0@+ ; clrl %0@+ ; clrl %0@+\n\t"
-            "dbra %1,5b   ; clrw %1; subql #1,%1; jcc 5b\n\t"
-         "6: movew %2,%1; btst #1,%1 ; jeq 7f ; clrw %0@+\n\t"
-         "7:            ; btst #0,%1 ; jeq 8f ; clrb %0@+\n\t"
-         "8:"
-            : "=a" (s), "=d" (count), "=d" (tmp)
-            : "0" (s), "1" (count)
-     );
-   }
-
-   return(0);
-}
-
-
-static __inline__ void *mymemset(void *s, size_t count)
-{
-   if (!count)
-      return(0);
-
-   __asm__ __volatile__(
-         "lsrl   #1,%1 ; jcc 1f ; moveb %2,%0@-\n\t"
-      "1: lsrl   #1,%1 ; jcc 1f ; movew %2,%0@-\n\t"
-      "1: lsrl   #1,%1 ; jcc 1f ; movel %2,%0@-\n\t"
-      "1: lsrl   #1,%1 ; jcc 1f ; movel %2,%0@- ; movel %2,%0@-\n\t"
-      "1: subql  #1,%1 ; jcs 3f\n\t"
-      "2: moveml %2/%3/%4/%5,%0@-\n\t"
-         "dbra %1,2b\n\t"
-      "3:"
-         : "=a" (s), "=d" (count)
-         :  "d" (-1), "d" (-1), "d" (-1), "d" (-1),
-            "0" ((char *) s + count), "1" (count)
-  );
-
-   return(0);
-}
-
-
-static __inline__ void *mymemmove(void *d, void *s, size_t count)
-{
-   if (d < s) {
-      if (count < 16) {
-         __asm__ __volatile__(
-               "lsrl   #1,%2 ; jcc 1f ; moveb %1@+,%0@+\n\t"
-            "1: lsrl   #1,%2 ; jcc 1f ; movew %1@+,%0@+\n\t"
-            "1: lsrl   #1,%2 ; jcc 1f ; movel %1@+,%0@+\n\t"
-            "1: lsrl   #1,%2 ; jcc 1f ; movel %1@+,%0@+ ; movel %1@+,%0@+\n\t"
-            "1:"
-               : "=a" (d), "=a" (s), "=d" (count)
-               : "0" (d), "1" (s), "2" (count)
-        );
-      } else {
-         long tmp;
-         __asm__ __volatile__(
-               "movel  %0,%3\n\t"
-               "lsrl   #1,%3 ; jcc 1f ; moveb %1@+,%0@+ ; subqw #1,%2\n\t"
-               "lsrl   #1,%3 ; jcs 2f\n\t"  /* %0 increased=>bit 2 switched*/
-               "movew  %1@+,%0@+  ; subqw  #2,%2 ; jra 2f\n\t"
-            "1: lsrl   #1,%3 ; jcc 2f\n\t"
-               "movew  %1@+,%0@+  ; subqw  #2,%2\n\t"
-            "2: movew  %2,%-; lsrl #2,%2 ; jeq 6f\n\t"
-               "lsrl   #1,%2 ; jcc 3f ; movel %1@+,%0@+\n\t"
-            "3: lsrl   #1,%2 ; jcc 4f ; movel %1@+,%0@+ ; movel %1@+,%0@+\n\t"
-            "4: subql  #1,%2 ; jcs 6f\n\t"
-            "5: movel  %1@+,%0@+;movel %1@+,%0@+\n\t"
-               "movel  %1@+,%0@+;movel %1@+,%0@+\n\t"
-               "dbra   %2,5b ; clrw %2; subql #1,%2; jcc 5b\n\t"
-            "6: movew  %+,%2; btst #1,%2 ; jeq 7f ; movew %1@+,%0@+\n\t"
-            "7:              ; btst #0,%2 ; jeq 8f ; moveb %1@+,%0@+\n\t"
-            "8:"
-               : "=a" (d), "=a" (s), "=d" (count), "=d" (tmp)
-               : "0" (d), "1" (s), "2" (count)
-        );
-      }
-   } else {
-      if (count < 16) {
-         __asm__ __volatile__(
-               "lsrl   #1,%2 ; jcc 1f ; moveb %1@-,%0@-\n\t"
-            "1: lsrl   #1,%2 ; jcc 1f ; movew %1@-,%0@-\n\t"
-            "1: lsrl   #1,%2 ; jcc 1f ; movel %1@-,%0@-\n\t"
-            "1: lsrl   #1,%2 ; jcc 1f ; movel %1@-,%0@- ; movel %1@-,%0@-\n\t"
-            "1:"
-               : "=a" (d), "=a" (s), "=d" (count)
-               : "0" ((char *) d + count), "1" ((char *) s + count), "2" (count)
-        );
-      } else {
-         long tmp;
-         __asm__ __volatile__(
-               "movel %0,%3\n\t"
-               "lsrl   #1,%3 ; jcc 1f ; moveb %1@-,%0@- ; subqw #1,%2\n\t"
-               "lsrl   #1,%3 ; jcs 2f\n\t"  /* %0 increased=>bit 2 switched*/
-               "movew  %1@-,%0@-  ; subqw  #2,%2 ; jra 2f\n\t"
-            "1: lsrl   #1,%3 ; jcc 2f\n\t"
-               "movew  %1@-,%0@-  ; subqw  #2,%2\n\t"
-            "2: movew %2,%-; lsrl #2,%2 ; jeq 6f\n\t"
-               "lsrl   #1,%2 ; jcc 3f ; movel %1@-,%0@-\n\t"
-            "3: lsrl   #1,%2 ; jcc 4f ; movel %1@-,%0@- ; movel %1@-,%0@-\n\t"
-            "4: subql  #1,%2 ; jcs 6f\n\t"
-            "5: movel %1@-,%0@-;movel %1@-,%0@-\n\t"
-               "movel %1@-,%0@-;movel %1@-,%0@-\n\t"
-               "dbra %2,5b ; clrw %2; subql #1,%2; jcc 5b\n\t"
-            "6: movew %+,%2; btst #1,%2 ; jeq 7f ; movew %1@-,%0@-\n\t"
-            "7:              ; btst #0,%2 ; jeq 8f ; moveb %1@-,%0@-\n\t"
-            "8:"
-               : "=a" (d), "=a" (s), "=d" (count), "=d" (tmp)
-               : "0" ((char *) d + count), "1" ((char *) s + count), "2" (count)
-        );
-      }
-   }
-
-   return(0);
-}
-
-
-/* ++andreas: Simple and fast version of memmove, assumes size is
-   divisible by 16, suitable for moving the whole screen bitplane */
-static __inline__ void fast_memmove(char *dst, char *src, size_t size)
-{
-  if (!size)
-    return;
-  if (dst < src)
-    __asm__ __volatile__
-      ("1:"
-       "  moveml %0@+,%/d0/%/d1/%/a0/%/a1\n"
-       "  moveml %/d0/%/d1/%/a0/%/a1,%1@\n"
-       "  addql #8,%1; addql #8,%1\n"
-       "  dbra %2,1b\n"
-       "  clrw %2; subql #1,%2\n"
-       "  jcc 1b"
-       : "=a" (src), "=a" (dst), "=d" (size)
-       : "0" (src), "1" (dst), "2" (size / 16 - 1)
-       : "d0", "d1", "a0", "a1", "memory");
-  else
-    __asm__ __volatile__
-      ("1:"
-       "  subql #8,%0; subql #8,%0\n"
-       "  moveml %0@,%/d0/%/d1/%/a0/%/a1\n"
-       "  moveml %/d0/%/d1/%/a0/%/a1,%1@-\n"
-       "  dbra %2,1b\n"
-       "  clrw %2; subql #1,%2\n"
-       "  jcc 1b"
-       : "=a" (src), "=a" (dst), "=d" (size)
-       : "0" (src + size), "1" (dst + size), "2" (size / 16 - 1)
-       : "d0", "d1", "a0", "a1", "memory");
-}
-
-
-/* Sets the bytes in the visible column at d, height h, to the value
- * val for a 4 plane screen. The the bis of the color in 'color' are
- * moved (8 times) to the respective bytes. This means:
- *
- * for(h times; d += bpr)
- *   *d     = (color & 1) ? 0xff : 0;
- *   *(d+2) = (color & 2) ? 0xff : 0;
- *   *(d+4) = (color & 4) ? 0xff : 0;
- *   *(d+6) = (color & 8) ? 0xff : 0;
- */
-
-static __inline__ void memclear_4p_col(void *d, size_t h, u_long val, int bpr)
-{
-	__asm__ __volatile__
-		("1: movepl %4,%0@(0)\n\t"
-		  "addal  %5,%0\n\t"
-		  "dbra	  %1,1b"
-		  : "=a" (d), "=d" (h)
-		  : "0" (d), "1" (h - 1), "d" (val), "r" (bpr)
-		);
-}
-
-/* Sets a 4 plane region from 'd', length 'count' bytes, to the color
- * in val1/val2. 'd' has to be an even address and count must be divisible
- * by 8, because only whole words and all planes are accessed. I.e.:
- *
- * for(count/8 times)
- *   *d     = *(d+1) = (color & 1) ? 0xff : 0;
- *   *(d+2) = *(d+3) = (color & 2) ? 0xff : 0;
- *   *(d+4) = *(d+5) = (color & 4) ? 0xff : 0;
- *   *(d+6) = *(d+7) = (color & 8) ? 0xff : 0;
- */
-
-static __inline__ void memset_even_4p(void *d, size_t count, u_long val1,
-                                      u_long val2)
-{
-  u_long *dd = d;
-
-  count /= 8;
-  while (count--)
-    {
-      *dd++ = val1;
-      *dd++ = val2;
-    }
-}
-
-/* Copies a 4 plane column from 's', height 'h', to 'd'. */
-
-static __inline__ void memmove_4p_col (void *d, void *s, int h, int bpr)
-{
-  u_char *dd = d, *ss = s;
-
-  while (h--)
-    {
-      dd[0] = ss[0];
-      dd[2] = ss[2];
-      dd[4] = ss[4];
-      dd[6] = ss[6];
-      dd += bpr;
-      ss += bpr;
-    }
-}
-
-
-/* This expands a 4 bit color into a long for movepl (4 plane) operations. */
-
-static __inline__ u_long expand4l(u_char c)
-{
-	u_long	rv;
-
-	__asm__ __volatile__
-		("lsrb	 #1,%2\n\t"
-		  "scs	 %0\n\t"
-		  "lsll	 #8,%0\n\t"
-		  "lsrb	 #1,%2\n\t"
-		  "scs	 %0\n\t"
-		  "lsll	 #8,%0\n\t"
-		  "lsrb	 #1,%2\n\t"
-		  "scs	 %0\n\t"
-		  "lsll	 #8,%0\n\t"
-		  "lsrb	 #1,%2\n\t"
-		  "scs	 %0\n\t"
-		  : "=&d" (rv), "=d" (c)
-		  : "1" (c)
-		);
-	return(rv);
-}
-
-/* This expands a 4 bit color into two longs for two movel operations
- * (4 planes).
- */
-
-static __inline__ void expand4dl(u_char c, u_long *ret1, u_long *ret2)
-{
-	u_long	rv1, rv2;
-
-	__asm__ __volatile__
-		("lsrb	 #1,%3\n\t"
-		  "scs	 %0\n\t"
-		  "extw	 %0\n\t"
-		  "swap	 %0\n\t"
-		  "lsrb	 #1,%3\n\t"
-		  "scs	 %0\n\t"
-		  "extw	 %0\n\t"
-		  "lsrb	 #1,%3\n\t"
-		  "scs	 %1\n\t"
-		  "extw	 %1\n\t"
-		  "swap	 %1\n\t"
-		  "lsrb	 #1,%3\n\t"
-		  "scs   %1\n\t"
-		  "extw	 %1"
-		  : "=&d" (rv1), "=&d" (rv2), "=d" (c)
-		  : "2" (c)
-		);
-	*ret1 = rv1;
-	*ret2 = rv2;
-}
-
-
-/* This duplicates a byte 4 times into a long. */
-
-static __inline__ u_long dup4l(u_char c)
-{
-	ushort	tmp;
-	ulong	rv;
-
-	__asm__ __volatile__
-		("moveb  %2,%0\n\t"
-		  "lslw   #8,%0\n\t"
-		  "moveb  %2,%0\n\t"
-		  "movew  %0,%1\n\t"
-		  "swap   %0\n\t"
-		  "movew  %1,%0"
-		  : "=&d" (rv), "=d" (tmp)
-		  : "d" (c)
-		);
-
-	return(rv);
-}
-
-
-/* Sets the bytes in the visible column at d, height h, to the value
- * val1,val2 for a 8 plane screen. The the bis of the color in 'color' are
- * moved (8 times) to the respective bytes. This means:
- *
- * for(h times; d += bpr)
- *   *d      = (color & 1) ? 0xff : 0;
- *   *(d+2)  = (color & 2) ? 0xff : 0;
- *   *(d+4)  = (color & 4) ? 0xff : 0;
- *   *(d+6)  = (color & 8) ? 0xff : 0;
- *   *(d+8)  = (color & 16) ? 0xff : 0;
- *   *(d+10) = (color & 32) ? 0xff : 0;
- *   *(d+12) = (color & 64) ? 0xff : 0;
- *   *(d+14) = (color & 128) ? 0xff : 0;
- */
-
-static __inline__ void memclear_8p_col(void *d, size_t h, u_long val1,
-                                       u_long val2, int bpr)
-{
-	__asm__ __volatile__
-		("1: movepl %4,%0@(0)\n\t"
-	      "movepl %5,%0@(8)\n\t"
-		  "addal  %6,%0\n\t"
-		  "dbra	  %1,1b"
-		  : "=a" (d), "=d" (h)
-		  : "0" (d), "1" (h - 1), "d" (val1), "d" (val2), "r" (bpr)
-		);
-}
-
-/* Sets a 8 plane region from 'd', length 'count' bytes, to the color
- * val1..val4. 'd' has to be an even address and count must be divisible
- * by 16, because only whole words and all planes are accessed. I.e.:
- *
- * for(count/16 times)
- *   *d      = *(d+1)  = (color & 1) ? 0xff : 0;
- *   *(d+2)  = *(d+3)  = (color & 2) ? 0xff : 0;
- *   *(d+4)  = *(d+5)  = (color & 4) ? 0xff : 0;
- *   *(d+6)  = *(d+7)  = (color & 8) ? 0xff : 0;
- *   *(d+8)  = *(d+9)  = (color & 16) ? 0xff : 0;
- *   *(d+10) = *(d+11) = (color & 32) ? 0xff : 0;
- *   *(d+12) = *(d+13) = (color & 64) ? 0xff : 0;
- *   *(d+14) = *(d+15) = (color & 128) ? 0xff : 0;
- */
-
-static __inline__ void memset_even_8p(void *d, size_t count, u_long val1,
-                                      u_long val2, u_long val3, u_long val4)
-{
-  u_long *dd = d;
-
-  count /= 16;
-  while (count--)
-    {
-      *dd++ = val1;
-      *dd++ = val2;
-      *dd++ = val3;
-      *dd++ = val4;
-    }
-}
-
-/* Copies a 8 plane column from 's', height 'h', to 'd'. */
-
-static __inline__ void memmove_8p_col (void *d, void *s, int h, int bpr)
-{
-  u_char *dd = d, *ss = s;
-
-  while (h--)
-    {
-      dd[0] = ss[0];
-      dd[2] = ss[2];
-      dd[4] = ss[4];
-      dd[6] = ss[6];
-      dd[8] = ss[8];
-      dd[10] = ss[10];
-      dd[12] = ss[12];
-      dd[14] = ss[14];
-      dd += bpr;
-      ss += bpr;
-    }
-}
-
-
-/* This expands a 8 bit color into two longs for two movepl (8 plane)
- * operations.
- */
-
-static __inline__ void expand8dl(u_char c, u_long *ret1, u_long *ret2)
-{
-	u_long	rv1, rv2;
-
-	__asm__ __volatile__
-		("lsrb	 #1,%3\n\t"
-		  "scs	 %0\n\t"
-		  "lsll	 #8,%0\n\t"
-		  "lsrb	 #1,%3\n\t"
-		  "scs	 %0\n\t"
-		  "lsll	 #8,%0\n\t"
-		  "lsrb	 #1,%3\n\t"
-		  "scs	 %0\n\t"
-		  "lsll	 #8,%0\n\t"
-		  "lsrb	 #1,%3\n\t"
-		  "scs	 %0\n\t"
-		  "lsrb	 #1,%3\n\t"
-		  "scs	 %1\n\t"
-		  "lsll	 #8,%1\n\t"
-		  "lsrb	 #1,%3\n\t"
-		  "scs	 %1\n\t"
-		  "lsll	 #8,%1\n\t"
-		  "lsrb	 #1,%3\n\t"
-		  "scs	 %1\n\t"
-		  "lsll	 #8,%1\n\t"
-		  "lsrb	 #1,%3\n\t"
-		  "scs	 %1"
-		  : "=&d" (rv1), "=&d" (rv2),"=d" (c)
-		  : "2" (c)
-		);
-
-	*ret1 = rv1;
-	*ret2 = rv2;
-}
-
-/* This expands a 8 bit color into four longs for four movel operations
- * (8 planes).
- */
-
-/* ++andreas: use macro to avoid taking address of return values */
-#define expand8ql(c, rv1, rv2, rv3, rv4) \
-do {	u_char tmp = c;						\
-	__asm__ __volatile__					\
-		("lsrb	 #1,%5\n\t"				\
-		  "scs	 %0\n\t"				\
-		  "extw	 %0\n\t"				\
-		  "swap	 %0\n\t"				\
-		  "lsrb	 #1,%5\n\t"				\
-		  "scs	 %0\n\t"				\
-		  "extw	 %0\n\t"				\
-		  "lsrb	 #1,%5\n\t"				\
-		  "scs	 %1\n\t"				\
-		  "extw	 %1\n\t"				\
-		  "swap	 %1\n\t"				\
-		  "lsrb	 #1,%5\n\t"				\
-		  "scs   %1\n\t"				\
-		  "extw	 %1\n\t"				\
-		  "lsrb	 #1,%5\n\t"				\
-		  "scs	 %2\n\t"				\
-		  "extw	 %2\n\t"				\
-		  "swap	 %2\n\t"				\
-		  "lsrb	 #1,%5\n\t"				\
-		  "scs	 %2\n\t"				\
-		  "extw	 %2\n\t"				\
-		  "lsrb	 #1,%5\n\t"				\
-		  "scs	 %3\n\t"				\
-		  "extw	 %3\n\t"				\
-		  "swap	 %3\n\t"				\
-		  "lsrb	 #1,%5\n\t"				\
-		  "scs   %3\n\t"				\
-		  "extw	 %3"					\
-		  : "=&d" (rv1), "=&d" (rv2), "=&d" (rv3),	\
-		    "=&d" (rv4), "=d" (tmp)			\
-		  : "4" (tmp)					\
-		);						\
-} while (0)
-
-
-/* Sets the bytes in the visible column at d, height h, to the value
- * val for a 2 plane screen. The the bis of the color in 'color' are
- * moved (8 times) to the respective bytes. This means:
- *
- * for(h times; d += bpr)
- *   *d     = (color & 1) ? 0xff : 0;
- *   *(d+2) = (color & 2) ? 0xff : 0;
- */
-
-static __inline__ void memclear_2p_col(void *d, size_t h, u_short val, int bpr)
-{
-	__asm__ __volatile__
-		("1: movepw %4,%0@(0)\n\t"
-		  "addal  %5,%0\n\t"
-		  "dbra	  %1,1b"
-		  : "=a" (d), "=d" (h)
-		  : "0" (d), "1" (h - 1), "d" (val), "r" (bpr)
-		);
-}
-
-/* Sets a 2 plane region from 'd', length 'count' bytes, to the color
- * in val1. 'd' has to be an even address and count must be divisible
- * by 8, because only whole words and all planes are accessed. I.e.:
- *
- * for(count/4 times)
- *   *d     = *(d+1) = (color & 1) ? 0xff : 0;
- *   *(d+2) = *(d+3) = (color & 2) ? 0xff : 0;
- */
-
-static __inline__ void memset_even_2p(void *d, size_t count, u_long val)
-{
-  u_long *dd = d;
-
-  count /= 4;
-  while (count--)
-    *dd++ = val;
-}
-
-/* Copies a 2 plane column from 's', height 'h', to 'd'. */
-
-static __inline__ void memmove_2p_col (void *d, void *s, int h, int bpr)
-{
-  u_char *dd = d, *ss = s;
-
-  while (h--)
-    {
-      dd[0] = ss[0];
-      dd[2] = ss[2];
-      dd += bpr;
-      ss += bpr;
-    }
-}
-
-
-/* This expands a 2 bit color into a short for movepw (2 plane) operations. */
-
-static __inline__ u_short expand2w(u_char c)
-{
-	u_short	rv;
-
-	__asm__ __volatile__
-		("lsrb	 #1,%2\n\t"
-		  "scs	 %0\n\t"
-		  "lsll	 #8,%0\n\t"
-		  "lsrb	 #1,%2\n\t"
-		  "scs	 %0\n\t"
-		  : "=&d" (rv), "=d" (c)
-		  : "1" (c)
-		);
-	return(rv);
-}
-
-/* This expands a 2 bit color into one long for a movel operation
- * (2 planes).
- */
-
-static __inline__ u_long expand2l(u_char c)
-{
-	u_long	rv;
-
-	__asm__ __volatile__
-		("lsrb	 #1,%2\n\t"
-		  "scs	 %0\n\t"
-		  "extw	 %0\n\t"
-		  "swap	 %0\n\t"
-		  "lsrb	 #1,%2\n\t"
-		  "scs	 %0\n\t"
-		  "extw	 %0\n\t"
-		  : "=&d" (rv), "=d" (c)
-		  : "1" (c)
-		);
-
-	return rv;
-}
-
-
-/* This duplicates a byte 2 times into a short. */
-
-static __inline__ u_short dup2w(u_char c)
-{
-    ushort  rv;
-
-    __asm__ __volatile__
-        ( "moveb  %1,%0\n\t"
-          "lslw   #8,%0\n\t"
-          "moveb  %1,%0\n\t"
-          : "=&d" (rv)
-          : "d" (c)
-        );
-
-    return( rv );
-}
-
-
-/* ====================================================================== */
-
-/* fbcon_XXX routines - interface used by the world
- *
- * This system is now divided into two levels because of complications
- * caused by hardware scrolling. Top level functions:
- *
- *    fbcon_bmove(), fbcon_clear(), fbcon_putc()
- *
- * handles y values in range [0, scr_height-1] that correspond to real
- * screen positions. y_wrap shift means that first line of bitmap may be
- * anywhere on this display. These functions convert lineoffsets to
- * bitmap offsets and deal with the wrap-around case by splitting blits.
- *
- *    fbcon_bmove_physical_8()   -- These functions fast implementations
- *    fbcon_clear_physical_8()   -- of original fbcon_XXX fns.
- *    fbcon_putc_physical_8()    -- (fontwidth != 8) may be added later
- *
- * WARNING:
- *
- * At the moment fbcon_putc() cannot blit across vertical wrap boundary
- * Implies should only really hardware scroll in rows. Only reason for
- * restriction is simplicity & efficiency at the moment.
- */
-
-static __inline__ int real_y(struct display *p, int yy)
-{
-   int rows = p->vrows;
-
-   yy += p->yscroll;
-   return(yy < rows ? yy : yy-rows);
-}
-
-
-static int fbcon_clear(struct vc_data *conp, int sy, int sx, int height,
-                       int width)
-{
-   int unit = conp->vc_num;
-   struct display *p = &disp[unit];
-   u_int y_break;
-
-   if (!p->can_soft_blank && console_blanked)
-      return(0);
-
-   if ((sy <= p->cursor_y) && (p->cursor_y < sy+height) &&
-       (sx <= p->cursor_x) && (p->cursor_x < sx+width))
-      CURSOR_UNDRAWN();
-
-   /* Split blits that cross physical y_wrap boundary */
-
-   y_break = p->vrows-p->yscroll;
-   if (sy < y_break && sy+height-1 >= y_break) {
-      u_int b = y_break-sy;
-      p->dispsw->clear(conp, p, real_y(p, sy), sx, b, width);
-      p->dispsw->clear(conp, p, real_y(p, sy+b), sx, height-b, width);
-   } else
-      p->dispsw->clear(conp, p, real_y(p, sy), sx, height, width);
-
-   return(0);
-}
-
-
-static int fbcon_putc(struct vc_data *conp, int c, int yy, int xx)
-{
-   int unit = conp->vc_num;
-   struct display *p = &disp[unit];
-
-   if (!p->can_soft_blank && console_blanked)
-      return(0);
-
-   if ((p->cursor_x == xx) && (p->cursor_y == yy))
-       CURSOR_UNDRAWN();
-
-   p->dispsw->putc(conp, p, c, real_y(p, yy), xx);
-
-   return(0);
-}
-
-
-static int fbcon_putcs(struct vc_data *conp, const char *s, int count, int yy,
-                       int xx)
-{
-   int unit = conp->vc_num;
-   struct display *p = &disp[unit];
-
-   if (!p->can_soft_blank && console_blanked)
-      return(0);
-
-   if ((p->cursor_y == yy) && (xx <= p->cursor_x) && (p->cursor_x < xx+count))
-      CURSOR_UNDRAWN();
-
-   p->dispsw->putcs(conp, p, s, count, real_y(p, yy), xx);
-
-   return(0);
-}
-
-
-static int fbcon_cursor(struct vc_data *conp, int mode)
-{
-   int unit = conp->vc_num;
-   struct display *p = &disp[unit];
-
-   /* Avoid flickering if there's no real change. */
-   if (p->cursor_x == conp->vc_x && p->cursor_y == conp->vc_y &&
-       (mode == CM_ERASE) == !cursor_on)
-      return 0;
-   if (CURSOR_UNDRAWN ())
-      p->dispsw->rev_char(p, p->cursor_x, real_y(p, p->cursor_y));
-   p->cursor_x = conp->vc_x;
-   p->cursor_y = conp->vc_y;
-
-   switch (mode) {
-      case CM_ERASE:
-         cursor_on = 0;
-         break;
-
-      case CM_MOVE:
-      case CM_DRAW:
-         vbl_cursor_cnt = CURSOR_DRAW_DELAY;
-         cursor_on = 1;
-         break;
-   }
-
-   return(0);
-}
-
-
-static void fbcon_vbl_handler(int irq, void *dummy, struct pt_regs *fp)
-{
-   struct display *p;
-
-   if (!cursor_on)
-      return;
-
-   if (vbl_cursor_cnt && --vbl_cursor_cnt == 0) {
-      /* Here no check is possible for console changing. The console
-       * switching code should set vbl_cursor_cnt to an appropriate value.
-       */
-      p = &disp[fg_console];
-      p->dispsw->rev_char(p, p->cursor_x, real_y(p, p->cursor_y));
-      cursor_drawn ^= 1;
-      vbl_cursor_cnt = cursor_blink_rate;
-   }
-}
-
-
-static __inline__ void ywrap_up(int unit, struct display *p, int count)
-{
-   p->yscroll += count;
-   if (p->yscroll >= p->vrows)	/* Deal with wrap */
-      p->yscroll -= p->vrows;
-   p->var.xoffset = 0;
-   p->var.yoffset = p->yscroll*p->fontheight;
-   p->var.vmode |= FB_VMODE_YWRAP;
-   fb_info->updatevar(unit);
-}
-
-
-static __inline__ void ywrap_down(int unit, struct display *p, int count)
-{
-   p->yscroll -= count;
-   if (p->yscroll < 0)		/* Deal with wrap */
-      p->yscroll += p->vrows;
-   p->var.xoffset = 0;
-   p->var.yoffset = p->yscroll*p->fontheight;
-   p->var.vmode |= FB_VMODE_YWRAP;
-   fb_info->updatevar(unit);
-}
-
-
-static __inline__ void ypan_up(int unit, struct vc_data *conp,
-			       struct display *p, int count)
-{
-   p->yscroll += count;
-   if (p->yscroll+conp->vc_rows > p->vrows) {
-      p->dispsw->bmove(p, p->yscroll, 0, 0, 0, conp->vc_rows-count,
-		       conp->vc_cols);
-      p->yscroll = 0;
-   }
-   p->var.xoffset = 0;
-   p->var.yoffset = p->yscroll*p->fontheight;
-   p->var.vmode &= ~FB_VMODE_YWRAP;
-   fb_info->updatevar(unit);
-}
-
-
-static __inline__ void ypan_down(int unit, struct vc_data *conp,
-				 struct display *p, int count)
-{
-   p->yscroll -= count;
-   if (p->yscroll < 0) {
-      p->yscroll = p->vrows-conp->vc_rows;
-      p->dispsw->bmove(p, 0, 0, p->yscroll+count, 0, conp->vc_rows-count,
-		       conp->vc_cols);
-   }
-   p->var.xoffset = 0;
-   p->var.yoffset = p->yscroll*p->fontheight;
-   p->var.vmode &= ~FB_VMODE_YWRAP;
-   fb_info->updatevar(unit);
-}
-
-
-static int fbcon_scroll(struct vc_data *conp, int t, int b, int dir, int count)
-{
-   int unit = conp->vc_num;
-   struct display *p = &disp[unit];
-
-   if (!p->can_soft_blank && console_blanked)
-      return(0);
-
-   fbcon_cursor(conp, CM_ERASE);
-
-   /*
-    * ++Geert: Only use ywrap/ypan if the console is in text mode
-    */
-
-   switch (dir) {
-      case SM_UP:
-	 if (count > conp->vc_rows)	/* Maximum realistic size */
-	    count = conp->vc_rows;
-	 if (vt_cons[unit]->vc_mode == KD_TEXT)
-	    switch (p->scrollmode) {
-	       case SCROLL_YWRAP:
-		  if (b-t-count > 3*conp->vc_rows>>2) {
-		     if (t > 0)
-			fbcon_bmove(conp, 0, 0, count, 0, t, conp->vc_cols);
-		     ywrap_up(unit, p, count);
-		     if (conp->vc_rows-b > 0)
-			fbcon_bmove(conp, b-count, 0, b, 0, conp->vc_rows-b,
-				    conp->vc_cols);
-		  } else
-		     fbcon_bmove(conp, t+count, 0, t, 0, b-t-count,
-				 conp->vc_cols);
-		  fbcon_clear(conp, b-count, 0, count, conp->vc_cols);
-		  break;
-
-	       case SCROLL_YPAN:
-		  if (b-t-count > 3*conp->vc_rows>>2) {
-		     if (t > 0)
-			fbcon_bmove(conp, 0, 0, count, 0, t, conp->vc_cols);
-		     ypan_up(unit, conp, p, count);
-		     if (conp->vc_rows-b > 0)
-			fbcon_bmove(conp, b-count, 0, b, 0, conp->vc_rows-b,
-				    conp->vc_cols);
-		  } else
-		     fbcon_bmove(conp, t+count, 0, t, 0, b-t-count,
-				 conp->vc_cols);
-		  fbcon_clear(conp, b-count, 0, count, conp->vc_cols);
-		  break;
-
-	       case SCROLL_YMOVE:
-		  p->dispsw->bmove(p, t+count, 0, t, 0, b-t-count,
-				   conp->vc_cols);
-		  p->dispsw->clear(conp, p, b-count, 0, count, conp->vc_cols);
-		  break;
-	    }
-	 else {
-	    fbcon_bmove(conp, t+count, 0, t, 0, b-t-count, conp->vc_cols);
-	    fbcon_clear(conp, b-count, 0, count, conp->vc_cols);
-	 }
-         break;
-
-      case SM_DOWN:
-	 if (count > conp->vc_rows)	/* Maximum realistic size */
-	    count = conp->vc_rows;
-	 if (vt_cons[unit]->vc_mode == KD_TEXT)
-	    switch (p->scrollmode) {
-	       case SCROLL_YWRAP:
-		  if (b-t-count > 3*conp->vc_rows>>2) {
-		     if (conp->vc_rows-b > 0)
-			fbcon_bmove(conp, b, 0, b-count, 0, conp->vc_rows-b,
-				    conp->vc_cols);
-		     ywrap_down(unit, p, count);
-		     if (t > 0)
-			fbcon_bmove(conp, count, 0, 0, 0, t, conp->vc_cols);
-		  } else
-		     fbcon_bmove(conp, t, 0, t+count, 0, b-t-count,
-				 conp->vc_cols);
-		  fbcon_clear(conp, t, 0, count, conp->vc_cols);
-		  break;
-
-	       case SCROLL_YPAN:
-		  if (b-t-count > 3*conp->vc_rows>>2) {
-		     if (conp->vc_rows-b > 0)
-			fbcon_bmove(conp, b, 0, b-count, 0, conp->vc_rows-b,
-				    conp->vc_cols);
-		     ypan_down(unit, conp, p, count);
-		     if (t > 0)
-			fbcon_bmove(conp, count, 0, 0, 0, t, conp->vc_cols);
-		  } else
-		     fbcon_bmove(conp, t, 0, t+count, 0, b-t-count,
-				 conp->vc_cols);
-		  fbcon_clear(conp, t, 0, count, conp->vc_cols);
-		  break;
-
-	       case SCROLL_YMOVE:
-		  p->dispsw->bmove(p, t, 0, t+count, 0, b-t-count,
-				   conp->vc_cols);
-		  p->dispsw->clear(conp, p, t, 0, count, conp->vc_cols);
-		  break;
-	    }
-	 else {
-	    /*
-	     * Fixed bmove() should end Arno's frustration with copying?
-	     * Confucius says:
-	     *    Man who copies in wrong direction, end up with trashed data
-	     */
-	    fbcon_bmove(conp, t, 0, t+count, 0, b-t-count, conp->vc_cols);
-	    fbcon_clear(conp, t, 0, count, conp->vc_cols);
-	 }
-         break;
-
-      case SM_LEFT:
-         fbcon_bmove(conp, 0, t+count, 0, t, conp->vc_rows, b-t-count);
-         fbcon_clear(conp, 0, b-count, conp->vc_rows, count);
-         break;
-
-      case SM_RIGHT:
-         fbcon_bmove(conp, 0, t, 0, t+count, conp->vc_rows, b-t-count);
-         fbcon_clear(conp, 0, t, conp->vc_rows, count);
-         break;
-   }
-
-   return(0);
-}
-
-
-static int fbcon_bmove(struct vc_data *conp, int sy, int sx, int dy, int dx,
-                       int height, int width)
-{
-   int unit = conp->vc_num;
-   struct display *p = &disp[unit];
-
-   if (!p->can_soft_blank && console_blanked)
-      return(0);
-
-   if (((sy <= p->cursor_y) && (p->cursor_y < sy+height) &&
-        (sx <= p->cursor_x) && (p->cursor_x < sx+width)) ||
-       ((dy <= p->cursor_y) && (p->cursor_y < dy+height) &&
-        (dx <= p->cursor_x) && (p->cursor_x < dx+width)))
-      fbcon_cursor(conp, CM_ERASE);
-
-   /* Split blits that cross physical y_wrap case.
-    * Pathological case involves 4 blits, better to use recursive
-    * code rather than unrolled case
-    *
-    * Recursive invocations don't need to erase the cursor over and
-    * over again, so we use fbcon_bmove_rec()
-    */
-   fbcon_bmove_rec(p, sy, sx, dy, dx, height, width, p->vrows-p->yscroll);
-
-   return(0);
-}
-
-
-static void fbcon_bmove_rec(struct display *p, int sy, int sx, int dy, int dx,
-                            int height, int width, u_int y_break)
-{
-   u_int b;
-
-   if (sy < y_break && sy+height > y_break) {
-      b = y_break-sy;
-      if (dy < sy) {       /* Avoid trashing self */
-         fbcon_bmove_rec(p, sy, sx, dy, dx, b, width, y_break);
-         fbcon_bmove_rec(p, sy+b, sx, dy+b, dx, height-b, width, y_break);
-      } else {
-         fbcon_bmove_rec(p, sy+b, sx, dy+b, dx, height-b, width, y_break);
-         fbcon_bmove_rec(p, sy, sx, dy, dx, b, width, y_break);
-      }
-      return;
-   }
-
-   if (dy < y_break && dy+height > y_break) {
-      b = y_break-dy;
-      if (dy < sy) {       /* Avoid trashing self */
-         fbcon_bmove_rec(p, sy, sx, dy, dx, b, width, y_break);
-         fbcon_bmove_rec(p, sy+b, sx, dy+b, dx, height-b, width, y_break);
-      } else {
-         fbcon_bmove_rec(p, sy+b, sx, dy+b, dx, height-b, width, y_break);
-         fbcon_bmove_rec(p, sy, sx, dy, dx, b, width, y_break);
-      }
-      return;
-   }
-   p->dispsw->bmove(p, real_y(p, sy), sx, real_y(p, dy), dx, height, width);
-}
-
-
-static int fbcon_switch(struct vc_data *conp)
-{
-   if (fb_info && fb_info->switch_con)
-      (*fb_info->switch_con)(conp->vc_num);
-   return(0);
-}
-
-
-static int fbcon_blank(int blank)
-{
-   struct display *p = &disp[fg_console];
-
-   fbcon_cursor(p->conp, blank ? CM_ERASE : CM_DRAW);
-
-   if (!p->can_soft_blank)
-      if (blank) {
-         if (p->visual == FB_VISUAL_MONO01)
-             mymemset(p->screen_base, p->var.xres_virtual*p->var.yres_virtual*
-                                      p->var.bits_per_pixel>>3);
-          else
-             mymemclear(p->screen_base, p->var.xres_virtual*p->var.yres_virtual*
-                                        p->var.bits_per_pixel>>3);
-         return(0);
-      } else {
-         /* Tell console.c that it has to restore the screen itself */
-         return(1);
-      }
-   (*fb_info->blank)(blank);
-   return(0);
-}
-
-
-static int fbcon_get_font(struct vc_data *conp, int *w, int *h, char *data)
-{
-	int unit = conp->vc_num;
-	struct display *p = &disp[unit];
-	int i, j, size, alloc;
-
-	size = (p->fontwidth+7)/8 * p->fontheight * 256;
-	alloc = (*w+7)/8 * *h * 256;
-	*w = p->fontwidth;
-	*h = p->fontheight;
-   
-	if (alloc < size)
-		/* allocation length not sufficient */
-		return( -ENAMETOOLONG );
-
-	for (i = 0; i < 256; i++)
-		for (j = 0; j < p->fontheight; j++)
-			data[i*32+j] = p->fontdata[i*p->fontheight+j];
-	return( 0 );
-}
-
-
-#define REFCOUNT(fd)	(((int *)(fd))[-1])
-
-static int fbcon_set_font(struct vc_data *conp, int w, int h, char *data)
-{
-	int unit = conp->vc_num;
-	struct display *p = &disp[unit];
-	int i, j, size, userspace = 1, resize;
-	char *old_data = NULL, *new_data;
-
-	if (w < 0)
-		w = p->fontwidth;
-	if (h < 0)
-		h = p->fontheight;
-	
-	if (w == 0) {
-		/* engage predefined font, name in 'data' */
-		char name[MAX_FONT_NAME+1];
-	   
-		if ((i = verify_area( VERIFY_READ, (void *)data, MAX_FONT_NAME )))
-			return i;
-		copy_from_user( name, data, MAX_FONT_NAME );
-		name[sizeof(name)-1] = 0;
-		
-		if (!findsoftfont( name, &w, &h, (u_char **)&data ))
-			return( -ENOENT );
-		userspace = 0;
-	}
-	else if (w == 1) {
-		/* copy font from some other console in 'h'*/
-		struct display *op;
-
-		if (h < 0 || !vc_cons_allocated( h ))
-			return( -ENOTTY );
-		if (h == unit)
-			return( 0 ); /* nothing to do */
-		op = &disp[h];
-		if (op->fontdata == p->fontdata)
-			return( 0 ); /* already the same font... */
-
-		resize = (op->fontwidth != p->fontwidth) ||
-			     (op->fontheight != p->fontheight);
-		if (p->userfont)
-			old_data = p->fontdata;
-		p->fontdata = op->fontdata;
-		w = p->fontwidth = op->fontwidth;
-		h = p->fontheight = op->fontheight;
-		if ((p->userfont = op->userfont))
-			REFCOUNT(p->fontdata)++; /* increment usage counter */
-		goto activate;
-	}
-
-	if (w != 8)
-		/* Currently only fontwidth == 8 supported */
-		return( -ENXIO );
-	
-	resize = (w != p->fontwidth) || (h != p->fontheight);
-	size = (w+7)/8 * h * 256;
-	
-	if (p->userfont)
-		old_data = p->fontdata;
-	
-	if (userspace) {
-		if (!(new_data = kmalloc( sizeof(int)+size, GFP_USER )))
-			return( -ENOMEM );
-		new_data += sizeof(int);
-		REFCOUNT(new_data) = 1; /* usage counter */
-
-		for (i = 0; i < 256; i++)
-			for (j = 0; j < h; j++)
-				new_data[i*h+j] = data[i*32+j];
-
-		p->fontdata = new_data;
-		p->userfont = 1;
-	}
-	else {
-		p->fontdata = data;
-		p->userfont = 0;
-	}
-	p->fontwidth = w;
-	p->fontheight = h;
-
-  activate:
-	if (resize) {
-		p->var.xoffset = p->var.yoffset = p->yscroll = 0;  /* reset wrap/pan */
-		/* Adjust the virtual screen-size to fontheight*rows */
-		p->var.yres_virtual = (p->var.yres/h)*h;
-		p->vrows = p->var.yres_virtual/h;
-		updatescrollmode(p);
-		vc_resize_con( p->var.yres/h, p->var.xres/w, unit );
-	}
-	else if (unit == fg_console)
-		update_screen( unit );
-	
-	if (old_data) {
-		if (--REFCOUNT(old_data) == 0) {
-			kfree( old_data - sizeof(int) );
-		}
-	}
-	
-	return( 0 );
-}
-
-static unsigned short palette_red[16];
-static unsigned short palette_green[16];
-static unsigned short palette_blue[16];
-
-static struct fb_cmap palette_cmap  = {
-    0, 16, palette_red, palette_green, palette_blue, NULL
-};
-
-static int fbcon_set_palette(struct vc_data *conp, unsigned char *table)
-{
-    int unit = conp->vc_num;
-    struct display *p = &disp[unit];
-    int i, j, k;
-    u_char val;
-
-    if (!conp->vc_can_do_color || (!p->can_soft_blank && console_blanked))
-	return(-EINVAL);
-    for (i = j = 0; i < 16; i++) {
-	k = table[i];
-	val = conp->vc_palette[j++];
-	palette_red[k] = (val<<8)|val;
-	val = conp->vc_palette[j++];
-	palette_green[k] = (val<<8)|val;
-	val = conp->vc_palette[j++];
-	palette_blue[k] = (val<<8)|val;
-    }
-    palette_cmap.len = 1<<p->var.bits_per_pixel;
-    if (palette_cmap.len > 16)
-	palette_cmap.len = 16;
-    return(fb_info->setcmap(&palette_cmap, unit));
-}
-
-
-/* ====================================================================== */
-
-/*
- *    Low Level Operations for the various display memory organizations.
- *
- *    Currently only the following organizations are supported here:
- *
- *      - Monochrome
- *      - Color Interleaved Planes à la Amiga
- *      - Color Normal Planes
- *      - Color Interleaved Planes à la Atari (2, 4 and 8 planes)
- *      - Color Packed Pixels (8 and 16 bpp)
- *      - Cybervision Color Packed Pixels (accelerated)
- */
-
-#ifdef CONFIG_FBCON_MONO
-
-   /*
-    *    Monochrome
-    */
-
-static void bmove_mono(struct display *p, int sy, int sx, int dy, int dx,
-                       int height, int width)
-{
-   u_char *src, *dest;
-   u_int rows;
-
-   if (sx == 0 && dx == 0 && width == p->next_line) {
-      src = p->screen_base+sy*p->fontheight*width;
-      dest = p->screen_base+dy*p->fontheight*width;
-      mymemmove(dest, src, height*p->fontheight*width);
-   } else if (dy <= sy) {
-      src = p->screen_base+sy*p->fontheight*p->next_line+sx;
-      dest = p->screen_base+dy*p->fontheight*p->next_line+dx;
-      for (rows = height*p->fontheight; rows--;) {
-         mymemmove(dest, src, width);
-         src += p->next_line;
-         dest += p->next_line;
-      }
-   } else {
-      src = p->screen_base+((sy+height)*p->fontheight-1)*p->next_line+sx;
-      dest = p->screen_base+((dy+height)*p->fontheight-1)*p->next_line+dx;
-      for (rows = height*p->fontheight; rows--;) {
-         mymemmove(dest, src, width);
-         src -= p->next_line;
-         dest -= p->next_line;
-      }
-   }
-}
-
-
-static void clear_mono(struct vc_data *conp, struct display *p, int sy, int sx,
-                       int height, int width)
-{
-   u_char *dest;
-   u_int rows;
-
-   dest = p->screen_base+sy*p->fontheight*p->next_line+sx;
-
-   if (sx == 0 && width == p->next_line)
-      if (attr_reverse(p,conp))
-         mymemset(dest, height*p->fontheight*width);
-      else
-         mymemclear(dest, height*p->fontheight*width);
-   else
-      for (rows = height*p->fontheight; rows--; dest += p->next_line)
-         if (attr_reverse(p,conp))
-            mymemset(dest, width);
-         else
-            mymemclear_small(dest, width);
-}
-
-
-static void putc_mono(struct vc_data *conp, struct display *p, int c, int yy,
-                      int xx)
-{
-   u_char *dest, *cdat;
-   u_int rows, bold, revs, underl;
-   u_char d;
-
-   c &= 0xff;
-
-   dest = p->screen_base + yy*p->fontheight*p->next_line + xx;
-   cdat = p->fontdata+c*p->fontheight;
-   bold = attr_bold(p,conp);
-   revs = attr_reverse(p,conp);
-   underl = attr_underline(p,conp);
-
-   for (rows = p->fontheight; rows--; dest += p->next_line) {
-      d = *cdat++;
-      if (underl && !rows)
-         d = 0xff;
-      else if (bold)
-         d |= d>>1;
-      if (revs)
-         d = ~d;
-      *dest = d;
-   }
-}
-
-
-static void putcs_mono(struct vc_data *conp, struct display *p, const char *s,
-                       int count, int yy, int xx)
-{
-   u_char *dest, *dest0, *cdat;
-   u_int rows, bold, revs, underl;
-   u_char c, d;
-
-   dest0 = p->screen_base + yy*p->fontheight*p->next_line + xx;
-   bold = attr_bold(p,conp);
-   revs = attr_reverse(p,conp);
-   underl = attr_underline(p,conp);
-
-   while (count--) {
-      c = *s++;
-      dest = dest0++;
-      cdat = p->fontdata+c*p->fontheight;
-      for (rows = p->fontheight; rows--; dest += p->next_line) {
-         d = *cdat++;
-         if (underl && !rows)
-            d = 0xff;
-         else if (bold)
-            d |= d>>1;
-         if (revs)
-            d = ~d;
-         *dest = d;
-      }
-   }
-}
-
-
-static void rev_char_mono(struct display *p, int xx, int yy)
-{
-   u_char *dest;
-   u_int rows;
-
-   dest = p->screen_base + yy*p->fontheight*p->next_line + xx;
-   for (rows = p->fontheight; rows--; dest += p->next_line)
-      *dest = ~*dest;
-}
-
-#endif /* CONFIG_FBCON_MONO */
-
-
-/* ====================================================================== */
-
-#ifdef CONFIG_FBCON_ILBM
-
-   /*
-    *    Color Interleaved Planes
-    *
-    *    This code heavily relies on the fact that
-    *
-    *       next_line == interleave == next_plane*bits_per_pixel
-    *
-    *    But maybe it can be merged with the code for normal bitplanes without
-    *    much performance loss?
-    */
-
-static void bmove_ilbm(struct display *p, int sy, int sx, int dy, int dx,
-                       int height, int width)
-{
-   if (sx == 0 && dx == 0 && width == p->next_plane)
-      mymemmove(p->screen_base+dy*p->fontheight*p->next_line,
-		p->screen_base+sy*p->fontheight*p->next_line,
-                height*p->fontheight*p->next_line);
-   else {
-      u_char *src, *dest;
-      u_int i;
-
-      if (dy <= sy) {
-         src = p->screen_base+sy*p->fontheight*p->next_line+sx;
-         dest = p->screen_base+dy*p->fontheight*p->next_line+dx;
-         for (i = p->var.bits_per_pixel*height*p->fontheight; i--;) {
-            mymemmove(dest, src, width);
-            src += p->next_plane;
-            dest += p->next_plane;
-         }
-      } else {
-         src = p->screen_base+(sy+height)*p->fontheight*p->next_line+sx;
-         dest = p->screen_base+(dy+height)*p->fontheight*p->next_line+dx;
-         for (i = p->var.bits_per_pixel*height*p->fontheight; i--;) {
-            src -= p->next_plane;
-            dest -= p->next_plane;
-            mymemmove(dest, src, width);
-         }
-      }
-   }
-}
-
-
-static void clear_ilbm(struct vc_data *conp, struct display *p, int sy, int sx,
-                       int height, int width)
-{
-   u_char *dest;
-   u_int i, rows;
-   int bg, bg0;
-
-   dest = p->screen_base+sy*p->fontheight*p->next_line+sx;
-
-   bg0 = attr_bgcol_ec(p,conp);
-   for (rows = height*p->fontheight; rows--;) {
-      bg = bg0;
-      for (i = p->var.bits_per_pixel; i--; dest += p->next_plane) {
-         if (bg & 1)
-            mymemset(dest, width);
-         else
-            mymemclear(dest, width);
-         bg >>= 1;
-      }
-   }
-}
-
-
-static void putc_ilbm(struct vc_data *conp, struct display *p, int c, int yy,
-                      int xx)
-{
-   u_char *dest, *cdat;
-   u_int rows, i;
-   u_char d;
-   int fg0, bg0, fg, bg;
-
-   c &= 0xff;
-
-   dest = p->screen_base + yy*p->fontheight*p->next_line + xx;
-   cdat = p->fontdata+c*p->fontheight;
-   fg0 = attr_fgcol(p,conp);
-   bg0 = attr_bgcol(p,conp);
-
-   for (rows = p->fontheight; rows--;) {
-      d = *cdat++;
-      fg = fg0;
-      bg = bg0;
-      for (i = p->var.bits_per_pixel; i--; dest += p->next_plane) {
-         if (bg & 1)
-            if (fg & 1)
-               *dest = 0xff;
-            else
-               *dest = ~d;
-         else
-            if (fg & 1)
-               *dest = d;
-            else
-               *dest = 0x00;
-         bg >>= 1;
-         fg >>= 1;
-      }
-   }
-}
-
-
-/*
- *    I split the console character loop in two parts:
- *
- *      - slow version: this blits one character at a time
- *
- *      - fast version: this blits 4 characters at a time at a longword aligned
- *                      address, to reduce the number of expensive Chip RAM
- *                      accesses.
- *
- *    Experiments on my A4000/040 revealed that this makes a console
- *    switch on a 640x400 screen with 256 colors about 3 times faster.
- *
- *                                                                Geert
- */
-
-static void putcs_ilbm(struct vc_data *conp, struct display *p, const char *s,
-                       int count, int yy, int xx)
-{
-   u_char *dest0, *dest, *cdat1, *cdat2, *cdat3, *cdat4;
-   u_int rows, i;
-   u_char c1, c2, c3, c4;
-   u_long d;
-   int fg0, bg0, fg, bg;
-
-   dest0 = p->screen_base + yy*p->fontheight*p->next_line + xx;
-   fg0 = attr_fgcol(p,conp);
-   bg0 = attr_bgcol(p,conp);
-
-   while (count--)
-      if (xx & 3 || count < 3) {   /* Slow version */
-         c1 = *s++;
-         dest = dest0++;
-         xx++;
-
-         cdat1 = p->fontdata+c1*p->fontheight;
-         for (rows = p->fontheight; rows--;) {
-            d = *cdat1++;
-            fg = fg0;
-            bg = bg0;
-            for (i = p->var.bits_per_pixel; i--; dest += p->next_plane) {
-               if (bg & 1)
-                  if (fg & 1)
-                     *dest = 0xff;
-                  else
-                     *dest = ~d;
-               else
-                  if (fg & 1)
-                     *dest = d;
-                  else
-                     *dest = 0x00;
-               bg >>= 1;
-               fg >>= 1;
-            }
-         }
-      } else {                      /* Fast version */
-         c1 = s[0];
-         c2 = s[1];
-         c3 = s[2];
-         c4 = s[3];
-
-         dest = dest0;
-         cdat1 = p->fontdata+c1*p->fontheight;
-         cdat2 = p->fontdata+c2*p->fontheight;
-         cdat3 = p->fontdata+c3*p->fontheight;
-         cdat4 = p->fontdata+c4*p->fontheight;
-         for (rows = p->fontheight; rows--;) {
-            d = *cdat1++<<24 | *cdat2++<<16 | *cdat3++<<8 | *cdat4++;
-            fg = fg0;
-            bg = bg0;
-            for (i = p->var.bits_per_pixel; i--; dest += p->next_plane) {
-               if (bg & 1)
-                  if (fg & 1)
-                     *(u_long *)dest = 0xffffffff;
-                  else
-                     *(u_long *)dest = ~d;
-               else
-                  if (fg & 1)
-                     *(u_long *)dest = d;
-                  else
-                     *(u_long *)dest = 0x00000000;
-               bg >>= 1;
-               fg >>= 1;
-            }
-         }
-         s += 4;
-         dest0 += 4;
-         xx += 4;
-         count -= 3;
-      }
-}
-
-
-static void rev_char_ilbm(struct display *p, int xx, int yy)
-{
-   u_char *dest, *dest0;
-   u_int rows, i;
-   int mask;
-
-   dest0 = p->screen_base + yy*p->fontheight*p->next_line + xx;
-   mask = p->fgcol ^ p->bgcol;
-
-   /*
-    *    This should really obey the individual character's
-    *    background and foreground colors instead of simply
-    *    inverting.
-    */
-
-   for (i = p->var.bits_per_pixel; i--; dest0 += p->next_plane) {
-      if (mask & 1) {
-         dest = dest0;
-         for (rows = p->fontheight; rows--; dest += p->next_line)
-            *dest = ~*dest;
-      }
-      mask >>= 1;
-   }
-}
-
-#endif /* CONFIG_FBCON_ILBM */
-
-
-/* ====================================================================== */
-
-#ifdef CONFIG_FBCON_PLANES
-
-   /*
-    *    Color Planes
-    */
-
-static void bmove_plan(struct display *p, int sy, int sx, int dy, int dx,
-                       int height, int width)
-{
-   u_char *src, *dest, *src0, *dest0;
-   u_int i, rows;
-
-   if (sx == 0 && dx == 0 && width == p->next_line) {
-      src = p->screen_base+sy*p->fontheight*width;
-      dest = p->screen_base+dy*p->fontheight*width;
-      for (i = p->var.bits_per_pixel; i--;) {
-         mymemmove(dest, src, height*p->fontheight*width);
-         src += p->next_plane;
-         dest += p->next_plane;
-      }
-   } else if (dy <= sy) {
-      src0 = p->screen_base+sy*p->fontheight*p->next_line+sx;
-      dest0 = p->screen_base+dy*p->fontheight*p->next_line+dx;
-      for (i = p->var.bits_per_pixel; i--;) {
-         src = src0;
-         dest = dest0;
-         for (rows = height*p->fontheight; rows--;) {
-            mymemmove(dest, src, width);
-            src += p->next_line;
-            dest += p->next_line;
-         }
-         src0 += p->next_plane;
-         dest0 += p->next_plane;
-      }
-   } else {
-      src0 = p->screen_base+(sy+height)*p->fontheight*p->next_line+sx;
-      dest0 = p->screen_base+(dy+height)*p->fontheight*p->next_line+dx;
-      for (i = p->var.bits_per_pixel; i--;) {
-         src = src0;
-         dest = dest0;
-         for (rows = height*p->fontheight; rows--;) {
-            src -= p->next_line;
-            dest -= p->next_line;
-            mymemmove(dest, src, width);
-         }
-         src0 += p->next_plane;
-         dest0 += p->next_plane;
-      }
-   }
-}
-
-
-static void clear_plan(struct vc_data *conp, struct display *p, int sy, int sx,
-                       int height, int width)
-{
-   u_char *dest, *dest0;
-   u_int i, rows;
-   int bg;
-
-   dest0 = p->screen_base+sy*p->fontheight*p->next_line+sx;
-
-   bg = attr_bgcol_ec(p,conp);
-   for (i = p->var.bits_per_pixel; i--; dest0 += p->next_plane) {
-      dest = dest0;
-      for (rows = height*p->fontheight; rows--; dest += p->next_line)
-         if (bg & 1)
-            mymemset(dest, width);
-         else
-            mymemclear(dest, width);
-      bg >>= 1;
-   }
-}
-
-
-static void putc_plan(struct vc_data *conp, struct display *p, int c, int yy,
-                      int xx)
-{
-   u_char *dest, *dest0, *cdat, *cdat0;
-   u_int rows, i;
-   u_char d;
-   int fg, bg;
-
-   c &= 0xff;
-
-   dest0 = p->screen_base + yy*p->fontheight*p->next_line + xx;
-   cdat0 = p->fontdata+c*p->fontheight;
-   fg = attr_fgcol(p,conp);
-   bg = attr_bgcol(p,conp);
-
-   for (i = p->var.bits_per_pixel; i--; dest0 += p->next_plane) {
-      dest = dest0;
-      cdat = cdat0;
-      for (rows = p->fontheight; rows--; dest += p->next_line) {
-         d = *cdat++;
-         if (bg & 1)
-            if (fg & 1)
-               *dest = 0xff;
-            else
-               *dest = ~d;
-         else
-            if (fg & 1)
-               *dest = d;
-            else
-               *dest = 0x00;
-      }
-      bg >>= 1;
-      fg >>= 1;
-   }
-}
-
-
-/*
- *    I split the console character loop in two parts
- *    (cfr. fbcon_putcs_ilbm())
- */
-
-static void putcs_plan(struct vc_data *conp, struct display *p, const char *s,
-                       int count, int yy, int xx)
-{
-   u_char *dest, *dest0, *dest1;
-   u_char *cdat1, *cdat2, *cdat3, *cdat4, *cdat10, *cdat20, *cdat30, *cdat40;
-   u_int rows, i;
-   u_char c1, c2, c3, c4;
-   u_long d;
-   int fg0, bg0, fg, bg;
-
-   dest0 = p->screen_base + yy*p->fontheight*p->next_line + xx;
-   fg0 = attr_fgcol(p,conp);
-   bg0 = attr_bgcol(p,conp);
-
-   while (count--)
-      if (xx & 3 || count < 3) {   /* Slow version */
-         c1 = *s++;
-         dest1 = dest0++;
-         xx++;
-
-         cdat10 = p->fontdata+c1*p->fontheight;
-         fg = fg0;
-         bg = bg0;
-
-         for (i = p->var.bits_per_pixel; i--; dest1 += p->next_plane) {
-            dest = dest1;
-            cdat1 = cdat10;
-            for (rows = p->fontheight; rows--; dest += p->next_line) {
-               d = *cdat1++;
-               if (bg & 1)
-                  if (fg & 1)
-                     *dest = 0xff;
-                  else
-                     *dest = ~d;
-               else
-                  if (fg & 1)
-                     *dest = d;
-                  else
-                     *dest = 0x00;
-            }
-            bg >>= 1;
-            fg >>= 1;
-         }
-      } else {                      /* Fast version */
-         c1 = s[0];
-         c2 = s[1];
-         c3 = s[2];
-         c4 = s[3];
-
-         dest1 = dest0;
-         cdat10 = p->fontdata+c1*p->fontheight;
-         cdat20 = p->fontdata+c2*p->fontheight;
-         cdat30 = p->fontdata+c3*p->fontheight;
-         cdat40 = p->fontdata+c4*p->fontheight;
-         fg = fg0;
-         bg = bg0;
-
-         for (i = p->var.bits_per_pixel; i--; dest1 += p->next_plane) {
-            dest = dest1;
-            cdat1 = cdat10;
-            cdat2 = cdat20;
-            cdat3 = cdat30;
-            cdat4 = cdat40;
-            for (rows = p->fontheight; rows--; dest += p->next_line) {
-               d = *cdat1++<<24 | *cdat2++<<16 | *cdat3++<<8 | *cdat4++;
-               if (bg & 1)
-                  if (fg & 1)
-                     *(u_long *)dest = 0xffffffff;
-                  else
-                     *(u_long *)dest = ~d;
-               else
-                  if (fg & 1)
-                     *(u_long *)dest = d;
-                  else
-                     *(u_long *)dest = 0x00000000;
-            }
-            bg >>= 1;
-            fg >>= 1;
-         }
-         s += 4;
-         dest0 += 4;
-         xx += 4;
-         count -= 3;
-      }
-}
-
-
-static void rev_char_plan(struct display *p, int xx, int yy)
-{
-   u_char *dest, *dest0;
-   u_int rows, i;
-   int mask;
-
-   dest0 = p->screen_base + yy*p->fontheight*p->next_line + xx;
-   mask = p->fgcol ^ p->bgcol;
-
-   /*
-    *    This should really obey the individual character's
-    *    background and foreground colors instead of simply
-    *    inverting.
-    */
-
-   for (i = p->var.bits_per_pixel; i--; dest0 += p->next_plane) {
-      if (mask & 1) {
-         dest = dest0;
-         for (rows = p->fontheight; rows--; dest += p->next_line)
-            *dest = ~*dest;
-      }
-      mask >>= 1;
-   }
-}
-
-#endif /* CONFIG_FBCON_PLANES */
-
-
-/* ====================================================================== */
-
-#ifdef CONFIG_FBCON_2PLANE
-
-   /*
-    *    2 Planes (2-bytes interleave)
-    */
-
-/* Increment/decrement 2 plane addresses */
-
-#define	INC_2P(p)	do { if (!((long)(++(p)) & 1)) (p) += 2; } while(0)
-#define	DEC_2P(p)	do { if ((long)(--(p)) & 1) (p) -= 2; } while(0)
-
-/* Convert a standard 4 bit color to our 2 bit color assignment:
- * If at least two RGB channels are active, the low bit is turned on;
- * The intensity bit (b3) is shifted into b1.
- */
-
-#define	COLOR_2P(c)	(((c & 7) >= 3 && (c & 7) != 4) | (c & 8) >> 2)
-
-
-static void bmove_2_plane(struct display *p, int sy, int sx, int dy, int dx,
-                          int height, int width)
-{
-	/* bmove() has to distinguish two major cases: If both, source and
-	 * destination, start at even addresses or both are at odd
-	 * addresses, just the first odd and last even column (if present)
-	 * require special treatment (memmove_col()). The rest between
-	 * then can be copied by normal operations, because all adjacent
-	 * bytes are affected and are to be stored in the same order.
-	 *   The pathological case is when the move should go from an odd
-	 * address to an even or vice versa. Since the bytes in the plane
-	 * words must be assembled in new order, it seems wisest to make
-	 * all movements by memmove_col().
-	 */
-
-    if (sx == 0 && dx == 0 && width == p->next_line/2) {
-		/* Special (but often used) case: Moving whole lines can be
-		 * done with memmove()
-		 */
-		mymemmove(p->screen_base + dy * p->next_line * p->fontheight,
-			  p->screen_base + sy * p->next_line * p->fontheight,
-			  p->next_line * height * p->fontheight);
-    } else {
-        int rows, cols;
-        u_char *src;
-        u_char *dst;
-        int bytes = p->next_line;
-        int linesize = bytes * p->fontheight;
-		       u_int colsize  = height * p->fontheight;
-		       u_int upwards  = (dy < sy) || (dy == sy && dx < sx);
-
-		if ((sx & 1) == (dx & 1)) {
-			/* odd->odd or even->even */
-
-			if (upwards) {
-
-				src = p->screen_base + sy * linesize + (sx>>1)*4 + (sx & 1);
-				dst = p->screen_base + dy * linesize + (dx>>1)*4 + (dx & 1);
-
-				if (sx & 1) {
-					memmove_2p_col(dst, src, colsize, bytes);
-					src += 3;
-					dst += 3;
-					--width;
-				}
-
-				if (width > 1) {
-					for(rows = colsize; rows > 0; --rows) {
-						mymemmove(dst, src, (width>>1)*4);
-						src += bytes;
-						dst += bytes;
-					}
-				}
-
-				if (width & 1) {
-					src -= colsize * bytes;
-					dst -= colsize * bytes;
-					memmove_2p_col(dst + (width>>1)*4, src + (width>>1)*4,
-									colsize, bytes);
-				}
-			}
-			else {
-
-				if (!((sx+width-1) & 1)) {
-					src = p->screen_base + sy * linesize + ((sx+width-1)>>1)*4;
-					dst = p->screen_base + dy * linesize + ((dx+width-1)>>1)*4;
-					memmove_2p_col(dst, src, colsize, bytes);
-					--width;
-				}
-
-				src = p->screen_base + sy * linesize + (sx>>1)*4 + (sx & 1);
-				dst = p->screen_base + dy * linesize + (dx>>1)*4 + (dx & 1);
-
-				if (width > 1) {
-					src += colsize * bytes + (sx & 1)*3;
-					dst += colsize * bytes + (sx & 1)*3;
-					for(rows = colsize; rows > 0; --rows) {
-						src -= bytes;
-						dst -= bytes;
-						mymemmove(dst, src, (width>>1)*4);
-					}
-				}
-
-				if (width & 1) {
-					memmove_2p_col(dst-3, src-3, colsize, bytes);
-				}
-
-			}
-		}
-		else {
-			/* odd->even or even->odd */
-
-			if (upwards) {
-				src = p->screen_base + sy * linesize + (sx>>1)*4 + (sx & 1);
-				dst = p->screen_base + dy * linesize + (dx>>1)*4 + (dx & 1);
-				for(cols = width; cols > 0; --cols) {
-					memmove_2p_col(dst, src, colsize, bytes);
-					INC_2P(src);
-					INC_2P(dst);
-				}
-			}
-			else {
-				sx += width-1;
-				dx += width-1;
-				src = p->screen_base + sy * linesize + (sx>>1)*4 + (sx & 1);
-				dst = p->screen_base + dy * linesize + (dx>>1)*4 + (dx & 1);
-				for(cols = width; cols > 0; --cols) {
-					memmove_2p_col(dst, src, colsize, bytes);
-					DEC_2P(src);
-					DEC_2P(dst);
-				}
-			}
-		}
-
-
-    }
-}
-
-
-static void clear_2_plane(struct vc_data *conp, struct display *p, int sy,
-                          int sx, int height, int width)
-{
-    ulong offset;
-    u_char *start;
-    int rows;
-    int bytes = p->next_line;
-    int lines = height * p->fontheight;
-    ulong  size;
-    u_long          cval;
-    u_short			pcval;
-
-    cval = expand2l (COLOR_2P (attr_bgcol_ec(p,conp)));
-
-    if (sx == 0 && width == bytes/2) {
-
-        offset = sy * bytes * p->fontheight;
-        size   = lines * bytes;
-		memset_even_2p(p->screen_base+offset, size, cval);
-
-    } else {
-
-        offset = (sy * bytes * p->fontheight) + (sx>>1)*4 + (sx & 1);
-		start = p->screen_base + offset;
-		pcval = expand2w(COLOR_2P(attr_bgcol_ec(p,conp)));
-
-		/* Clears are split if the region starts at an odd column or
-		 * end at an even column. These extra columns are spread
-		 * across the interleaved planes. All in between can be
-		 * cleared by normal mymemclear_small(), because both bytes of
-		 * the single plane words are affected.
-		 */
-
-		if (sx & 1) {
-			memclear_2p_col(start, lines, pcval, bytes);
-			start += 3;
-			width--;
-		}
-
-		if (width & 1) {
-			memclear_2p_col(start + (width>>1)*4, lines, pcval, bytes);
-			width--;
-		}
-
-		if (width) {
-			for(rows = lines; rows-- ; start += bytes)
-				memset_even_2p(start, width*2, cval);
-		}
-    }
-}
-
-
-static void putc_2_plane(struct vc_data *conp, struct display *p, int
-			 c, int yy, int xx)
-{
-	u_char   *dest;
-	u_char   *cdat;
-	int rows;
-	int bytes = p->next_line;
-	ulong    eorx, fgx, bgx, fdx;
-
-	c &= 0xff;
-
-	dest  = p->screen_base + yy * p->fontheight * bytes +
-		(xx >> 1)*4 + (xx & 1);
-	cdat  = p->fontdata + (c * p->fontheight);
-
-	fgx   = expand2w(COLOR_2P(attr_fgcol(p,conp)));
-	bgx   = expand2w(COLOR_2P(attr_bgcol(p,conp)));
-	eorx  = fgx ^ bgx;
-
-	for(rows = p->fontheight ; rows-- ; dest += bytes) {
-		fdx = dup2w(*cdat++);
-		__asm__ __volatile__ ("movepw %1,%0@(0)" : /* no outputs */
-				      : "a" (dest), "d" ((fdx & eorx) ^ bgx));
-	}
-}
-
-
-static void putcs_2_plane(struct vc_data *conp, struct display *p,
-                          const char *s, int count, int yy, int xx)
-{
-	u_char   *dest, *dest0;
-	u_char   *cdat, c;
-	int rows;
-	int bytes;
-	ulong    eorx, fgx, bgx, fdx;
-
-	bytes = p->next_line;
-	dest0 = p->screen_base + yy * p->fontheight * bytes
-		+ (xx >> 1)*4 + (xx & 1);
-	fgx   = expand2w(COLOR_2P(attr_fgcol(p,conp)));
-	bgx   = expand2w(COLOR_2P(attr_bgcol(p,conp)));
-	eorx  = fgx ^ bgx;
-
-	while (count--) {
-
-		c = *s++;
-		cdat  = p->fontdata + (c * p->fontheight);
-
-		for(rows = p->fontheight, dest = dest0; rows-- ; dest += bytes) {
-			fdx = dup2w(*cdat++);
-			__asm__ __volatile__ ("movepw %1,%0@(0)" : /* no outputs */
-					      : "a" (dest), "d" ((fdx & eorx) ^ bgx));
-		}
-		INC_2P(dest0);
-	}
-}
-
-
-static void rev_char_2_plane(struct display *p, int xx, int yy)
-{
-	u_char *dest;
-	int j;
-	int bytes;
-
-	dest = p->screen_base + yy * p->fontheight * p->next_line +
-		(xx >> 1)*4 + (xx & 1);
-	j = p->fontheight;
-	bytes = p->next_line;
-	while (j--)
-	{
-		/* This should really obey the individual character's
-		 * background and foreground colors instead of simply
-		 * inverting.
-		 */
-		dest[0] = ~dest[0];
-		dest[2] = ~dest[2];
-		dest += bytes;
-	}
-}
-#endif /* CONFIG_FBCON_2PLANE */
-
-
-/* ====================================================================== */
-
-#ifdef CONFIG_FBCON_4PLANE
-
-   /*
-    *    4 Planes (2-bytes interleave)
-    */
-
-/* Increment/decrement 4 plane addresses */
-
-#define	INC_4P(p)	do { if (!((long)(++(p)) & 1)) (p) += 6; } while(0)
-#define	DEC_4P(p)	do { if ((long)(--(p)) & 1) (p) -= 6; } while(0)
-
-
-static void bmove_4_plane(struct display *p, int sy, int sx, int dy, int dx,
-                          int height, int width)
-{
-	/* bmove() has to distinguish two major cases: If both, source and
-	 * destination, start at even addresses or both are at odd
-	 * addresses, just the first odd and last even column (if present)
-	 * require special treatment (memmove_col()). The rest between
-	 * then can be copied by normal operations, because all adjacent
-	 * bytes are affected and are to be stored in the same order.
-	 *   The pathological case is when the move should go from an odd
-	 * address to an even or vice versa. Since the bytes in the plane
-	 * words must be assembled in new order, it seems wisest to make
-	 * all movements by memmove_col().
-	 */
-
-    if (sx == 0 && dx == 0 && width == p->next_line/4) {
-		/* Special (but often used) case: Moving whole lines can be
-		 * done with memmove()
-		 */
-		mymemmove(p->screen_base + dy * p->next_line * p->fontheight,
-			  p->screen_base + sy * p->next_line * p->fontheight,
-			  p->next_line * height * p->fontheight);
-    } else {
-        int rows, cols;
-        u_char *src;
-        u_char *dst;
-        int bytes = p->next_line;
-        int linesize = bytes * p->fontheight;
-		       u_int colsize  = height * p->fontheight;
-		       u_int upwards  = (dy < sy) || (dy == sy && dx < sx);
-
-		if ((sx & 1) == (dx & 1)) {
-			/* odd->odd or even->even */
-
-			if (upwards) {
-
-				src = p->screen_base + sy * linesize + (sx>>1)*8 + (sx & 1);
-				dst = p->screen_base + dy * linesize + (dx>>1)*8 + (dx & 1);
-
-				if (sx & 1) {
-					memmove_4p_col(dst, src, colsize, bytes);
-					src += 7;
-					dst += 7;
-					--width;
-				}
-
-				if (width > 1) {
-					for(rows = colsize; rows > 0; --rows) {
-						mymemmove(dst, src, (width>>1)*8);
-						src += bytes;
-						dst += bytes;
-					}
-				}
-
-				if (width & 1) {
-					src -= colsize * bytes;
-					dst -= colsize * bytes;
-					memmove_4p_col(dst + (width>>1)*8, src + (width>>1)*8,
-									colsize, bytes);
-				}
-			}
-			else {
-
-				if (!((sx+width-1) & 1)) {
-					src = p->screen_base + sy * linesize + ((sx+width-1)>>1)*8;
-					dst = p->screen_base + dy * linesize + ((dx+width-1)>>1)*8;
-					memmove_4p_col(dst, src, colsize, bytes);
-					--width;
-				}
-
-				src = p->screen_base + sy * linesize + (sx>>1)*8 + (sx & 1);
-				dst = p->screen_base + dy * linesize + (dx>>1)*8 + (dx & 1);
-
-				if (width > 1) {
-					src += colsize * bytes + (sx & 1)*7;
-					dst += colsize * bytes + (sx & 1)*7;
-					for(rows = colsize; rows > 0; --rows) {
-						src -= bytes;
-						dst -= bytes;
-						mymemmove(dst, src, (width>>1)*8);
-					}
-				}
-
-				if (width & 1) {
-					memmove_4p_col(dst-7, src-7, colsize, bytes);
-				}
-
-			}
-		}
-		else {
-			/* odd->even or even->odd */
-
-			if (upwards) {
-				src = p->screen_base + sy * linesize + (sx>>1)*8 + (sx & 1);
-				dst = p->screen_base + dy * linesize + (dx>>1)*8 + (dx & 1);
-				for(cols = width; cols > 0; --cols) {
-					memmove_4p_col(dst, src, colsize, bytes);
-					INC_4P(src);
-					INC_4P(dst);
-				}
-			}
-			else {
-				sx += width-1;
-				dx += width-1;
-				src = p->screen_base + sy * linesize + (sx>>1)*8 + (sx & 1);
-				dst = p->screen_base + dy * linesize + (dx>>1)*8 + (dx & 1);
-				for(cols = width; cols > 0; --cols) {
-					memmove_4p_col(dst, src, colsize, bytes);
-					DEC_4P(src);
-					DEC_4P(dst);
-				}
-			}
-		}
-
-
-    }
-}
-
-
-static void clear_4_plane(struct vc_data *conp, struct display *p, int sy,
-                          int sx, int height, int width)
-{
-    ulong offset;
-    u_char *start;
-    int rows;
-    int bytes = p->next_line;
-    int lines = height * p->fontheight;
-    ulong  size;
-    u_long          cval1, cval2, pcval;
-
-    expand4dl(attr_bgcol_ec(p,conp), &cval1, &cval2);
-
-    if (sx == 0 && width == bytes/4) {
-
-	offset = sy * bytes * p->fontheight;
-        size   = lines * bytes;
-		memset_even_4p(p->screen_base+offset, size, cval1, cval2);
-
-    } else {
-
-        offset = (sy * bytes * p->fontheight) + (sx>>1)*8 + (sx & 1);
-		start = p->screen_base + offset;
-		pcval = expand4l(attr_bgcol_ec(p,conp));
-
-		/* Clears are split if the region starts at an odd column or
-		 * end at an even column. These extra columns are spread
-		 * across the interleaved planes. All in between can be
-		 * cleared by normal mymemclear_small(), because both bytes of
-		 * the single plane words are affected.
-		 */
-
-		if (sx & 1) {
-			memclear_4p_col(start, lines, pcval, bytes);
-			start += 7;
-			width--;
-		}
-
-		if (width & 1) {
-			memclear_4p_col(start + (width>>1)*8, lines, pcval, bytes);
-			width--;
-		}
-
-		if (width) {
-			for(rows = lines; rows-- ; start += bytes)
-				memset_even_4p(start, width*4, cval1, cval2);
-		}
-    }
-}
-
-
-static void putc_4_plane(struct vc_data *conp, struct display *p, int
-			 c, int yy, int xx)
-{
-	u_char   *dest;
-	u_char   *cdat;
-	int rows;
-	int bytes = p->next_line;
-	ulong	  eorx, fgx, bgx, fdx;
-
-	c &= 0xff;
-
-	dest  = p->screen_base + yy * p->fontheight * bytes +
-		(xx >> 1)*8 + (xx & 1);
-	cdat  = p->fontdata + (c * p->fontheight);
-
-	fgx   = expand4l(attr_fgcol(p,conp));
-	bgx   = expand4l(attr_bgcol(p,conp));
-	eorx  = fgx ^ bgx;
-
-	for(rows = p->fontheight ; rows-- ; dest += bytes) {
-		fdx = dup4l(*cdat++);
-		__asm__ __volatile__ ("movepl %1,%0@(0)" : /* no outputs */
-				      : "a" (dest), "d" ((fdx & eorx) ^ bgx));
-	}
-}
-
-
-static void putcs_4_plane(struct vc_data *conp, struct display *p,
-                          const char *s, int count, int yy, int xx)
-{
-	u_char   *dest, *dest0;
-	u_char   *cdat, c;
-	int rows;
-	int bytes;
-	ulong	  eorx, fgx, bgx, fdx;
-
-	bytes = p->next_line;
-	dest0 = p->screen_base + yy * p->fontheight * bytes
-		+ (xx >> 1)*8 + (xx & 1);
-	fgx   = expand4l(attr_fgcol(p,conp));
-	bgx   = expand4l(attr_bgcol(p,conp));
-	eorx  = fgx ^ bgx;
-
-	while (count--) {
-
-		/* I think, unrolling the loops like in the 1 plane case isn't
-		 * practicable here, because the body is much longer for 4
-		 * planes (mostly the dup4l()). I guess, unrolling this would
-		 * need more than 256 bytes and so exceed the instruction
-		 * cache :-(
-		 */
-
-		c = *s++;
-		cdat  = p->fontdata + (c * p->fontheight);
-
-		for(rows = p->fontheight, dest = dest0; rows-- ; dest += bytes) {
-			fdx = dup4l(*cdat++);
-			__asm__ __volatile__ ("movepl %1,%0@(0)" : /* no outputs */
-					      : "a" (dest), "d" ((fdx & eorx) ^ bgx));
-		}
-		INC_4P(dest0);
-	}
-}
-
-
-static void rev_char_4_plane(struct display *p, int xx, int yy)
-{
-   u_char *dest;
-   int j;
-   int bytes;
-
-   dest = p->screen_base + yy * p->fontheight * p->next_line +
-	   (xx >> 1)*8 + (xx & 1);
-   j = p->fontheight;
-   bytes = p->next_line;
-
-   while (j--)
-     {
-      /* This should really obey the individual character's
-       * background and foreground colors instead of simply
-       * inverting.
-       */
-       dest[0] = ~dest[0];
-       dest[2] = ~dest[2];
-       dest[4] = ~dest[4];
-       dest[6] = ~dest[6];
-       dest += bytes;
-     }
-}
-#endif /* CONFIG_FBCON_4PLANE */
-
-
-/* ====================================================================== */
-
-#ifdef CONFIG_FBCON_8PLANE
-
-   /*
-    *    8 Planes (2-bytes interleave)
-    */
-
-/* In 8 plane mode, 256 colors would be possible, but only the first
- * 16 are used by the console code (the upper 4 bits are
- * background/unused). For that, the following functions mask off the
- * higher 4 bits of each color.
- */
-
-/* Increment/decrement 8 plane addresses */
-
-#define	INC_8P(p)	do { if (!((long)(++(p)) & 1)) (p) += 14; } while(0)
-#define	DEC_8P(p)	do { if ((long)(--(p)) & 1) (p) -= 14; } while(0)
-
-
-static void bmove_8_plane(struct display *p, int sy, int sx, int dy, int dx,
-                          int height, int width)
-{
-	/* bmove() has to distinguish two major cases: If both, source and
-	 * destination, start at even addresses or both are at odd
-	 * addresses, just the first odd and last even column (if present)
-	 * require special treatment (memmove_col()). The rest between
-	 * then can be copied by normal operations, because all adjacent
-	 * bytes are affected and are to be stored in the same order.
-	 *   The pathological case is when the move should go from an odd
-	 * address to an even or vice versa. Since the bytes in the plane
-	 * words must be assembled in new order, it seems wisest to make
-	 * all movements by memmove_col().
-	 */
-
-    if (sx == 0 && dx == 0 && width == p->next_line/8) {
-		/* Special (but often used) case: Moving whole lines can be
-		 * done with memmove()
-		 */
-      fast_memmove (p->screen_base + dy * p->next_line * p->fontheight,
-		    p->screen_base + sy * p->next_line * p->fontheight,
-		    p->next_line * height * p->fontheight);
-    } else {
-        int rows, cols;
-        u_char *src;
-        u_char *dst;
-        int bytes = p->next_line;
-        int linesize = bytes * p->fontheight;
-		       u_int colsize  = height * p->fontheight;
-		       u_int upwards  = (dy < sy) || (dy == sy && dx < sx);
-
-		if ((sx & 1) == (dx & 1)) {
-			/* odd->odd or even->even */
-
-			if (upwards) {
-
-				src = p->screen_base + sy * linesize + (sx>>1)*16 + (sx & 1);
-				dst = p->screen_base + dy * linesize + (dx>>1)*16 + (dx & 1);
-
-				if (sx & 1) {
-					memmove_8p_col(dst, src, colsize, bytes);
-					src += 15;
-					dst += 15;
-					--width;
-				}
-
-				if (width > 1) {
-					for(rows = colsize; rows > 0; --rows) {
-						fast_memmove (dst, src, (width >> 1) * 16);
-						src += bytes;
-						dst += bytes;
-					}
-				}
-
-				if (width & 1) {
-					src -= colsize * bytes;
-					dst -= colsize * bytes;
-					memmove_8p_col(dst + (width>>1)*16, src + (width>>1)*16,
-									colsize, bytes);
-				}
-			}
-			else {
-
-				if (!((sx+width-1) & 1)) {
-					src = p->screen_base + sy * linesize + ((sx+width-1)>>1)*16;
-					dst = p->screen_base + dy * linesize + ((dx+width-1)>>1)*16;
-					memmove_8p_col(dst, src, colsize, bytes);
-					--width;
-				}
-
-				src = p->screen_base + sy * linesize + (sx>>1)*16 + (sx & 1);
-				dst = p->screen_base + dy * linesize + (dx>>1)*16 + (dx & 1);
-
-				if (width > 1) {
-					src += colsize * bytes + (sx & 1)*15;
-					dst += colsize * bytes + (sx & 1)*15;
-					for(rows = colsize; rows > 0; --rows) {
-						src -= bytes;
-						dst -= bytes;
-						fast_memmove (dst, src, (width>>1)*16);
-					}
-				}
-
-				if (width & 1) {
-					memmove_8p_col(dst-15, src-15, colsize, bytes);
-				}
-
-			}
-		}
-		else {
-			/* odd->even or even->odd */
-
-			if (upwards) {
-				src = p->screen_base + sy * linesize + (sx>>1)*16 + (sx & 1);
-				dst = p->screen_base + dy * linesize + (dx>>1)*16 + (dx & 1);
-				for(cols = width; cols > 0; --cols) {
-					memmove_8p_col(dst, src, colsize, bytes);
-					INC_8P(src);
-					INC_8P(dst);
-				}
-			}
-			else {
-				sx += width-1;
-				dx += width-1;
-				src = p->screen_base + sy * linesize + (sx>>1)*16 + (sx & 1);
-				dst = p->screen_base + dy * linesize + (dx>>1)*16 + (dx & 1);
-				for(cols = width; cols > 0; --cols) {
-					memmove_8p_col(dst, src, colsize, bytes);
-					DEC_8P(src);
-					DEC_8P(dst);
-				}
-			}
-		}
-
-
-    }
-}
-
-
-static void clear_8_plane(struct vc_data *conp, struct display *p, int sy,
-                          int sx, int height, int width)
-{
-    ulong offset;
-    u_char *start;
-    int rows;
-    int bytes = p->next_line;
-    int lines = height * p->fontheight;
-    ulong  size;
-    u_long          cval1, cval2, cval3, cval4, pcval1, pcval2;
-
-    expand8ql(attr_bgcol_ec(p,conp), cval1, cval2, cval3, cval4);
-
-    if (sx == 0 && width == bytes/8) {
-
-        offset = sy * bytes * p->fontheight;
-        size   = lines * bytes;
-		memset_even_8p(p->screen_base+offset, size, cval1,
-			       cval2, cval3, cval4);
-
-    } else {
-
-        offset = (sy * bytes * p->fontheight) + (sx>>1)*16 + (sx & 1);
-		start = p->screen_base + offset;
-		expand8dl(attr_bgcol_ec(p,conp), &pcval1, &pcval2);
-
-		/* Clears are split if the region starts at an odd column or
-		 * end at an even column. These extra columns are spread
-		 * across the interleaved planes. All in between can be
-		 * cleared by normal mymemclear_small(), because both bytes of
-		 * the single plane words are affected.
-		 */
-
-		if (sx & 1) {
-			memclear_8p_col(start, lines, pcval1, pcval2, bytes);
-			start += 7;
-			width--;
-		}
-
-		if (width & 1) {
-			memclear_8p_col(start + (width>>1)*16, lines, pcval1,
-							 pcval2, bytes);
-			width--;
-		}
-
-		if (width) {
-			for(rows = lines; rows-- ; start += bytes)
-				memset_even_8p(start, width*8, cval1, cval2, cval3, cval4);
-		}
-    }
-}
-
-
-static void putc_8_plane(struct vc_data *conp, struct display *p, int c, int yy,
-                         int xx)
-{
-	u_char   *dest;
-	u_char   *cdat;
-	int rows;
-	int bytes = p->next_line;
-	ulong	  eorx1, eorx2, fgx1, fgx2, bgx1, bgx2, fdx;
-
-	c &= 0xff;
-
-	dest  = p->screen_base + yy * p->fontheight * bytes +
-		(xx >> 1)*16 + (xx & 1);
-	cdat  = p->fontdata + (c * p->fontheight);
-
-	expand8dl(attr_fgcol(p,conp), &fgx1, &fgx2);
-	expand8dl(attr_bgcol(p,conp), &bgx1, &bgx2);
-	eorx1  = fgx1 ^ bgx1; eorx2  = fgx2 ^ bgx2;
-
-	for(rows = p->fontheight ; rows-- ; dest += bytes) {
-		fdx = dup4l(*cdat++);
-		__asm__ __volatile__
-			("movepl %1,%0@(0)\n\t"
-			 "movepl %2,%0@(8)"
-			 : /* no outputs */
-			 : "a" (dest), "d" ((fdx & eorx1) ^ bgx1),
-			 "d" ((fdx & eorx2) ^ bgx2)
-			);
-	}
-}
-
-
-static void putcs_8_plane(struct vc_data *conp, struct display *p,
-                          const char *s, int count, int yy, int xx)
-{
-	u_char   *dest, *dest0;
-	u_char   *cdat, c;
-	int rows;
-	int bytes;
-	ulong	  eorx1, eorx2, fgx1, fgx2, bgx1, bgx2, fdx;
-
-	bytes = p->next_line;
-	dest0 = p->screen_base + yy * p->fontheight * bytes
-		+ (xx >> 1)*16 + (xx & 1);
-
-	expand8dl(attr_fgcol(p,conp), &fgx1, &fgx2);
-	expand8dl(attr_bgcol(p,conp), &bgx1, &bgx2);
-	eorx1  = fgx1 ^ bgx1; eorx2  = fgx2 ^ bgx2;
-
-	while (count--) {
-
-		/* I think, unrolling the loops like in the 1 plane case isn't
-		 * practicable here, because the body is much longer for 4
-		 * planes (mostly the dup4l()). I guess, unrolling this would
-		 * need more than 256 bytes and so exceed the instruction
-		 * cache :-(
-		 */
-
-		c = *s++;
-		cdat  = p->fontdata + (c * p->fontheight);
-
-		for(rows = p->fontheight, dest = dest0; rows-- ; dest += bytes) {
-			fdx = dup4l(*cdat++);
-			__asm__ __volatile__
-				("movepl %1,%0@(0)\n\t"
-				  "movepl %2,%0@(8)"
-				  : /* no outputs */
-				  : "a" (dest), "d" ((fdx & eorx1) ^ bgx1),
-				  "d" ((fdx & eorx2) ^ bgx2)
-				);
-		}
-		INC_8P(dest0);
-	}
-}
-
-
-static void rev_char_8_plane(struct display *p, int xx, int yy)
-{
-	u_char *dest;
-	int j;
-	int bytes;
-
-	dest = p->screen_base + yy * p->fontheight * p->next_line
-		+ (xx >> 1)*16 + (xx & 1);
-	j = p->fontheight;
-	bytes = p->next_line;
-
-	while (j--)
-	{
-		/* This should really obey the individual character's
-		 * background and foreground colors instead of simply
-		 * inverting. For 8 plane mode, only the lower 4 bits of the
-		 * color are inverted, because only that color registers have
-		 * been set up.
-		 */
-		dest[0] = ~dest[0];
-		dest[2] = ~dest[2];
-		dest[4] = ~dest[4];
-		dest[6] = ~dest[6];
-		dest += bytes;
-	}
-}
-#endif /* CONFIG_FBCON_8PLANE */
-
-
-/* ====================================================================== */
-
-#ifdef CONFIG_FBCON_8PACKED
-
-   /*
-    *    8 bpp Packed Pixels
-    */
-
-static u_long nibbletab_8_packed[]={
-0x00000000,0x000000ff,0x0000ff00,0x0000ffff,
-0x00ff0000,0x00ff00ff,0x00ffff00,0x00ffffff,
-0xff000000,0xff0000ff,0xff00ff00,0xff00ffff,
-0xffff0000,0xffff00ff,0xffffff00,0xffffffff};
-
-static void bmove_8_packed(struct display *p, int sy, int sx, int dy, int dx,
-                           int height, int width)
-{
-	int bytes = p->next_line, linesize = bytes * p->fontheight, rows;
-	u_char *src,*dst;
-
-	if (sx == 0 && dx == 0 && width * 8 == bytes) {
-		mymemmove(p->screen_base + dy * linesize,
-			  p->screen_base + sy * linesize,
-			  height * linesize);
-	}
-	else {
-		if (dy < sy || (dy == sy && dx < sx)) {
-			src = p->screen_base + sy * linesize + sx * 8;
-			dst = p->screen_base + dy * linesize + dx * 8;
-			for (rows = height * p->fontheight ; rows-- ;) {
-				mymemmove(dst, src, width * 8);
-				src += bytes;
-				dst += bytes;
-			}
-		}
-		else {
-			src = p->screen_base + (sy+height) * linesize + sx * 8
-				- bytes;
-			dst = p->screen_base + (dy+height) * linesize + dx * 8
-				- bytes;
-			for (rows = height * p->fontheight ; rows-- ;) {
-				mymemmove(dst, src, width * 8);
-				src -= bytes;
-				dst -= bytes;
-			}
-		}
-	}
-}
-
-
-static void clear_8_packed(struct vc_data *conp, struct display *p, int sy,
-                           int sx, int height, int width)
-{
-	u_char *dest0,*dest;
-	int bytes=p->next_line,lines=height * p->fontheight, rows, i;
-	u_long bgx;
-
-	dest = p->screen_base + sy * p->fontheight * bytes + sx * 8;
-
-	bgx=attr_bgcol_ec(p,conp);
-	bgx |= (bgx << 8);
-	bgx |= (bgx << 16);
-
-	if (sx == 0 && width * 8 == bytes) {
-		for (i = 0 ; i < lines * width ; i++) {
-			((u_long *)dest)[0]=bgx;
-			((u_long *)dest)[1]=bgx;
-			dest+=8;
-		}
-	} else {
-		dest0=dest;
-		for (rows = lines; rows-- ; dest0 += bytes) {
-			dest=dest0;
-			for (i = 0 ; i < width ; i++) {
-				((u_long *)dest)[0]=bgx;
-				((u_long *)dest)[1]=bgx;
-				dest+=8;
-			}
-		}
-	}
-}
-
-
-static void putc_8_packed(struct vc_data *conp, struct display *p, int c,
-			  int yy, int xx)
-{
-	u_char *dest,*cdat;
-	int bytes=p->next_line,rows;
-	ulong eorx,fgx,bgx;
-
-	c &= 0xff;
-
-	dest = p->screen_base + yy * p->fontheight * bytes + xx * 8;
-	cdat = p->fontdata + c * p->fontheight;
-
-	fgx=attr_fgcol(p,conp);
-	bgx=attr_bgcol(p,conp);
-	fgx |= (fgx << 8);
-	fgx |= (fgx << 16);
-	bgx |= (bgx << 8);
-	bgx |= (bgx << 16);
-	eorx = fgx ^ bgx;
-
-	for (rows = p->fontheight ; rows-- ; dest += bytes) {
-		((u_long *)dest)[0]=
-			(nibbletab_8_packed[*cdat >> 4] & eorx) ^ bgx;
-		((u_long *)dest)[1]=
-			(nibbletab_8_packed[*cdat++ & 0xf] & eorx) ^ bgx;
-	}
-}
-
-
-static void putcs_8_packed(struct vc_data *conp, struct display *p,
-                           const char *s, int count, int yy, int xx)
-{
-	u_char *cdat, c, *dest, *dest0;
-	int rows,bytes=p->next_line;
-	u_long eorx, fgx, bgx;
-
-	dest0 = p->screen_base + yy * p->fontheight * bytes + xx * 8;
-	fgx=attr_fgcol(p,conp);
-	bgx=attr_bgcol(p,conp);
-	fgx |= (fgx << 8);
-	fgx |= (fgx << 16);
-	bgx |= (bgx << 8);
-	bgx |= (bgx << 16);
-	eorx = fgx ^ bgx;
-	while (count--) {
-		c = *s++;
-		cdat = p->fontdata + c * p->fontheight;
-
-		for (rows = p->fontheight, dest = dest0; rows-- ; dest += bytes) {
-			((u_long *)dest)[0]=
-			(nibbletab_8_packed[*cdat >> 4] & eorx) ^ bgx;
-			((u_long *)dest)[1]=
-			(nibbletab_8_packed[*cdat++ & 0xf] & eorx) ^ bgx;
-		}
-		dest0+=8;
-	}
-}
-
-
-static void rev_char_8_packed(struct display *p, int xx, int yy)
-{
-	u_char *dest;
-	int bytes=p->next_line, rows;
-
-	dest = p->screen_base + yy * p->fontheight * bytes + xx * 8;
-	for (rows = p->fontheight ; rows-- ; dest += bytes) {
-		((u_long *)dest)[0] ^= 0x0f0f0f0f;
-		((u_long *)dest)[1] ^= 0x0f0f0f0f;
-	}
-}
-
-#endif /* CONFIG_FBCON_8PACKED */
-
-
-/* ====================================================================== */
-
-#ifdef CONFIG_FBCON_16PACKED
-
-   /*
-    *    16 bpp Packed Pixels
-    */
-
-u_short packed16_cmap[16];
-
-static u_long tab_16_packed[]={
-0x00000000,0x0000ffff,0xffff0000,0xffffffff};
-
-static void bmove_16_packed(struct display *p, int sy, int sx, int dy, int dx,
-                            int height, int width)
-{
-	int bytes = p->next_line, linesize = bytes * p->fontheight, rows;
-	u_char *src,*dst;
-
-	if (sx == 0 && dx == 0 && width * 16 == bytes) {
-		mymemmove(p->screen_base + dy * linesize,
-			  p->screen_base + sy * linesize,
-			  height * linesize);
-	}
-	else {
-		if (dy < sy || (dy == sy && dx < sx)) {
-			src = p->screen_base + sy * linesize + sx * 16;
-			dst = p->screen_base + dy * linesize + dx * 16;
-			for (rows = height * p->fontheight ; rows-- ;) {
-				mymemmove(dst, src, width * 16);
-				src += bytes;
-				dst += bytes;
-			}
-		}
-		else {
-			src = p->screen_base + (sy+height) * linesize + sx * 16
-				- bytes;
-			dst = p->screen_base + (dy+height) * linesize + dx * 16
-				- bytes;
-			for (rows = height * p->fontheight ; rows-- ;) {
-				mymemmove(dst, src, width * 16);
-				src -= bytes;
-				dst -= bytes;
-			}
-		}
-	}
-}
-
-
-static void clear_16_packed(struct vc_data *conp, struct display *p, int sy,
-                            int sx, int height, int width)
-{
-	u_char *dest0,*dest;
-	int bytes=p->next_line,lines=height * p->fontheight, rows, i;
-	u_long bgx;
-
-	dest = p->screen_base + sy * p->fontheight * bytes + sx * 16;
-
-	bgx = attr_bgcol_ec(p,conp);
-	bgx = packed16_cmap[bgx];
-	bgx |= (bgx << 16);
-
-	if (sx == 0 && width * 16 == bytes) {
-		for (i = 0 ; i < lines * width ; i++) {
-			((u_long *)dest)[0]=bgx;
-			((u_long *)dest)[1]=bgx;
-			((u_long *)dest)[2]=bgx;
-			((u_long *)dest)[3]=bgx;
-			dest+=16;
-		}
-	} else {
-		dest0=dest;
-		for (rows = lines; rows-- ; dest0 += bytes) {
-			dest=dest0;
-			for (i = 0 ; i < width ; i++) {
-				((u_long *)dest)[0]=bgx;
-				((u_long *)dest)[1]=bgx;
-				((u_long *)dest)[2]=bgx;
-				((u_long *)dest)[3]=bgx;
-				dest+=16;
-			}
-		}
-	}
-}
-
-
-static void putc_16_packed(struct vc_data *conp, struct display *p, int c,
-                           int yy, int xx)
-{
-	u_char *dest,*cdat;
-	int bytes=p->next_line,rows;
-	ulong eorx,fgx,bgx;
-
-	c &= 0xff;
-
-	dest = p->screen_base + yy * p->fontheight * bytes + xx * 16;
-	cdat = p->fontdata + c * p->fontheight;
-
-	fgx = attr_fgcol(p,conp);
-	fgx = packed16_cmap[fgx];
-	bgx = attr_bgcol(p,conp);
-	bgx = packed16_cmap[bgx];
-	fgx |= (fgx << 16);
-	bgx |= (bgx << 16);
-	eorx = fgx ^ bgx;
-
-	for (rows = p->fontheight ; rows-- ; dest += bytes) {
-		((u_long *)dest)[0]=
-			(tab_16_packed[*cdat >> 6] & eorx) ^ bgx;
-		((u_long *)dest)[1]=
-			(tab_16_packed[*cdat >> 4 & 0x3] & eorx) ^ bgx;
-		((u_long *)dest)[2]=
-			(tab_16_packed[*cdat >> 2 & 0x3] & eorx) ^ bgx;
-		((u_long *)dest)[3]=
-			(tab_16_packed[*cdat++ & 0x3] & eorx) ^ bgx;
-	}
-}
-
-
-/* TODO */
-static void putcs_16_packed(struct vc_data *conp, struct display *p,
-                            const char *s, int count, int yy, int xx)
-{
-	u_char *cdat, c, *dest, *dest0;
-	int rows,bytes=p->next_line;
-	u_long eorx, fgx, bgx;
-
-	dest0 = p->screen_base + yy * p->fontheight * bytes + xx * 16;
-	fgx = attr_fgcol(p,conp);
-	fgx = packed16_cmap[fgx];
-	bgx = attr_bgcol(p,conp);
-	bgx = packed16_cmap[bgx];
-	fgx |= (fgx << 16);
-	bgx |= (bgx << 16);
-	eorx = fgx ^ bgx;
-	while (count--) {
-		c = *s++;
-		cdat = p->fontdata + c * p->fontheight;
-
-		for (rows = p->fontheight, dest = dest0; rows-- ; dest += bytes) {
-			((u_long *)dest)[0]=
-				(tab_16_packed[*cdat >> 6] & eorx) ^ bgx;
-			((u_long *)dest)[1]=
-				(tab_16_packed[*cdat >> 4 & 0x3] & eorx) ^ bgx;
-			((u_long *)dest)[2]=
-				(tab_16_packed[*cdat >> 2 & 0x3] & eorx) ^ bgx;
-			((u_long *)dest)[3]=
-				(tab_16_packed[*cdat++ & 0x3] & eorx) ^ bgx;
-		}
-		dest0+=16;
-	}
-}
-
-
-static void rev_char_16_packed(struct display *p, int xx, int yy)
-{
-	u_char *dest;
-	int bytes=p->next_line, rows;
-
-	dest = p->screen_base + yy * p->fontheight * bytes + xx * 16;
-	for (rows = p->fontheight ; rows-- ; dest += bytes) {
-		((u_long *)dest)[0] ^= 0xffffffff;
-		((u_long *)dest)[1] ^= 0xffffffff;
-		((u_long *)dest)[2] ^= 0xffffffff;
-		((u_long *)dest)[3] ^= 0xffffffff;
-	}
-}
-
-#endif /* CONFIG_FBCON_16PACKED */
-
-
-/* ====================================================================== */
-
-#ifdef CONFIG_FBCON_CYBER
-
-   /*
-    *    Cybervision (accelerated)
-    */
-
-static void bmove_cyber(struct display *p, int sy, int sx, int dy, int dx,
-                        int height, int width)
-{
-	sx *= 8; dx *= 8; width *= 8;
-	Cyber_BitBLT((u_short)sx, (u_short)(sy*p->fontheight), (u_short)dx,
-                (u_short)(dy*p->fontheight), (u_short)width,
-                (u_short)(height*p->fontheight), (u_short)S3_NEW);
-}
-
-
-static void clear_cyber(struct vc_data *conp, struct display *p, int
-			sy, int sx, int height, int width)
-{
-	unsigned char bg;
-        
-	sx *= 8; width *= 8;
-	bg = attr_bgcol_ec(p,conp);
-	Cyber_RectFill((u_short)sx,
-		       (u_short)(sy*p->fontheight),
-		       (u_short)width,
-		       (u_short)(height*p->fontheight),
-		       (u_short)S3_NEW, 
-		       (u_short)bg); 
-}
-
-
-static void putc_cyber(struct vc_data *conp, struct display *p, int c, int yy,
-                       int xx)
-{
-	u_char *dest, *cdat;
-	u_long tmp;
-	u_int rows, revs, underl; 
-	u_char d;
-	u_char fg, bg;
-
-	c &= 0xff;
-
-	dest = p->screen_base + yy * p->fontheight * p->next_line + 8 * xx;
-	cdat = p->fontdata+(c*p->fontheight);
-	fg = disp->fgcol;
-	bg = disp->bgcol;
-	revs = conp->vc_reverse;
-	underl = conp->vc_underline;
-
-   Cyber_WaitBlit();
-	for (rows = p->fontheight; rows--; dest += p->next_line) {
-  		d = *cdat++;
-
-		if (underl && !rows)
-			d = 0xff;
-		if (revs)
-			d = ~d;
-
-		tmp =  ((d & 0x80) ? fg : bg) << 24;
-		tmp |= ((d & 0x40) ? fg : bg) << 16;
-		tmp |= ((d & 0x20) ? fg : bg) << 8;
-		tmp |= ((d & 0x10) ? fg : bg);
-		*((u_long*) dest) = tmp;
-		tmp =  ((d & 0x8) ? fg : bg) << 24;
-		tmp |= ((d & 0x4) ? fg : bg) << 16;
-		tmp |= ((d & 0x2) ? fg : bg) << 8;
-		tmp |= ((d & 0x1) ? fg : bg);
-		*((u_long*) dest + 1) = tmp;
-	}
-}
-
-
-static void putcs_cyber(struct vc_data *conp, struct display *p, const char *s,
-                        int count, int yy, int xx)
-{
-	u_char *dest, *dest0, *cdat;
-	u_long tmp;
-	u_int rows, revs, underl;
-	u_char c, d;
-	u_char fg, bg;
-
-	dest0 = p->screen_base + yy * p->fontheight * p->next_line + 8 * xx;
-	fg = disp->fgcol;
-	bg = disp->bgcol;
-	revs = conp->vc_reverse;
-	underl = conp->vc_underline;
-
-   Cyber_WaitBlit();
-	while (count--) {
-		c = *s++;
-		dest = dest0;
-		dest0 += 8;
-		cdat = p->fontdata+(c*p->fontheight);
-		for (rows = p->fontheight; rows--; dest += p->next_line) {
- 			d = *cdat++;
-
-			if (underl && !rows)
-				d = 0xff;
-			if (revs)
-				d = ~d;
-
-         tmp =  ((d & 0x80) ? fg : bg) << 24;
-         tmp |= ((d & 0x40) ? fg : bg) << 16;
-         tmp |= ((d & 0x20) ? fg : bg) << 8;
-         tmp |= ((d & 0x10) ? fg : bg);
-         *((u_long*) dest) = tmp;
-         tmp =  ((d & 0x8) ? fg : bg) << 24;
-         tmp |= ((d & 0x4) ? fg : bg) << 16;
-         tmp |= ((d & 0x2) ? fg : bg) << 8;
-         tmp |= ((d & 0x1) ? fg : bg);
-         *((u_long*) dest + 1) = tmp;
-		}
-	}
-}
-
-
-static void rev_char_cyber(struct display *p, int xx, int yy)
-{
-	unsigned char *dest;
-	unsigned int rows;
-	unsigned char fg, bg;
-
-	fg = disp->fgcol;
-	bg = disp->bgcol;
-
-	dest = p->screen_base + yy * p->fontheight * p->next_line + 8 * xx;
-   Cyber_WaitBlit();
-	for (rows = p->fontheight; rows--; dest += p->next_line) {
-		*dest = (*dest == fg) ? bg : fg;
-		*(dest+1) = (*(dest + 1) == fg) ? bg : fg;
-		*(dest+2) = (*(dest + 2) == fg) ? bg : fg;
-		*(dest+3) = (*(dest + 3) == fg) ? bg : fg;
-		*(dest+4) = (*(dest + 4) == fg) ? bg : fg;
-		*(dest+5) = (*(dest + 5) == fg) ? bg : fg;
-		*(dest+6) = (*(dest + 6) == fg) ? bg : fg;
-		*(dest+7) = (*(dest + 7) == fg) ? bg : fg;
-	}
-}
-
-#endif /* CONFIG_FBCON_CYBER */
-
-
-#ifdef CONFIG_FBCON_RETINAZ3
-
-/*
- *    RetinaZ3 (accelerated)
- */
-
-#define Z3BLTcopy		0xc0
-#define Z3BLTset		0xf0
-
-static void clear_retz3(struct vc_data *conp, struct display *p, int
-			sy, int sx, int height, int width)
-{
-	unsigned short col;
-	int fontwidth = p->fontwidth;
-
-	sx *= fontwidth;
-	width *= fontwidth;
-
-	col = attr_bgcol_ec(p, conp);
-	col &= 0xff;
-	col |= (col << 8);
-
-	retz3_bitblt(&p->var,
-		     (unsigned short)sx,
-		     (unsigned short)(sy*p->fontheight),
-		     (unsigned short)sx,
-		     (unsigned short)(sy*p->fontheight),
-		     (unsigned short)width,
-		     (unsigned short)(height*p->fontheight),
-		     Z3BLTset,
-		     col); 
-}
-
-static void bmove_retz3(struct display *p, int sy, int sx, int dy, int dx,
-                        int height, int width)
-{
-	int fontwidth = p->fontwidth;
-
-	sx *= fontwidth;
-	dx *= fontwidth;
-	width *= fontwidth;
-
-	retz3_bitblt(&p->var,
-		     (unsigned short)sx,
-		     (unsigned short)(sy*p->fontheight),
-		     (unsigned short)dx,
-		     (unsigned short)(dy*p->fontheight),
-		     (unsigned short)width,
-		     (unsigned short)(height*p->fontheight),
-		     Z3BLTcopy,
-		     0xffff);
-}
-
-static void putc_retz3(struct vc_data *conp, struct display *p,
-		       int c, int yy, int xx)
-{
-	unsigned char *dest, *cdat;
-	unsigned long tmp;
-	unsigned int rows, revs, underl, bytes;
-	unsigned char d;
-	unsigned char fg, bg;
-   
-	c &= 0xff;
-
-	bytes = p->next_line;
-
-	dest = p->screen_base + yy*p->fontheight*bytes
-		+ xx*p->var.bits_per_pixel;
-	cdat = p->fontdata + c * p->fontheight;
-
-	fg = disp->fgcol;
-	bg = disp->bgcol;
-	revs = conp->vc_reverse;
-	underl = conp->vc_underline;
-
-	for (rows = p->fontheight; rows--; dest += bytes) {
-		d = *cdat++;
-
-		if (underl && !rows)
-			d = 0xff;
-		if (revs)
-			d = ~d;
-
-		tmp =  ((d & 0x80) ? fg : bg) << 24;
-		tmp |= ((d & 0x40) ? fg : bg) << 16;
-		tmp |= ((d & 0x20) ? fg : bg) << 8;
-		tmp |= ((d & 0x10) ? fg : bg);
-		*((unsigned long*) dest) = tmp;
-		tmp =  ((d & 0x8) ? fg : bg) << 24;
-		tmp |= ((d & 0x4) ? fg : bg) << 16;
-		tmp |= ((d & 0x2) ? fg : bg) << 8;
-		tmp |= ((d & 0x1) ? fg : bg);
-		*((unsigned long*) dest + 1) = tmp;
-	}
-}
-
-
-static void putcs_retz3(struct vc_data *conp, struct display *p,
-			const char *s, int count, int yy, int xx)
-{
-	unsigned char *dest, *dest0, *cdat;
-	unsigned long tmp;
-	unsigned int rows, revs, underl, bytes;
-	unsigned char c, d;
-	unsigned char fg, bg;
-
-	bytes = p->next_line;
-
-	dest0 = p->screen_base + yy*p->fontheight*bytes
-		+ xx * p->var.bits_per_pixel;
-	fg = disp->fgcol;
-	bg = disp->bgcol;
-	revs = conp->vc_reverse;
-	underl = conp->vc_underline;
-
-	while (count--) {
-		c = *s++;
-		dest = dest0;
-		dest0 += 8;
-
-		cdat = p->fontdata + c * p->fontheight;
-		for (rows = p->fontheight; rows--; dest += bytes) {
- 			d = *cdat++;
-
-			if (underl && !rows)
-				d = 0xff;
-			if (revs)
-				d = ~d;
-
-			tmp =  ((d & 0x80) ? fg : bg) << 24;
-			tmp |= ((d & 0x40) ? fg : bg) << 16;
-			tmp |= ((d & 0x20) ? fg : bg) << 8;
-			tmp |= ((d & 0x10) ? fg : bg);
-			*((unsigned long*) dest) = tmp;
-			tmp =  ((d & 0x8) ? fg : bg) << 24;
-			tmp |= ((d & 0x4) ? fg : bg) << 16;
-			tmp |= ((d & 0x2) ? fg : bg) << 8;
-			tmp |= ((d & 0x1) ? fg : bg);
-			*((unsigned long*) dest + 1) = tmp;
-		}
-	}
-}
-
-static void rev_char_retz3(struct display *p, int xx, int yy)
-{
-	unsigned char *dest;
-	int bytes=p->next_line, rows;
-	unsigned int bpp, mask;
-
-	bpp = p->var.bits_per_pixel;
-
-	switch (bpp){
-	case 8:
-		mask = 0x0f0f0f0f;
-		break;
-	case 16:
-		mask = 0xffffffff;
-		break;
-	case 24:
-		mask = 0xffffffff; /* ??? */
-		break;
-	default:
-		printk("illegal depth for rev_char_retz3(), bpp = %i\n", bpp);
-		return;
-	}
-
-	dest = p->screen_base + yy * p->fontheight * bytes + xx * bpp;
-
-	for (rows = p->fontheight ; rows-- ; dest += bytes) {
-		((unsigned long *)dest)[0] ^= mask;
-		((unsigned long *)dest)[1] ^= mask;
-	}
-}
-
-#endif
-
-/* ====================================================================== */
-
-   /*
-    *    The console `switch' structure for the frame buffer based console
-    */
-
-struct consw fb_con = {
-   fbcon_startup, fbcon_init, fbcon_deinit, fbcon_clear, fbcon_putc,
-   fbcon_putcs, fbcon_cursor, fbcon_scroll, fbcon_bmove, fbcon_switch,
-   fbcon_blank, fbcon_get_font, fbcon_set_font, fbcon_set_palette
-};
diff -u --recursive --new-file v2.1.72/linux/arch/m68k/console/font_8x16.c linux/arch/m68k/console/font_8x16.c
--- v2.1.72/linux/arch/m68k/console/font_8x16.c	Mon Mar  4 12:38:11 1996
+++ linux/arch/m68k/console/font_8x16.c	Wed Dec 31 16:00:00 1969
@@ -1,4625 +0,0 @@
-/**********************************************/
-/*                                            */
-/*       Font file generated by cpi2fnt       */
-/*                                            */
-/**********************************************/
-
-#define FONTDATAMAX 4096
-
-char fontname_8x16[] = "VGA8x16";
-
-int  fontheight_8x16 = 16;
-int  fontwidth_8x16  = 8;
-
-unsigned char fontdata_8x16[FONTDATAMAX] = {
-
-	/* 0 0x00 '^@' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 1 0x01 '^A' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x7e, /* 01111110 */
-	0x81, /* 10000001 */
-	0xa5, /* 10100101 */
-	0x81, /* 10000001 */
-	0x81, /* 10000001 */
-	0xbd, /* 10111101 */
-	0x99, /* 10011001 */
-	0x81, /* 10000001 */
-	0x81, /* 10000001 */
-	0x7e, /* 01111110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 2 0x02 '^B' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x7e, /* 01111110 */
-	0xff, /* 11111111 */
-	0xdb, /* 11011011 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0xc3, /* 11000011 */
-	0xe7, /* 11100111 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0x7e, /* 01111110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 3 0x03 '^C' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x6c, /* 01101100 */
-	0xfe, /* 11111110 */
-	0xfe, /* 11111110 */
-	0xfe, /* 11111110 */
-	0xfe, /* 11111110 */
-	0x7c, /* 01111100 */
-	0x38, /* 00111000 */
-	0x10, /* 00010000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 4 0x04 '^D' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x10, /* 00010000 */
-	0x38, /* 00111000 */
-	0x7c, /* 01111100 */
-	0xfe, /* 11111110 */
-	0x7c, /* 01111100 */
-	0x38, /* 00111000 */
-	0x10, /* 00010000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 5 0x05 '^E' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x18, /* 00011000 */
-	0x3c, /* 00111100 */
-	0x3c, /* 00111100 */
-	0xe7, /* 11100111 */
-	0xe7, /* 11100111 */
-	0xe7, /* 11100111 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x3c, /* 00111100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 6 0x06 '^F' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x18, /* 00011000 */
-	0x3c, /* 00111100 */
-	0x7e, /* 01111110 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0x7e, /* 01111110 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x3c, /* 00111100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 7 0x07 '^G' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x18, /* 00011000 */
-	0x3c, /* 00111100 */
-	0x3c, /* 00111100 */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 8 0x08 '^H' */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0xe7, /* 11100111 */
-	0xc3, /* 11000011 */
-	0xc3, /* 11000011 */
-	0xe7, /* 11100111 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-
-	/* 9 0x09 '^I' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x3c, /* 00111100 */
-	0x66, /* 01100110 */
-	0x42, /* 01000010 */
-	0x42, /* 01000010 */
-	0x66, /* 01100110 */
-	0x3c, /* 00111100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 10 0x0a '^J' */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0xc3, /* 11000011 */
-	0x99, /* 10011001 */
-	0xbd, /* 10111101 */
-	0xbd, /* 10111101 */
-	0x99, /* 10011001 */
-	0xc3, /* 11000011 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-
-	/* 11 0x0b '^K' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x1e, /* 00011110 */
-	0x0e, /* 00001110 */
-	0x1a, /* 00011010 */
-	0x32, /* 00110010 */
-	0x78, /* 01111000 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0x78, /* 01111000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 12 0x0c '^L' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x3c, /* 00111100 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x3c, /* 00111100 */
-	0x18, /* 00011000 */
-	0x7e, /* 01111110 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 13 0x0d '^M' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x3f, /* 00111111 */
-	0x33, /* 00110011 */
-	0x3f, /* 00111111 */
-	0x30, /* 00110000 */
-	0x30, /* 00110000 */
-	0x30, /* 00110000 */
-	0x30, /* 00110000 */
-	0x70, /* 01110000 */
-	0xf0, /* 11110000 */
-	0xe0, /* 11100000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 14 0x0e '^N' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x7f, /* 01111111 */
-	0x63, /* 01100011 */
-	0x7f, /* 01111111 */
-	0x63, /* 01100011 */
-	0x63, /* 01100011 */
-	0x63, /* 01100011 */
-	0x63, /* 01100011 */
-	0x67, /* 01100111 */
-	0xe7, /* 11100111 */
-	0xe6, /* 11100110 */
-	0xc0, /* 11000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 15 0x0f '^O' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0xdb, /* 11011011 */
-	0x3c, /* 00111100 */
-	0xe7, /* 11100111 */
-	0x3c, /* 00111100 */
-	0xdb, /* 11011011 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 16 0x10 '^P' */
-	0x00, /* 00000000 */
-	0x80, /* 10000000 */
-	0xc0, /* 11000000 */
-	0xe0, /* 11100000 */
-	0xf0, /* 11110000 */
-	0xf8, /* 11111000 */
-	0xfe, /* 11111110 */
-	0xf8, /* 11111000 */
-	0xf0, /* 11110000 */
-	0xe0, /* 11100000 */
-	0xc0, /* 11000000 */
-	0x80, /* 10000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 17 0x11 '^Q' */
-	0x00, /* 00000000 */
-	0x02, /* 00000010 */
-	0x06, /* 00000110 */
-	0x0e, /* 00001110 */
-	0x1e, /* 00011110 */
-	0x3e, /* 00111110 */
-	0xfe, /* 11111110 */
-	0x3e, /* 00111110 */
-	0x1e, /* 00011110 */
-	0x0e, /* 00001110 */
-	0x06, /* 00000110 */
-	0x02, /* 00000010 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 18 0x12 '^R' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x18, /* 00011000 */
-	0x3c, /* 00111100 */
-	0x7e, /* 01111110 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x7e, /* 01111110 */
-	0x3c, /* 00111100 */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 19 0x13 '^S' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x00, /* 00000000 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 20 0x14 '^T' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x7f, /* 01111111 */
-	0xdb, /* 11011011 */
-	0xdb, /* 11011011 */
-	0xdb, /* 11011011 */
-	0x7b, /* 01111011 */
-	0x1b, /* 00011011 */
-	0x1b, /* 00011011 */
-	0x1b, /* 00011011 */
-	0x1b, /* 00011011 */
-	0x1b, /* 00011011 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 21 0x15 '^U' */
-	0x00, /* 00000000 */
-	0x7c, /* 01111100 */
-	0xc6, /* 11000110 */
-	0x60, /* 01100000 */
-	0x38, /* 00111000 */
-	0x6c, /* 01101100 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x6c, /* 01101100 */
-	0x38, /* 00111000 */
-	0x0c, /* 00001100 */
-	0xc6, /* 11000110 */
-	0x7c, /* 01111100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 22 0x16 '^V' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xfe, /* 11111110 */
-	0xfe, /* 11111110 */
-	0xfe, /* 11111110 */
-	0xfe, /* 11111110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 23 0x17 '^W' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x18, /* 00011000 */
-	0x3c, /* 00111100 */
-	0x7e, /* 01111110 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x7e, /* 01111110 */
-	0x3c, /* 00111100 */
-	0x18, /* 00011000 */
-	0x7e, /* 01111110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 24 0x18 '^X' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x18, /* 00011000 */
-	0x3c, /* 00111100 */
-	0x7e, /* 01111110 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 25 0x19 '^Y' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x7e, /* 01111110 */
-	0x3c, /* 00111100 */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 26 0x1a '^Z' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x18, /* 00011000 */
-	0x0c, /* 00001100 */
-	0xfe, /* 11111110 */
-	0x0c, /* 00001100 */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 27 0x1b '^[' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x30, /* 00110000 */
-	0x60, /* 01100000 */
-	0xfe, /* 11111110 */
-	0x60, /* 01100000 */
-	0x30, /* 00110000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 28 0x1c '^\' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xc0, /* 11000000 */
-	0xc0, /* 11000000 */
-	0xc0, /* 11000000 */
-	0xfe, /* 11111110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 29 0x1d '^]' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x28, /* 00101000 */
-	0x6c, /* 01101100 */
-	0xfe, /* 11111110 */
-	0x6c, /* 01101100 */
-	0x28, /* 00101000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 30 0x1e '^^' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x10, /* 00010000 */
-	0x38, /* 00111000 */
-	0x38, /* 00111000 */
-	0x7c, /* 01111100 */
-	0x7c, /* 01111100 */
-	0xfe, /* 11111110 */
-	0xfe, /* 11111110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 31 0x1f '^_' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xfe, /* 11111110 */
-	0xfe, /* 11111110 */
-	0x7c, /* 01111100 */
-	0x7c, /* 01111100 */
-	0x38, /* 00111000 */
-	0x38, /* 00111000 */
-	0x10, /* 00010000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 32 0x20 ' ' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 33 0x21 '!' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x18, /* 00011000 */
-	0x3c, /* 00111100 */
-	0x3c, /* 00111100 */
-	0x3c, /* 00111100 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 34 0x22 '"' */
-	0x00, /* 00000000 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x24, /* 00100100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 35 0x23 '#' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x6c, /* 01101100 */
-	0x6c, /* 01101100 */
-	0xfe, /* 11111110 */
-	0x6c, /* 01101100 */
-	0x6c, /* 01101100 */
-	0x6c, /* 01101100 */
-	0xfe, /* 11111110 */
-	0x6c, /* 01101100 */
-	0x6c, /* 01101100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 36 0x24 '$' */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x7c, /* 01111100 */
-	0xc6, /* 11000110 */
-	0xc2, /* 11000010 */
-	0xc0, /* 11000000 */
-	0x7c, /* 01111100 */
-	0x06, /* 00000110 */
-	0x06, /* 00000110 */
-	0x86, /* 10000110 */
-	0xc6, /* 11000110 */
-	0x7c, /* 01111100 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 37 0x25 '%' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xc2, /* 11000010 */
-	0xc6, /* 11000110 */
-	0x0c, /* 00001100 */
-	0x18, /* 00011000 */
-	0x30, /* 00110000 */
-	0x60, /* 01100000 */
-	0xc6, /* 11000110 */
-	0x86, /* 10000110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 38 0x26 '&' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x38, /* 00111000 */
-	0x6c, /* 01101100 */
-	0x6c, /* 01101100 */
-	0x38, /* 00111000 */
-	0x76, /* 01110110 */
-	0xdc, /* 11011100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0x76, /* 01110110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 39 0x27 ''' */
-	0x00, /* 00000000 */
-	0x30, /* 00110000 */
-	0x30, /* 00110000 */
-	0x30, /* 00110000 */
-	0x60, /* 01100000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 40 0x28 '(' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x0c, /* 00001100 */
-	0x18, /* 00011000 */
-	0x30, /* 00110000 */
-	0x30, /* 00110000 */
-	0x30, /* 00110000 */
-	0x30, /* 00110000 */
-	0x30, /* 00110000 */
-	0x30, /* 00110000 */
-	0x18, /* 00011000 */
-	0x0c, /* 00001100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 41 0x29 ')' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x30, /* 00110000 */
-	0x18, /* 00011000 */
-	0x0c, /* 00001100 */
-	0x0c, /* 00001100 */
-	0x0c, /* 00001100 */
-	0x0c, /* 00001100 */
-	0x0c, /* 00001100 */
-	0x0c, /* 00001100 */
-	0x18, /* 00011000 */
-	0x30, /* 00110000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 42 0x2a '*' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x66, /* 01100110 */
-	0x3c, /* 00111100 */
-	0xff, /* 11111111 */
-	0x3c, /* 00111100 */
-	0x66, /* 01100110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 43 0x2b '+' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x7e, /* 01111110 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 44 0x2c ',' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x30, /* 00110000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 45 0x2d '-' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xfe, /* 11111110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 46 0x2e '.' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 47 0x2f '/' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x02, /* 00000010 */
-	0x06, /* 00000110 */
-	0x0c, /* 00001100 */
-	0x18, /* 00011000 */
-	0x30, /* 00110000 */
-	0x60, /* 01100000 */
-	0xc0, /* 11000000 */
-	0x80, /* 10000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 48 0x30 '0' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x38, /* 00111000 */
-	0x6c, /* 01101100 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xd6, /* 11010110 */
-	0xd6, /* 11010110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x6c, /* 01101100 */
-	0x38, /* 00111000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 49 0x31 '1' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x18, /* 00011000 */
-	0x38, /* 00111000 */
-	0x78, /* 01111000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x7e, /* 01111110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 50 0x32 '2' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x7c, /* 01111100 */
-	0xc6, /* 11000110 */
-	0x06, /* 00000110 */
-	0x0c, /* 00001100 */
-	0x18, /* 00011000 */
-	0x30, /* 00110000 */
-	0x60, /* 01100000 */
-	0xc0, /* 11000000 */
-	0xc6, /* 11000110 */
-	0xfe, /* 11111110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 51 0x33 '3' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x7c, /* 01111100 */
-	0xc6, /* 11000110 */
-	0x06, /* 00000110 */
-	0x06, /* 00000110 */
-	0x3c, /* 00111100 */
-	0x06, /* 00000110 */
-	0x06, /* 00000110 */
-	0x06, /* 00000110 */
-	0xc6, /* 11000110 */
-	0x7c, /* 01111100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 52 0x34 '4' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x0c, /* 00001100 */
-	0x1c, /* 00011100 */
-	0x3c, /* 00111100 */
-	0x6c, /* 01101100 */
-	0xcc, /* 11001100 */
-	0xfe, /* 11111110 */
-	0x0c, /* 00001100 */
-	0x0c, /* 00001100 */
-	0x0c, /* 00001100 */
-	0x1e, /* 00011110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 53 0x35 '5' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xfe, /* 11111110 */
-	0xc0, /* 11000000 */
-	0xc0, /* 11000000 */
-	0xc0, /* 11000000 */
-	0xfc, /* 11111100 */
-	0x06, /* 00000110 */
-	0x06, /* 00000110 */
-	0x06, /* 00000110 */
-	0xc6, /* 11000110 */
-	0x7c, /* 01111100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 54 0x36 '6' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x38, /* 00111000 */
-	0x60, /* 01100000 */
-	0xc0, /* 11000000 */
-	0xc0, /* 11000000 */
-	0xfc, /* 11111100 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x7c, /* 01111100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 55 0x37 '7' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xfe, /* 11111110 */
-	0xc6, /* 11000110 */
-	0x06, /* 00000110 */
-	0x06, /* 00000110 */
-	0x0c, /* 00001100 */
-	0x18, /* 00011000 */
-	0x30, /* 00110000 */
-	0x30, /* 00110000 */
-	0x30, /* 00110000 */
-	0x30, /* 00110000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 56 0x38 '8' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x7c, /* 01111100 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x7c, /* 01111100 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x7c, /* 01111100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 57 0x39 '9' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x7c, /* 01111100 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x7e, /* 01111110 */
-	0x06, /* 00000110 */
-	0x06, /* 00000110 */
-	0x06, /* 00000110 */
-	0x0c, /* 00001100 */
-	0x78, /* 01111000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 58 0x3a ':' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 59 0x3b ';' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x30, /* 00110000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 60 0x3c '<' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x06, /* 00000110 */
-	0x0c, /* 00001100 */
-	0x18, /* 00011000 */
-	0x30, /* 00110000 */
-	0x60, /* 01100000 */
-	0x30, /* 00110000 */
-	0x18, /* 00011000 */
-	0x0c, /* 00001100 */
-	0x06, /* 00000110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 61 0x3d '=' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x7e, /* 01111110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x7e, /* 01111110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 62 0x3e '>' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x60, /* 01100000 */
-	0x30, /* 00110000 */
-	0x18, /* 00011000 */
-	0x0c, /* 00001100 */
-	0x06, /* 00000110 */
-	0x0c, /* 00001100 */
-	0x18, /* 00011000 */
-	0x30, /* 00110000 */
-	0x60, /* 01100000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 63 0x3f '?' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x7c, /* 01111100 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x0c, /* 00001100 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 64 0x40 '@' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x7c, /* 01111100 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xde, /* 11011110 */
-	0xde, /* 11011110 */
-	0xde, /* 11011110 */
-	0xdc, /* 11011100 */
-	0xc0, /* 11000000 */
-	0x7c, /* 01111100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 65 0x41 'A' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x10, /* 00010000 */
-	0x38, /* 00111000 */
-	0x6c, /* 01101100 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xfe, /* 11111110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 66 0x42 'B' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xfc, /* 11111100 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x7c, /* 01111100 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0xfc, /* 11111100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 67 0x43 'C' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x3c, /* 00111100 */
-	0x66, /* 01100110 */
-	0xc2, /* 11000010 */
-	0xc0, /* 11000000 */
-	0xc0, /* 11000000 */
-	0xc0, /* 11000000 */
-	0xc0, /* 11000000 */
-	0xc2, /* 11000010 */
-	0x66, /* 01100110 */
-	0x3c, /* 00111100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 68 0x44 'D' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xf8, /* 11111000 */
-	0x6c, /* 01101100 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x6c, /* 01101100 */
-	0xf8, /* 11111000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 69 0x45 'E' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xfe, /* 11111110 */
-	0x66, /* 01100110 */
-	0x62, /* 01100010 */
-	0x68, /* 01101000 */
-	0x78, /* 01111000 */
-	0x68, /* 01101000 */
-	0x60, /* 01100000 */
-	0x62, /* 01100010 */
-	0x66, /* 01100110 */
-	0xfe, /* 11111110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 70 0x46 'F' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xfe, /* 11111110 */
-	0x66, /* 01100110 */
-	0x62, /* 01100010 */
-	0x68, /* 01101000 */
-	0x78, /* 01111000 */
-	0x68, /* 01101000 */
-	0x60, /* 01100000 */
-	0x60, /* 01100000 */
-	0x60, /* 01100000 */
-	0xf0, /* 11110000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 71 0x47 'G' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x3c, /* 00111100 */
-	0x66, /* 01100110 */
-	0xc2, /* 11000010 */
-	0xc0, /* 11000000 */
-	0xc0, /* 11000000 */
-	0xde, /* 11011110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x66, /* 01100110 */
-	0x3a, /* 00111010 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 72 0x48 'H' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xfe, /* 11111110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 73 0x49 'I' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x3c, /* 00111100 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x3c, /* 00111100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 74 0x4a 'J' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x1e, /* 00011110 */
-	0x0c, /* 00001100 */
-	0x0c, /* 00001100 */
-	0x0c, /* 00001100 */
-	0x0c, /* 00001100 */
-	0x0c, /* 00001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0x78, /* 01111000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 75 0x4b 'K' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xe6, /* 11100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x6c, /* 01101100 */
-	0x78, /* 01111000 */
-	0x78, /* 01111000 */
-	0x6c, /* 01101100 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0xe6, /* 11100110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 76 0x4c 'L' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xf0, /* 11110000 */
-	0x60, /* 01100000 */
-	0x60, /* 01100000 */
-	0x60, /* 01100000 */
-	0x60, /* 01100000 */
-	0x60, /* 01100000 */
-	0x60, /* 01100000 */
-	0x62, /* 01100010 */
-	0x66, /* 01100110 */
-	0xfe, /* 11111110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 77 0x4d 'M' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xc6, /* 11000110 */
-	0xee, /* 11101110 */
-	0xfe, /* 11111110 */
-	0xfe, /* 11111110 */
-	0xd6, /* 11010110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 78 0x4e 'N' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xc6, /* 11000110 */
-	0xe6, /* 11100110 */
-	0xf6, /* 11110110 */
-	0xfe, /* 11111110 */
-	0xde, /* 11011110 */
-	0xce, /* 11001110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 79 0x4f 'O' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x7c, /* 01111100 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x7c, /* 01111100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 80 0x50 'P' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xfc, /* 11111100 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x7c, /* 01111100 */
-	0x60, /* 01100000 */
-	0x60, /* 01100000 */
-	0x60, /* 01100000 */
-	0x60, /* 01100000 */
-	0xf0, /* 11110000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 81 0x51 'Q' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x7c, /* 01111100 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xd6, /* 11010110 */
-	0xde, /* 11011110 */
-	0x7c, /* 01111100 */
-	0x0c, /* 00001100 */
-	0x0e, /* 00001110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 82 0x52 'R' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xfc, /* 11111100 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x7c, /* 01111100 */
-	0x6c, /* 01101100 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0xe6, /* 11100110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 83 0x53 'S' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x7c, /* 01111100 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x60, /* 01100000 */
-	0x38, /* 00111000 */
-	0x0c, /* 00001100 */
-	0x06, /* 00000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x7c, /* 01111100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 84 0x54 'T' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x7e, /* 01111110 */
-	0x7e, /* 01111110 */
-	0x5a, /* 01011010 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x3c, /* 00111100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 85 0x55 'U' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x7c, /* 01111100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 86 0x56 'V' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x6c, /* 01101100 */
-	0x38, /* 00111000 */
-	0x10, /* 00010000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 87 0x57 'W' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xd6, /* 11010110 */
-	0xd6, /* 11010110 */
-	0xd6, /* 11010110 */
-	0xfe, /* 11111110 */
-	0xee, /* 11101110 */
-	0x6c, /* 01101100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 88 0x58 'X' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x6c, /* 01101100 */
-	0x7c, /* 01111100 */
-	0x38, /* 00111000 */
-	0x38, /* 00111000 */
-	0x7c, /* 01111100 */
-	0x6c, /* 01101100 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 89 0x59 'Y' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x3c, /* 00111100 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x3c, /* 00111100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 90 0x5a 'Z' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xfe, /* 11111110 */
-	0xc6, /* 11000110 */
-	0x86, /* 10000110 */
-	0x0c, /* 00001100 */
-	0x18, /* 00011000 */
-	0x30, /* 00110000 */
-	0x60, /* 01100000 */
-	0xc2, /* 11000010 */
-	0xc6, /* 11000110 */
-	0xfe, /* 11111110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 91 0x5b '[' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x3c, /* 00111100 */
-	0x30, /* 00110000 */
-	0x30, /* 00110000 */
-	0x30, /* 00110000 */
-	0x30, /* 00110000 */
-	0x30, /* 00110000 */
-	0x30, /* 00110000 */
-	0x30, /* 00110000 */
-	0x30, /* 00110000 */
-	0x3c, /* 00111100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 92 0x5c '\' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x80, /* 10000000 */
-	0xc0, /* 11000000 */
-	0xe0, /* 11100000 */
-	0x70, /* 01110000 */
-	0x38, /* 00111000 */
-	0x1c, /* 00011100 */
-	0x0e, /* 00001110 */
-	0x06, /* 00000110 */
-	0x02, /* 00000010 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 93 0x5d ']' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x3c, /* 00111100 */
-	0x0c, /* 00001100 */
-	0x0c, /* 00001100 */
-	0x0c, /* 00001100 */
-	0x0c, /* 00001100 */
-	0x0c, /* 00001100 */
-	0x0c, /* 00001100 */
-	0x0c, /* 00001100 */
-	0x0c, /* 00001100 */
-	0x3c, /* 00111100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 94 0x5e '^' */
-	0x10, /* 00010000 */
-	0x38, /* 00111000 */
-	0x6c, /* 01101100 */
-	0xc6, /* 11000110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 95 0x5f '_' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xff, /* 11111111 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 96 0x60 '`' */
-	0x00, /* 00000000 */
-	0x30, /* 00110000 */
-	0x18, /* 00011000 */
-	0x0c, /* 00001100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 97 0x61 'a' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x78, /* 01111000 */
-	0x0c, /* 00001100 */
-	0x7c, /* 01111100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0x76, /* 01110110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 98 0x62 'b' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xe0, /* 11100000 */
-	0x60, /* 01100000 */
-	0x60, /* 01100000 */
-	0x78, /* 01111000 */
-	0x6c, /* 01101100 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x7c, /* 01111100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 99 0x63 'c' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x7c, /* 01111100 */
-	0xc6, /* 11000110 */
-	0xc0, /* 11000000 */
-	0xc0, /* 11000000 */
-	0xc0, /* 11000000 */
-	0xc6, /* 11000110 */
-	0x7c, /* 01111100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 100 0x64 'd' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x1c, /* 00011100 */
-	0x0c, /* 00001100 */
-	0x0c, /* 00001100 */
-	0x3c, /* 00111100 */
-	0x6c, /* 01101100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0x76, /* 01110110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 101 0x65 'e' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x7c, /* 01111100 */
-	0xc6, /* 11000110 */
-	0xfe, /* 11111110 */
-	0xc0, /* 11000000 */
-	0xc0, /* 11000000 */
-	0xc6, /* 11000110 */
-	0x7c, /* 01111100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 102 0x66 'f' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x1c, /* 00011100 */
-	0x36, /* 00110110 */
-	0x32, /* 00110010 */
-	0x30, /* 00110000 */
-	0x78, /* 01111000 */
-	0x30, /* 00110000 */
-	0x30, /* 00110000 */
-	0x30, /* 00110000 */
-	0x30, /* 00110000 */
-	0x78, /* 01111000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 103 0x67 'g' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x76, /* 01110110 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0x7c, /* 01111100 */
-	0x0c, /* 00001100 */
-	0xcc, /* 11001100 */
-	0x78, /* 01111000 */
-	0x00, /* 00000000 */
-
-	/* 104 0x68 'h' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xe0, /* 11100000 */
-	0x60, /* 01100000 */
-	0x60, /* 01100000 */
-	0x6c, /* 01101100 */
-	0x76, /* 01110110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0xe6, /* 11100110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 105 0x69 'i' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-	0x38, /* 00111000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x3c, /* 00111100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 106 0x6a 'j' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x06, /* 00000110 */
-	0x06, /* 00000110 */
-	0x00, /* 00000000 */
-	0x0e, /* 00001110 */
-	0x06, /* 00000110 */
-	0x06, /* 00000110 */
-	0x06, /* 00000110 */
-	0x06, /* 00000110 */
-	0x06, /* 00000110 */
-	0x06, /* 00000110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x3c, /* 00111100 */
-	0x00, /* 00000000 */
-
-	/* 107 0x6b 'k' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xe0, /* 11100000 */
-	0x60, /* 01100000 */
-	0x60, /* 01100000 */
-	0x66, /* 01100110 */
-	0x6c, /* 01101100 */
-	0x78, /* 01111000 */
-	0x78, /* 01111000 */
-	0x6c, /* 01101100 */
-	0x66, /* 01100110 */
-	0xe6, /* 11100110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 108 0x6c 'l' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x38, /* 00111000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x3c, /* 00111100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 109 0x6d 'm' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xec, /* 11101100 */
-	0xfe, /* 11111110 */
-	0xd6, /* 11010110 */
-	0xd6, /* 11010110 */
-	0xd6, /* 11010110 */
-	0xd6, /* 11010110 */
-	0xc6, /* 11000110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 110 0x6e 'n' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xdc, /* 11011100 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 111 0x6f 'o' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x7c, /* 01111100 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x7c, /* 01111100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 112 0x70 'p' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xdc, /* 11011100 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x7c, /* 01111100 */
-	0x60, /* 01100000 */
-	0x60, /* 01100000 */
-	0xf0, /* 11110000 */
-	0x00, /* 00000000 */
-
-	/* 113 0x71 'q' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x76, /* 01110110 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0x7c, /* 01111100 */
-	0x0c, /* 00001100 */
-	0x0c, /* 00001100 */
-	0x1e, /* 00011110 */
-	0x00, /* 00000000 */
-
-	/* 114 0x72 'r' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xdc, /* 11011100 */
-	0x76, /* 01110110 */
-	0x66, /* 01100110 */
-	0x60, /* 01100000 */
-	0x60, /* 01100000 */
-	0x60, /* 01100000 */
-	0xf0, /* 11110000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 115 0x73 's' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x7c, /* 01111100 */
-	0xc6, /* 11000110 */
-	0x60, /* 01100000 */
-	0x38, /* 00111000 */
-	0x0c, /* 00001100 */
-	0xc6, /* 11000110 */
-	0x7c, /* 01111100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 116 0x74 't' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x10, /* 00010000 */
-	0x30, /* 00110000 */
-	0x30, /* 00110000 */
-	0xfc, /* 11111100 */
-	0x30, /* 00110000 */
-	0x30, /* 00110000 */
-	0x30, /* 00110000 */
-	0x30, /* 00110000 */
-	0x36, /* 00110110 */
-	0x1c, /* 00011100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 117 0x75 'u' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0x76, /* 01110110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 118 0x76 'v' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x6c, /* 01101100 */
-	0x38, /* 00111000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 119 0x77 'w' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xd6, /* 11010110 */
-	0xd6, /* 11010110 */
-	0xd6, /* 11010110 */
-	0xfe, /* 11111110 */
-	0x6c, /* 01101100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 120 0x78 'x' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xc6, /* 11000110 */
-	0x6c, /* 01101100 */
-	0x38, /* 00111000 */
-	0x38, /* 00111000 */
-	0x38, /* 00111000 */
-	0x6c, /* 01101100 */
-	0xc6, /* 11000110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 121 0x79 'y' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x7e, /* 01111110 */
-	0x06, /* 00000110 */
-	0x0c, /* 00001100 */
-	0xf8, /* 11111000 */
-	0x00, /* 00000000 */
-
-	/* 122 0x7a 'z' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xfe, /* 11111110 */
-	0xcc, /* 11001100 */
-	0x18, /* 00011000 */
-	0x30, /* 00110000 */
-	0x60, /* 01100000 */
-	0xc6, /* 11000110 */
-	0xfe, /* 11111110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 123 0x7b '{' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x0e, /* 00001110 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x70, /* 01110000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x0e, /* 00001110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 124 0x7c '|' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 125 0x7d '}' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x70, /* 01110000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x0e, /* 00001110 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x70, /* 01110000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 126 0x7e '~' */
-	0x00, /* 00000000 */
-	0x76, /* 01110110 */
-	0xdc, /* 11011100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 127 0x7f '' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x10, /* 00010000 */
-	0x38, /* 00111000 */
-	0x6c, /* 01101100 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xfe, /* 11111110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 128 0x80 '€' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x3c, /* 00111100 */
-	0x66, /* 01100110 */
-	0xc2, /* 11000010 */
-	0xc0, /* 11000000 */
-	0xc0, /* 11000000 */
-	0xc0, /* 11000000 */
-	0xc0, /* 11000000 */
-	0xc2, /* 11000010 */
-	0x66, /* 01100110 */
-	0x3c, /* 00111100 */
-	0x18, /* 00011000 */
-	0x70, /* 01110000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 129 0x81 '�' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xcc, /* 11001100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0x76, /* 01110110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 130 0x82 '‚' */
-	0x00, /* 00000000 */
-	0x0c, /* 00001100 */
-	0x18, /* 00011000 */
-	0x30, /* 00110000 */
-	0x00, /* 00000000 */
-	0x7c, /* 01111100 */
-	0xc6, /* 11000110 */
-	0xfe, /* 11111110 */
-	0xc0, /* 11000000 */
-	0xc0, /* 11000000 */
-	0xc6, /* 11000110 */
-	0x7c, /* 01111100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 131 0x83 'ƒ' */
-	0x00, /* 00000000 */
-	0x10, /* 00010000 */
-	0x38, /* 00111000 */
-	0x6c, /* 01101100 */
-	0x00, /* 00000000 */
-	0x78, /* 01111000 */
-	0x0c, /* 00001100 */
-	0x7c, /* 01111100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0x76, /* 01110110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 132 0x84 '„' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xcc, /* 11001100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x78, /* 01111000 */
-	0x0c, /* 00001100 */
-	0x7c, /* 01111100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0x76, /* 01110110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 133 0x85 '…' */
-	0x00, /* 00000000 */
-	0x60, /* 01100000 */
-	0x30, /* 00110000 */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-	0x78, /* 01111000 */
-	0x0c, /* 00001100 */
-	0x7c, /* 01111100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0x76, /* 01110110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 134 0x86 '†' */
-	0x00, /* 00000000 */
-	0x38, /* 00111000 */
-	0x6c, /* 01101100 */
-	0x38, /* 00111000 */
-	0x00, /* 00000000 */
-	0x78, /* 01111000 */
-	0x0c, /* 00001100 */
-	0x7c, /* 01111100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0x76, /* 01110110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 135 0x87 '‡' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x7c, /* 01111100 */
-	0xc6, /* 11000110 */
-	0xc0, /* 11000000 */
-	0xc0, /* 11000000 */
-	0xc0, /* 11000000 */
-	0xc6, /* 11000110 */
-	0x7c, /* 01111100 */
-	0x18, /* 00011000 */
-	0x70, /* 01110000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 136 0x88 'ˆ' */
-	0x00, /* 00000000 */
-	0x10, /* 00010000 */
-	0x38, /* 00111000 */
-	0x6c, /* 01101100 */
-	0x00, /* 00000000 */
-	0x7c, /* 01111100 */
-	0xc6, /* 11000110 */
-	0xfe, /* 11111110 */
-	0xc0, /* 11000000 */
-	0xc0, /* 11000000 */
-	0xc6, /* 11000110 */
-	0x7c, /* 01111100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 137 0x89 '‰' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xc6, /* 11000110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x7c, /* 01111100 */
-	0xc6, /* 11000110 */
-	0xfe, /* 11111110 */
-	0xc0, /* 11000000 */
-	0xc0, /* 11000000 */
-	0xc6, /* 11000110 */
-	0x7c, /* 01111100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 138 0x8a 'Š' */
-	0x00, /* 00000000 */
-	0x60, /* 01100000 */
-	0x30, /* 00110000 */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-	0x7c, /* 01111100 */
-	0xc6, /* 11000110 */
-	0xfe, /* 11111110 */
-	0xc0, /* 11000000 */
-	0xc0, /* 11000000 */
-	0xc6, /* 11000110 */
-	0x7c, /* 01111100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 139 0x8b '‹' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x66, /* 01100110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x38, /* 00111000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x3c, /* 00111100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 140 0x8c 'Œ' */
-	0x00, /* 00000000 */
-	0x18, /* 00011000 */
-	0x3c, /* 00111100 */
-	0x66, /* 01100110 */
-	0x00, /* 00000000 */
-	0x38, /* 00111000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x3c, /* 00111100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 141 0x8d '�' */
-	0x00, /* 00000000 */
-	0x60, /* 01100000 */
-	0x30, /* 00110000 */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-	0x38, /* 00111000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x3c, /* 00111100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 142 0x8e 'Ž' */
-	0x00, /* 00000000 */
-	0xc6, /* 11000110 */
-	0x00, /* 00000000 */
-	0x10, /* 00010000 */
-	0x38, /* 00111000 */
-	0x6c, /* 01101100 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xfe, /* 11111110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 143 0x8f '�' */
-	0x38, /* 00111000 */
-	0x6c, /* 01101100 */
-	0x38, /* 00111000 */
-	0x10, /* 00010000 */
-	0x38, /* 00111000 */
-	0x6c, /* 01101100 */
-	0xc6, /* 11000110 */
-	0xfe, /* 11111110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 144 0x90 '�' */
-	0x0c, /* 00001100 */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-	0xfe, /* 11111110 */
-	0x66, /* 01100110 */
-	0x62, /* 01100010 */
-	0x68, /* 01101000 */
-	0x78, /* 01111000 */
-	0x68, /* 01101000 */
-	0x62, /* 01100010 */
-	0x66, /* 01100110 */
-	0xfe, /* 11111110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 145 0x91 '‘' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xec, /* 11101100 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x7e, /* 01111110 */
-	0xd8, /* 11011000 */
-	0xd8, /* 11011000 */
-	0x6e, /* 01101110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 146 0x92 '’' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x3e, /* 00111110 */
-	0x6c, /* 01101100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xfe, /* 11111110 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xce, /* 11001110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 147 0x93 '“' */
-	0x00, /* 00000000 */
-	0x10, /* 00010000 */
-	0x38, /* 00111000 */
-	0x6c, /* 01101100 */
-	0x00, /* 00000000 */
-	0x7c, /* 01111100 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x7c, /* 01111100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 148 0x94 '”' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xc6, /* 11000110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x7c, /* 01111100 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x7c, /* 01111100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 149 0x95 '•' */
-	0x00, /* 00000000 */
-	0x60, /* 01100000 */
-	0x30, /* 00110000 */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-	0x7c, /* 01111100 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x7c, /* 01111100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 150 0x96 '–' */
-	0x00, /* 00000000 */
-	0x30, /* 00110000 */
-	0x78, /* 01111000 */
-	0xcc, /* 11001100 */
-	0x00, /* 00000000 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0x76, /* 01110110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 151 0x97 '—' */
-	0x00, /* 00000000 */
-	0x60, /* 01100000 */
-	0x30, /* 00110000 */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0x76, /* 01110110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 152 0x98 '˜' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xc6, /* 11000110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x7e, /* 01111110 */
-	0x06, /* 00000110 */
-	0x0c, /* 00001100 */
-	0x78, /* 01111000 */
-	0x00, /* 00000000 */
-
-	/* 153 0x99 '™' */
-	0x00, /* 00000000 */
-	0xc6, /* 11000110 */
-	0x00, /* 00000000 */
-	0x7c, /* 01111100 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x7c, /* 01111100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 154 0x9a 'š' */
-	0x00, /* 00000000 */
-	0xc6, /* 11000110 */
-	0x00, /* 00000000 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x7c, /* 01111100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 155 0x9b '›' */
-	0x00, /* 00000000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x7c, /* 01111100 */
-	0xc6, /* 11000110 */
-	0xc0, /* 11000000 */
-	0xc0, /* 11000000 */
-	0xc0, /* 11000000 */
-	0xc6, /* 11000110 */
-	0x7c, /* 01111100 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 156 0x9c 'œ' */
-	0x00, /* 00000000 */
-	0x38, /* 00111000 */
-	0x6c, /* 01101100 */
-	0x64, /* 01100100 */
-	0x60, /* 01100000 */
-	0xf0, /* 11110000 */
-	0x60, /* 01100000 */
-	0x60, /* 01100000 */
-	0x60, /* 01100000 */
-	0x60, /* 01100000 */
-	0xe6, /* 11100110 */
-	0xfc, /* 11111100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 157 0x9d '�' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x3c, /* 00111100 */
-	0x18, /* 00011000 */
-	0x7e, /* 01111110 */
-	0x18, /* 00011000 */
-	0x7e, /* 01111110 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 158 0x9e 'ž' */
-	0x00, /* 00000000 */
-	0xf8, /* 11111000 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xf8, /* 11111000 */
-	0xc4, /* 11000100 */
-	0xcc, /* 11001100 */
-	0xde, /* 11011110 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xc6, /* 11000110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 159 0x9f 'Ÿ' */
-	0x00, /* 00000000 */
-	0x0e, /* 00001110 */
-	0x1b, /* 00011011 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x7e, /* 01111110 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0xd8, /* 11011000 */
-	0x70, /* 01110000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 160 0xa0 ' ' */
-	0x00, /* 00000000 */
-	0x18, /* 00011000 */
-	0x30, /* 00110000 */
-	0x60, /* 01100000 */
-	0x00, /* 00000000 */
-	0x78, /* 01111000 */
-	0x0c, /* 00001100 */
-	0x7c, /* 01111100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0x76, /* 01110110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 161 0xa1 '¡' */
-	0x00, /* 00000000 */
-	0x0c, /* 00001100 */
-	0x18, /* 00011000 */
-	0x30, /* 00110000 */
-	0x00, /* 00000000 */
-	0x38, /* 00111000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x3c, /* 00111100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 162 0xa2 '¢' */
-	0x00, /* 00000000 */
-	0x18, /* 00011000 */
-	0x30, /* 00110000 */
-	0x60, /* 01100000 */
-	0x00, /* 00000000 */
-	0x7c, /* 01111100 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x7c, /* 01111100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 163 0xa3 '£' */
-	0x00, /* 00000000 */
-	0x18, /* 00011000 */
-	0x30, /* 00110000 */
-	0x60, /* 01100000 */
-	0x00, /* 00000000 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0x76, /* 01110110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 164 0xa4 '¤' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x76, /* 01110110 */
-	0xdc, /* 11011100 */
-	0x00, /* 00000000 */
-	0xdc, /* 11011100 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 165 0xa5 '¥' */
-	0x76, /* 01110110 */
-	0xdc, /* 11011100 */
-	0x00, /* 00000000 */
-	0xc6, /* 11000110 */
-	0xe6, /* 11100110 */
-	0xf6, /* 11110110 */
-	0xfe, /* 11111110 */
-	0xde, /* 11011110 */
-	0xce, /* 11001110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 166 0xa6 '¦' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x3c, /* 00111100 */
-	0x6c, /* 01101100 */
-	0x6c, /* 01101100 */
-	0x3e, /* 00111110 */
-	0x00, /* 00000000 */
-	0x7e, /* 01111110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 167 0xa7 '§' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x38, /* 00111000 */
-	0x6c, /* 01101100 */
-	0x6c, /* 01101100 */
-	0x38, /* 00111000 */
-	0x00, /* 00000000 */
-	0x7c, /* 01111100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 168 0xa8 '¨' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x30, /* 00110000 */
-	0x30, /* 00110000 */
-	0x00, /* 00000000 */
-	0x30, /* 00110000 */
-	0x30, /* 00110000 */
-	0x60, /* 01100000 */
-	0xc0, /* 11000000 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x7c, /* 01111100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 169 0xa9 '©' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xfe, /* 11111110 */
-	0xc0, /* 11000000 */
-	0xc0, /* 11000000 */
-	0xc0, /* 11000000 */
-	0xc0, /* 11000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 170 0xaa 'ª' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xfe, /* 11111110 */
-	0x06, /* 00000110 */
-	0x06, /* 00000110 */
-	0x06, /* 00000110 */
-	0x06, /* 00000110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 171 0xab '«' */
-	0x00, /* 00000000 */
-	0x60, /* 01100000 */
-	0xe0, /* 11100000 */
-	0x62, /* 01100010 */
-	0x66, /* 01100110 */
-	0x6c, /* 01101100 */
-	0x18, /* 00011000 */
-	0x30, /* 00110000 */
-	0x60, /* 01100000 */
-	0xdc, /* 11011100 */
-	0x86, /* 10000110 */
-	0x0c, /* 00001100 */
-	0x18, /* 00011000 */
-	0x3e, /* 00111110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 172 0xac '¬' */
-	0x00, /* 00000000 */
-	0x60, /* 01100000 */
-	0xe0, /* 11100000 */
-	0x62, /* 01100010 */
-	0x66, /* 01100110 */
-	0x6c, /* 01101100 */
-	0x18, /* 00011000 */
-	0x30, /* 00110000 */
-	0x66, /* 01100110 */
-	0xce, /* 11001110 */
-	0x9a, /* 10011010 */
-	0x3f, /* 00111111 */
-	0x06, /* 00000110 */
-	0x06, /* 00000110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 173 0xad '­' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x3c, /* 00111100 */
-	0x3c, /* 00111100 */
-	0x3c, /* 00111100 */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 174 0xae '®' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x36, /* 00110110 */
-	0x6c, /* 01101100 */
-	0xd8, /* 11011000 */
-	0x6c, /* 01101100 */
-	0x36, /* 00110110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 175 0xaf '¯' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xd8, /* 11011000 */
-	0x6c, /* 01101100 */
-	0x36, /* 00110110 */
-	0x6c, /* 01101100 */
-	0xd8, /* 11011000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 176 0xb0 '°' */
-	0x11, /* 00010001 */
-	0x44, /* 01000100 */
-	0x11, /* 00010001 */
-	0x44, /* 01000100 */
-	0x11, /* 00010001 */
-	0x44, /* 01000100 */
-	0x11, /* 00010001 */
-	0x44, /* 01000100 */
-	0x11, /* 00010001 */
-	0x44, /* 01000100 */
-	0x11, /* 00010001 */
-	0x44, /* 01000100 */
-	0x11, /* 00010001 */
-	0x44, /* 01000100 */
-	0x11, /* 00010001 */
-	0x44, /* 01000100 */
-
-	/* 177 0xb1 '±' */
-	0x55, /* 01010101 */
-	0xaa, /* 10101010 */
-	0x55, /* 01010101 */
-	0xaa, /* 10101010 */
-	0x55, /* 01010101 */
-	0xaa, /* 10101010 */
-	0x55, /* 01010101 */
-	0xaa, /* 10101010 */
-	0x55, /* 01010101 */
-	0xaa, /* 10101010 */
-	0x55, /* 01010101 */
-	0xaa, /* 10101010 */
-	0x55, /* 01010101 */
-	0xaa, /* 10101010 */
-	0x55, /* 01010101 */
-	0xaa, /* 10101010 */
-
-	/* 178 0xb2 '²' */
-	0xdd, /* 11011101 */
-	0x77, /* 01110111 */
-	0xdd, /* 11011101 */
-	0x77, /* 01110111 */
-	0xdd, /* 11011101 */
-	0x77, /* 01110111 */
-	0xdd, /* 11011101 */
-	0x77, /* 01110111 */
-	0xdd, /* 11011101 */
-	0x77, /* 01110111 */
-	0xdd, /* 11011101 */
-	0x77, /* 01110111 */
-	0xdd, /* 11011101 */
-	0x77, /* 01110111 */
-	0xdd, /* 11011101 */
-	0x77, /* 01110111 */
-
-	/* 179 0xb3 '³' */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-
-	/* 180 0xb4 '´' */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0xf8, /* 11111000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-
-	/* 181 0xb5 'µ' */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0xf8, /* 11111000 */
-	0x18, /* 00011000 */
-	0xf8, /* 11111000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-
-	/* 182 0xb6 '¶' */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0xf6, /* 11110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-
-	/* 183 0xb7 '·' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xfe, /* 11111110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-
-	/* 184 0xb8 '¸' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xf8, /* 11111000 */
-	0x18, /* 00011000 */
-	0xf8, /* 11111000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-
-	/* 185 0xb9 '¹' */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0xf6, /* 11110110 */
-	0x06, /* 00000110 */
-	0xf6, /* 11110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-
-	/* 186 0xba 'º' */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-
-	/* 187 0xbb '»' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xfe, /* 11111110 */
-	0x06, /* 00000110 */
-	0xf6, /* 11110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-
-	/* 188 0xbc '¼' */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0xf6, /* 11110110 */
-	0x06, /* 00000110 */
-	0xfe, /* 11111110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 189 0xbd '½' */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0xfe, /* 11111110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 190 0xbe '¾' */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0xf8, /* 11111000 */
-	0x18, /* 00011000 */
-	0xf8, /* 11111000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 191 0xbf '¿' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xf8, /* 11111000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-
-	/* 192 0xc0 'À' */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x1f, /* 00011111 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 193 0xc1 'Á' */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0xff, /* 11111111 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 194 0xc2 'Â' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xff, /* 11111111 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-
-	/* 195 0xc3 'Ã' */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x1f, /* 00011111 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-
-	/* 196 0xc4 'Ä' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xff, /* 11111111 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 197 0xc5 'Å' */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0xff, /* 11111111 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-
-	/* 198 0xc6 'Æ' */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x1f, /* 00011111 */
-	0x18, /* 00011000 */
-	0x1f, /* 00011111 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-
-	/* 199 0xc7 'Ç' */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x37, /* 00110111 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-
-	/* 200 0xc8 'È' */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x37, /* 00110111 */
-	0x30, /* 00110000 */
-	0x3f, /* 00111111 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 201 0xc9 'É' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x3f, /* 00111111 */
-	0x30, /* 00110000 */
-	0x37, /* 00110111 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-
-	/* 202 0xca 'Ê' */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0xf7, /* 11110111 */
-	0x00, /* 00000000 */
-	0xff, /* 11111111 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 203 0xcb 'Ë' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xff, /* 11111111 */
-	0x00, /* 00000000 */
-	0xf7, /* 11110111 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-
-	/* 204 0xcc 'Ì' */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x37, /* 00110111 */
-	0x30, /* 00110000 */
-	0x37, /* 00110111 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-
-	/* 205 0xcd 'Í' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xff, /* 11111111 */
-	0x00, /* 00000000 */
-	0xff, /* 11111111 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 206 0xce 'Î' */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0xf7, /* 11110111 */
-	0x00, /* 00000000 */
-	0xf7, /* 11110111 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-
-	/* 207 0xcf 'Ï' */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0xff, /* 11111111 */
-	0x00, /* 00000000 */
-	0xff, /* 11111111 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 208 0xd0 'Ð' */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0xff, /* 11111111 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 209 0xd1 'Ñ' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xff, /* 11111111 */
-	0x00, /* 00000000 */
-	0xff, /* 11111111 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-
-	/* 210 0xd2 'Ò' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xff, /* 11111111 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-
-	/* 211 0xd3 'Ó' */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x3f, /* 00111111 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 212 0xd4 'Ô' */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x1f, /* 00011111 */
-	0x18, /* 00011000 */
-	0x1f, /* 00011111 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 213 0xd5 'Õ' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x1f, /* 00011111 */
-	0x18, /* 00011000 */
-	0x1f, /* 00011111 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-
-	/* 214 0xd6 'Ö' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x3f, /* 00111111 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-
-	/* 215 0xd7 '×' */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0xff, /* 11111111 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-
-	/* 216 0xd8 'Ø' */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0xff, /* 11111111 */
-	0x18, /* 00011000 */
-	0xff, /* 11111111 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-
-	/* 217 0xd9 'Ù' */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0xf8, /* 11111000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 218 0xda 'Ú' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x1f, /* 00011111 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-
-	/* 219 0xdb 'Û' */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-
-	/* 220 0xdc 'Ü' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-
-	/* 221 0xdd 'Ý' */
-	0xf0, /* 11110000 */
-	0xf0, /* 11110000 */
-	0xf0, /* 11110000 */
-	0xf0, /* 11110000 */
-	0xf0, /* 11110000 */
-	0xf0, /* 11110000 */
-	0xf0, /* 11110000 */
-	0xf0, /* 11110000 */
-	0xf0, /* 11110000 */
-	0xf0, /* 11110000 */
-	0xf0, /* 11110000 */
-	0xf0, /* 11110000 */
-	0xf0, /* 11110000 */
-	0xf0, /* 11110000 */
-	0xf0, /* 11110000 */
-	0xf0, /* 11110000 */
-
-	/* 222 0xde 'Þ' */
-	0x0f, /* 00001111 */
-	0x0f, /* 00001111 */
-	0x0f, /* 00001111 */
-	0x0f, /* 00001111 */
-	0x0f, /* 00001111 */
-	0x0f, /* 00001111 */
-	0x0f, /* 00001111 */
-	0x0f, /* 00001111 */
-	0x0f, /* 00001111 */
-	0x0f, /* 00001111 */
-	0x0f, /* 00001111 */
-	0x0f, /* 00001111 */
-	0x0f, /* 00001111 */
-	0x0f, /* 00001111 */
-	0x0f, /* 00001111 */
-	0x0f, /* 00001111 */
-
-	/* 223 0xdf 'ß' */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 224 0xe0 'à' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x76, /* 01110110 */
-	0xdc, /* 11011100 */
-	0xd8, /* 11011000 */
-	0xd8, /* 11011000 */
-	0xd8, /* 11011000 */
-	0xdc, /* 11011100 */
-	0x76, /* 01110110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 225 0xe1 'á' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x78, /* 01111000 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xd8, /* 11011000 */
-	0xcc, /* 11001100 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xcc, /* 11001100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 226 0xe2 'â' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xfe, /* 11111110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc0, /* 11000000 */
-	0xc0, /* 11000000 */
-	0xc0, /* 11000000 */
-	0xc0, /* 11000000 */
-	0xc0, /* 11000000 */
-	0xc0, /* 11000000 */
-	0xc0, /* 11000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 227 0xe3 'ã' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xfe, /* 11111110 */
-	0x6c, /* 01101100 */
-	0x6c, /* 01101100 */
-	0x6c, /* 01101100 */
-	0x6c, /* 01101100 */
-	0x6c, /* 01101100 */
-	0x6c, /* 01101100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 228 0xe4 'ä' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xfe, /* 11111110 */
-	0xc6, /* 11000110 */
-	0x60, /* 01100000 */
-	0x30, /* 00110000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x30, /* 00110000 */
-	0x60, /* 01100000 */
-	0xc6, /* 11000110 */
-	0xfe, /* 11111110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 229 0xe5 'å' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x7e, /* 01111110 */
-	0xd8, /* 11011000 */
-	0xd8, /* 11011000 */
-	0xd8, /* 11011000 */
-	0xd8, /* 11011000 */
-	0xd8, /* 11011000 */
-	0x70, /* 01110000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 230 0xe6 'æ' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x7c, /* 01111100 */
-	0x60, /* 01100000 */
-	0x60, /* 01100000 */
-	0xc0, /* 11000000 */
-	0x00, /* 00000000 */
-
-	/* 231 0xe7 'ç' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x76, /* 01110110 */
-	0xdc, /* 11011100 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 232 0xe8 'è' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x7e, /* 01111110 */
-	0x18, /* 00011000 */
-	0x3c, /* 00111100 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x3c, /* 00111100 */
-	0x18, /* 00011000 */
-	0x7e, /* 01111110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 233 0xe9 'é' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x38, /* 00111000 */
-	0x6c, /* 01101100 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xfe, /* 11111110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x6c, /* 01101100 */
-	0x38, /* 00111000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 234 0xea 'ê' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x38, /* 00111000 */
-	0x6c, /* 01101100 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x6c, /* 01101100 */
-	0x6c, /* 01101100 */
-	0x6c, /* 01101100 */
-	0x6c, /* 01101100 */
-	0xee, /* 11101110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 235 0xeb 'ë' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x1e, /* 00011110 */
-	0x30, /* 00110000 */
-	0x18, /* 00011000 */
-	0x0c, /* 00001100 */
-	0x3e, /* 00111110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x3c, /* 00111100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 236 0xec 'ì' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x7e, /* 01111110 */
-	0xdb, /* 11011011 */
-	0xdb, /* 11011011 */
-	0xdb, /* 11011011 */
-	0x7e, /* 01111110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 237 0xed 'í' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x03, /* 00000011 */
-	0x06, /* 00000110 */
-	0x7e, /* 01111110 */
-	0xdb, /* 11011011 */
-	0xdb, /* 11011011 */
-	0xf3, /* 11110011 */
-	0x7e, /* 01111110 */
-	0x60, /* 01100000 */
-	0xc0, /* 11000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 238 0xee 'î' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x1c, /* 00011100 */
-	0x30, /* 00110000 */
-	0x60, /* 01100000 */
-	0x60, /* 01100000 */
-	0x7c, /* 01111100 */
-	0x60, /* 01100000 */
-	0x60, /* 01100000 */
-	0x60, /* 01100000 */
-	0x30, /* 00110000 */
-	0x1c, /* 00011100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 239 0xef 'ï' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x7c, /* 01111100 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 240 0xf0 'ð' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xfe, /* 11111110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xfe, /* 11111110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xfe, /* 11111110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 241 0xf1 'ñ' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x7e, /* 01111110 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x7e, /* 01111110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 242 0xf2 'ò' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x30, /* 00110000 */
-	0x18, /* 00011000 */
-	0x0c, /* 00001100 */
-	0x06, /* 00000110 */
-	0x0c, /* 00001100 */
-	0x18, /* 00011000 */
-	0x30, /* 00110000 */
-	0x00, /* 00000000 */
-	0x7e, /* 01111110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 243 0xf3 'ó' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x0c, /* 00001100 */
-	0x18, /* 00011000 */
-	0x30, /* 00110000 */
-	0x60, /* 01100000 */
-	0x30, /* 00110000 */
-	0x18, /* 00011000 */
-	0x0c, /* 00001100 */
-	0x00, /* 00000000 */
-	0x7e, /* 01111110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 244 0xf4 'ô' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x0e, /* 00001110 */
-	0x1b, /* 00011011 */
-	0x1b, /* 00011011 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-
-	/* 245 0xf5 'õ' */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0xd8, /* 11011000 */
-	0xd8, /* 11011000 */
-	0xd8, /* 11011000 */
-	0x70, /* 01110000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 246 0xf6 'ö' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-	0x7e, /* 01111110 */
-	0x00, /* 00000000 */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 247 0xf7 '÷' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x76, /* 01110110 */
-	0xdc, /* 11011100 */
-	0x00, /* 00000000 */
-	0x76, /* 01110110 */
-	0xdc, /* 11011100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 248 0xf8 'ø' */
-	0x00, /* 00000000 */
-	0x38, /* 00111000 */
-	0x6c, /* 01101100 */
-	0x6c, /* 01101100 */
-	0x38, /* 00111000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 249 0xf9 'ù' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 250 0xfa 'ú' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 251 0xfb 'û' */
-	0x00, /* 00000000 */
-	0x0f, /* 00001111 */
-	0x0c, /* 00001100 */
-	0x0c, /* 00001100 */
-	0x0c, /* 00001100 */
-	0x0c, /* 00001100 */
-	0x0c, /* 00001100 */
-	0xec, /* 11101100 */
-	0x6c, /* 01101100 */
-	0x6c, /* 01101100 */
-	0x3c, /* 00111100 */
-	0x1c, /* 00011100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 252 0xfc 'ü' */
-	0x00, /* 00000000 */
-	0x6c, /* 01101100 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 253 0xfd 'ý' */
-	0x00, /* 00000000 */
-	0x3c, /* 00111100 */
-	0x66, /* 01100110 */
-	0x0c, /* 00001100 */
-	0x18, /* 00011000 */
-	0x32, /* 00110010 */
-	0x7e, /* 01111110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 254 0xfe 'þ' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x7e, /* 01111110 */
-	0x7e, /* 01111110 */
-	0x7e, /* 01111110 */
-	0x7e, /* 01111110 */
-	0x7e, /* 01111110 */
-	0x7e, /* 01111110 */
-	0x7e, /* 01111110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 255 0xff 'ÿ' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-};
-
diff -u --recursive --new-file v2.1.72/linux/arch/m68k/console/font_8x8.c linux/arch/m68k/console/font_8x8.c
--- v2.1.72/linux/arch/m68k/console/font_8x8.c	Mon Mar  4 12:38:11 1996
+++ linux/arch/m68k/console/font_8x8.c	Wed Dec 31 16:00:00 1969
@@ -1,2577 +0,0 @@
-/**********************************************/
-/*                                            */
-/*       Font file generated by cpi2fnt       */
-/*                                            */
-/**********************************************/
-
-#define FONTDATAMAX 2048
-
-char fontname_8x8[] = "VGA8x8";
-
-int  fontheight_8x8 = 8;
-int  fontwidth_8x8  = 8;
-
-unsigned char fontdata_8x8[FONTDATAMAX] = {
-
-	/* 0 0x00 '^@' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 1 0x01 '^A' */
-	0x7e, /* 01111110 */
-	0x81, /* 10000001 */
-	0xa5, /* 10100101 */
-	0x81, /* 10000001 */
-	0xbd, /* 10111101 */
-	0x99, /* 10011001 */
-	0x81, /* 10000001 */
-	0x7e, /* 01111110 */
-
-	/* 2 0x02 '^B' */
-	0x7e, /* 01111110 */
-	0xff, /* 11111111 */
-	0xdb, /* 11011011 */
-	0xff, /* 11111111 */
-	0xc3, /* 11000011 */
-	0xe7, /* 11100111 */
-	0xff, /* 11111111 */
-	0x7e, /* 01111110 */
-
-	/* 3 0x03 '^C' */
-	0x6c, /* 01101100 */
-	0xfe, /* 11111110 */
-	0xfe, /* 11111110 */
-	0xfe, /* 11111110 */
-	0x7c, /* 01111100 */
-	0x38, /* 00111000 */
-	0x10, /* 00010000 */
-	0x00, /* 00000000 */
-
-	/* 4 0x04 '^D' */
-	0x10, /* 00010000 */
-	0x38, /* 00111000 */
-	0x7c, /* 01111100 */
-	0xfe, /* 11111110 */
-	0x7c, /* 01111100 */
-	0x38, /* 00111000 */
-	0x10, /* 00010000 */
-	0x00, /* 00000000 */
-
-	/* 5 0x05 '^E' */
-	0x38, /* 00111000 */
-	0x7c, /* 01111100 */
-	0x38, /* 00111000 */
-	0xfe, /* 11111110 */
-	0xfe, /* 11111110 */
-	0xd6, /* 11010110 */
-	0x10, /* 00010000 */
-	0x38, /* 00111000 */
-
-	/* 6 0x06 '^F' */
-	0x10, /* 00010000 */
-	0x38, /* 00111000 */
-	0x7c, /* 01111100 */
-	0xfe, /* 11111110 */
-	0xfe, /* 11111110 */
-	0x7c, /* 01111100 */
-	0x10, /* 00010000 */
-	0x38, /* 00111000 */
-
-	/* 7 0x07 '^G' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x18, /* 00011000 */
-	0x3c, /* 00111100 */
-	0x3c, /* 00111100 */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 8 0x08 '^H' */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0xe7, /* 11100111 */
-	0xc3, /* 11000011 */
-	0xc3, /* 11000011 */
-	0xe7, /* 11100111 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-
-	/* 9 0x09 '^I' */
-	0x00, /* 00000000 */
-	0x3c, /* 00111100 */
-	0x66, /* 01100110 */
-	0x42, /* 01000010 */
-	0x42, /* 01000010 */
-	0x66, /* 01100110 */
-	0x3c, /* 00111100 */
-	0x00, /* 00000000 */
-
-	/* 10 0x0a '^J' */
-	0xff, /* 11111111 */
-	0xc3, /* 11000011 */
-	0x99, /* 10011001 */
-	0xbd, /* 10111101 */
-	0xbd, /* 10111101 */
-	0x99, /* 10011001 */
-	0xc3, /* 11000011 */
-	0xff, /* 11111111 */
-
-	/* 11 0x0b '^K' */
-	0x0f, /* 00001111 */
-	0x07, /* 00000111 */
-	0x0f, /* 00001111 */
-	0x7d, /* 01111101 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0x78, /* 01111000 */
-
-	/* 12 0x0c '^L' */
-	0x3c, /* 00111100 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x3c, /* 00111100 */
-	0x18, /* 00011000 */
-	0x7e, /* 01111110 */
-	0x18, /* 00011000 */
-
-	/* 13 0x0d '^M' */
-	0x3f, /* 00111111 */
-	0x33, /* 00110011 */
-	0x3f, /* 00111111 */
-	0x30, /* 00110000 */
-	0x30, /* 00110000 */
-	0x70, /* 01110000 */
-	0xf0, /* 11110000 */
-	0xe0, /* 11100000 */
-
-	/* 14 0x0e '^N' */
-	0x7f, /* 01111111 */
-	0x63, /* 01100011 */
-	0x7f, /* 01111111 */
-	0x63, /* 01100011 */
-	0x63, /* 01100011 */
-	0x67, /* 01100111 */
-	0xe6, /* 11100110 */
-	0xc0, /* 11000000 */
-
-	/* 15 0x0f '^O' */
-	0x18, /* 00011000 */
-	0xdb, /* 11011011 */
-	0x3c, /* 00111100 */
-	0xe7, /* 11100111 */
-	0xe7, /* 11100111 */
-	0x3c, /* 00111100 */
-	0xdb, /* 11011011 */
-	0x18, /* 00011000 */
-
-	/* 16 0x10 '^P' */
-	0x80, /* 10000000 */
-	0xe0, /* 11100000 */
-	0xf8, /* 11111000 */
-	0xfe, /* 11111110 */
-	0xf8, /* 11111000 */
-	0xe0, /* 11100000 */
-	0x80, /* 10000000 */
-	0x00, /* 00000000 */
-
-	/* 17 0x11 '^Q' */
-	0x02, /* 00000010 */
-	0x0e, /* 00001110 */
-	0x3e, /* 00111110 */
-	0xfe, /* 11111110 */
-	0x3e, /* 00111110 */
-	0x0e, /* 00001110 */
-	0x02, /* 00000010 */
-	0x00, /* 00000000 */
-
-	/* 18 0x12 '^R' */
-	0x18, /* 00011000 */
-	0x3c, /* 00111100 */
-	0x7e, /* 01111110 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x7e, /* 01111110 */
-	0x3c, /* 00111100 */
-	0x18, /* 00011000 */
-
-	/* 19 0x13 '^S' */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x00, /* 00000000 */
-	0x66, /* 01100110 */
-	0x00, /* 00000000 */
-
-	/* 20 0x14 '^T' */
-	0x7f, /* 01111111 */
-	0xdb, /* 11011011 */
-	0xdb, /* 11011011 */
-	0x7b, /* 01111011 */
-	0x1b, /* 00011011 */
-	0x1b, /* 00011011 */
-	0x1b, /* 00011011 */
-	0x00, /* 00000000 */
-
-	/* 21 0x15 '^U' */
-	0x3e, /* 00111110 */
-	0x61, /* 01100001 */
-	0x3c, /* 00111100 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x3c, /* 00111100 */
-	0x86, /* 10000110 */
-	0x7c, /* 01111100 */
-
-	/* 22 0x16 '^V' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x7e, /* 01111110 */
-	0x7e, /* 01111110 */
-	0x7e, /* 01111110 */
-	0x00, /* 00000000 */
-
-	/* 23 0x17 '^W' */
-	0x18, /* 00011000 */
-	0x3c, /* 00111100 */
-	0x7e, /* 01111110 */
-	0x18, /* 00011000 */
-	0x7e, /* 01111110 */
-	0x3c, /* 00111100 */
-	0x18, /* 00011000 */
-	0xff, /* 11111111 */
-
-	/* 24 0x18 '^X' */
-	0x18, /* 00011000 */
-	0x3c, /* 00111100 */
-	0x7e, /* 01111110 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-
-	/* 25 0x19 '^Y' */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x7e, /* 01111110 */
-	0x3c, /* 00111100 */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-
-	/* 26 0x1a '^Z' */
-	0x00, /* 00000000 */
-	0x18, /* 00011000 */
-	0x0c, /* 00001100 */
-	0xfe, /* 11111110 */
-	0x0c, /* 00001100 */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 27 0x1b '^[' */
-	0x00, /* 00000000 */
-	0x30, /* 00110000 */
-	0x60, /* 01100000 */
-	0xfe, /* 11111110 */
-	0x60, /* 01100000 */
-	0x30, /* 00110000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 28 0x1c '^\' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xc0, /* 11000000 */
-	0xc0, /* 11000000 */
-	0xc0, /* 11000000 */
-	0xfe, /* 11111110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 29 0x1d '^]' */
-	0x00, /* 00000000 */
-	0x24, /* 00100100 */
-	0x66, /* 01100110 */
-	0xff, /* 11111111 */
-	0x66, /* 01100110 */
-	0x24, /* 00100100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 30 0x1e '^^' */
-	0x00, /* 00000000 */
-	0x18, /* 00011000 */
-	0x3c, /* 00111100 */
-	0x7e, /* 01111110 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 31 0x1f '^_' */
-	0x00, /* 00000000 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0x7e, /* 01111110 */
-	0x3c, /* 00111100 */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 32 0x20 ' ' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 33 0x21 '!' */
-	0x18, /* 00011000 */
-	0x3c, /* 00111100 */
-	0x3c, /* 00111100 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-
-	/* 34 0x22 '"' */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x24, /* 00100100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 35 0x23 '#' */
-	0x6c, /* 01101100 */
-	0x6c, /* 01101100 */
-	0xfe, /* 11111110 */
-	0x6c, /* 01101100 */
-	0xfe, /* 11111110 */
-	0x6c, /* 01101100 */
-	0x6c, /* 01101100 */
-	0x00, /* 00000000 */
-
-	/* 36 0x24 '$' */
-	0x18, /* 00011000 */
-	0x3e, /* 00111110 */
-	0x60, /* 01100000 */
-	0x3c, /* 00111100 */
-	0x06, /* 00000110 */
-	0x7c, /* 01111100 */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-
-	/* 37 0x25 '%' */
-	0x00, /* 00000000 */
-	0xc6, /* 11000110 */
-	0xcc, /* 11001100 */
-	0x18, /* 00011000 */
-	0x30, /* 00110000 */
-	0x66, /* 01100110 */
-	0xc6, /* 11000110 */
-	0x00, /* 00000000 */
-
-	/* 38 0x26 '&' */
-	0x38, /* 00111000 */
-	0x6c, /* 01101100 */
-	0x38, /* 00111000 */
-	0x76, /* 01110110 */
-	0xdc, /* 11011100 */
-	0xcc, /* 11001100 */
-	0x76, /* 01110110 */
-	0x00, /* 00000000 */
-
-	/* 39 0x27 ''' */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x30, /* 00110000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 40 0x28 '(' */
-	0x0c, /* 00001100 */
-	0x18, /* 00011000 */
-	0x30, /* 00110000 */
-	0x30, /* 00110000 */
-	0x30, /* 00110000 */
-	0x18, /* 00011000 */
-	0x0c, /* 00001100 */
-	0x00, /* 00000000 */
-
-	/* 41 0x29 ')' */
-	0x30, /* 00110000 */
-	0x18, /* 00011000 */
-	0x0c, /* 00001100 */
-	0x0c, /* 00001100 */
-	0x0c, /* 00001100 */
-	0x18, /* 00011000 */
-	0x30, /* 00110000 */
-	0x00, /* 00000000 */
-
-	/* 42 0x2a '*' */
-	0x00, /* 00000000 */
-	0x66, /* 01100110 */
-	0x3c, /* 00111100 */
-	0xff, /* 11111111 */
-	0x3c, /* 00111100 */
-	0x66, /* 01100110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 43 0x2b '+' */
-	0x00, /* 00000000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x7e, /* 01111110 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 44 0x2c ',' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x30, /* 00110000 */
-
-	/* 45 0x2d '-' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x7e, /* 01111110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 46 0x2e '.' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-
-	/* 47 0x2f '/' */
-	0x06, /* 00000110 */
-	0x0c, /* 00001100 */
-	0x18, /* 00011000 */
-	0x30, /* 00110000 */
-	0x60, /* 01100000 */
-	0xc0, /* 11000000 */
-	0x80, /* 10000000 */
-	0x00, /* 00000000 */
-
-	/* 48 0x30 '0' */
-	0x38, /* 00111000 */
-	0x6c, /* 01101100 */
-	0xc6, /* 11000110 */
-	0xd6, /* 11010110 */
-	0xc6, /* 11000110 */
-	0x6c, /* 01101100 */
-	0x38, /* 00111000 */
-	0x00, /* 00000000 */
-
-	/* 49 0x31 '1' */
-	0x18, /* 00011000 */
-	0x38, /* 00111000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x7e, /* 01111110 */
-	0x00, /* 00000000 */
-
-	/* 50 0x32 '2' */
-	0x7c, /* 01111100 */
-	0xc6, /* 11000110 */
-	0x06, /* 00000110 */
-	0x1c, /* 00011100 */
-	0x30, /* 00110000 */
-	0x66, /* 01100110 */
-	0xfe, /* 11111110 */
-	0x00, /* 00000000 */
-
-	/* 51 0x33 '3' */
-	0x7c, /* 01111100 */
-	0xc6, /* 11000110 */
-	0x06, /* 00000110 */
-	0x3c, /* 00111100 */
-	0x06, /* 00000110 */
-	0xc6, /* 11000110 */
-	0x7c, /* 01111100 */
-	0x00, /* 00000000 */
-
-	/* 52 0x34 '4' */
-	0x1c, /* 00011100 */
-	0x3c, /* 00111100 */
-	0x6c, /* 01101100 */
-	0xcc, /* 11001100 */
-	0xfe, /* 11111110 */
-	0x0c, /* 00001100 */
-	0x1e, /* 00011110 */
-	0x00, /* 00000000 */
-
-	/* 53 0x35 '5' */
-	0xfe, /* 11111110 */
-	0xc0, /* 11000000 */
-	0xc0, /* 11000000 */
-	0xfc, /* 11111100 */
-	0x06, /* 00000110 */
-	0xc6, /* 11000110 */
-	0x7c, /* 01111100 */
-	0x00, /* 00000000 */
-
-	/* 54 0x36 '6' */
-	0x38, /* 00111000 */
-	0x60, /* 01100000 */
-	0xc0, /* 11000000 */
-	0xfc, /* 11111100 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x7c, /* 01111100 */
-	0x00, /* 00000000 */
-
-	/* 55 0x37 '7' */
-	0xfe, /* 11111110 */
-	0xc6, /* 11000110 */
-	0x0c, /* 00001100 */
-	0x18, /* 00011000 */
-	0x30, /* 00110000 */
-	0x30, /* 00110000 */
-	0x30, /* 00110000 */
-	0x00, /* 00000000 */
-
-	/* 56 0x38 '8' */
-	0x7c, /* 01111100 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x7c, /* 01111100 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x7c, /* 01111100 */
-	0x00, /* 00000000 */
-
-	/* 57 0x39 '9' */
-	0x7c, /* 01111100 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x7e, /* 01111110 */
-	0x06, /* 00000110 */
-	0x0c, /* 00001100 */
-	0x78, /* 01111000 */
-	0x00, /* 00000000 */
-
-	/* 58 0x3a ':' */
-	0x00, /* 00000000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-
-	/* 59 0x3b ';' */
-	0x00, /* 00000000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x30, /* 00110000 */
-
-	/* 60 0x3c '<' */
-	0x06, /* 00000110 */
-	0x0c, /* 00001100 */
-	0x18, /* 00011000 */
-	0x30, /* 00110000 */
-	0x18, /* 00011000 */
-	0x0c, /* 00001100 */
-	0x06, /* 00000110 */
-	0x00, /* 00000000 */
-
-	/* 61 0x3d '=' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x7e, /* 01111110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x7e, /* 01111110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 62 0x3e '>' */
-	0x60, /* 01100000 */
-	0x30, /* 00110000 */
-	0x18, /* 00011000 */
-	0x0c, /* 00001100 */
-	0x18, /* 00011000 */
-	0x30, /* 00110000 */
-	0x60, /* 01100000 */
-	0x00, /* 00000000 */
-
-	/* 63 0x3f '?' */
-	0x7c, /* 01111100 */
-	0xc6, /* 11000110 */
-	0x0c, /* 00001100 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-
-	/* 64 0x40 '@' */
-	0x7c, /* 01111100 */
-	0xc6, /* 11000110 */
-	0xde, /* 11011110 */
-	0xde, /* 11011110 */
-	0xde, /* 11011110 */
-	0xc0, /* 11000000 */
-	0x78, /* 01111000 */
-	0x00, /* 00000000 */
-
-	/* 65 0x41 'A' */
-	0x38, /* 00111000 */
-	0x6c, /* 01101100 */
-	0xc6, /* 11000110 */
-	0xfe, /* 11111110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x00, /* 00000000 */
-
-	/* 66 0x42 'B' */
-	0xfc, /* 11111100 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x7c, /* 01111100 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0xfc, /* 11111100 */
-	0x00, /* 00000000 */
-
-	/* 67 0x43 'C' */
-	0x3c, /* 00111100 */
-	0x66, /* 01100110 */
-	0xc0, /* 11000000 */
-	0xc0, /* 11000000 */
-	0xc0, /* 11000000 */
-	0x66, /* 01100110 */
-	0x3c, /* 00111100 */
-	0x00, /* 00000000 */
-
-	/* 68 0x44 'D' */
-	0xf8, /* 11111000 */
-	0x6c, /* 01101100 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x6c, /* 01101100 */
-	0xf8, /* 11111000 */
-	0x00, /* 00000000 */
-
-	/* 69 0x45 'E' */
-	0xfe, /* 11111110 */
-	0x62, /* 01100010 */
-	0x68, /* 01101000 */
-	0x78, /* 01111000 */
-	0x68, /* 01101000 */
-	0x62, /* 01100010 */
-	0xfe, /* 11111110 */
-	0x00, /* 00000000 */
-
-	/* 70 0x46 'F' */
-	0xfe, /* 11111110 */
-	0x62, /* 01100010 */
-	0x68, /* 01101000 */
-	0x78, /* 01111000 */
-	0x68, /* 01101000 */
-	0x60, /* 01100000 */
-	0xf0, /* 11110000 */
-	0x00, /* 00000000 */
-
-	/* 71 0x47 'G' */
-	0x3c, /* 00111100 */
-	0x66, /* 01100110 */
-	0xc0, /* 11000000 */
-	0xc0, /* 11000000 */
-	0xce, /* 11001110 */
-	0x66, /* 01100110 */
-	0x3a, /* 00111010 */
-	0x00, /* 00000000 */
-
-	/* 72 0x48 'H' */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xfe, /* 11111110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x00, /* 00000000 */
-
-	/* 73 0x49 'I' */
-	0x3c, /* 00111100 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x3c, /* 00111100 */
-	0x00, /* 00000000 */
-
-	/* 74 0x4a 'J' */
-	0x1e, /* 00011110 */
-	0x0c, /* 00001100 */
-	0x0c, /* 00001100 */
-	0x0c, /* 00001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0x78, /* 01111000 */
-	0x00, /* 00000000 */
-
-	/* 75 0x4b 'K' */
-	0xe6, /* 11100110 */
-	0x66, /* 01100110 */
-	0x6c, /* 01101100 */
-	0x78, /* 01111000 */
-	0x6c, /* 01101100 */
-	0x66, /* 01100110 */
-	0xe6, /* 11100110 */
-	0x00, /* 00000000 */
-
-	/* 76 0x4c 'L' */
-	0xf0, /* 11110000 */
-	0x60, /* 01100000 */
-	0x60, /* 01100000 */
-	0x60, /* 01100000 */
-	0x62, /* 01100010 */
-	0x66, /* 01100110 */
-	0xfe, /* 11111110 */
-	0x00, /* 00000000 */
-
-	/* 77 0x4d 'M' */
-	0xc6, /* 11000110 */
-	0xee, /* 11101110 */
-	0xfe, /* 11111110 */
-	0xfe, /* 11111110 */
-	0xd6, /* 11010110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x00, /* 00000000 */
-
-	/* 78 0x4e 'N' */
-	0xc6, /* 11000110 */
-	0xe6, /* 11100110 */
-	0xf6, /* 11110110 */
-	0xde, /* 11011110 */
-	0xce, /* 11001110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x00, /* 00000000 */
-
-	/* 79 0x4f 'O' */
-	0x7c, /* 01111100 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x7c, /* 01111100 */
-	0x00, /* 00000000 */
-
-	/* 80 0x50 'P' */
-	0xfc, /* 11111100 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x7c, /* 01111100 */
-	0x60, /* 01100000 */
-	0x60, /* 01100000 */
-	0xf0, /* 11110000 */
-	0x00, /* 00000000 */
-
-	/* 81 0x51 'Q' */
-	0x7c, /* 01111100 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xce, /* 11001110 */
-	0x7c, /* 01111100 */
-	0x0e, /* 00001110 */
-
-	/* 82 0x52 'R' */
-	0xfc, /* 11111100 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x7c, /* 01111100 */
-	0x6c, /* 01101100 */
-	0x66, /* 01100110 */
-	0xe6, /* 11100110 */
-	0x00, /* 00000000 */
-
-	/* 83 0x53 'S' */
-	0x3c, /* 00111100 */
-	0x66, /* 01100110 */
-	0x30, /* 00110000 */
-	0x18, /* 00011000 */
-	0x0c, /* 00001100 */
-	0x66, /* 01100110 */
-	0x3c, /* 00111100 */
-	0x00, /* 00000000 */
-
-	/* 84 0x54 'T' */
-	0x7e, /* 01111110 */
-	0x7e, /* 01111110 */
-	0x5a, /* 01011010 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x3c, /* 00111100 */
-	0x00, /* 00000000 */
-
-	/* 85 0x55 'U' */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x7c, /* 01111100 */
-	0x00, /* 00000000 */
-
-	/* 86 0x56 'V' */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x6c, /* 01101100 */
-	0x38, /* 00111000 */
-	0x00, /* 00000000 */
-
-	/* 87 0x57 'W' */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xd6, /* 11010110 */
-	0xd6, /* 11010110 */
-	0xfe, /* 11111110 */
-	0x6c, /* 01101100 */
-	0x00, /* 00000000 */
-
-	/* 88 0x58 'X' */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x6c, /* 01101100 */
-	0x38, /* 00111000 */
-	0x6c, /* 01101100 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x00, /* 00000000 */
-
-	/* 89 0x59 'Y' */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x3c, /* 00111100 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x3c, /* 00111100 */
-	0x00, /* 00000000 */
-
-	/* 90 0x5a 'Z' */
-	0xfe, /* 11111110 */
-	0xc6, /* 11000110 */
-	0x8c, /* 10001100 */
-	0x18, /* 00011000 */
-	0x32, /* 00110010 */
-	0x66, /* 01100110 */
-	0xfe, /* 11111110 */
-	0x00, /* 00000000 */
-
-	/* 91 0x5b '[' */
-	0x3c, /* 00111100 */
-	0x30, /* 00110000 */
-	0x30, /* 00110000 */
-	0x30, /* 00110000 */
-	0x30, /* 00110000 */
-	0x30, /* 00110000 */
-	0x3c, /* 00111100 */
-	0x00, /* 00000000 */
-
-	/* 92 0x5c '\' */
-	0xc0, /* 11000000 */
-	0x60, /* 01100000 */
-	0x30, /* 00110000 */
-	0x18, /* 00011000 */
-	0x0c, /* 00001100 */
-	0x06, /* 00000110 */
-	0x02, /* 00000010 */
-	0x00, /* 00000000 */
-
-	/* 93 0x5d ']' */
-	0x3c, /* 00111100 */
-	0x0c, /* 00001100 */
-	0x0c, /* 00001100 */
-	0x0c, /* 00001100 */
-	0x0c, /* 00001100 */
-	0x0c, /* 00001100 */
-	0x3c, /* 00111100 */
-	0x00, /* 00000000 */
-
-	/* 94 0x5e '^' */
-	0x10, /* 00010000 */
-	0x38, /* 00111000 */
-	0x6c, /* 01101100 */
-	0xc6, /* 11000110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 95 0x5f '_' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xff, /* 11111111 */
-
-	/* 96 0x60 '`' */
-	0x30, /* 00110000 */
-	0x18, /* 00011000 */
-	0x0c, /* 00001100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 97 0x61 'a' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x78, /* 01111000 */
-	0x0c, /* 00001100 */
-	0x7c, /* 01111100 */
-	0xcc, /* 11001100 */
-	0x76, /* 01110110 */
-	0x00, /* 00000000 */
-
-	/* 98 0x62 'b' */
-	0xe0, /* 11100000 */
-	0x60, /* 01100000 */
-	0x7c, /* 01111100 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0xdc, /* 11011100 */
-	0x00, /* 00000000 */
-
-	/* 99 0x63 'c' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x7c, /* 01111100 */
-	0xc6, /* 11000110 */
-	0xc0, /* 11000000 */
-	0xc6, /* 11000110 */
-	0x7c, /* 01111100 */
-	0x00, /* 00000000 */
-
-	/* 100 0x64 'd' */
-	0x1c, /* 00011100 */
-	0x0c, /* 00001100 */
-	0x7c, /* 01111100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0x76, /* 01110110 */
-	0x00, /* 00000000 */
-
-	/* 101 0x65 'e' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x7c, /* 01111100 */
-	0xc6, /* 11000110 */
-	0xfe, /* 11111110 */
-	0xc0, /* 11000000 */
-	0x7c, /* 01111100 */
-	0x00, /* 00000000 */
-
-	/* 102 0x66 'f' */
-	0x3c, /* 00111100 */
-	0x66, /* 01100110 */
-	0x60, /* 01100000 */
-	0xf8, /* 11111000 */
-	0x60, /* 01100000 */
-	0x60, /* 01100000 */
-	0xf0, /* 11110000 */
-	0x00, /* 00000000 */
-
-	/* 103 0x67 'g' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x76, /* 01110110 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0x7c, /* 01111100 */
-	0x0c, /* 00001100 */
-	0xf8, /* 11111000 */
-
-	/* 104 0x68 'h' */
-	0xe0, /* 11100000 */
-	0x60, /* 01100000 */
-	0x6c, /* 01101100 */
-	0x76, /* 01110110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0xe6, /* 11100110 */
-	0x00, /* 00000000 */
-
-	/* 105 0x69 'i' */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-	0x38, /* 00111000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x3c, /* 00111100 */
-	0x00, /* 00000000 */
-
-	/* 106 0x6a 'j' */
-	0x06, /* 00000110 */
-	0x00, /* 00000000 */
-	0x06, /* 00000110 */
-	0x06, /* 00000110 */
-	0x06, /* 00000110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x3c, /* 00111100 */
-
-	/* 107 0x6b 'k' */
-	0xe0, /* 11100000 */
-	0x60, /* 01100000 */
-	0x66, /* 01100110 */
-	0x6c, /* 01101100 */
-	0x78, /* 01111000 */
-	0x6c, /* 01101100 */
-	0xe6, /* 11100110 */
-	0x00, /* 00000000 */
-
-	/* 108 0x6c 'l' */
-	0x38, /* 00111000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x3c, /* 00111100 */
-	0x00, /* 00000000 */
-
-	/* 109 0x6d 'm' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xec, /* 11101100 */
-	0xfe, /* 11111110 */
-	0xd6, /* 11010110 */
-	0xd6, /* 11010110 */
-	0xd6, /* 11010110 */
-	0x00, /* 00000000 */
-
-	/* 110 0x6e 'n' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xdc, /* 11011100 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x00, /* 00000000 */
-
-	/* 111 0x6f 'o' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x7c, /* 01111100 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x7c, /* 01111100 */
-	0x00, /* 00000000 */
-
-	/* 112 0x70 'p' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xdc, /* 11011100 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x7c, /* 01111100 */
-	0x60, /* 01100000 */
-	0xf0, /* 11110000 */
-
-	/* 113 0x71 'q' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x76, /* 01110110 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0x7c, /* 01111100 */
-	0x0c, /* 00001100 */
-	0x1e, /* 00011110 */
-
-	/* 114 0x72 'r' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xdc, /* 11011100 */
-	0x76, /* 01110110 */
-	0x60, /* 01100000 */
-	0x60, /* 01100000 */
-	0xf0, /* 11110000 */
-	0x00, /* 00000000 */
-
-	/* 115 0x73 's' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x7e, /* 01111110 */
-	0xc0, /* 11000000 */
-	0x7c, /* 01111100 */
-	0x06, /* 00000110 */
-	0xfc, /* 11111100 */
-	0x00, /* 00000000 */
-
-	/* 116 0x74 't' */
-	0x30, /* 00110000 */
-	0x30, /* 00110000 */
-	0xfc, /* 11111100 */
-	0x30, /* 00110000 */
-	0x30, /* 00110000 */
-	0x36, /* 00110110 */
-	0x1c, /* 00011100 */
-	0x00, /* 00000000 */
-
-	/* 117 0x75 'u' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0x76, /* 01110110 */
-	0x00, /* 00000000 */
-
-	/* 118 0x76 'v' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x6c, /* 01101100 */
-	0x38, /* 00111000 */
-	0x00, /* 00000000 */
-
-	/* 119 0x77 'w' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xc6, /* 11000110 */
-	0xd6, /* 11010110 */
-	0xd6, /* 11010110 */
-	0xfe, /* 11111110 */
-	0x6c, /* 01101100 */
-	0x00, /* 00000000 */
-
-	/* 120 0x78 'x' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xc6, /* 11000110 */
-	0x6c, /* 01101100 */
-	0x38, /* 00111000 */
-	0x6c, /* 01101100 */
-	0xc6, /* 11000110 */
-	0x00, /* 00000000 */
-
-	/* 121 0x79 'y' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x7e, /* 01111110 */
-	0x06, /* 00000110 */
-	0xfc, /* 11111100 */
-
-	/* 122 0x7a 'z' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x7e, /* 01111110 */
-	0x4c, /* 01001100 */
-	0x18, /* 00011000 */
-	0x32, /* 00110010 */
-	0x7e, /* 01111110 */
-	0x00, /* 00000000 */
-
-	/* 123 0x7b '{' */
-	0x0e, /* 00001110 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x70, /* 01110000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x0e, /* 00001110 */
-	0x00, /* 00000000 */
-
-	/* 124 0x7c '|' */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-
-	/* 125 0x7d '}' */
-	0x70, /* 01110000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x0e, /* 00001110 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x70, /* 01110000 */
-	0x00, /* 00000000 */
-
-	/* 126 0x7e '~' */
-	0x76, /* 01110110 */
-	0xdc, /* 11011100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 127 0x7f '' */
-	0x00, /* 00000000 */
-	0x10, /* 00010000 */
-	0x38, /* 00111000 */
-	0x6c, /* 01101100 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xfe, /* 11111110 */
-	0x00, /* 00000000 */
-
-	/* 128 0x80 '€' */
-	0x7c, /* 01111100 */
-	0xc6, /* 11000110 */
-	0xc0, /* 11000000 */
-	0xc0, /* 11000000 */
-	0xc6, /* 11000110 */
-	0x7c, /* 01111100 */
-	0x0c, /* 00001100 */
-	0x78, /* 01111000 */
-
-	/* 129 0x81 '�' */
-	0xcc, /* 11001100 */
-	0x00, /* 00000000 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0x76, /* 01110110 */
-	0x00, /* 00000000 */
-
-	/* 130 0x82 '‚' */
-	0x0c, /* 00001100 */
-	0x18, /* 00011000 */
-	0x7c, /* 01111100 */
-	0xc6, /* 11000110 */
-	0xfe, /* 11111110 */
-	0xc0, /* 11000000 */
-	0x7c, /* 01111100 */
-	0x00, /* 00000000 */
-
-	/* 131 0x83 'ƒ' */
-	0x7c, /* 01111100 */
-	0x82, /* 10000010 */
-	0x78, /* 01111000 */
-	0x0c, /* 00001100 */
-	0x7c, /* 01111100 */
-	0xcc, /* 11001100 */
-	0x76, /* 01110110 */
-	0x00, /* 00000000 */
-
-	/* 132 0x84 '„' */
-	0xc6, /* 11000110 */
-	0x00, /* 00000000 */
-	0x78, /* 01111000 */
-	0x0c, /* 00001100 */
-	0x7c, /* 01111100 */
-	0xcc, /* 11001100 */
-	0x76, /* 01110110 */
-	0x00, /* 00000000 */
-
-	/* 133 0x85 '…' */
-	0x30, /* 00110000 */
-	0x18, /* 00011000 */
-	0x78, /* 01111000 */
-	0x0c, /* 00001100 */
-	0x7c, /* 01111100 */
-	0xcc, /* 11001100 */
-	0x76, /* 01110110 */
-	0x00, /* 00000000 */
-
-	/* 134 0x86 '†' */
-	0x30, /* 00110000 */
-	0x30, /* 00110000 */
-	0x78, /* 01111000 */
-	0x0c, /* 00001100 */
-	0x7c, /* 01111100 */
-	0xcc, /* 11001100 */
-	0x76, /* 01110110 */
-	0x00, /* 00000000 */
-
-	/* 135 0x87 '‡' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x7e, /* 01111110 */
-	0xc0, /* 11000000 */
-	0xc0, /* 11000000 */
-	0x7e, /* 01111110 */
-	0x0c, /* 00001100 */
-	0x38, /* 00111000 */
-
-	/* 136 0x88 'ˆ' */
-	0x7c, /* 01111100 */
-	0x82, /* 10000010 */
-	0x7c, /* 01111100 */
-	0xc6, /* 11000110 */
-	0xfe, /* 11111110 */
-	0xc0, /* 11000000 */
-	0x7c, /* 01111100 */
-	0x00, /* 00000000 */
-
-	/* 137 0x89 '‰' */
-	0xc6, /* 11000110 */
-	0x00, /* 00000000 */
-	0x7c, /* 01111100 */
-	0xc6, /* 11000110 */
-	0xfe, /* 11111110 */
-	0xc0, /* 11000000 */
-	0x7c, /* 01111100 */
-	0x00, /* 00000000 */
-
-	/* 138 0x8a 'Š' */
-	0x30, /* 00110000 */
-	0x18, /* 00011000 */
-	0x7c, /* 01111100 */
-	0xc6, /* 11000110 */
-	0xfe, /* 11111110 */
-	0xc0, /* 11000000 */
-	0x7c, /* 01111100 */
-	0x00, /* 00000000 */
-
-	/* 139 0x8b '‹' */
-	0x66, /* 01100110 */
-	0x00, /* 00000000 */
-	0x38, /* 00111000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x3c, /* 00111100 */
-	0x00, /* 00000000 */
-
-	/* 140 0x8c 'Œ' */
-	0x7c, /* 01111100 */
-	0x82, /* 10000010 */
-	0x38, /* 00111000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x3c, /* 00111100 */
-	0x00, /* 00000000 */
-
-	/* 141 0x8d '�' */
-	0x30, /* 00110000 */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-	0x38, /* 00111000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x3c, /* 00111100 */
-	0x00, /* 00000000 */
-
-	/* 142 0x8e 'Ž' */
-	0xc6, /* 11000110 */
-	0x38, /* 00111000 */
-	0x6c, /* 01101100 */
-	0xc6, /* 11000110 */
-	0xfe, /* 11111110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x00, /* 00000000 */
-
-	/* 143 0x8f '�' */
-	0x38, /* 00111000 */
-	0x6c, /* 01101100 */
-	0x7c, /* 01111100 */
-	0xc6, /* 11000110 */
-	0xfe, /* 11111110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x00, /* 00000000 */
-
-	/* 144 0x90 '�' */
-	0x18, /* 00011000 */
-	0x30, /* 00110000 */
-	0xfe, /* 11111110 */
-	0xc0, /* 11000000 */
-	0xf8, /* 11111000 */
-	0xc0, /* 11000000 */
-	0xfe, /* 11111110 */
-	0x00, /* 00000000 */
-
-	/* 145 0x91 '‘' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x7e, /* 01111110 */
-	0x18, /* 00011000 */
-	0x7e, /* 01111110 */
-	0xd8, /* 11011000 */
-	0x7e, /* 01111110 */
-	0x00, /* 00000000 */
-
-	/* 146 0x92 '’' */
-	0x3e, /* 00111110 */
-	0x6c, /* 01101100 */
-	0xcc, /* 11001100 */
-	0xfe, /* 11111110 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xce, /* 11001110 */
-	0x00, /* 00000000 */
-
-	/* 147 0x93 '“' */
-	0x7c, /* 01111100 */
-	0x82, /* 10000010 */
-	0x7c, /* 01111100 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x7c, /* 01111100 */
-	0x00, /* 00000000 */
-
-	/* 148 0x94 '”' */
-	0xc6, /* 11000110 */
-	0x00, /* 00000000 */
-	0x7c, /* 01111100 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x7c, /* 01111100 */
-	0x00, /* 00000000 */
-
-	/* 149 0x95 '•' */
-	0x30, /* 00110000 */
-	0x18, /* 00011000 */
-	0x7c, /* 01111100 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x7c, /* 01111100 */
-	0x00, /* 00000000 */
-
-	/* 150 0x96 '–' */
-	0x78, /* 01111000 */
-	0x84, /* 10000100 */
-	0x00, /* 00000000 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0x76, /* 01110110 */
-	0x00, /* 00000000 */
-
-	/* 151 0x97 '—' */
-	0x60, /* 01100000 */
-	0x30, /* 00110000 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0x76, /* 01110110 */
-	0x00, /* 00000000 */
-
-	/* 152 0x98 '˜' */
-	0xc6, /* 11000110 */
-	0x00, /* 00000000 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x7e, /* 01111110 */
-	0x06, /* 00000110 */
-	0xfc, /* 11111100 */
-
-	/* 153 0x99 '™' */
-	0xc6, /* 11000110 */
-	0x38, /* 00111000 */
-	0x6c, /* 01101100 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x6c, /* 01101100 */
-	0x38, /* 00111000 */
-	0x00, /* 00000000 */
-
-	/* 154 0x9a 'š' */
-	0xc6, /* 11000110 */
-	0x00, /* 00000000 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x7c, /* 01111100 */
-	0x00, /* 00000000 */
-
-	/* 155 0x9b '›' */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x7e, /* 01111110 */
-	0xc0, /* 11000000 */
-	0xc0, /* 11000000 */
-	0x7e, /* 01111110 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-
-	/* 156 0x9c 'œ' */
-	0x38, /* 00111000 */
-	0x6c, /* 01101100 */
-	0x64, /* 01100100 */
-	0xf0, /* 11110000 */
-	0x60, /* 01100000 */
-	0x66, /* 01100110 */
-	0xfc, /* 11111100 */
-	0x00, /* 00000000 */
-
-	/* 157 0x9d '�' */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x3c, /* 00111100 */
-	0x7e, /* 01111110 */
-	0x18, /* 00011000 */
-	0x7e, /* 01111110 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-
-	/* 158 0x9e 'ž' */
-	0xf8, /* 11111000 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xfa, /* 11111010 */
-	0xc6, /* 11000110 */
-	0xcf, /* 11001111 */
-	0xc6, /* 11000110 */
-	0xc7, /* 11000111 */
-
-	/* 159 0x9f 'Ÿ' */
-	0x0e, /* 00001110 */
-	0x1b, /* 00011011 */
-	0x18, /* 00011000 */
-	0x3c, /* 00111100 */
-	0x18, /* 00011000 */
-	0xd8, /* 11011000 */
-	0x70, /* 01110000 */
-	0x00, /* 00000000 */
-
-	/* 160 0xa0 ' ' */
-	0x18, /* 00011000 */
-	0x30, /* 00110000 */
-	0x78, /* 01111000 */
-	0x0c, /* 00001100 */
-	0x7c, /* 01111100 */
-	0xcc, /* 11001100 */
-	0x76, /* 01110110 */
-	0x00, /* 00000000 */
-
-	/* 161 0xa1 '¡' */
-	0x0c, /* 00001100 */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-	0x38, /* 00111000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x3c, /* 00111100 */
-	0x00, /* 00000000 */
-
-	/* 162 0xa2 '¢' */
-	0x0c, /* 00001100 */
-	0x18, /* 00011000 */
-	0x7c, /* 01111100 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x7c, /* 01111100 */
-	0x00, /* 00000000 */
-
-	/* 163 0xa3 '£' */
-	0x18, /* 00011000 */
-	0x30, /* 00110000 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0x76, /* 01110110 */
-	0x00, /* 00000000 */
-
-	/* 164 0xa4 '¤' */
-	0x76, /* 01110110 */
-	0xdc, /* 11011100 */
-	0x00, /* 00000000 */
-	0xdc, /* 11011100 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x00, /* 00000000 */
-
-	/* 165 0xa5 '¥' */
-	0x76, /* 01110110 */
-	0xdc, /* 11011100 */
-	0x00, /* 00000000 */
-	0xe6, /* 11100110 */
-	0xf6, /* 11110110 */
-	0xde, /* 11011110 */
-	0xce, /* 11001110 */
-	0x00, /* 00000000 */
-
-	/* 166 0xa6 '¦' */
-	0x3c, /* 00111100 */
-	0x6c, /* 01101100 */
-	0x6c, /* 01101100 */
-	0x3e, /* 00111110 */
-	0x00, /* 00000000 */
-	0x7e, /* 01111110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 167 0xa7 '§' */
-	0x38, /* 00111000 */
-	0x6c, /* 01101100 */
-	0x6c, /* 01101100 */
-	0x38, /* 00111000 */
-	0x00, /* 00000000 */
-	0x7c, /* 01111100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 168 0xa8 '¨' */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x30, /* 00110000 */
-	0x63, /* 01100011 */
-	0x3e, /* 00111110 */
-	0x00, /* 00000000 */
-
-	/* 169 0xa9 '©' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xfe, /* 11111110 */
-	0xc0, /* 11000000 */
-	0xc0, /* 11000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 170 0xaa 'ª' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xfe, /* 11111110 */
-	0x06, /* 00000110 */
-	0x06, /* 00000110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 171 0xab '«' */
-	0x63, /* 01100011 */
-	0xe6, /* 11100110 */
-	0x6c, /* 01101100 */
-	0x7e, /* 01111110 */
-	0x33, /* 00110011 */
-	0x66, /* 01100110 */
-	0xcc, /* 11001100 */
-	0x0f, /* 00001111 */
-
-	/* 172 0xac '¬' */
-	0x63, /* 01100011 */
-	0xe6, /* 11100110 */
-	0x6c, /* 01101100 */
-	0x7a, /* 01111010 */
-	0x36, /* 00110110 */
-	0x6a, /* 01101010 */
-	0xdf, /* 11011111 */
-	0x06, /* 00000110 */
-
-	/* 173 0xad '­' */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x3c, /* 00111100 */
-	0x3c, /* 00111100 */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-
-	/* 174 0xae '®' */
-	0x00, /* 00000000 */
-	0x33, /* 00110011 */
-	0x66, /* 01100110 */
-	0xcc, /* 11001100 */
-	0x66, /* 01100110 */
-	0x33, /* 00110011 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 175 0xaf '¯' */
-	0x00, /* 00000000 */
-	0xcc, /* 11001100 */
-	0x66, /* 01100110 */
-	0x33, /* 00110011 */
-	0x66, /* 01100110 */
-	0xcc, /* 11001100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 176 0xb0 '°' */
-	0x22, /* 00100010 */
-	0x88, /* 10001000 */
-	0x22, /* 00100010 */
-	0x88, /* 10001000 */
-	0x22, /* 00100010 */
-	0x88, /* 10001000 */
-	0x22, /* 00100010 */
-	0x88, /* 10001000 */
-
-	/* 177 0xb1 '±' */
-	0x55, /* 01010101 */
-	0xaa, /* 10101010 */
-	0x55, /* 01010101 */
-	0xaa, /* 10101010 */
-	0x55, /* 01010101 */
-	0xaa, /* 10101010 */
-	0x55, /* 01010101 */
-	0xaa, /* 10101010 */
-
-	/* 178 0xb2 '²' */
-	0x77, /* 01110111 */
-	0xdd, /* 11011101 */
-	0x77, /* 01110111 */
-	0xdd, /* 11011101 */
-	0x77, /* 01110111 */
-	0xdd, /* 11011101 */
-	0x77, /* 01110111 */
-	0xdd, /* 11011101 */
-
-	/* 179 0xb3 '³' */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-
-	/* 180 0xb4 '´' */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0xf8, /* 11111000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-
-	/* 181 0xb5 'µ' */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0xf8, /* 11111000 */
-	0x18, /* 00011000 */
-	0xf8, /* 11111000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-
-	/* 182 0xb6 '¶' */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0xf6, /* 11110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-
-	/* 183 0xb7 '·' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xfe, /* 11111110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-
-	/* 184 0xb8 '¸' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xf8, /* 11111000 */
-	0x18, /* 00011000 */
-	0xf8, /* 11111000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-
-	/* 185 0xb9 '¹' */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0xf6, /* 11110110 */
-	0x06, /* 00000110 */
-	0xf6, /* 11110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-
-	/* 186 0xba 'º' */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-
-	/* 187 0xbb '»' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xfe, /* 11111110 */
-	0x06, /* 00000110 */
-	0xf6, /* 11110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-
-	/* 188 0xbc '¼' */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0xf6, /* 11110110 */
-	0x06, /* 00000110 */
-	0xfe, /* 11111110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 189 0xbd '½' */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0xfe, /* 11111110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 190 0xbe '¾' */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0xf8, /* 11111000 */
-	0x18, /* 00011000 */
-	0xf8, /* 11111000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 191 0xbf '¿' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xf8, /* 11111000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-
-	/* 192 0xc0 'À' */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x1f, /* 00011111 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 193 0xc1 'Á' */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0xff, /* 11111111 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 194 0xc2 'Â' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xff, /* 11111111 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-
-	/* 195 0xc3 'Ã' */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x1f, /* 00011111 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-
-	/* 196 0xc4 'Ä' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xff, /* 11111111 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 197 0xc5 'Å' */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0xff, /* 11111111 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-
-	/* 198 0xc6 'Æ' */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x1f, /* 00011111 */
-	0x18, /* 00011000 */
-	0x1f, /* 00011111 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-
-	/* 199 0xc7 'Ç' */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x37, /* 00110111 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-
-	/* 200 0xc8 'È' */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x37, /* 00110111 */
-	0x30, /* 00110000 */
-	0x3f, /* 00111111 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 201 0xc9 'É' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x3f, /* 00111111 */
-	0x30, /* 00110000 */
-	0x37, /* 00110111 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-
-	/* 202 0xca 'Ê' */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0xf7, /* 11110111 */
-	0x00, /* 00000000 */
-	0xff, /* 11111111 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 203 0xcb 'Ë' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xff, /* 11111111 */
-	0x00, /* 00000000 */
-	0xf7, /* 11110111 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-
-	/* 204 0xcc 'Ì' */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x37, /* 00110111 */
-	0x30, /* 00110000 */
-	0x37, /* 00110111 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-
-	/* 205 0xcd 'Í' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xff, /* 11111111 */
-	0x00, /* 00000000 */
-	0xff, /* 11111111 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 206 0xce 'Î' */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0xf7, /* 11110111 */
-	0x00, /* 00000000 */
-	0xf7, /* 11110111 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-
-	/* 207 0xcf 'Ï' */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0xff, /* 11111111 */
-	0x00, /* 00000000 */
-	0xff, /* 11111111 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 208 0xd0 'Ð' */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0xff, /* 11111111 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 209 0xd1 'Ñ' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xff, /* 11111111 */
-	0x00, /* 00000000 */
-	0xff, /* 11111111 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-
-	/* 210 0xd2 'Ò' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xff, /* 11111111 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-
-	/* 211 0xd3 'Ó' */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x3f, /* 00111111 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 212 0xd4 'Ô' */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x1f, /* 00011111 */
-	0x18, /* 00011000 */
-	0x1f, /* 00011111 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 213 0xd5 'Õ' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x1f, /* 00011111 */
-	0x18, /* 00011000 */
-	0x1f, /* 00011111 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-
-	/* 214 0xd6 'Ö' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x3f, /* 00111111 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-
-	/* 215 0xd7 '×' */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0xff, /* 11111111 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-
-	/* 216 0xd8 'Ø' */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0xff, /* 11111111 */
-	0x18, /* 00011000 */
-	0xff, /* 11111111 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-
-	/* 217 0xd9 'Ù' */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0xf8, /* 11111000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 218 0xda 'Ú' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x1f, /* 00011111 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-
-	/* 219 0xdb 'Û' */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-
-	/* 220 0xdc 'Ü' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-
-	/* 221 0xdd 'Ý' */
-	0xf0, /* 11110000 */
-	0xf0, /* 11110000 */
-	0xf0, /* 11110000 */
-	0xf0, /* 11110000 */
-	0xf0, /* 11110000 */
-	0xf0, /* 11110000 */
-	0xf0, /* 11110000 */
-	0xf0, /* 11110000 */
-
-	/* 222 0xde 'Þ' */
-	0x0f, /* 00001111 */
-	0x0f, /* 00001111 */
-	0x0f, /* 00001111 */
-	0x0f, /* 00001111 */
-	0x0f, /* 00001111 */
-	0x0f, /* 00001111 */
-	0x0f, /* 00001111 */
-	0x0f, /* 00001111 */
-
-	/* 223 0xdf 'ß' */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 224 0xe0 'à' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x76, /* 01110110 */
-	0xdc, /* 11011100 */
-	0xc8, /* 11001000 */
-	0xdc, /* 11011100 */
-	0x76, /* 01110110 */
-	0x00, /* 00000000 */
-
-	/* 225 0xe1 'á' */
-	0x78, /* 01111000 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xd8, /* 11011000 */
-	0xcc, /* 11001100 */
-	0xc6, /* 11000110 */
-	0xcc, /* 11001100 */
-	0x00, /* 00000000 */
-
-	/* 226 0xe2 'â' */
-	0xfe, /* 11111110 */
-	0xc6, /* 11000110 */
-	0xc0, /* 11000000 */
-	0xc0, /* 11000000 */
-	0xc0, /* 11000000 */
-	0xc0, /* 11000000 */
-	0xc0, /* 11000000 */
-	0x00, /* 00000000 */
-
-	/* 227 0xe3 'ã' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xfe, /* 11111110 */
-	0x6c, /* 01101100 */
-	0x6c, /* 01101100 */
-	0x6c, /* 01101100 */
-	0x6c, /* 01101100 */
-	0x00, /* 00000000 */
-
-	/* 228 0xe4 'ä' */
-	0xfe, /* 11111110 */
-	0xc6, /* 11000110 */
-	0x60, /* 01100000 */
-	0x30, /* 00110000 */
-	0x60, /* 01100000 */
-	0xc6, /* 11000110 */
-	0xfe, /* 11111110 */
-	0x00, /* 00000000 */
-
-	/* 229 0xe5 'å' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x7e, /* 01111110 */
-	0xd8, /* 11011000 */
-	0xd8, /* 11011000 */
-	0xd8, /* 11011000 */
-	0x70, /* 01110000 */
-	0x00, /* 00000000 */
-
-	/* 230 0xe6 'æ' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x7c, /* 01111100 */
-	0xc0, /* 11000000 */
-
-	/* 231 0xe7 'ç' */
-	0x00, /* 00000000 */
-	0x76, /* 01110110 */
-	0xdc, /* 11011100 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-
-	/* 232 0xe8 'è' */
-	0x7e, /* 01111110 */
-	0x18, /* 00011000 */
-	0x3c, /* 00111100 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x3c, /* 00111100 */
-	0x18, /* 00011000 */
-	0x7e, /* 01111110 */
-
-	/* 233 0xe9 'é' */
-	0x38, /* 00111000 */
-	0x6c, /* 01101100 */
-	0xc6, /* 11000110 */
-	0xfe, /* 11111110 */
-	0xc6, /* 11000110 */
-	0x6c, /* 01101100 */
-	0x38, /* 00111000 */
-	0x00, /* 00000000 */
-
-	/* 234 0xea 'ê' */
-	0x38, /* 00111000 */
-	0x6c, /* 01101100 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x6c, /* 01101100 */
-	0x6c, /* 01101100 */
-	0xee, /* 11101110 */
-	0x00, /* 00000000 */
-
-	/* 235 0xeb 'ë' */
-	0x0e, /* 00001110 */
-	0x18, /* 00011000 */
-	0x0c, /* 00001100 */
-	0x3e, /* 00111110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x3c, /* 00111100 */
-	0x00, /* 00000000 */
-
-	/* 236 0xec 'ì' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x7e, /* 01111110 */
-	0xdb, /* 11011011 */
-	0xdb, /* 11011011 */
-	0x7e, /* 01111110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 237 0xed 'í' */
-	0x06, /* 00000110 */
-	0x0c, /* 00001100 */
-	0x7e, /* 01111110 */
-	0xdb, /* 11011011 */
-	0xdb, /* 11011011 */
-	0x7e, /* 01111110 */
-	0x60, /* 01100000 */
-	0xc0, /* 11000000 */
-
-	/* 238 0xee 'î' */
-	0x1e, /* 00011110 */
-	0x30, /* 00110000 */
-	0x60, /* 01100000 */
-	0x7e, /* 01111110 */
-	0x60, /* 01100000 */
-	0x30, /* 00110000 */
-	0x1e, /* 00011110 */
-	0x00, /* 00000000 */
-
-	/* 239 0xef 'ï' */
-	0x00, /* 00000000 */
-	0x7c, /* 01111100 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x00, /* 00000000 */
-
-	/* 240 0xf0 'ð' */
-	0x00, /* 00000000 */
-	0xfe, /* 11111110 */
-	0x00, /* 00000000 */
-	0xfe, /* 11111110 */
-	0x00, /* 00000000 */
-	0xfe, /* 11111110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 241 0xf1 'ñ' */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x7e, /* 01111110 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-	0x7e, /* 01111110 */
-	0x00, /* 00000000 */
-
-	/* 242 0xf2 'ò' */
-	0x30, /* 00110000 */
-	0x18, /* 00011000 */
-	0x0c, /* 00001100 */
-	0x18, /* 00011000 */
-	0x30, /* 00110000 */
-	0x00, /* 00000000 */
-	0x7e, /* 01111110 */
-	0x00, /* 00000000 */
-
-	/* 243 0xf3 'ó' */
-	0x0c, /* 00001100 */
-	0x18, /* 00011000 */
-	0x30, /* 00110000 */
-	0x18, /* 00011000 */
-	0x0c, /* 00001100 */
-	0x00, /* 00000000 */
-	0x7e, /* 01111110 */
-	0x00, /* 00000000 */
-
-	/* 244 0xf4 'ô' */
-	0x0e, /* 00001110 */
-	0x1b, /* 00011011 */
-	0x1b, /* 00011011 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-
-	/* 245 0xf5 'õ' */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0xd8, /* 11011000 */
-	0xd8, /* 11011000 */
-	0x70, /* 01110000 */
-
-	/* 246 0xf6 'ö' */
-	0x00, /* 00000000 */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-	0x7e, /* 01111110 */
-	0x00, /* 00000000 */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 247 0xf7 '÷' */
-	0x00, /* 00000000 */
-	0x76, /* 01110110 */
-	0xdc, /* 11011100 */
-	0x00, /* 00000000 */
-	0x76, /* 01110110 */
-	0xdc, /* 11011100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 248 0xf8 'ø' */
-	0x38, /* 00111000 */
-	0x6c, /* 01101100 */
-	0x6c, /* 01101100 */
-	0x38, /* 00111000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 249 0xf9 'ù' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 250 0xfa 'ú' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 251 0xfb 'û' */
-	0x0f, /* 00001111 */
-	0x0c, /* 00001100 */
-	0x0c, /* 00001100 */
-	0x0c, /* 00001100 */
-	0xec, /* 11101100 */
-	0x6c, /* 01101100 */
-	0x3c, /* 00111100 */
-	0x1c, /* 00011100 */
-
-	/* 252 0xfc 'ü' */
-	0x6c, /* 01101100 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 253 0xfd 'ý' */
-	0x78, /* 01111000 */
-	0x0c, /* 00001100 */
-	0x18, /* 00011000 */
-	0x30, /* 00110000 */
-	0x7c, /* 01111100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 254 0xfe 'þ' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x3c, /* 00111100 */
-	0x3c, /* 00111100 */
-	0x3c, /* 00111100 */
-	0x3c, /* 00111100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 255 0xff 'ÿ' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-};
-
diff -u --recursive --new-file v2.1.72/linux/arch/m68k/console/fonts.c linux/arch/m68k/console/fonts.c
--- v2.1.72/linux/arch/m68k/console/fonts.c	Wed Sep 25 00:47:39 1996
+++ linux/arch/m68k/console/fonts.c	Wed Dec 31 16:00:00 1969
@@ -1,108 +0,0 @@
-
-/*
- * arch/m68k/console/fonts.c -- `Soft' font definitions
- *
- *    Created 1995 by Geert Uytterhoeven
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file COPYING in the main directory of this archive
- * for more details.
- */
-
-
-#include <linux/types.h>
-#include <linux/string.h>
-#include <asm/setup.h>
-#include <asm/font.h>
-
-
-   /*
-    *    External Font Definitions
-    */
-
-/* VGA8x8 */
-extern char fontname_8x8[];
-extern int fontwidth_8x8, fontheight_8x8;
-extern u_char fontdata_8x8[];
-
-/* VGA8x16 */
-extern char fontname_8x16[];
-extern int fontwidth_8x16, fontheight_8x16;
-extern u_char fontdata_8x16[];
-
-/* PEARL8x8 */
-extern char fontname_pearl8x8[];
-extern int fontwidth_pearl8x8, fontheight_pearl8x8;
-extern u_char fontdata_pearl8x8[];
-
-
-   /*
-    *    Font Descriptor Array
-    */
-
-struct softfontdesc {
-   char *name;
-   int *width;
-   int *height;
-   u_char *data;
-};
-
-#define VGA8x8_IDX	0
-#define VGA8x16_IDX	1
-#define PEARL8x8_IDX	2
-
-static struct softfontdesc softfonts[] = {
-   { fontname_8x8, &fontwidth_8x8, &fontheight_8x8, fontdata_8x8 },
-   { fontname_8x16, &fontwidth_8x16, &fontheight_8x16, fontdata_8x16 },
-   { fontname_pearl8x8, &fontwidth_pearl8x8, &fontheight_pearl8x8,
-     fontdata_pearl8x8 },
-};
-
-static u_long numsoftfonts = sizeof(softfonts)/sizeof(*softfonts);
-
-
-   /*
-    *    Find a font with a specific name
-    */
-
-int findsoftfont(char *name, int *width, int *height, u_char *data[])
-{
-   int i;
-
-   for (i = 0; i < numsoftfonts; i++)
-      if (!strcmp(softfonts[i].name, name)) {
-         if (width)
-            *width = *softfonts[i].width;
-         if (height)
-            *height = *softfonts[i].height;
-         if (data)
-            *data = softfonts[i].data;
-			return(1);
-      }
-	return(0);
-}
-
-
-   /*
-    *    Get the default font for a specific screen size
-    */
-
-void getdefaultfont(int xres, int yres, char *name[], int *width, int *height,
-                    u_char *data[])
-{
-    int i;
-    
-    if (yres < 400)
-	i = MACH_IS_AMIGA ? PEARL8x8_IDX : VGA8x8_IDX;
-    else
-	i = VGA8x16_IDX;
-
-    if (name)
-	*name = softfonts[i].name;
-    if (width)
-	*width = *softfonts[i].width;
-    if (height)
-	*height = *softfonts[i].height;
-    if (data)
-	*data = softfonts[i].data;
-}
diff -u --recursive --new-file v2.1.72/linux/arch/m68k/console/pearl_8x8.c linux/arch/m68k/console/pearl_8x8.c
--- v2.1.72/linux/arch/m68k/console/pearl_8x8.c	Sun May 19 21:54:26 1996
+++ linux/arch/m68k/console/pearl_8x8.c	Wed Dec 31 16:00:00 1969
@@ -1,2582 +0,0 @@
-/**********************************************/
-/*                                            */
-/*       Font file generated by cpi2fnt       */
-/*       ------------------------------       */
-/*       Combined with the alpha-numeric      */
-/*       portion of Greg Harp's old PEARL     */
-/*       font (from earlier versions of       */
-/*       linux-m86k) by John Shifflett        */
-/*                                            */
-/**********************************************/
-
-#define FONTDATAMAX 2048
-
-char fontname_pearl8x8[] = "PEARL8x8";
-
-int  fontheight_pearl8x8 = 8;
-int  fontwidth_pearl8x8  = 8;
-
-unsigned char fontdata_pearl8x8[FONTDATAMAX] = {
-
-   /* 0 0x00 '^@' */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-
-   /* 1 0x01 '^A' */
-   0x7e, /* 01111110 */
-   0x81, /* 10000001 */
-   0xa5, /* 10100101 */
-   0x81, /* 10000001 */
-   0xbd, /* 10111101 */
-   0x99, /* 10011001 */
-   0x81, /* 10000001 */
-   0x7e, /* 01111110 */
-
-   /* 2 0x02 '^B' */
-   0x7e, /* 01111110 */
-   0xff, /* 11111111 */
-   0xdb, /* 11011011 */
-   0xff, /* 11111111 */
-   0xc3, /* 11000011 */
-   0xe7, /* 11100111 */
-   0xff, /* 11111111 */
-   0x7e, /* 01111110 */
-
-   /* 3 0x03 '^C' */
-   0x6c, /* 01101100 */
-   0xfe, /* 11111110 */
-   0xfe, /* 11111110 */
-   0xfe, /* 11111110 */
-   0x7c, /* 01111100 */
-   0x38, /* 00111000 */
-   0x10, /* 00010000 */
-   0x00, /* 00000000 */
-
-   /* 4 0x04 '^D' */
-   0x10, /* 00010000 */
-   0x38, /* 00111000 */
-   0x7c, /* 01111100 */
-   0xfe, /* 11111110 */
-   0x7c, /* 01111100 */
-   0x38, /* 00111000 */
-   0x10, /* 00010000 */
-   0x00, /* 00000000 */
-
-   /* 5 0x05 '^E' */
-   0x38, /* 00111000 */
-   0x7c, /* 01111100 */
-   0x38, /* 00111000 */
-   0xfe, /* 11111110 */
-   0xfe, /* 11111110 */
-   0xd6, /* 11010110 */
-   0x10, /* 00010000 */
-   0x38, /* 00111000 */
-
-   /* 6 0x06 '^F' */
-   0x10, /* 00010000 */
-   0x38, /* 00111000 */
-   0x7c, /* 01111100 */
-   0xfe, /* 11111110 */
-   0xfe, /* 11111110 */
-   0x7c, /* 01111100 */
-   0x10, /* 00010000 */
-   0x38, /* 00111000 */
-
-   /* 7 0x07 '^G' */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x18, /* 00011000 */
-   0x3c, /* 00111100 */
-   0x3c, /* 00111100 */
-   0x18, /* 00011000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-
-   /* 8 0x08 '^H' */
-   0xff, /* 11111111 */
-   0xff, /* 11111111 */
-   0xe7, /* 11100111 */
-   0xc3, /* 11000011 */
-   0xc3, /* 11000011 */
-   0xe7, /* 11100111 */
-   0xff, /* 11111111 */
-   0xff, /* 11111111 */
-
-   /* 9 0x09 '^I' */
-   0x00, /* 00000000 */
-   0x3c, /* 00111100 */
-   0x66, /* 01100110 */
-   0x42, /* 01000010 */
-   0x42, /* 01000010 */
-   0x66, /* 01100110 */
-   0x3c, /* 00111100 */
-   0x00, /* 00000000 */
-
-   /* 10 0x0a '^J' */
-   0xff, /* 11111111 */
-   0xc3, /* 11000011 */
-   0x99, /* 10011001 */
-   0xbd, /* 10111101 */
-   0xbd, /* 10111101 */
-   0x99, /* 10011001 */
-   0xc3, /* 11000011 */
-   0xff, /* 11111111 */
-
-   /* 11 0x0b '^K' */
-   0x0f, /* 00001111 */
-   0x07, /* 00000111 */
-   0x0f, /* 00001111 */
-   0x7d, /* 01111101 */
-   0xcc, /* 11001100 */
-   0xcc, /* 11001100 */
-   0xcc, /* 11001100 */
-   0x78, /* 01111000 */
-
-   /* 12 0x0c '^L' */
-   0x3c, /* 00111100 */
-   0x66, /* 01100110 */
-   0x66, /* 01100110 */
-   0x66, /* 01100110 */
-   0x3c, /* 00111100 */
-   0x18, /* 00011000 */
-   0x7e, /* 01111110 */
-   0x18, /* 00011000 */
-
-   /* 13 0x0d '^M' */
-   0x3f, /* 00111111 */
-   0x33, /* 00110011 */
-   0x3f, /* 00111111 */
-   0x30, /* 00110000 */
-   0x30, /* 00110000 */
-   0x70, /* 01110000 */
-   0xf0, /* 11110000 */
-   0xe0, /* 11100000 */
-
-   /* 14 0x0e '^N' */
-   0x7f, /* 01111111 */
-   0x63, /* 01100011 */
-   0x7f, /* 01111111 */
-   0x63, /* 01100011 */
-   0x63, /* 01100011 */
-   0x67, /* 01100111 */
-   0xe6, /* 11100110 */
-   0xc0, /* 11000000 */
-
-   /* 15 0x0f '^O' */
-   0x18, /* 00011000 */
-   0xdb, /* 11011011 */
-   0x3c, /* 00111100 */
-   0xe7, /* 11100111 */
-   0xe7, /* 11100111 */
-   0x3c, /* 00111100 */
-   0xdb, /* 11011011 */
-   0x18, /* 00011000 */
-
-   /* 16 0x10 '^P' */
-   0x80, /* 10000000 */
-   0xe0, /* 11100000 */
-   0xf8, /* 11111000 */
-   0xfe, /* 11111110 */
-   0xf8, /* 11111000 */
-   0xe0, /* 11100000 */
-   0x80, /* 10000000 */
-   0x00, /* 00000000 */
-
-   /* 17 0x11 '^Q' */
-   0x02, /* 00000010 */
-   0x0e, /* 00001110 */
-   0x3e, /* 00111110 */
-   0xfe, /* 11111110 */
-   0x3e, /* 00111110 */
-   0x0e, /* 00001110 */
-   0x02, /* 00000010 */
-   0x00, /* 00000000 */
-
-   /* 18 0x12 '^R' */
-   0x18, /* 00011000 */
-   0x3c, /* 00111100 */
-   0x7e, /* 01111110 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x7e, /* 01111110 */
-   0x3c, /* 00111100 */
-   0x18, /* 00011000 */
-
-   /* 19 0x13 '^S' */
-   0x66, /* 01100110 */
-   0x66, /* 01100110 */
-   0x66, /* 01100110 */
-   0x66, /* 01100110 */
-   0x66, /* 01100110 */
-   0x00, /* 00000000 */
-   0x66, /* 01100110 */
-   0x00, /* 00000000 */
-
-   /* 20 0x14 '^T' */
-   0x7f, /* 01111111 */
-   0xdb, /* 11011011 */
-   0xdb, /* 11011011 */
-   0x7b, /* 01111011 */
-   0x1b, /* 00011011 */
-   0x1b, /* 00011011 */
-   0x1b, /* 00011011 */
-   0x00, /* 00000000 */
-
-   /* 21 0x15 '^U' */
-   0x3e, /* 00111110 */
-   0x61, /* 01100001 */
-   0x3c, /* 00111100 */
-   0x66, /* 01100110 */
-   0x66, /* 01100110 */
-   0x3c, /* 00111100 */
-   0x86, /* 10000110 */
-   0x7c, /* 01111100 */
-
-   /* 22 0x16 '^V' */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x7e, /* 01111110 */
-   0x7e, /* 01111110 */
-   0x7e, /* 01111110 */
-   0x00, /* 00000000 */
-
-   /* 23 0x17 '^W' */
-   0x18, /* 00011000 */
-   0x3c, /* 00111100 */
-   0x7e, /* 01111110 */
-   0x18, /* 00011000 */
-   0x7e, /* 01111110 */
-   0x3c, /* 00111100 */
-   0x18, /* 00011000 */
-   0xff, /* 11111111 */
-
-   /* 24 0x18 '^X' */
-   0x18, /* 00011000 */
-   0x3c, /* 00111100 */
-   0x7e, /* 01111110 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x00, /* 00000000 */
-
-   /* 25 0x19 '^Y' */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x7e, /* 01111110 */
-   0x3c, /* 00111100 */
-   0x18, /* 00011000 */
-   0x00, /* 00000000 */
-
-   /* 26 0x1a '^Z' */
-   0x00, /* 00000000 */
-   0x18, /* 00011000 */
-   0x0c, /* 00001100 */
-   0xfe, /* 11111110 */
-   0x0c, /* 00001100 */
-   0x18, /* 00011000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-
-   /* 27 0x1b '^[' */
-   0x00, /* 00000000 */
-   0x30, /* 00110000 */
-   0x60, /* 01100000 */
-   0xfe, /* 11111110 */
-   0x60, /* 01100000 */
-   0x30, /* 00110000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-
-   /* 28 0x1c '^\' */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0xc0, /* 11000000 */
-   0xc0, /* 11000000 */
-   0xc0, /* 11000000 */
-   0xfe, /* 11111110 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-
-   /* 29 0x1d '^]' */
-   0x00, /* 00000000 */
-   0x24, /* 00100100 */
-   0x66, /* 01100110 */
-   0xff, /* 11111111 */
-   0x66, /* 01100110 */
-   0x24, /* 00100100 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-
-   /* 30 0x1e '^^' */
-   0x00, /* 00000000 */
-   0x18, /* 00011000 */
-   0x3c, /* 00111100 */
-   0x7e, /* 01111110 */
-   0xff, /* 11111111 */
-   0xff, /* 11111111 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-
-   /* 31 0x1f '^_' */
-   0x00, /* 00000000 */
-   0xff, /* 11111111 */
-   0xff, /* 11111111 */
-   0x7e, /* 01111110 */
-   0x3c, /* 00111100 */
-   0x18, /* 00011000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-
-   /* 32 0x20 ' ' */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-
-   /* 33 0x21 '!' */
-   0x18, /* 00011000 */
-   0x3c, /* 00111100 */
-   0x3c, /* 00111100 */
-   0x3c, /* 00111100 */
-   0x18, /* 00011000 */
-   0x00, /* 00000000 */
-   0x18, /* 00011000 */
-   0x00, /* 00000000 */
-
-   /* 34 0x22 '"' */
-   0x6c, /* 01101100 */
-   0x6c, /* 01101100 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-
-   /* 35 0x23 '#' */
-   0x6c, /* 01101100 */
-   0x6c, /* 01101100 */
-   0xfe, /* 11111110 */
-   0x6c, /* 01101100 */
-   0xfe, /* 11111110 */
-   0x6c, /* 01101100 */
-   0x6c, /* 01101100 */
-   0x00, /* 00000000 */
-
-   /* 36 0x24 '$' */
-   0x18, /* 00011000 */
-   0x3e, /* 00111110 */
-   0x60, /* 01100000 */
-   0x3c, /* 00111100 */
-   0x06, /* 00000110 */
-   0x7c, /* 01111100 */
-   0x18, /* 00011000 */
-   0x00, /* 00000000 */
-
-   /* 37 0x25 '%' */
-   0x00, /* 00000000 */
-   0xc6, /* 11000110 */
-   0xcc, /* 11001100 */
-   0x18, /* 00011000 */
-   0x30, /* 00110000 */
-   0x66, /* 01100110 */
-   0xc6, /* 11000110 */
-   0x00, /* 00000000 */
-
-   /* 38 0x26 '&' */
-   0x38, /* 00111000 */
-   0x6c, /* 01101100 */
-   0x68, /* 01101000 */
-   0x76, /* 01110110 */
-   0xdc, /* 11011100 */
-   0xcc, /* 11001100 */
-   0x76, /* 01110110 */
-   0x00, /* 00000000 */
-
-   /* 39 0x27 ''' */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x30, /* 00110000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-
-   /* 40 0x28 '(' */
-   0x0c, /* 00001100 */
-   0x18, /* 00011000 */
-   0x30, /* 00110000 */
-   0x30, /* 00110000 */
-   0x30, /* 00110000 */
-   0x18, /* 00011000 */
-   0x0c, /* 00001100 */
-   0x00, /* 00000000 */
-
-   /* 41 0x29 ')' */
-   0x30, /* 00110000 */
-   0x18, /* 00011000 */
-   0x0c, /* 00001100 */
-   0x0c, /* 00001100 */
-   0x0c, /* 00001100 */
-   0x18, /* 00011000 */
-   0x30, /* 00110000 */
-   0x00, /* 00000000 */
-
-   /* 42 0x2a '*' */
-   0x00, /* 00000000 */
-   0x66, /* 01100110 */
-   0x3c, /* 00111100 */
-   0xff, /* 11111111 */
-   0x3c, /* 00111100 */
-   0x66, /* 01100110 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-
-   /* 43 0x2b '+' */
-   0x00, /* 00000000 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x7e, /* 01111110 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-
-   /* 44 0x2c ',' */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x30, /* 00110000 */
-
-   /* 45 0x2d '-' */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x7e, /* 01111110 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-
-   /* 46 0x2e '.' */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x00, /* 00000000 */
-
-   /* 47 0x2f '/' */
-   0x03, /* 00000011 */
-   0x06, /* 00000110 */
-   0x0c, /* 00001100 */
-   0x18, /* 00011000 */
-   0x30, /* 00110000 */
-   0x60, /* 01100000 */
-   0xc0, /* 11000000 */
-   0x00, /* 00000000 */
-
-   /* 48 0x30 '0' */
-   0x7c, /* 01111100 */
-   0xc6, /* 11000110 */
-   0xde, /* 11011110 */
-   0xfe, /* 11111110 */
-   0xf6, /* 11110110 */
-   0xc6, /* 11000110 */
-   0x7c, /* 01111100 */
-   0x00, /* 00000000 */
-
-   /* 49 0x31 '1' */
-   0x18, /* 00011000 */
-   0x78, /* 01111000 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x00, /* 00000000 */
-
-   /* 50 0x32 '2' */
-   0x7c, /* 01111100 */
-   0xc6, /* 11000110 */
-   0x0c, /* 00001100 */
-   0x18, /* 00011000 */
-   0x30, /* 00110000 */
-   0x60, /* 01100000 */
-   0xfe, /* 11111110 */
-   0x00, /* 00000000 */
-
-   /* 51 0x33 '3' */
-   0x7c, /* 01111100 */
-   0xc6, /* 11000110 */
-   0x06, /* 00000110 */
-   0x1c, /* 00011100 */
-   0x06, /* 00000110 */
-   0xc6, /* 11000110 */
-   0x7c, /* 01111100 */
-   0x00, /* 00000000 */
-
-   /* 52 0x34 '4' */
-   0x1c, /* 00011100 */
-   0x3c, /* 00111100 */
-   0x6c, /* 01101100 */
-   0xcc, /* 11001100 */
-   0xfe, /* 11111110 */
-   0x0c, /* 00001100 */
-   0x0c, /* 00001100 */
-   0x00, /* 00000000 */
-
-   /* 53 0x35 '5' */
-   0xfe, /* 11111110 */
-   0xc0, /* 11000000 */
-   0xfc, /* 11111100 */
-   0x06, /* 00000110 */
-   0x06, /* 00000110 */
-   0xc6, /* 11000110 */
-   0x7c, /* 01111100 */
-   0x00, /* 00000000 */
-
-   /* 54 0x36 '6' */
-   0x38, /* 00111000 */
-   0x60, /* 01100000 */
-   0xc0, /* 11000000 */
-   0xfc, /* 11111100 */
-   0xc6, /* 11000110 */
-   0xc6, /* 11000110 */
-   0x7c, /* 01111100 */
-   0x00, /* 00000000 */
-
-   /* 55 0x37 '7' */
-   0xfe, /* 11111110 */
-   0x06, /* 00000110 */
-   0x0c, /* 00001100 */
-   0x18, /* 00011000 */
-   0x30, /* 00110000 */
-   0x60, /* 01100000 */
-   0x60, /* 01100000 */
-   0x00, /* 00000000 */
-
-   /* 56 0x38 '8' */
-   0x7c, /* 01111100 */
-   0xc6, /* 11000110 */
-   0xc6, /* 11000110 */
-   0x7c, /* 01111100 */
-   0xc6, /* 11000110 */
-   0xc6, /* 11000110 */
-   0x7c, /* 01111100 */
-   0x00, /* 00000000 */
-
-   /* 57 0x39 '9' */
-   0x7c, /* 01111100 */
-   0xc6, /* 11000110 */
-   0xc6, /* 11000110 */
-   0x7e, /* 01111110 */
-   0x06, /* 00000110 */
-   0x0c, /* 00001100 */
-   0x38, /* 00111000 */
-   0x00, /* 00000000 */
-
-   /* 58 0x3a ':' */
-   0x00, /* 00000000 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x00, /* 00000000 */
-
-   /* 59 0x3b ';' */
-   0x00, /* 00000000 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x30, /* 00110000 */
-
-   /* 60 0x3c '<' */
-   0x0c, /* 00001100 */
-   0x18, /* 00011000 */
-   0x30, /* 00110000 */
-   0x60, /* 01100000 */
-   0x30, /* 00110000 */
-   0x18, /* 00011000 */
-   0x0c, /* 00001100 */
-   0x00, /* 00000000 */
-
-   /* 61 0x3d '=' */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x7e, /* 01111110 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x7e, /* 01111110 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-
-   /* 62 0x3e '>' */
-   0x30, /* 00110000 */
-   0x18, /* 00011000 */
-   0x0c, /* 00001100 */
-   0x06, /* 00000110 */
-   0x0c, /* 00001100 */
-   0x18, /* 00011000 */
-   0x30, /* 00110000 */
-   0x00, /* 00000000 */
-
-   /* 63 0x3f '?' */
-   0x3c, /* 00111100 */
-   0x66, /* 01100110 */
-   0x06, /* 00000110 */
-   0x0c, /* 00001100 */
-   0x18, /* 00011000 */
-   0x00, /* 00000000 */
-   0x18, /* 00011000 */
-   0x00, /* 00000000 */
-
-   /* 64 0x40 '@' */
-   0x7c, /* 01111100 */
-   0xc6, /* 11000110 */
-   0xde, /* 11011110 */
-   0xde, /* 11011110 */
-   0xde, /* 11011110 */
-   0xc0, /* 11000000 */
-   0x7c, /* 01111100 */
-   0x00, /* 00000000 */
-
-   /* 65 0x41 'A' */
-   0x10, /* 00010000 */
-   0x38, /* 00111000 */
-   0x6c, /* 01101100 */
-   0xc6, /* 11000110 */
-   0xfe, /* 11111110 */
-   0xc6, /* 11000110 */
-   0xc6, /* 11000110 */
-   0x00, /* 00000000 */
-
-   /* 66 0x42 'B' */
-   0xfc, /* 11111100 */
-   0xc6, /* 11000110 */
-   0xc6, /* 11000110 */
-   0xfc, /* 11111100 */
-   0xc6, /* 11000110 */
-   0xc6, /* 11000110 */
-   0xfc, /* 11111100 */
-   0x00, /* 00000000 */
-
-   /* 67 0x43 'C' */
-   0x7c, /* 01111100 */
-   0xc6, /* 11000110 */
-   0xc0, /* 11000000 */
-   0xc0, /* 11000000 */
-   0xc0, /* 11000000 */
-   0xc6, /* 11000110 */
-   0x7c, /* 01111100 */
-   0x00, /* 00000000 */
-
-   /* 68 0x44 'D' */
-   0xfc, /* 11111100 */
-   0xc6, /* 11000110 */
-   0xc6, /* 11000110 */
-   0xc6, /* 11000110 */
-   0xc6, /* 11000110 */
-   0xc6, /* 11000110 */
-   0xfc, /* 11111100 */
-   0x00, /* 00000000 */
-
-   /* 69 0x45 'E' */
-   0xfe, /* 11111110 */
-   0xc0, /* 11000000 */
-   0xc0, /* 11000000 */
-   0xf8, /* 11111000 */
-   0xc0, /* 11000000 */
-   0xc0, /* 11000000 */
-   0xfe, /* 11111110 */
-   0x00, /* 00000000 */
-
-   /* 70 0x46 'F' */
-   0xfe, /* 11111110 */
-   0xc0, /* 11000000 */
-   0xc0, /* 11000000 */
-   0xf8, /* 11111000 */
-   0xc0, /* 11000000 */
-   0xc0, /* 11000000 */
-   0xc0, /* 11000000 */
-   0x00, /* 00000000 */
-
-   /* 71 0x47 'G' */
-   0x7c, /* 01111100 */
-   0xc6, /* 11000110 */
-   0xc0, /* 11000000 */
-   0xce, /* 11001110 */
-   0xc6, /* 11000110 */
-   0xc6, /* 11000110 */
-   0x7c, /* 01111100 */
-   0x00, /* 00000000 */
-
-   /* 72 0x48 'H' */
-   0xc6, /* 11000110 */
-   0xc6, /* 11000110 */
-   0xc6, /* 11000110 */
-   0xfe, /* 11111110 */
-   0xc6, /* 11000110 */
-   0xc6, /* 11000110 */
-   0xc6, /* 11000110 */
-   0x00, /* 00000000 */
-
-   /* 73 0x49 'I' */
-   0x7e, /* 01111110 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x7e, /* 01111110 */
-   0x00, /* 00000000 */
-
-   /* 74 0x4a 'J' */
-   0x06, /* 00000110 */
-   0x06, /* 00000110 */
-   0x06, /* 00000110 */
-   0x06, /* 00000110 */
-   0xc6, /* 11000110 */
-   0xc6, /* 11000110 */
-   0x7c, /* 01111100 */
-   0x00, /* 00000000 */
-
-   /* 75 0x4b 'K' */
-   0xc6, /* 11000110 */
-   0xcc, /* 11001100 */
-   0xd8, /* 11011000 */
-   0xf0, /* 11110000 */
-   0xd8, /* 11011000 */
-   0xcc, /* 11001100 */
-   0xc6, /* 11000110 */
-   0x00, /* 00000000 */
-
-   /* 76 0x4c 'L' */
-   0xc0, /* 11000000 */
-   0xc0, /* 11000000 */
-   0xc0, /* 11000000 */
-   0xc0, /* 11000000 */
-   0xc0, /* 11000000 */
-   0xc0, /* 11000000 */
-   0xfe, /* 11111110 */
-   0x00, /* 00000000 */
-
-   /* 77 0x4d 'M' */
-   0x82, /* 10000010 */
-   0xc6, /* 11000110 */
-   0xee, /* 11101110 */
-   0xfe, /* 11111110 */
-   0xd6, /* 11010110 */
-   0xc6, /* 11000110 */
-   0xc6, /* 11000110 */
-   0x00, /* 00000000 */
-
-   /* 78 0x4e 'N' */
-   0xc6, /* 11000110 */
-   0xe6, /* 11100110 */
-   0xf6, /* 11110110 */
-   0xde, /* 11011110 */
-   0xce, /* 11001110 */
-   0xc6, /* 11000110 */
-   0xc6, /* 11000110 */
-   0x00, /* 00000000 */
-
-   /* 79 0x4f 'O' */
-   0x7c, /* 01111100 */
-   0xc6, /* 11000110 */
-   0xc6, /* 11000110 */
-   0xc6, /* 11000110 */
-   0xc6, /* 11000110 */
-   0xc6, /* 11000110 */
-   0x7c, /* 01111100 */
-   0x00, /* 00000000 */
-
-   /* 80 0x50 'P' */
-   0xfc, /* 11111100 */
-   0xc6, /* 11000110 */
-   0xc6, /* 11000110 */
-   0xfc, /* 11111100 */
-   0xc0, /* 11000000 */
-   0xc0, /* 11000000 */
-   0xc0, /* 11000000 */
-   0x00, /* 00000000 */
-
-   /* 81 0x51 'Q' */
-   0x7c, /* 01111100 */
-   0xc6, /* 11000110 */
-   0xc6, /* 11000110 */
-   0xc6, /* 11000110 */
-   0xf6, /* 11110110 */
-   0xde, /* 11011110 */
-   0x7c, /* 01111100 */
-   0x06, /* 00000110 */
-
-   /* 82 0x52 'R' */
-   0xfc, /* 11111100 */
-   0xc6, /* 11000110 */
-   0xc6, /* 11000110 */
-   0xfc, /* 11111100 */
-   0xd8, /* 11011000 */
-   0xcc, /* 11001100 */
-   0xc6, /* 11000110 */
-   0x00, /* 00000000 */
-
-   /* 83 0x53 'S' */
-   0x7c, /* 01111100 */
-   0xc6, /* 11000110 */
-   0x60, /* 01100000 */
-   0x38, /* 00111000 */
-   0x0c, /* 00001100 */
-   0xc6, /* 11000110 */
-   0x7c, /* 01111100 */
-   0x00, /* 00000000 */
-
-   /* 84 0x54 'T' */
-   0x7e, /* 01111110 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x00, /* 00000000 */
-
-   /* 85 0x55 'U' */
-   0xc6, /* 11000110 */
-   0xc6, /* 11000110 */
-   0xc6, /* 11000110 */
-   0xc6, /* 11000110 */
-   0xc6, /* 11000110 */
-   0xc6, /* 11000110 */
-   0x7c, /* 01111100 */
-   0x00, /* 00000000 */
-
-   /* 86 0x56 'V' */
-   0xc3, /* 11000011 */
-   0xc3, /* 11000011 */
-   0x66, /* 01100110 */
-   0x66, /* 01100110 */
-   0x3c, /* 00111100 */
-   0x3c, /* 00111100 */
-   0x18, /* 00011000 */
-   0x00, /* 00000000 */
-
-   /* 87 0x57 'W' */
-   0xc6, /* 11000110 */
-   0xc6, /* 11000110 */
-   0xc6, /* 11000110 */
-   0xd6, /* 11010110 */
-   0xfe, /* 11111110 */
-   0xee, /* 11101110 */
-   0xc6, /* 11000110 */
-   0x00, /* 00000000 */
-
-   /* 88 0x58 'X' */
-   0xc3, /* 11000011 */
-   0x66, /* 01100110 */
-   0x3c, /* 00111100 */
-   0x18, /* 00011000 */
-   0x3c, /* 00111100 */
-   0x66, /* 01100110 */
-   0xc3, /* 11000011 */
-   0x00, /* 00000000 */
-
-   /* 89 0x59 'Y' */
-   0xc3, /* 11000011 */
-   0xc3, /* 11000011 */
-   0x66, /* 01100110 */
-   0x3c, /* 00111100 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x00, /* 00000000 */
-
-   /* 90 0x5a 'Z' */
-   0xfe, /* 11111110 */
-   0x06, /* 00000110 */
-   0x0c, /* 00001100 */
-   0x18, /* 00011000 */
-   0x30, /* 00110000 */
-   0x60, /* 01100000 */
-   0xfe, /* 11111110 */
-   0x00, /* 00000000 */
-
-   /* 91 0x5b '[' */
-   0x3c, /* 00111100 */
-   0x30, /* 00110000 */
-   0x30, /* 00110000 */
-   0x30, /* 00110000 */
-   0x30, /* 00110000 */
-   0x30, /* 00110000 */
-   0x3c, /* 00111100 */
-   0x00, /* 00000000 */
-
-   /* 92 0x5c '\' */
-   0xc0, /* 11000000 */
-   0x60, /* 01100000 */
-   0x30, /* 00110000 */
-   0x18, /* 00011000 */
-   0x0c, /* 00001100 */
-   0x06, /* 00000110 */
-   0x03, /* 00000011 */
-   0x00, /* 00000000 */
-
-   /* 93 0x5d ']' */
-   0x3c, /* 00111100 */
-   0x0c, /* 00001100 */
-   0x0c, /* 00001100 */
-   0x0c, /* 00001100 */
-   0x0c, /* 00001100 */
-   0x0c, /* 00001100 */
-   0x3c, /* 00111100 */
-   0x00, /* 00000000 */
-
-   /* 94 0x5e '^' */
-   0x10, /* 00010000 */
-   0x38, /* 00111000 */
-   0x6c, /* 01101100 */
-   0xc6, /* 11000110 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-
-   /* 95 0x5f '_' */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0xfe, /* 11111110 */
-
-   /* 96 0x60 '`' */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x0c, /* 00001100 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-
-   /* 97 0x61 'a' */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x7c, /* 01111100 */
-   0x06, /* 00000110 */
-   0x7e, /* 01111110 */
-   0xc6, /* 11000110 */
-   0x7e, /* 01111110 */
-   0x00, /* 00000000 */
-
-   /* 98 0x62 'b' */
-   0xc0, /* 11000000 */
-   0xc0, /* 11000000 */
-   0xfc, /* 11111100 */
-   0xc6, /* 11000110 */
-   0xc6, /* 11000110 */
-   0xc6, /* 11000110 */
-   0xfc, /* 11111100 */
-   0x00, /* 00000000 */
-
-   /* 99 0x63 'c' */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x7c, /* 01111100 */
-   0xc6, /* 11000110 */
-   0xc0, /* 11000000 */
-   0xc6, /* 11000110 */
-   0x7c, /* 01111100 */
-   0x00, /* 00000000 */
-
-   /* 100 0x64 'd' */
-   0x06, /* 00000110 */
-   0x06, /* 00000110 */
-   0x7e, /* 01111110 */
-   0xc6, /* 11000110 */
-   0xc6, /* 11000110 */
-   0xc6, /* 11000110 */
-   0x7e, /* 01111110 */
-   0x00, /* 00000000 */
-
-   /* 101 0x65 'e' */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x7c, /* 01111100 */
-   0xc6, /* 11000110 */
-   0xfe, /* 11111110 */
-   0xc0, /* 11000000 */
-   0x7c, /* 01111100 */
-   0x00, /* 00000000 */
-
-   /* 102 0x66 'f' */
-   0x3c, /* 00111100 */
-   0x66, /* 01100110 */
-   0x60, /* 01100000 */
-   0xf0, /* 11110000 */
-   0x60, /* 01100000 */
-   0x60, /* 01100000 */
-   0x60, /* 01100000 */
-   0x00, /* 00000000 */
-
-   /* 103 0x67 'g' */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x7e, /* 01111110 */
-   0xc6, /* 11000110 */
-   0xc6, /* 11000110 */
-   0x7e, /* 01111110 */
-   0x06, /* 00000110 */
-   0x7c, /* 01111100 */
-
-   /* 104 0x68 'h' */
-   0xc0, /* 11000000 */
-   0xc0, /* 11000000 */
-   0xfc, /* 11111100 */
-   0xc6, /* 11000110 */
-   0xc6, /* 11000110 */
-   0xc6, /* 11000110 */
-   0xc6, /* 11000110 */
-   0x00, /* 00000000 */
-
-   /* 105 0x69 'i' */
-   0x18, /* 00011000 */
-   0x00, /* 00000000 */
-   0x38, /* 00111000 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x00, /* 00000000 */
-
-   /* 106 0x6a 'j' */
-   0x06, /* 00000110 */
-   0x00, /* 00000000 */
-   0x06, /* 00000110 */
-   0x06, /* 00000110 */
-   0x06, /* 00000110 */
-   0x06, /* 00000110 */
-   0xc6, /* 11000110 */
-   0x7c, /* 01111100 */
-
-   /* 107 0x6b 'k' */
-   0xc0, /* 11000000 */
-   0xc0, /* 11000000 */
-   0xcc, /* 11001100 */
-   0xd8, /* 11011000 */
-   0xf0, /* 11110000 */
-   0xd8, /* 11011000 */
-   0xcc, /* 11001100 */
-   0x00, /* 00000000 */
-
-   /* 108 0x6c 'l' */
-   0x38, /* 00111000 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x00, /* 00000000 */
-
-   /* 109 0x6d 'm' */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0xec, /* 11101100 */
-   0xfe, /* 11111110 */
-   0xd6, /* 11010110 */
-   0xc6, /* 11000110 */
-   0xc6, /* 11000110 */
-   0x00, /* 00000000 */
-
-   /* 110 0x6e 'n' */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0xfc, /* 11111100 */
-   0xc6, /* 11000110 */
-   0xc6, /* 11000110 */
-   0xc6, /* 11000110 */
-   0xc6, /* 11000110 */
-   0x00, /* 00000000 */
-
-   /* 111 0x6f 'o' */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x7c, /* 01111100 */
-   0xc6, /* 11000110 */
-   0xc6, /* 11000110 */
-   0xc6, /* 11000110 */
-   0x7c, /* 01111100 */
-   0x00, /* 00000000 */
-
-   /* 112 0x70 'p' */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0xfc, /* 11111100 */
-   0xc6, /* 11000110 */
-   0xc6, /* 11000110 */
-   0xfc, /* 11111100 */
-   0xc0, /* 11000000 */
-   0xc0, /* 11000000 */
-
-   /* 113 0x71 'q' */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x7e, /* 01111110 */
-   0xc6, /* 11000110 */
-   0xc6, /* 11000110 */
-   0x7e, /* 01111110 */
-   0x06, /* 00000110 */
-   0x06, /* 00000110 */
-
-   /* 114 0x72 'r' */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0xdc, /* 11011100 */
-   0xe6, /* 11100110 */
-   0xc0, /* 11000000 */
-   0xc0, /* 11000000 */
-   0xc0, /* 11000000 */
-   0x00, /* 00000000 */
-
-   /* 115 0x73 's' */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x7e, /* 01111110 */
-   0xc0, /* 11000000 */
-   0x7c, /* 01111100 */
-   0x06, /* 00000110 */
-   0xfc, /* 11111100 */
-   0x00, /* 00000000 */
-
-   /* 116 0x74 't' */
-   0x30, /* 00110000 */
-   0x30, /* 00110000 */
-   0x7c, /* 01111100 */
-   0x30, /* 00110000 */
-   0x30, /* 00110000 */
-   0x36, /* 00110110 */
-   0x1c, /* 00011100 */
-   0x00, /* 00000000 */
-
-   /* 117 0x75 'u' */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0xc6, /* 11000110 */
-   0xc6, /* 11000110 */
-   0xc6, /* 11000110 */
-   0xc6, /* 11000110 */
-   0x7c, /* 01111100 */
-   0x00, /* 00000000 */
-
-   /* 118 0x76 'v' */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0xc6, /* 11000110 */
-   0xc6, /* 11000110 */
-   0xc6, /* 11000110 */
-   0x6c, /* 01101100 */
-   0x38, /* 00111000 */
-   0x00, /* 00000000 */
-
-   /* 119 0x77 'w' */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0xc6, /* 11000110 */
-   0xc6, /* 11000110 */
-   0xd6, /* 11010110 */
-   0xfe, /* 11111110 */
-   0x6c, /* 01101100 */
-   0x00, /* 00000000 */
-
-   /* 120 0x78 'x' */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0xc6, /* 11000110 */
-   0x6c, /* 01101100 */
-   0x38, /* 00111000 */
-   0x6c, /* 01101100 */
-   0xc6, /* 11000110 */
-   0x00, /* 00000000 */
-
-   /* 121 0x79 'y' */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0xc3, /* 11000011 */
-   0x66, /* 01100110 */
-   0x3c, /* 00111100 */
-   0x18, /* 00011000 */
-   0x30, /* 00110000 */
-   0x60, /* 01100000 */
-
-   /* 122 0x7a 'z' */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0xfe, /* 11111110 */
-   0x0c, /* 00001100 */
-   0x38, /* 00111000 */
-   0x60, /* 01100000 */
-   0xfe, /* 11111110 */
-   0x00, /* 00000000 */
-
-   /* 123 0x7b '{' */
-   0x0e, /* 00001110 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x70, /* 01110000 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x0e, /* 00001110 */
-   0x00, /* 00000000 */
-
-   /* 124 0x7c '|' */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x00, /* 00000000 */
-
-   /* 125 0x7d '}' */
-   0x70, /* 01110000 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x0e, /* 00001110 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x70, /* 01110000 */
-   0x00, /* 00000000 */
-
-   /* 126 0x7e '~' */
-   0x72, /* 01110010 */
-   0x9c, /* 10011100 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-
-   /* 127 0x7f '' */
-   0x00, /* 00000000 */
-   0x10, /* 00010000 */
-   0x38, /* 00111000 */
-   0x6c, /* 01101100 */
-   0xc6, /* 11000110 */
-   0xc6, /* 11000110 */
-   0xfe, /* 11111110 */
-   0x00, /* 00000000 */
-
-   /* 128 0x80 '€' */
-   0x7c, /* 01111100 */
-   0xc6, /* 11000110 */
-   0xc0, /* 11000000 */
-   0xc0, /* 11000000 */
-   0xc6, /* 11000110 */
-   0x7c, /* 01111100 */
-   0x0c, /* 00001100 */
-   0x78, /* 01111000 */
-
-   /* 129 0x81 '�' */
-   0xcc, /* 11001100 */
-   0x00, /* 00000000 */
-   0xcc, /* 11001100 */
-   0xcc, /* 11001100 */
-   0xcc, /* 11001100 */
-   0xcc, /* 11001100 */
-   0x76, /* 01110110 */
-   0x00, /* 00000000 */
-
-   /* 130 0x82 '‚' */
-   0x0c, /* 00001100 */
-   0x18, /* 00011000 */
-   0x7c, /* 01111100 */
-   0xc6, /* 11000110 */
-   0xfe, /* 11111110 */
-   0xc0, /* 11000000 */
-   0x7c, /* 01111100 */
-   0x00, /* 00000000 */
-
-   /* 131 0x83 'ƒ' */
-   0x7c, /* 01111100 */
-   0x82, /* 10000010 */
-   0x78, /* 01111000 */
-   0x0c, /* 00001100 */
-   0x7c, /* 01111100 */
-   0xcc, /* 11001100 */
-   0x76, /* 01110110 */
-   0x00, /* 00000000 */
-
-   /* 132 0x84 '„' */
-   0xc6, /* 11000110 */
-   0x00, /* 00000000 */
-   0x78, /* 01111000 */
-   0x0c, /* 00001100 */
-   0x7c, /* 01111100 */
-   0xcc, /* 11001100 */
-   0x76, /* 01110110 */
-   0x00, /* 00000000 */
-
-   /* 133 0x85 '…' */
-   0x30, /* 00110000 */
-   0x18, /* 00011000 */
-   0x78, /* 01111000 */
-   0x0c, /* 00001100 */
-   0x7c, /* 01111100 */
-   0xcc, /* 11001100 */
-   0x76, /* 01110110 */
-   0x00, /* 00000000 */
-
-   /* 134 0x86 '†' */
-   0x30, /* 00110000 */
-   0x30, /* 00110000 */
-   0x78, /* 01111000 */
-   0x0c, /* 00001100 */
-   0x7c, /* 01111100 */
-   0xcc, /* 11001100 */
-   0x76, /* 01110110 */
-   0x00, /* 00000000 */
-
-   /* 135 0x87 '‡' */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x7e, /* 01111110 */
-   0xc0, /* 11000000 */
-   0xc0, /* 11000000 */
-   0x7e, /* 01111110 */
-   0x0c, /* 00001100 */
-   0x38, /* 00111000 */
-
-   /* 136 0x88 'ˆ' */
-   0x7c, /* 01111100 */
-   0x82, /* 10000010 */
-   0x7c, /* 01111100 */
-   0xc6, /* 11000110 */
-   0xfe, /* 11111110 */
-   0xc0, /* 11000000 */
-   0x7c, /* 01111100 */
-   0x00, /* 00000000 */
-
-   /* 137 0x89 '‰' */
-   0xc6, /* 11000110 */
-   0x00, /* 00000000 */
-   0x7c, /* 01111100 */
-   0xc6, /* 11000110 */
-   0xfe, /* 11111110 */
-   0xc0, /* 11000000 */
-   0x7c, /* 01111100 */
-   0x00, /* 00000000 */
-
-   /* 138 0x8a 'Š' */
-   0x30, /* 00110000 */
-   0x18, /* 00011000 */
-   0x7c, /* 01111100 */
-   0xc6, /* 11000110 */
-   0xfe, /* 11111110 */
-   0xc0, /* 11000000 */
-   0x7c, /* 01111100 */
-   0x00, /* 00000000 */
-
-   /* 139 0x8b '‹' */
-   0x66, /* 01100110 */
-   0x00, /* 00000000 */
-   0x38, /* 00111000 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x3c, /* 00111100 */
-   0x00, /* 00000000 */
-
-   /* 140 0x8c 'Œ' */
-   0x7c, /* 01111100 */
-   0x82, /* 10000010 */
-   0x38, /* 00111000 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x3c, /* 00111100 */
-   0x00, /* 00000000 */
-
-   /* 141 0x8d '�' */
-   0x30, /* 00110000 */
-   0x18, /* 00011000 */
-   0x00, /* 00000000 */
-   0x38, /* 00111000 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x3c, /* 00111100 */
-   0x00, /* 00000000 */
-
-   /* 142 0x8e 'Ž' */
-   0xc6, /* 11000110 */
-   0x38, /* 00111000 */
-   0x6c, /* 01101100 */
-   0xc6, /* 11000110 */
-   0xfe, /* 11111110 */
-   0xc6, /* 11000110 */
-   0xc6, /* 11000110 */
-   0x00, /* 00000000 */
-
-   /* 143 0x8f '�' */
-   0x38, /* 00111000 */
-   0x6c, /* 01101100 */
-   0x7c, /* 01111100 */
-   0xc6, /* 11000110 */
-   0xfe, /* 11111110 */
-   0xc6, /* 11000110 */
-   0xc6, /* 11000110 */
-   0x00, /* 00000000 */
-
-   /* 144 0x90 '�' */
-   0x18, /* 00011000 */
-   0x30, /* 00110000 */
-   0xfe, /* 11111110 */
-   0xc0, /* 11000000 */
-   0xf8, /* 11111000 */
-   0xc0, /* 11000000 */
-   0xfe, /* 11111110 */
-   0x00, /* 00000000 */
-
-   /* 145 0x91 '‘' */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x7e, /* 01111110 */
-   0x18, /* 00011000 */
-   0x7e, /* 01111110 */
-   0xd8, /* 11011000 */
-   0x7e, /* 01111110 */
-   0x00, /* 00000000 */
-
-   /* 146 0x92 '’' */
-   0x3e, /* 00111110 */
-   0x6c, /* 01101100 */
-   0xcc, /* 11001100 */
-   0xfe, /* 11111110 */
-   0xcc, /* 11001100 */
-   0xcc, /* 11001100 */
-   0xce, /* 11001110 */
-   0x00, /* 00000000 */
-
-   /* 147 0x93 '“' */
-   0x7c, /* 01111100 */
-   0x82, /* 10000010 */
-   0x7c, /* 01111100 */
-   0xc6, /* 11000110 */
-   0xc6, /* 11000110 */
-   0xc6, /* 11000110 */
-   0x7c, /* 01111100 */
-   0x00, /* 00000000 */
-
-   /* 148 0x94 '”' */
-   0xc6, /* 11000110 */
-   0x00, /* 00000000 */
-   0x7c, /* 01111100 */
-   0xc6, /* 11000110 */
-   0xc6, /* 11000110 */
-   0xc6, /* 11000110 */
-   0x7c, /* 01111100 */
-   0x00, /* 00000000 */
-
-   /* 149 0x95 '•' */
-   0x30, /* 00110000 */
-   0x18, /* 00011000 */
-   0x7c, /* 01111100 */
-   0xc6, /* 11000110 */
-   0xc6, /* 11000110 */
-   0xc6, /* 11000110 */
-   0x7c, /* 01111100 */
-   0x00, /* 00000000 */
-
-   /* 150 0x96 '–' */
-   0x78, /* 01111000 */
-   0x84, /* 10000100 */
-   0x00, /* 00000000 */
-   0xcc, /* 11001100 */
-   0xcc, /* 11001100 */
-   0xcc, /* 11001100 */
-   0x76, /* 01110110 */
-   0x00, /* 00000000 */
-
-   /* 151 0x97 '—' */
-   0x60, /* 01100000 */
-   0x30, /* 00110000 */
-   0xcc, /* 11001100 */
-   0xcc, /* 11001100 */
-   0xcc, /* 11001100 */
-   0xcc, /* 11001100 */
-   0x76, /* 01110110 */
-   0x00, /* 00000000 */
-
-   /* 152 0x98 '˜' */
-   0xc6, /* 11000110 */
-   0x00, /* 00000000 */
-   0xc6, /* 11000110 */
-   0xc6, /* 11000110 */
-   0xc6, /* 11000110 */
-   0x7e, /* 01111110 */
-   0x06, /* 00000110 */
-   0xfc, /* 11111100 */
-
-   /* 153 0x99 '™' */
-   0xc6, /* 11000110 */
-   0x38, /* 00111000 */
-   0x6c, /* 01101100 */
-   0xc6, /* 11000110 */
-   0xc6, /* 11000110 */
-   0x6c, /* 01101100 */
-   0x38, /* 00111000 */
-   0x00, /* 00000000 */
-
-   /* 154 0x9a 'š' */
-   0xc6, /* 11000110 */
-   0x00, /* 00000000 */
-   0xc6, /* 11000110 */
-   0xc6, /* 11000110 */
-   0xc6, /* 11000110 */
-   0xc6, /* 11000110 */
-   0x7c, /* 01111100 */
-   0x00, /* 00000000 */
-
-   /* 155 0x9b '›' */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x7e, /* 01111110 */
-   0xc0, /* 11000000 */
-   0xc0, /* 11000000 */
-   0x7e, /* 01111110 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-
-   /* 156 0x9c 'œ' */
-   0x38, /* 00111000 */
-   0x6c, /* 01101100 */
-   0x64, /* 01100100 */
-   0xf0, /* 11110000 */
-   0x60, /* 01100000 */
-   0x66, /* 01100110 */
-   0xfc, /* 11111100 */
-   0x00, /* 00000000 */
-
-   /* 157 0x9d '�' */
-   0x66, /* 01100110 */
-   0x66, /* 01100110 */
-   0x3c, /* 00111100 */
-   0x7e, /* 01111110 */
-   0x18, /* 00011000 */
-   0x7e, /* 01111110 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-
-   /* 158 0x9e 'ž' */
-   0xf8, /* 11111000 */
-   0xcc, /* 11001100 */
-   0xcc, /* 11001100 */
-   0xfa, /* 11111010 */
-   0xc6, /* 11000110 */
-   0xcf, /* 11001111 */
-   0xc6, /* 11000110 */
-   0xc7, /* 11000111 */
-
-   /* 159 0x9f 'Ÿ' */
-   0x0e, /* 00001110 */
-   0x1b, /* 00011011 */
-   0x18, /* 00011000 */
-   0x3c, /* 00111100 */
-   0x18, /* 00011000 */
-   0xd8, /* 11011000 */
-   0x70, /* 01110000 */
-   0x00, /* 00000000 */
-
-   /* 160 0xa0 ' ' */
-   0x18, /* 00011000 */
-   0x30, /* 00110000 */
-   0x78, /* 01111000 */
-   0x0c, /* 00001100 */
-   0x7c, /* 01111100 */
-   0xcc, /* 11001100 */
-   0x76, /* 01110110 */
-   0x00, /* 00000000 */
-
-   /* 161 0xa1 '¡' */
-   0x0c, /* 00001100 */
-   0x18, /* 00011000 */
-   0x00, /* 00000000 */
-   0x38, /* 00111000 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x3c, /* 00111100 */
-   0x00, /* 00000000 */
-
-   /* 162 0xa2 '¢' */
-   0x0c, /* 00001100 */
-   0x18, /* 00011000 */
-   0x7c, /* 01111100 */
-   0xc6, /* 11000110 */
-   0xc6, /* 11000110 */
-   0xc6, /* 11000110 */
-   0x7c, /* 01111100 */
-   0x00, /* 00000000 */
-
-   /* 163 0xa3 '£' */
-   0x18, /* 00011000 */
-   0x30, /* 00110000 */
-   0xcc, /* 11001100 */
-   0xcc, /* 11001100 */
-   0xcc, /* 11001100 */
-   0xcc, /* 11001100 */
-   0x76, /* 01110110 */
-   0x00, /* 00000000 */
-
-   /* 164 0xa4 '¤' */
-   0x76, /* 01110110 */
-   0xdc, /* 11011100 */
-   0x00, /* 00000000 */
-   0xdc, /* 11011100 */
-   0x66, /* 01100110 */
-   0x66, /* 01100110 */
-   0x66, /* 01100110 */
-   0x00, /* 00000000 */
-
-   /* 165 0xa5 '¥' */
-   0x76, /* 01110110 */
-   0xdc, /* 11011100 */
-   0x00, /* 00000000 */
-   0xe6, /* 11100110 */
-   0xf6, /* 11110110 */
-   0xde, /* 11011110 */
-   0xce, /* 11001110 */
-   0x00, /* 00000000 */
-
-   /* 166 0xa6 '¦' */
-   0x3c, /* 00111100 */
-   0x6c, /* 01101100 */
-   0x6c, /* 01101100 */
-   0x3e, /* 00111110 */
-   0x00, /* 00000000 */
-   0x7e, /* 01111110 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-
-   /* 167 0xa7 '§' */
-   0x38, /* 00111000 */
-   0x6c, /* 01101100 */
-   0x6c, /* 01101100 */
-   0x38, /* 00111000 */
-   0x00, /* 00000000 */
-   0x7c, /* 01111100 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-
-   /* 168 0xa8 '¨' */
-   0x18, /* 00011000 */
-   0x00, /* 00000000 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x30, /* 00110000 */
-   0x63, /* 01100011 */
-   0x3e, /* 00111110 */
-   0x00, /* 00000000 */
-
-   /* 169 0xa9 '©' */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0xfe, /* 11111110 */
-   0xc0, /* 11000000 */
-   0xc0, /* 11000000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-
-   /* 170 0xaa 'ª' */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0xfe, /* 11111110 */
-   0x06, /* 00000110 */
-   0x06, /* 00000110 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-
-   /* 171 0xab '«' */
-   0x63, /* 01100011 */
-   0xe6, /* 11100110 */
-   0x6c, /* 01101100 */
-   0x7e, /* 01111110 */
-   0x33, /* 00110011 */
-   0x66, /* 01100110 */
-   0xcc, /* 11001100 */
-   0x0f, /* 00001111 */
-
-   /* 172 0xac '¬' */
-   0x63, /* 01100011 */
-   0xe6, /* 11100110 */
-   0x6c, /* 01101100 */
-   0x7a, /* 01111010 */
-   0x36, /* 00110110 */
-   0x6a, /* 01101010 */
-   0xdf, /* 11011111 */
-   0x06, /* 00000110 */
-
-   /* 173 0xad '­' */
-   0x18, /* 00011000 */
-   0x00, /* 00000000 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x3c, /* 00111100 */
-   0x3c, /* 00111100 */
-   0x18, /* 00011000 */
-   0x00, /* 00000000 */
-
-   /* 174 0xae '®' */
-   0x00, /* 00000000 */
-   0x33, /* 00110011 */
-   0x66, /* 01100110 */
-   0xcc, /* 11001100 */
-   0x66, /* 01100110 */
-   0x33, /* 00110011 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-
-   /* 175 0xaf '¯' */
-   0x00, /* 00000000 */
-   0xcc, /* 11001100 */
-   0x66, /* 01100110 */
-   0x33, /* 00110011 */
-   0x66, /* 01100110 */
-   0xcc, /* 11001100 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-
-   /* 176 0xb0 '°' */
-   0x22, /* 00100010 */
-   0x88, /* 10001000 */
-   0x22, /* 00100010 */
-   0x88, /* 10001000 */
-   0x22, /* 00100010 */
-   0x88, /* 10001000 */
-   0x22, /* 00100010 */
-   0x88, /* 10001000 */
-
-   /* 177 0xb1 '±' */
-   0x55, /* 01010101 */
-   0xaa, /* 10101010 */
-   0x55, /* 01010101 */
-   0xaa, /* 10101010 */
-   0x55, /* 01010101 */
-   0xaa, /* 10101010 */
-   0x55, /* 01010101 */
-   0xaa, /* 10101010 */
-
-   /* 178 0xb2 '²' */
-   0x77, /* 01110111 */
-   0xdd, /* 11011101 */
-   0x77, /* 01110111 */
-   0xdd, /* 11011101 */
-   0x77, /* 01110111 */
-   0xdd, /* 11011101 */
-   0x77, /* 01110111 */
-   0xdd, /* 11011101 */
-
-   /* 179 0xb3 '³' */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-
-   /* 180 0xb4 '´' */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0xf8, /* 11111000 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-
-   /* 181 0xb5 'µ' */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0xf8, /* 11111000 */
-   0x18, /* 00011000 */
-   0xf8, /* 11111000 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-
-   /* 182 0xb6 '¶' */
-   0x36, /* 00110110 */
-   0x36, /* 00110110 */
-   0x36, /* 00110110 */
-   0x36, /* 00110110 */
-   0xf6, /* 11110110 */
-   0x36, /* 00110110 */
-   0x36, /* 00110110 */
-   0x36, /* 00110110 */
-
-   /* 183 0xb7 '·' */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0xfe, /* 11111110 */
-   0x36, /* 00110110 */
-   0x36, /* 00110110 */
-   0x36, /* 00110110 */
-
-   /* 184 0xb8 '¸' */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0xf8, /* 11111000 */
-   0x18, /* 00011000 */
-   0xf8, /* 11111000 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-
-   /* 185 0xb9 '¹' */
-   0x36, /* 00110110 */
-   0x36, /* 00110110 */
-   0xf6, /* 11110110 */
-   0x06, /* 00000110 */
-   0xf6, /* 11110110 */
-   0x36, /* 00110110 */
-   0x36, /* 00110110 */
-   0x36, /* 00110110 */
-
-   /* 186 0xba 'º' */
-   0x36, /* 00110110 */
-   0x36, /* 00110110 */
-   0x36, /* 00110110 */
-   0x36, /* 00110110 */
-   0x36, /* 00110110 */
-   0x36, /* 00110110 */
-   0x36, /* 00110110 */
-   0x36, /* 00110110 */
-
-   /* 187 0xbb '»' */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0xfe, /* 11111110 */
-   0x06, /* 00000110 */
-   0xf6, /* 11110110 */
-   0x36, /* 00110110 */
-   0x36, /* 00110110 */
-   0x36, /* 00110110 */
-
-   /* 188 0xbc '¼' */
-   0x36, /* 00110110 */
-   0x36, /* 00110110 */
-   0xf6, /* 11110110 */
-   0x06, /* 00000110 */
-   0xfe, /* 11111110 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-
-   /* 189 0xbd '½' */
-   0x36, /* 00110110 */
-   0x36, /* 00110110 */
-   0x36, /* 00110110 */
-   0x36, /* 00110110 */
-   0xfe, /* 11111110 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-
-   /* 190 0xbe '¾' */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0xf8, /* 11111000 */
-   0x18, /* 00011000 */
-   0xf8, /* 11111000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-
-   /* 191 0xbf '¿' */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0xf8, /* 11111000 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-
-   /* 192 0xc0 'À' */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x1f, /* 00011111 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-
-   /* 193 0xc1 'Á' */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0xff, /* 11111111 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-
-   /* 194 0xc2 'Â' */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0xff, /* 11111111 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-
-   /* 195 0xc3 'Ã' */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x1f, /* 00011111 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-
-   /* 196 0xc4 'Ä' */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0xff, /* 11111111 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-
-   /* 197 0xc5 'Å' */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0xff, /* 11111111 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-
-   /* 198 0xc6 'Æ' */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x1f, /* 00011111 */
-   0x18, /* 00011000 */
-   0x1f, /* 00011111 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-
-   /* 199 0xc7 'Ç' */
-   0x36, /* 00110110 */
-   0x36, /* 00110110 */
-   0x36, /* 00110110 */
-   0x36, /* 00110110 */
-   0x37, /* 00110111 */
-   0x36, /* 00110110 */
-   0x36, /* 00110110 */
-   0x36, /* 00110110 */
-
-   /* 200 0xc8 'È' */
-   0x36, /* 00110110 */
-   0x36, /* 00110110 */
-   0x37, /* 00110111 */
-   0x30, /* 00110000 */
-   0x3f, /* 00111111 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-
-   /* 201 0xc9 'É' */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x3f, /* 00111111 */
-   0x30, /* 00110000 */
-   0x37, /* 00110111 */
-   0x36, /* 00110110 */
-   0x36, /* 00110110 */
-   0x36, /* 00110110 */
-
-   /* 202 0xca 'Ê' */
-   0x36, /* 00110110 */
-   0x36, /* 00110110 */
-   0xf7, /* 11110111 */
-   0x00, /* 00000000 */
-   0xff, /* 11111111 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-
-   /* 203 0xcb 'Ë' */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0xff, /* 11111111 */
-   0x00, /* 00000000 */
-   0xf7, /* 11110111 */
-   0x36, /* 00110110 */
-   0x36, /* 00110110 */
-   0x36, /* 00110110 */
-
-   /* 204 0xcc 'Ì' */
-   0x36, /* 00110110 */
-   0x36, /* 00110110 */
-   0x37, /* 00110111 */
-   0x30, /* 00110000 */
-   0x37, /* 00110111 */
-   0x36, /* 00110110 */
-   0x36, /* 00110110 */
-   0x36, /* 00110110 */
-
-   /* 205 0xcd 'Í' */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0xff, /* 11111111 */
-   0x00, /* 00000000 */
-   0xff, /* 11111111 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-
-   /* 206 0xce 'Î' */
-   0x36, /* 00110110 */
-   0x36, /* 00110110 */
-   0xf7, /* 11110111 */
-   0x00, /* 00000000 */
-   0xf7, /* 11110111 */
-   0x36, /* 00110110 */
-   0x36, /* 00110110 */
-   0x36, /* 00110110 */
-
-   /* 207 0xcf 'Ï' */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0xff, /* 11111111 */
-   0x00, /* 00000000 */
-   0xff, /* 11111111 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-
-   /* 208 0xd0 'Ð' */
-   0x36, /* 00110110 */
-   0x36, /* 00110110 */
-   0x36, /* 00110110 */
-   0x36, /* 00110110 */
-   0xff, /* 11111111 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-
-   /* 209 0xd1 'Ñ' */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0xff, /* 11111111 */
-   0x00, /* 00000000 */
-   0xff, /* 11111111 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-
-   /* 210 0xd2 'Ò' */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0xff, /* 11111111 */
-   0x36, /* 00110110 */
-   0x36, /* 00110110 */
-   0x36, /* 00110110 */
-
-   /* 211 0xd3 'Ó' */
-   0x36, /* 00110110 */
-   0x36, /* 00110110 */
-   0x36, /* 00110110 */
-   0x36, /* 00110110 */
-   0x3f, /* 00111111 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-
-   /* 212 0xd4 'Ô' */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x1f, /* 00011111 */
-   0x18, /* 00011000 */
-   0x1f, /* 00011111 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-
-   /* 213 0xd5 'Õ' */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x1f, /* 00011111 */
-   0x18, /* 00011000 */
-   0x1f, /* 00011111 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-
-   /* 214 0xd6 'Ö' */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x3f, /* 00111111 */
-   0x36, /* 00110110 */
-   0x36, /* 00110110 */
-   0x36, /* 00110110 */
-
-   /* 215 0xd7 '×' */
-   0x36, /* 00110110 */
-   0x36, /* 00110110 */
-   0x36, /* 00110110 */
-   0x36, /* 00110110 */
-   0xff, /* 11111111 */
-   0x36, /* 00110110 */
-   0x36, /* 00110110 */
-   0x36, /* 00110110 */
-
-   /* 216 0xd8 'Ø' */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0xff, /* 11111111 */
-   0x18, /* 00011000 */
-   0xff, /* 11111111 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-
-   /* 217 0xd9 'Ù' */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0xf8, /* 11111000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-
-   /* 218 0xda 'Ú' */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x1f, /* 00011111 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-
-   /* 219 0xdb 'Û' */
-   0xff, /* 11111111 */
-   0xff, /* 11111111 */
-   0xff, /* 11111111 */
-   0xff, /* 11111111 */
-   0xff, /* 11111111 */
-   0xff, /* 11111111 */
-   0xff, /* 11111111 */
-   0xff, /* 11111111 */
-
-   /* 220 0xdc 'Ü' */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0xff, /* 11111111 */
-   0xff, /* 11111111 */
-   0xff, /* 11111111 */
-   0xff, /* 11111111 */
-
-   /* 221 0xdd 'Ý' */
-   0xf0, /* 11110000 */
-   0xf0, /* 11110000 */
-   0xf0, /* 11110000 */
-   0xf0, /* 11110000 */
-   0xf0, /* 11110000 */
-   0xf0, /* 11110000 */
-   0xf0, /* 11110000 */
-   0xf0, /* 11110000 */
-
-   /* 222 0xde 'Þ' */
-   0x0f, /* 00001111 */
-   0x0f, /* 00001111 */
-   0x0f, /* 00001111 */
-   0x0f, /* 00001111 */
-   0x0f, /* 00001111 */
-   0x0f, /* 00001111 */
-   0x0f, /* 00001111 */
-   0x0f, /* 00001111 */
-
-   /* 223 0xdf 'ß' */
-   0xff, /* 11111111 */
-   0xff, /* 11111111 */
-   0xff, /* 11111111 */
-   0xff, /* 11111111 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-
-   /* 224 0xe0 'à' */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x76, /* 01110110 */
-   0xdc, /* 11011100 */
-   0xc8, /* 11001000 */
-   0xdc, /* 11011100 */
-   0x76, /* 01110110 */
-   0x00, /* 00000000 */
-
-   /* 225 0xe1 'á' */
-   0x78, /* 01111000 */
-   0xcc, /* 11001100 */
-   0xcc, /* 11001100 */
-   0xd8, /* 11011000 */
-   0xcc, /* 11001100 */
-   0xc6, /* 11000110 */
-   0xcc, /* 11001100 */
-   0x00, /* 00000000 */
-
-   /* 226 0xe2 'â' */
-   0xfe, /* 11111110 */
-   0xc6, /* 11000110 */
-   0xc0, /* 11000000 */
-   0xc0, /* 11000000 */
-   0xc0, /* 11000000 */
-   0xc0, /* 11000000 */
-   0xc0, /* 11000000 */
-   0x00, /* 00000000 */
-
-   /* 227 0xe3 'ã' */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0xfe, /* 11111110 */
-   0x6c, /* 01101100 */
-   0x6c, /* 01101100 */
-   0x6c, /* 01101100 */
-   0x6c, /* 01101100 */
-   0x00, /* 00000000 */
-
-   /* 228 0xe4 'ä' */
-   0xfe, /* 11111110 */
-   0xc6, /* 11000110 */
-   0x60, /* 01100000 */
-   0x30, /* 00110000 */
-   0x60, /* 01100000 */
-   0xc6, /* 11000110 */
-   0xfe, /* 11111110 */
-   0x00, /* 00000000 */
-
-   /* 229 0xe5 'å' */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x7e, /* 01111110 */
-   0xd8, /* 11011000 */
-   0xd8, /* 11011000 */
-   0xd8, /* 11011000 */
-   0x70, /* 01110000 */
-   0x00, /* 00000000 */
-
-   /* 230 0xe6 'æ' */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x66, /* 01100110 */
-   0x66, /* 01100110 */
-   0x66, /* 01100110 */
-   0x66, /* 01100110 */
-   0x7c, /* 01111100 */
-   0xc0, /* 11000000 */
-
-   /* 231 0xe7 'ç' */
-   0x00, /* 00000000 */
-   0x76, /* 01110110 */
-   0xdc, /* 11011100 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x00, /* 00000000 */
-
-   /* 232 0xe8 'è' */
-   0x7e, /* 01111110 */
-   0x18, /* 00011000 */
-   0x3c, /* 00111100 */
-   0x66, /* 01100110 */
-   0x66, /* 01100110 */
-   0x3c, /* 00111100 */
-   0x18, /* 00011000 */
-   0x7e, /* 01111110 */
-
-   /* 233 0xe9 'é' */
-   0x38, /* 00111000 */
-   0x6c, /* 01101100 */
-   0xc6, /* 11000110 */
-   0xfe, /* 11111110 */
-   0xc6, /* 11000110 */
-   0x6c, /* 01101100 */
-   0x38, /* 00111000 */
-   0x00, /* 00000000 */
-
-   /* 234 0xea 'ê' */
-   0x38, /* 00111000 */
-   0x6c, /* 01101100 */
-   0xc6, /* 11000110 */
-   0xc6, /* 11000110 */
-   0x6c, /* 01101100 */
-   0x6c, /* 01101100 */
-   0xee, /* 11101110 */
-   0x00, /* 00000000 */
-
-   /* 235 0xeb 'ë' */
-   0x0e, /* 00001110 */
-   0x18, /* 00011000 */
-   0x0c, /* 00001100 */
-   0x3e, /* 00111110 */
-   0x66, /* 01100110 */
-   0x66, /* 01100110 */
-   0x3c, /* 00111100 */
-   0x00, /* 00000000 */
-
-   /* 236 0xec 'ì' */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x7e, /* 01111110 */
-   0xdb, /* 11011011 */
-   0xdb, /* 11011011 */
-   0x7e, /* 01111110 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-
-   /* 237 0xed 'í' */
-   0x06, /* 00000110 */
-   0x0c, /* 00001100 */
-   0x7e, /* 01111110 */
-   0xdb, /* 11011011 */
-   0xdb, /* 11011011 */
-   0x7e, /* 01111110 */
-   0x60, /* 01100000 */
-   0xc0, /* 11000000 */
-
-   /* 238 0xee 'î' */
-   0x1e, /* 00011110 */
-   0x30, /* 00110000 */
-   0x60, /* 01100000 */
-   0x7e, /* 01111110 */
-   0x60, /* 01100000 */
-   0x30, /* 00110000 */
-   0x1e, /* 00011110 */
-   0x00, /* 00000000 */
-
-   /* 239 0xef 'ï' */
-   0x00, /* 00000000 */
-   0x7c, /* 01111100 */
-   0xc6, /* 11000110 */
-   0xc6, /* 11000110 */
-   0xc6, /* 11000110 */
-   0xc6, /* 11000110 */
-   0xc6, /* 11000110 */
-   0x00, /* 00000000 */
-
-   /* 240 0xf0 'ð' */
-   0x00, /* 00000000 */
-   0xfe, /* 11111110 */
-   0x00, /* 00000000 */
-   0xfe, /* 11111110 */
-   0x00, /* 00000000 */
-   0xfe, /* 11111110 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-
-   /* 241 0xf1 'ñ' */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x7e, /* 01111110 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x00, /* 00000000 */
-   0x7e, /* 01111110 */
-   0x00, /* 00000000 */
-
-   /* 242 0xf2 'ò' */
-   0x30, /* 00110000 */
-   0x18, /* 00011000 */
-   0x0c, /* 00001100 */
-   0x18, /* 00011000 */
-   0x30, /* 00110000 */
-   0x00, /* 00000000 */
-   0x7e, /* 01111110 */
-   0x00, /* 00000000 */
-
-   /* 243 0xf3 'ó' */
-   0x0c, /* 00001100 */
-   0x18, /* 00011000 */
-   0x30, /* 00110000 */
-   0x18, /* 00011000 */
-   0x0c, /* 00001100 */
-   0x00, /* 00000000 */
-   0x7e, /* 01111110 */
-   0x00, /* 00000000 */
-
-   /* 244 0xf4 'ô' */
-   0x0e, /* 00001110 */
-   0x1b, /* 00011011 */
-   0x1b, /* 00011011 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-
-   /* 245 0xf5 'õ' */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0xd8, /* 11011000 */
-   0xd8, /* 11011000 */
-   0x70, /* 01110000 */
-
-   /* 246 0xf6 'ö' */
-   0x00, /* 00000000 */
-   0x18, /* 00011000 */
-   0x00, /* 00000000 */
-   0x7e, /* 01111110 */
-   0x00, /* 00000000 */
-   0x18, /* 00011000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-
-   /* 247 0xf7 '÷' */
-   0x00, /* 00000000 */
-   0x76, /* 01110110 */
-   0xdc, /* 11011100 */
-   0x00, /* 00000000 */
-   0x76, /* 01110110 */
-   0xdc, /* 11011100 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-
-   /* 248 0xf8 'ø' */
-   0x38, /* 00111000 */
-   0x6c, /* 01101100 */
-   0x6c, /* 01101100 */
-   0x38, /* 00111000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-
-   /* 249 0xf9 'ù' */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x18, /* 00011000 */
-   0x18, /* 00011000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-
-   /* 250 0xfa 'ú' */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x18, /* 00011000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-
-   /* 251 0xfb 'û' */
-   0x0f, /* 00001111 */
-   0x0c, /* 00001100 */
-   0x0c, /* 00001100 */
-   0x0c, /* 00001100 */
-   0xec, /* 11101100 */
-   0x6c, /* 01101100 */
-   0x3c, /* 00111100 */
-   0x1c, /* 00011100 */
-
-   /* 252 0xfc 'ü' */
-   0x6c, /* 01101100 */
-   0x36, /* 00110110 */
-   0x36, /* 00110110 */
-   0x36, /* 00110110 */
-   0x36, /* 00110110 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-
-   /* 253 0xfd 'ý' */
-   0x78, /* 01111000 */
-   0x0c, /* 00001100 */
-   0x18, /* 00011000 */
-   0x30, /* 00110000 */
-   0x7c, /* 01111100 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-
-   /* 254 0xfe 'þ' */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x3c, /* 00111100 */
-   0x3c, /* 00111100 */
-   0x3c, /* 00111100 */
-   0x3c, /* 00111100 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-
-   /* 255 0xff 'ÿ' */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-   0x00, /* 00000000 */
-
-};
-
diff -u --recursive --new-file v2.1.72/linux/arch/m68k/console/txtcon.c linux/arch/m68k/console/txtcon.c
--- v2.1.72/linux/arch/m68k/console/txtcon.c	Wed Apr 23 19:01:15 1997
+++ linux/arch/m68k/console/txtcon.c	Wed Dec 31 16:00:00 1969
@@ -1,147 +0,0 @@
-/*
- * linux/arch/m68k/console/txtcon.c -- Low level text mode based console driver
- *
- *    Copyright (C) 1995 Geert Uytterhoeven
- *
- *
- * This file is currently only a skeleton, since all Amigas and Ataris have
- * bitmapped graphics.
- *
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file COPYING in the main directory of this archive
- * for more details.
- */
-
-
-#include <linux/types.h>
-#include <linux/console.h>
-
-
-   /*
-    *    Interface used by the world
-    */
-
-static u_long txtcon_startup(u_long kmem_start, const char **display_desc);
-static void txtcon_init(struct vc_data *conp);
-static int txtcon_deinit(struct vc_data *conp);
-static int txtcon_clear(struct vc_data *conp, int sy, int sx, int height,
-                        int width);
-static int txtcon_putc(struct vc_data *conp, int c, int y, int x);
-static int txtcon_putcs(struct vc_data *conp, const char *s, int count, int y,
-                        int x);
-static int txtcon_cursor(struct vc_data *conp, int mode);
-static int txtcon_scroll(struct vc_data *conp, int t, int b, int dir, int count);
-static int txtcon_bmove(struct vc_data *conp, int sy, int sx, int dy, int dx,
-                        int height, int width);
-static int txtcon_switch(struct vc_data *conp);
-static int txtcon_blank(int blank);
-static int txtcon_get_font(struct vc_data *conp, int *w, int *h, char *data);
-static int txtcon_set_font(struct vc_data *conp, int w, int h, char *data);
-static int txtcon_set_palette(struct vc_data *conp, unsigned char *table);
-
-
-static u_long txtcon_startup(u_long kmem_start, const char **display_desc)
-{
-   *display_desc = "Not yet implemented";
-   return(kmem_start);
-}
-
-
-static void txtcon_init(struct vc_data *conp)
-{
-}
-
-
-static int txtcon_deinit(struct vc_data *conp)
-{
-   return(0);
-}
-
-
-/* ====================================================================== */
-
-/* txtcon_XXX routines - interface used by the world */
-
-
-static int txtcon_clear(struct vc_data *conp, int sy, int sx, int height,
-                        int width)
-{
-   return(0);
-}
-
-
-static int txtcon_putc(struct vc_data *conp, int c, int y, int x)
-{
-   return(0);
-}
-
-
-static int txtcon_putcs(struct vc_data *conp, const char *s, int count, int y,
-                        int x)
-{
-   return(0);
-}
-
-
-static int txtcon_cursor(struct vc_data *conp, int mode)
-{
-   return(0);
-}
-
-
-static int txtcon_scroll(struct vc_data *conp, int t, int b, int dir, int count)
-{
-   return(0);
-}
-
-
-static int txtcon_bmove(struct vc_data *conp, int sy, int sx, int dy, int dx,
-                        int height, int width)
-{
-   return(0);
-}
-
-
-static int txtcon_switch(struct vc_data *conp)
-{
-   return(0);
-}
-
-
-static int txtcon_blank(int blank)
-{
-   return(0);
-}
-
-
-static int txtcon_get_font(struct vc_data *conp, int *w, int *h, char *data)
-{
-   return(0);
-}
-
-
-static int txtcon_set_font(struct vc_data *conp, int w, int h, char *data)
-{
-   return(0);
-}
-
-
-static int txtcon_set_palette(struct vc_data *conp, unsigned char *table)
-{
-   return(0);
-}
-
-
-/* ====================================================================== */
-
-   /*
-    *    The console `switch' structure for the text mode based console
-    */
-
-struct consw txt_con = {
-   txtcon_startup, txtcon_init, txtcon_deinit, txtcon_clear, txtcon_putc,
-   txtcon_putcs, txtcon_cursor, txtcon_scroll, txtcon_bmove, txtcon_switch,
-   txtcon_blank, txtcon_get_font, txtcon_set_font, txtcon_set_palette
-};
-
diff -u --recursive --new-file v2.1.72/linux/arch/mips/.gdbinit linux/arch/mips/.gdbinit
--- v2.1.72/linux/arch/mips/.gdbinit	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/.gdbinit	Wed Dec 10 10:31:09 1997
@@ -0,0 +1,7 @@
+echo Setting up the environment for debugging vmlinux...\n
+echo set remotedebug 0 \n
+set remotedebug 0
+echo cd arch/mips/kernel \n
+cd arch/mips/kernel
+echo target remote /dev/ttyS0 \n
+target remote /dev/ttyS0
diff -u --recursive --new-file v2.1.72/linux/arch/mips/Makefile linux/arch/mips/Makefile
--- v2.1.72/linux/arch/mips/Makefile	Mon Aug 18 18:19:42 1997
+++ linux/arch/mips/Makefile	Wed Dec 10 10:31:09 1997
@@ -13,21 +13,21 @@
 # Copyright (C) 1994, 1995, 1996 by Ralf Baechle
 # DECStation modifications by Paul M. Antoine, 1996
 #
-# $Id: Makefile,v 1.8 1997/08/08 18:11:35 miguel Exp $
+# $Id: Makefile,v 1.9 1997/09/19 08:34:54 ralf Exp $
 #
 
 #
 # Select the object file format to substitute into the linker script.
 #
 ifdef CONFIG_CPU_LITTLE_ENDIAN
-CROSS_COMPILE	= mipsel-linux-
+tool-prefix	= mipsel-linux-
 ifdef CONFIG_MIPS_ECOFF
 oformat		= ecoff-littlemips
 else
 oformat		= elf32-littlemips
 endif
 else
-CROSS_COMPILE	= mips-linux-
+tool-prefix	= mips-linux-
 ifdef CONFIG_MIPS_ECOFF
 oformat		= ecoff-bigmips
 else
@@ -35,6 +35,10 @@
 endif
 endif
 
+ifdef CONFIG_CROSSCOMPILE
+CROSS_COMPILE  = $(tool-prefix)
+endif
+
 LINKFLAGS	= -static -N
 MODFLAGS	+= -mlong-calls
 
@@ -77,6 +81,9 @@
 endif
 ifdef CONFIG_CPU_R5000
 CFLAGS		:= $(CFLAGS) -mcpu=r8000 -mips2
+endif
+ifdef CONFIG_CPU_NEVADA
+CFLAGS		:= $(CFLAGS) -mcpu=r8000 -mips2 -mmad
 endif
 ifdef CONFIG_CPU_R8000
 CFLAGS		:= $(CFLAGS) -mcpu=r8000 -mips2
diff -u --recursive --new-file v2.1.72/linux/arch/mips/boot/Makefile linux/arch/mips/boot/Makefile
--- v2.1.72/linux/arch/mips/boot/Makefile	Mon Aug 18 18:19:42 1997
+++ linux/arch/mips/boot/Makefile	Wed Dec 10 10:31:09 1997
@@ -41,6 +41,7 @@
 	fi
 
 dep:
+	$(CPP) -M *.[cS] > .depend
 
 clean:
 	rm -f zImage zImage.tmp mkboot
diff -u --recursive --new-file v2.1.72/linux/arch/mips/config.in linux/arch/mips/config.in
--- v2.1.72/linux/arch/mips/config.in	Tue Dec  2 16:45:17 1997
+++ linux/arch/mips/config.in	Wed Dec 10 10:31:09 1997
@@ -21,17 +21,29 @@
 fi
 bool 'Support for Mips Magnum 4000' CONFIG_MIPS_MAGNUM_4000
 bool 'Support for Olivetti M700-10' CONFIG_OLIVETTI_M700
-if [ "$CONFIG_MIPS_MAGNUM_4000" = "y" -o \
-     "$CONFIG_OLIVETTI_M700" = "y" ]; then
-       define_bool CONFIG_VIDEO_G364 y
-fi
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
   bool 'Support for SGI workstations' CONFIG_SGI
   if [ "$CONFIG_SGI" = "y" ]; then
-     bool 'Support for SGI graphic devices' CONFIG_SGI_GRAPHICS
+    bool 'Support for SGI graphic devices' CONFIG_SGI_GRAPHICS
+    define_bool CONFIG_UMISC y
   fi
 fi
 bool 'Support for SNI RM200 PCI' CONFIG_SNI_RM200_PCI
+
+#
+# Select some configuration options automatically for certain systems.
+#
+unset CONFIG_PCI
+unset CONFIG_MIPS_JAZZ
+unset CONFIG_VIDEO_G364
+
+if [ "$CONFIG_ALGOR_P4032" = "y" ]; then
+	define_bool CONFIG_PCI y
+fi
+if [ "$CONFIG_MIPS_MAGNUM_4000" = "y" -o \
+     "$CONFIG_OLIVETTI_M700" = "y" ]; then
+       define_bool CONFIG_VIDEO_G364 y
+fi
 if [ "$CONFIG_DESKSTATION_RPC44" = "y" -o \
      "$CONFIG_DESKSTATION_TYNE" = "y" ]; then
 	define_bool CONFIG_MIPS_ARC y
@@ -41,9 +53,7 @@
      "$CONFIG_MIPS_MAGNUM_4000" = "y" ]; then
 	define_bool CONFIG_MIPS_JAZZ y
 fi
-unset CONFIG_PCI
-if [ "$CONFIG_SNI_RM200_PCI" = "y" -o \
-     "$CONFIG_ALGOR_P4032" = "y" ]; then
+if [ "$CONFIG_SNI_RM200_PCI" = "y" ]; then
 	define_bool CONFIG_PCI y
 fi
 endmenu
@@ -57,6 +67,7 @@
 	 R4300 CONFIG_CPU_R4300	\
 	 R4x00 CONFIG_CPU_R4X00	\
 	 R5000 CONFIG_CPU_R5000	\
+	 R56x0 CONFIG_CPU_NEVADA \
 	 R8000 CONFIG_CPU_R8000	\
 	 R10000 CONFIG_CPU_R10000" R4x00
 endmenu
@@ -70,22 +81,25 @@
   define_bool CONFIG_ELF_KERNEL y
   bool 'Generate little endian code' CONFIG_CPU_LITTLE_ENDIAN
 fi
+
 if [ "$CONFIG_CPU_LITTLE_ENDIAN" = "n" ]; then
   define_bool CONFIG_BINFMT_IRIX y
   define_bool CONFIG_FORWARD_KEYBOARD y
 fi
-define_bool CONFIG_BINFMT_ELF y
 define_bool CONFIG_BINFMT_AOUT n
+define_bool CONFIG_BINFMT_ELF y
+tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
   tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
   tristate 'Kernel support for JAVA binaries (obsolete)' CONFIG_BINFMT_JAVA
 fi
+
 bool 'Networking support' CONFIG_NET
 bool 'System V IPC' CONFIG_SYSVIPC
 bool 'Sysctl support' CONFIG_SYSCTL
 
 if [ "$CONFIG_SGI" != "y" ]; then
-  tristate 'Parallel port support' CONFIG_PNP_PARPORT
+  tristate 'Parallel port support' CONFIG_PARPORT
 fi
 
 endmenu
@@ -179,17 +193,6 @@
 	endmenu
 fi
 
-# Conditionally compile in the Uniform CD-ROM driver
-if [ "$CONFIG_BLK_DEV_SR" = "y" ]; then
-  define_bool CONFIG_CDROM y
-else
-  if [ "$CONFIG_BLK_DEV_SR" = "m" ]; then
-    define_bool CONFIG_CDROM m
-  else
-    define_bool CONFIG_CDROM n
-  fi
-fi
-
 source fs/Config.in
 
 source fs/nls/Config.in
@@ -222,11 +225,13 @@
 comment 'Kernel hacking'
 
 #bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC
+bool 'Are you using a crosscompiler' CONFIG_CROSSCOMPILE
+if [ "$CONFIG_MODULES" = "y" ]; then
+  bool ' Build fp execption handler module' CONFIG_MIPS_FPE_MODULE
+fi
 bool 'Remote GDB kernel debugging' CONFIG_REMOTE_DEBUG
 bool 'Kernel profiling support' CONFIG_PROFILE
 if [ "$CONFIG_PROFILE" = "y" ]; then
   int ' Profile shift count' CONFIG_PROFILE_SHIFT 2
 fi
 endmenu
-
-define_bool CONFIG_VGA_CONSOLE y
diff -u --recursive --new-file v2.1.72/linux/arch/mips/defconfig linux/arch/mips/defconfig
--- v2.1.72/linux/arch/mips/defconfig	Mon Aug 18 18:19:42 1997
+++ linux/arch/mips/defconfig	Wed Dec 10 10:31:09 1997
@@ -25,6 +25,7 @@
 # CONFIG_CPU_R4300 is not set
 CONFIG_CPU_R4X00=y
 # CONFIG_CPU_R5000 is not set
+# CONFIG_CPU_NEVADA is not set
 # CONFIG_CPU_R8000 is not set
 # CONFIG_CPU_R10000 is not set
 
@@ -33,8 +34,9 @@
 #
 CONFIG_ELF_KERNEL=y
 CONFIG_CPU_LITTLE_ENDIAN=y
-CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_AOUT is not set
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
 CONFIG_NET=y
 CONFIG_SYSVIPC=y
 CONFIG_SYSCTL=y
@@ -121,6 +123,7 @@
 # CONFIG_NET_VENDOR_3COM is not set
 # CONFIG_LANCE is not set
 # CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_NET_VENDOR_RACAL is not set
 # CONFIG_NET_ISA is not set
 CONFIG_NET_EISA=y
 CONFIG_PCNET32=y
@@ -128,16 +131,17 @@
 # CONFIG_CS89x0 is not set
 # CONFIG_DE4X5 is not set
 # CONFIG_DEC_ELCP is not set
+# CONFIG_DEC_ELCP is not set
 # CONFIG_DGRS is not set
 # CONFIG_EEXPRESS_PRO100 is not set
 # CONFIG_NET_POCKET is not set
 # CONFIG_FDDI is not set
 # CONFIG_DLCI is not set
-# CONFIG_PLIP is not set
 # CONFIG_PPP is not set
 # CONFIG_NET_RADIO is not set
 # CONFIG_SLIP is not set
 # CONFIG_TR is not set
+# CONFIG_WAN_DRIVERS is not set
 # CONFIG_LAPBETHER is not set
 # CONFIG_X25_ASY is not set
 
@@ -157,10 +161,12 @@
 # CONFIG_QUOTA is not set
 # CONFIG_MINIX_FS is not set
 CONFIG_EXT2_FS=y
-# CONFIG_FAT_FS is not set
-# CONFIG_MSDOS_FS is not set
-# CONFIG_VFAT_FS is not set
+CONFIG_ISO9660_FS=y
+# CONFIG_JOLIET is not set
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
 # CONFIG_UMSDOS_FS is not set
+CONFIG_VFAT_FS=y
 CONFIG_PROC_FS=y
 CONFIG_NFS_FS=y
 CONFIG_ROOT_NFS=y
@@ -170,13 +176,44 @@
 CONFIG_SUNRPC=y
 CONFIG_LOCKD=y
 # CONFIG_SMB_FS is not set
-CONFIG_ISO9660_FS=y
 # CONFIG_HPFS_FS is not set
 # CONFIG_SYSV_FS is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_ROMFS_FS is not set
 # CONFIG_AUTOFS_FS is not set
 # CONFIG_UFS_FS is not set
+# CONFIG_MAC_PARTITION is not set
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+CONFIG_NLS_CODEPAGE_850=y
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_KOI8_R is not set
 
 #
 # Character devices
@@ -188,11 +225,17 @@
 # CONFIG_SERIAL_NONSTANDARD is not set
 # CONFIG_MOUSE is not set
 # CONFIG_QIC02_TAPE is not set
-# CONFIG_FTAPE is not set
 # CONFIG_APM is not set
 # CONFIG_WATCHDOG is not set
 # CONFIG_RTC is not set
+# CONFIG_NVRAM is not set
 # CONFIG_JOYSTICK is not set
+# CONFIG_MISC_RADIO is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
 
 #
 # Sound
@@ -202,5 +245,6 @@
 #
 # Kernel hacking
 #
+CONFIG_CROSSCOMPILE=y
 # CONFIG_REMOTE_DEBUG is not set
 # CONFIG_PROFILE is not set
diff -u --recursive --new-file v2.1.72/linux/arch/mips/deskstation/hw-access.c linux/arch/mips/deskstation/hw-access.c
--- v2.1.72/linux/arch/mips/deskstation/hw-access.c	Mon Aug 18 18:19:42 1997
+++ linux/arch/mips/deskstation/hw-access.c	Wed Dec 10 10:31:09 1997
@@ -7,7 +7,7 @@
  *
  * Copyright (C) 1996, 1997 by Ralf Baechle
  *
- * $Id: hw-access.c,v 1.2 1997/08/08 18:11:57 miguel Exp $
+ * $Id: hw-access.c,v 1.3 1997/07/29 17:46:42 ralf Exp $
  */
 #include <linux/config.h>
 #include <linux/delay.h>
@@ -46,69 +46,69 @@
  * How to access the floppy DMA functions.
  */
 static void
-fd_enable_dma(void)
+fd_enable_dma(int channel)
 {
-	enable_dma(FLOPPY_DMA);
+	enable_dma(channel);
 }
 
 static void
-fd_disable_dma(void)
+fd_disable_dma(int channel)
 {
-	disable_dma(FLOPPY_DMA);
+	disable_dma(int channel);
 }
 
 static int
-fd_request_dma(void)
+fd_request_dma(int channel)
 {
-	return request_dma(FLOPPY_DMA, "floppy");
+	return request_dma(channel, "floppy");
 }
 
 static void
-fd_free_dma(void)
+fd_free_dma(int channel)
 {
-	free_dma(FLOPPY_DMA);
+	free_dma(channel);
 }
 
 static void
-fd_clear_dma_ff(void)
+fd_clear_dma_ff(int channel)
 {
-	clear_dma_ff(FLOPPY_DMA);
+	clear_dma_ff(channel);
 }
 
 static void
-fd_set_dma_mode(char mode)
+fd_set_dma_mode(int channel, char mode)
 {
-	set_dma_mode(FLOPPY_DMA, mode);
+	set_dma_mode(channel, mode);
 }
 
 static void
-fd_set_dma_addr(unsigned int addr)
+fd_set_dma_addr(int channel, unsigned int addr)
 {
-	set_dma_addr(FLOPPY_DMA, addr);
+	set_dma_addr(channel, addr);
 }
 
 static void
-fd_set_dma_count(unsigned int count)
+fd_set_dma_count(int channel, unsigned int count)
 {
-	set_dma_count(FLOPPY_DMA, count);
+	set_dma_count(channel, count);
 }
 
 static int
-fd_get_dma_residue(void)
+fd_get_dma_residue(int channel)
 {
-	return get_dma_residue(FLOPPY_DMA);
+	return get_dma_residue(channel);
 }
 
 static void
-fd_enable_irq(void)
+fd_enable_irq(int irq)
 {
-	enable_irq(FLOPPY_IRQ);
+	enable_irq(irq);
 }
 
 static void
-fd_disable_irq(void)
+fd_disable_irq(int irq)
 {
-	disable_irq(FLOPPY_IRQ);
+	disable_irq(irq);
 }
 
 void
diff -u --recursive --new-file v2.1.72/linux/arch/mips/deskstation/int-handler.S linux/arch/mips/deskstation/int-handler.S
--- v2.1.72/linux/arch/mips/deskstation/int-handler.S	Thu Jun 26 12:33:37 1997
+++ linux/arch/mips/deskstation/int-handler.S	Wed Dec 10 10:31:09 1997
@@ -1,7 +1,9 @@
 /*
  * Deskstation rPC44/Tyne specific interrupt handler code
  *
- * Copyright (C) 1994, 1995, 1996 by Ralf Baechle
+ * Copyright (C) 1994, 1995, 1996, 1997 by Ralf Baechle
+ *
+ * $Id: int-handler.S,v 1.3 1997/09/20 19:20:09 root Exp $
  */
 #include <asm/asm.h>
 #include <asm/mipsconfig.h>
@@ -9,7 +11,7 @@
 #include <asm/regdef.h>
 #include <asm/stackframe.h>
 
-#error "FIXME - PORT_BASE is defined to port_base which breaks this file"
+#error "FIXME - PORT_BASE is defined to mips_io_port_base which breaks this file"
 
 		.text
 		.set	noreorder
@@ -43,12 +45,8 @@
 		/*
 		 * Now call the real handler
 		 */
-		la	t3,IRQ_vectors
-		sll	t2,a0,PTRLOG
-		addu	t3,t2
-		LONG_L	t3,(t3)
-		jalr	t3
-		nop					# delay slot
+		jal	do_IRQ
+		 move	a1,sp
 		/*
 		 * Unblock first pic
 		 */
@@ -57,7 +55,7 @@
 		nor	s1,zero,s1
 		and	t1,s1
 		sb	t1,%lo(cache_21)(s4)
-		jr	v0
+		j	ret_from_irq
 		sb	t1,%lo(PORT_BASE+0x21)(s0)	# delay slot
 
 		/*
@@ -85,13 +83,8 @@
 		/*
 		 * Now call the real handler
 		 */
-		la	t3,IRQ_vectors
-		addiu	a0,8
-		sll	t2,a0,PTRLOG
-		addu	t3,t2
-		LONG_L	t3,(t3)
-		jalr	t3
-		nop					# delay slot
+		jal	do_IRQ
+		 nop
 		/*
 		 * Unblock second pic
 		 */
@@ -100,12 +93,12 @@
 		nor	s1,zero,s1
 		and	t1,t1,s1
 		sb	t1,%lo(cache_A1)(s4)
-		jr	v0
-		sb	t1,%lo(PORT_BASE+0xa1)(s0)	# delay slot
+		j	ret_from_irq
+		 sb	t1,%lo(PORT_BASE+0xa1)(s0)
 
 /*
  * "Jump extender" to reach spurious_interrupt
  */
 3:		j	spurious_interrupt
-		nop					# delay slot
+		 nop
 		END(deskstation_handle_int)
diff -u --recursive --new-file v2.1.72/linux/arch/mips/deskstation/setup.c linux/arch/mips/deskstation/setup.c
--- v2.1.72/linux/arch/mips/deskstation/setup.c	Mon Aug 18 18:19:42 1997
+++ linux/arch/mips/deskstation/setup.c	Wed Dec 10 10:31:09 1997
@@ -7,7 +7,7 @@
  *
  * Copyright (C) 1996, 1997 by Ralf Baechle
  *
- * $Id: setup.c,v 1.2 1997/08/08 18:11:59 miguel Exp $
+ * $Id: setup.c,v 1.2 1997/07/23 17:40:54 ralf Exp $
  */
 #include <linux/config.h>
 #include <linux/init.h>
diff -u --recursive --new-file v2.1.72/linux/arch/mips/jazz/g364.c linux/arch/mips/jazz/g364.c
--- v2.1.72/linux/arch/mips/jazz/g364.c	Mon Aug 18 18:19:42 1997
+++ linux/arch/mips/jazz/g364.c	Wed Dec 10 10:31:09 1997
@@ -30,6 +30,7 @@
 #include <linux/consolemap.h>
 #include <linux/selection.h>
 #include <linux/console_struct.h>
+#include <linux/init.h>
 
 #include <asm/io.h>
 #include <asm/system.h>
@@ -94,18 +95,6 @@
 #include "g364.fnt"
 };
 
-u32 g364_cursor[256] = {
-  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-  0xffff0000,0,0,0,0xffff0000,0,0,0,0xffff0000,0,0,0,0,0,0,0,
-  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
-};
-
 #ifdef CONFIG_REMOTE_DEBUG
 /* #define DEBUG_G364 */
 
@@ -127,8 +116,8 @@
 
 int cursor_initialised=0;
 
-unsigned long
-con_type_init(unsigned long kmem_start, const char **display_desc)
+__initfunc(unsigned long
+con_type_init(unsigned long kmem_start, const char **display_desc))
 {
         can_do_color = 1;
 
@@ -146,7 +135,8 @@
 	return kmem_start;
 }
 
-con_type_init_finish(void)
+__initfunc(void
+con_type_init_finish(void))
 {
 }
 
@@ -164,19 +154,31 @@
 void
 hide_cursor(void)
 {
-/*	*(unsigned int *) CTLA_REG &= ~CURS_TOGGLE; */
+	*(unsigned int *) CTLA_REG |= CURS_TOGGLE;
 }
 
 void
 init_g364_cursor(void)
 {
 	volatile unsigned int *ptr = (unsigned int *) CURS_PAL_REG;
+        int i;
 
         *ptr |= 0x00ffffff;
 	ptr[2] |= 0x00ffffff;
 	ptr[4] |= 0x00ffffff;
 
-	memcpy((unsigned int *)CURS_PAT_REG, &g364_cursor, 1024);
+        /*
+	 * first set the whole cursor to transparent
+	 */
+        for (i = 0; i < 512; i++)
+	        *(unsigned short *)(CURS_PAT_REG+i*8) = 0;
+
+        /*
+	 * switch the last to lines to cursor palette 3
+	 * we assume here, that FONTSIZE_X is 8
+	 */
+        *(unsigned short *)(CURS_PAT_REG + (FONTSIZE_Y-2)*64) = 0xffff;
+        *(unsigned short *)(CURS_PAT_REG + (FONTSIZE_Y-1)*64) = 0xffff;			    
 	cursor_initialised = 1;
 }
 
@@ -186,15 +188,29 @@
 void
 set_cursor(int currcons)
 {
-/*
+        unsigned int idx, xt, yt, row, col;
+    
 	if (!cursor_initialised)
 		init_g364_cursor();
 
-	if (console_blanked)
+	if (currcons != fg_console || console_blanked || vcmode == KD_GRAPHICS)
 		return;
 
-	*(unsigned int *) CTLA_REG |= CURS_TOGGLE;
-*/
+	*(unsigned int *) CTLA_REG &= ~CURS_TOGGLE;
+    
+        if (__real_origin != __origin)
+	        __set_origin (__real_origin);
+    
+        if (deccm) {
+	    idx = (pos - video_mem_base) >> 1;
+	    col = idx % video_num_columns;
+	    row = (idx - col) / video_num_columns;
+	    
+	    xt = col * FONTSIZE_X;
+	    yt = row * FONTSIZE_Y;
+	    *(unsigned int *)CURS_POS_REG = (xt << 12) | yt;
+	} else
+	       hide_cursor();
 }
 
 /*
diff -u --recursive --new-file v2.1.72/linux/arch/mips/jazz/hw-access.c linux/arch/mips/jazz/hw-access.c
--- v2.1.72/linux/arch/mips/jazz/hw-access.c	Mon Aug 18 18:19:42 1997
+++ linux/arch/mips/jazz/hw-access.c	Wed Dec 10 10:31:09 1997
@@ -6,6 +6,8 @@
  * for more details.
  *
  * Copyright (C) 1995, 1996, 1997 by Ralf Baechle
+ *
+ * $Id: hw-access.c,v 1.4 1997/07/29 17:46:45 ralf Exp $
  */
 #include <linux/delay.h>
 #include <linux/linkage.h>
@@ -40,64 +42,64 @@
  * How to access the floppy DMA functions.
  */
 static void
-fd_enable_dma(void)
+fd_enable_dma(int channel)
 {
 	vdma_enable(JAZZ_FLOPPY_DMA);
 }
 
 static void
-fd_disable_dma(void)
+fd_disable_dma(int channel)
 {
 	vdma_disable(JAZZ_FLOPPY_DMA);
 }
 
 static int
-fd_request_dma(void)
+fd_request_dma(int channel)
 {
 	return 0;
 }
 
 static void
-fd_free_dma(void)
+fd_free_dma(int channel)
 {
 }
 
 static void
-fd_clear_dma_ff(void)
+fd_clear_dma_ff(int channel)
 {
 }
 
 static void
-fd_set_dma_mode(char mode)
+fd_set_dma_mode(int channel, char mode)
 {
 	vdma_set_mode(JAZZ_FLOPPY_DMA, mode);
 }
 
 static void
-fd_set_dma_addr(unsigned int a)
+fd_set_dma_addr(int channel, unsigned int a)
 {
 	vdma_set_addr(JAZZ_FLOPPY_DMA, vdma_phys2log(PHYSADDR(a)));
 }
 
 static void
-fd_set_dma_count(unsigned int count)
+fd_set_dma_count(int channel, unsigned int count)
 {
 	vdma_set_count(JAZZ_FLOPPY_DMA, count);
 }
 
 static int
-fd_get_dma_residue(void)
+fd_get_dma_residue(int channel)
 {
 	return vdma_get_residue(JAZZ_FLOPPY_DMA);
 }
 
 static void
-fd_enable_irq(void)
+fd_enable_irq(int irq)
 {
 }
 
 static void
-fd_disable_irq(void)
+fd_disable_irq(int irq)
 {
 }
 
@@ -148,7 +150,8 @@
 	rtc_write_data
 };
 
-static volatile keyboard_hardware *jazz_kh = (keyboard_hardware *)JAZZ_KEYBOARD_ADDRESS;
+static volatile keyboard_hardware *jazz_kh = 
+	(keyboard_hardware *) JAZZ_KEYBOARD_ADDRESS;
 
 static unsigned char jazz_read_input(void)
 {
@@ -177,5 +180,4 @@
 	kbd_write_command = jazz_write_command;
 	kbd_read_status = jazz_read_status;
 	request_region(0x60, 16, "keyboard");
-        r4030_write_reg16(JAZZ_IO_IRQ_ENABLE, r4030_read_reg16(JAZZ_IO_IRQ_ENABLE) | JAZZ_IE_KEYBOARD);
 }
diff -u --recursive --new-file v2.1.72/linux/arch/mips/jazz/int-handler.S linux/arch/mips/jazz/int-handler.S
--- v2.1.72/linux/arch/mips/jazz/int-handler.S	Mon Aug  4 16:25:36 1997
+++ linux/arch/mips/jazz/int-handler.S	Wed Dec 10 10:31:09 1997
@@ -9,6 +9,8 @@
  *        interrupts.  These interrupts should use their own vectors.
  *        Squeeze the last cycles out of the handlers.  Only a dead
  *        cycle is a good cycle.
+ *
+ * $Id: int-handler.S,v 1.3 1997/09/20 19:20:11 root Exp $
  */
 #include <asm/asm.h>
 #include <asm/mipsconfig.h>
@@ -110,12 +112,8 @@
 		/*
 		 * Now call the real handler
 		 */
-		la	t3,IRQ_vectors
-		sll	t2,a0,PTRLOG
-		addu	t3,t2
-		LONG_L	t3,(t3)
-		jalr	t3
-		nop					# delay slot
+		jal	do_IRQ
+		 move	a1,sp
 		/*
 		 * Unblock first pic
 		 */
@@ -124,8 +122,8 @@
 		nor	s1,zero,s1
 		and	a0,s1
 		sb	a0,%lo(cache_21)(s4)
-		jr	v0
-		sb	a0,%lo(JAZZ_PORT_BASE)+0x21(s0)	# delay slot
+		j	ret_from_irq
+		 sb	a0,%lo(JAZZ_PORT_BASE)+0x21(s0)
 
 		.align	5
 ack_second:	/*
@@ -144,13 +142,8 @@
 		/*
 		 * Now call the real handler
 		 */
-		la	t3,IRQ_vectors
-		addiu	a0,8
-		sll	t2,a0,PTRLOG
-		addu	t3,t2
-		LONG_L	t3,(t3)
-		jalr	t3
-		nop					# delay slot
+		jal	do_IRQ
+		 move	a1,sp
 
 		/*
 		 * Unblock second pic
@@ -160,8 +153,8 @@
 		nor	s1,zero,s1
 		and	a0,s1
 		sb	a0,%lo(cache_A1)(s4)
-		jr	v0
-		sb	a0,%lo(JAZZ_PORT_BASE)+0xa1(s0)	# delay slot
+		j	ret_from_irq
+		 sb	a0,%lo(JAZZ_PORT_BASE)+0xa1(s0)
 
 /*
  * Hmm...  This is not just a plain PC clone so the question is
@@ -187,40 +180,35 @@
 
 		li	a0,0
 		jal	do_IRQ
-		move	a1,sp			# delay slot
+		 move	a1,sp
 
 		mfc0	t0,CP0_STATUS		# disable interrupts again
 		ori	t0,1
 		xori	t0,1
 		mtc0	t0,CP0_STATUS
 
-		j	ret_from_sys_call
-		nop				# delay slot
+		j	ret_from_irq
+		 nop
 
 /*
  * CPU count/compare IRQ (unused)
  */
 ll_count:	j	return
-		mtc0	zero,CP0_COMPARE
+		 mtc0	zero,CP0_COMPARE
 
 #if 0
 /*
  * Call the handler for the interrupt
  * (Currently unused)
  */
-call_real:	la	t0,IRQ_vectors
-
-		/*
+call_real:	/*
 		 * temporarily disable interrupt
 		 */
 		mfc0	t2,CP0_STATUS
 		and	t2,s1
-
-		addu	t0,t3
-		lw	t0,(t0)
-		mtc0	t2,CP0_STATUS		# delay slot
-		jalr	t0
-		nor	s1,zero,s1		# delay slot
+		mtc0	t2,CP0_STATUS
+		nor	s1,zero,s1
+		jal	do_IRQ
 
 		/*
 		 * reenable interrupt
@@ -228,9 +216,7 @@
 		mfc0	t2,CP0_STATUS
 		or	t2,s1
 		mtc0	t2,CP0_STATUS
-
-		jr	v0
-		nop				# delay slot
+		j	ret_from_irq
 #endif
 
 		.data
@@ -247,6 +233,7 @@
 		 * Interrupt handlers for local devices.
 		 */
 		.text
+		.set	reorder
 loc_no_irq:	PANIC("Unimplemented loc_no_irq handler")
 /*
  * Parallel port IRQ, remapped to level 5
@@ -254,7 +241,6 @@
 loc_parallel:	li	s1,~JAZZ_IE_PARALLEL
 		li	a0,JAZZ_PARALLEL_IRQ
 		b	loc_call
-		li	t3,PTRSIZE*JAZZ_PARALLEL_IRQ 	# delay slot
 
 /*
  * Floppy IRQ, remapped to level 6
@@ -262,7 +248,6 @@
 loc_floppy:	li	s1,~JAZZ_IE_FLOPPY
 		li	a0,JAZZ_FLOPPY_IRQ
 		b	loc_call
-		li	t3,PTRSIZE*JAZZ_FLOPPY_IRQ 	# delay slot
 
 /*
  * Sound? What sound hardware (whistle) ???
@@ -276,12 +261,10 @@
 loc_ethernet: 	li	s1,~JAZZ_IE_ETHERNET
 		li	a0,JAZZ_ETHERNET_IRQ
 		b	loc_call
-		li	t3,PTRSIZE*JAZZ_ETHERNET_IRQ 	# delay slot
 
 loc_scsi:	li	s1,~JAZZ_IE_SCSI
-		li	a0,12         # JAZZ_SCSI_IRQ */
+		li	a0,12         # JAZZ_SCSI_IRQ
 		b	loc_call
-		li	t3,PTRSIZE*12 # JAZZ_ETHERNET_IRQ 	# delay slot
 
 /*
  * Keyboard interrupt handler
@@ -289,7 +272,6 @@
 loc_keyboard:	li	s1,~JAZZ_IE_KEYBOARD
 		li	a0,JAZZ_KEYBOARD_IRQ
 		b	loc_call
-		li	t3,PTRSIZE*JAZZ_KEYBOARD_IRQ	# re-map to irq level 1
 
 loc_mouse:	PANIC("Unimplemented loc_mouse handler")
 
@@ -299,7 +281,6 @@
 loc_serial1:	li	s1,~JAZZ_IE_SERIAL1
 		li	a0,JAZZ_SERIAL1_IRQ
 		b	loc_call
-		li	t3,PTRSIZE*JAZZ_SERIAL1_IRQ 	# delay slot
 
 /*
  * Serial port 2 IRQ, remapped to level 4
@@ -307,24 +288,20 @@
 loc_serial2:	li	s1,~JAZZ_IE_SERIAL2
 		li	a0,JAZZ_SERIAL2_IRQ
 		b	loc_call
-		li	t3,PTRSIZE*JAZZ_SERIAL2_IRQ 	# delay slot
 
 /*
  * Call the interrupt handler for an interrupt generated by a
  * local device.
  */
-loc_call:	la	t0,IRQ_vectors			# delay slot
-
-		/*
+loc_call:	/*
 		 * Temporarily disable interrupt source
 		 */
 		lhu	t2,JAZZ_IO_IRQ_ENABLE
-		addu	t0,t3				# make ptr to IRQ handler
-		lw	t0,(t0)
-		and	t2,s1				# delay slot
+		and	t2,s1
 		sh	t2,JAZZ_IO_IRQ_ENABLE
-		jalr	t0				# call IRQ handler
- 		nor	s1,zero,s1			# delay slot
+
+ 		nor	s1,zero,s1
+		jal	do_IRQ
  
  		/*
  		 * Reenable interrupt
@@ -333,14 +310,12 @@
  		or	t2,s1
 		sh	t2,JAZZ_IO_IRQ_ENABLE
  
- 		jr	v0
-		nop					# delay slot
+ 		j	ret_from_irq
 
 /*
  * "Jump extender" to reach spurious_interrupt
  */
 3:		j	spurious_interrupt
-		nop					# delay slot
 
 /*
  * Vectors for interrupts generated by local devices
diff -u --recursive --new-file v2.1.72/linux/arch/mips/jazz/jazzdma.c linux/arch/mips/jazz/jazzdma.c
--- v2.1.72/linux/arch/mips/jazz/jazzdma.c	Mon Aug 18 18:19:42 1997
+++ linux/arch/mips/jazz/jazzdma.c	Wed Dec 10 10:31:09 1997
@@ -514,18 +514,3 @@
   
     return residual;
 }
-
-/*
- * Get DMA channel enable register
- */
-int vdma_get_enable(int channel)
-{
-    int enable;
-    
-    enable = r4030_read_reg32(JAZZ_R4030_CHNL_ENABLE+(channel<<5));
-    
-    if (vdma_debug)
-	printk("vdma_get_enable: channel %d: enable=%d\n",channel,enable);
-    
-    return enable;
-}
diff -u --recursive --new-file v2.1.72/linux/arch/mips/jazz/setup.c linux/arch/mips/jazz/setup.c
--- v2.1.72/linux/arch/mips/jazz/setup.c	Mon Aug 18 18:19:42 1997
+++ linux/arch/mips/jazz/setup.c	Wed Dec 10 10:31:09 1997
@@ -6,12 +6,13 @@
  * for more details.
  *
  * Copyright (C) 1996, 1997 by Ralf Baechle
+ *
+ * $Id: setup.c,v 1.5 1997/12/02 05:51:05 ralf Exp $
  */
 #include <linux/init.h>
 #include <linux/ioport.h>
 #include <linux/sched.h>
 #include <linux/interrupt.h>
-#include <linux/mm.h>
 #include <asm/bootinfo.h>
 #include <asm/keyboard.h>
 #include <asm/irq.h>
@@ -20,7 +21,6 @@
 #include <asm/reboot.h>
 #include <asm/vector.h>
 #include <asm/io.h>
-#include <asm/pgtable.h>
 
 /*
  * Initial irq handlers.
@@ -98,15 +98,15 @@
 	}
     }
 
-        add_wired_entry (0x02000017, 0x03c00017, 0xe0000000, PM_64K);
-        add_wired_entry (0x02400017, 0x02440017, 0xe2000000, PM_16M);
-        add_wired_entry (0x01800017, 0x01000017, 0xe4000000, PM_4M);
+	add_wired_entry (0x02000017, 0x03c00017, 0xe0000000, PM_64K);
+	add_wired_entry (0x02400017, 0x02440017, 0xe2000000, PM_16M);
+	add_wired_entry (0x01800017, 0x01000017, 0xe4000000, PM_4M);
 
 	irq_setup = jazz_irq_setup;
 	fd_cacheflush = jazz_fd_cacheflush;
 	keyboard_setup = jazz_keyboard_setup;
 	feature = &jazz_feature;			// Will go away
-	port_base = JAZZ_PORT_BASE;
+	mips_io_port_base = JAZZ_PORT_BASE;
 	isa_slot_offset = 0xe3000000;
 	request_region(0x00,0x20,"dma1");
 	request_region(0x40,0x20,"timer");
diff -u --recursive --new-file v2.1.72/linux/arch/mips/kernel/Makefile linux/arch/mips/kernel/Makefile
--- v2.1.72/linux/arch/mips/kernel/Makefile	Thu Jun 26 12:33:37 1997
+++ linux/arch/mips/kernel/Makefile	Wed Dec 10 10:31:09 1997
@@ -18,6 +18,10 @@
 	   r2300_misc.o r2300_scall.o r2300_fpu.o r6000_fpu.o unaligned.o
 OX_OBJS := mips_ksyms.o
 
+ifdef CONFIG_MIPS_FPE_MODULE
+M_OBJS += fpe.o
+endif
+
 #
 # SGI's have very different interrupt/timer hardware.
 #
@@ -29,7 +33,7 @@
 # Do we want to be able to execute IRIX elf binaries?
 #
 ifdef CONFIG_BINFMT_IRIX
-O_OBJS += irixelf.o irixioctl.o irixsig.o sysirix.o
+O_OBJS += irixelf.o irixioctl.o irixsig.o sysirix.o irixinv.o
 endif
 
 #
diff -u --recursive --new-file v2.1.72/linux/arch/mips/kernel/branch.c linux/arch/mips/kernel/branch.c
--- v2.1.72/linux/arch/mips/kernel/branch.c	Thu Jun 26 12:33:37 1997
+++ linux/arch/mips/kernel/branch.c	Wed Dec 10 10:31:09 1997
@@ -16,8 +16,7 @@
 #include <asm/uaccess.h>
 
 /*
- * Compute the return address and do emulate branch and instruction
- * simulation, if required.
+ * Compute the return address and do emulate branch simulation, if required.
  */
 int __compute_return_epc(struct pt_regs *regs)
 {
@@ -162,14 +161,12 @@
 
 	/*
 	 * And now the FPA/cp1 branch instructions.
-	 *
-	 * FIXME: This will silently fail for MIPS IV cop1 branches with
-	 *        the cc field != 0.
 	 */
 	case cop1_op:
 		asm ("cfc1\t%0,$31":"=r" (fcr31));
 		bit = (insn.i_format.rt >> 2);
-		bit += bit ? 24 : 23;
+		bit += (bit != 0);
+		bit += 23;
 		switch (insn.i_format.rt) {
 		case 0:	/* bc1f */
 		case 2:	/* bc1fl */
diff -u --recursive --new-file v2.1.72/linux/arch/mips/kernel/entry.S linux/arch/mips/kernel/entry.S
--- v2.1.72/linux/arch/mips/kernel/entry.S	Thu Jun 26 12:33:37 1997
+++ linux/arch/mips/kernel/entry.S	Wed Dec 10 10:31:09 1997
@@ -6,6 +6,8 @@
  * for more details.
  *
  * Copyright (C) 1994, 1995 by Ralf Baechle
+ *
+ * $Id: entry.S,v 1.4 1997/09/20 19:20:13 root Exp $
  */
 
 /*
@@ -38,24 +40,18 @@
 		.set	noreorder
 		.set	mips3
 		.align 4
-/* XXX cli/sti ??? */
 handle_bottom_half:
-		mfc0	s3,CP0_STATUS		# Enable IRQs
-		ori	t0,s3, 0x1f
-		xori	t0,0x1e
-
 		jal	do_bottom_half
-		 mtc0	t0,CP0_STATUS
-
+		 nop
 		b	9f
-		 mtc0	s3,CP0_STATUS		# Restore old IRQ state
+		 nop
 
-reschedule:
-		jal	schedule 
+reschedule:	jal	schedule 
 		 nop
 
 EXPORT(ret_from_sys_call)
-		 lw	t0,bh_mask
+EXPORT(ret_from_irq)
+		lw	t0,bh_mask
 		lw	t1,bh_active		# unused delay slot
 		and	t0,t1
 		bnez	t0,handle_bottom_half
@@ -80,64 +76,15 @@
 		jal	do_signal
 		 move	a1,sp
 
-		.set	noat
-EXPORT(return)
+EXPORT(return)	.set	noat
 		RESTORE_ALL
 		eret
 		.set	at
 
 /*
- * Beware: interrupt, fast_interrupt and bad_interrupt have unusual
- * calling conventions to speedup the mess.
- *
- * a0 - interrupt number
- * s2 - destroyed
- * return values:
- * v0 - return routine
+ * Common spurious interrupt handler.
  */
 		.text
-		.set	at
-		.align	5
-NESTED(interrupt, PT_SIZE, sp)
-		move	s2,ra
-		mfc0	t0,CP0_STATUS			# enable IRQs
-		ori	t0,0x1f
-		xori	t0,0x1e
-		mtc0	t0,CP0_STATUS
-
-		jal	do_IRQ
-		 move	a1,sp
-
-		mfc0	t0,CP0_STATUS			# disable IRQs
-		ori	t0,1
-		xori	t0,1
-		mtc0	t0,CP0_STATUS
-		.set	reorder
-		la	v0,ret_from_sys_call
-		jr	s2
-		.set	noreorder
-		END(interrupt)
-
-		.align	5
-NESTED(fast_interrupt, PT_SIZE, sp)
-		move	s2,ra
-		jal	do_fast_IRQ
-		 nop
-
-		.set	reorder
-		la	v0,return
-		jr	s2
-		.set	noreorder
-		END(fast_interrupt)
-
-		/*
-		 * Don't return & unblock the pic
-		 */
-LEAF(bad_interrupt)
-		j	return
-		END(bad_interrupt)
-
-		.text
 		.align  5
 LEAF(spurious_interrupt)
 		/*
@@ -146,10 +93,8 @@
 		 */
 		lui     t1,%hi(spurious_count)
 		lw      t0,%lo(spurious_count)(t1)
-		la      v0,return
 		addiu   t0,1
-
-		jr      ra
+		j	ret_from_irq
 		 sw      t0,%lo(spurious_count)(t1)
 		END(spurious_interrupt)
 
@@ -169,7 +114,7 @@
 		REG_S	t0,PT_BVADDR(sp);
 #define __BUILD_silent(exception)
 
-#define fmt "Got %s at %016Lx.\n"
+#define fmt "Got %s at %08lx.\n"
 
 #define __BUILD_verbose(exception)                                      \
 		la	a1,8f;                                          \
@@ -218,21 +163,6 @@
 		BUILD_HANDLER(watch,watch,none,verbose)		/* #23 */
 		BUILD_HANDLER(vced,vced,none,verbose)		/* #31 */
 		BUILD_HANDLER(reserved,reserved,none,verbose)	/* others */
-
-/*
- * Exception handler table with 32 entries.
- * This might be extended to handle software exceptions
- */
-		.bss
-		.align	PTRLOG
-EXPORT(exception_handlers)
-		.fill	32,PTRSIZE,0
-
-/*
- * Interrupt handler table with 16 entries.
- */
-EXPORT(IRQ_vectors)
-		.fill	16,PTRSIZE,0
 
 /*
  * Table of syscalls
diff -u --recursive --new-file v2.1.72/linux/arch/mips/kernel/fpe.c linux/arch/mips/kernel/fpe.c
--- v2.1.72/linux/arch/mips/kernel/fpe.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/kernel/fpe.c	Wed Dec 10 10:31:09 1997
@@ -0,0 +1,55 @@
+/*
+ * The real floating point exception handler.  While it doesn't really
+ * make sense to have this in a module, it makes debugging of this code
+ * in the kernel space a lot easier.  So far this handler in the released
+ * kernel source is just a dummy.
+ *
+ * Copyright (C) 1997 Ralf Baechle
+ *
+ * $Id: fpe.c,v 1.1 1997/08/11 04:17:18 ralf Exp $
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+
+#include <asm/branch.h>
+#include <asm/ptrace.h>
+
+MODULE_AUTHOR("Ralf Baechle <ralf@gnu.ai.mit.edu>");
+MODULE_DESCRIPTION("Experimental floating point exception handler");
+MODULE_SUPPORTED_DEVICE("MIPS FPU");
+
+static void do_fpe(struct pt_regs *regs, unsigned int fcr31)
+{
+	lock_kernel();
+#ifdef CONF_DEBUG_EXCEPTIONS
+	show_regs(regs);
+#endif
+	printk("Caught floating exception at epc == %08lx, fcr31 == %08x\n",
+	       regs->cp0_epc, fcr31);
+	if (compute_return_epc(regs))
+		goto out;
+	force_sig(SIGFPE, current);
+out:
+	unlock_kernel();
+}
+
+/*
+ * For easier experimentation we never increment/decrement
+ * the module useable counter.
+ */
+int register_fpe(void (*handler)(struct pt_regs *regs, unsigned int fcr31));
+int unregister_fpe(void (*handler)(struct pt_regs *regs, unsigned int fcr31));
+
+int init_module(void)
+{
+	return register_fpe(do_fpe);
+}
+
+void cleanup_module(void)
+{
+	unregister_fpe(do_fpe);
+}
diff -u --recursive --new-file v2.1.72/linux/arch/mips/kernel/gdb-low.S linux/arch/mips/kernel/gdb-low.S
--- v2.1.72/linux/arch/mips/kernel/gdb-low.S	Thu Jun 26 12:33:37 1997
+++ linux/arch/mips/kernel/gdb-low.S	Wed Dec 10 10:31:09 1997
@@ -4,6 +4,8 @@
  * gdb-low.S contains the low-level trap handler for the GDB stub.
  *
  * Copyright (C) 1995 Andreas Busse
+ *
+ * $Id: gdb-low.S,v 1.3 1997/12/02 05:51:05 ralf Exp $
  */
 
 #include <linux/sys.h>
@@ -40,7 +42,7 @@
 		sw	v0,GDB_FR_REG2(sp)
 
 /*
- * first save the CP0 and special registers
+ * First save the CP0 and special registers
  */
 
 		mfc0	v0,CP0_STATUS
@@ -93,12 +95,12 @@
 		sw	fp,GDB_FR_REG30(sp)
 		sw	ra,GDB_FR_REG31(sp)
 
-		STI				/* disable interrupts */
+		CLI				/* disable interrupts */
 		
 /*
  * Followed by the floating point registers
  */
-		mfc0	v0,CP0_STATUS		/* check if the FPU is enabled */
+		mfc0	v0,CP0_STATUS		/* FPU enabled? */
 		srl	v0,v0,16
 		andi	v0,v0,(ST0_CU1 >> 16)
 
@@ -148,7 +150,7 @@
 		sw	v0,GDB_FR_FIR(sp)
 
 /*
- * current stack frame ptr
+ * Current stack frame ptr
  */
 
 2:
@@ -166,6 +168,8 @@
 		sw	v0,GDB_FR_CP0_ENTRYLO0(sp)
 		mfc0	v0,CP0_ENTRYLO1
 		sw	v0,GDB_FR_CP0_ENTRYLO1(sp)
+		mfc0	v0,CP0_CONTEXT
+		sw	v0,GDB_FR_CP0_CONTEXT(sp)
 		mfc0	v0,CP0_PAGEMASK
 		sw	v0,GDB_FR_CP0_PAGEMASK(sp)
 		mfc0	v0,CP0_WIRED
@@ -178,7 +182,7 @@
 		.set	at
 
 /*
- * continue with the higher level handler
+ * Continue with the higher level handler
  */
 
 		move	a0,sp
@@ -187,7 +191,7 @@
 		 nop
 
 /*
- * restore all writable registers, in reverse order
+ * Restore all writable registers, in reverse order
  */
 
 		.set	noat
@@ -203,7 +207,10 @@
 		lw	v0,GDB_FR_CP0_ENTRYLO0(sp)
 		lw	v1,GDB_FR_CP0_INDEX(sp)
 		mtc0	v0,CP0_ENTRYLO0
+		lw	v0,GDB_FR_CP0_CONTEXT(sp)
 		mtc0	v1,CP0_INDEX
+		mtc0	v0,CP0_CONTEXT
+		
 
 /*
  * Next, the floating point registers
@@ -298,9 +305,9 @@
 		lw	$1,GDB_FR_REG1(sp)
 		lw	sp,GDB_FR_REG29(sp)		/* Deallocate stack */
 
+		.set	mips3
 		eret
+		.set	mips0
 		.set	at
 		.set	reorder
 		END(trap_low)
-
-/* end of file gdb-low.S */
diff -u --recursive --new-file v2.1.72/linux/arch/mips/kernel/gdb-stub.c linux/arch/mips/kernel/gdb-stub.c
--- v2.1.72/linux/arch/mips/kernel/gdb-stub.c	Mon Aug 18 18:19:42 1997
+++ linux/arch/mips/kernel/gdb-stub.c	Wed Dec 10 10:31:09 1997
@@ -12,7 +12,7 @@
  *
  *  Copyright (C) 1995 Andreas Busse
  *
- * $Id: gdb-stub.c,v 1.5 1997/08/08 18:12:15 miguel Exp $
+ * $Id: gdb-stub.c,v 1.4 1997/12/02 05:51:06 ralf Exp $
  */
 
 /*
@@ -77,6 +77,7 @@
 #include <asm/pgtable.h>
 #include <asm/system.h>
 #include <asm/gdb-stub.h>
+#include <asm/inst.h>
 
 /*
  * external low-level support routines
@@ -450,6 +451,122 @@
 #endif /* dead code */
 
 /*
+ * We single-step by setting breakpoints. When an exception
+ * is handled, we need to restore the instructions hoisted
+ * when the breakpoints were set.
+ *
+ * This is where we save the original instructions.
+ */
+static struct gdb_bp_save {
+	unsigned int addr;
+        unsigned int val;
+} step_bp[2];
+
+#define BP 0x0000000d  /* break opcode */
+
+/*
+ * Set breakpoint instructions for single stepping.
+ */
+static void single_step(struct gdb_regs *regs)
+{
+	union mips_instruction insn;
+	unsigned int targ;
+	int is_branch, is_cond, i;
+
+	targ = regs->cp0_epc;
+	insn.word = *(unsigned int *)targ;
+	is_branch = is_cond = 0;
+
+	switch (insn.i_format.opcode) {
+	/*
+	 * jr and jalr are in r_format format.
+	 */
+	case spec_op:
+		switch (insn.r_format.func) {
+		case jalr_op:
+		case jr_op:
+			targ = *(&regs->reg0 + insn.r_format.rs);
+			is_branch = 1;
+			break;
+		}
+		break;
+
+	/*
+	 * This group contains:
+	 * bltz_op, bgez_op, bltzl_op, bgezl_op,
+	 * bltzal_op, bgezal_op, bltzall_op, bgezall_op.
+	 */
+	case bcond_op:
+		is_branch = is_cond = 1;
+		targ += 4 + (insn.i_format.simmediate << 2);
+		break;
+
+	/*
+	 * These are unconditional and in j_format.
+	 */
+	case jal_op:
+	case j_op:
+		is_branch = 1;
+		targ += 4;
+		targ >>= 28;
+		targ <<= 28;
+		targ |= (insn.j_format.target << 2);
+		break;
+
+	/*
+	 * These are conditional.
+	 */
+	case beq_op:
+	case beql_op:
+	case bne_op:
+	case bnel_op:
+	case blez_op:
+	case blezl_op:
+	case bgtz_op:
+	case bgtzl_op:
+	case cop0_op:
+	case cop1_op:
+	case cop2_op:
+	case cop1x_op:
+		is_branch = is_cond = 1;
+		targ += 4 + (insn.i_format.simmediate << 2);
+		break;
+	}
+				
+	if (is_branch) {
+		i = 0;
+		if (is_cond && targ != (regs->cp0_epc + 8)) {
+			step_bp[i].addr = regs->cp0_epc + 8;
+			step_bp[i++].val = *(unsigned *)(regs->cp0_epc + 8);
+			*(unsigned *)(regs->cp0_epc + 8) = BP;
+		}
+		step_bp[i].addr = targ;
+		step_bp[i].val  = *(unsigned *)targ;
+		*(unsigned *)targ = BP;
+	} else {
+		step_bp[0].addr = regs->cp0_epc + 4;
+		step_bp[0].val  = *(unsigned *)(regs->cp0_epc + 4);
+		*(unsigned *)(regs->cp0_epc + 4) = BP;
+	}
+}
+
+/*
+ *  If asynchronously interrupted by gdb, then we need to set a breakpoint
+ *  at the interrupted instruction so that we wind up stopped with a 
+ *  reasonable stack frame.
+ */
+static struct gdb_bp_save async_bp;
+
+void set_async_breakpoint(unsigned int epc)
+{
+	async_bp.addr = epc;
+	async_bp.val  = *(unsigned *)epc;
+	*(unsigned *)epc = BP;
+	flush_cache_all();
+}
+
+
+/*
  * This function does all command processing for interfacing to gdb.  It
  * returns 1 if you should skip the instruction at the trap address, 0
  * otherwise.
@@ -490,6 +607,30 @@
 	if (trap == 9 && regs->cp0_epc == (unsigned long)breakinst)		
 		regs->cp0_epc += 4;
 
+	/*
+	 * If we were single_stepping, restore the opcodes hoisted
+	 * for the breakpoint[s].
+	 */
+	if (step_bp[0].addr) {
+		*(unsigned *)step_bp[0].addr = step_bp[0].val;
+		step_bp[0].addr = 0;
+		    
+		if (step_bp[1].addr) {
+			*(unsigned *)step_bp[1].addr = step_bp[1].val;
+			step_bp[1].addr = 0;
+		}
+	}
+
+	/*
+	 * If we were interrupted asynchronously by gdb, then a
+	 * breakpoint was set at the EPC of the interrupt so
+	 * that we'd wind up here with an interesting stack frame.
+	 */
+	if (async_bp.addr) {
+		*(unsigned *)async_bp.addr = async_bp.val;
+		async_bp.addr = 0;
+	}
+
 	stack = (long *)regs->reg29;			/* stack ptr */
 	sigval = computeSignal(trap);
 
@@ -670,11 +811,16 @@
 
 		/*
 		 * Step to next instruction
-		 * FIXME: Needs to be written
 		 */
 		case 's':
-			strcpy (output_buffer, "S01");
-			break;
+			/*
+			 * There is no single step insn in the MIPS ISA, so we
+			 * use breakpoints and continue, instead.
+			 */
+			single_step(regs);
+			flush_cache_all();
+			return;
+			/* NOTREACHED */
 
 		/*
 		 * Set baud rate (bBB)
diff -u --recursive --new-file v2.1.72/linux/arch/mips/kernel/head.S linux/arch/mips/kernel/head.S
--- v2.1.72/linux/arch/mips/kernel/head.S	Mon Jul  7 08:18:53 1997
+++ linux/arch/mips/kernel/head.S	Wed Dec 10 10:31:09 1997
@@ -7,6 +7,8 @@
  *  Further modifications by David S. Miller
  *
  *  Head.S contains the MIPS exception handler and startup code.
+ *
+ * $Id: head.S,v 1.10 1997/11/13 12:55:29 ralf Exp $
  */
 #include <linux/config.h>
 #include <linux/tasks.h>
@@ -27,8 +29,10 @@
 	/*
 	 * Reserved space for exception handlers.
 	 * Necessary for machines which link their kernels at KSEG0.
+	 * FIXME: We could overwrite some of the useless handlers
+	 * with those actually being used.
 	 */
-	.fill	512
+	.fill	520
 /*	
  * This is space for the interrupt handlers.
  * After trap_init() they are located at virtual address KSEG0.
@@ -93,6 +97,34 @@
 	eret
 	END(except_vec0_r4600)
 
+	/* TLB refill, EXL == 0, R4xx0, non-R4600 version */
+	.set	noreorder
+	.set	noat
+	LEAF(except_vec0_nevada)
+	.set	mips3
+	mfc0	k0, CP0_BADVADDR		# Get faulting address
+	_GET_CURRENT(k1)			# get current task ptr
+	srl	k0, k0, 22			# get pgd only bits
+	lw	k1, THREAD_PGDIR(k1)		# get task pg_dir
+	sll	k0, k0, 2
+	addu	k1, k1, k0			# add in pgd offset
+	lw	k1, (k1)
+	mfc0	k0, CP0_CONTEXT			# get context reg
+	srl	k0, k0, 1			# get pte offset
+	and	k0, k0, 0xff8
+	addu	k1, k1, k0			# add in offset
+	lw	k0, 0(k1)			# get even pte
+	lw	k1, 4(k1)			# get odd pte
+	srl	k0, k0, 6			# convert to entrylo0
+	mtc0	k0, CP0_ENTRYLO0		# load it
+	srl	k1, k1, 6			# convert to entrylo1
+	mtc0	k1, CP0_ENTRYLO1		# load it
+	tlbwr					# write random tlb entry
+	nop
+	nop
+	eret					# return from trap
+	END(except_vec0_nevada)
+
 	/* TLB refill, EXL == 0, R4[40]00/R5000 badvaddr hwbug version */
 	LEAF(except_vec0_r45k_bvahwbug)
 	.set	mips3
@@ -109,6 +141,7 @@
 	addu	k1, k1, k0
 	lw	k0, 0(k1)
 	lw	k1, 4(k1)
+	nop				/* XXX */
 	tlbp
 	srl	k0, k0, 6
 	mtc0	k0, CP0_ENTRYLO0
@@ -139,6 +172,7 @@
 	addu	k1, k1, k0
 	lw	k0, 0(k1)
 	lw	k1, 4(k1)
+	nop				/* XXX */
 	tlbp
 	srl	k0, k0, 6
 	mtc0	k0, CP0_ENTRYLO0
@@ -199,6 +233,7 @@
 	addu	k1, k1, k0
 	lw	k0, 0(k1)
 	lw	k1, 4(k1)
+	nop				/* XXX */
 	tlbp
 	srl	k0, k0, 6
 	mtc0	zero, CP0_ENTRYLO0
@@ -309,6 +344,17 @@
 	END(except_vec3_generic)
 	.set	at
 
+	/*
+	 * Special interrupt vector for embedded MIPS.  This is a
+	 * dedicated interrupt vector which reduces interrupt processing
+	 * overhead.  The jump instruction will be inserted here at
+	 * initialization time.  This handler may only be 8 bytes in size!
+	 */
+	NESTED(except_vec4, 0, sp)
+1:	j	1b			/* Dummy, will be replaced */
+	 nop
+	END(except_vec4)
+
 /*
  * Kernel entry point
  */
@@ -350,6 +396,7 @@
 	jal	sgi_sysinit
 	 nop
 #endif
+
 	/* Get the very one tags we need early in the boot process */
 	nop
 	jal	bi_EarlySnarf
@@ -357,13 +404,10 @@
 #ifndef CONFIG_SGI
 	/* Clear BSS first so that there are no surprises... */
 	la	t0, _edata
-	la	t1, (_end - 4)
-	sw	zero, (t0)
-1:
-	addiu	t0, 4
+	la	t1, _end
+1:	addiu	t0, 1
 	bne	t0, t1, 1b
-	 sw	zero, (t0)
-	nop
+	sb	zero, -1(t0)
 #endif
 	/*
 	 * Determine the mmu/cache attached to this machine,
@@ -400,8 +444,9 @@
 	/*
 	 * Stack for kernel and init
 	 */
-9:	la	sp, init_task_union+(KERNEL_STACK_SIZE-4*SZREG)
-	sw	sp, kernelsp
+9:	la	t0, init_task_union+KERNEL_STACK_SIZE-32
+	sw	t0, kernelsp
+	subu	sp, t0, 4*SZREG
 
 	/* Disable coprocessors */
 	mfc0	t0, CP0_STATUS
@@ -601,6 +646,14 @@
 	 nop
 
 	li	t2, CPU_R5000
+	b	probe_done
+	 sw	t2, (t3)
+1:
+	li	t2, PRID_IMP_NEVADA
+	bne	t1, t2, 1f
+	 nop
+
+	li	t2, CPU_NEVADA
 	b	probe_done
 	 sw	t2, (t3)
 1:
diff -u --recursive --new-file v2.1.72/linux/arch/mips/kernel/irix5sys.h linux/arch/mips/kernel/irix5sys.h
--- v2.1.72/linux/arch/mips/kernel/irix5sys.h	Mon Aug 18 18:19:42 1997
+++ linux/arch/mips/kernel/irix5sys.h	Wed Dec 10 10:31:09 1997
@@ -1,4 +1,4 @@
-/* $Id: irix5sys.h,v 1.2 1997/08/08 18:12:17 miguel Exp $
+/* $Id: irix5sys.h,v 1.1.1.1 1997/06/01 03:16:43 ralf Exp $
  * irix5sys.h: 32-bit IRIX5 ABI system call table.
  *
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
diff -u --recursive --new-file v2.1.72/linux/arch/mips/kernel/irixelf.c linux/arch/mips/kernel/irixelf.c
--- v2.1.72/linux/arch/mips/kernel/irixelf.c	Sat Oct 25 02:44:14 1997
+++ linux/arch/mips/kernel/irixelf.c	Wed Dec 10 10:31:09 1997
@@ -826,13 +826,14 @@
 
 	/* Seek to the beginning of the file. */
 	if (file->f_op->llseek) {
-		if ((error = file->f_op->llseek(inode, file, 0, 0)) != 0)
+		if ((error = file->f_op->llseek(file, 0, 0)) != 0)
 			return -ENOEXEC;
 	} else
 		file->f_pos = 0;
 
 	set_fs(KERNEL_DS);
-	error = file->f_op->read(inode, file, (char *) &elf_ex, sizeof(elf_ex));
+	error = file->f_op->read(file, (char *) &elf_ex, sizeof(elf_ex),
+	                         &file->f_pos);
 	set_fs(USER_DS);
 	if (error != sizeof(elf_ex))
 		return -ENOEXEC;
@@ -987,13 +988,13 @@
  */
 static int dump_write(struct file *file, const void *addr, int nr)
 {
-	return file->f_op->write(file->f_dentry->d_inode, file, addr, nr) == nr;
+	return file->f_op->write(file, addr, nr, &file->f_pos) == nr;
 }
 
 static int dump_seek(struct file *file, off_t off)
 {
 	if (file->f_op->llseek) {
-		if (file->f_op->llseek(file->f_dentry->d_inode, file, off, 0) != off)
+		if (file->f_op->llseek(file, off, 0) != off)
 			return 0;
 	} else
 		file->f_pos = off;
diff -u --recursive --new-file v2.1.72/linux/arch/mips/kernel/irixinv.c linux/arch/mips/kernel/irixinv.c
--- v2.1.72/linux/arch/mips/kernel/irixinv.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/kernel/irixinv.c	Wed Dec 10 10:31:09 1997
@@ -0,0 +1,81 @@
+/*
+ * Support the inventory interface for IRIX binaries
+ * This is invoked before the mm layer is working, so we do not
+ * use the linked lists for the inventory yet. 
+ *
+ * Miguel de Icaza, 1997.
+ *
+ * $Id: irixinv.c,v 1.2 1997/12/06 21:29:58 ralf Exp $
+ */
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <asm/uaccess.h>
+#include <asm/inventory.h>
+
+#define MAX_INVENTORY 50
+int inventory_items = 0;
+
+static inventory_t inventory [MAX_INVENTORY];
+
+void
+add_to_inventory (int class, int type, int controller, int unit, int state)
+{
+	inventory_t *ni = &inventory [inventory_items];
+
+	if (inventory_items == MAX_INVENTORY)
+		return;
+	
+	ni->inv_class      = class;
+	ni->inv_type       = type;
+	ni->inv_controller = controller;
+	ni->inv_unit       = unit;
+	ni->inv_state      = state;
+	ni->inv_next       = ni;
+	inventory_items++;
+}
+
+int
+dump_inventory_to_user (void *userbuf, int size)
+{
+	inventory_t *inv  = &inventory [0];
+	inventory_t *user = userbuf;
+	int v;
+
+	if ((v = verify_area (VERIFY_WRITE, userbuf, size)))
+		return v;
+
+	for (v = 0; v < inventory_items; v++){
+		inv = &inventory [v];
+		copy_to_user (user, inv, sizeof (inventory_t));
+		user++;
+	}
+	return inventory_items * sizeof (inventory_t);
+}
+
+void
+init_inventory (void)
+{
+	/* gross hack while we put the right bits all over the kernel
+	 * most likely this will not let just anyone run the X server
+	 * until we put the right values all over the place
+	 */
+	 
+	add_to_inventory (10, 3, 0, 0, 16400);
+	add_to_inventory (1, 1, 150, -1, 12);
+	add_to_inventory (1, 3, 0, 0, 8976);
+	add_to_inventory (1, 2, 0, 0, 8976);
+	add_to_inventory (4, 8, 0, 0, 2);
+	add_to_inventory (5, 5, 0, 0, 1);
+	add_to_inventory (3, 3, 0, 0, 32768);
+	add_to_inventory (3, 4, 0, 0, 32768);
+	add_to_inventory (3, 8, 0, 0, 524288);
+	add_to_inventory (3, 9, 0, 0, 64);
+	add_to_inventory (3, 1, 0, 0, 67108864);
+	add_to_inventory (12, 3, 0, 0, 16);
+	add_to_inventory (8, 7, 17, 0, 16777472);
+	add_to_inventory (8, 0, 0, 0, 1);
+	add_to_inventory (2, 1, 0, 13, 2);
+	add_to_inventory (2, 2, 0, 2, 0);
+	add_to_inventory (2, 2, 0, 1, 0);
+	add_to_inventory (7, 14, 0, 0, 6);
+}
diff -u --recursive --new-file v2.1.72/linux/arch/mips/kernel/irixioctl.c linux/arch/mips/kernel/irixioctl.c
--- v2.1.72/linux/arch/mips/kernel/irixioctl.c	Mon Aug 18 18:19:42 1997
+++ linux/arch/mips/kernel/irixioctl.c	Wed Dec 10 10:31:09 1997
@@ -1,4 +1,4 @@
-/* $Id: irixioctl.c,v 1.2 1997/08/08 18:12:19 miguel Exp $
+/* $Id: irixioctl.c,v 1.2 1997/12/02 05:51:06 ralf Exp $
  * irixioctl.c: A fucking mess...
  *
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
@@ -17,6 +17,7 @@
 #include <asm/ioctls.h>
 
 #undef DEBUG_IOCTLS
+#undef DEBUG_MISSING_IOCTL
 
 struct irix_termios {
 	tcflag_t c_iflag, c_oflag, c_cflag, c_lflag;
@@ -235,6 +236,7 @@
 		break;
 
 	default: {
+#ifdef DEBUG_MISSING_IOCTL
 		char *msg = "Unimplemented IOCTL cmd tell dm@engr.sgi.com\n";
 
 #ifdef DEBUG_IOCTLS
@@ -246,6 +248,9 @@
 		printk("[%s:%d] Does unimplemented IRIX ioctl cmd %08lx\n",
 		       current->comm, current->pid, cmd);
 		do_exit(255);
+#else
+		error = sys_ioctl (fd, cmd, arg);
+#endif
 	}
 
 	};
diff -u --recursive --new-file v2.1.72/linux/arch/mips/kernel/irixsig.c linux/arch/mips/kernel/irixsig.c
--- v2.1.72/linux/arch/mips/kernel/irixsig.c	Wed Sep 24 20:05:45 1997
+++ linux/arch/mips/kernel/irixsig.c	Wed Dec 10 10:31:09 1997
@@ -1,4 +1,4 @@
-/* $Id: irixsig.c,v 1.4 1997/08/08 18:12:21 miguel Exp $
+/* $Id: irixsig.c,v 1.5 1997/12/06 09:57:38 ralf Exp $
  * irixsig.c: WHEEE, IRIX signals!  YOW, am I compatable or what?!?!
  *
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
diff -u --recursive --new-file v2.1.72/linux/arch/mips/kernel/irq.c linux/arch/mips/kernel/irq.c
--- v2.1.72/linux/arch/mips/kernel/irq.c	Mon Aug 18 18:19:42 1997
+++ linux/arch/mips/kernel/irq.c	Wed Dec 10 10:31:09 1997
@@ -1,19 +1,11 @@
 /*
- *	linux/arch/mips/kernel/irq.c
+ * Code to handle x86 style IRQs plus some generic interrupt stuff.
  *
- *	Copyright (C) 1992 Linus Torvalds
+ * Copyright (C) 1992 Linus Torvalds
+ * Copyright (C) 1994, 1995, 1996, 1997 Ralf Baechle
  *
- * This file contains the code used by various IRQ handling routines:
- * asking for different IRQ's should be done through these routines
- * instead of just grabbing them. Thus setups with different IRQ numbers
- * shouldn't result in any weird surprises, and installing new handlers
- * should be easier.
- *
- * Mips support by Ralf Baechle and Andreas Busse
- *
- * $Id: irq.c,v 1.7 1997/08/08 18:12:24 miguel Exp $
+ * $Id: irq.c,v 1.7 1997/09/26 11:51:33 ralf Exp $
  */
-#include <linux/config.h>
 #include <linux/errno.h>
 #include <linux/init.h>
 #include <linux/kernel_stat.h>
@@ -30,13 +22,9 @@
 #include <asm/bootinfo.h>
 #include <asm/io.h>
 #include <asm/irq.h>
-#include <asm/jazz.h>
 #include <asm/mipsregs.h>
 #include <asm/system.h>
 #include <asm/vector.h>
-#ifdef CONFIG_SGI
-#include <asm/sgialib.h>
-#endif
 
 unsigned char cache_21 = 0xff;
 unsigned char cache_A1 = 0xff;
@@ -51,9 +39,6 @@
 static inline void mask_irq(unsigned int irq_nr)
 {
 	unsigned char mask;
-    
-        if (irq_nr >= 16)
-	    return;
 
 	mask = 1 << (irq_nr & 7);
 	if (irq_nr < 8) {
@@ -69,9 +54,6 @@
 {
 	unsigned char mask;
 
-        if (irq_nr >= 16)
-	    return;
-
 	mask = ~(1 << (irq_nr & 7));
 	if (irq_nr < 8) {
 		cache_21 &= mask;
@@ -104,8 +86,6 @@
  * fast ones, then the bad ones.
  */
 extern void interrupt(void);
-extern void fast_interrupt(void);
-extern void bad_interrupt(void);
 
 static struct irqaction *irq_action[32] = {
 	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
@@ -139,13 +119,6 @@
 
 atomic_t __mips_bh_counter;
 
-#ifdef __SMP__
-#error Send superfluous SMP boxes to ralf@uni-koblenz.de
-#else
-#define irq_enter(cpu, irq)     (++local_irq_count[cpu])
-#define irq_exit(cpu, irq)      (--local_irq_count[cpu])
-#endif
-
 /*
  * do_IRQ handles IRQ's that have been installed without the
  * SA_INTERRUPT flag: it uses the full signal-handling return
@@ -155,48 +128,45 @@
  */
 asmlinkage void do_IRQ(int irq, struct pt_regs * regs)
 {
-	struct irqaction * action = *(irq + irq_action);
-	int do_random, cpu = smp_processor_id();
+	struct irqaction *action;
+	int do_random, cpu;
 
+	cpu = smp_processor_id();
 	irq_enter(cpu, irq);
 	kstat.interrupts[irq]++;
 
-	/* slow interrupts run with interrupts enabled */
-	sti();
-	action = *(irq + irq_action);
-	do_random = 0;
-        while (action) {
-		do_random |= action->flags;
-		action->handler(irq, action->dev_id, regs);
-		action = action->next;
-        }
-	if (do_random & SA_SAMPLE_RANDOM)
-		add_interrupt_randomness(irq);
-	irq_exit(cpu, irq);
-}
+	/*
+	 * mask and ack quickly, we don't want the irq controller
+	 * thinking we're snobs just because some other CPU has
+	 * disabled global interrupts (we have already done the
+	 * INT_ACK cycles, it's too late to try to pretend to the
+	 * controller that we aren't taking the interrupt).
+	 *
+	 * Commented out because we've already done this in the
+	 * machinespecific part of the handler.  It's reasonable to
+	 * do this here in a highlevel language though because that way
+	 * we could get rid of a good part of duplicated code ...
+	 */
+        /* mask_and_ack_irq(irq); */
 
-/*
- * do_fast_IRQ handles IRQ's that don't need the fancy interrupt return
- * stuff - the handler is also running with interrupts disabled unless
- * it explicitly enables them later.
- */
-asmlinkage void do_fast_IRQ(int irq)
-{
-	struct irqaction * action;
-	int do_random, cpu = smp_processor_id();
-
-	irq_enter(cpu, irq);
-	kstat.interrupts[irq]++;
 	action = *(irq + irq_action);
-	do_random = 0;
-	while (action) {
-		do_random |= action->flags;
-		action->handler(irq, action->dev_id, NULL);
-		action = action->next;
+	if (action) {
+		if (!(action->flags & SA_INTERRUPT))
+			__sti();
+		action = *(irq + irq_action);
+		do_random = 0;
+        	do {
+			do_random |= action->flags;
+			action->handler(irq, action->dev_id, regs);
+			action = action->next;
+        	} while (action);
+		if (do_random & SA_SAMPLE_RANDOM)
+			add_interrupt_randomness(irq);
+		__cli();
 	}
-	if (do_random & SA_SAMPLE_RANDOM)
-		add_interrupt_randomness(irq);
 	irq_exit(cpu, irq);
+
+	/* unmasking and bottom half handling is done magically for us. */
 }
 
 /*
@@ -236,10 +206,6 @@
 	*p = new;
 
 	if (!shared) {
-		if (new->flags & SA_INTERRUPT)
-			set_int_vector(irq,fast_interrupt);
-		else
-			set_int_vector(irq,interrupt);
 		unmask_irq(irq);
 	}
 	restore_flags(flags);
@@ -255,7 +221,7 @@
 	int retval;
 	struct irqaction * action;
 
-	if (irq > 31)
+	if (irq >= 32)
 		return -EINVAL;
 	if (!handler)
 		return -EINVAL;
@@ -294,10 +260,8 @@
 		/* Found it - now free it */
 		save_and_cli(flags);
 		*p = action->next;
-		if (!irq[irq_action]) {
+		if (!irq[irq_action])
 			mask_irq(irq);
-			set_int_vector(irq, bad_interrupt);
-		}
 		restore_flags(flags);
 		kfree(action);
 		return;
@@ -346,9 +310,5 @@
 
 __initfunc(void init_IRQ(void))
 {
-	int i;
-
-	for (i = 0; i < 32 ; i++)
-		set_int_vector(i, bad_interrupt);
 	irq_setup();
 }
diff -u --recursive --new-file v2.1.72/linux/arch/mips/kernel/mips_ksyms.c linux/arch/mips/kernel/mips_ksyms.c
--- v2.1.72/linux/arch/mips/kernel/mips_ksyms.c	Mon Aug 18 18:19:42 1997
+++ linux/arch/mips/kernel/mips_ksyms.c	Wed Dec 10 10:31:09 1997
@@ -7,7 +7,7 @@
  *
  * Copyright (C) 1996, 1997 by Ralf Baechle
  *
- * $Id: mips_ksyms.c,v 1.2 1997/08/08 18:12:26 miguel Exp $
+ * $Id: mips_ksyms.c,v 1.4 1997/08/11 04:17:18 ralf Exp $
  */
 #include <linux/config.h>
 #include <linux/module.h>
@@ -62,12 +62,38 @@
  */
 EXPORT_SYMBOL(flush_page_to_ram);
 EXPORT_SYMBOL(fd_cacheflush);
+EXPORT_SYMBOL(flush_cache_all);
 
 /*
  * Base address of ports for Intel style I/O.
  */
-EXPORT_SYMBOL(port_base);
+EXPORT_SYMBOL(mips_io_port_base);
+
+/*
+ * Architecture specific stuff.
+ */
+#ifdef CONFIG_MIPS_JAZZ
+EXPORT_SYMBOL(vdma_alloc);
+EXPORT_SYMBOL(vdma_free);
+EXPORT_SYMBOL(vdma_log2phys);
+#endif
 
 #ifdef CONFIG_SGI
 EXPORT_SYMBOL(hpc3c0);
+#endif
+
+/*
+ * Kernel hacking ...
+ */
+#include <asm/branch.h>
+#include <linux/sched.h>
+
+int register_fpe(void (*handler)(struct pt_regs *regs, unsigned int fcr31));
+int unregister_fpe(void (*handler)(struct pt_regs *regs, unsigned int fcr31));
+
+#ifdef CONFIG_MIPS_FPE_MODULE
+EXPORT_SYMBOL(force_sig);
+EXPORT_SYMBOL(__compute_return_epc);
+EXPORT_SYMBOL(register_fpe);
+EXPORT_SYMBOL(unregister_fpe);
 #endif
diff -u --recursive --new-file v2.1.72/linux/arch/mips/kernel/pci.c linux/arch/mips/kernel/pci.c
--- v2.1.72/linux/arch/mips/kernel/pci.c	Thu Jun 26 12:33:37 1997
+++ linux/arch/mips/kernel/pci.c	Wed Dec 10 10:31:09 1997
@@ -13,7 +13,9 @@
 #include <linux/types.h>
 #include <asm/pci.h>
 
-#ifndef CONFIG_PCI
+#ifdef CONFIG_PCI
+
+struct pci_ops *pci_ops;
 
 /*
  * BIOS32 replacement.
@@ -24,15 +26,13 @@
 	return memory_start;
 }
 
-#else /* defined(CONFIG_PCI) */
-
 /*
  * Following the generic parts of the MIPS BIOS32 code.
  */
 
 int pcibios_present (void)
 {
-	return _pcibios_init != NULL;
+	return pci_ops != NULL;
 }
 
 /*
@@ -82,99 +82,51 @@
 	return PCIBIOS_DEVICE_NOT_FOUND;
 }
 
-const char *pcibios_strerror (int error)
-{
-	static char buf[80];
-
-	switch (error) {
-	case PCIBIOS_SUCCESSFUL:
-		return "SUCCESSFUL";
-
-	case PCIBIOS_FUNC_NOT_SUPPORTED:
-		return "FUNC_NOT_SUPPORTED";
-
-	case PCIBIOS_BAD_VENDOR_ID:
-		return "SUCCESSFUL";
-
-	case PCIBIOS_DEVICE_NOT_FOUND:
-		return "DEVICE_NOT_FOUND";
-
-	case PCIBIOS_BAD_REGISTER_NUMBER:
-		return "BAD_REGISTER_NUMBER";
-
-	default:
-		sprintf (buf, "UNKNOWN RETURN 0x%x", error);
-		return buf;
-	}
-}
-
 /*
  * The functions below are machine specific and must be reimplented for
  * each PCI chipset configuration.  We just run the hook to the machine
  * specific implementation.
  */
-unsigned long (*_pcibios_init)(unsigned long memory_start, unsigned long memory_end);
-__initfunc(unsigned long pcibios_init(unsigned long memory_start,
-                                      unsigned long memory_end))
-{
-	return _pcibios_init ? _pcibios_init(memory_start, memory_end)
-	                     : memory_start;
-}
-
-unsigned long (*_pcibios_fixup) (unsigned long memory_start,
-                                 unsigned long memory_end);
 unsigned long pcibios_fixup (unsigned long memory_start,
                              unsigned long memory_end)
 {
-	return _pcibios_fixup(memory_start, memory_end);
+	return pci_ops->pcibios_fixup(memory_start, memory_end);
 }
 
-int (*_pcibios_read_config_byte) (unsigned char bus, unsigned char dev_fn,
-                                  unsigned char where, unsigned char *val);
 int pcibios_read_config_byte (unsigned char bus, unsigned char dev_fn,
                               unsigned char where, unsigned char *val)
 {
-	return _pcibios_read_config_byte(bus, dev_fn, where, val);
+	return pci_ops->pcibios_read_config_byte(bus, dev_fn, where, val);
 }
 
-int (*_pcibios_read_config_word) (unsigned char bus, unsigned char dev_fn,
-                                  unsigned char where, unsigned short *val);
 int pcibios_read_config_word (unsigned char bus, unsigned char dev_fn,
                               unsigned char where, unsigned short *val)
 {
-	return _pcibios_read_config_word(bus, dev_fn, where, val);
+	return pci_ops->pcibios_read_config_word(bus, dev_fn, where, val);
 }
 
-int (*_pcibios_read_config_dword) (unsigned char bus, unsigned char dev_fn,
-                                   unsigned char where, unsigned int *val);
 int pcibios_read_config_dword (unsigned char bus, unsigned char dev_fn,
                                unsigned char where, unsigned int *val)
 {
-	return _pcibios_read_config_dword(bus, dev_fn, where, val);
+	return pci_ops->pcibios_read_config_dword(bus, dev_fn, where, val);
 }
 
-int (*_pcibios_write_config_byte) (unsigned char bus, unsigned char dev_fn,
-                                   unsigned char where, unsigned char val);
 int pcibios_write_config_byte (unsigned char bus, unsigned char dev_fn,
                                unsigned char where, unsigned char val)
 {
-	return _pcibios_write_config_byte(bus, dev_fn, where, val);
+	return pci_ops->pcibios_write_config_byte(bus, dev_fn, where, val);
 }
 
-int (*_pcibios_write_config_word) (unsigned char bus, unsigned char dev_fn,
-                                   unsigned char where, unsigned short val);
 int pcibios_write_config_word (unsigned char bus, unsigned char dev_fn,
                                unsigned char where, unsigned short val)
 {
-	return _pcibios_write_config_word(bus, dev_fn, where, val);
+	return pci_ops->pcibios_write_config_word(bus, dev_fn, where, val);
 }
 
-int (*_pcibios_write_config_dword) (unsigned char bus, unsigned char dev_fn,
-                                    unsigned char where, unsigned int val);
 int pcibios_write_config_dword (unsigned char bus, unsigned char dev_fn,
                                 unsigned char where, unsigned int val)
 {
-	return _pcibios_write_config_dword(bus, dev_fn, where, val);
+	return pci_ops->pcibios_write_config_dword(bus, dev_fn, where, val);
 }
 
 #endif /* defined(CONFIG_PCI) */
diff -u --recursive --new-file v2.1.72/linux/arch/mips/kernel/proc.c linux/arch/mips/kernel/proc.c
--- v2.1.72/linux/arch/mips/kernel/proc.c	Thu Jun 26 12:33:37 1997
+++ linux/arch/mips/kernel/proc.c	Wed Dec 10 10:31:09 1997
@@ -5,11 +5,12 @@
  */
 #include <linux/delay.h>
 #include <linux/kernel.h>
+#include <linux/sched.h>
 #include <asm/bootinfo.h>
 #include <asm/mipsregs.h>
+#include <asm/processor.h>
+#include <asm/watch.h>
 
-unsigned long dflushes = 0;
-unsigned long iflushes = 0;
 unsigned long unaligned_instructions;
 
 /*
@@ -27,8 +28,15 @@
 	const char *mach_dec_names[] = GROUP_DEC_NAMES;
 	const char *mach_arc_names[] = GROUP_ARC_NAMES;
 	const char *mach_sni_rm_names[] = GROUP_SNI_RM_NAMES;
-	const char **mach_group_to_name[] = { mach_unknown_names, mach_jazz_names,
-					    mach_dec_names, mach_arc_names, mach_sni_rm_names};
+	const char *mach_acn_names[] = GROUP_ACN_NAMES;
+	const char *mach_sgi_names[] = GROUP_SGI_NAMES;
+	const char **mach_group_to_name[] = { mach_unknown_names,
+	                                      mach_jazz_names,
+	                                      mach_dec_names,
+	                                      mach_arc_names,
+	                                      mach_sni_rm_names,
+	                                      mach_acn_names,
+	                                      mach_sgi_names };
 	unsigned int version = read_32bit_cp0_register(CP0_PRID);
 	int len;
 
@@ -51,12 +59,16 @@
 #if defined (__MIPSEL__)
 	len += sprintf(buffer + len, "byteorder\t\t: little endian\n");
 #endif
-	len += sprintf(buffer + len, "D-cache flushes\t\t: %lu\n",
-		       dflushes);
-	len += sprintf(buffer + len, "I-cache flushes\t\t: %lu\n",
-		       iflushes);
 	len += sprintf(buffer + len, "unaligned accesses\t: %lu\n",
 		       unaligned_instructions);
+	len += sprintf(buffer + len, "wait instruction\t: %s\n",
+	               wait_available ? "yes" : "no");
+	len += sprintf(buffer + len, "microsecond timers\t: %s\n",
+	               cyclecounter_available ? "yes" : "no");
+	len += sprintf(buffer + len, "extra interrupt vector\t: %s\n",
+	               dedicated_iv_available ? "yes" : "no");
+	len += sprintf(buffer + len, "hardware watchpoint\t: %s\n",
+	               watch_available ? "yes" : "no");
 
 	return len;
 }
diff -u --recursive --new-file v2.1.72/linux/arch/mips/kernel/process.c linux/arch/mips/kernel/process.c
--- v2.1.72/linux/arch/mips/kernel/process.c	Thu Jun 26 12:33:37 1997
+++ linux/arch/mips/kernel/process.c	Wed Dec 10 10:31:09 1997
@@ -70,10 +70,10 @@
 	struct pt_regs * childregs;
 	long childksp;
 
-	childksp = (unsigned long)p + KERNEL_STACK_SIZE - 8;
+	childksp = (unsigned long)p + KERNEL_STACK_SIZE - 32;
 
 	/* set up new TSS. */
-	childregs = ((struct pt_regs *) ((unsigned long)p + KERNEL_STACK_SIZE)) - 1;
+	childregs = (struct pt_regs *) childksp - 1;
 	*childregs = *regs;
 	childregs->regs[7] = 0;	/* Clear error flag */
 	if(current->personality == PER_LINUX) {
diff -u --recursive --new-file v2.1.72/linux/arch/mips/kernel/ptrace.c linux/arch/mips/kernel/ptrace.c
--- v2.1.72/linux/arch/mips/kernel/ptrace.c	Mon Aug 18 18:19:42 1997
+++ linux/arch/mips/kernel/ptrace.c	Wed Dec 10 10:31:09 1997
@@ -59,12 +59,15 @@
 		goto repeat;
 	}
 	page = pte_page(*pgtable);
-/* this is a hack for non-kernel-mapped video buffers and similar */
+	/* This is a hack for non-kernel-mapped video buffers and similar */
 	if (MAP_NR(page) >= MAP_NR(high_memory))
 		return 0;
 	page += addr & ~PAGE_MASK;
+	/* We can't use flush_page_to_ram() since we're running in
+	 * another context ...
+	 */
+	flush_cache_all();
 	retval = *(unsigned long *) page;
-	flush_page_to_ram(page);
 	return retval;
 }
 
@@ -117,14 +120,17 @@
 		handle_mm_fault(tsk, vma, addr, 1);
 		goto repeat;
 	}
-/* this is a hack for non-kernel-mapped video buffers and similar */
-	flush_cache_page(vma, addr);
-	if (MAP_NR(page) < MAP_NR(high_memory)) {
-		*(unsigned long *) (page + (addr & ~PAGE_MASK)) = data;
+	/* This is a hack for non-kernel-mapped video buffers and similar */
+	if (MAP_NR(page) < MAP_NR(high_memory))
+		flush_cache_page(vma, addr);
+	*(unsigned long *) (page + (addr & ~PAGE_MASK)) = data;
+	if (MAP_NR(page) < MAP_NR(high_memory))
 		flush_page_to_ram(page);
-	}
-/* we're bypassing pagetables, so we have to set the dirty bit ourselves */
-/* this should also re-instate whatever read-only mode there was before */
+	/*
+	 * We're bypassing pagetables, so we have to set the dirty bit
+	 * ourselves this should also re-instate whatever read-only mode
+	 * there was before
+	 */
 	set_pte(pgtable, pte_mkdirty(mk_pte(page, vma->vm_page_prot)));
 	flush_tlb_page(vma, addr);
 }
@@ -369,7 +375,7 @@
 				case 5:
 					tmp = child->tss.fpu.hard.control;
 					break;
-				case 6:
+				case 6:	/* implementation / version register */
 					tmp = 0;
 					break;
 				default:
diff -u --recursive --new-file v2.1.72/linux/arch/mips/kernel/r2300_fpu.S linux/arch/mips/kernel/r2300_fpu.S
--- v2.1.72/linux/arch/mips/kernel/r2300_fpu.S	Mon Jul  7 08:18:53 1997
+++ linux/arch/mips/kernel/r2300_fpu.S	Wed Dec 10 10:31:09 1997
@@ -10,7 +10,7 @@
  * Multi-arch abstraction and asm macros for easier reading:
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
  *
- * $Id: r2300_fpu.S,v 1.2 1997/06/25 16:57:15 ralf Exp $
+ * $Id: r2300_fpu.S,v 1.3 1997/12/01 16:54:20 ralf Exp $
  */
 #include <asm/asm.h>
 #include <asm/fpregdef.h>
@@ -30,7 +30,7 @@
 	 nop
 
 	cfc1	t0,fcr31
-	/* Store the 16 odd double precision registers */
+	/* Store the 32 single precision registers */
 	swc1	$f0,(SC_FPREGS+0)(a0)
 	swc1	$f1,(SC_FPREGS+8)(a0)
 	swc1	$f2,(SC_FPREGS+16)(a0)
@@ -76,7 +76,8 @@
 	.set	macro
 	END(r2300_save_fp_context)
 
-/* Restore fpu state:
+/*
+ * Restore fpu state:
  *  - fp gp registers
  *  - cp1 status/control register
  *
@@ -91,7 +92,6 @@
 	bgez	t0,1f
 	 nop
 
-	bgez	t0,1f
 	 lw	t0,SC_FPC_CSR(a0)
 	/* Restore the 16 odd double precision registers only
 	 * when enabled in the cp0 status register.
diff -u --recursive --new-file v2.1.72/linux/arch/mips/kernel/r2300_misc.S linux/arch/mips/kernel/r2300_misc.S
--- v2.1.72/linux/arch/mips/kernel/r2300_misc.S	Thu Jun 26 12:33:37 1997
+++ linux/arch/mips/kernel/r2300_misc.S	Wed Dec 10 10:31:09 1997
@@ -1,4 +1,4 @@
-/* $Id: r2300_misc.S,v 1.1 1997/06/06 09:32:57 ralf Exp $
+/* $Id: r2300_misc.S,v 1.1.1.1 1997/06/01 03:16:42 ralf Exp $
  * r2300_misc.S: Misc. exception handling code for R3000/R2000.
  *
  * Copyright (C) 1994, 1995, 1996 by Ralf Baechle and Andreas Busse
diff -u --recursive --new-file v2.1.72/linux/arch/mips/kernel/r2300_scall.S linux/arch/mips/kernel/r2300_scall.S
--- v2.1.72/linux/arch/mips/kernel/r2300_scall.S	Thu Jun 26 12:33:37 1997
+++ linux/arch/mips/kernel/r2300_scall.S	Wed Dec 10 10:31:09 1997
@@ -1,4 +1,4 @@
-/* $Id: r2300_scall.S,v 1.1 1997/06/06 09:33:00 ralf Exp $
+/* $Id: r2300_scall.S,v 1.1.1.1 1997/06/01 03:16:42 ralf Exp $
  * r2300_scall.S: R2000/R3000 specific code to handle system calls.
  *
  * Copyright (C) 1994, 1995, 1996 by Ralf Baechle and Andreas Busse
diff -u --recursive --new-file v2.1.72/linux/arch/mips/kernel/r2300_switch.S linux/arch/mips/kernel/r2300_switch.S
--- v2.1.72/linux/arch/mips/kernel/r2300_switch.S	Thu Jun 26 12:33:37 1997
+++ linux/arch/mips/kernel/r2300_switch.S	Wed Dec 10 10:31:09 1997
@@ -1,4 +1,4 @@
-/* $Id: r2300_switch.S,v 1.1 1997/06/06 09:33:02 ralf Exp $
+/* $Id: r2300_switch.S,v 1.1.1.1 1997/06/01 03:16:43 ralf Exp $
  * r2300_switch.S: R3000/R2000 specific task switching code.
  *
  * Copyright (C) 1994, 1995, 1996 by Ralf Baechle and Andreas Busse
diff -u --recursive --new-file v2.1.72/linux/arch/mips/kernel/r4k_fpu.S linux/arch/mips/kernel/r4k_fpu.S
--- v2.1.72/linux/arch/mips/kernel/r4k_fpu.S	Mon Jul  7 08:18:53 1997
+++ linux/arch/mips/kernel/r4k_fpu.S	Wed Dec 10 10:31:09 1997
@@ -10,7 +10,7 @@
  * Multi-arch abstraction and asm macros for easier reading:
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
  *
- * $Id: r4k_fpu.S,v 1.2 1997/06/25 16:57:18 ralf Exp $
+ * $Id: r4k_fpu.S,v 1.3 1997/12/01 16:56:06 ralf Exp $
  */
 #include <asm/asm.h>
 #include <asm/fpregdef.h>
@@ -21,7 +21,7 @@
 	.set	noreorder
 	.set	mips3
 	/* Save floating point context */
-	LEAF(r4k_save_fp_context)
+LEAF(r4k_save_fp_context)
 	mfc0	t1,CP0_STATUS
 	sll	t2,t1,2
 	bgez	t2,2f
@@ -31,41 +31,41 @@
 	bgez	t2,1f
 	 nop
 	/* Store the 16 odd double precision registers */
-	swc1	$f1,(SC_FPREGS+8)(a0)
-	swc1	$f3,(SC_FPREGS+24)(a0)
-	swc1	$f5,(SC_FPREGS+40)(a0)
-	swc1	$f7,(SC_FPREGS+56)(a0)
-	swc1	$f9,(SC_FPREGS+72)(a0)
-	swc1	$f11,(SC_FPREGS+88)(a0)
-	swc1	$f13,(SC_FPREGS+104)(a0)
-	swc1	$f15,(SC_FPREGS+120)(a0)
-	swc1	$f17,(SC_FPREGS+136)(a0)
-	swc1	$f19,(SC_FPREGS+152)(a0)
-	swc1	$f21,(SC_FPREGS+168)(a0)
-	swc1	$f23,(SC_FPREGS+184)(a0)
-	swc1	$f25,(SC_FPREGS+200)(a0)
-	swc1	$f27,(SC_FPREGS+216)(a0)
-	swc1	$f29,(SC_FPREGS+232)(a0)
-	swc1	$f31,(SC_FPREGS+248)(a0)
+	sdc1	$f1,(SC_FPREGS+8)(a0)
+	sdc1	$f3,(SC_FPREGS+24)(a0)
+	sdc1	$f5,(SC_FPREGS+40)(a0)
+	sdc1	$f7,(SC_FPREGS+56)(a0)
+	sdc1	$f9,(SC_FPREGS+72)(a0)
+	sdc1	$f11,(SC_FPREGS+88)(a0)
+	sdc1	$f13,(SC_FPREGS+104)(a0)
+	sdc1	$f15,(SC_FPREGS+120)(a0)
+	sdc1	$f17,(SC_FPREGS+136)(a0)
+	sdc1	$f19,(SC_FPREGS+152)(a0)
+	sdc1	$f21,(SC_FPREGS+168)(a0)
+	sdc1	$f23,(SC_FPREGS+184)(a0)
+	sdc1	$f25,(SC_FPREGS+200)(a0)
+	sdc1	$f27,(SC_FPREGS+216)(a0)
+	sdc1	$f29,(SC_FPREGS+232)(a0)
+	sdc1	$f31,(SC_FPREGS+248)(a0)
 
 	/* Store the 16 even double precision registers */
 1:
-	swc1	$f0,(SC_FPREGS+0)(a0)
-	swc1	$f2,(SC_FPREGS+16)(a0)
-	swc1	$f4,(SC_FPREGS+32)(a0)
-	swc1	$f6,(SC_FPREGS+48)(a0)
-	swc1	$f8,(SC_FPREGS+64)(a0)
-	swc1	$f10,(SC_FPREGS+80)(a0)
-	swc1	$f12,(SC_FPREGS+96)(a0)
-	swc1	$f14,(SC_FPREGS+112)(a0)
-	swc1	$f16,(SC_FPREGS+128)(a0)
-	swc1	$f18,(SC_FPREGS+144)(a0)
-	swc1	$f20,(SC_FPREGS+160)(a0)
-	swc1	$f22,(SC_FPREGS+176)(a0)
-	swc1	$f24,(SC_FPREGS+192)(a0)
-	swc1	$f26,(SC_FPREGS+208)(a0)
-	swc1	$f28,(SC_FPREGS+224)(a0)
-	swc1	$f30,(SC_FPREGS+240)(a0)
+	sdc1	$f0,(SC_FPREGS+0)(a0)
+	sdc1	$f2,(SC_FPREGS+16)(a0)
+	sdc1	$f4,(SC_FPREGS+32)(a0)
+	sdc1	$f6,(SC_FPREGS+48)(a0)
+	sdc1	$f8,(SC_FPREGS+64)(a0)
+	sdc1	$f10,(SC_FPREGS+80)(a0)
+	sdc1	$f12,(SC_FPREGS+96)(a0)
+	sdc1	$f14,(SC_FPREGS+112)(a0)
+	sdc1	$f16,(SC_FPREGS+128)(a0)
+	sdc1	$f18,(SC_FPREGS+144)(a0)
+	sdc1	$f20,(SC_FPREGS+160)(a0)
+	sdc1	$f22,(SC_FPREGS+176)(a0)
+	sdc1	$f24,(SC_FPREGS+192)(a0)
+	sdc1	$f26,(SC_FPREGS+208)(a0)
+	sdc1	$f28,(SC_FPREGS+224)(a0)
+	sdc1	$f30,(SC_FPREGS+240)(a0)
 	sw	t1,SC_FPC_CSR(a0)
 	cfc1	t0,$0				# implementation/version
 
@@ -80,7 +80,8 @@
 	.set	macro
 	END(r4k_save_fp_context)
 
-/* Restore fpu state:
+/*
+ * Restore fpu state:
  *  - fp gp registers
  *  - cp1 status/control register
  *
@@ -88,7 +89,7 @@
  * frame on the current content of c0_status, not on the content of the
  * stack frame which might have been changed by the user.
  */
-	LEAF(r4k_restore_fp_context)
+LEAF(r4k_restore_fp_context)
 	mfc0	t1,CP0_STATUS
 	sll	t0,t1,2
 	bgez	t0,2f
@@ -99,52 +100,46 @@
 	/* Restore the 16 odd double precision registers only
 	 * when enabled in the cp0 status register.
 	 */
-	lwc1	$f1,(SC_FPREGS+8)(a0)
-	lwc1	$f3,(SC_FPREGS+24)(a0)
-	lwc1	$f5,(SC_FPREGS+40)(a0)
-	lwc1	$f7,(SC_FPREGS+56)(a0)
-	lwc1	$f9,(SC_FPREGS+72)(a0)
-	lwc1	$f11,(SC_FPREGS+88)(a0)
-	lwc1	$f13,(SC_FPREGS+104)(a0)
-	lwc1	$f15,(SC_FPREGS+120)(a0)
-	lwc1	$f17,(SC_FPREGS+136)(a0)
-	lwc1	$f19,(SC_FPREGS+152)(a0)
-	lwc1	$f21,(SC_FPREGS+168)(a0)
-	lwc1	$f23,(SC_FPREGS+184)(a0)
-	lwc1	$f25,(SC_FPREGS+200)(a0)
-	lwc1	$f27,(SC_FPREGS+216)(a0)
-	lwc1	$f29,(SC_FPREGS+232)(a0)
-	lwc1	$f31,(SC_FPREGS+248)(a0)
+	ldc1	$f1,(SC_FPREGS+8)(a0)
+	ldc1	$f3,(SC_FPREGS+24)(a0)
+	ldc1	$f5,(SC_FPREGS+40)(a0)
+	ldc1	$f7,(SC_FPREGS+56)(a0)
+	ldc1	$f9,(SC_FPREGS+72)(a0)
+	ldc1	$f11,(SC_FPREGS+88)(a0)
+	ldc1	$f13,(SC_FPREGS+104)(a0)
+	ldc1	$f15,(SC_FPREGS+120)(a0)
+	ldc1	$f17,(SC_FPREGS+136)(a0)
+	ldc1	$f19,(SC_FPREGS+152)(a0)
+	ldc1	$f21,(SC_FPREGS+168)(a0)
+	ldc1	$f23,(SC_FPREGS+184)(a0)
+	ldc1	$f25,(SC_FPREGS+200)(a0)
+	ldc1	$f27,(SC_FPREGS+216)(a0)
+	ldc1	$f29,(SC_FPREGS+232)(a0)
+	ldc1	$f31,(SC_FPREGS+248)(a0)
 
-	/* Restore the 16 even double precision registers
+	/*
+	 * Restore the 16 even double precision registers
 	 * when cp1 was enabled in the cp0 status register.
 	 */
-1:
-	lwc1	$f0,(SC_FPREGS+0)(a0)
-	lwc1	$f2,(SC_FPREGS+16)(a0)
-	lwc1	$f4,(SC_FPREGS+32)(a0)
-	lwc1	$f6,(SC_FPREGS+48)(a0)
-	lwc1	$f8,(SC_FPREGS+64)(a0)
-	lwc1	$f10,(SC_FPREGS+80)(a0)
-	lwc1	$f12,(SC_FPREGS+96)(a0)
-	lwc1	$f14,(SC_FPREGS+112)(a0)
-	lwc1	$f16,(SC_FPREGS+128)(a0)
-	lwc1	$f18,(SC_FPREGS+144)(a0)
-	lwc1	$f20,(SC_FPREGS+160)(a0)
-	lwc1	$f22,(SC_FPREGS+176)(a0)
-	lwc1	$f24,(SC_FPREGS+192)(a0)
-	lwc1	$f26,(SC_FPREGS+208)(a0)
-	lwc1	$f28,(SC_FPREGS+224)(a0)
-	lwc1	$f30,(SC_FPREGS+240)(a0)
-	ctc1	t0,fcr31
-
-	jr	ra
-	.set	nomacro
-	 nop
-	.set	macro
-2:
+1:	ldc1	$f0,(SC_FPREGS+0)(a0)
+	ldc1	$f2,(SC_FPREGS+16)(a0)
+	ldc1	$f4,(SC_FPREGS+32)(a0)
+	ldc1	$f6,(SC_FPREGS+48)(a0)
+	ldc1	$f8,(SC_FPREGS+64)(a0)
+	ldc1	$f10,(SC_FPREGS+80)(a0)
+	ldc1	$f12,(SC_FPREGS+96)(a0)
+	ldc1	$f14,(SC_FPREGS+112)(a0)
+	ldc1	$f16,(SC_FPREGS+128)(a0)
+	ldc1	$f18,(SC_FPREGS+144)(a0)
+	ldc1	$f20,(SC_FPREGS+160)(a0)
+	ldc1	$f22,(SC_FPREGS+176)(a0)
+	ldc1	$f24,(SC_FPREGS+192)(a0)
+	ldc1	$f26,(SC_FPREGS+208)(a0)
+	ldc1	$f28,(SC_FPREGS+224)(a0)
+	ldc1	$f30,(SC_FPREGS+240)(a0)
 	jr	ra
-	.set	nomacro
+	 ctc1	t0,fcr31
+
+2:	jr	ra
 	 nop
-	.set	macro
 	END(r4k_restore_fp_context)
diff -u --recursive --new-file v2.1.72/linux/arch/mips/kernel/r4k_misc.S linux/arch/mips/kernel/r4k_misc.S
--- v2.1.72/linux/arch/mips/kernel/r4k_misc.S	Thu Jun 26 12:33:37 1997
+++ linux/arch/mips/kernel/r4k_misc.S	Wed Dec 10 10:31:09 1997
@@ -1,10 +1,12 @@
-/* $Id: r4k_misc.S,v 1.2 1997/06/12 14:18:10 ralf Exp $
+/*
  * r4k_misc.S: Misc. exception handling code for r4k.
  *
  * Copyright (C) 1994, 1995, 1996 by Ralf Baechle and Andreas Busse
  *
  * Multi-cpu abstraction and reworking:
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ *
+ * $Id: r4k_misc.S,v 1.3 1997/09/07 04:51:07 ralf Exp $
  */
 #include <asm/asm.h>
 #include <asm/current.h>
@@ -21,7 +23,7 @@
 #include <asm/regdef.h>
 #include <asm/stackframe.h>
 
-#define NOTLB_OPTIMIZE /* If you are paranoid, define this. */
+#undef NOTLB_OPTIMIZE /* If you are paranoid, define this. */
 
 	/* ABUSE of CPP macros 101. */
 
@@ -108,10 +110,32 @@
 	.set	noreorder
 	.set	mips3
 
-	/* Note for many R4k variants tlb probes cannot be executed out
+/*
+ * From the IDT errata for the QED RM5230 (Nevada), processor revision 1.0:
+ * 2. A timing hazard exists for the TLBP instruction.
+ *
+ *      stalling_instruction
+ *      TLBP
+ *
+ * The JTLB is being read for the TLBP throughout the stall generated by the
+ * previous instruction. This is not really correct as the stalling instruction
+ * can modify the address used to access the JTLB.  The failure symptom is that
+ * the TLBP instruction will use an address created for the stalling instruction
+ * and not the address held in C0_ENHI and thus report the wrong results.
+ *
+ * The software work-around is to not allow the instruction preceding the TLBP
+ * to stall - make it an NOP or some other instruction guaranteed not to stall.
+ *
+ * Errata 2 will not be fixed.  This errata is also on the R5000.
+ *
+ * As if we MIPS hackers wouldn't know how to nop pipelines happy ...
+ */
+#define R5K_HAZARD nop
+
+	/*
+	 * Note for many R4k variants tlb probes cannot be executed out
 	 * of the instruction cache else you get bogus results.
 	 */
-
 	.align	5
 	NESTED(r4k_handle_tlbl, PT_SIZE, sp)
 	.set	noat
@@ -120,6 +144,7 @@
 #ifndef NOTLB_OPTIMIZE
 	/* Test present bit in entry. */
 	LOAD_PTE(k0, k1)
+	R5K_HAZARD
 	tlbp
 	PTE_PRESENT(k0, k1, nopage_tlbl)
 	PTE_MAKEVALID(k0, k1)
@@ -141,6 +166,7 @@
 	.set	noat
 #ifndef NOTLB_OPTIMIZE
 	LOAD_PTE(k0, k1)
+	R5K_HAZARD
 	tlbp				# find faulting entry
 	PTE_WRITABLE(k0, k1, nopage_tlbs)
 	PTE_MAKEWRITE(k0, k1)
@@ -162,6 +188,7 @@
 	.set	noat
 #ifndef NOTLB_OPTIMIZE
 	LOAD_PTE(k0, k1)
+	R5K_HAZARD
 	tlbp					# find faulting entry
 	andi	k0, k0, _PAGE_WRITE
 	beqz	k0, nowrite_mod
diff -u --recursive --new-file v2.1.72/linux/arch/mips/kernel/r4k_scall.S linux/arch/mips/kernel/r4k_scall.S
--- v2.1.72/linux/arch/mips/kernel/r4k_scall.S	Thu Jun 26 12:33:37 1997
+++ linux/arch/mips/kernel/r4k_scall.S	Wed Dec 10 10:31:09 1997
@@ -1,4 +1,4 @@
-/* $Id: r4k_scall.S,v 1.1 1997/06/06 09:33:08 ralf Exp $
+/* $Id: r4k_scall.S,v 1.1.1.1 1997/06/01 03:16:43 ralf Exp $
  * r4k_scall.S: R4xx0 specific code to handle system calls.
  *
  * Copyright (C) 1994, 1995, 1996 by Ralf Baechle and Andreas Busse
diff -u --recursive --new-file v2.1.72/linux/arch/mips/kernel/r6000_fpu.S linux/arch/mips/kernel/r6000_fpu.S
--- v2.1.72/linux/arch/mips/kernel/r6000_fpu.S	Mon Jul  7 08:18:53 1997
+++ linux/arch/mips/kernel/r6000_fpu.S	Wed Dec 10 10:31:09 1997
@@ -10,7 +10,7 @@
  * Multi-arch abstraction and asm macros for easier reading:
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
  *
- * $Id: r6000_fpu.S,v 1.2 1997/06/25 16:57:19 ralf Exp $
+ * $Id: r6000_fpu.S,v 1.3 1997/12/01 16:56:56 ralf Exp $
  */
 #include <asm/asm.h>
 #include <asm/fpregdef.h>
@@ -44,18 +44,10 @@
 	sdc1	$f26,(SC_FPREGS+208)(a0)
 	sdc1	$f28,(SC_FPREGS+224)(a0)
 	sdc1	$f30,(SC_FPREGS+240)(a0)
-	sw	t0,SC_FPC_CSR(a0)
-	cfc1	t0,$0				# implementation/version
-
-	jr	ra
-	.set	nomacro
-	 sw	t0,SC_FPC_EIR(a0)
-	.set	macro
-1:
 	jr	ra
-	.set	nomacro
+	 sw	t0,SC_FPC_CSR(a0)
+1:	jr	ra
 	 nop
-	.set	macro
 	END(r6000_save_fp_context)
 
 /* Restore fpu state:
@@ -89,14 +81,8 @@
 	ldc1	$f26,(SC_FPREGS+208)(a0)
 	ldc1	$f28,(SC_FPREGS+224)(a0)
 	ldc1	$f30,(SC_FPREGS+240)(a0)
-
 	jr	ra
-	.set	nomacro
 	 ctc1	t0,fcr31
-	.set	macro
-1:
-	jr	ra
-	.set	nomacro
+1:	jr	ra
 	 nop
-	.set	macro
 	END(r6000_restore_fp_context)
diff -u --recursive --new-file v2.1.72/linux/arch/mips/kernel/setup.c linux/arch/mips/kernel/setup.c
--- v2.1.72/linux/arch/mips/kernel/setup.c	Thu Jun 26 12:33:37 1997
+++ linux/arch/mips/kernel/setup.c	Wed Dec 10 10:31:09 1997
@@ -4,6 +4,8 @@
  *  Copyright (C) 1995  Linus Torvalds
  *  Copyright (C) 1995, 1996  Ralf Baechle
  *  Copyright (C) 1996  Stoned Elipot
+ *
+ * $Id: setup.c,v 1.5 1997/12/06 08:55:42 ralf Exp $
  */
 #include <linux/config.h>
 #include <linux/errno.h>
@@ -59,6 +61,11 @@
 char wait_available;
 
 /*
+ * Do we have a cyclecounter available?
+ */
+char cyclecounter_available;
+
+/*
  * There are several bus types available for MIPS machines.  "RISC PC"
  * type machines have ISA, EISA, VLB or PCI available, DECstations
  * have Turbochannel or Q-Bus, SGI has GIO, there are lots of VME
@@ -120,6 +127,12 @@
 void (*irq_setup)(void);
 
 /*
+ * mips_io_port_base is the begin of the address space to which x86 style
+ * I/O ports are mapped.
+ */
+unsigned long mips_io_port_base;
+
+/*
  * isa_slot_offset is the address where E(ISA) busaddress 0 is is mapped
  * for the processor.
  */
@@ -168,9 +181,10 @@
 		break;
 #endif
 #if defined(CONFIG_MIPS_ARC) 
-/* Perhaps arch/mips/deskstation should be renommed arch/mips/arc.
- * For now CONFIG_MIPS_ARC means DeskStation. -Stoned.
- */
+	/*
+	 * Perhaps arch/mips/deskstation should be renamed to arch/mips/arc.
+	 * For now CONFIG_MIPS_ARC means DeskStation. -Stoned.
+	 */
 	case MACH_GROUP_ARC:
 		deskstation_setup();
 		break;
@@ -196,9 +210,6 @@
 
 	atag = bi_TagFind(tag_drive_info);
 	memcpy(&drive_info, TAGVALPTR(atag), atag->size);
-#if 0
-	aux_device_present = AUX_DEVICE_INFO;
-#endif
 
 	memory_end = mips_memory_upper;
 	/*
diff -u --recursive --new-file v2.1.72/linux/arch/mips/kernel/signal.c linux/arch/mips/kernel/signal.c
--- v2.1.72/linux/arch/mips/kernel/signal.c	Mon Aug 18 18:19:42 1997
+++ linux/arch/mips/kernel/signal.c	Wed Dec 10 10:31:09 1997
@@ -4,7 +4,7 @@
  *  Copyright (C) 1991, 1992  Linus Torvalds
  *  Copyright (C) 1994, 1995, 1996  Ralf Baechle
  *
- * $Id: signal.c,v 1.8 1997/08/08 18:12:30 miguel Exp $
+ * $Id: signal.c,v 1.8 1997/12/01 16:26:34 ralf Exp $
  */
 #include <linux/config.h>
 #include <linux/sched.h>
@@ -42,7 +42,7 @@
 	unsigned long mask;
 	sigset_t *uset, set;
 
-	uset = (sigset_t *)(long) regs->regs[4];
+	uset = (sigset_t *) regs->regs[4];
 	if (get_user(set, uset))
 		return -EFAULT;
 
@@ -64,6 +64,8 @@
 asmlinkage int sys_sigreturn(struct pt_regs *regs)
 {
 	struct sigcontext *context;
+	unsigned long blocked;
+	long long reg;
 	int i;
 
 	context = (struct sigcontext *)(long) regs->regs[29];
@@ -71,36 +73,26 @@
 	    (regs->regs[29] & (SZREG - 1)))
 		goto badframe;
 
-	current->blocked = context->sc_sigset & _BLOCKABLE; /* XXX */
-	regs->cp0_epc = context->sc_pc; /* XXX */
+	__get_user(blocked, &context->sc_sigset);
+	current->blocked = blocked & _BLOCKABLE;
+	__get_user(regs->cp0_epc, &context->sc_pc);
 
-/*
- * Disabled because we only use the lower 32 bit of the registers.
- */
-#if 0
 	/*
-	 * We only allow user processes in 64bit mode (n32, 64 bit ABI) to
-	 * restore the upper half of registers.
+	 * Restore all integer registers.
 	 */
-	if (read_32bit_cp0_register(CP0_STATUS) & ST0_UX) {
-		for(i = 31;i >= 0;i--)
-			__get_user(regs->regs[i], &context->sc_regs[i]);
-		__get_user(regs->hi, &context->sc_mdhi);
-		__get_user(regs->lo, &context->sc_mdlo);
-	} else
-#endif
-	{
-		long long reg;
-		for(i = 31;i >= 0;i--) {
-			__get_user(reg, &context->sc_regs[i]);
-			regs->regs[i] = (int) reg;
-		}
-		__get_user(reg, &context->sc_mdhi);
-		regs->hi = (int) reg;
-		__get_user(reg, &context->sc_mdlo);
-		regs->lo = (int) reg;
+	for(i = 31;i >= 0;i--) {
+		__get_user(reg, &context->sc_regs[i]);
+		regs->regs[i] = (int) reg;
 	}
+	__get_user(reg, &context->sc_mdhi);
+	regs->hi = (int) reg;
+	__get_user(reg, &context->sc_mdlo);
+	regs->lo = (int) reg;
 
+	/*
+	 * FP depends on what FPU in what mode we have.  Best done in
+	 * Assembler ...
+	 */
 	restore_fp_context(context);
 
 	/*
@@ -182,7 +174,7 @@
 	 * Set up the return code ...
 	 *
 	 *         .set    noreorder
-	 *         addiu   sp,24
+	 *         addiu   sp,0x20
 	 *         li      v0,__NR_sigreturn
 	 *         syscall
 	 *         .set    reorder
@@ -391,4 +383,14 @@
 asmlinkage unsigned long sys_signal(int signum, __sighandler_t handler)
 {
 	return -ENOSYS;
+}
+
+/*
+ * Compatibility syscall.  Can be replaced in libc.
+ */
+asmlinkage int sys_pause(void)
+{
+	current->state = TASK_INTERRUPTIBLE;
+	schedule();
+	return -ERESTARTNOHAND;
 }
diff -u --recursive --new-file v2.1.72/linux/arch/mips/kernel/syscall.c linux/arch/mips/kernel/syscall.c
--- v2.1.72/linux/arch/mips/kernel/syscall.c	Mon Aug 18 18:19:42 1997
+++ linux/arch/mips/kernel/syscall.c	Wed Dec 10 10:31:10 1997
@@ -10,6 +10,8 @@
  * TODO:  Implement the compatibility syscalls.
  *        Don't waste that much memory for empty entries in the syscall
  *        table.
+ *
+ * $Id: syscall.c,v 1.4 1997/09/18 07:57:30 root Exp $
  */
 #undef CONF_PRINT_SYSCALLS
 #undef CONF_DEBUG_IRIX
@@ -21,6 +23,7 @@
 #include <linux/smp_lock.h>
 #include <linux/mman.h>
 #include <linux/sched.h>
+#include <linux/utsname.h>
 #include <linux/unistd.h>
 #include <asm/branch.h>
 #include <asm/ptrace.h>
@@ -83,15 +86,17 @@
 	current->counter = -100;
 	for (;;) {
 		/*
-		 * R4[236]00 have wait, R4[04]00 don't.
+		 * R4[36]00 have wait, R4[04]00 don't.
 		 * FIXME: We should save power by reducing the clock where
-		 *        possible.  Should help alot for battery powered
-		 *        R4200/4300i systems.
+		 *        possible.  Thiss will cut down the power consuption
+		 *        of R4200 systems to about 1/16th of normal, the
+		 *        same for logic clocked with the processor generated
+		 *        clocks.
 		 */
-		if (wait_available && !resched_needed())
+		if (wait_available && !need_resched)
 			__asm__(".set\tmips3\n\t"
 				"wait\n\t"
-				".set\tmips0\n\t");
+				".set\tmips0");
 		run_task_queue(&tq_scheduler);
 		schedule();
 	}
@@ -145,6 +150,43 @@
 
 out:
 	unlock_kernel();
+	return error;
+}
+
+/*
+ * Compacrapability ...
+ */
+asmlinkage int sys_uname(struct old_utsname * name)
+{
+	if (name && !copy_to_user(name, &system_utsname, sizeof (*name)))
+		return 0;
+	return -EFAULT;
+}
+
+/*
+ * Compacrapability ...
+ */
+asmlinkage int sys_olduname(struct oldold_utsname * name)
+{
+	int error;
+
+	if (!name)
+		return -EFAULT;
+	if (!access_ok(VERIFY_WRITE,name,sizeof(struct oldold_utsname)))
+		return -EFAULT;
+  
+	error = __copy_to_user(&name->sysname,&system_utsname.sysname,__OLD_UTS_LEN);
+	error -= __put_user(0,name->sysname+__OLD_UTS_LEN);
+	error -= __copy_to_user(&name->nodename,&system_utsname.nodename,__OLD_UTS_LEN);
+	error -= __put_user(0,name->nodename+__OLD_UTS_LEN);
+	error -= __copy_to_user(&name->release,&system_utsname.release,__OLD_UTS_LEN);
+	error -= __put_user(0,name->release+__OLD_UTS_LEN);
+	error -= __copy_to_user(&name->version,&system_utsname.version,__OLD_UTS_LEN);
+	error -= __put_user(0,name->version+__OLD_UTS_LEN);
+	error -= __copy_to_user(&name->machine,&system_utsname.machine,__OLD_UTS_LEN);
+	error = __put_user(0,name->machine+__OLD_UTS_LEN);
+	error = error ? -EFAULT : 0;
+
 	return error;
 }
 
diff -u --recursive --new-file v2.1.72/linux/arch/mips/kernel/syscalls.h linux/arch/mips/kernel/syscalls.h
--- v2.1.72/linux/arch/mips/kernel/syscalls.h	Wed Sep 24 20:05:45 1997
+++ linux/arch/mips/kernel/syscalls.h	Wed Dec 10 10:31:10 1997
@@ -5,9 +5,9 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1995, 1996, 1997 by Ralf Baechle
+ * Copyright (C) 1995, 1996 by Ralf Baechle
  *
- * $Id: syscalls.h,v 1.7 1997/08/08 18:12:32 miguel Exp $
+ * $Id: syscalls.h,v 1.6 1997/12/06 09:57:39 ralf Exp $
  */
 
 /*
@@ -35,7 +35,7 @@
 SYS(sys_mknod, 3)
 SYS(sys_chmod, 2)				/* 4015 */
 SYS(sys_chown, 3)
-SYS(sys_break, 0)
+SYS(sys_ni_syscall, 0)
 SYS(sys_stat, 2)
 SYS(sys_lseek, 3)
 SYS(sys_getpid, 0)				/* 4020 */
@@ -49,11 +49,11 @@
 SYS(sys_fstat, 2)
 SYS(sys_pause, 0)
 SYS(sys_utime, 2)				/* 4030 */
-SYS(sys_stty, 0)
-SYS(sys_gtty, 0)
+SYS(sys_ni_syscall, 0)
+SYS(sys_ni_syscall, 0)
 SYS(sys_access, 2)
 SYS(sys_nice, 1)
-SYS(sys_ftime, 0)				/* 4035 */
+SYS(sys_ni_syscall, 0)				/* 4035 */
 SYS(sys_sync, 0)
 SYS(sys_kill, 2)
 SYS(sys_rename, 2)
@@ -62,7 +62,7 @@
 SYS(sys_dup, 1)
 SYS(sys_pipe, 0)
 SYS(sys_times, 1)
-SYS(sys_prof, 0)
+SYS(sys_ni_syscall, 0)
 SYS(sys_brk, 1)					/* 4045 */
 SYS(sys_setgid, 1)
 SYS(sys_getgid, 0)
@@ -70,13 +70,13 @@
 SYS(sys_geteuid, 0)
 SYS(sys_getegid, 0)				/* 4050 */
 SYS(sys_acct, 0)
-SYS(sys_phys, 0)
-SYS(sys_lock, 0)
+SYS(sys_ni_syscall, 0)
+SYS(sys_ni_syscall, 0)
 SYS(sys_ioctl, 3)
 SYS(sys_fcntl, 3)				/* 4055 */
-SYS(sys_mpx, 2)
+SYS(sys_ni_syscall, 2)
 SYS(sys_setpgid, 2)
-SYS(sys_ulimit, 0)
+SYS(sys_ni_syscall, 0)
 SYS(sys_olduname, 1)
 SYS(sys_umask, 1)				/* 4060 */
 SYS(sys_chroot, 1)
@@ -116,7 +116,7 @@
 SYS(sys_fchown, 3)				/* 4095 */
 SYS(sys_getpriority, 2)
 SYS(sys_setpriority, 3)
-SYS(sys_profil, 0)
+SYS(sys_ni_syscall, 0)
 SYS(sys_statfs, 2)
 SYS(sys_fstatfs, 2)				/* 4100 */
 SYS(sys_ioperm, 3)
@@ -208,8 +208,6 @@
 SYS(sys_query_module, 5)
 SYS(sys_poll, 3)
 SYS(sys_nfsservctl, 3)
-SYS(sys_setresgid, 3)				/* 4190 */
-SYS(sys_getresgid, 3)
 SYS(sys_setresgid, 3)				/* 4190 */
 SYS(sys_getresgid, 3)
 SYS(sys_prctl, 5)
diff -u --recursive --new-file v2.1.72/linux/arch/mips/kernel/sysirix.c linux/arch/mips/kernel/sysirix.c
--- v2.1.72/linux/arch/mips/kernel/sysirix.c	Mon Aug 18 18:19:42 1997
+++ linux/arch/mips/kernel/sysirix.c	Wed Dec 10 10:31:10 1997
@@ -1,4 +1,4 @@
-/* $Id: sysirix.c,v 1.4 1997/08/08 18:12:35 miguel Exp $
+/* $Id: sysirix.c,v 1.6 1997/12/06 11:29:29 ralf Exp $
  * sysirix.c: IRIX system call emulation.
  *
  * Copyright (C) 1996 David S. Miller
@@ -26,7 +26,7 @@
 #include <asm/pgtable.h>
 #include <asm/uaccess.h>
 
-/* 2,300 lines of complete and utter shit coming up... */
+/* 2,358 lines of complete and utter shit coming up... */
 
 /* The sysmp commands supported thus far. */
 #define MP_PGSIZE           14 /* Return system page size in v1. */
@@ -751,8 +751,6 @@
 	}
 	error = 0;
 
-dput_and_out:
-	dput(dentry);
 out:
 	unlock_kernel();
 	return error;
@@ -1516,8 +1514,6 @@
 
 	error = 0;
 
-dput_and_out:
-	dput(dentry);
 out:
 	unlock_kernel();
 	return error;
@@ -1881,8 +1877,6 @@
 
 	error = 0;
 
-dput_and_out:
-	dput(dentry);
 out:
 	unlock_kernel();
 	return error;
@@ -2023,7 +2017,7 @@
 	buf.count = count;
 	buf.error = 0;
 
-	error = file->f_op->readdir(inode, file, &buf, irix_filldir32);
+	error = file->f_op->readdir(file, &buf, irix_filldir32);
 	if (error < 0)
 		goto out;
 	lastdirent = buf.previous;
@@ -2135,7 +2129,7 @@
 	buf.previous = NULL;
 	buf.count = cnt;
 	buf.error = 0;
-	error = file->f_op->readdir(inode, file, &buf, irix_filldir64);
+	error = file->f_op->readdir(file, &buf, irix_filldir64);
 	if (error < 0)
 		goto out;
 	lastdirent = buf.previous;
@@ -2198,7 +2192,7 @@
 	buf.previous = NULL;
 	buf.count = cnt;
 	buf.error = 0;
-	error = file->f_op->readdir(inode, file, &buf, irix_filldir64);
+	error = file->f_op->readdir(file, &buf, irix_filldir64);
 	if (error < 0)
 		goto out;
 	lastdirent = buf.previous;
diff -u --recursive --new-file v2.1.72/linux/arch/mips/kernel/sysmips.c linux/arch/mips/kernel/sysmips.c
--- v2.1.72/linux/arch/mips/kernel/sysmips.c	Mon Aug 18 18:19:42 1997
+++ linux/arch/mips/kernel/sysmips.c	Wed Dec 10 10:31:10 1997
@@ -7,7 +7,7 @@
  *
  * Copyright (C) 1995, 1996, 1997 by Ralf Baechle
  *
- * $Id: sysmips.c,v 1.6 1997/08/08 18:12:38 miguel Exp $
+ * $Id: sysmips.c,v 1.3 1997/07/18 06:26:02 ralf Exp $
  */
 #include <linux/errno.h>
 #include <linux/linkage.h>
diff -u --recursive --new-file v2.1.72/linux/arch/mips/kernel/time.c linux/arch/mips/kernel/time.c
--- v2.1.72/linux/arch/mips/kernel/time.c	Mon Aug 18 18:19:43 1997
+++ linux/arch/mips/kernel/time.c	Wed Dec 10 10:31:10 1997
@@ -6,7 +6,7 @@
  * This file contains the time handling details for PC-style clocks as
  * found in some MIPS systems.
  *
- * $Id: time.c,v 1.5 1997/08/08 18:12:39 miguel Exp $
+ * $Id: time.c,v 1.5 1997/11/12 12:12:12 ralf Exp $
  */
 #include <linux/errno.h>
 #include <linux/init.h>
@@ -18,7 +18,7 @@
 #include <linux/interrupt.h>
 
 #include <asm/bootinfo.h>
-#include <asm/uaccess.h>
+#include <asm/mipsregs.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 
@@ -27,8 +27,91 @@
 
 extern volatile unsigned long lost_ticks;
 
-/* change this if you have some constant time drift */
-#define USECS_PER_JIFFY (1000020/HZ)
+/*
+ * Change this if you have some constant time drift
+ */
+/* This is the value for the PC-style PICs. */
+/* #define USECS_PER_JIFFY (1000020/HZ) */
+
+/* This is for machines which generate the exact clock. */
+#define USECS_PER_JIFFY (1000000/HZ)
+
+/* Cycle counter value at the previous timer interrupt.. */
+
+static unsigned int timerhi = 0, timerlo = 0;
+
+/*
+ * On MIPS only R4000 and better have a cycle counter.
+ *
+ * FIXME: Does playing with the RP bit in c0_status interfere with this code?
+ */
+static unsigned long do_fast_gettimeoffset(void)
+{
+	u32 count;
+	unsigned long res, tmp;
+
+	/* Last jiffy when do_fast_gettimeoffset() was called. */
+	static unsigned long last_jiffies=0;
+	unsigned long quotient;
+
+	/*
+	 * Cached "1/(clocks per usec)*2^32" value.
+	 * It has to be recalculated once each jiffy.
+	 */
+	static unsigned long cached_quotient=0;
+
+	tmp = jiffies;
+
+	quotient = cached_quotient;
+
+	if (last_jiffies != tmp) {
+		last_jiffies = tmp;
+		__asm__(".set\tnoreorder\n\t"
+			".set\tnoat\n\t"
+			".set\tmips3\n\t"
+			"lwu\t%0,%2\n\t"
+			"dsll32\t$1,%1,0\n\t"
+			"or\t$1,$1,%0\n\t"
+			"ddivu\t$0,$1,%3\n\t"
+			"mflo\t$1\n\t"
+			"dsll32\t%0,%4,0\n\t"
+			"nop\n\t"
+			"ddivu\t$0,%0,$1\n\t"
+			"mflo\t%0\n\t"
+			".set\tmips0\n\t"
+			".set\tat\n\t"
+			".set\treorder"
+			:"=&r" (quotient)
+			:"r" (timerhi),
+			 "m" (timerlo),
+			 "r" (tmp),
+			 "r" (USECS_PER_JIFFY)
+			:"$1");
+		cached_quotient = quotient;
+	}
+
+	/* Get last timer tick in absolute kernel time */
+	count = read_32bit_cp0_register(CP0_COUNT);
+
+	/* .. relative to previous jiffy (32 bits is enough) */
+	count -= timerlo;
+//printk("count: %08lx, %08lx:%08lx\n", count, timerhi, timerlo);
+
+	__asm__("multu\t%1,%2\n\t"
+		"mfhi\t%0"
+		:"=r" (res)
+		:"r" (count),
+		 "r" (quotient));
+
+	/*
+ 	 * Due to possible jiffies inconsistencies, we need to check 
+	 * the result so that we'll get a timer that is monotonic.
+	 */
+	if (res >= USECS_PER_JIFFY)
+		res = USECS_PER_JIFFY-1;
+
+	return res;
+}
 
 /* This function must be called with interrupts disabled 
  * It was inspired by Steve McCanne's microtime-i386 for BSD.  -- jrs
@@ -85,7 +168,7 @@
 	 * We do this guaranteed double memory access instead of a _p 
 	 * postfix in the previous port access. Wheee, hackady hack
 	 */
- 	jiffies_t = jiffies;
+	jiffies_t = jiffies;
 
 	count |= inb_p(0x40) << 8;
 
@@ -105,7 +188,7 @@
 			outb_p(0x0A, 0x20);
 
 			/* assumption about timer being IRQ1 */
-			if( inb(0x20) & 0x01 ) {
+			if (inb(0x20) & 0x01) {
 				/*
 				 * We cannot detect lost timer interrupts ... 
 				 * well, thats why we call them lost, dont we? :)
@@ -243,7 +326,8 @@
  * timer_interrupt() needs to keep up the real-time clock,
  * as well as call the "do_timer()" routine every clocktick
  */
-static void timer_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+static void inline
+timer_interrupt(int irq, void *dev_id, struct pt_regs * regs)
 {
 	do_timer(regs);
 
@@ -266,6 +350,21 @@
 	/*smp_message_pass(MSG_ALL_BUT_SELF, MSG_RESCHEDULE, 0L, 0); */
 }
 
+static void r4k_timer_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+{
+	unsigned int count;
+
+	/*
+	 * The cycle counter is only 32 bit which is good for about
+	 * a minute at current count rates of upto 150MHz or so.
+	 */
+	count = read_32bit_cp0_register(CP0_COUNT);
+	timerhi += (count < timerlo);	/* Wrap around */
+	timerlo = count;
+
+	timer_interrupt(irq, dev_id, regs);
+}
+
 /* Converts Gregorian date to seconds since 1970-01-01 00:00:00.
  * Assumes input in normal date format, i.e. 1980-12-31 23:59:59
  * => year=1980, mon=12, day=31, hour=23, min=59, sec=59.
@@ -297,7 +396,49 @@
 	  )*60 + sec; /* finally seconds */
 }
 
-static struct irqaction irq0  = { timer_interrupt, 0, 0, "timer", NULL, NULL};
+char cyclecounter_available;
+
+static inline void init_cycle_counter(void)
+{
+	switch(mips_cputype) {
+	case CPU_UNKNOWN:
+	case CPU_R2000:
+	case CPU_R3000:
+	case CPU_R3000A:
+	case CPU_R3041:
+	case CPU_R3051:
+	case CPU_R3052:
+	case CPU_R3081:
+	case CPU_R3081E:
+	case CPU_R6000:
+	case CPU_R6000A:
+	case CPU_R8000:		/* Not shure about that one, play safe */
+		cyclecounter_available = 0;
+		break;
+	case CPU_R4000PC:
+	case CPU_R4000SC:
+	case CPU_R4000MC:
+	case CPU_R4200:
+	case CPU_R4400PC:
+	case CPU_R4400SC:
+	case CPU_R4400MC:
+	case CPU_R4600:
+	case CPU_R10000:
+	case CPU_R4300:
+	case CPU_R4650:
+	case CPU_R4700:
+	case CPU_R5000:
+	case CPU_R5000A:
+	case CPU_R4640:
+	case CPU_NEVADA:
+		cyclecounter_available = 1;
+		break;
+	}
+}
+
+struct irqaction irq0  = { timer_interrupt, SA_INTERRUPT, 0,
+                                  "timer", NULL, NULL};
+
 
 void (*board_time_init)(struct irqaction *irq);
 
@@ -345,6 +486,13 @@
 	xtime.tv_sec = mktime(year, mon, day, hour, min, sec);
 	xtime.tv_usec = 0;
 
-	/* FIXME: If we have the CPU hardware time counters, use them */
+	init_cycle_counter();
+
+	if (cyclecounter_available) {
+		write_32bit_cp0_register(CP0_COUNT, 0);
+		do_gettimeoffset = do_fast_gettimeoffset;
+		irq0.handler = r4k_timer_interrupt;
+	}
+
 	board_time_init(&irq0);
 }
diff -u --recursive --new-file v2.1.72/linux/arch/mips/kernel/traps.c linux/arch/mips/kernel/traps.c
--- v2.1.72/linux/arch/mips/kernel/traps.c	Mon Aug 18 18:19:43 1997
+++ linux/arch/mips/kernel/traps.c	Wed Dec 10 10:31:10 1997
@@ -4,17 +4,11 @@
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
- */
-
-/*
- * 'traps.c' handles hardware traps and faults after we have saved some
- * state in 'asm.s'. Currently mostly a debugging-aid, will be extended
- * to mainly kill the offending process (probably by giving it a signal,
- * but possibly by killing it outright if necessary).
- *
- * FIXME: This is the place for a fpu emulator.
  *
+ * Copyright 1994, 1995, 1996, 1997 by Ralf Baechle
  * Modified for R3000 by Paul M. Antoine, 1995, 1996
+ *
+ * $Id: traps.c,v 1.7 1997/12/01 16:33:28 ralf Exp $
  */
 #include <linux/config.h>
 #include <linux/init.h>
@@ -78,8 +72,8 @@
 
 static char *cpu_names[] = CPU_NAMES;
 
-unsigned long page_colour_mask;
-unsigned int watch_available = 0;
+char watch_available = 0;
+char dedicated_iv_available = 0;
 
 void (*ibe_board_handler)(struct pt_regs *regs);
 void (*dbe_board_handler)(struct pt_regs *regs);
@@ -182,7 +176,7 @@
 		return;
 #endif
 #if (_MIPS_ISA == _MIPS_ISA_MIPS3) || (_MIPS_ISA == _MIPS_ISA_MIPS4)
-	if (!(regs->cp0_status & 0x18))
+	if (regs->cp0_status & ST0_KSU == KSU_USER)
 		return;
 #endif
 	console_verbose();
@@ -196,8 +190,6 @@
 	/*
 	 * Assume it would be too dangerous to continue ...
 	 */
-	printk ("BE HANDLER\n");
-	show_regs (regs);
 	force_sig(SIGBUS, current);
 }
 
@@ -228,8 +220,34 @@
 	unlock_kernel();
 }
 
+#ifdef CONFIG_MIPS_FPE_MODULE
+static void (*fpe_handler)(struct pt_regs *regs, unsigned int fcr31);
+
+/*
+ * Register_fpe/unregister_fpe are for debugging purposes only.  To make
+ * this hack work a bit better there is no error checking.
+ */
+int register_fpe(void (*handler)(struct pt_regs *regs, unsigned int fcr31))
+{
+	fpe_handler = handler;
+	return 0;
+}
+
+int unregister_fpe(void (*handler)(struct pt_regs *regs, unsigned int fcr31))
+{
+	fpe_handler = NULL;
+	return 0;
+}
+#endif
+
 void do_fpe(struct pt_regs *regs, unsigned int fcr31)
 {
+#ifdef CONFIG_MIPS_FPE_MODULE
+	if (fpe_handler != NULL) {
+		fpe_handler(regs, fcr31);
+		return;
+	}
+#endif
 	lock_kernel();
 #ifdef CONF_DEBUG_EXCEPTIONS
 	show_regs(regs);
@@ -408,6 +426,40 @@
 	}
 }
 
+/*
+ * Some MIPS CPUs have a dedicated interrupt vector which reduces the
+ * interrupt processing overhead.  Use it where available.
+ * FIXME: more CPUs than just the Nevada have this feature.
+ */
+static inline void setup_dedicated_int(void)
+{
+	extern void except_vec4(void);
+	switch(mips_cputype) {
+	case CPU_NEVADA:
+		memcpy((void *)(KSEG0 + 0x200), except_vec4, 8);
+		set_cp0_cause(CAUSEF_IV, CAUSEF_IV);
+		dedicated_iv_available = 1;
+	}
+}
+
+unsigned long exception_handlers[32];
+
+/*
+ * As a side effect of the way this is implemented we're limited
+ * to interrupt handlers in the address range from
+ * KSEG0 <= x < KSEG0 + 256mb on the Nevada.  Oh well ...
+ */
+void set_except_vector(int n, void *addr)
+{
+	unsigned handler = (unsigned long) addr;
+	exception_handlers[n] = handler;
+	if (n == 0 && dedicated_iv_available) {
+		*(volatile u32 *)(KSEG0+0x200) = 0x08000000 |
+		                                 (0x03ffffff & (handler >> 2));
+		flush_icache_range(KSEG0+0x200, KSEG0 + 0x204);
+	}
+}
+
 typedef asmlinkage int (*syscall_t)(void *a0,...);
 asmlinkage int (*do_syscalls)(struct pt_regs *regs, syscall_t fun, int narg);
 extern asmlinkage int r4k_do_syscalls(struct pt_regs *regs,
@@ -430,7 +482,8 @@
 
 __initfunc(void trap_init(void))
 {
-	extern char except_vec0_r4000, except_vec0_r4600, except_vec0_r2300;
+	extern char except_vec0_nevada, except_vec0_r4000;
+	extern char except_vec0_r4600, except_vec0_r2300;
 	extern char except_vec1_generic, except_vec2_generic;
 	extern char except_vec3_generic, except_vec3_r4000;
 	unsigned long i;
@@ -452,9 +505,11 @@
 		set_except_vector(i, handle_reserved);
 
 	/*
-	 * Only some CPUs have the watch exception.
+	 * Only some CPUs have the watch exceptions or a dedicated
+	 * interrupt vector.
 	 */
 	watch_init(mips_cputype);
+	setup_dedicated_int();
 
 	/*
 	 * Handling the following exceptions depends mostly of the cpu type
@@ -468,11 +523,6 @@
 		write_32bit_cp0_register(CP0_FRAMEMASK, 0);
 		set_cp0_status(ST0_XX, ST0_XX);
 		/*
-		 * Actually this mask stands for only 16k cache.  This is
-		 * correct since the R10000 has multiple ways in it's cache.
-		 */
-		page_colour_mask = 0x3000;
-		/*
 		 * The R10k might even work for Linux/MIPS - but we're paranoid
 		 * and refuse to run until this is tested on real silicon
 		 */
@@ -494,10 +544,13 @@
      /* case CPU_R4640: */
 	case CPU_R4600:
         case CPU_R5000:
-		if(mips_cputype != CPU_R4600)
-			memcpy((void *)KSEG0, &except_vec0_r4000, 0x80);
-		else
+        case CPU_NEVADA:
+		if(mips_cputype == CPU_NEVADA) {
+			memcpy((void *)KSEG0, &except_vec0_nevada, 0x80);
+		} else if (mips_cputype == CPU_R4600)
 			memcpy((void *)KSEG0, &except_vec0_r4600, 0x80);
+		else
+			memcpy((void *)KSEG0, &except_vec0_r4000, 0x80);
 
 		/*
 		 * The idea is that this special r4000 general exception
@@ -532,15 +585,8 @@
 		set_except_vector(12, handle_ov);
 		set_except_vector(13, handle_tr);
 		set_except_vector(15, handle_fpe);
-
-		/*
-		 * Compute mask for page_colour().  This is based on the
-		 * size of the data cache.
-		 */
-		i = read_32bit_cp0_register(CP0_CONFIG);
-		i = (i >> 26) & 7;
-		page_colour_mask = 1 << (12 + i);
 		break;
+
 	case CPU_R6000:
 	case CPU_R6000A:
 		save_fp_context = r6000_save_fp_context;
@@ -552,6 +598,7 @@
 		 * unaligned ldc1/sdc1 exception.  The handlers have not been
 		 * written yet.  Well, anyway there is no R6000 machine on the
 		 * current list of targets for Linux/MIPS.
+		 * (Duh, crap, there is someone with a tripple R6k machine)
 		 */
 		set_except_vector(14, handle_mc);
 		set_except_vector(15, handle_ndc);
@@ -559,9 +606,6 @@
 	case CPU_R2000:
 	case CPU_R3000:
 	case CPU_R3000A:
-		/*
-		 * Actually don't know about these, but let's guess - PMA
-		 */
 		memcpy((void *)KSEG0, &except_vec0_r2300, 0x80);
 		do_syscalls = r2300_do_syscalls;
 		save_fp_context = r2300_save_fp_context;
@@ -589,20 +633,6 @@
 		set_except_vector(12, handle_ov);
 		set_except_vector(13, handle_tr);
 		set_except_vector(15, handle_fpe);
-
-		/*
-		 * Compute mask for page_colour().  This is based on the
-		 * size of the data cache.  Does the size of the icache
-		 * need to be accounted for?
-		 *
-		 * FIXME: is any of this necessary for the R3000, which
-		 *        doesn't have a config register?
-		 *        (No, the R2000, R3000 family has a physical indexed
-		 *        cache and doesn't need this braindamage.)
-		i = read_32bit_cp0_register(CP0_CONFIG);
-		i = (i >> 26) & 7;
-		page_colour_mask = 1 << (12 + i);
-		 */
 		break;
 	case CPU_R3041:
 	case CPU_R3051:
@@ -619,5 +649,5 @@
 	default:
 		panic("Unknown CPU type");
 	}
-	flush_cache_all();
+	flush_icache_range(KSEG0, KSEG0 + 0x200);
 }
diff -u --recursive --new-file v2.1.72/linux/arch/mips/kernel/unaligned.c linux/arch/mips/kernel/unaligned.c
--- v2.1.72/linux/arch/mips/kernel/unaligned.c	Thu Jun 26 12:33:37 1997
+++ linux/arch/mips/kernel/unaligned.c	Wed Dec 10 10:31:10 1997
@@ -407,11 +407,11 @@
 {
 	register_t pc = regs->cp0_epc;
 	register_t badvaddr __attribute__ ((unused)) = regs->cp0_badvaddr;
-	char *adels;
+	char adels;
 
 	lock_kernel();
 	adels = (((regs->cp0_cause & CAUSEF_EXCCODE) >>
-                  CAUSEB_EXCCODE) == 4) ? "adel" : "ades";
+                  CAUSEB_EXCCODE) == 4) ? 'l' : 's';
 
 #ifdef CONF_NO_UNALIGNED_KERNEL_ACCESS
 	/*
@@ -420,13 +420,8 @@
 	 */
 	if (kernel_address(badvaddr) && !user_mode(regs)) {
 		show_regs(regs);
-#ifdef __mips64
-		panic("Caught %s exception in kernel mode accessing %016Lx.",
-                      adels, badvaddr);
-#else
-		panic("Caught %s exception in kernel mode accessing %08lx.",
-                      adels, badvaddr);
-#endif
+		panic("Caught adel%c exception in kernel mode accessing %08lx.",
+		      adels, badvaddr);
 	}
 #endif /* CONF_NO_UNALIGNED_KERNEL_ACCESS */
 
@@ -435,15 +430,9 @@
 		register_t logpc = pc;
 		if (regs->cp0_cause & CAUSEF_BD)
 			logpc += 4;
-#ifdef __mips64
 		printk(KERN_DEBUG
-		       "Caught %s in '%s' at 0x%016Lx accessing 0x%016Lx.\n",
+		       "Caught adel%c in '%s' at 0x%08lx accessing 0x%08lx.\n",
 		       adels, current->comm, logpc, regs->cp0_badvaddr);
-#else
-		printk(KERN_DEBUG
-		       "Caught %s in '%s' at 0x%08lx accessing 0x%08lx.\n",
-		       adels, current->comm, logpc, regs->cp0_badvaddr);
-#endif
 	}
 #endif /* CONF_LOG_UNALIGNED_ACCESSES */
 
diff -u --recursive --new-file v2.1.72/linux/arch/mips/lib/Makefile linux/arch/mips/lib/Makefile
--- v2.1.72/linux/arch/mips/lib/Makefile	Mon Aug 18 18:19:43 1997
+++ linux/arch/mips/lib/Makefile	Wed Dec 10 10:31:10 1997
@@ -14,8 +14,8 @@
 	$(CC) $(CFLAGS) -c $< -o $*.o
 
 L_TARGET = lib.a
-L_OBJS	= beep.o checksum.o copy_user.o csum.o dump_tlb.o io.o memset.o \
-	  memcpy.o strlen_user.o strncpy_user.o tags.o watch.o
+L_OBJS	= beep.o checksum.o copy_user.o csum.o dump_tlb.o memset.o memcpy.o \
+          strlen_user.o strncpy_user.o tags.o watch.o
 
 ifdef CONFIG_DECSTATION
 L_OBJS += pmaxcon.o pmaxio.o
diff -u --recursive --new-file v2.1.72/linux/arch/mips/lib/checksum.c linux/arch/mips/lib/checksum.c
--- v2.1.72/linux/arch/mips/lib/checksum.c	Mon Aug 18 18:19:43 1997
+++ linux/arch/mips/lib/checksum.c	Wed Dec 10 10:31:10 1997
@@ -14,7 +14,7 @@
  *		as published by the Free Software Foundation; either version
  *		2 of the License, or (at your option) any later version.
  *
- * $Id: checksum.c,v 1.5 1997/08/08 18:12:51 miguel Exp $
+ * $Id: checksum.c,v 1.2 1997/07/29 18:37:35 ralf Exp $
  */
 #include <net/checksum.h>
 #include <linux/types.h>
diff -u --recursive --new-file v2.1.72/linux/arch/mips/lib/copy_user.S linux/arch/mips/lib/copy_user.S
--- v2.1.72/linux/arch/mips/lib/copy_user.S	Thu Jun 26 12:33:37 1997
+++ linux/arch/mips/lib/copy_user.S	Wed Dec 10 10:31:10 1997
@@ -1,13 +1,15 @@
 /*
- * arch/mips/mips1/memcpy.S
+ * arch/mips/lib/copy_user.S
  *
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (c) 1996 by Ralf Baechle
+ * Copyright (c) 1996, 1997 by Ralf Baechle
  *
- * Less stupid memcpy/user_copy implementation for 32 bit MIPS CPUs.
+ * Less stupid user_copy implementation for 32 bit MIPS CPUs.
+ *
+ * $Id: copy_user.S,v 1.2 1997/08/11 04:26:12 ralf Exp $
  */
 #include <asm/asm.h>
 #include <asm/regdef.h>
@@ -34,11 +36,11 @@
  */
 not_even_the_same_alignment:
 		LONG_SUBU	v1,zero,a1
-		andi		v1,a1,3
+		andi		v1,3
 		sltu		t0,v0,v1
 		MOVN(v1,v0,t0)
-		beqz		v1,align4		# -> finished
-		LONG_ADDU	v1,a0			# delay slot
+		beqz		v1,src_aligned
+		 LONG_ADDU	v1,a0
 1:		lb		$1,(a1)
 		EX(1b, fault)
 		LONG_ADDIU	a1,1
@@ -46,7 +48,8 @@
 		EX(2b, fault)
 		LONG_ADDIU	a0,1
 		bne		a0,v1,1b
-		LONG_SUBU	v0,1			# delay slot
+		 LONG_SUBU	v0,1
+src_aligned:
 
 /*
  * Ok.  We've fixed the alignment of the copy src for this case.
@@ -54,12 +57,13 @@
  * stores.
  * XXX Align the destination address.  This is better if the __copy_user
  *     encounters an access fault because we never have to deal with an
- *     only partially modified destination word.
+ *     only partially modified destination word.  This is required to
+ *     keep the semantics of the result of copy_*_user().
  */
 		ori		v1,v0,BLOCK_SIZE-1
 		xori		v1,BLOCK_SIZE-1
 		beqz		v1,copy_left_over
-		nop				# delay slot
+		 nop
 		LONG_SUBU	v0,v1
 		LONG_ADDU	v1,a0
 
@@ -81,16 +85,16 @@
 		UEX(2b, fault_plus_12)
 		LONG_ADDIU	a0,BLOCK_SIZE
 		bne		a0,v1,1b
-		LONG_ADDIU	a1,BLOCK_SIZE	# delay slot
+		 LONG_ADDIU	a1,BLOCK_SIZE
 9:
 		b		copy_left_over	# < BLOCK_SIZE bytes left
-		nop				# delay slot
+		 nop
 
 /* ---------------------------------------------------------------------- */
 
 not_w_aligned:
 /*
- * Ok, src or destination are not 8-byte aligned.
+ * Ok, src or destination are not 4-byte aligned.
  * Try to fix that.  Do at least both addresses have the same alignment?
  */
 		xor		t0,a0,a1
@@ -107,8 +111,8 @@
 		andi		v1,3
 		sltu		t0,v0,v1
 		MOVN(v1,v0,t0)
-		beqz		v1,3f			# -> finished
-		LONG_ADDU	v1,a0			# delay slot
+		beqz		v1,__copy_user
+		 LONG_ADDU	v1,a0
 1:		lb		$1,(a1)
 		EX(1b, fault)
 		LONG_ADDIU	a1,1
@@ -116,24 +120,23 @@
 		EX(2b, fault)
 		LONG_ADDIU	a0,1
 		bne		a0,v1,1b
-		LONG_SUBU	v0,1			# delay slot
+		 LONG_SUBU	v0,1
 		b		align4
-		nop					# delay slot
-3:
+		 nop
 
 /* ---------------------------------------------------------------------- */
 
 LEAF(__copy_user)
 		or		t1,a0,a1
 		andi		t1,3
-		bnez		t1,not_w_aligned
-		move		v0,a2			# delay slot
+		bnez		t1,not_w_aligned	# not word alignment
+		 move		v0,a2
 
 align4:
 		ori		v1,v0,BLOCK_SIZE-1
 		xori		v1,BLOCK_SIZE-1
 		beqz		v1,copy_left_over
-		nop				# delay slot
+		 nop
 		LONG_SUBU	v0,v1
 		LONG_ADDU	v1,a0
 
@@ -155,7 +158,7 @@
 		EX(2b, fault_plus_12)
 		LONG_ADDIU	a0,BLOCK_SIZE
 		bne		a0,v1,1b
-		LONG_ADDIU	a1,BLOCK_SIZE	# delay slot
+		 LONG_ADDIU	a1,BLOCK_SIZE
 9:
 
 /*
@@ -163,7 +166,7 @@
  */
 copy_left_over:
 		beqz		v0,3f
-		nop					# delay slot
+		 nop
 1:		lb		$1,(a1)
 		EX(1b, fault)
 		LONG_ADDIU	a1,1
@@ -171,9 +174,11 @@
 		EX(2b, fault)
 		LONG_SUBU	v0,1
 		bnez		v0,1b
-		LONG_ADDIU	a0,1
-3:		jr		ra
-		nop				# delay slot
+		 LONG_ADDIU	a0,1
+3:
+
+done:		jr		ra
+		 nop
 
 		END(__copy_user)
 		.set		at
@@ -194,14 +199,3 @@
 			jr	ra
 fault_plus_12:		LONG_ADDIU	v0,12
 			jr	ra
-
-/* ---------------------------------------------------------------------- */
-
-/*
- * For now we use __copy_user for __memcpy, too.  This is effizient (one
- * instruction penatly) and smaller but adds unwanted error checking we don't
- * need.  This hopefully doesn't cover any bugs.  The memcpy() wrapper in
- * <asm/string.h> takes care of the return value in a way GCC can optimize.
- */
-		.globl	__memcpy
-__memcpy	=	__copy_user
diff -u --recursive --new-file v2.1.72/linux/arch/mips/lib/io.c linux/arch/mips/lib/io.c
--- v2.1.72/linux/arch/mips/lib/io.c	Thu Jun 26 12:33:37 1997
+++ linux/arch/mips/lib/io.c	Wed Dec 31 16:00:00 1969
@@ -1,24 +0,0 @@
-/*
- * include/asm-mips/string.h
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (c) 1994, 1995, 1996 by Ralf Baechle
- *
- * For now io.c contains only the definition of isa_slot_offset.  The
- * real io.S doesn't assemble due to a GAS bug.
- */
-
-/*
- * port_base is the begin of the address space to which x86 style
- * I/O ports are mapped.
- */
-unsigned long port_base;
-
-/*
- * isa_slot_offset is the address where E(ISA) busaddress 0 is is mapped
- * for the processor.
- */
-unsigned long isa_slot_offset;
diff -u --recursive --new-file v2.1.72/linux/arch/mips/mm/andes.c linux/arch/mips/mm/andes.c
--- v2.1.72/linux/arch/mips/mm/andes.c	Mon Aug 18 18:19:43 1997
+++ linux/arch/mips/mm/andes.c	Wed Dec 10 10:31:10 1997
@@ -1,4 +1,4 @@
-/* $Id: andes.c,v 1.2 1997/08/08 18:13:01 miguel Exp $
+/* $Id: andes.c,v 1.2 1997/12/02 05:51:07 ralf Exp $
  * andes.c: MMU and cache operations for the R10000 (ANDES).
  *
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
diff -u --recursive --new-file v2.1.72/linux/arch/mips/mm/loadmmu.c linux/arch/mips/mm/loadmmu.c
--- v2.1.72/linux/arch/mips/mm/loadmmu.c	Mon Aug 18 18:19:43 1997
+++ linux/arch/mips/mm/loadmmu.c	Wed Dec 10 10:31:10 1997
@@ -1,7 +1,9 @@
-/* $Id: loadmmu.c,v 1.2 1997/08/08 18:13:05 miguel Exp $
+/*
  * loadmmu.c: Setup cpu/cache specific function ptrs at boot time.
  *
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ *
+ * $Id: loadmmu.c,v 1.4 1997/12/02 05:51:07 ralf Exp $
  */
 
 #include <linux/kernel.h>
@@ -27,6 +29,10 @@
 void (*flush_cache_sigtramp)(unsigned long addr);
 void (*flush_page_to_ram)(unsigned long page);
 
+/* DMA cache operations. */
+void (*flush_cache_pre_dma_out)(unsigned long start, unsigned long size);
+void (*flush_cache_post_dma_in)(unsigned long start, unsigned long size);
+
 /* TLB operations. */
 void (*flush_tlb_all)(void);
 void (*flush_tlb_mm)(struct mm_struct *mm);
@@ -76,6 +82,7 @@
 	case CPU_R4700:
 	case CPU_R5000:
 	case CPU_R5000A:
+	case CPU_NEVADA:
 		printk("Loading R4000 MMU routines.\n");
 		ld_mmu_r4xx0();
 		break;
diff -u --recursive --new-file v2.1.72/linux/arch/mips/mm/r2300.c linux/arch/mips/mm/r2300.c
--- v2.1.72/linux/arch/mips/mm/r2300.c	Mon Aug 18 18:19:43 1997
+++ linux/arch/mips/mm/r2300.c	Wed Dec 10 10:31:10 1997
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
  *
- * $Id: r2300.c,v 1.3 1997/08/08 18:13:06 miguel Exp $
+ * $Id: r2300.c,v 1.3 1997/12/02 05:51:08 ralf Exp $
  */
 
 #include <linux/kernel.h>
diff -u --recursive --new-file v2.1.72/linux/arch/mips/mm/r4xx0.c linux/arch/mips/mm/r4xx0.c
--- v2.1.72/linux/arch/mips/mm/r4xx0.c	Mon Aug 18 18:19:43 1997
+++ linux/arch/mips/mm/r4xx0.c	Wed Dec 10 10:31:10 1997
@@ -3,7 +3,13 @@
  *
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
  *
- * $Id: r4xx0.c,v 1.5 1997/08/08 18:13:07 miguel Exp $
+ * $Id: r4xx0.c,v 1.11 1997/12/02 06:33:53 ralf Exp $
+ *
+ * To do:
+ *
+ *  - this code is a overbloated pig
+ *  - many of the bug workarounds are not efficient at all, but at
+ *    least they are functional ...
  */
 #include <linux/config.h>
 
@@ -39,7 +45,17 @@
 #undef DEBUG_CACHE
 
 /*
- * Zero an entire page.
+ * On processors with QED R4600 style two set assosicative cache
+ * this is the bit which selects the way in the cache for the
+ * indexed cachops.
+ */
+#define icache_waybit (icache_size >> 1)
+#define dcache_waybit (dcache_size >> 1)
+
+/*
+ * Zero an entire page.  We have three flavours of the routine available.
+ * One for CPU with 16byte, with 32byte cachelines plus a special version
+ * with nops which handles the buggy R4600 v1.x.
  */
 
 static void r4k_clear_page_d16(unsigned long page)
@@ -108,7 +124,7 @@
  * IDT R4600 V1.7 errata:
  *
  *  18. The CACHE instructions Hit_Writeback_Invalidate_D, Hit_Writeback_D,
- *      Hit_Invalidate_D and Create_Dirty_Exclusive_D should only be
+ *      Hit_Invalidate_D and Create_Dirty_Excl_D should only be
  *      executed if there is no other dcache activity. If the dcache is
  *      accessed for another instruction immeidately preceding when these
  *      cache instructions are executing, it is possible that the dcache 
@@ -167,6 +183,44 @@
 }
 
 /*
+ * And this one is for the R4600 V2.0
+ */
+static void r4k_clear_page_r4600_v2(unsigned long page)
+{
+	unsigned int flags;
+
+	save_and_cli(flags);
+	*(volatile unsigned int *)KSEG1;
+	__asm__ __volatile__(
+		".set\tnoreorder\n\t"
+		".set\tnoat\n\t"
+		".set\tmips3\n\t"
+		"daddiu\t$1,%0,%2\n"
+		"1:\tcache\t%3,(%0)\n\t"
+		"sd\t$0,(%0)\n\t"
+		"sd\t$0,8(%0)\n\t"
+		"sd\t$0,16(%0)\n\t"
+		"sd\t$0,24(%0)\n\t"
+		"daddiu\t%0,64\n\t"
+		"cache\t%3,-32(%0)\n\t"
+		"sd\t$0,-32(%0)\n\t"
+		"sd\t$0,-24(%0)\n\t"
+		"sd\t$0,-16(%0)\n\t"
+		"bne\t$1,%0,1b\n\t"
+		"sd\t$0,-8(%0)\n\t"
+		".set\tmips0\n\t"
+		".set\tat\n\t"
+		".set\treorder"
+		:"=r" (page)
+		:"0" (page),
+		 "I" (PAGE_SIZE),
+		 "i" (Create_Dirty_Excl_D)
+		:"$1","memory");
+	restore_flags(flags);
+}
+
+
+/*
  * This is still inefficient.  We only can do better if we know the
  * virtual address where the copy will be accessed.
  */
@@ -355,6 +409,74 @@
 		 "i" (Create_Dirty_Excl_D));
 }
 
+static void r4k_copy_page_r4600_v2(unsigned long to, unsigned long from)
+{
+	unsigned long dummy1, dummy2;
+	unsigned long reg1, reg2, reg3, reg4;
+	unsigned int flags;
+
+	__save_and_cli(flags);
+	__asm__ __volatile__(
+		".set\tnoreorder\n\t"
+		".set\tnoat\n\t"
+		".set\tmips3\n\t"
+		"daddiu\t$1,%0,%8\n"
+		"1:\tnop\n\t"
+		"nop\n\t"
+		"nop\n\t"
+		"nop\n\t"
+		"\tcache\t%9,(%0)\n\t"
+		"lw\t%2,(%1)\n\t"
+		"lw\t%3,4(%1)\n\t"
+		"lw\t%4,8(%1)\n\t"
+		"lw\t%5,12(%1)\n\t"
+		"sw\t%2,(%0)\n\t"
+		"sw\t%3,4(%0)\n\t"
+		"sw\t%4,8(%0)\n\t"
+		"sw\t%5,12(%0)\n\t"
+		"lw\t%2,16(%1)\n\t"
+		"lw\t%3,20(%1)\n\t"
+		"lw\t%4,24(%1)\n\t"
+		"lw\t%5,28(%1)\n\t"
+		"sw\t%2,16(%0)\n\t"
+		"sw\t%3,20(%0)\n\t"
+		"sw\t%4,24(%0)\n\t"
+		"sw\t%5,28(%0)\n\t"
+		"nop\n\t"
+		"nop\n\t"
+		"nop\n\t"
+		"nop\n\t"
+		"cache\t%9,32(%0)\n\t"
+		"daddiu\t%0,64\n\t"
+		"daddiu\t%1,64\n\t"
+		"lw\t%2,-32(%1)\n\t"
+		"lw\t%3,-28(%1)\n\t"
+		"lw\t%4,-24(%1)\n\t"
+		"lw\t%5,-20(%1)\n\t"
+		"sw\t%2,-32(%0)\n\t"
+		"sw\t%3,-28(%0)\n\t"
+		"sw\t%4,-24(%0)\n\t"
+		"sw\t%5,-20(%0)\n\t"
+		"lw\t%2,-16(%1)\n\t"
+		"lw\t%3,-12(%1)\n\t"
+		"lw\t%4,-8(%1)\n\t"
+		"lw\t%5,-4(%1)\n\t"
+		"sw\t%2,-16(%0)\n\t"
+		"sw\t%3,-12(%0)\n\t"
+		"sw\t%4,-8(%0)\n\t"
+		"bne\t$1,%0,1b\n\t"
+		"sw\t%5,-4(%0)\n\t"
+		".set\tmips0\n\t"
+		".set\tat\n\t"
+		".set\treorder"
+		:"=r" (dummy1), "=r" (dummy2),
+		 "=&r" (reg1), "=&r" (reg2), "=&r" (reg3), "=&r" (reg4)
+		:"0" (to), "1" (from),
+		 "I" (PAGE_SIZE),
+		 "i" (Create_Dirty_Excl_D));
+	restore_flags(flags);
+}
+
 /*
  * If you think for one second that this stuff coming up is a lot
  * of bulky code eating too many kernel cache lines.  Think _again_.
@@ -1427,7 +1549,8 @@
 	pte_t *ptep;
 	int text;
 
-	/* If ownes no valid ASID yet, cannot possibly have gotten
+	/*
+	 * If ownes no valid ASID yet, cannot possibly have gotten
 	 * this page into the cache.
 	 */
 	if(mm->context == 0)
@@ -1465,11 +1588,8 @@
 		 */
 		page = (KSEG0 + (page & (dcache_size - 1)));
 		blast_dcache16_page_indexed(page);
-		blast_dcache16_page_indexed(page ^ 0x2000);
-		if(text) {
+		if(text)
 			blast_icache16_page_indexed(page);
-			blast_icache16_page_indexed(page ^ 0x2000);
-		}
 	}
 out:
 	restore_flags(flags);
@@ -1583,10 +1703,10 @@
 		 */
 		page = (KSEG0 + (page & (dcache_size - 1)));
 		blast_dcache32_page_indexed(page);
-		blast_dcache32_page_indexed(page ^ 0x2000);
+		blast_dcache32_page_indexed(page ^ dcache_waybit);
 		if(text) {
 			blast_icache32_page_indexed(page);
-			blast_icache32_page_indexed(page ^ 0x2000);
+			blast_icache32_page_indexed(page ^ icache_waybit);
 		}
 	}
 out:
@@ -1761,7 +1881,9 @@
 }
 
 /*
- * R4600 v2.0 bug: "The CACHE instructions Hit_Writeback_Invalidate_D,
+ * Writeback and invalidate the primary cache dcache before DMA.
+ *
+ * R4600 v2.0 bug: "The CACHE instructions Hit_Writeback_Inv_D,
  * Hit_Writeback_D, Hit_Invalidate_D and Create_Dirty_Exclusive_D will only
  * operate correctly if the internal data cache refill buffer is empty.  These
  * CACHE instructions should be separated from any potential data cache miss
@@ -1769,6 +1891,104 @@
  * (Revision 2.0 device errata from IDT available on http://www.idt.com/
  * in .pdf format.)
  */
+static void
+r4k_flush_cache_pre_dma_out_pc(unsigned long addr, unsigned long size)
+{
+	unsigned long end, a;
+	unsigned int cmode, flags;
+
+	cmode = read_32bit_cp0_register(CP0_CONFIG) & CONFIG_CM_CMASK;
+	if (cmode == CONFIG_CM_CACHABLE_WA ||
+	    cmode == CONFIG_CM_CACHABLE_NO_WA) {
+		/* primary dcache is writethrough, therefore memory
+		   is already consistent with the caches.  */
+		return;
+	}
+
+	if (size >= dcache_size) {
+		flush_cache_all();
+		return;
+	}
+
+	/* Workaround for R4600 bug.  See comment above. */
+	save_and_cli(flags);
+	*(volatile unsigned long *)KSEG1;
+
+	a = addr & ~(dc_lsize - 1);
+	end = (addr + size) & ~(dc_lsize - 1);
+	while (1) {
+		flush_dcache_line(a); /* Hit_Writeback_Inv_D */
+		if (a == end) break;
+		a += dc_lsize;
+	}
+	restore_flags(flags);
+}
+
+static void
+r4k_flush_cache_pre_dma_out_sc(unsigned long addr, unsigned long size)
+{
+	unsigned long end;
+	unsigned long a;
+
+	if (size >= scache_size) {
+		flush_cache_all();
+		return;
+	}
+
+	a = addr & ~(sc_lsize - 1);
+	end = (addr + size) & ~(sc_lsize - 1);
+	while (1) {
+		flush_scache_line(addr); /* Hit_Writeback_Inv_SD */
+		if (addr == end) break;
+		addr += sc_lsize;
+	}
+	r4k_flush_cache_pre_dma_out_pc(addr, size);
+}
+
+static void
+r4k_flush_cache_post_dma_in_pc(unsigned long addr, unsigned long size)
+{
+	unsigned long end;
+	unsigned long a;
+
+	if (size >= dcache_size) {
+		flush_cache_all();
+		return;
+	}
+
+	/* Workaround for R4600 bug.  See comment above. */
+	*(volatile unsigned long *)KSEG1;
+
+	a = addr & ~(dc_lsize - 1);
+	end = (addr + size) & ~(dc_lsize - 1);
+	while (1) {
+		invalidate_dcache_line(a); /* Hit_Invalidate_D */
+		if (a == end) break;
+		a += dc_lsize;
+	}
+}
+
+static void
+r4k_flush_cache_post_dma_in_sc(unsigned long addr, unsigned long size)
+{
+	unsigned long end;
+	unsigned long a;
+
+	if (size >= scache_size) {
+		flush_cache_all();
+		return;
+	}
+
+	a = addr & ~(sc_lsize - 1);
+	end = (addr + size) & ~(sc_lsize - 1);
+	while (1) {
+		invalidate_scache_line(addr); /* Hit_Invalidate_SD */
+		if (addr == end) break;
+		addr += sc_lsize;
+	}
+	r4k_flush_cache_pre_dma_out_pc(addr, size);
+}
+
 static void r4k_flush_page_to_ram_d32i32_r4600(unsigned long page)
 {
 	page &= PAGE_MASK;
@@ -1776,23 +1996,14 @@
 		unsigned long flags;
 
 #ifdef DEBUG_CACHE
-		/* #if 1 */
 		printk("r4600_cram[%08lx]", page);
 #endif
-		/*
-		 * Workaround for R4600 bug.  Explanation see above.
-		 */
-		*(volatile unsigned long *)KSEG1;
-
 		save_and_cli(flags);
 		blast_dcache32_page(page);
-		blast_dcache32_page(page ^ 0x2000);
 #ifdef CONFIG_SGI
 		{
 			unsigned long tmp1, tmp2;
-			/*
-			 * SGI goo.  Have to check this closer ...
-			 */
+
 			__asm__ __volatile__("
 			.set noreorder
 			.set mips3
@@ -1822,20 +2033,48 @@
 	}
 }
 
+/*
+ * While we're protected against bad userland addresses we don't care
+ * very much about what happens in that case.  Usually a segmentation
+ * fault will dump the process later on anyway ...
+ */
 static void r4k_flush_cache_sigtramp(unsigned long addr)
 {
-	addr &= ~(dc_lsize - 1);
-	__asm__ __volatile__("nop;nop;nop;nop");
-	flush_dcache_line(addr);
-	flush_dcache_line(addr + dc_lsize);
-	flush_icache_line(addr);
-	flush_icache_line(addr + dc_lsize);
+	unsigned long daddr, iaddr;
+
+	daddr = addr & ~(dc_lsize - 1);
+	__asm__ __volatile__("nop;nop;nop;nop");	/* R4600 V1.7 */
+	protected_writeback_dcache_line(daddr);
+	protected_writeback_dcache_line(daddr + dc_lsize);
+	iaddr = addr & ~(ic_lsize - 1);
+	protected_flush_icache_line(iaddr);
+	protected_flush_icache_line(iaddr + ic_lsize);
+}
+
+static void r4600v20k_flush_cache_sigtramp(unsigned long addr)
+{
+	unsigned long daddr, iaddr;
+	unsigned int flags;
+
+	daddr = addr & ~(dc_lsize - 1);
+	save_and_cli(flags);
+
+	/* Clear internal cache refill buffer */
+	*(volatile unsigned int *)KSEG1;
+
+	protected_writeback_dcache_line(daddr);
+	protected_writeback_dcache_line(daddr + dc_lsize);
+	iaddr = addr & ~(ic_lsize - 1);
+	protected_flush_icache_line(iaddr);
+	protected_flush_icache_line(iaddr + ic_lsize);
+	restore_flags(flags);
 }
 
 #undef DEBUG_TLB
 #undef DEBUG_TLBUPDATE
 
 #define NTLB_ENTRIES       48  /* Fixed on all R4XX0 variants... */
+
 #define NTLB_ENTRIES_HALF  24  /* Fixed on all R4XX0 variants... */
 
 static inline void r4k_flush_tlb_all(void)
@@ -1943,7 +2182,7 @@
 		int oldpid, newpid, idx;
 
 #ifdef DEBUG_TLB
-               printk("[tlbpage<%d,%08lx>]", vma->vm_mm->context, page);
+		printk("[tlbpage<%d,%08lx>]", vma->vm_mm->context, page);
 #endif
 		newpid = (vma->vm_mm->context & 0xff);
 		page &= (PAGE_MASK << 1);
@@ -2407,6 +2646,8 @@
 
 static void setup_noscache_funcs(void)
 {
+	unsigned int prid;
+
 	switch(dc_lsize) {
 	case 16:
 		clear_page = r4k_clear_page_d16;
@@ -2418,9 +2659,13 @@
 		flush_page_to_ram = r4k_flush_page_to_ram_d16i16;
 		break;
 	case 32:
-		if ((read_32bit_cp0_register(CP0_PRID) & 0xfff0) == 0x2010) {
+		prid = read_32bit_cp0_register(CP0_PRID) & 0xfff0;
+		if (prid == 0x2010) {			/* R4600 V1.7 */
 			clear_page = r4k_clear_page_r4600_v1;
 			copy_page = r4k_copy_page_r4600_v1;
+		} else if (prid == 0x2020) {		/* R4600 V2.0 */
+			clear_page = r4k_clear_page_r4600_v2;
+			copy_page = r4k_copy_page_r4600_v2;
 		} else {
 			clear_page = r4k_clear_page_d32;
 			copy_page = r4k_copy_page_d32;
@@ -2432,6 +2677,8 @@
 		flush_page_to_ram = r4k_flush_page_to_ram_d32i32;
 		break;
 	}
+	flush_cache_pre_dma_out = r4k_flush_cache_pre_dma_out_pc;
+	flush_cache_post_dma_in = r4k_flush_cache_post_dma_in_pc;
 }
 
 static void setup_scache_funcs(void)
@@ -2524,6 +2771,10 @@
 		};
 		break;
 	}
+
+	/* XXX Do these for Indy style caches also.  No need for now ... */
+	flush_cache_pre_dma_out = r4k_flush_cache_pre_dma_out_sc;
+	flush_cache_post_dma_in = r4k_flush_cache_post_dma_in_sc;
 }
 
 typedef int (*probe_func_t)(unsigned long);
@@ -2534,7 +2785,11 @@
 	unsigned long cfg = read_32bit_cp0_register(CP0_CONFIG);
 	int sc_present = 0;
 
-	printk("CPU REVISION IS: %08x\n", read_32bit_cp0_register(CP0_PRID));
+	printk("CPU revision is: %08x\n", read_32bit_cp0_register(CP0_PRID));
+
+	set_cp0_config(CONFIG_CM_CMASK, CONFIG_CM_CACHABLE_NONCOHERENT);
+//set_cp0_config(CONFIG_CM_CMASK, CONFIG_CM_CACHABLE_WA);
+//set_cp0_config(CONFIG_CM_CMASK, CONFIG_CM_CACHABLE_NO_WA);
 
 	probe_icache(cfg);
 	probe_dcache(cfg);
@@ -2546,7 +2801,6 @@
 	case CPU_R4400PC:
 	case CPU_R4400SC:
 	case CPU_R4400MC:
-try_again:
 		probe_scache_kseg1 = (probe_func_t) (KSEG1ADDR(&probe_scache));
 		sc_present = probe_scache_kseg1(cfg);
 		break;
@@ -2554,39 +2808,44 @@
 	case CPU_R4600:
 	case CPU_R4640:
 	case CPU_R4700:
-	case CPU_R5000:
+	case CPU_R5000:	/* XXX: We don't handle the true R5000 SCACHE */
+	case CPU_NEVADA:
 		probe_scache_kseg1 = (probe_func_t)
 			(KSEG1ADDR(&probe_scache_eeprom));
 		sc_present = probe_scache_eeprom(cfg);
 
-		/* Try using tags if eeprom give us bogus data. */
-		if(sc_present == -1)
-			goto try_again;
+		/* Try using tags if eeprom gives us bogus data. */
+		if(sc_present == -1) {
+			probe_scache_kseg1 =
+				(probe_func_t) (KSEG1ADDR(&probe_scache));
+			sc_present = probe_scache_kseg1(cfg);
+		}
 		break;
 	};
 
-	if(!sc_present) {
-		/* Lacks secondary cache. */
-		setup_noscache_funcs();
+	if(sc_present == 1
+	   && (mips_cputype == CPU_R4000SC
+               || mips_cputype == CPU_R4000MC
+               || mips_cputype == CPU_R4400SC
+               || mips_cputype == CPU_R4400MC)) {
+		/* Has a true secondary cache. */
+		setup_scache_funcs();
 	} else {
-		/* Has a secondary cache. */
-		if(mips_cputype != CPU_R4600 &&
-		   mips_cputype != CPU_R4640 &&
-		   mips_cputype != CPU_R4700 &&
-		   mips_cputype != CPU_R5000) {
-			setup_scache_funcs();
-		} else {
-			setup_noscache_funcs();
-			if((mips_cputype != CPU_R5000)) {
-				flush_cache_page =
-					r4k_flush_cache_page_d32i32_r4600;
-				flush_page_to_ram =
-					r4k_flush_page_to_ram_d32i32_r4600;
-			}
+		/* Lacks true secondary cache. */
+		setup_noscache_funcs();
+		if((mips_cputype != CPU_R5000)) { /* XXX */
+			flush_cache_page =
+				r4k_flush_cache_page_d32i32_r4600;
+			flush_page_to_ram =
+				r4k_flush_page_to_ram_d32i32_r4600;
 		}
 	}
 
+	/* XXX Handle true second level cache w/ split I/D */
 	flush_cache_sigtramp = r4k_flush_cache_sigtramp;
+	if ((read_32bit_cp0_register(CP0_PRID) & 0xfff0) == 0x2020) {
+		flush_cache_sigtramp = r4600v20k_flush_cache_sigtramp;
+	}
 
 	flush_tlb_all = r4k_flush_tlb_all;
 	flush_tlb_mm = r4k_flush_tlb_mm;
diff -u --recursive --new-file v2.1.72/linux/arch/mips/mm/r6000.c linux/arch/mips/mm/r6000.c
--- v2.1.72/linux/arch/mips/mm/r6000.c	Mon Aug 18 18:19:43 1997
+++ linux/arch/mips/mm/r6000.c	Wed Dec 10 10:31:10 1997
@@ -1,4 +1,4 @@
-/* $Id: r6000.c,v 1.2 1997/08/08 18:13:11 miguel Exp $
+/* $Id: r6000.c,v 1.2 1997/12/02 05:51:08 ralf Exp $
  * r6000.c: MMU and cache routines for the R6000 processors.
  *
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
diff -u --recursive --new-file v2.1.72/linux/arch/mips/mm/tfp.c linux/arch/mips/mm/tfp.c
--- v2.1.72/linux/arch/mips/mm/tfp.c	Mon Aug 18 18:19:43 1997
+++ linux/arch/mips/mm/tfp.c	Wed Dec 10 10:31:10 1997
@@ -1,4 +1,4 @@
-/* $Id: tfp.c,v 1.2 1997/08/08 18:13:13 miguel Exp $
+/* $Id: tfp.c,v 1.2 1997/12/02 05:51:09 ralf Exp $
  * tfp.c: MMU and cache routines specific to the r8000 (TFP).
  *
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
diff -u --recursive --new-file v2.1.72/linux/arch/mips/sgi/kernel/Makefile linux/arch/mips/sgi/kernel/Makefile
--- v2.1.72/linux/arch/mips/sgi/kernel/Makefile	Thu Jun 26 12:33:38 1997
+++ linux/arch/mips/sgi/kernel/Makefile	Wed Dec 10 10:31:10 1997
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.1 1997/06/06 09:36:08 ralf Exp $
+# $Id: Makefile,v 1.1.1.1 1997/06/01 03:16:40 ralf Exp $
 # Makefile for the SGI specific kernel interface routines
 # under Linux.
 #
diff -u --recursive --new-file v2.1.72/linux/arch/mips/sgi/kernel/indyIRQ.S linux/arch/mips/sgi/kernel/indyIRQ.S
--- v2.1.72/linux/arch/mips/sgi/kernel/indyIRQ.S	Thu Jun 26 12:33:38 1997
+++ linux/arch/mips/sgi/kernel/indyIRQ.S	Wed Dec 10 10:31:10 1997
@@ -1,4 +1,4 @@
-/* $Id: indyIRQ.S,v 1.1 1997/06/06 09:36:13 ralf Exp $
+/* $Id: indyIRQ.S,v 1.2 1997/09/20 19:20:14 root Exp $
  * indyIRQ.S: Interrupt exception dispatch code for FullHouse and
  *            Guiness.
  *
@@ -72,7 +72,7 @@
 	jal	indy_timer_interrupt
 	 nop				# delay slot
 
-	j	ret_from_sys_call
+	j	ret_from_irq
 	 nop				# delay slot
 
 1:
@@ -83,7 +83,7 @@
 	jal	indy_local0_irqdispatch
 	 move	a0, sp			# delay slot
 
-	j	ret_from_sys_call
+	j	ret_from_irq
 	 nop				# delay slot
 
 1:
@@ -95,7 +95,7 @@
 	jal	indy_local1_irqdispatch
 	 nop
 
-	j	ret_from_sys_call
+	j	ret_from_irq
 	 nop
 
 1:
@@ -107,7 +107,7 @@
 	jal	indy_buserror_irq
 	 nop
 
-	j	ret_from_sys_call
+	j	ret_from_irq
 	 nop
 
 1:
@@ -124,6 +124,6 @@
 	jal	indy_8254timer_irq
 	 nop
 1:
-	j	ret_from_sys_call
+	j	ret_from_irq
 	 nop
 	END(indyIRQ)
diff -u --recursive --new-file v2.1.72/linux/arch/mips/sgi/kernel/indy_hpc.c linux/arch/mips/sgi/kernel/indy_hpc.c
--- v2.1.72/linux/arch/mips/sgi/kernel/indy_hpc.c	Thu Jun 26 12:33:38 1997
+++ linux/arch/mips/sgi/kernel/indy_hpc.c	Wed Dec 10 10:31:10 1997
@@ -1,4 +1,4 @@
-/* $Id: indy_hpc.c,v 1.1 1997/06/06 09:36:18 ralf Exp $
+/* $Id: indy_hpc.c,v 1.1.1.1 1997/06/01 03:16:40 ralf Exp $
  * indy_hpc.c: Routines for generic manipulation of the HPC controllers.
  *
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
diff -u --recursive --new-file v2.1.72/linux/arch/mips/sgi/kernel/indy_int.c linux/arch/mips/sgi/kernel/indy_int.c
--- v2.1.72/linux/arch/mips/sgi/kernel/indy_int.c	Mon Jul  7 08:18:54 1997
+++ linux/arch/mips/sgi/kernel/indy_int.c	Wed Dec 10 10:31:10 1997
@@ -4,7 +4,7 @@
  *
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
  *
- * $Id: indy_int.c,v 1.2 1997/06/30 15:53:01 ralf Exp $
+ * $Id: indy_int.c,v 1.4 1997/09/20 19:20:15 root Exp $
  */
 #include <linux/config.h>
 
@@ -260,13 +260,6 @@
 
 atomic_t __mips_bh_counter;
 
-#ifdef __SMP__
-#error Send superfluous SMP boxes to ralf@uni-koblenz.de
-#else
-#define irq_enter(cpu, irq)     (++local_irq_count[cpu])
-#define irq_exit(cpu, irq)      (--local_irq_count[cpu])
-#endif
-
 /*
  * do_IRQ handles IRQ's that have been installed without the
  * SA_INTERRUPT flag: it uses the full signal-handling return
@@ -276,43 +269,49 @@
  */
 asmlinkage void do_IRQ(int irq, struct pt_regs * regs)
 {
-	struct irqaction * action = *(irq + irq_action);
+	struct irqaction *action;
+	int do_random, cpu;
 
-	lock_kernel();
+	cpu = smp_processor_id();
+	irq_enter(cpu, irq);
 	kstat.interrupts[irq]++;
-	printk("Got irq %d, press a key.", irq);
-	prom_getchar();
-	romvec->imode();
-        while (action) {
-		if (action->flags & SA_SAMPLE_RANDOM)
-			add_interrupt_randomness(irq);
-		action->handler(irq, action->dev_id, regs);
-		action = action->next;
-        }
-	unlock_kernel();
-}
-
-/*
- * do_fast_IRQ handles IRQ's that don't need the fancy interrupt return
- * stuff - the handler is also running with interrupts disabled unless
- * it explicitly enables them later.
- */
-asmlinkage void do_fast_IRQ(int irq)
-{
-	struct irqaction * action = *(irq + irq_action);
 
-	lock_kernel();
 	printk("Got irq %d, press a key.", irq);
 	prom_getchar();
 	romvec->imode();
-	kstat.interrupts[irq]++;
-        while (action) {
-		if (action->flags & SA_SAMPLE_RANDOM)
+
+	/*
+	 * mask and ack quickly, we don't want the irq controller
+	 * thinking we're snobs just because some other CPU has
+	 * disabled global interrupts (we have already done the
+	 * INT_ACK cycles, it's too late to try to pretend to the
+	 * controller that we aren't taking the interrupt).
+	 *
+	 * Commented out because we've already done this in the
+	 * machinespecific part of the handler.  It's reasonable to
+	 * do this here in a highlevel language though because that way
+	 * we could get rid of a good part of duplicated code ...
+	 */
+        /* mask_and_ack_irq(irq); */
+
+	action = *(irq + irq_action);
+	if (action) {
+		if (!(action->flags & SA_INTERRUPT))
+			__sti();
+		action = *(irq + irq_action);
+		do_random = 0;
+		do {
+			do_random |= action->flags;
+			action->handler(irq, action->dev_id, regs);
+			action = action->next;
+		} while (action);
+		if (do_random & SA_SAMPLE_RANDOM)
 			add_interrupt_randomness(irq);
-		action->handler(irq, action->dev_id, NULL);
-		action = action->next;
-        }
-	unlock_kernel();
+		__cli();
+	}
+	irq_exit(cpu, irq);
+
+	/* unmasking and bottom half handling is done magically for us. */
 }
 
 int request_local_irq(unsigned int lirq, void (*func)(int, void *, struct pt_regs *),
@@ -419,10 +418,6 @@
 
 void init_IRQ(void)
 {
-	int i;
-
-	for (i = 0; i < 16 ; i++)
-		set_int_vector(i, 0);
 	irq_setup();
 }
 
@@ -431,7 +426,7 @@
 	struct irqaction *action;
 	unsigned char mask = ioc_icontrol->istat0;
 	unsigned char mask2 = 0;
-	int irq;
+	int irq, cpu = smp_processor_id();;
 
 	mask &= ioc_icontrol->imask0;
 	if(mask & ISTAT0_LIO2) {
@@ -443,13 +438,11 @@
 		irq = lc0msk_to_irqnr[mask];
 		action = local_irq_action[irq];
 	}
-#if 0
-	printk("local0_dispatch: got irq %d mask %2x mask2 %2x\n",
-	       irq, mask, mask2);
-	prom_getchar();
-#endif
+
+	irq_enter(cpu, irq);
 	kstat.interrupts[irq + 16]++;
 	action->handler(irq, action->dev_id, regs);
+	irq_exit(cpu, irq);
 }
 
 void indy_local1_irqdispatch(struct pt_regs *regs)
@@ -457,7 +450,7 @@
 	struct irqaction *action;
 	unsigned char mask = ioc_icontrol->istat1;
 	unsigned char mask2 = 0;
-	int irq;
+	int irq, cpu = smp_processor_id();;
 
 	mask &= ioc_icontrol->imask1;
 	if(mask & ISTAT1_LIO3) {
@@ -470,23 +463,24 @@
 		irq = lc1msk_to_irqnr[mask];
 		action = local_irq_action[irq];
 	}
-#if 0
-	printk("local1_dispatch: got irq %d mask %2x mask2 %2x\n",
-	       irq, mask, mask2);
-	prom_getchar();
-#endif
+	irq_enter(cpu, irq);
 	kstat.interrupts[irq + 24]++;
 	action->handler(irq, action->dev_id, regs);
+	irq_exit(cpu, irq);
 }
 
 void indy_buserror_irq(struct pt_regs *regs)
 {
-	kstat.interrupts[6]++;
+	int cpu = smp_processor_id();
+	int irq = 6;
+
+	irq_enter(cpu, irq);
+	kstat.interrupts[irq]++;
 	printk("Got a bus error IRQ, shouldn't happen yet\n");
 	show_regs(regs);
 	printk("Spinning...\n");
-	while(1)
-		;
+	while(1);
+	irq_exit(cpu, irq);
 }
 
 /* Misc. crap just to keep the kernel linking... */
diff -u --recursive --new-file v2.1.72/linux/arch/mips/sgi/kernel/indy_mc.c linux/arch/mips/sgi/kernel/indy_mc.c
--- v2.1.72/linux/arch/mips/sgi/kernel/indy_mc.c	Thu Jun 26 12:33:38 1997
+++ linux/arch/mips/sgi/kernel/indy_mc.c	Wed Dec 10 10:31:10 1997
@@ -1,4 +1,4 @@
-/* $Id: indy_mc.c,v 1.1 1997/06/06 09:36:24 ralf Exp $
+/* $Id: indy_mc.c,v 1.1.1.1 1997/06/01 03:16:40 ralf Exp $
  * indy_mc.c: Routines for manipulating the INDY memory controller.
  *
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
diff -u --recursive --new-file v2.1.72/linux/arch/mips/sgi/kernel/indy_timer.c linux/arch/mips/sgi/kernel/indy_timer.c
--- v2.1.72/linux/arch/mips/sgi/kernel/indy_timer.c	Mon Jul  7 08:18:54 1997
+++ linux/arch/mips/sgi/kernel/indy_timer.c	Wed Dec 10 10:31:10 1997
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
  *
- * $Id: indy_timer.c,v 1.2 1997/06/30 15:53:04 ralf Exp $
+ * $Id: indy_timer.c,v 1.3 1997/08/11 04:37:09 ralf Exp $
  */
 
 #include <linux/errno.h>
@@ -101,10 +101,12 @@
 
 void indy_timer_interrupt(struct pt_regs *regs)
 {
+	int irq = 7;
+
 	/* Ack timer and compute new compare. */
 	r4k_cur = (read_32bit_cp0_register(CP0_COUNT) + r4k_offset);
 	ack_r4ktimer(r4k_cur);
-	kstat.interrupts[7]++;
+	kstat.interrupts[irq]++;
 	do_timer(regs);
 
 	/* We update the Dallas time of day approx. every 11 minutes,
@@ -272,10 +274,15 @@
 
 void indy_8254timer_irq(void)
 {
-	kstat.interrupts[4]++;
+	int cpu = smp_processor_id();
+	int irq = 4;
+
+	irq_enter(cpu, irq);
+	kstat.interrupts[irq]++;
 	printk("indy_8254timer_irq: Whoops, should not have gotten this IRQ\n");
 	prom_getchar();
 	prom_imode();
+	irq_exit(cpu, irq);
 }
 
 void do_gettimeofday(struct timeval *tv)
diff -u --recursive --new-file v2.1.72/linux/arch/mips/sgi/kernel/setup.c linux/arch/mips/sgi/kernel/setup.c
--- v2.1.72/linux/arch/mips/sgi/kernel/setup.c	Mon Aug 18 18:19:43 1997
+++ linux/arch/mips/sgi/kernel/setup.c	Wed Dec 10 10:31:10 1997
@@ -3,11 +3,8 @@
  *
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
  *
- * $Id: setup.c,v 1.3 1997/08/08 18:13:22 miguel Exp $
+ * $Id: setup.c,v 1.5 1997/09/13 02:19:18 ralf Exp $
  */
-#ifndef __GOGOGO__
-#error "... about to fuckup your Indy?"
-#endif
 #include <linux/kernel.h>
 #include <linux/sched.h>
 
@@ -65,21 +62,6 @@
 	sgint_init();
 }
 
-#if 0
-extern void register_console(void (*proc)(const char *));
-
-static void sgi_print(const char *p)
-{
-	char c;
-
-	while((c = *p++) != 0) {
-		if(c == '\n')
-			prom_putchar('\r');
-		prom_putchar(c);
-	}
-}
-#endif
-
 void sgi_setup(void)
 {
 	char *ctype;
@@ -91,8 +73,6 @@
 	_machine_restart = sgi_machine_restart;
 	_machine_halt = sgi_machine_halt;
 	_machine_power_off = sgi_machine_power_off;
-
-	/* register_console(sgi_print); */
 
 	/* Init the INDY HPC I/O controller.  Need to call this before
 	 * fucking with the memory controller because it needs to know the
diff -u --recursive --new-file v2.1.72/linux/arch/mips/sgi/kernel/system.c linux/arch/mips/sgi/kernel/system.c
--- v2.1.72/linux/arch/mips/sgi/kernel/system.c	Mon Jul  7 08:18:54 1997
+++ linux/arch/mips/sgi/kernel/system.c	Wed Dec 10 10:31:10 1997
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
  *
- * $Id: system.c,v 1.2 1997/06/30 15:26:32 ralf Exp $
+ * $Id: system.c,v 1.3 1997/09/13 02:19:18 ralf Exp $
  */
 #include <linux/kernel.h>
 #include <linux/types.h>
@@ -12,10 +12,6 @@
 #include <asm/sgi.h>
 #include <asm/sgialib.h>
 #include <asm/bootinfo.h>
-
-#ifndef __GOGOGO__
-#error "... You're fearless, aren't you?"
-#endif
 
 enum sgi_mach sgimach;
 
diff -u --recursive --new-file v2.1.72/linux/arch/mips/sgi/kernel/time.c linux/arch/mips/sgi/kernel/time.c
--- v2.1.72/linux/arch/mips/sgi/kernel/time.c	Thu Jun 26 12:33:38 1997
+++ linux/arch/mips/sgi/kernel/time.c	Wed Dec 10 10:31:10 1997
@@ -1,4 +1,4 @@
-/* $Id: time.c,v 1.1 1997/06/06 09:36:39 ralf Exp $
+/* $Id: time.c,v 1.1.1.1 1997/06/01 03:16:40 ralf Exp $
  * time.c: Generic SGI time_init() code, this will dispatch to the
  *         appropriate per-architecture time/counter init code.
  *
diff -u --recursive --new-file v2.1.72/linux/arch/mips/sgi/prom/Makefile linux/arch/mips/sgi/prom/Makefile
--- v2.1.72/linux/arch/mips/sgi/prom/Makefile	Thu Jun 26 12:33:38 1997
+++ linux/arch/mips/sgi/prom/Makefile	Wed Dec 10 10:31:10 1997
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.1 1997/06/06 09:36:49 ralf Exp $
+# $Id: Makefile,v 1.1.1.1 1997/06/01 03:16:40 ralf Exp $
 # Makefile for the SGI arcs prom monitor library routines
 # under Linux.
 #
diff -u --recursive --new-file v2.1.72/linux/arch/mips/sgi/prom/cmdline.c linux/arch/mips/sgi/prom/cmdline.c
--- v2.1.72/linux/arch/mips/sgi/prom/cmdline.c	Thu Jun 26 12:33:38 1997
+++ linux/arch/mips/sgi/prom/cmdline.c	Wed Dec 10 10:31:10 1997
@@ -1,4 +1,4 @@
-/* $Id: cmdline.c,v 1.1 1997/06/06 09:36:53 ralf Exp $
+/* $Id: cmdline.c,v 1.2 1997/12/02 05:51:09 ralf Exp $
  * cmdline.c: Kernel command line creation using ARCS argc/argv.
  *
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
@@ -52,6 +52,8 @@
 	pic_cont:
 		actr++;
 	}
+	if (cp != &(arcs_cmdline[0])) /* get rid of trailing space */
+		--cp;
 	*cp = '\0';
 
 #ifdef DEBUG_CMDLINE
diff -u --recursive --new-file v2.1.72/linux/arch/mips/sgi/prom/console.c linux/arch/mips/sgi/prom/console.c
--- v2.1.72/linux/arch/mips/sgi/prom/console.c	Thu Jun 26 12:33:38 1997
+++ linux/arch/mips/sgi/prom/console.c	Wed Dec 10 10:31:10 1997
@@ -1,4 +1,4 @@
-/* $Id: console.c,v 1.1 1997/06/06 09:36:56 ralf Exp $
+/* $Id: console.c,v 1.1.1.1 1997/06/01 03:16:40 ralf Exp $
  * console.c: SGI arcs console code.
  *
  * Copyright (C) 1996 David S. Miller (dm@sgi.com)
diff -u --recursive --new-file v2.1.72/linux/arch/mips/sgi/prom/env.c linux/arch/mips/sgi/prom/env.c
--- v2.1.72/linux/arch/mips/sgi/prom/env.c	Thu Jun 26 12:33:38 1997
+++ linux/arch/mips/sgi/prom/env.c	Wed Dec 10 10:31:10 1997
@@ -1,4 +1,4 @@
-/* $Id: env.c,v 1.1 1997/06/06 09:36:59 ralf Exp $
+/* $Id: env.c,v 1.1.1.1 1997/06/01 03:16:40 ralf Exp $
  * env.c: ARCS environment variable routines.
  *
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
diff -u --recursive --new-file v2.1.72/linux/arch/mips/sgi/prom/file.c linux/arch/mips/sgi/prom/file.c
--- v2.1.72/linux/arch/mips/sgi/prom/file.c	Thu Jun 26 12:33:38 1997
+++ linux/arch/mips/sgi/prom/file.c	Wed Dec 10 10:31:10 1997
@@ -1,4 +1,4 @@
-/* $Id: file.c,v 1.1 1997/06/06 09:37:03 ralf Exp $
+/* $Id: file.c,v 1.1.1.1 1997/06/01 03:16:40 ralf Exp $
  * file.c: ARCS firmware interface to files.
  *
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
diff -u --recursive --new-file v2.1.72/linux/arch/mips/sgi/prom/init.c linux/arch/mips/sgi/prom/init.c
--- v2.1.72/linux/arch/mips/sgi/prom/init.c	Thu Jun 26 12:33:38 1997
+++ linux/arch/mips/sgi/prom/init.c	Wed Dec 10 10:31:10 1997
@@ -1,4 +1,4 @@
-/* $Id: init.c,v 1.1 1997/06/06 09:37:06 ralf Exp $
+/* $Id: init.c,v 1.1.1.1 1997/06/01 03:16:40 ralf Exp $
  * init.c: PROM library initialisation code.
  *
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
diff -u --recursive --new-file v2.1.72/linux/arch/mips/sgi/prom/memory.c linux/arch/mips/sgi/prom/memory.c
--- v2.1.72/linux/arch/mips/sgi/prom/memory.c	Thu Jun 26 12:33:38 1997
+++ linux/arch/mips/sgi/prom/memory.c	Wed Dec 10 10:31:10 1997
@@ -1,4 +1,4 @@
-/* $Id: memory.c,v 1.1 1997/06/06 09:37:10 ralf Exp $
+/* $Id: memory.c,v 1.1.1.1 1997/06/01 03:16:40 ralf Exp $
  * memory.c: PROM library functions for acquiring/using memory descriptors
  *           given to us from the ARCS firmware.
  *
diff -u --recursive --new-file v2.1.72/linux/arch/mips/sgi/prom/printf.c linux/arch/mips/sgi/prom/printf.c
--- v2.1.72/linux/arch/mips/sgi/prom/printf.c	Thu Jun 26 12:33:38 1997
+++ linux/arch/mips/sgi/prom/printf.c	Wed Dec 10 10:31:10 1997
@@ -1,4 +1,4 @@
-/* $Id: printf.c,v 1.1 1997/06/06 09:37:17 ralf Exp $
+/* $Id: printf.c,v 1.1.1.1 1997/06/01 03:16:40 ralf Exp $
  * printf.c: Putting things on the screen using SGI arcs
  *           PROM facilities.
  *
diff -u --recursive --new-file v2.1.72/linux/arch/mips/sgi/prom/salone.c linux/arch/mips/sgi/prom/salone.c
--- v2.1.72/linux/arch/mips/sgi/prom/salone.c	Thu Jun 26 12:33:38 1997
+++ linux/arch/mips/sgi/prom/salone.c	Wed Dec 10 10:31:10 1997
@@ -1,4 +1,4 @@
-/* $Id: salone.c,v 1.1 1997/06/06 09:37:20 ralf Exp $
+/* $Id: salone.c,v 1.1.1.1 1997/06/01 03:16:40 ralf Exp $
  * salone.c: Routines to load into memory and execute stand-along
  *           program images using ARCS PROM firmware.
  *
diff -u --recursive --new-file v2.1.72/linux/arch/mips/sgi/prom/tags.c linux/arch/mips/sgi/prom/tags.c
--- v2.1.72/linux/arch/mips/sgi/prom/tags.c	Thu Jun 26 12:33:38 1997
+++ linux/arch/mips/sgi/prom/tags.c	Wed Dec 10 10:31:10 1997
@@ -1,4 +1,4 @@
-/* $Id: tags.c,v 1.1 1997/06/06 09:37:22 ralf Exp $
+/* $Id: tags.c,v 1.1.1.1 1997/06/01 03:16:40 ralf Exp $
  * tags.c: Initialize the arch tags the way the MIPS kernel setup
  *         expects.
  *
diff -u --recursive --new-file v2.1.72/linux/arch/mips/sgi/prom/time.c linux/arch/mips/sgi/prom/time.c
--- v2.1.72/linux/arch/mips/sgi/prom/time.c	Thu Jun 26 12:33:38 1997
+++ linux/arch/mips/sgi/prom/time.c	Wed Dec 10 10:31:10 1997
@@ -1,4 +1,4 @@
-/* $Id: time.c,v 1.1 1997/06/06 09:37:26 ralf Exp $
+/* $Id: time.c,v 1.1.1.1 1997/06/01 03:16:40 ralf Exp $
  * time.c: Extracting time information from ARCS prom.
  *
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
diff -u --recursive --new-file v2.1.72/linux/arch/mips/sgi/prom/tree.c linux/arch/mips/sgi/prom/tree.c
--- v2.1.72/linux/arch/mips/sgi/prom/tree.c	Thu Jun 26 12:33:38 1997
+++ linux/arch/mips/sgi/prom/tree.c	Wed Dec 10 10:31:10 1997
@@ -1,4 +1,4 @@
-/* $Id: tree.c,v 1.1 1997/06/06 09:37:29 ralf Exp $
+/* $Id: tree.c,v 1.1.1.1 1997/06/01 03:16:40 ralf Exp $
  * tree.c: PROM component device tree code.
  *
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
diff -u --recursive --new-file v2.1.72/linux/arch/mips/sni/hw-access.c linux/arch/mips/sni/hw-access.c
--- v2.1.72/linux/arch/mips/sni/hw-access.c	Mon Aug 18 18:19:43 1997
+++ linux/arch/mips/sni/hw-access.c	Wed Dec 10 10:31:10 1997
@@ -7,7 +7,7 @@
  *
  * Copyright (C) 1996, 1997 by Ralf Baechle
  *
- * $Id: hw-access.c,v 1.2 1997/08/08 18:13:27 miguel Exp $
+ * $Id: hw-access.c,v 1.3 1997/07/29 17:46:46 ralf Exp $
  */
 #include <linux/delay.h>
 #include <linux/kbdcntrlr.h>
@@ -47,69 +47,69 @@
  * How to access the floppy DMA functions.
  */
 static void
-fd_enable_dma(void)
+fd_enable_dma(int channel)
 {
-	enable_dma(FLOPPY_DMA);
+	enable_dma(channel);
 }
 
 static void
-fd_disable_dma(void)
+fd_disable_dma(int channel)
 {
-	disable_dma(FLOPPY_DMA);
+	disable_dma(channel);
 }
 
 static int
-fd_request_dma(void)
+fd_request_dma(int channel)
 {
-	return request_dma(FLOPPY_DMA, "floppy");
+	return request_dma(channel, "floppy");
 }
 
 static void
-fd_free_dma(void)
+fd_free_dma(int channel)
 {
-	free_dma(FLOPPY_DMA);
+	free_dma(channel);
 }
 
 static void
-fd_clear_dma_ff(void)
+fd_clear_dma_ff(int channel)
 {
-	clear_dma_ff(FLOPPY_DMA);
+	clear_dma_ff(channel);
 }
 
 static void
-fd_set_dma_mode(char mode)
+fd_set_dma_mode(int channel, char mode)
 {
-	set_dma_mode(FLOPPY_DMA, mode);
+	set_dma_mode(channel, mode);
 }
 
 static void
-fd_set_dma_addr(unsigned int addr)
+fd_set_dma_addr(int channel, unsigned int addr)
 {
-	set_dma_addr(FLOPPY_DMA, addr);
+	set_dma_addr(channel, addr);
 }
 
 static void
-fd_set_dma_count(unsigned int count)
+fd_set_dma_count(int channel, unsigned int count)
 {
-	set_dma_count(FLOPPY_DMA, count);
+	set_dma_count(channel, count);
 }
 
 static int
-fd_get_dma_residue(void)
+fd_get_dma_residue(int channel)
 {
-	return get_dma_residue(FLOPPY_DMA);
+	return get_dma_residue(channel);
 }
 
 static void
-fd_enable_irq(void)
+fd_enable_irq(int irq)
 {
-	enable_irq(FLOPPY_IRQ);
+	enable_irq(irq);
 }
 
 static void
-fd_disable_irq(void)
+fd_disable_irq(int irq)
 {
-	disable_irq(FLOPPY_IRQ);
+	disable_irq(irq);
 }
 
 void
diff -u --recursive --new-file v2.1.72/linux/arch/mips/sni/int-handler.S linux/arch/mips/sni/int-handler.S
--- v2.1.72/linux/arch/mips/sni/int-handler.S	Thu Jun 26 12:33:38 1997
+++ linux/arch/mips/sni/int-handler.S	Wed Dec 10 10:31:10 1997
@@ -2,6 +2,8 @@
  * SNI RM200 PCI specific interrupt handler code.
  *
  * Copyright (C) 1994 - 1997 by Ralf Baechle
+ *
+ * $Id: int-handler.S,v 1.3 1997/12/01 16:39:24 ralf Exp $
  */
 #include <asm/asm.h>
 #include <linux/config.h>
@@ -18,18 +20,77 @@
 		SAVE_ALL
 		REG_S	sp,PT_OR2(sp)
 		CLI
-		/*
-		 * Asume we received an interrupt from the PCI ASIC.
-		 */
 		.set	at
-		lui	s0,%hi(SNI_PORT_BASE)
+
+		lb	t0,led_cache
+		addiu	t0,1
+		sb	t0,led_cache
+		sb	t0,PCIMT_CSLED
+		.data
+led_cache:	.byte	0
+		.text
+
+		mfc0	t0,CP0_STATUS
+		mfc0	t1,CP0_CAUSE
+		and	t0,t1
+
+		 andi	t1,t0,0x0800			# hardware interrupt 1
+		bnez	t1,hwint1
+		 andi	t1,t0,0x4000			# hardware interrupt 4
+		bnez	t1,eth_int
+
+		 andi	t1,t0,0x1000			# hardware interrupt 2
+		bnez	t1,hwint2
+		 andi	t1,t0,0x2000			# hardware interrupt 3
+		bnez	t1,hwint3
+		 andi	t1,t0,0x8000			# hardware interrupt 5
+		bnez	t1,hwint5
+		 andi	t1,t0,0x0400			# hardware interrupt 0
+		bnez	t1,hwint0
+		 nop
+
+		j	spurious_interrupt		# Nothing up ...
+		 nop
+
+ ##############################################################################
+
+swint0:		PANIC("swint0")
+swint1:		PANIC("swint1")
+
+ /* ------------------------------------------------------------------------ */
+
+hwint1:		lbu	t0,PCIMT_CSITPEND
+
+		 andi	t1,t0,0x20
+		bnez	t1,eisa_int
+
+#ifdef CONFIG_SCSI_NCR53C8XX
+		 andi	t1,t0,0x40
+		beqz	t1,scsi_int
+#endif
+		 nop
+
+		j	spurious_interrupt
+		 nop
+
+ /* ------------------------------------------------------------------------ */
+
+hwint0:		lbu	t0,PCIMT_CSITPEND
+
+		 andi	t1,t0,0x01
+		beqz	t1,int2
+
+go_spurious:	j	spurious_interrupt		# we got fooled
+		 nop
+
+eisa_int:	lui	s0,%hi(SNI_PORT_BASE)
 		li	a0,0x0f
 		sb	a0,%lo(SNI_PORT_BASE+0x20)(s0)	# poll command
 		lb	a0,%lo(SNI_PORT_BASE+0x20)(s0)	# read result
 		bgtz	a0,poll_second
-		andi	a0,7
+		 andi	a0,7
 		beq	a0,2,poll_second		# cascade?
-		li	s1,1				# delay slot
+		 li	s1,1
 		/*
 		 * Acknowledge first pic
 		 */
@@ -45,12 +106,8 @@
 		/*
 		 * Now call the real handler
 		 */
-		la	t3,IRQ_vectors
-		sll	t2,a0,PTRLOG
-		addu	t3,t2
-		LONG_L	t3,(t3)
-		jalr	t3
-		nop					# delay slot
+		jal	do_IRQ
+		 move	a1,sp
 		/*
 		 * Unblock first pic
 		 */
@@ -59,8 +116,8 @@
 		nor	s1,zero,s1
 		and	t1,s1
 		sb	t1,%lo(cache_21)(s4)
-		jr	v0
-		sb	t1,%lo(SNI_PORT_BASE+0x21)(s0)	# delay slot
+		j	ret_from_irq
+		 sb	t1,%lo(SNI_PORT_BASE+0x21)(s0)
 
 		/*
 		 * Cascade interrupt from second PIC
@@ -69,8 +126,8 @@
 poll_second:	li	a0,0x0f
 		sb	a0,%lo(SNI_PORT_BASE+0xa0)(s0)	# poll command
 		lb	a0,%lo(SNI_PORT_BASE+0xa0)(s0)	# read result
-		bgtz	a0,3f
-		andi	a0,7
+		bgtz	a0,go_spurious
+		 andi	a0,7
 		/*
 		 * Acknowledge second pic
 		 */
@@ -87,13 +144,9 @@
 		/*
 		 * Now call the real handler
 		 */
-		la	t3,IRQ_vectors
 		addiu	a0,8
-		sll	t2,a0,PTRLOG
-		addu	t3,t2
-		LONG_L	t3,(t3)
-		jalr	t3
-		nop					# delay slot
+		jal	do_IRQ
+		 move	a1,sp
 		/*
 		 * Unblock second pic
 		 */
@@ -103,72 +156,49 @@
 		nor	s1,zero,s1
 		and	t1,t1,s1
 		sb	t1,%lo(cache_A1)(s4)
-		jr	v0
-		sb	t1,%lo(SNI_PORT_BASE+0xa1)(s0)	# delay slot
-
-/*
- * FIXME:  This is definatly wrong but I'll have to do it this way
- *         'till I get more hardware info.
- * XXX: Apparently the Lance is attached to interrupt #5.
- */
-#ifdef CONFIG_PCNET32
-
-/*
- * FIXME: detect this address
- */
-#define LANCE_BASE 0xbb000100
-
-/* Offsets from base I/O address. */
-#define LANCE_DATA 0x10
-#define LANCE_ADDR 0x12
-#define LANCE_RESET 0x14
-#define LANCE_BUS_IF 0x16
-#define LANCE_TOTAL_SIZE 0x18
+		j	ret_from_irq
+		 sb	t1,%lo(SNI_PORT_BASE+0xa1)(s0)
 
 /*
  * ... check if we were interrupted by the Lance ...
  */
-3:		lh	s0,LANCE_BASE+LANCE_ADDR
-		sh	zero,LANCE_BASE+LANCE_ADDR
-		lh	t1,LANCE_BASE+LANCE_DATA
-		andi	t2,t1,0x80
-		beqz	t1,3f				# no Lance interrupt?
-		mfc0	t0,CP0_STATUS			# delay slot
-		ori	t0,0x041f
-		xori	t0,0x041e
+eth_int:	mfc0	s0,CP0_STATUS
+		ori	t0,s0,0x4000
+		xori	t0,0x4000
 		mtc0	t0,CP0_STATUS
+
 		li	a0,PCIMT_IRQ_ETHERNET
 		jal	do_IRQ
-		 move	a1,sp				# delay slot
-		sh	s0,LANCE_BASE+LANCE_ADDR
-		mfc0	t0,CP0_STATUS
-		ori	t0,0x0401
-		xori	t0,0x0001
-		mtc0	t0,CP0_STATUS
-		j	ret_from_sys_call
-		nop					# delay slot
+		 move	a1,sp
+
+		mtc0	s0,CP0_STATUS
 
-#endif /* CONFIG_PCNET32 */
+		j	ret_from_irq
+		 nop
 
 #ifdef CONFIG_SCSI_NCR53C8XX
 
 /*
  * ... check if we were interrupted by the NCR ...
  */
-3:		lb	t0,PCIMT_CSITPEND
-		andi	t0,0x40
-		bnez	t0,3f				# bit 6 == 0 -> SCSI IRQ
-		nop					# delay slot
-		jal	do_fast_IRQ
-		li	a0,PCIMT_IRQ_SCSI		# delay slot
-		j	return
-		nop					# delay slot
+scsi_int:	li	a0,PCIMT_IRQ_SCSI
+		jal	do_IRQ
+		 move	a1,sp
+		j	ret_from_irq
+		 nop
 
 #endif /* CONFIG_SCSI_NCR53C8XX */
 
-/*
- * "Jump extender" to reach spurious_interrupt
- */
-3:		j	spurious_interrupt
-		nop					# delay slot
+pci_int:	PANIC("Received PCI interrupt but no handler yet ...\n")
+1:		j	1b
+		 nop
+
+int2:		PANIC("Received int2 but no handler yet ...\n")
+1:		j	1b
+		 nop
+
+hwint2:		PANIC("hwint2 and no handler yet")
+hwint3:		PANIC("hwint3 and no handler yet")
+hwint5:		PANIC("hwint5 and no handler yet")
+
 		END(sni_rm200_pci_handle_int)
diff -u --recursive --new-file v2.1.72/linux/arch/mips/sni/pci.c linux/arch/mips/sni/pci.c
--- v2.1.72/linux/arch/mips/sni/pci.c	Thu Jun 26 12:33:38 1997
+++ linux/arch/mips/sni/pci.c	Wed Dec 10 10:31:10 1997
@@ -119,17 +119,14 @@
 	return PCIBIOS_SUCCESSFUL;
 }
 
-__initfunc(unsigned long sni_rm200_pcibios_init(unsigned long memory_start, unsigned long memory_end))
-{
-	_pcibios_fixup = sni_rm200_pcibios_fixup;
-	_pcibios_read_config_byte = sni_rm200_pcibios_read_config_byte;
-	_pcibios_read_config_word = sni_rm200_pcibios_read_config_word;
-	_pcibios_read_config_dword = sni_rm200_pcibios_read_config_dword;
-	_pcibios_write_config_byte = sni_rm200_pcibios_write_config_byte;
-	_pcibios_write_config_word = sni_rm200_pcibios_write_config_word;
-	_pcibios_write_config_dword = sni_rm200_pcibios_write_config_dword;
-
-	return memory_start;
-}
+struct pci_ops sni_pci_ops = {
+	sni_rm200_pcibios_fixup,
+	sni_rm200_pcibios_read_config_byte,
+	sni_rm200_pcibios_read_config_word,
+	sni_rm200_pcibios_read_config_dword,
+	sni_rm200_pcibios_write_config_byte,
+	sni_rm200_pcibios_write_config_word,
+	sni_rm200_pcibios_write_config_dword
+};
 
 #endif /* CONFIG_PCI */
diff -u --recursive --new-file v2.1.72/linux/arch/mips/sni/setup.c linux/arch/mips/sni/setup.c
--- v2.1.72/linux/arch/mips/sni/setup.c	Mon Aug 18 18:19:43 1997
+++ linux/arch/mips/sni/setup.c	Wed Dec 10 10:31:10 1997
@@ -6,6 +6,8 @@
  * for more details.
  *
  * Copyright (C) 1996, 1997 by Ralf Baechle
+ *
+ * $Id: setup.c,v 1.5 1997/12/01 16:19:12 ralf Exp $
  */
 #include <asm/ptrace.h>
 #include <linux/ioport.h>
@@ -54,7 +56,7 @@
 	 * I don't know how to handle the debug button interrupt, so
 	 * don't use this button yet or bad things happen ...
 	 */
-	set_cp0_status(ST0_IM, IE_IRQ0);
+	set_cp0_status(ST0_IM, IE_IRQ1 | IE_IRQ4);
 }
 
 void (*board_time_init)(struct irqaction *irq);
@@ -69,8 +71,7 @@
 }
 
 unsigned char aux_device_present;
-extern unsigned long sni_rm200_pcibios_init (unsigned long memory_start,
-                                             unsigned long memory_end);
+extern struct pci_ops sni_pci_ops;
 extern unsigned char sni_map_isa_cache;
 
 /*
@@ -81,7 +82,7 @@
 	char boardtype[80];
 	unsigned char csmsr;
 	char *p = boardtype;
-	int asic;
+	unsigned int asic, cacheconf;
 
 	csmsr = *(volatile unsigned char *)PCIMT_CSMSR;
 
@@ -93,6 +94,30 @@
 	asic = (csmsr & 0x08) ? asic : !asic;
 	p += sprintf(p, ", ASIC PCI Rev %s", asic ? "1.0" : "1.1");
 	printk("%s.\n", boardtype);
+
+	cacheconf = *(volatile unsigned int *)PCIMT_CACHECONF;
+	switch(cacheconf & 7) {
+	case 0:
+		printk("Secondary cache disabled\n");
+		break;
+	case 1:
+		printk("256kb secondary cache\n");
+		break;
+	case 2:
+		printk("512kb secondary cache\n");
+		break;
+	case 3:
+		printk("1mb secondary cache\n");
+		break;
+	case 4:
+		printk("2mb secondary cache\n");
+		break;
+	case 5:
+		printk("4mb secondary cache\n");
+		break;
+	default:
+		panic("invalid secondary cache size\n");
+	}
 }
 	
 __initfunc(void sni_rm200_pci_setup(void))
@@ -128,7 +153,7 @@
 	irq_setup = sni_irq_setup;
 	fd_cacheflush = sni_fd_cacheflush;	// Will go away
 	feature = &sni_rm200_pci_feature;
-	port_base = SNI_PORT_BASE;
+	mips_io_port_base = SNI_PORT_BASE;
 	keyboard_setup = sni_rm200_keyboard_setup;
 
 	/*
@@ -157,5 +182,5 @@
 	 * the I/O port space ...
 	 */
 	request_region(0xcfc,0x04,"PCI config data");
-	_pcibios_init = sni_rm200_pcibios_init;
+	pci_ops = &sni_pci_ops;
 }
diff -u --recursive --new-file v2.1.72/linux/arch/mips/tools/Makefile linux/arch/mips/tools/Makefile
--- v2.1.72/linux/arch/mips/tools/Makefile	Thu Jun 26 12:33:38 1997
+++ linux/arch/mips/tools/Makefile	Wed Dec 10 10:31:10 1997
@@ -3,6 +3,8 @@
 # Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
 # Copyright (C) 1997 Ralf Baechle (ralf@gnu.ai.mit.edu)
 #
+# $Id: Makefile,v 1.2 1997/09/23 06:23:49 ralf Exp $
+#
 TARGET	:= $(TOPDIR)/include/asm-$(ARCH)/offset.h
 
 .S.s:
@@ -21,6 +23,6 @@
 offset.s: offset.c
 
 clean:
-	rm -f offset.s $(TARGET).new
+	rm -f offset.[hs] $(TARGET).new
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.1.72/linux/arch/mips/tools/offset.c linux/arch/mips/tools/offset.c
--- v2.1.72/linux/arch/mips/tools/offset.c	Mon Jul  7 08:18:54 1997
+++ linux/arch/mips/tools/offset.c	Wed Dec 10 10:31:10 1997
@@ -3,6 +3,8 @@
  *
  * Copyright (C) 1996 David S. Miller
  * Made portable by Ralf Baechle
+ *
+ * $Id: offset.c,v 1.3 1997/07/29 18:57:11 ralf Exp $
  */
 
 #include <linux/types.h>
@@ -21,10 +23,10 @@
 #define linefeed text("")
 
 text("/* DO NOT TOUCH, AUTOGENERATED BY OFFSET.C */");
-text("");
+linefeed;
 text("#ifndef _MIPS_OFFSET_H");
 text("#define _MIPS_OFFSET_H");
-text("");
+linefeed;
 
 void output_ptreg_defines(void)
 {
diff -u --recursive --new-file v2.1.72/linux/drivers/block/Config.in linux/drivers/block/Config.in
--- v2.1.72/linux/drivers/block/Config.in	Thu Dec  4 14:53:54 1997
+++ linux/drivers/block/Config.in	Wed Dec 17 11:11:16 1997
@@ -23,26 +23,28 @@
     fi
     if [ "$CONFIG_PCI" = "y" ]; then
       bool '   RZ1000 chipset bugfix/support' CONFIG_BLK_DEV_RZ1000
-      bool '   PCI bus-master DMA support' CONFIG_BLK_DEV_IDEDMA
-      if [ "$CONFIG_BLK_DEV_IDEDMA" = "y" ]; then
+      bool '   Generic PCI IDE chipset support' CONFIG_BLK_DEV_IDEPCI
+      if [ "$CONFIG_BLK_DEV_IDEPCI" = "y" ]; then
+        bool '     Generic PCI bus-master DMA support' CONFIG_BLK_DEV_IDEDMA
         if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-          bool '      Tekram TRM290 DMA support (EXPERIMENTAL)' CONFIG_BLK_DEV_TRM290
-          bool '      OPTi 82C621 enhanced support (EXPERIMENTAL)' CONFIG_BLK_DEV_OPTI621
+          bool '     Tekram TRM290 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_TRM290
+          bool '     OPTi 82C621 chipset enhanced support (EXPERIMENTAL)' CONFIG_BLK_DEV_OPTI621
+          bool '     NS87415 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_NS87415
         fi
       fi
     fi
     bool '   Other IDE chipset support' CONFIG_IDE_CHIPSETS
     if [ "$CONFIG_IDE_CHIPSETS" = "y" ]; then
       comment 'Note: most of these also require special kernel boot parameters'
-      bool '      Generic 4 drives/port support' CONFIG_BLK_DEV_4DRIVES
-      bool '      ALI M14xx support' CONFIG_BLK_DEV_ALI14XX
-      bool '      DTC-2278 support' CONFIG_BLK_DEV_DTC2278
-      bool '      Holtek HT6560B support' CONFIG_BLK_DEV_HT6560B
+      bool '     Generic 4 drives/port support' CONFIG_BLK_DEV_4DRIVES
+      bool '     ALI M14xx support' CONFIG_BLK_DEV_ALI14XX
+      bool '     DTC-2278 support' CONFIG_BLK_DEV_DTC2278
+      bool '     Holtek HT6560B support' CONFIG_BLK_DEV_HT6560B
+      bool '     QDI QD6580 support' CONFIG_BLK_DEV_QD6580
+      bool '     UMC-8672 support' CONFIG_BLK_DEV_UMC8672
       if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-        bool '      PROMISE DC4030 support (EXPERIMENTAL)' CONFIG_BLK_DEV_PDC4030
+        bool '     PROMISE DC4030 support (EXPERIMENTAL)' CONFIG_BLK_DEV_PDC4030
       fi
-      bool '      QDI QD6580 support' CONFIG_BLK_DEV_QD6580
-      bool '      UMC-8672 support' CONFIG_BLK_DEV_UMC8672
     fi
   fi
 fi
diff -u --recursive --new-file v2.1.72/linux/drivers/block/Makefile linux/drivers/block/Makefile
--- v2.1.72/linux/drivers/block/Makefile	Thu Dec  4 14:53:54 1997
+++ linux/drivers/block/Makefile	Wed Dec 17 11:11:16 1997
@@ -79,11 +79,17 @@
 endif
 
 ifeq ($(CONFIG_BLK_DEV_IDE),y)
-LX_OBJS += ide.o
-L_OBJS += ide-probe.o
+  LX_OBJS += ide.o
+  ifeq ($(CONFIG_PROC_FS),y)
+    L_OBJS += ide-proc.o
+  endif
+  L_OBJS += ide-probe.o
 else
   ifeq ($(CONFIG_BLK_DEV_IDE),m)
   MX_OBJS += ide.o
+  ifeq ($(CONFIG_PROC_FS),y)
+    M_OBJS += ide-proc.o
+  endif
   M_OBJS += ide-probe.o
   endif
 endif
@@ -96,6 +102,10 @@
 L_OBJS += cmd640.o
 endif
 
+ifeq ($(CONFIG_BLK_DEV_IDEPCI),y)
+L_OBJS += ide-pci.o
+endif
+
 ifeq ($(CONFIG_BLK_DEV_IDEDMA),y)
 L_OBJS += ide-dma.o
 endif
@@ -135,6 +145,10 @@
 
 ifeq ($(CONFIG_BLK_DEV_OPTI621),y)
 L_OBJS += opti621.o
+endif
+
+ifeq ($(CONFIG_BLK_DEV_NS87415),y)
+L_OBJS += ns87415.o
 endif
 
 ifeq ($(CONFIG_BLK_DEV_IDEDISK),y)
diff -u --recursive --new-file v2.1.72/linux/drivers/block/ali14xx.c linux/drivers/block/ali14xx.c
--- v2.1.72/linux/drivers/block/ali14xx.c	Thu Dec  4 14:53:54 1997
+++ linux/drivers/block/ali14xx.c	Wed Dec 17 11:11:16 1997
@@ -213,6 +213,7 @@
 	ide_hwifs[1].tuneproc = &ali14xx_tune_drive;
 	ide_hwifs[0].mate = &ide_hwifs[1];
 	ide_hwifs[1].mate = &ide_hwifs[0];
+	ide_hwifs[1].channel = 1;
 
 	/* initialize controller registers */
 	if (!initRegisters()) {
diff -u --recursive --new-file v2.1.72/linux/drivers/block/cmd640.c linux/drivers/block/cmd640.c
--- v2.1.72/linux/drivers/block/cmd640.c	Thu Dec  4 14:53:54 1997
+++ linux/drivers/block/cmd640.c	Wed Dec 17 11:11:16 1997
@@ -797,6 +797,7 @@
 		cmd_hwif1->chipset = ide_cmd640;
 		cmd_hwif0->mate = cmd_hwif1;
 		cmd_hwif1->mate = cmd_hwif0;
+		cmd_hwif1->channel = 1;
 #ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
 		cmd_hwif1->tuneproc = &cmd640_tune_drive;
 #endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
diff -u --recursive --new-file v2.1.72/linux/drivers/block/dtc2278.c linux/drivers/block/dtc2278.c
--- v2.1.72/linux/drivers/block/dtc2278.c	Thu Dec  4 14:53:54 1997
+++ linux/drivers/block/dtc2278.c	Wed Dec 17 11:11:16 1997
@@ -127,4 +127,5 @@
 	ide_hwifs[1].drives[1].no_unmask = 1;
 	ide_hwifs[0].mate = &ide_hwifs[1];
 	ide_hwifs[1].mate = &ide_hwifs[0];
+	ide_hwifs[1].channel = 1;
 }
diff -u --recursive --new-file v2.1.72/linux/drivers/block/ht6560b.c linux/drivers/block/ht6560b.c
--- v2.1.72/linux/drivers/block/ht6560b.c	Thu Dec  4 14:53:54 1997
+++ linux/drivers/block/ht6560b.c	Wed Dec 17 11:11:16 1997
@@ -155,7 +155,6 @@
 		printk("ht6560b: %s: select=%#x timing=%#x\n", drive->name, t, timing);
 #endif
 	}
-	OUT_BYTE(drive->select.all,IDE_SELECT_REG);
 }
 
 /*
@@ -229,6 +228,7 @@
 			ide_hwifs[1].serialized = 1;
 			ide_hwifs[0].mate = &ide_hwifs[1];
 			ide_hwifs[1].mate = &ide_hwifs[0];
+			ide_hwifs[1].channel = 1;
 		} else
 			printk("\nht6560b: not found\n");
 	}
diff -u --recursive --new-file v2.1.72/linux/drivers/block/ide-cd.c linux/drivers/block/ide-cd.c
--- v2.1.72/linux/drivers/block/ide-cd.c	Tue Dec  2 16:45:18 1997
+++ linux/drivers/block/ide-cd.c	Thu Dec 18 11:31:30 1997
@@ -2,7 +2,7 @@
 /*
  * linux/drivers/block/ide-cd.c
  * Copyright (C) 1994, 1995, 1996  scott snyder  <snyder@fnald0.fnal.gov>
- * Copyright (C) 1996, 1997  Erik Andersen <andersee@debian.org>
+ * Copyright (C) 1996-1998  Erik Andersen <andersee@debian.org>
  * May be copied or modified under the terms of the GNU General Public
  * License.  See linux/COPYING for more information.
  *
@@ -27,13 +27,6 @@
  *     unless you have a patch to fix it.  I am working on it...)
  * -Implement ide_cdrom_select_speed using the generic cdrom interface
  * -Fix ide_cdrom_reset so that it works (it does nothing right now)
- * -When trying to mount a cdrom with the tray open, you get an billion
- *     "tray open or drive not ready" messages until the tray gets closed.
- *     This is because ide-cd does not properly return drive_status immediatly,
- *     but instead waits for the drive to close first (bad, bad, bad)
- *     and keeps on trying, and failing...  This bug was revealed by the 
- *     recent changes to the Uniform CD-ROm driver, and I havn't had a 
- *     chance to fix it yet.
  *
  * MOSTLY DONE LIST:
  *  Query the drive to find what features are available
@@ -185,8 +178,13 @@
  *                        Added identifier so new Sanyo CD-changer works
  *                        Better detection if door locking isn't supported
  *
+ * 4.06  Dec 17, 1997  -- fixed endless "tray open" messages  -ml
+ * 4.07  Dec 17, 1997  -- fallback to set pc->stat on "tray open"
+ *
  *************************************************************************/
 
+#define IDECD_VERSION "4.07"
+
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/types.h>
@@ -194,11 +192,8 @@
 #include <linux/delay.h>
 #include <linux/timer.h>
 #include <linux/malloc.h>
-#include <linux/ioport.h>
 #include <linux/interrupt.h>
-#include <linux/blkdev.h>
 #include <linux/errno.h>
-#include <linux/hdreg.h>
 #include <linux/cdrom.h>
 #include <asm/irq.h>
 #include <asm/io.h>
@@ -418,7 +413,8 @@
 					  (struct packet_command *)
 					  	pc->sense_data);
 	}
-
+	if (rq->cmd == READ && !rq->current_nr_sectors)
+		uptodate = 1;
 	ide_end_request (uptodate, HWGROUP(drive));
 }
 
@@ -443,7 +439,7 @@
 	sense_key = err >> 4;
 
 	if (rq == NULL)
-		printk ("%s : missing request in cdrom_decode_status\n",
+		printk ("%s: missing request in cdrom_decode_status\n",
 			drive->name);
 	else {
 		cmd = rq->cmd;
@@ -477,16 +473,13 @@
 				   because workman constantly polls the drive
 				   with this command, and we don't want
 				   to uselessly fill up the syslog. */
-				if (pc->c[0] != SCMD_READ_SUBCHANNEL) {
+				if (pc->c[0] != SCMD_READ_SUBCHANNEL)
 					printk ("%s: tray open or drive not ready\n",
 						drive->name);
-					return 1;
-				}
 			} else if (sense_key == UNIT_ATTENTION) {
 				/* Check for media change. */
 				cdrom_saw_media_change (drive);
-				printk (" %s: media changed\n", drive->name);
-				return 0;
+				printk ("%s: media changed\n", drive->name);
 			} else {
 				/* Otherwise, print an error. */
 				ide_dump_status (drive, "packet command error",
@@ -521,7 +514,7 @@
 				cdrom_saw_media_change (drive);
 
 				/* Fail the request. */
-				printk ("%s : tray open\n", drive->name);
+				printk ("%s: tray open\n", drive->name);
 				cdrom_end_request (0, drive);
 			} else if (sense_key == UNIT_ATTENTION) {
 				/* Media change. */
@@ -591,7 +584,6 @@
 	if (info->dma)
 		(void) (HWIF(drive)->dmaproc(ide_dma_begin, drive));
 
-
 	if (CDROM_CONFIG_FLAGS (drive)->drq_interrupt) {
 		ide_set_handler (drive, handler, WAIT_CMD);
 		OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* packet command */
@@ -619,7 +611,8 @@
 		int stat_dum;
 
 		/* Check for errors. */
-		if (cdrom_decode_status (drive, DRQ_STAT, &stat_dum)) return 1;
+		if (cdrom_decode_status (drive, DRQ_STAT, &stat_dum))
+			return 1;
 	} else {
 		/* Otherwise, we must wait for DRQ to get set. */
 		if (ide_wait_stat (drive, DRQ_STAT, BUSY_STAT, WAIT_READY))
@@ -746,12 +739,12 @@
 	/* Check for errors. */
 	if (dma) {
 		info->dma = 0;
-		if ((dma_error = HWIF(drive)->dmaproc(ide_dma_status_bad, drive)))
+		if ((dma_error = HWIF(drive)->dmaproc(ide_dma_end, drive)))
 			HWIF(drive)->dmaproc(ide_dma_off, drive);
-		(void) (HWIF(drive)->dmaproc(ide_dma_abort, drive));
 	}
 
-	if (cdrom_decode_status (drive, 0, &stat)) return;
+	if (cdrom_decode_status (drive, 0, &stat))
+		return;
  
 	if (dma) {
 		if (!dma_error) {
@@ -764,7 +757,6 @@
 		return;
 	}
 
-
 	/* Read the interrupt reason and the transfer length. */
 	ireason = IN_BYTE (IDE_NSECTOR_REG);
 	len = IN_BYTE (IDE_LCYL_REG) + 256 * IN_BYTE (IDE_HCYL_REG);
@@ -779,7 +771,6 @@
 			cdrom_end_request (0, drive);
 		} else
 			cdrom_end_request (1, drive);
-
 		return;
 	}
 
@@ -990,7 +981,8 @@
 	int stat;
 	static int retry = 10;
 
-	if (cdrom_decode_status (drive, 0, &stat)) return;
+	if (cdrom_decode_status (drive, 0, &stat))
+		return;
 	CDROM_CONFIG_FLAGS(drive)->seeking = 1;
 
 	if (retry && jiffies - info->start_seek > IDECD_SEEK_TIMER) {
@@ -1088,7 +1080,8 @@
 	struct packet_command *pc = (struct packet_command *)rq->buffer;
 
 	/* Check for errors. */
-	if (cdrom_decode_status (drive, 0, &stat)) return;
+	if (cdrom_decode_status (drive, 0, &stat))
+		return;
 
 	/* Read the interrupt reason and the transfer length. */
 	ireason = IN_BYTE (IDE_NSECTOR_REG);
@@ -1251,8 +1244,11 @@
 		ide_init_drive_cmd (&req);
 		req.cmd = PACKET_COMMAND;
 		req.buffer = (char *)pc;
-		(void) ide_do_drive_cmd (drive, &req, ide_wait);
-
+		if (ide_do_drive_cmd (drive, &req, ide_wait)) {
+			printk("%s: do_drive_cmd returned stat=%02x,err=%02x\n",
+				drive->name, req.buffer[0], req.buffer[1]);
+			/* FIXME: we should probably abort/retry or something */
+		}
 		if (pc->stat != 0) {
 			/* The request failed.  Retry if it was due to a unit
 			   attention status
@@ -2692,7 +2688,7 @@
 static
 int ide_cdrom_probe_capabilities (ide_drive_t *drive)
 {
-	int stat, nslots;
+	int stat, nslots, attempts = 3;
  	struct {
 		char pad[8];
 		struct atapi_capabilities_page cap;
@@ -2703,14 +2699,15 @@
 	if (CDROM_CONFIG_FLAGS (drive)->nec260)
 		return nslots;
 
-	stat = cdrom_mode_sense (drive, PAGE_CAPABILITIES, 0,
-				 (char *)&buf, sizeof (buf), NULL);
-	if (stat)
-		return nslots;
+	do {	/* we seem to get stat=0x01,err=0x00 the first time (??) */
+		if (attempts-- <= 0)
+			return 0;
+		stat = cdrom_mode_sense (drive, PAGE_CAPABILITIES, 0,
+				 	(char *)&buf, sizeof (buf), NULL);
+	} while (stat);
 
 	if (buf.cap.lock == 0)
 		CDROM_CONFIG_FLAGS (drive)->no_doorlock = 1;
-
 	if (buf.cap.cd_r_write)
 		CDROM_CONFIG_FLAGS (drive)->cd_r = 1;
 	if (buf.cap.cd_rw_write)
@@ -2737,11 +2734,15 @@
 		}
 	}
 
-	CDROM_STATE_FLAGS (drive)->curent_speed  = ntohs(buf.cap.curspeed)/176;
-	CDROM_CONFIG_FLAGS (drive)->max_speed = ntohs(buf.cap.maxspeed)/176;
+	if (drive->id && drive->id->model[0]) {
+		CDROM_STATE_FLAGS (drive)->current_speed  = (ntohs(buf.cap.curspeed) + (176/2)) / 176;
+		CDROM_CONFIG_FLAGS (drive)->max_speed = (ntohs(buf.cap.maxspeed) + (176/2)) / 176;
+	} else {  /* no-name ACERs (AOpen) have it backwards */
+		CDROM_STATE_FLAGS (drive)->current_speed  = (((unsigned int)buf.cap.curspeed) + (176/2)) / 176;
+		CDROM_CONFIG_FLAGS (drive)->max_speed = (((unsigned int)buf.cap.maxspeed) + (176/2)) / 176;
+	}
 
-        stat=0;
-        printk ("%s: ATAPI %dx CDROM", 
+        printk ("%s: ATAPI %dX CDROM", 
         	drive->name, CDROM_CONFIG_FLAGS (drive)->max_speed);
         if (CDROM_CONFIG_FLAGS (drive)->cd_r|CDROM_CONFIG_FLAGS (drive)->cd_rw) 
         	printk (" CD%s%s", 
@@ -2827,7 +2828,7 @@
 
 		else if (strcmp (drive->id->model,
 				 "NEC CD-ROM DRIVE:260") == 0 &&
-			 strcmp (drive->id->fw_rev, "1.01") == 0) {
+			 strncmp (drive->id->fw_rev, "1.01", 4) == 0) { /* FIXME */
 			/* Old NEC260 (not R).
 			   This drive was released before the 1.2 version
 			   of the spec. */
@@ -2838,7 +2839,7 @@
 		}
 
 		else if (strcmp (drive->id->model, "WEARNES CDD-120") == 0 &&
-			 strcmp (drive->id->fw_rev, "A1.1") == 0) {
+			 strncmp (drive->id->fw_rev, "A1.1", 4) == 0) { /* FIXME */
 			/* Wearnes */
 			CDROM_CONFIG_FLAGS (drive)->playmsf_as_bcd = 1;
 			CDROM_CONFIG_FLAGS (drive)->subchan_as_bcd = 1;
@@ -2936,21 +2937,23 @@
 };
 
 static ide_driver_t ide_cdrom_driver = {
+	"ide-cdrom",			/* name */
+	IDECD_VERSION,			/* version */
 	ide_cdrom,			/* media */
 	0,				/* busy */
 	1,				/* supports_dma */
 	1,				/* supports_dsc_overlap */
 	ide_cdrom_cleanup,		/* cleanup */
 	ide_do_rw_cdrom,		/* do_request */
-	NULL,				/* ??? or perhaps
-	cdrom_end_request? */
+	NULL,				/* ??? or perhaps cdrom_end_request? */
 	ide_cdrom_ioctl,		/* ioctl */
 	ide_cdrom_open,			/* open */
 	ide_cdrom_release,		/* release */
 	ide_cdrom_check_media_change,	/* media_change */
 	NULL,				/* pre_reset */
 	NULL,				/* capacity */
-	NULL				/* special */
+	NULL,				/* special */
+	NULL				/* proc */
 };
 
 
diff -u --recursive --new-file v2.1.72/linux/drivers/block/ide-cd.h linux/drivers/block/ide-cd.h
--- v2.1.72/linux/drivers/block/ide-cd.h	Tue Dec  2 16:45:18 1997
+++ linux/drivers/block/ide-cd.h	Wed Dec 17 11:11:51 1997
@@ -119,11 +119,11 @@
 	__u8 cd_rw            : 1; /* Drive can write to CD-R/W media . */
 	__u8 supp_disc_present: 1; /* Changer can report exact contents
 				      of slots. */
-	__u8 max_speed        : 4; /* Max speed of the drive */
 	__u8 seeking          : 1; /* Seeking in progress */
 	__u8 reserved         : 6;
+	byte max_speed; 	   /* Max speed of the drive */
 };
-#define CDROM_CONFIG_FLAGS(drive) ((struct ide_cd_config_flags *)&((drive)->bios_cyl))
+#define CDROM_CONFIG_FLAGS(drive) (&(((struct cdrom_info *)(drive->driver_data))->config_flags))
 
  
 /* State flags.  These give information about the current state of the
@@ -133,10 +133,10 @@
 	__u8 toc_valid     : 1; /* Saved TOC information is current. */
 	__u8 door_locked   : 1; /* We think that the drive door is locked. */
 	__u8 sanyo_slot    : 2; /* Sanyo 3 CD changer support */
-	__u8 curent_speed  : 4; /* Current speed of the drive */
 	__u8 reserved      : 3;
+	byte current_speed;	/* Current speed of the drive */
 };
-#define CDROM_STATE_FLAGS(drive)  ((struct ide_cd_state_flags *)&((drive)->bios_head))
+#define CDROM_STATE_FLAGS(drive) (&(((struct cdrom_info *)(drive->driver_data))->state_flags))
 
 
 struct atapi_request_sense {
@@ -385,6 +385,8 @@
 	/* Buffer to hold mechanism status and changer slot table. */
 	struct atapi_changer_info *changer_info;
 
+	struct ide_cd_config_flags	config_flags;
+	struct ide_cd_state_flags	state_flags;
 
         /* Per-device info needed by cdrom.c generic driver. */
         struct cdrom_device_info devinfo;
diff -u --recursive --new-file v2.1.72/linux/drivers/block/ide-disk.c linux/drivers/block/ide-disk.c
--- v2.1.72/linux/drivers/block/ide-disk.c	Thu Dec  4 14:53:54 1997
+++ linux/drivers/block/ide-disk.c	Wed Dec 17 11:11:16 1997
@@ -10,32 +10,6 @@
  *
  * This is the IDE/ATA disk driver, as evolved from hd.c and ide.c.
  *
- *  From hd.c:
- *  |
- *  | It traverses the request-list, using interrupts to jump between functions.
- *  | As nearly all functions can be called within interrupts, we may not sleep.
- *  | Special care is recommended.  Have Fun!
- *  |
- *  | modified by Drew Eckhardt to check nr of hd's from the CMOS.
- *  |
- *  | Thanks to Branko Lankester, lankeste@fwi.uva.nl, who found a bug
- *  | in the early extended-partition checks and added DM partitions.
- *  |
- *  | Early work on error handling by Mika Liljeberg (liljeber@cs.Helsinki.FI).
- *  |
- *  | IRQ-unmask, drive-id, multiple-mode, support for ">16 heads",
- *  | and general streamlining by Mark Lord (mlord@pobox.com).
- *
- *  October, 1994 -- Complete line-by-line overhaul for linux 1.1.x, by:
- *
- *	Mark Lord	(mlord@pobox.com)		(IDE Perf.Pkg)
- *	Delman Lee	(delman@mipg.upenn.edu)		("Mr. atdisk2")
- *	Scott Snyder	(snyder@fnald0.fnal.gov)	(ATAPI IDE cd-rom)
- *
- *  This was a rewrite of just about everything from hd.c, though some original
- *  code is still sprinkled about.  Think of it as a major evolution, with
- *  inspiration from lots of linux users, esp.  hamish@zot.apana.org.au
- *
  * Version 1.00		move disk only code from ide.c to ide-disk.c
  *			support optional byte-swapping of all data
  * Version 1.01		fix previous byte-swapping code
@@ -43,6 +17,8 @@
  * Verions 1.03		fix display of id->buf_size for big-endian
  */
 
+#define IDEDISK_VERSION	"1.03"
+
 #undef REALLY_SLOW_IO		/* most systems can safely undef this */
 
 #include <linux/config.h>
@@ -52,12 +28,9 @@
 #include <linux/kernel.h>
 #include <linux/timer.h>
 #include <linux/mm.h>
-#include <linux/ioport.h>
 #include <linux/interrupt.h>
 #include <linux/major.h>
-#include <linux/blkdev.h>
 #include <linux/errno.h>
-#include <linux/hdreg.h>
 #include <linux/genhd.h>
 #include <linux/malloc.h>
 #include <linux/delay.h>
@@ -319,7 +292,7 @@
 	OUT_BYTE(rq->nr_sectors,IDE_NSECTOR_REG);
 #ifdef CONFIG_BLK_DEV_PDC4030
 	if (IS_PDC4030_DRIVE) {
-		if (hwif->is_pdc4030_2 || rq->cmd == READ) {
+		if (hwif->channel != 0 || rq->cmd == READ) {
 			use_pdc4030_io = 1;
 		}
 	}
@@ -494,6 +467,11 @@
 		drive->special.b.set_multmode = 1;
 }
 
+static ide_proc_entry_t idedisk_proc[] = {
+	{ "geometry", proc_ide_read_geometry, NULL },
+	{ NULL, NULL, NULL }
+};
+
 int idedisk_init (void);
 static ide_module_t idedisk_module = {
 	IDE_DRIVER_MODULE,
@@ -505,6 +483,8 @@
  *	IDE subdriver functions, registered with ide.c
  */
 static ide_driver_t idedisk_driver = {
+	"ide-disk",		/* name */
+	IDEDISK_VERSION,	/* version */
 	ide_disk,		/* media */
 	0,			/* busy */
 	1,			/* supports_dma */
@@ -518,7 +498,8 @@
 	idedisk_media_change,	/* media_change */
 	idedisk_pre_reset,	/* pre_reset */
 	idedisk_capacity,	/* capacity */
-	idedisk_special		/* special */
+	idedisk_special,	/* special */
+	idedisk_proc		/* proc */
 };
 
 static int idedisk_cleanup (ide_drive_t *drive)
@@ -526,20 +507,6 @@
 	return ide_unregister_subdriver(drive);
 }
 
-static int idedisk_identify_device (ide_drive_t *drive)
-{
-	struct hd_driveid *id = drive->id;
-	
-	if (id == NULL)
-		return 0;
-
-	/* SunDisk drives: force one unit */
-	if (id->model[0] == 'S' && id->model[1] == 'u' && (drive->select.all & (1<<4)))
-		return 1;
-
-	return 0;
-}
-
 static void idedisk_setup (ide_drive_t *drive)
 {
 	struct hd_driveid *id = drive->id;
@@ -554,7 +521,7 @@
 			drive->removable = 1;
 	}
 
-	/* SunDisk drives: treat as non-removable */
+	/* SunDisk drives: treat as non-removable;   can mess up non-Sun systems!  FIXME */
 	if (id->model[0] == 'S' && id->model[1] == 'u')
 		drive->removable = 0;
 
@@ -634,8 +601,12 @@
 	
 	MOD_INC_USE_COUNT;
 	while ((drive = ide_scan_devices (ide_disk, NULL, failed++)) != NULL) {
-		if (idedisk_identify_device (drive))
+
+		/* SunDisk drives: ignore "second" drive;   can mess up non-Sun systems!  FIXME */
+		struct hd_driveid *id = drive->id;
+		if (id && id->model[0] == 'S' && id->model[1] == 'u' && drive->select.b.unit)
 			continue;
+
 		if (ide_register_subdriver (drive, &idedisk_driver, IDE_SUBDRIVER_VERSION)) {
 			printk (KERN_ERR "ide-disk: %s: Failed to register the driver with ide.c\n", drive->name);
 			continue;
diff -u --recursive --new-file v2.1.72/linux/drivers/block/ide-dma.c linux/drivers/block/ide-dma.c
--- v2.1.72/linux/drivers/block/ide-dma.c	Thu Dec  4 14:53:54 1997
+++ linux/drivers/block/ide-dma.c	Wed Dec 17 11:11:51 1997
@@ -1,5 +1,5 @@
 /*
- *  linux/drivers/block/ide-dma.c	Version 4.06  December 3, 1997
+ *  linux/drivers/block/ide-dma.c	Version 4.07  December 5, 1997
  *
  *  Copyright (c) 1995-1998  Mark Lord
  *  May be copied or modified under the terms of the GNU General Public License
@@ -49,9 +49,8 @@
  * available from ftp://ftp.intel.com/pub/bios/10004bs0.exe
  * (thanks to Glen Morrell <glen@spin.Stanford.edu> for researching this).
  *
- * Thanks to "Christopher J. Reimer" <reimer@doe.carleton.ca> for fixing the
- * problem with some (all?) ACER motherboards/BIOSs.  Hopefully the fix
- * still works here (?).
+ * Thanks to "Christopher J. Reimer" <reimer@doe.carleton.ca> for
+ * fixing the problem with the BIOS on some Acer motherboards.
  *
  * Thanks to "Benoit Poulot-Cazajous" <poulot@chorus.fr> for testing
  * "TX" chipset compatibility and for providing patches for the "TX" chipset.
@@ -69,16 +68,12 @@
 #include <linux/kernel.h>
 #include <linux/timer.h>
 #include <linux/mm.h>
-#include <linux/ioport.h>
 #include <linux/interrupt.h>
-#include <linux/blkdev.h>
-#include <linux/hdreg.h>
 #include <linux/pci.h>
 #include <linux/bios32.h>
-#include <linux/init.h>
 
 #include <asm/io.h>
-#include <asm/dma.h>
+#include <asm/irq.h>
 
 #include "ide.h"
 
@@ -110,23 +105,19 @@
 #define PRD_BYTES	8
 #define PRD_ENTRIES	(PAGE_SIZE / (2 * PRD_BYTES))
 
-static int config_drive_for_dma (ide_drive_t *);
-
 /*
  * dma_intr() is the handler for disk read/write DMA interrupts
  */
-static void dma_intr (ide_drive_t *drive)
+void ide_dma_intr (ide_drive_t *drive)
 {
-	byte stat, dma_stat;
 	int i;
-	struct request *rq = HWGROUP(drive)->rq;
-	unsigned short dma_base = HWIF(drive)->dma_base;
+	byte stat, dma_stat;
 
-	dma_stat = inb(dma_base+2);		/* get DMA status */
-	outb(inb(dma_base)&~1, dma_base);	/* stop DMA operation */
+	dma_stat = HWIF(drive)->dmaproc(ide_dma_end, drive);
 	stat = GET_STAT();			/* get drive status */
 	if (OK_STAT(stat,DRIVE_READY,drive->bad_wstat|DRQ_STAT)) {
-		if ((dma_stat & 7) == 4) {	/* verify good DMA status */
+		if (!dma_stat) {
+			struct request *rq = HWGROUP(drive)->rq;
 			rq = HWGROUP(drive)->rq;
 			for (i = rq->nr_sectors; i > 0;) {
 				i -= rq->current_nr_sectors;
@@ -134,7 +125,7 @@
 			}
 			return;
 		}
-		printk("%s: bad DMA status: 0x%02x\n", drive->name, dma_stat);
+		printk("%s: dma_intr: bad DMA status\n", drive->name);
 	}
 	sti();
 	ide_error(drive, "dma_intr", stat);
@@ -195,23 +186,46 @@
 				unsigned long xcount, bcount = 0x10000 - (addr & 0xffff);
 				if (bcount > size)
 					bcount = size;
-				*table++ = addr;
+				*table++ = cpu_to_le32(addr);
 				xcount = bcount & 0xffff;
 				if (is_trm290_chipset)
 					xcount = ((xcount >> 2) - 1) << 16;
-				*table++ = xcount;
+				*table++ = cpu_to_le32(xcount);
 				addr += bcount;
 				size -= bcount;
 			}
 		}
 	} while (bh != NULL);
-	if (count) {
-		if (!is_trm290_chipset)
-			*--table |= 0x80000000;	/* set End-Of-Table (EOT) bit */
-		return count;
+	if (!count)
+		printk("%s: empty DMA table?\n", drive->name);
+	else if (!is_trm290_chipset)
+		*--table |= cpu_to_le32(0x80000000);	/* set End-Of-Table (EOT) bit */
+	return count;
+}
+
+static int config_drive_for_dma (ide_drive_t *drive)
+{
+	const char **list;
+	struct hd_driveid *id = drive->id;
+	ide_hwif_t *hwif = HWIF(drive);
+
+	if (id && (id->capability & 1) && !HWIF(drive)->no_autodma) {
+		/* Enable DMA on any drive that has UltraDMA (mode 0/1/2) enabled */
+		if (id->field_valid & 4)	/* UltraDMA */
+			if  ((id->dma_ultra & (id->dma_ultra >> 8) & 7))
+				return hwif->dmaproc(ide_dma_on, drive);
+		/* Enable DMA on any drive that has mode2 DMA (multi or single) enabled */
+		if (id->field_valid & 2)	/* regular DMA */
+			if  ((id->dma_mword & 0x404) == 0x404 || (id->dma_1word & 0x404) == 0x404)
+				return hwif->dmaproc(ide_dma_on, drive);
+		/* Consult the list of known "good" drives */
+		list = good_dma_drives;
+		while (*list) {
+			if (!strcmp(*list++,id->model))
+				return hwif->dmaproc(ide_dma_on, drive);
+		}
 	}
-	printk("%s: empty DMA table?\n", drive->name);
-	return 0;
+	return hwif->dmaproc(ide_dma_off_quietly, drive);
 }
 
 /*
@@ -233,7 +247,7 @@
 int ide_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
 {
 	ide_hwif_t *hwif = HWIF(drive);
-	unsigned long dma_base = hwif->dma_base;
+	unsigned int dma_base = hwif->dma_base;
 	unsigned int count, reading = 0;
 
 	switch (func) {
@@ -243,21 +257,8 @@
 		case ide_dma_on:
 			drive->using_dma = (func == ide_dma_on);
 			return 0;
-		case ide_dma_abort:
-			outb(inb(dma_base)&~1, dma_base);	/* stop DMA */
-			return 0;
 		case ide_dma_check:
 			return config_drive_for_dma (drive);
-		case ide_dma_status_bad:
-			return ((inb(dma_base+2) & 7) != 4);	/* verify good DMA status */
-		case ide_dma_transferred:
-			return 0; /* NOT IMPLEMENTED: number of bytes actually transferred */
-		case ide_dma_begin:
-			outb(inb(dma_base)|1, dma_base);	/* begin DMA */
-			return 0;
-		default:
-			printk("ide_dmaproc: unsupported func: %d\n", func);
-			return 1;
 		case ide_dma_read:
 			reading = 1 << 3;
 		case ide_dma_write:
@@ -268,50 +269,37 @@
 			outb(inb(dma_base+2)|0x06, dma_base+2);		/* clear status bits */
 			if (drive->media != ide_disk)
 				return 0;
-			ide_set_handler(drive, &dma_intr, WAIT_CMD);	/* issue cmd to drive */
+			ide_set_handler(drive, &ide_dma_intr, WAIT_CMD);/* issue cmd to drive */
 			OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG);
-			outb(inb(dma_base)|1, dma_base);		/* begin DMA */
+		case ide_dma_begin:
+			outb(inb(dma_base)|1, dma_base);		/* start DMA */
 			return 0;
-	}
-}
-
-static int config_drive_for_dma (ide_drive_t *drive)
-{
-	const char **list;
-	struct hd_driveid *id = drive->id;
-	ide_hwif_t *hwif = HWIF(drive);
-
-	if (id && (id->capability & 1)) {
-		/* Enable DMA on any drive that has UltraDMA (mode 0/1/2) enabled */
-		if (id->field_valid & 4)	/* UltraDMA */
-			if  ((id->dma_ultra & (id->dma_ultra >> 8) & 7))
-				return hwif->dmaproc(ide_dma_on, drive);
-		/* Enable DMA on any drive that has mode2 DMA (multi or single) enabled */
-		if (id->field_valid & 2)	/* regular DMA */
-			if  ((id->dma_mword & 0x404) == 0x404 || (id->dma_1word & 0x404) == 0x404)
-				return hwif->dmaproc(ide_dma_on, drive);
-		/* Consult the list of known "good" drives */
-		list = good_dma_drives;
-		while (*list) {
-			if (!strcmp(*list++,id->model))
-				return hwif->dmaproc(ide_dma_on, drive);
+		case ide_dma_end: /* returns 1 on error, 0 otherwise */
+		{
+			byte dma_stat = inb(dma_base+2);
+			int rc = (dma_stat & 7) != 4;
+			outb(inb(dma_base)&~1, dma_base);		/* stop DMA */
+			outb(dma_stat|6, dma_base+2);	/* clear the INTR & ERROR bits */
+			return rc;	/* verify good DMA status */
 		}
+		default:
+			printk("ide_dmaproc: unsupported func: %d\n", func);
+			return 1;
 	}
-	return hwif->dmaproc(ide_dma_off_quietly, drive);
 }
 
-void ide_setup_dma (ide_hwif_t *hwif, unsigned short dmabase, unsigned int num_ports)
+void ide_setup_dma (ide_hwif_t *hwif, unsigned int dma_base, unsigned int num_ports) /* __init */
 {
 	static unsigned long dmatable = 0;
 	static unsigned leftover = 0;
 
-	printk("    %s: BM-DMA at 0x%04x-0x%04x", hwif->name, dmabase, dmabase + num_ports - 1);
-	if (check_region(dmabase, num_ports)) {
+	printk("    %s: BM-DMA at 0x%04x-0x%04x", hwif->name, dma_base, dma_base + num_ports - 1);
+	if (check_region(dma_base, num_ports)) {
 		printk(" -- ERROR, PORT ADDRESSES ALREADY IN USE\n");
 		return;
 	}
-	request_region(dmabase, num_ports, hwif->name);
-	hwif->dma_base = dmabase;
+	request_region(dma_base, num_ports, hwif->name);
+	hwif->dma_base = dma_base;
 	if (leftover < (PRD_ENTRIES * PRD_BYTES)) {
 		/*
 		 * The BM-DMA uses full 32bit addr, so we can
@@ -328,87 +316,18 @@
 		dmatable += (PRD_ENTRIES * PRD_BYTES);
 		leftover -= (PRD_ENTRIES * PRD_BYTES);
 		hwif->dmaproc = &ide_dmaproc;
+
 		if (hwif->chipset != ide_trm290) {
-			byte dma_stat = inb(dmabase+2);
-			printk(", BIOS DMA settings: %s:%s %s:%s",
-		 	 hwif->drives[0].name, (dma_stat & 0x20) ? "yes" : "no ",
-		 	 hwif->drives[1].name, (dma_stat & 0x40) ? "yes" : "no");
+			byte dma_stat = inb(dma_base+2);
+			printk(", BIOS settings: %s:%s, %s:%s",
+		 	 hwif->drives[0].name, (dma_stat & 0x20) ? "DMA" : "pio",
+		 	 hwif->drives[1].name, (dma_stat & 0x40) ? "DMA" : "pio");
 		}
 		printk("\n");
 	}
 }
 
-#ifdef CONFIG_BLK_DEV_TRM290
-extern void ide_init_trm290(byte, byte, ide_hwif_t *);
-#define INIT_TRM290 (&ide_init_trm290)
-#else
-#define INIT_TRM290 (NULL)
-#endif	/* CONFIG_BLK_DEV_TRM290 */
-
-#ifdef CONFIG_BLK_DEV_OPTI621
-extern void ide_init_opti621(byte, byte, ide_hwif_t *);
-#define INIT_OPTI (&ide_init_opti621)
-#else
-#define INIT_OPTI (NULL)
-#endif	/* CONFIG_BLK_DEV_OPTI621 */
-
-#define DEVID_PIIX	(PCI_VENDOR_ID_INTEL  |(PCI_DEVICE_ID_INTEL_82371_1   <<16))
-#define DEVID_PIIX3	(PCI_VENDOR_ID_INTEL  |(PCI_DEVICE_ID_INTEL_82371SB_1 <<16))
-#define DEVID_PIIX4	(PCI_VENDOR_ID_INTEL  |(PCI_DEVICE_ID_INTEL_82371AB   <<16))
-#define DEVID_VP_IDE 	(PCI_VENDOR_ID_VIA    |(PCI_DEVICE_ID_VIA_82C586_1    <<16))
-#define DEVID_PDC20246	(PCI_VENDOR_ID_PROMISE|(PCI_DEVICE_ID_PROMISE_20246   <<16))
-#define DEVID_RZ1000	(PCI_VENDOR_ID_PCTECH |(PCI_DEVICE_ID_PCTECH_RZ1000   <<16))
-#define DEVID_RZ1001	(PCI_VENDOR_ID_PCTECH |(PCI_DEVICE_ID_PCTECH_RZ1001   <<16))
-#define DEVID_CMD640	(PCI_VENDOR_ID_CMD    |(PCI_DEVICE_ID_CMD_640         <<16))
-#define DEVID_CMD646	(PCI_VENDOR_ID_CMD    |(PCI_DEVICE_ID_CMD_646         <<16))
-#define DEVID_SIS5513	(PCI_VENDOR_ID_SI     |(PCI_DEVICE_ID_SI_5513         <<16))
-#define DEVID_OPTI	(PCI_VENDOR_ID_OPTI   |(PCI_DEVICE_ID_OPTI_82C621     <<16))
-#define DEVID_OPTI2	(PCI_VENDOR_ID_OPTI   |(0xd568 /* from datasheets */  <<16))
-#define DEVID_TRM290	(PCI_VENDOR_ID_TEKRAM |(PCI_DEVICE_ID_TEKRAM_DC290    <<16))
-#define DEVID_NS87410	(PCI_VENDOR_ID_NS     |(PCI_DEVICE_ID_NS_87410        <<16))
-#define DEVID_HT6565	(PCI_VENDOR_ID_HOLTEK |(PCI_DEVICE_ID_HOLTEK_6565     <<16))
-
-typedef struct ide_pci_enablebit_s {
-	byte	reg;	/* byte pci reg holding the enable-bit */
-	byte	mask;	/* mask to isolate the enable-bit */
-	byte	val;	/* value of masked reg when "enabled" */
-} ide_pci_enablebit_t;
-
-typedef struct ide_pci_device_s {
-	unsigned int		id;
-	const char		*name;
-	void 			(*init_hwif)(byte bus, byte fn, ide_hwif_t *hwif);
-	ide_pci_enablebit_t	enablebits[2];
-} ide_pci_device_t;
-
-static ide_pci_device_t ide_pci_chipsets[] = {
-	{DEVID_PIIX,	"PIIX",		NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}} },
-	{DEVID_PIIX3,	"PIIX3",	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}} },
-	{DEVID_PIIX4,	"PIIX4",	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}} },
-	{DEVID_VP_IDE,	"VP_IDE",	NULL,		{{0x40,0x02,0x02}, {0x40,0x01,0x01}} },
-	{DEVID_PDC20246,"PDC20246",	NULL,		{{0x50,0x02,0x02}, {0x50,0x04,0x04}} },
-	{DEVID_RZ1000,	NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}} },
-	{DEVID_RZ1001,	NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}} },
-	{DEVID_CMD640,	NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}} },
-	{DEVID_OPTI,	"OPTI",		INIT_OPTI,	{{0x45,0x80,0x00}, {0x40,0x08,0x00}} },
-	{DEVID_OPTI2,	"OPTI2",	INIT_OPTI,	{{0x45,0x80,0x00}, {0x40,0x08,0x00}} },
-	{DEVID_SIS5513,	"SIS5513",	NULL,		{{0x4a,0x02,0x02}, {0x4a,0x04,0x04}} },
-	{DEVID_CMD646,	"CMD646",	NULL,		{{0x00,0x00,0x00}, {0x51,0x80,0x80}} },
-	{DEVID_TRM290,	"TRM290",	INIT_TRM290,	{{0x00,0x00,0x00}, {0x00,0x00,0x00}} },
-	{DEVID_NS87410,	"NS87410",	NULL,		{{0x43,0x08,0x08}, {0x47,0x08,0x08}} },
-	{DEVID_HT6565,	"HT6565",	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}} },
-	{0,		"PCI_IDE",	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}} }};
-
-__initfunc(static ide_pci_device_t *lookup_devid(unsigned int devid))
-{
-	ide_pci_device_t *d = ide_pci_chipsets;
-	while (d->id && d->id != devid)
-		++d;
-	return d;
-}
-
-/* The next two functions were stolen from cmd640.c, with
-   a few modifications  */
+/* The next two functions were stolen from cmd640.c, with a few modifications  */
 
 __initfunc(static void write_pcicfg_dword (byte fn, unsigned short reg, long val))
 {
@@ -435,244 +354,50 @@
 }
 
 /*
- * Search for an (apparently) unused block of I/O space
- * of "size" bytes in length.
+ * Fetch the DMA Bus-Master-I/O-Base-Address (BMIBA) from PCI space:
  */
-__initfunc(static short find_free_region (unsigned short size))
+unsigned int ide_get_or_set_dma_base (ide_hwif_t *hwif, int extra, const char *name) /* __init */
 {
-	unsigned short i, base = 0xe800;
-	for (base = 0xe800; base > 0; base -= 0x800) {
-		if (!check_region(base,size)) {
-			for (i = 0; i < size; i++) {
-				if (inb(base+i) != 0xff)
-					goto next;
-			}
-			return base;	/* success */
-		}
-	next:
-	}
-	return 0;	/* failure */
-}
+	unsigned int new, dma_base = 0;
+	byte bus = hwif->pci_bus, fn = hwif->pci_fn;
 
-/*
- * Fetch the Bus-Master I/O Base-Address (BMIBA) from PCI space:
- */
-__initfunc(static unsigned int ide_get_or_set_bmiba (byte bus, byte fn, const char *name))
-{
-	unsigned int bmiba = 0;
-	unsigned short base;
-	int rc;
-
-	if ((rc = pcibios_read_config_dword(bus, fn, 0x20, &bmiba))) {
-		printk("%s: failed to read BMIBA\n", name);
-	} else if ((bmiba &= 0xfff0) == 0) {
-	        printk("%s: BMIBA is invalid (0x%04x, BIOS problem)\n", name, bmiba);
-		base = find_free_region(16);
-	        if (base) {
-			printk("%s: setting BMIBA to 0x%04x\n", name, base);
-			pcibios_write_config_dword(bus, fn, 0x20, base | 1);
-			pcibios_read_config_dword(bus, fn, 0x20, &bmiba);
-			bmiba &= 0xfff0;
-			if (bmiba != base) {
+	if (hwif->mate && hwif->mate->dma_base) {
+		dma_base = hwif->mate->dma_base - (hwif->channel ? 0 : 8);
+	} else if (pcibios_read_config_dword(bus, fn, 0x20, &dma_base)) {
+		printk("%s: failed to read dma_base\n", name);
+		dma_base = 0;
+	} else if ((dma_base &= ~0xf) == 0 || dma_base == ~0xf) {
+		printk("%s: dma_base is invalid (0x%04x, BIOS problem)\n", name, dma_base);
+		new = ide_find_free_region(16 + extra);
+		hwif->no_autodma = 1;	/* default DMA off if we had to configure it here */
+		if (new) {
+			printk("%s: setting dma_base to 0x%04x\n", name, new);
+			new |= 1;
+			(void) pcibios_write_config_dword(bus, fn, 0x20, new);
+			(void) pcibios_read_config_dword(bus, fn, 0x20, &dma_base);
+			if (dma_base != new) {
 				if (bus == 0) {
 					printk("%s: operation failed, bypassing BIOS to try again\n", name);
-					write_pcicfg_dword(fn, 0x20, base | 1);
-					bmiba = read_pcicfg_dword(fn, 0x20) & 0xfff0;
+					write_pcicfg_dword(fn, 0x20, new);
+					dma_base = read_pcicfg_dword(fn, 0x20);
 				}
-				if (bmiba != base) {
+				if (dma_base != new) {
 					printk("%s: operation failed, DMA disabled\n", name);
-					bmiba = 0;
+					dma_base = 0;
 				}
 			}
+			dma_base &= ~0xf;
 		}
 	}
-	return bmiba;
-}
-
-/*
- * Match a PCI IDE port against an entry in ide_hwifs[],
- * based on io_base port if possible.
- */
-__initfunc(ide_hwif_t *ide_match_hwif (unsigned int io_base))
-{
-	int h;
-	ide_hwif_t *hwif;
-
-	/*
-	 * Look for a hwif with matching io_base specified using
-	 * parameters to ide_setup().
-	 */
-	for (h = 0; h < MAX_HWIFS; ++h) {
-		hwif = &ide_hwifs[h];
-		if (hwif->io_ports[IDE_DATA_OFFSET] == io_base) {
-			if (hwif->chipset == ide_generic)
-				return hwif; /* a perfect match */
-		}
-	}
-	/*
-	 * Look for a hwif with matching io_base default value.
-	 * If chipset is "ide_unknown", then claim that hwif slot.
-	 * Otherwise, some other chipset has already claimed it..  :(
-	 */
-	for (h = 0; h < MAX_HWIFS; ++h) {
-		hwif = &ide_hwifs[h];
-		if (hwif->io_ports[IDE_DATA_OFFSET] == io_base) {
-			if (hwif->chipset == ide_unknown)
-				return hwif; /* match */
-			return NULL;	/* already claimed */
-		}
-	}
-	/*
-	 * Okay, there is no hwif matching our io_base,
-	 * so we'll just claim an unassigned slot.
-	 * Give preference to claiming ide2/ide3 before ide0/ide1,
-	 * just in case there's another interface yet-to-be-scanned
-	 * which uses ports 1f0/170 (the ide0/ide1 defaults).
-	 */
-	for (h = 0; h < MAX_HWIFS; ++h) {
-		int hwifs[] = {2,3,1,0}; /* assign 3rd/4th before 1st/2nd */
-		hwif = &ide_hwifs[hwifs[h]];
-		if (hwif->chipset == ide_unknown)
-			return hwif;	/* pick an unused entry */
-	}
-	return NULL;
-}
-				
-/*
- * ide_setup_pci_device() looks at the primary/secondary interfaces
- * on a PCI IDE device and, if they are enabled, prepares the IDE driver
- * for use with them.  This generic code works for most PCI chipsets.
- *
- * One thing that is not standardized is the location of the
- * primary/secondary interface "enable/disable" bits.  For chipsets that
- * we "know" about, this information is in the ide_pci_device_t struct;
- * for all other chipsets, we just assume both interfaces are enabled.
- */
-__initfunc(static void ide_setup_pci_device (byte bus, byte fn, unsigned int bmiba, ide_pci_device_t *d))
-{
-	unsigned int port, at_least_one_hwif_enabled = 0;
-	unsigned short base = 0, ctl = 0;
-	byte tmp = 0;
-	ide_hwif_t *hwif, *mate = NULL;
-
-	for (port = 0; port <= 1; ++port) {
-		ide_pci_enablebit_t *e = &(d->enablebits[port]);
-		if (e->reg) {
-			if (pcibios_read_config_byte(bus, fn, e->reg, &tmp)) {
-				printk("%s: unable to read pci reg 0x%x\n", d->name, e->reg);
-			} else if ((tmp & e->mask) != e->val)
-				continue;	/* port not enabled */
-		}
-		if (pcibios_read_config_word(bus, fn, 0x14+(port*8), &ctl))
-			ctl = 0;
-		if ((ctl &= 0xfffc) == 0)
-			ctl = 0x3f4 ^ (port << 7);
-		if (pcibios_read_config_word(bus, fn, 0x10+(port*8), &base))
-			base = 0;
-		if ((base &= 0xfff8) == 0)
-			base = 0x1F0 ^ (port << 7);
-		if ((hwif = ide_match_hwif(base)) == NULL) {
-			printk("%s: no room in hwif table for port %d\n", d->name, port);
-			continue;
-		}
-		hwif->chipset = ide_pci;
-		hwif->pci_port = port;
-		if (mate) {
-			hwif->mate = mate;
-			mate->mate = hwif;
-		}
-		mate = hwif;	/* for next iteration */
-		if (hwif->io_ports[IDE_DATA_OFFSET] != base) {
-			ide_init_hwif_ports(hwif->io_ports, base, NULL);
-			hwif->io_ports[IDE_CONTROL_OFFSET] = ctl + 2;
-		}
-		if (bmiba) {
-			if ((inb(bmiba+2) & 0x80)) {	/* simplex DMA only? */
-				printk("%s: simplex device:  DMA disabled\n", d->name);
-			} else {	/* supports simultaneous DMA on both channels */
-				ide_setup_dma(hwif, bmiba + (8 * port), 8);
-			}
-		}
-		if (d->id) {  /* For "known" chipsets, allow other irqs during i/o */
-			hwif->drives[0].unmask = 1;
-			hwif->drives[1].unmask = 1;
-		}
-		if (d->init_hwif)  /* Call chipset-specific routine for each enabled hwif */
-			d->init_hwif(bus, fn, hwif);
-		at_least_one_hwif_enabled = 1;
-	}
-	if (!at_least_one_hwif_enabled)
-		printk("%s: neither IDE port enabled (BIOS)\n", d->name);
-}
-
-/*
- * ide_scan_pci_device() examines all functions of a PCI device,
- * looking for IDE interfaces and/or devices in ide_pci_chipsets[].
- */
-__initfunc(static inline void ide_scan_pci_device (unsigned int bus, unsigned int fn))
-{
-	unsigned int devid, ccode;
-	unsigned short pcicmd, class;
-	ide_pci_device_t *d;
-	byte hedt, progif;
-
-	if (pcibios_read_config_byte(bus, fn, 0x0e, &hedt))
-		hedt = 0;
-	do {
-		if (pcibios_read_config_dword(bus, fn, 0x00, &devid)
-		 || devid == 0xffffffff
-		 || pcibios_read_config_dword(bus, fn, 0x08, &ccode))
-			return;
-		d = lookup_devid(devid);
-		if (d->name == NULL)	/* some chips (cmd640, rz1000) are handled elsewhere */
-			continue;
-		progif = (ccode >> 8) & 0xff;
-		class = ccode >> 16;
-		if (d->id || class == PCI_CLASS_STORAGE_IDE) {
-			if (d->id)
-				printk("%s: IDE device on PCI bus %d function %d\n", d->name, bus, fn);
-			else
-				printk("%s: unknown IDE device on PCI bus %d function %d, VID=%04x, DID=%04x\n",
-					d->name, bus, fn, devid & 0xffff, devid >> 16);
-			/*
-	 		 * See if IDE ports are enabled
-	 		 */
-			if (pcibios_read_config_word(bus, fn, 0x04, &pcicmd)) {
-				printk("%s: error accessing PCICMD\n", d->name);
-			} else if ((pcicmd & 1) == 0) {
-				printk("%s: device disabled (BIOS)\n", d->name);
-			} else {
-				unsigned int bmiba = 0;
-				/*
-			 	 * Check for Bus-Master DMA capability
-			 	 */
-				if (d->id == DEVID_PDC20246 || (class == PCI_CLASS_STORAGE_IDE && (progif & 0x80))) {
-					if ((!(pcicmd & 4) || !(bmiba = ide_get_or_set_bmiba(bus, fn, d->name)))) {
-						printk("%s: Bus-Master DMA disabled (BIOS), pcicmd=0x%04x, progif=0x%02x, bmiba=0x%04x\n", d->name, pcicmd, progif, bmiba);
-					}
-				}
-				/*
-				 * Setup the IDE ports
-				 */
-				ide_setup_pci_device(bus, fn, bmiba, d);
-			}
-		}
-	} while (hedt == 0x80 && (++fn & 7));
-}
-
-/*
- * ide_scan_pcibus() gets invoked at boot time from ide.c
- */
-__initfunc(void ide_scan_pcibus (void))
-{
-	unsigned int bus, dev;
-
-	if (!pcibios_present())
-		return;
-	for (bus = 0; bus <= 255; ++bus) {
-		for (dev = 0; dev <= 31; ++dev) {
-			ide_scan_pci_device(bus, dev << 3);
+	if (dma_base) {
+		if (extra) /* PDC20246 */
+			request_region(dma_base+16, extra, name);
+		dma_base += hwif->channel ? 8 : 0;
+		if (inb(dma_base+2) & 0x80) {
+			printk("%s: simplex device:  DMA disabled\n", name);
+			dma_base = 0;
 		}
 	}
+	return dma_base;
 }
 
diff -u --recursive --new-file v2.1.72/linux/drivers/block/ide-floppy.c linux/drivers/block/ide-floppy.c
--- v2.1.72/linux/drivers/block/ide-floppy.c	Mon Dec  1 12:04:12 1997
+++ linux/drivers/block/ide-floppy.c	Wed Dec 17 11:11:16 1997
@@ -1,5 +1,5 @@
 /*
- * linux/drivers/block/ide-floppy.c	Version 0.5 - ALPHA	Feb  21, 1997
+ * linux/drivers/block/ide-floppy.c	Version 0.8		Feb  21, 1997
  *
  * Copyright (C) 1996, 1997 Gadi Oxman <gadio@netvision.net.il>
  */
@@ -21,8 +21,15 @@
  *                       Use the minimum of the LBA and CHS capacities.
  *                       Avoid hwgroup->rq == NULL on the last irq.
  *                       Fix potential null dereferencing with DEBUG_LOG.
+ * Ver 0.8   Dec  7 97   Increase irq timeout from 10 to 50 seconds.
+ *                       Add media write-protect detection.
+ *                       Issue START command only if TEST UNIT READY fails.
+ *                       Add work-around for IOMEGA ZIP revision 21.D.
+ *                       Remove idefloppy_get_capabilities().
  */
 
+#define IDEFLOPPY_VERSION "0.8"
+
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/types.h>
@@ -31,12 +38,9 @@
 #include <linux/delay.h>
 #include <linux/timer.h>
 #include <linux/mm.h>
-#include <linux/ioport.h>
 #include <linux/interrupt.h>
 #include <linux/major.h>
-#include <linux/blkdev.h>
 #include <linux/errno.h>
-#include <linux/hdreg.h>
 #include <linux/genhd.h>
 #include <linux/malloc.h>
 
@@ -60,6 +64,11 @@
 #define IDEFLOPPY_DEBUG_BUGS		1
 
 /*
+ *	Some drives require a longer irq timeout.
+ */
+#define IDEFLOPPY_WAIT_CMD		(5 * WAIT_CMD)
+
+/*
  *	After each failed packet command we issue a request sense command
  *	and retry the packet command IDEFLOPPY_MAX_PC_RETRIES times.
  */
@@ -191,6 +200,7 @@
 	int blocks, block_size, bs_factor;			/* Current format */
 	idefloppy_capacity_descriptor_t capacity;		/* Last format capacity */
 	idefloppy_flexible_disk_page_t flexible_disk_page;	/* Copy of the flexible disk page */
+	int wp;							/* Write protect */
 
 	unsigned int flags;			/* Status/Action flags */
 } idefloppy_floppy_t;
@@ -683,13 +693,12 @@
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
 	if (test_bit (PC_DMA_IN_PROGRESS, &pc->flags)) {
-		if (HWIF(drive)->dmaproc(ide_dma_status_bad, drive)) {
+		if (HWIF(drive)->dmaproc(ide_dma_end, drive)) {
 			set_bit (PC_DMA_ERROR, &pc->flags);
 		} else {
 			pc->actually_transferred=pc->request_transfer;
 			idefloppy_update_buffers (drive, pc);
 		}
-		(void) (HWIF(drive)->dmaproc(ide_dma_abort, drive));	/* End DMA */
 #if IDEFLOPPY_DEBUG_LOG
 		printk (KERN_INFO "ide-floppy: DMA finished\n");
 #endif /* IDEFLOPPY_DEBUG_LOG */
@@ -728,8 +737,7 @@
 #ifdef CONFIG_BLK_DEV_IDEDMA
 	if (test_and_clear_bit (PC_DMA_IN_PROGRESS, &pc->flags)) {
 		printk (KERN_ERR "ide-floppy: The floppy wants to issue more interrupts in DMA mode\n");
-		printk (KERN_ERR "ide-floppy: DMA disabled, reverting to PIO\n");
-		HWIF(drive)->dmaproc(ide_dma_off, drive);
+		(void) HWIF(drive)->dmaproc(ide_dma_off, drive);
 		ide_do_reset (drive);
 		return;
 	}
@@ -755,7 +763,7 @@
 			if (temp > pc->buffer_size) {
 				printk (KERN_ERR "ide-floppy: The floppy wants to send us more data than expected - discarding data\n");
 				idefloppy_discard_data (drive,bcount.all);
-				ide_set_handler (drive,&idefloppy_pc_intr,WAIT_CMD);
+				ide_set_handler (drive,&idefloppy_pc_intr,IDEFLOPPY_WAIT_CMD);
 				return;
 			}
 #if IDEFLOPPY_DEBUG_LOG
@@ -777,7 +785,7 @@
 	pc->actually_transferred+=bcount.all;				/* Update the current position */
 	pc->current_position+=bcount.all;
 
-	ide_set_handler (drive,&idefloppy_pc_intr,WAIT_CMD);		/* And set the interrupt handler again */
+	ide_set_handler (drive,&idefloppy_pc_intr,IDEFLOPPY_WAIT_CMD);		/* And set the interrupt handler again */
 }
 
 static void idefloppy_transfer_pc (ide_drive_t *drive)
@@ -795,7 +803,7 @@
 		ide_do_reset (drive);
 		return;
 	}
-	ide_set_handler (drive, &idefloppy_pc_intr, WAIT_CMD);	/* Set the interrupt routine */
+	ide_set_handler (drive, &idefloppy_pc_intr, IDEFLOPPY_WAIT_CMD);	/* Set the interrupt routine */
 	atapi_output_bytes (drive, floppy->pc->c, 12);		/* Send the actual packet */
 }
 
@@ -843,8 +851,7 @@
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
 	if (test_and_clear_bit (PC_DMA_ERROR, &pc->flags)) {
-		printk (KERN_WARNING "ide-floppy: DMA disabled, reverting to PIO\n");
-		HWIF(drive)->dmaproc(ide_dma_off, drive);
+		(void) HWIF(drive)->dmaproc(ide_dma_off, drive);
 	}
 	if (test_bit (PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma)
 		dma_ok=!HWIF(drive)->dmaproc(test_bit (PC_WRITING, &pc->flags) ? ide_dma_write : ide_dma_read, drive);
@@ -864,7 +871,7 @@
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 
 	if (test_bit (IDEFLOPPY_DRQ_INTERRUPT, &floppy->flags)) {
-		ide_set_handler (drive, &idefloppy_transfer_pc, WAIT_CMD);
+		ide_set_handler (drive, &idefloppy_transfer_pc, IDEFLOPPY_WAIT_CMD);
 		OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG);		/* Issue the packet command */
 	} else {
 		OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG);
@@ -934,6 +941,12 @@
 	pc->c[4] = start;
 }
 
+static void idefloppy_create_test_unit_ready_cmd(idefloppy_pc_t *pc)
+{
+	idefloppy_init_pc(pc);
+	pc->c[0] = IDEFLOPPY_TEST_UNIT_READY_CMD;
+}
+
 static void idefloppy_create_rw_cmd (idefloppy_floppy_t *floppy, idefloppy_pc_t *pc, struct request *rq, unsigned long sector)
 {
 	int block = sector / floppy->bs_factor;
@@ -1041,6 +1054,7 @@
 		return 1;
 	}
 	header = (idefloppy_mode_parameter_header_t *) pc.buffer;
+	floppy->wp = header->wp;
 	page = (idefloppy_flexible_disk_page_t *) (header + 1);
 
 	page->transfer_rate = ntohs (page->transfer_rate);
@@ -1144,13 +1158,21 @@
 
 	MOD_INC_USE_COUNT;
 	if (drive->usage == 1) {
-		idefloppy_create_start_stop_cmd (&pc, 1);
-		(void) idefloppy_queue_pc_tail (drive, &pc);
+		idefloppy_create_test_unit_ready_cmd(&pc);
+		if (idefloppy_queue_pc_tail(drive, &pc)) {
+			idefloppy_create_start_stop_cmd (&pc, 1);
+			(void) idefloppy_queue_pc_tail (drive, &pc);
+		}
 		if (idefloppy_get_capacity (drive)) {
 			drive->usage--;
 			MOD_DEC_USE_COUNT;
 			return -EIO;
 		}
+		if (floppy->wp && (filp->f_mode & 2)) {
+			drive->usage--;
+			MOD_DEC_USE_COUNT;
+			return -EROFS;
+		}		
 		set_bit (IDEFLOPPY_MEDIA_CHANGED, &floppy->flags);
 		idefloppy_create_prevent_cmd (&pc, 1);
 		(void) idefloppy_queue_pc_tail (drive, &pc);
@@ -1243,9 +1265,9 @@
 		default: sprintf (buffer, "Reserved");break;
 	}
 	printk (KERN_INFO "Command Packet Size: %s\n", buffer);
-	printk (KERN_INFO "Model: %s\n",id->model);
-	printk (KERN_INFO "Firmware Revision: %s\n",id->fw_rev);
-	printk (KERN_INFO "Serial Number: %s\n",id->serial_no);
+	printk (KERN_INFO "Model: %.40s\n",id->model);
+	printk (KERN_INFO "Firmware Revision: %.8s\n",id->fw_rev);
+	printk (KERN_INFO "Serial Number: %.20s\n",id->serial_no);
 	printk (KERN_INFO "Write buffer size(?): %d bytes\n",id->buf_size*512);
 	printk (KERN_INFO "DMA: %s",id->capability & 0x01 ? "Yes\n":"No\n");
 	printk (KERN_INFO "LBA: %s",id->capability & 0x02 ? "Yes\n":"No\n");
@@ -1306,51 +1328,13 @@
 }
 
 /*
- *	idefloppy_get_capabilities asks the floppy about its various
- *	parameters.
- */
-static void idefloppy_get_capabilities (ide_drive_t *drive)
-{
-	idefloppy_pc_t pc;
-	idefloppy_mode_parameter_header_t *header;
-	idefloppy_capabilities_page_t *capabilities;
-	
-	idefloppy_create_mode_sense_cmd (&pc, IDEFLOPPY_CAPABILITIES_PAGE, MODE_SENSE_CURRENT);
-	if (idefloppy_queue_pc_tail (drive,&pc)) {
-		printk (KERN_ERR "ide-floppy: Can't get drive capabilities\n");
-		return;
-	}
-	header = (idefloppy_mode_parameter_header_t *) pc.buffer;
-	capabilities = (idefloppy_capabilities_page_t *) (header + 1);
-
-	if (!capabilities->sflp)
-		printk (KERN_INFO "%s: Warning - system floppy device bit is not set\n", drive->name);
-
-#if IDEFLOPPY_DEBUG_INFO
-	printk (KERN_INFO "Dumping the results of the MODE SENSE packet command\n");
-	printk (KERN_INFO "Mode Parameter Header:\n");
-	printk (KERN_INFO "Mode Data Length - %d\n",header->mode_data_length);
-	printk (KERN_INFO "Medium Type - %d\n",header->medium_type);
-	printk (KERN_INFO "WP - %d\n",header->wp);
-
-	printk (KERN_INFO "Capabilities Page:\n");
-	printk (KERN_INFO "Page code - %d\n",capabilities->page_code);
-	printk (KERN_INFO "Page length - %d\n",capabilities->page_length);
-	printk (KERN_INFO "PS - %d\n",capabilities->ps);
-	printk (KERN_INFO "System Floppy Type device - %s\n",capabilities->sflp ? "Yes":"No");
-	printk (KERN_INFO "Supports Reporting progress of Format - %s\n",capabilities->srfp ? "Yes":"No");
-	printk (KERN_INFO "Non CD Optical device - %s\n",capabilities->ncd ? "Yes":"No");
-	printk (KERN_INFO "Multiple LUN support - %s\n",capabilities->sml ? "Yes":"No");
-	printk (KERN_INFO "Total LUN supported - %s\n",capabilities->tlun ? "Yes":"No");
-#endif /* IDEFLOPPY_DEBUG_INFO */
-}
-
-/*
  *	Driver initialization.
  */
 static void idefloppy_setup (ide_drive_t *drive, idefloppy_floppy_t *floppy)
 {
 	struct idefloppy_id_gcw gcw;
+	int major = HWIF(drive)->major, i;
+	int minor = drive->select.b.unit << PARTN_BITS;
 
 	*((unsigned short *) &gcw) = drive->id->config;
 	drive->driver_data = floppy;
@@ -1360,8 +1344,12 @@
 	floppy->pc = floppy->pc_stack;
 	if (gcw.drq_type == 1)
 		set_bit (IDEFLOPPY_DRQ_INTERRUPT, &floppy->flags);
+	if (strcmp(drive->id->model, "IOMEGA ZIP 100 ATAPI") == 0 &&
+	    strcmp(drive->id->fw_rev, "21.D") == 0) {
+		for (i = 0; i < 1 << PARTN_BITS; i++)
+			max_sectors[major][minor + i] = 64;
+	}
 
-	idefloppy_get_capabilities (drive);
 	(void) idefloppy_get_capacity (drive);
 }
 
@@ -1387,6 +1375,8 @@
  *	IDE subdriver functions, registered with ide.c
  */
 static ide_driver_t idefloppy_driver = {
+	"ide-floppy",		/* name */
+	IDEFLOPPY_VERSION,	/* version */
 	ide_floppy,		/* media */
 	0,			/* busy */
 	1,			/* supports_dma */
@@ -1400,7 +1390,8 @@
 	idefloppy_media_change,	/* media_change */
 	NULL,			/* pre_reset */
 	idefloppy_capacity,	/* capacity */
-	NULL			/* special */
+	NULL,			/* special */
+	NULL			/* proc */
 };
 
 /*
diff -u --recursive --new-file v2.1.72/linux/drivers/block/ide-pci.c linux/drivers/block/ide-pci.c
--- v2.1.72/linux/drivers/block/ide-pci.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/block/ide-pci.c	Wed Dec 17 11:11:51 1997
@@ -0,0 +1,382 @@
+/*
+ *  linux/drivers/block/ide-pci.c	Version 1.00  December 8, 1997
+ *
+ *  Copyright (c) 1995-1998  Mark Lord
+ *  May be copied or modified under the terms of the GNU General Public License
+ */
+
+/*
+ * This modules provides support for automatic detection and
+ * configuration of all PCI IDE interfaces present in a system.  
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/bios32.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include "ide.h"
+
+#define DEVID_PIIX	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82371FB_1})
+#define DEVID_PIIX3	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82371SB_1})
+#define DEVID_PIIX4	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82371AB})
+#define DEVID_VP_IDE	((ide_pci_devid_t){PCI_VENDOR_ID_VIA,     PCI_DEVICE_ID_VIA_82C586_1})
+#define DEVID_PDC20246	((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20246})
+#define DEVID_RZ1000	((ide_pci_devid_t){PCI_VENDOR_ID_PCTECH,  PCI_DEVICE_ID_PCTECH_RZ1000})
+#define DEVID_RZ1001	((ide_pci_devid_t){PCI_VENDOR_ID_PCTECH,  PCI_DEVICE_ID_PCTECH_RZ1001})
+#define DEVID_CMD640	((ide_pci_devid_t){PCI_VENDOR_ID_CMD,     PCI_DEVICE_ID_CMD_640})
+#define DEVID_CMD646	((ide_pci_devid_t){PCI_VENDOR_ID_CMD,     PCI_DEVICE_ID_CMD_646})
+#define DEVID_SIS5513	((ide_pci_devid_t){PCI_VENDOR_ID_SI,      PCI_DEVICE_ID_SI_5513})
+#define DEVID_OPTI621	((ide_pci_devid_t){PCI_VENDOR_ID_OPTI,    PCI_DEVICE_ID_OPTI_82C621})
+#define DEVID_OPTI621V	((ide_pci_devid_t){PCI_VENDOR_ID_OPTI,    PCI_DEVICE_ID_OPTI_82C558})
+#define DEVID_OPTI621X	((ide_pci_devid_t){PCI_VENDOR_ID_OPTI,    0xd568})  /* from datasheets */
+#define DEVID_TRM290	((ide_pci_devid_t){PCI_VENDOR_ID_TEKRAM,  PCI_DEVICE_ID_TEKRAM_DC290})
+#define DEVID_NS87410	((ide_pci_devid_t){PCI_VENDOR_ID_NS,      PCI_DEVICE_ID_NS_87410})
+#define DEVID_NS87415	((ide_pci_devid_t){PCI_VENDOR_ID_NS,      PCI_DEVICE_ID_NS_87415})
+#define DEVID_HT6565	((ide_pci_devid_t){PCI_VENDOR_ID_HOLTEK,  PCI_DEVICE_ID_HOLTEK_6565})
+
+#define IDE_IGNORE	((void *)-1)
+
+#ifdef CONFIG_BLK_DEV_TRM290
+extern void ide_init_trm290(ide_hwif_t *);
+#define INIT_TRM290	&ide_init_trm290
+#else
+#define INIT_TRM290	IDE_IGNORE
+#endif
+
+#ifdef CONFIG_BLK_DEV_OPTI621
+extern void ide_init_opti621(ide_hwif_t *);
+#define INIT_OPTI621	&ide_init_opti621
+#else
+#define INIT_OPTI621	NULL
+#endif
+
+#ifdef CONFIG_BLK_DEV_NS87415
+extern void ide_init_ns87415(ide_hwif_t *);
+#define INIT_NS87415	&ide_init_ns87415
+#else
+#define INIT_NS87415	IDE_IGNORE
+#endif
+
+#ifdef CONFIG_BLK_DEV_RZ1000
+extern void ide_init_rz1000(ide_hwif_t *);
+#define INIT_RZ1000	&ide_init_rz1000
+#else
+#define INIT_RZ1000	IDE_IGNORE
+#endif
+
+typedef struct ide_pci_enablebit_s {
+	byte	reg;	/* byte pci reg holding the enable-bit */
+	byte	mask;	/* mask to isolate the enable-bit */
+	byte	val;	/* value of masked reg when "enabled" */
+} ide_pci_enablebit_t;
+
+typedef struct ide_pci_device_s {
+	ide_pci_devid_t		devid;
+	const char		*name;
+	void 			(*init_hwif)(ide_hwif_t *hwif);
+	ide_pci_enablebit_t	enablebits[2];
+} ide_pci_device_t;
+
+static ide_pci_device_t ide_pci_chipsets[] __initdata = {
+	{DEVID_PIIX,	"PIIX",		NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}} },
+	{DEVID_PIIX3,	"PIIX3",	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}} },
+	{DEVID_PIIX4,	"PIIX4",	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}} },
+	{DEVID_VP_IDE,	"VP_IDE",	NULL,		{{0x40,0x02,0x02}, {0x40,0x01,0x01}} },
+	{DEVID_PDC20246,"PDC20246",	NULL,		{{0x50,0x02,0x02}, {0x50,0x04,0x04}} },
+	{DEVID_RZ1000,	"RZ1000",	INIT_RZ1000,	{{0x00,0x00,0x00}, {0x00,0x00,0x00}} },
+	{DEVID_RZ1001,	"RZ1001",	INIT_RZ1000,	{{0x00,0x00,0x00}, {0x00,0x00,0x00}} },
+	{DEVID_CMD640,	"CMD640",	IDE_IGNORE,	{{0x00,0x00,0x00}, {0x00,0x00,0x00}} },
+	{DEVID_NS87410,	"NS87410",	NULL,		{{0x43,0x08,0x08}, {0x47,0x08,0x08}} },
+	{DEVID_SIS5513,	"SIS5513",	NULL,		{{0x4a,0x02,0x02}, {0x4a,0x04,0x04}} },
+	{DEVID_CMD646,	"CMD646",	NULL,		{{0x00,0x00,0x00}, {0x51,0x80,0x80}} },
+	{DEVID_HT6565,	"HT6565",	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}} },
+	{DEVID_OPTI621,	"OPTI621",	INIT_OPTI621,	{{0x45,0x80,0x00}, {0x40,0x08,0x00}} },
+	{DEVID_OPTI621X,"OPTI621X",	INIT_OPTI621,	{{0x45,0x80,0x00}, {0x40,0x08,0x00}} },
+	{DEVID_TRM290,	"TRM290",	INIT_TRM290,	{{0x00,0x00,0x00}, {0x00,0x00,0x00}} },
+	{DEVID_NS87415,	"NS87415",	INIT_NS87415,	{{0x00,0x00,0x00}, {0x00,0x00,0x00}} },
+	{IDE_PCI_DEVID_NULL, "PCI_IDE",	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}} }};
+
+/*
+ * Search for an (apparently) unused block of I/O space
+ * of "size" bytes in length.  Ideally we ought to do a pass
+ * through pcicfg space to eliminate ports already allocated
+ * by the BIOS, to avoid conflicts later in the init cycle,
+ * but we don't.	FIXME
+ */
+unsigned int ide_find_free_region (unsigned short size) /* __init */
+{
+	static unsigned short base = 0x5800;	/* it works for me */
+	unsigned short i;
+
+	for (; base > 0; base -= 0x200) {
+		if (!check_region(base,size)) {
+			for (i = 0; i < size; i++) {
+				if (inb(base+i) != 0xff)
+					goto next;
+			}
+			return base;	/* success */
+		}
+	next:
+	}
+	return 0;	/* failure */
+}
+
+/*
+ * Match a PCI IDE port against an entry in ide_hwifs[],
+ * based on io_base port if possible.
+ */
+__initfunc(static ide_hwif_t *ide_match_hwif (unsigned int io_base, const char *name))
+{
+	int h;
+	ide_hwif_t *hwif;
+
+	/*
+	 * Look for a hwif with matching io_base specified using
+	 * parameters to ide_setup().
+	 */
+	for (h = 0; h < MAX_HWIFS; ++h) {
+		hwif = &ide_hwifs[h];
+		if (hwif->io_ports[IDE_DATA_OFFSET] == io_base) {
+			if (hwif->chipset == ide_generic)
+				return hwif; /* a perfect match */
+		}
+	}
+	/*
+	 * Look for a hwif with matching io_base default value.
+	 * If chipset is "ide_unknown", then claim that hwif slot.
+	 * Otherwise, some other chipset has already claimed it..  :(
+	 */
+	for (h = 0; h < MAX_HWIFS; ++h) {
+		hwif = &ide_hwifs[h];
+		if (hwif->io_ports[IDE_DATA_OFFSET] == io_base) {
+			if (hwif->chipset == ide_unknown)
+				return hwif; /* match */
+			printk("%s: port 0x%04x already claimed by %s\n", name, io_base, hwif->name);
+			return NULL;	/* already claimed */
+		}
+	}
+	/*
+	 * Okay, there is no hwif matching our io_base,
+	 * so we'll just claim an unassigned slot.
+	 * Give preference to claiming other slots before claiming ide0/ide1,
+	 * just in case there's another interface yet-to-be-scanned
+	 * which uses ports 1f0/170 (the ide0/ide1 defaults).
+	 */
+	for (h = 0; h < MAX_HWIFS; ++h) {
+		int hwifs[] = {2,3,1,0}; /* assign 3rd/4th before 1st/2nd */
+		hwif = &ide_hwifs[hwifs[h]];
+		if (hwif->chipset == ide_unknown)
+			return hwif;	/* pick an unused entry */
+	}
+	printk("%s: too many IDE interfaces, no room in table\n", name);
+	return NULL;
+}
+
+__initfunc(static int ide_setup_pci_baseregs (byte bus, byte fn, const char *name))
+{
+	unsigned int base, readback;
+	byte reg, progif = 0;
+
+	/*
+	 * Place both IDE interfaces into PCI "native" mode:
+	 */
+	if (pcibios_read_config_byte(bus, fn, 0x09, &progif) || (progif & 5) != 5) {
+		if ((progif & 0xa) != 0xa) {
+			printk("%s: device not capable of full native PCI mode\n", name);
+			return 1;
+		}
+		printk("%s: placing both ports into native PCI mode\n", name);
+		(void) pcibios_write_config_byte(bus, fn, 0x09, progif|5);
+		if (pcibios_read_config_byte(bus, fn, 0x09, &progif) || (progif & 5) != 5) {
+			printk("%s: rewrite of PROGIF failed, wanted 0x%04x, got 0x%04x\n", name, progif|5, progif);
+			return 1;
+		}
+	}
+	/*
+	 * Setup base registers for IDE command/control spaces for each interface:
+	 */
+	if (!(base = ide_find_free_region(32)))
+		return 1;
+	for (reg = 0x10; reg <= 0x1c; reg += 4, base += 8) {
+		(void) pcibios_write_config_dword(bus, fn, reg, base|1);
+		if (pcibios_read_config_dword(bus, fn, reg, &readback) || (readback &= ~1) != base) {
+			printk("%s: readback failed for basereg 0x%02x: wrote 0x%04x, read 0x%x04\n", name, reg, base, readback);
+			return 1;
+		}
+	}
+	return 0;
+}
+
+/*
+ * ide_setup_pci_device() looks at the primary/secondary interfaces
+ * on a PCI IDE device and, if they are enabled, prepares the IDE driver
+ * for use with them.  This generic code works for most PCI chipsets.
+ *
+ * One thing that is not standardized is the location of the
+ * primary/secondary interface "enable/disable" bits.  For chipsets that
+ * we "know" about, this information is in the ide_pci_device_t struct;
+ * for all other chipsets, we just assume both interfaces are enabled.
+ */
+__initfunc(static void ide_setup_pci_device (byte bus, byte fn, unsigned int ccode, ide_pci_device_t *d))
+{
+	unsigned int port, at_least_one_hwif_enabled = 0, no_autodma = 0;
+	unsigned short pcicmd = 0;
+	byte tmp = 0, progif = 0, pciirq = 0;
+	ide_hwif_t *hwif, *mate = NULL;
+
+	if (pcibios_read_config_word(bus, fn, 0x04, &pcicmd)
+	 || pcibios_read_config_byte(bus, fn, 0x09, &progif)
+	 || pcibios_read_config_byte(bus, fn, 0x3c, &pciirq))
+	{
+		printk("%s: error accessing PCI regs\n", d->name);
+		return;
+	}
+	if (!(pcicmd & 1)) {	/* is device disabled? */
+		/*
+		 * PnP BIOS was *supposed* to have set this device up for us,
+		 * but we can do it ourselves, so long as the BIOS has assigned an IRQ
+		 *  (or possibly the device is using a "legacy header" for IRQs).
+		 * Maybe the user deliberately *disabled* the device,
+		 * but we'll eventually ignore it again if no drives respond.
+		 */
+		if (ide_setup_pci_baseregs(bus, fn, d->name)
+		 || pcibios_write_config_word(bus, fn, 0x04, pcicmd|1)
+		 || pcibios_read_config_word(bus, fn, 0x04, &pcicmd)
+		 || !(pcicmd & 1))
+		{
+			printk("%s: device disabled (BIOS)\n", d->name);
+			return;
+		}
+		no_autodma = 1;	/* default DMA off if we had to configure it here */
+		printk("%s: device enabled (Linux)\n", d->name);
+	}
+	if (!pciirq || pciirq >= NR_IRQS) {	/* is pciirq invalid? */
+		if (pciirq || (progif & 0x5))	/* don't complain if using "legacy" mode */
+			printk("%s: BIOS returned %d for IRQ (ignored)\n", d->name, pciirq);
+		pciirq = 0;	/* probe for it instead */
+	}
+	/*
+	 * Set up the IDE ports
+	 */
+	for (port = 0; port <= 1; ++port) {
+		unsigned int base = 0, ctl = 0;
+		ide_pci_enablebit_t *e = &(d->enablebits[port]);
+		if (e->reg && (pcibios_read_config_byte(bus, fn, e->reg, &tmp) || (tmp & e->mask) != e->val))
+			continue;	/* port not enabled */
+		if (pcibios_read_config_dword(bus, fn, 0x14+(port*8), &ctl) || (ctl &= ~3) == 0)
+			ctl = port ? 0x374 : 0x3f4;	/* use default value */
+		if (pcibios_read_config_dword(bus, fn, 0x10+(port*8), &base) || (base &= ~7) == 0)
+			base = port ? 0x170 : 0x1f0;	/* use default value */
+		if ((hwif = ide_match_hwif(base, d->name)) == NULL)
+			continue;	/* no room in ide_hwifs[] */
+		if (hwif->io_ports[IDE_DATA_OFFSET] != base) {
+			ide_init_hwif_ports(hwif->io_ports, base, NULL);
+			hwif->io_ports[IDE_CONTROL_OFFSET] = ctl + 2;
+		}
+		hwif->chipset = ide_pci;
+		hwif->pci_bus = bus;
+		hwif->pci_fn = fn;
+		hwif->pci_devid = d->devid;
+		hwif->channel = port;
+		hwif->irq = pciirq;
+		if (mate) {
+			hwif->mate = mate;
+			mate->mate = hwif;
+		}
+		if (no_autodma)
+			hwif->no_autodma = 1;
+#ifdef CONFIG_BLK_DEV_IDEDMA
+		if (IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20246) || ((ccode >> 16) == PCI_CLASS_STORAGE_IDE && (ccode & 0x8000))) {
+			unsigned int extra = (!mate && IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20246)) ? 16 : 0;
+			unsigned int dma_base = ide_get_or_set_dma_base(hwif, extra, d->name);
+			if (dma_base && !(pcicmd & 4)) {
+				/*
+ 	 			 * Set up BM-DMA capability (PnP BIOS should have done this)
+ 	 			 */
+				hwif->no_autodma = 1;	/* default DMA off if we had to configure it here */
+				(void) pcibios_write_config_word(bus, fn, 0x04, (pcicmd|4));
+				if (pcibios_read_config_word(bus, fn, 0x04, &pcicmd) || !(pcicmd & 4)) {
+					printk("%s: %s error updating PCICMD\n", hwif->name, d->name);
+					dma_base = 0;
+				}
+			}
+			if (dma_base)
+				ide_setup_dma(hwif, dma_base, 8);
+			else
+				printk("%s: %s Bus-Master DMA disabled (BIOS), pcicmd=0x%04x, ccode=0x%04x, dma_base=0x%04x\n",
+				 hwif->name, d->name, pcicmd, ccode, dma_base);
+		}
+#endif	/* CONFIG_BLK_DEV_IDEDMA */
+		if (d->init_hwif)  /* Call chipset-specific routine for each enabled hwif */
+			d->init_hwif(hwif);
+		mate = hwif;
+		at_least_one_hwif_enabled = 1;
+	}
+	if (!at_least_one_hwif_enabled)
+		printk("%s: neither IDE port enabled (BIOS)\n", d->name);
+}
+
+/*
+ * ide_scan_pci_device() examines all functions of a PCI device,
+ * looking for IDE interfaces and/or devices in ide_pci_chipsets[].
+ * We cannot use pcibios_find_class() cuz it doesn't work in all systems.
+ */
+static inline void ide_scan_pci_device (unsigned int bus, unsigned int fn)
+{
+	unsigned int		ccode;
+	ide_pci_devid_t		devid;
+	ide_pci_device_t	*d;
+	byte			hedt;
+
+	if (pcibios_read_config_byte(bus, fn, 0x0e, &hedt))
+		hedt = 0;
+	do {
+		if (pcibios_read_config_word(bus, fn, 0x00, &devid.vid)
+		 || devid.vid == 0xffff
+		 || pcibios_read_config_word(bus, fn, 0x02, &devid.did)
+		 || IDE_PCI_DEVID_EQ(devid, IDE_PCI_DEVID_NULL)
+		 || pcibios_read_config_dword(bus, fn, 0x08, &ccode))
+			return;
+		for (d = ide_pci_chipsets; d->devid.vid && !IDE_PCI_DEVID_EQ(d->devid, devid); ++d);
+		if (d->init_hwif == IDE_IGNORE)
+			printk("%s: ignored by ide_scan_pci_device() (uses own driver)\n", d->name);
+		else if (IDE_PCI_DEVID_EQ(d->devid, DEVID_OPTI621V) && !(fn & 1))
+			continue;	/* OPTI Viper-M uses same devid for functions 0 and 1 */
+		else if (!IDE_PCI_DEVID_EQ(d->devid, IDE_PCI_DEVID_NULL) || (ccode >> 16) == PCI_CLASS_STORAGE_IDE) {
+			if (IDE_PCI_DEVID_EQ(d->devid, IDE_PCI_DEVID_NULL))
+				printk("%s: unknown IDE device on PCI bus %d function %d, VID=%04x, DID=%04x\n",
+					d->name, bus, fn, devid.vid, devid.did);
+			else
+				printk("%s: PCI bus %d function %d\n", d->name, bus, fn);
+			ide_setup_pci_device(bus, fn, ccode, d);
+		}
+	} while (hedt == 0x80 && (++fn & 7));
+}
+
+/*
+ * ide_scan_pcibus() gets invoked at boot time from ide.c
+ *
+ * Loops over all PCI devices on all PCI buses, invoking ide_scan_pci_device().
+ * We cannot use pcibios_find_class() cuz it doesn't work in all systems.
+ */
+void ide_scan_pcibus (void) /* __init */
+{
+	unsigned int bus, dev;
+
+	if (!pcibios_present())
+		return;
+	for (bus = 0; bus <= 255; ++bus) {
+		for (dev = 0; dev < 256; dev += 8) {
+			ide_scan_pci_device(bus, dev);
+		}
+	}
+}
+
diff -u --recursive --new-file v2.1.72/linux/drivers/block/ide-probe.c linux/drivers/block/ide-probe.c
--- v2.1.72/linux/drivers/block/ide-probe.c	Thu Dec  4 14:53:54 1997
+++ linux/drivers/block/ide-probe.c	Wed Dec 17 11:11:16 1997
@@ -1,7 +1,7 @@
 /*
- *  linux/drivers/block/ide-probe.c	Version 1.02  Jul  29, 1997
+ *  linux/drivers/block/ide-probe.c	Version 1.03  Dec  5, 1997
  *
- *  Copyright (C) 1994-1996  Linus Torvalds & authors (see below)
+ *  Copyright (C) 1994-1998  Linus Torvalds & authors (see below)
  */
 
 /*
@@ -10,36 +10,11 @@
  *
  * This is the IDE probe module, as evolved from hd.c and ide.c.
  *
- *  From hd.c:
- *  |
- *  | It traverses the request-list, using interrupts to jump between functions.
- *  | As nearly all functions can be called within interrupts, we may not sleep.
- *  | Special care is recommended.  Have Fun!
- *  |
- *  | modified by Drew Eckhardt to check nr of hd's from the CMOS.
- *  |
- *  | Thanks to Branko Lankester, lankeste@fwi.uva.nl, who found a bug
- *  | in the early extended-partition checks and added DM partitions.
- *  |
- *  | Early work on error handling by Mika Liljeberg (liljeber@cs.Helsinki.FI).
- *  |
- *  | IRQ-unmask, drive-id, multiple-mode, support for ">16 heads",
- *  | and general streamlining by Mark Lord (mlord@pobox.com).
- *
- *  October, 1994 -- Complete line-by-line overhaul for linux 1.1.x, by:
- *
- *	Mark Lord	(mlord@pobox.com)		(IDE Perf.Pkg)
- *	Delman Lee	(delman@mipg.upenn.edu)		("Mr. atdisk2")
- *	Scott Snyder	(snyder@fnald0.fnal.gov)	(ATAPI IDE cd-rom)
- *
- *  This was a rewrite of just about everything from hd.c, though some original
- *  code is still sprinkled about.  Think of it as a major evolution, with
- *  inspiration from lots of linux users, esp.  hamish@zot.apana.org.au
- *
  * Version 1.00		move drive probing code from ide.c to ide-probe.c
  * Version 1.01		fix compilation problem for m68k
  * Version 1.02		increase WAIT_PIDENTIFY to avoid CD-ROM locking at boot
- *			by Andrea Arcangeli <arcangeli@mbox.queen.it>
+ *			 by Andrea Arcangeli <arcangeli@mbox.queen.it>
+ * Version 1.03		fix for (hwif->chipset == ide_4drives)
  */
 
 #undef REALLY_SLOW_IO		/* most systems can safely undef this */
@@ -51,12 +26,9 @@
 #include <linux/kernel.h>
 #include <linux/timer.h>
 #include <linux/mm.h>
-#include <linux/ioport.h>
 #include <linux/interrupt.h>
 #include <linux/major.h>
-#include <linux/blkdev.h>
 #include <linux/errno.h>
-#include <linux/hdreg.h>
 #include <linux/genhd.h>
 #include <linux/malloc.h>
 #include <linux/delay.h>
@@ -105,6 +77,7 @@
 	ide_fixstring (id->fw_rev,    sizeof(id->fw_rev),    bswap);
 	ide_fixstring (id->serial_no, sizeof(id->serial_no), bswap);
 
+	id->model[sizeof(id->model)-1] = '\0';	/* we depend on this a lot! */
 	drive->present = 1;
 	printk("%s: %s, ", drive->name, id->model);
 
@@ -115,7 +88,7 @@
 		byte type = (id->config >> 8) & 0x1f;
 		printk("ATAPI ");
 #ifdef CONFIG_BLK_DEV_PDC4030
-		if (HWIF(drive)->is_pdc4030_2) {
+		if (HWIF(drive)->channel == 1 && HWIF(drive)->chipset == ide_pdc4030) {
 			printk(" -- not supported on 2nd Promise port\n");
 			drive->present = 0;
 			return;
@@ -160,8 +133,8 @@
  */
 static void delay_50ms (void)
 {
-	unsigned long timer = jiffies + ((HZ + 19)/20) + 1;
-	while (timer > jiffies);
+	unsigned long timeout = jiffies + ((HZ + 19)/20) + 1;
+	while (0 < (signed long)(timeout - jiffies));
 }
 
 /*
@@ -180,6 +153,7 @@
 	ide_ioreg_t hd_status;
 	unsigned long timeout;
 	unsigned long irqs = 0;
+	byte s, a;
 
 	if (!HWIF(drive)->irq) {		/* already got an IRQ? */
 		probe_irq_off(probe_irq_on());	/* clear dangling irqs */
@@ -188,9 +162,11 @@
 	}
 
 	delay_50ms();				/* take a deep breath */
-	if ((IN_BYTE(IDE_ALTSTATUS_REG) ^ IN_BYTE(IDE_STATUS_REG)) & ~INDEX_STAT) {
-		printk("%s: probing with STATUS instead of ALTSTATUS\n", drive->name);
-		hd_status = IDE_STATUS_REG;	/* ancient Seagate drives */
+	a = IN_BYTE(IDE_ALTSTATUS_REG);
+	s = IN_BYTE(IDE_STATUS_REG);
+	if ((a ^ s) & ~INDEX_STAT) {
+		printk("%s: probing with STATUS(0x%02x) instead of ALTSTATUS(0x%02x)\n", drive->name, s, a);
+		hd_status = IDE_STATUS_REG;	/* ancient Seagate drives, broken interfaces */
 	} else
 		hd_status = IDE_ALTSTATUS_REG;	/* use non-intrusive polling */
 
@@ -208,7 +184,7 @@
 	timeout = ((cmd == WIN_IDENTIFY) ? WAIT_WORSTCASE : WAIT_PIDENTIFY) / 2;
 	timeout += jiffies;
 	do {
-		if (jiffies > timeout) {
+		if (0 < (signed long)(jiffies - timeout)) {
 			if (irqs)
 				(void) probe_irq_off(irqs);
 			return 1;	/* drive timed-out */
@@ -285,9 +261,11 @@
 	SELECT_DRIVE(hwif,drive);
 	delay_50ms();
 	if (IN_BYTE(IDE_SELECT_REG) != drive->select.all && !drive->present) {
-		OUT_BYTE(0xa0,IDE_SELECT_REG);	/* exit with drive0 selected */
-		delay_50ms();		/* allow BUSY_STAT to assert & clear */
-		return 3;    /* no i/f present: avoid killing ethernet cards */
+		if (drive->select.b.unit != 0) {
+			SELECT_DRIVE(hwif,&hwif->drives[0]);	/* exit with drive0 selected */
+			delay_50ms();		/* allow BUSY_STAT to assert & clear */
+		}
+		return 3;    /* no i/f present: mmm.. this should be a 4 -ml */
 	}
 
 	if (OK_STAT(GET_STAT(),READY_STAT,BUSY_STAT)
@@ -302,7 +280,7 @@
 		rc = 3;				/* not present or maybe ATAPI */
 	}
 	if (drive->select.b.unit != 0) {
-		OUT_BYTE(0xa0,IDE_SELECT_REG);	/* exit with drive0 selected */
+		SELECT_DRIVE(hwif,&hwif->drives[0]);	/* exit with drive0 selected */
 		delay_50ms();
 		(void) GET_STAT();		/* ensure drive irq is clear */
 	}
@@ -367,7 +345,7 @@
 	int unit;
 
 #ifdef CONFIG_BLK_DEV_PDC4030
-	if (hwif->is_pdc4030_2)
+	if (hwif->chipset == ide_pdc4030 && hwif->channel != 0)
 		return;
 #endif /* CONFIG_BLK_DEV_PDC4030 */
 	outb_p(0x12,0x70);		/* specify CMOS address 0x12 */
@@ -400,12 +378,12 @@
 		return;
 	if (hwif->io_ports[IDE_DATA_OFFSET] == HD_DATA)
 		probe_cmos_for_drives (hwif);
+	if ((hwif->chipset != ide_4drives || !hwif->mate->present)
 #if CONFIG_BLK_DEV_PDC4030
-	if (!hwif->is_pdc4030_2 &&
-	   (ide_check_region(hwif->io_ports[IDE_DATA_OFFSET],8) || ide_check_region(hwif->io_ports[IDE_CONTROL_OFFSET],1))) {
-#else
-	if (ide_check_region(hwif->io_ports[IDE_DATA_OFFSET],8) || ide_check_region(hwif->io_ports[IDE_CONTROL_OFFSET],1)) {
+	 && (hwif->chipset != ide_pdc4030 || hwif->channel == 0)
 #endif /* CONFIG_BLK_DEV_PDC4030 */
+	 && (ide_check_region(hwif->io_ports[IDE_DATA_OFFSET],8) || ide_check_region(hwif->io_ports[IDE_CONTROL_OFFSET],1)))
+	{
 		int msgout = 0;
 		for (unit = 0; unit < MAX_DRIVES; ++unit) {
 			ide_drive_t *drive = &hwif->drives[unit];
@@ -431,8 +409,10 @@
 		(void) probe_for_drive (drive);
 		if (drive->present && !hwif->present) {
 			hwif->present = 1;
-			ide_request_region(hwif->io_ports[IDE_DATA_OFFSET],  8, hwif->name);
-			ide_request_region(hwif->io_ports[IDE_CONTROL_OFFSET], 1, hwif->name);
+			if (hwif->chipset != ide_4drives || !hwif->mate->present) {
+				ide_request_region(hwif->io_ports[IDE_DATA_OFFSET],  8, hwif->name);
+				ide_request_region(hwif->io_ports[IDE_CONTROL_OFFSET], 1, hwif->name);
+			}
 		}
 	}
 	if (hwif->reset) {
@@ -446,7 +426,8 @@
 		do {
 			delay_50ms();
 			stat = IN_BYTE(hwif->io_ports[IDE_STATUS_OFFSET]);
-		} while ((stat & BUSY_STAT) && jiffies < timeout);
+		} while ((stat & BUSY_STAT) && 0 < (signed long)(timeout - jiffies));
+
 	}
 	restore_flags(flags);
 	for (unit = 0; unit < MAX_DRIVES; ++unit) {
@@ -521,13 +502,11 @@
 				save_match(hwif, h, &match);
 			}
 			if (hwif->serialized) {
-				ide_hwif_t *mate = &ide_hwifs[hwif->index^1];
-				if (index == mate->index || h->irq == mate->irq)
+				if (hwif->mate && hwif->mate->irq == h->irq)
 					save_match(hwif, h, &match);
 			}
 			if (h->serialized) {
-				ide_hwif_t *mate = &ide_hwifs[h->index^1];
-				if (hwif->irq == mate->irq)
+				if (h->mate && hwif->irq == h->mate->irq)
 					save_match(hwif, h, &match);
 			}
 		}
@@ -603,7 +582,7 @@
 {
 	struct gendisk *gd, **gdp;
 	unsigned int unit, units, minors;
-	int *bs;
+	int *bs, *max_sect;
 
 	/* figure out maximum drive number on the interface */
 	for (units = MAX_DRIVES; units > 0; --units) {
@@ -615,13 +594,17 @@
 	gd->sizes = kmalloc (minors * sizeof(int), GFP_KERNEL);
 	gd->part  = kmalloc (minors * sizeof(struct hd_struct), GFP_KERNEL);
 	bs        = kmalloc (minors*sizeof(int), GFP_KERNEL);
+	max_sect  = kmalloc (minors*sizeof(int), GFP_KERNEL);
 
 	memset(gd->part, 0, minors * sizeof(struct hd_struct));
 
 	/* cdroms and msdos f/s are examples of non-1024 blocksizes */
 	blksize_size[hwif->major] = bs;
-	for (unit = 0; unit < minors; ++unit)
+	max_sectors[hwif->major] = max_sect;
+	for (unit = 0; unit < minors; ++unit) {
 		*bs++ = BLOCK_SIZE;
+		*max_sect++ = 244;
+	}
 
 	for (unit = 0; unit < units; ++unit)
 		hwif->drives[unit].part = &gd->part[unit << PARTN_BITS];
@@ -640,9 +623,8 @@
 	hwif->gd = *gdp = gd;			/* link onto tail of list */
 }
 
-static int hwif_init (int h)
+static int hwif_init (ide_hwif_t *hwif)
 {
-	ide_hwif_t *hwif = &ide_hwifs[h];
 	void (*rfn)(void);
 	
 	if (!hwif->present)
@@ -692,7 +674,6 @@
 	return hwif->present;
 }
 
-int ideprobe_init (void);
 static ide_module_t ideprobe_module = {
 	IDE_PROBE_MODULE,
 	ideprobe_init,
@@ -713,9 +694,11 @@
 	 * Probe for drives in the usual way.. CMOS/BIOS, then poke at ports
 	 */
 	for (index = 0; index < MAX_HWIFS; ++index)
-		if (probe[index]) probe_hwif (&ide_hwifs[index]);
+		if (probe[index])
+			probe_hwif(&ide_hwifs[index]);
 	for (index = 0; index < MAX_HWIFS; ++index)
-		if (probe[index]) hwif_init (index);
+		if (probe[index])
+			hwif_init(&ide_hwifs[index]);
 	ide_register_module(&ideprobe_module);
 	MOD_DEC_USE_COUNT;
 	return 0;
diff -u --recursive --new-file v2.1.72/linux/drivers/block/ide-proc.c linux/drivers/block/ide-proc.c
--- v2.1.72/linux/drivers/block/ide-proc.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/block/ide-proc.c	Wed Dec 17 11:11:51 1997
@@ -0,0 +1,505 @@
+/*
+ *  linux/drivers/block/proc_ide.c	Version 1.01	December 12, 1997
+ *
+ *  Copyright (C) 1997-1998	Mark Lord
+ */
+
+/*
+ * This is the /proc/ide/ filesystem implementation.
+ *
+ * The major reason this exists is to provide sufficient access
+ * to driver and config data, such that user-mode programs can
+ * be developed to handle chipset tuning for most PCI interfaces.
+ * This should provide better utilities, and less kernel bloat.
+ *
+ * The entire pci config space for a PCI interface chipset can be
+ * retrieved by just reading it.  e.g.    "cat /proc/ide3/pci"
+ *
+ * To modify registers, do something like:
+ *   echo "40:88" >/proc/ide/ide3/pci
+ * That expression writes 0x88 to pci config register 0x40
+ * on the chip which controls ide3.  Multiple tuples can be issued,
+ * and the writes will be completed as an atomic set:
+ *   echo "40:88 41:35 42:00 43:00" >/proc/ide/ide3/pci
+ * All numbers must be pairs of ascii hex digits.
+ *
+ * Also useful, "cat /proc/ide0/hda/identify" will issue an IDENTIFY
+ * (or PACKET_IDENTIFY) command to /dev/hda, and then dump out the
+ * returned data as 256 16-bit words.  The "hdparm" utility will
+ * be updated someday soon to use this mechanism.
+ *
+ * Feel free to develop and distribute fancy GUI configuration
+ * utilities for you favorite PCI chipsets.  I'll be working on
+ * one for the Promise 20246 someday soon.  -ml
+ *
+ */
+
+#include <linux/config.h>
+#include <asm/uaccess.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/proc_fs.h>
+#include <linux/stat.h>
+#include <linux/mm.h>
+#include <linux/pci.h>
+#include <linux/bios32.h>
+#include <linux/ctype.h>
+#include "ide.h"
+
+#ifndef MIN
+#define MIN(a,b) (((a) < (b)) ? (a) : (b))
+#endif
+
+/*
+ * Standard exit stuff:
+ */
+#define PROC_IDE_READ_RETURN(page,start,off,count,eof,len) \
+{					\
+	len -= off;			\
+	if (len < count) {		\
+		*eof = 1;		\
+		if (len <= 0)		\
+			return 0;	\
+	} else				\
+		len = count;		\
+	*start = page + off;		\
+	return len;			\
+}
+
+
+#ifdef CONFIG_PCI
+
+static int ide_getxdigit(char c)
+{
+	int digit;
+	if (isdigit(c))
+		digit = c - '0';
+	else if (isxdigit(c))
+		digit = tolower(c) - 'a' + 10;
+	else
+		digit = -1;
+	return digit;
+}
+
+
+static int xx_xx_parse_error (const char *start, unsigned long maxlen)
+{
+	char errbuf[7];
+	int i, len = MIN(6, maxlen);
+	for (i = 0; i < len; ++i) {
+		char c = start[i];
+		if (!c || c == '\n')
+			c = '\0';
+		else if (iscntrl(c))
+			c = '?';
+		errbuf[i] = c;
+	}
+	errbuf[i] = '\0';
+	printk("proc_ide: error: expected 'xx:xx', but got '%s'\n", errbuf);
+	return -EINVAL;
+}
+
+static int proc_ide_write_pci
+	(struct file *file, const char *buffer, unsigned long count, void *data)
+{
+	ide_hwif_t	*hwif = (ide_hwif_t *)data;
+	int		for_real = 0;
+	unsigned long	n, flags;
+	const char	*start;
+
+	if (!suser())
+		return -EACCES;
+	/*
+	 * Skip over leading whitespace
+	 */
+	while (count && isspace(*buffer)) {
+		--count;
+		++buffer;
+	}
+	/*
+	 * Do one full pass to verify all parameters,
+	 * then do another to actually write the pci regs.
+	 */
+	save_flags(flags);
+	do {
+		const char *p = buffer;
+		n = count;
+		if (for_real) {
+			unsigned long timeout = jiffies + (3 * HZ);
+			cli();	/* ensure all PCI writes are done together */
+			while (((ide_hwgroup_t *)(hwif->hwgroup))->active || (hwif->mate && ((ide_hwgroup_t *)(hwif->mate->hwgroup))->active)) {
+				sti();
+				if (0 < (signed long)(timeout - jiffies)) {
+					printk("/proc/ide/%s/pci: channel(s) busy, cannot write\n", hwif->name);
+					return -EBUSY;
+				}
+				cli();
+			}
+		}
+		while (n) {
+			int d1, d2, rc;
+			byte reg, val;
+			start = p;
+#if 0
+			printk("loop(%d): n=%ld, input=%.5s\n", for_real, n, p);
+#endif
+			if (n < 5)
+				goto parse_error;
+			if (0 > (d1 = ide_getxdigit(*p++)) || 0 > (d2 = ide_getxdigit(*p++)))
+				goto parse_error;
+			reg = (d1 << 4) | d2;
+			if (*p++ != ':')
+				goto parse_error;
+			if (0 > (d1 = ide_getxdigit(*p++)) || 0 > (d2 = ide_getxdigit(*p++)))
+				goto parse_error;
+			val = (d1 << 4) | d2;
+			if (n > 5 && !isspace(*p))
+				goto parse_error;
+			n -= 5;
+			while (n && isspace(*p)) {
+				--n;
+				++p;
+			}
+			if (for_real) {
+#if 0
+				printk("proc_ide_write_pci: reg=0x%02x, val=0x%02x\n", reg, val);
+#endif
+				rc = pcibios_write_config_byte(hwif->pci_bus, hwif->pci_fn, reg, val);
+				if (rc) {
+					restore_flags(flags);
+					printk("proc_ide_write_pci: error writing bus %d fn %d reg 0x%02x value 0x%02x\n",
+						hwif->pci_bus, hwif->pci_fn, reg, val);
+					printk("proc_ide_write_pci: %s\n", pcibios_strerror(rc));
+					return -EIO;
+				}
+			}
+		}
+	} while (!for_real++);
+	restore_flags(flags);
+	return count;
+parse_error:
+	restore_flags(flags);
+	return xx_xx_parse_error(start, n);
+}
+
+static int proc_ide_read_pci
+	(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+	ide_hwif_t	*hwif = (ide_hwif_t *)data;
+	char		*out = page;
+	int		len, reg = 0;
+
+	out += sprintf(out, "Bus %d Function %d Vendor %04x Device %04x Channel %d\n",
+		hwif->pci_bus, hwif->pci_fn, hwif->pci_devid.vid, hwif->pci_devid.did, hwif->channel);
+	do {
+		byte val;
+		int rc = pcibios_read_config_byte(hwif->pci_bus, hwif->pci_fn, reg, &val);
+		if (rc) {
+			printk("proc_ide_read_pci: error reading bus %d fn %d reg 0x%02x\n",
+				hwif->pci_bus, hwif->pci_fn, reg);
+			printk("proc_ide_read_pci: %s\n", pcibios_strerror(rc));
+			return -EIO;
+			out += sprintf(out, "??%c", (++reg & 0xf) ? ' ' : '\n');
+		} else
+			out += sprintf(out, "%02x%c", val, (++reg & 0xf) ? ' ' : '\n');
+	} while (reg < 0x100);
+	len = out - page;
+	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
+}
+
+static int proc_ide_read_imodel
+	(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+	ide_hwif_t	*hwif = (ide_hwif_t *) data;
+	int		len;
+	const char	*vids, *dids;
+
+	vids = pci_strvendor(hwif->pci_devid.vid);
+	dids = pci_strdev(hwif->pci_devid.vid, hwif->pci_devid.did);
+	len = sprintf(page,"%s: %s\n", vids ? vids : "(none)", dids ? dids : "(none)");
+	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
+}
+#endif	/* CONFIG_PCI */
+
+static int proc_ide_read_type
+	(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+	ide_hwif_t	*hwif = (ide_hwif_t *) data;
+	int		len;
+	const char	*name;
+
+	switch (hwif->chipset) {
+		case ide_unknown:	name = "(none)";	break;
+		case ide_generic:	name = "generic";	break;
+		case ide_pci:		name = "pci";		break;
+		case ide_cmd640:	name = "cmd640";	break;
+		case ide_dtc2278:	name = "dtc2278";	break;
+		case ide_ali14xx:	name = "ali14xx";	break;
+		case ide_qd6580:	name = "qd6580";	break;
+		case ide_umc8672:	name = "umc8672";	break;
+		case ide_ht6560b:	name = "ht6560b";	break;
+		case ide_pdc4030:	name = "pdc4030";	break;
+		case ide_rz1000:	name = "rz1000";	break;
+		case ide_trm290:	name = "trm290";	break;
+		case ide_4drives:	name = "4drives";	break;
+		default:		name = "(unknown)";	break;
+	}
+	len = sprintf(page, "%s\n", name);
+	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
+}
+
+static int proc_ide_read_mate
+	(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+	ide_hwif_t	*hwif = (ide_hwif_t *) data;
+	int		len;
+
+	len = sprintf(page, "%s\n", hwif->mate->name);
+	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
+}
+
+static int proc_ide_read_channel
+	(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+	ide_hwif_t	*hwif = (ide_hwif_t *) data;
+	int		len;
+
+	page[0] = hwif->channel ? '1' : '0';
+	page[1] = '\n';
+	len = 2;
+	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
+}
+
+static int proc_ide_get_identify (ide_drive_t *drive, byte *buf)
+{
+	struct request rq;
+	byte *end;
+
+	ide_init_drive_cmd(&rq);
+	rq.buffer = buf;
+	*buf++ = (drive->media == ide_disk) ? WIN_IDENTIFY : WIN_PIDENTIFY;
+	*buf++ = 0;
+	*buf++ = 0;
+	*buf++ = 1;
+	end = buf + (SECTOR_WORDS * 4);
+	while (buf != end)
+		*buf++ = 0;	/* pre-zero it, in case identify fails */
+	(void) ide_do_drive_cmd(drive, &rq, ide_wait);
+	return 0;
+}
+
+static int proc_ide_read_identify
+	(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+	ide_drive_t	*drive = (ide_drive_t *)data;
+	int		len = 0, i = 0;
+
+	if (!proc_ide_get_identify(drive, page)) {
+		unsigned short *val = ((unsigned short *)page) + 2;
+		char *out = ((char *)val) + (SECTOR_WORDS * 4);
+		page = out;
+		do {
+			out += sprintf(out, "%04x%c", le16_to_cpu(*val), (++i & 7) ? ' ' : '\n');
+			val += 1;
+		} while (i < (SECTOR_WORDS * 2));
+		len = out - page;
+	}
+	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
+}
+
+static int proc_ide_read_settings
+	(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+	ide_drive_t	*drive = (ide_drive_t *) data;
+	char		*out = page;
+	int		len;
+
+	out += sprintf(out,"multcount    %i\n", drive->mult_count);
+	out += sprintf(out,"io_32bit     %i\n", drive->io_32bit);
+	out += sprintf(out,"unmaskirq    %i\n", drive->unmask);
+	out += sprintf(out,"using_dma    %i\n", drive->using_dma);
+	out += sprintf(out,"nowerr       %i\n", drive->bad_wstat == BAD_R_STAT);
+	out += sprintf(out,"keepsettings %i\n", drive->keep_settings);
+	out += sprintf(out,"nice         %i/%i/%i\n", drive->nice0, drive->nice1, drive->nice2);
+	len = out - page;
+	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
+}
+
+int proc_ide_read_capacity
+	(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+	ide_drive_t	*drive = (ide_drive_t *) data;
+	int		len;
+
+	len = sprintf(page,"%li\n", ((ide_driver_t *)drive->driver)->capacity(drive));
+	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
+}
+
+int proc_ide_read_geometry
+	(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+	ide_drive_t	*drive = (ide_drive_t *) data;
+	char		*out = page;
+	int		len;
+
+	out += sprintf(out,"physical     %hi/%hi/%hi\n", drive->cyl, drive->head, drive->sect);
+	out += sprintf(out,"logical      %hi/%hi/%hi\n", drive->bios_cyl, drive->bios_head, drive->bios_sect);
+	len = out - page;
+	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
+}
+
+static int proc_ide_read_dmodel
+	(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+	ide_drive_t	*drive = (ide_drive_t *) data;
+	struct hd_driveid *id = drive->id;
+	int		len;
+
+	len = sprintf(page, "%.40s\n", (id && id->model[0]) ? (char *)id->model : "(none)");
+	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
+}
+
+static int proc_ide_read_driver
+	(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+	ide_drive_t	*drive = (ide_drive_t *) data;
+	ide_driver_t	*driver = (ide_driver_t *) drive->driver;
+	int		len;
+
+	if (!driver)
+		len = sprintf(page, "(none)\n");
+	else
+		len = sprintf(page, "%s version %s\n", driver->name, driver->version);
+	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
+}
+
+static int proc_ide_read_media
+	(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+	ide_drive_t	*drive = (ide_drive_t *) data;
+	const char	*media;
+	int		len;
+
+	switch (drive->media) {
+		case ide_disk:	media = "disk\n";
+				break;
+		case ide_cdrom:	media = "cdrom\n";
+				break;
+		case ide_tape:	media = "tape\n";
+				break;
+		case ide_floppy:media = "floppy\n";
+				break;
+		default:	media = "UNKNOWN\n";
+				break;
+	}
+	strcpy(page,media);
+	len = strlen(media);
+	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
+}
+
+
+static ide_proc_entry_t generic_drive_entries[] = {
+	{ "capacity", proc_ide_read_capacity, NULL },
+	{ "driver", proc_ide_read_driver, NULL },
+	{ "identify", proc_ide_read_identify, NULL },
+	{ "media", proc_ide_read_media, NULL },
+	{ "model", proc_ide_read_dmodel, NULL },
+	{ "settings", proc_ide_read_settings, NULL },
+	{ NULL, NULL, NULL }
+};
+
+void ide_add_proc_entries(ide_drive_t *drive, ide_proc_entry_t *p)
+{
+	struct proc_dir_entry *ent;
+
+	if (!drive->proc || !p)
+		return;
+	while (p->name != NULL) {
+		ent = create_proc_entry(p->name, 0, drive->proc);
+		if (!ent) return;
+		ent->data = drive;
+		ent->read_proc = p->read_proc;
+		ent->write_proc = p->write_proc;
+		p++;
+	}
+}
+
+void ide_remove_proc_entries(ide_drive_t *drive, ide_proc_entry_t *p)
+{
+	if (!drive->proc || !p)
+		return;
+	while (p->name != NULL) {
+		remove_proc_entry(p->name, drive->proc);
+		p++;
+	}
+}
+
+static void create_proc_ide_drives (ide_hwif_t *hwif, struct proc_dir_entry *parent)
+{
+	int	d;
+
+	for (d = 0; d < MAX_DRIVES; d++) {
+		ide_drive_t *drive = &hwif->drives[d];
+
+		if (!drive->present)
+			continue;
+		drive->proc = create_proc_entry(drive->name, S_IFDIR, parent);
+		if (drive->proc)
+			ide_add_proc_entries(drive, generic_drive_entries);
+	}
+}
+
+static void create_proc_ide_interfaces (struct proc_dir_entry *parent)
+{
+	int	h;
+	struct proc_dir_entry *hwif_ent, *ent;
+
+	for (h = 0; h < MAX_HWIFS; h++) {
+		ide_hwif_t *hwif = &ide_hwifs[h];
+
+		if (!hwif->present)
+			continue;
+		hwif_ent = create_proc_entry(hwif->name, S_IFDIR, parent);
+		if (!hwif_ent) return;
+#ifdef CONFIG_PCI
+		if (!IDE_PCI_DEVID_EQ(hwif->pci_devid, IDE_PCI_DEVID_NULL)) {
+			ent = create_proc_entry("pci", 0, hwif_ent);
+			if (!ent) return;
+			ent->data = hwif;
+			ent->read_proc  = proc_ide_read_pci;
+			ent->write_proc = proc_ide_write_pci;;
+
+			ent = create_proc_entry("model", 0, hwif_ent);
+			if (!ent) return;
+			ent->data = hwif;
+			ent->read_proc  = proc_ide_read_imodel;
+		}
+#endif	/* CONFIG_PCI */
+		ent = create_proc_entry("channel", 0, hwif_ent);
+		if (!ent) return;
+		ent->data = hwif;
+		ent->read_proc  = proc_ide_read_channel;
+
+		if (hwif->mate && hwif->mate->present) {
+			ent = create_proc_entry("mate", 0, hwif_ent);
+			if (!ent) return;
+			ent->data = hwif;
+			ent->read_proc  = proc_ide_read_mate;
+		}
+
+		ent = create_proc_entry("type", 0, hwif_ent);
+		if (!ent) return;
+		ent->data = hwif;
+		ent->read_proc  = proc_ide_read_type;
+
+		create_proc_ide_drives(hwif, hwif_ent);
+	}
+}
+
+void proc_ide_init(void)
+{
+	struct proc_dir_entry *ent;
+	ent = create_proc_entry("ide", S_IFDIR, 0);
+	if (!ent) return;
+	create_proc_ide_interfaces(ent);
+}
diff -u --recursive --new-file v2.1.72/linux/drivers/block/ide-tape.c linux/drivers/block/ide-tape.c
--- v2.1.72/linux/drivers/block/ide-tape.c	Mon Dec  1 12:04:12 1997
+++ linux/drivers/block/ide-tape.c	Wed Dec 17 11:11:16 1997
@@ -1,5 +1,5 @@
 /*
- * linux/drivers/block/ide-tape.c	Version 1.11 - BETA	Dec   2, 1996
+ * linux/drivers/block/ide-tape.c	Version 1.12		Dec   7, 1997
  *
  * Copyright (C) 1995, 1996 Gadi Oxman <gadio@netvision.net.il>
  *
@@ -206,6 +206,11 @@
  *                       Use ide_stall_queue() for DSC overlap.
  *                       Use the maximum speed rather than the current speed
  *                        to compute the request service time.
+ * Ver 1.12  Dec  7 97   Fix random memory overwriting and/or last block data
+ *                        corruption, which could occur if the total number
+ *                        of bytes written to the tape was not an integral
+ *                        number of tape blocks.
+ *                       Add support for INTERRUPT DRQ devices.
  *
  * Here are some words from the first releases of hd.c, which are quoted
  * in ide.c and apply here as well:
@@ -315,6 +320,8 @@
  *		sharing a (fast) ATA-2 disk with any (slow) new ATAPI device.
  */
 
+#define IDETAPE_VERSION "1.12"
+
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/types.h>
@@ -323,12 +330,9 @@
 #include <linux/delay.h>
 #include <linux/timer.h>
 #include <linux/mm.h>
-#include <linux/ioport.h>
 #include <linux/interrupt.h>
 #include <linux/major.h>
-#include <linux/blkdev.h>
 #include <linux/errno.h>
-#include <linux/hdreg.h>
 #include <linux/genhd.h>
 #include <linux/malloc.h>
 
@@ -692,6 +696,7 @@
 #define IDETAPE_PIPELINE_ERROR		3	/* Error detected in a pipeline stage */
 #define IDETAPE_DETECT_BS		4	/* Attempt to auto-detect the current user block size */
 #define IDETAPE_FILEMARK		5	/* Currently on a filemark */
+#define IDETAPE_DRQ_INTERRUPT		6	/* DRQ interrupt device */
 
 /*
  *	Supported ATAPI tape drives packet commands
@@ -1152,11 +1157,6 @@
  */
 static void idetape_queue_pc_head (ide_drive_t *drive,idetape_pc_t *pc,struct request *rq)
 {
-	unsigned int major = HWIF(drive)->major;
-	struct blk_dev_struct *bdev = &blk_dev[major];
-
-	bdev->current_request=HWGROUP (drive)->rq;		/* Since we may have taken it out */
-
 	ide_init_drive_cmd (rq);
 	rq->buffer = (char *) pc;
 	rq->cmd = IDETAPE_PC_RQ1;
@@ -1542,16 +1542,12 @@
 	ide_drive_t *drive = hwgroup->drive;
 	struct request *rq = hwgroup->rq;
 	idetape_tape_t *tape = drive->driver_data;
-	unsigned int major = HWIF(drive)->major;
-	struct blk_dev_struct *bdev = &blk_dev[major];
 	int error;
 
 #if IDETAPE_DEBUG_LOG
 	printk (KERN_INFO "Reached idetape_end_request\n");
 #endif /* IDETAPE_DEBUG_LOG */
 
-	bdev->current_request=rq;			/* Since we may have taken it out */
-
 	switch (uptodate) {
 		case 0:	error = IDETAPE_ERROR_GENERAL; break;
 		case 1: error = 0; break;
@@ -1723,18 +1719,23 @@
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
 	if (test_bit (PC_DMA_IN_PROGRESS, &pc->flags)) {
-		if (HWIF(drive)->dmaproc(ide_dma_status_bad, drive)) {
-			set_bit (PC_DMA_ERROR, &pc->flags);
+		if (HWIF(drive)->dmaproc(ide_dma_end, drive)) {
 			/*
-			 *	We will currently correct the following in
-			 *	idetape_analyze_error.
+			 * A DMA error is sometimes expected. For example,
+			 * if the tape is crossing a filemark during a
+			 * READ command, it will issue an irq and position
+			 * itself before the filemark, so that only a partial
+			 * data transfer will occur (which causes the DMA
+			 * error). In that case, we will later ask the tape
+			 * how much bytes of the original request were
+			 * actually transferred (we can't receive that
+			 * information from the DMA engine on most chipsets).
 			 */
-			pc->actually_transferred=HWIF(drive)->dmaproc(ide_dma_transferred, drive);
+			set_bit (PC_DMA_ERROR, &pc->flags);
 		} else {
 			pc->actually_transferred=pc->request_transfer;
 			idetape_update_buffers (pc);
 		}
-		(void) (HWIF(drive)->dmaproc(ide_dma_abort, drive));	/* End DMA */
 #if IDETAPE_DEBUG_LOG
 		printk (KERN_INFO "ide-tape: DMA finished\n");
 #endif /* IDETAPE_DEBUG_LOG */
@@ -1780,7 +1781,7 @@
 	if (test_and_clear_bit (PC_DMA_IN_PROGRESS, &pc->flags)) {
 		printk (KERN_ERR "ide-tape: The tape wants to issue more interrupts in DMA mode\n");
 		printk (KERN_ERR "ide-tape: DMA disabled, reverting to PIO\n");
-		HWIF(drive)->dmaproc(ide_dma_off, drive);
+		(void) HWIF(drive)->dmaproc(ide_dma_off, drive);
 		ide_do_reset (drive);
 		return;
 	}
@@ -1873,11 +1874,31 @@
  *		we will handle the next request.
  *
  */
+
+static void idetape_transfer_pc(ide_drive_t *drive)
+{
+	idetape_tape_t *tape = drive->driver_data;
+	idetape_pc_t *pc = tape->pc;
+	idetape_ireason_reg_t ireason;
+
+	if (ide_wait_stat (drive,DRQ_STAT,BUSY_STAT,WAIT_READY)) {
+		printk (KERN_ERR "ide-tape: Strange, packet command initiated yet DRQ isn't asserted\n");
+		return;
+	}
+	ireason.all=IN_BYTE (IDE_IREASON_REG);
+	if (!ireason.b.cod || ireason.b.io) {
+		printk (KERN_ERR "ide-tape: (IO,CoD) != (0,1) while issuing a packet command\n");
+		ide_do_reset (drive);
+		return;
+	}
+	ide_set_handler(drive, &idetape_pc_intr, WAIT_CMD);	/* Set the interrupt routine */
+	atapi_output_bytes (drive,pc->c,12);			/* Send the actual packet */
+}
+
 static void idetape_issue_packet_command (ide_drive_t *drive, idetape_pc_t *pc)
 {
 	idetape_tape_t *tape = drive->driver_data;
 	idetape_bcount_reg_t bcount;
-	idetape_ireason_reg_t ireason;
 	int dma_ok=0;
 
 #if IDETAPE_DEBUG_BUGS
@@ -1918,7 +1939,7 @@
 #ifdef CONFIG_BLK_DEV_IDEDMA
 	if (test_and_clear_bit (PC_DMA_ERROR, &pc->flags)) {
 		printk (KERN_WARNING "ide-tape: DMA disabled, reverting to PIO\n");
-		HWIF(drive)->dmaproc(ide_dma_off, drive);
+		(void) HWIF(drive)->dmaproc(ide_dma_off, drive);
 	}
 	if (test_bit (PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma)
 		dma_ok=!HWIF(drive)->dmaproc(test_bit (PC_WRITING, &pc->flags) ? ide_dma_write : ide_dma_read, drive);
@@ -1929,35 +1950,19 @@
 	OUT_BYTE (bcount.b.high,IDE_BCOUNTH_REG);
 	OUT_BYTE (bcount.b.low,IDE_BCOUNTL_REG);
 	OUT_BYTE (drive->select.all,IDE_SELECT_REG);
-
-	ide_set_handler (drive, &idetape_pc_intr, WAIT_CMD);		/* Set the interrupt routine */
-	OUT_BYTE (WIN_PACKETCMD,IDE_COMMAND_REG);			/* Issue the packet command */
-
-	if (ide_wait_stat (drive,DRQ_STAT,BUSY_STAT,WAIT_READY)) { 	/* Wait for DRQ to be ready - Assuming Accelerated DRQ */
-		/*
-		 *	We currently only support tape drives which report
-		 *	accelerated DRQ assertion. For this case, specs
-		 *	allow up to 50us. We really shouldn't get here.
-		 *
-		 *	??? Still needs to think what to do if we reach
-		 *	here anyway.
-		 */
-		printk (KERN_ERR "ide-tape: Strange, packet command initiated yet DRQ isn't asserted\n");
-		return;
-	}
-	ireason.all=IN_BYTE (IDE_IREASON_REG);
-	if (!ireason.b.cod || ireason.b.io) {
-		printk (KERN_ERR "ide-tape: (IO,CoD) != (0,1) while issuing a packet command\n");
-		ide_do_reset (drive);
-		return;
-	}
-	atapi_output_bytes (drive,pc->c,12);			/* Send the actual packet */
 #ifdef CONFIG_BLK_DEV_IDEDMA
 	if (dma_ok) {						/* Begin DMA, if necessary */
 		set_bit (PC_DMA_IN_PROGRESS, &pc->flags);
 		(void) (HWIF(drive)->dmaproc(ide_dma_begin, drive));
 	}
 #endif /* CONFIG_BLK_DEV_IDEDMA */
+	if (test_bit(IDETAPE_DRQ_INTERRUPT, &tape->flags)) {
+		ide_set_handler(drive, &idetape_transfer_pc, WAIT_CMD);
+		OUT_BYTE(WIN_PACKETCMD, IDE_COMMAND_REG);
+	} else {
+		OUT_BYTE(WIN_PACKETCMD, IDE_COMMAND_REG);
+		idetape_transfer_pc(drive);
+	}
 }
 
 static void idetape_media_access_finished (ide_drive_t *drive)
@@ -2179,7 +2184,6 @@
 {
 	idetape_tape_t *tape = drive->driver_data;
 	idetape_pc_t *pc;
-	struct blk_dev_struct *bdev = &blk_dev[HWIF(drive)->major];
 	struct request *postponed_rq = tape->postponed_rq;
 	idetape_status_reg_t status;
 
@@ -2198,32 +2202,6 @@
 	}
 
 	/*
-	 *	This is an important point. We will try to remove our request
-	 *	from the block device request queue while we service the
-	 *	request. Note that the request must be returned to
-	 *	bdev->current_request before the next call to
-	 *	ide_end_drive_cmd or ide_do_drive_cmd to conform with the
-	 *	normal behavior of the IDE driver, which leaves the active
-	 *	request in bdev->current_request during I/O.
-	 *
-	 *	This will eliminate fragmentation of disk/cdrom requests
-	 *	around a tape request, now that we are using ide_next to
-	 *	insert pending pipeline requests, since we have only one
-	 *	ide-tape.c data request in the device request queue, and
-	 *	thus once removed, ll_rw_blk.c will only see requests from
-	 *	the other device.
-	 *
-	 *	The potential fragmentation inefficiency was pointed to me
-	 *	by Mark Lord.
-	 *
-	 *	Uhuh.. the following "fix" is actually not entirely correct.
-	 *	Some day we should probably move to a per device request
-	 *	queue, rather than per interface.
-	 */
-	if (rq->next != NULL && rq->rq_dev != rq->next->rq_dev)
-		bdev->current_request=rq->next;
-
-	/*
 	 *	Retry a failed packet command
 	 */
 	if (tape->failed_pc != NULL && tape->pc->c[0] == IDETAPE_REQUEST_SENSE_CMD) {
@@ -2612,8 +2590,8 @@
 		if (tape->merge_stage_size % tape->tape_block_size) {
 			blocks++;
 			i = tape->tape_block_size - tape->merge_stage_size % tape->tape_block_size;
-			memset (tape->merge_stage->bh->b_data + tape->merge_stage->bh->b_count, 0, i);
-			tape->merge_stage->bh->b_count += i;
+			memset (tape->bh->b_data + tape->bh->b_count, 0, i);
+			tape->bh->b_count += i;
 		}
 		(void) idetape_add_chrdev_write_request (drive, blocks);
 		tape->merge_stage_size = 0;
@@ -3378,9 +3356,9 @@
 		case 1: printk (KERN_INFO "16 bytes\n");break;
 		default: printk (KERN_INFO "Reserved\n");break;
 	}
-	printk (KERN_INFO "Model: %s\n",id->model);
-	printk (KERN_INFO "Firmware Revision: %s\n",id->fw_rev);
-	printk (KERN_INFO "Serial Number: %s\n",id->serial_no);
+	printk (KERN_INFO "Model: %.40s\n",id->model);
+	printk (KERN_INFO "Firmware Revision: %.8s\n",id->fw_rev);
+	printk (KERN_INFO "Serial Number: %.20s\n",id->serial_no);
 	printk (KERN_INFO "Write buffer size: %d bytes\n",id->buf_size*512);
 	printk (KERN_INFO "DMA: %s",id->capability & 0x01 ? "Yes\n":"No\n");
 	printk (KERN_INFO "LBA: %s",id->capability & 0x02 ? "Yes\n":"No\n");
@@ -3532,6 +3510,7 @@
 	ide_hwif_t *hwif = HWIF(drive);
 	unsigned long t1, tmid, tn, t;
 	u16 speed;
+	struct idetape_id_gcw gcw;
 
 	drive->driver_data = tape;
 	drive->ready_stat = 0;			/* An ATAPI device ignores DRDY */
@@ -3543,6 +3522,9 @@
 	tape->chrdev_direction = idetape_direction_none;
 	tape->pc = tape->pc_stack;
 	tape->max_stages = IDETAPE_MIN_PIPELINE_STAGES;
+	*((unsigned short *) &gcw) = drive->id->config;
+	if (gcw.drq_type == 1)
+		set_bit(IDETAPE_DRQ_INTERRUPT, &tape->flags);
 
 	idetape_get_mode_sense_results (drive);
 
@@ -3635,6 +3617,8 @@
  *	IDE subdriver functions, registered with ide.c
  */
 static ide_driver_t idetape_driver = {
+	"ide-tape",		/* name */
+	IDETAPE_VERSION,	/* version */
 	ide_tape,		/* media */
 	1,			/* busy */
 	1,			/* supports_dma */
@@ -3648,7 +3632,8 @@
 	NULL,			/* media_change */
 	idetape_pre_reset,	/* pre_reset */
 	NULL,			/* capacity */
-	NULL			/* special */
+	NULL,			/* special */
+	NULL			/* proc */
 };
 
 /*
diff -u --recursive --new-file v2.1.72/linux/drivers/block/ide.c linux/drivers/block/ide.c
--- v2.1.72/linux/drivers/block/ide.c	Thu Dec  4 14:53:54 1997
+++ linux/drivers/block/ide.c	Wed Dec 17 11:11:16 1997
@@ -1,5 +1,5 @@
 /*
- *  linux/drivers/block/ide.c	Version 6.05  November 30, 1997
+ *  linux/drivers/block/ide.c	Version 6.11  December 5, 1997
  *
  *  Copyright (C) 1994-1998  Linus Torvalds & authors (see below)
  */
@@ -95,6 +95,9 @@
  *			added support for BIOS-enabled UltraDMA
  *			rename all "promise" things to "pdc4030"
  *			fix EZ-DRIVE handling on small disks
+ * Version 6.11		fix probe error in ide_scan_devices()
+ *			fix ancient "jiffies" polling bugs
+ *			mask all hwgroup interrupts on each irq entry
  *
  *  Some additional driver compile-time options are in ide.h
  *
@@ -111,18 +114,14 @@
 #include <linux/kernel.h>
 #include <linux/timer.h>
 #include <linux/mm.h>
-#include <linux/ioport.h>
 #include <linux/interrupt.h>
 #include <linux/major.h>
-#include <linux/blkdev.h>
 #include <linux/errno.h>
-#include <linux/hdreg.h>
 #include <linux/genhd.h>
 #include <linux/malloc.h>
 #include <linux/bios32.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
-#include <linux/init.h>
 
 #include <asm/byteorder.h>
 #include <asm/irq.h>
@@ -312,11 +311,12 @@
 	if (io_32bit) {
 #if SUPPORT_VLB_SYNC
 		if (io_32bit & 2) {
+			unsigned long flags;
+			save_flags(flags);
 			cli();
 			do_vlb_sync(IDE_NSECTOR_REG);
 			insl(IDE_DATA_REG, buffer, wcount);
-			if (drive->unmask)
-				sti();
+			restore_flags(flags);
 		} else
 #endif /* SUPPORT_VLB_SYNC */
 			insl(IDE_DATA_REG, buffer, wcount);
@@ -344,11 +344,12 @@
 	if (io_32bit) {
 #if SUPPORT_VLB_SYNC
 		if (io_32bit & 2) {
+			unsigned long flags;
+			save_flags(flags);
 			cli();
 			do_vlb_sync(IDE_NSECTOR_REG);
 			outsl(IDE_DATA_REG, buffer, wcount);
-			if (drive->unmask)
-				sti();
+			restore_flags(flags);
 		} else
 #endif /* SUPPORT_VLB_SYNC */
 			outsl(IDE_DATA_REG, buffer, wcount);
@@ -469,13 +470,13 @@
 	ide_hwgroup_t *hwgroup = HWGROUP(drive);
 	byte stat;
 
-	OUT_BYTE (drive->select.all, IDE_SELECT_REG);
+	SELECT_DRIVE(HWIF(drive),drive);
 	udelay (10);
 
 	if (OK_STAT(stat=GET_STAT(), 0, BUSY_STAT)) {
 		printk("%s: ATAPI reset complete\n", drive->name);
 	} else {
-		if (jiffies < hwgroup->poll_timeout) {
+		if (0 < (signed long)(hwgroup->poll_timeout - jiffies)) {
 			ide_set_handler (drive, &atapi_reset_pollfunc, HZ/20);
 			return;	/* continue polling */
 		}
@@ -500,7 +501,7 @@
 	byte tmp;
 
 	if (!OK_STAT(tmp=GET_STAT(), 0, BUSY_STAT)) {
-		if (jiffies < hwgroup->poll_timeout) {
+		if (0 < (signed long)(hwgroup->poll_timeout - jiffies)) {
 			ide_set_handler (drive, &reset_pollfunc, HZ/20);
 			return;	/* continue polling */
 		}
@@ -542,7 +543,7 @@
 		drive->unmask = 0;
 		drive->io_32bit = 0;
 		if (drive->using_dma)
-			HWIF(drive)->dmaproc(ide_dma_off, drive);
+			(void) HWIF(drive)->dmaproc(ide_dma_off, drive);
 	}
 	if (drive->driver != NULL)
 		DRIVER(drive)->pre_reset(drive);
@@ -576,7 +577,7 @@
 	/* For an ATAPI device, first try an ATAPI SRST. */
 	if (drive->media != ide_disk && !do_not_try_atapi) {
 		pre_reset(drive);
-		OUT_BYTE (drive->select.all, IDE_SELECT_REG);
+		SELECT_DRIVE(hwif,drive);
 		udelay (20);
 		OUT_BYTE (WIN_SRST, IDE_COMMAND_REG);
 		hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
@@ -808,7 +809,7 @@
 {
 	struct request *rq = HWGROUP(drive)->rq;
 	byte *args = (byte *) rq->buffer;
-	byte stat = GET_STAT();
+	byte test, stat = GET_STAT();
 
 	ide_sti();
 	if ((stat & DRQ_STAT) && args && args[3]) {
@@ -818,7 +819,10 @@
 		drive->io_32bit = io_32bit;
 		stat = GET_STAT();
 	}
-	if (OK_STAT(stat,READY_STAT,BAD_STAT))
+	test = stat;
+	if (drive->media == ide_cdrom)
+		test = stat &~BUSY_STAT;
+	if (OK_STAT(test,READY_STAT,BAD_STAT))
 		ide_end_drive_cmd (drive, stat, GET_ERR());
 	else
 		ide_error(drive, "drive_cmd", stat); /* calls ide_end_drive_cmd */
@@ -870,7 +874,7 @@
 		ide_sti();
 		timeout += jiffies;
 		while ((stat = GET_STAT()) & BUSY_STAT) {
-			if (jiffies > timeout) {
+			if (0 < (signed long)(jiffies - timeout)) {
 				restore_flags(flags);
 				ide_error(drive, "status timeout", stat);
 				return 1;
@@ -1007,7 +1011,7 @@
 	do {
 		if (!drive->queue)
 			continue;
-		if (drive->sleep && drive->sleep > jiffies)
+		if (drive->sleep && 0 < (signed long)(drive->sleep - jiffies))
 			continue;
 		if (!best) {
 			best = drive;
@@ -1019,7 +1023,7 @@
 			best = drive;
 	} while ((drive = drive->next) != hwgroup->drive);
 	if (best != hwgroup->drive && best && best->service_time > WAIT_MIN_SLEEP && !best->sleep && best->nice1) {
-		long t = (signed) (WAKEUP(best) - jiffies);
+		long t = (signed) (WAKEUP(best) - jiffies);	/* BUGGY? */
 		if (t >= WAIT_MIN_SLEEP) {
 			/*
 			 * We *may* have some time to spare, but first let's see if
@@ -1029,7 +1033,7 @@
 			do {
 				if (drive->sleep)	/* this drive tried to be nice to us */
 					continue;
-				if (WAKEUP(drive) > jiffies - best->service_time && WAKEUP(drive) < jiffies + t) {
+				if (WAKEUP(drive) > (jiffies - best->service_time) && WAKEUP(drive) < (jiffies + t)) {  /* BUGGY? */
 					ide_stall_queue(best, IDE_MIN(t, 10 * WAIT_MIN_SLEEP));
 					goto repeat;
 				}
@@ -1057,7 +1061,7 @@
 			sleep = drive->sleep;
 	} while ((drive = drive->next) != hwgroup->drive);
 	if (sleep) {
-		if (sleep < jiffies + WAIT_MIN_SLEEP)
+		if (0 < (signed long)(jiffies + WAIT_MIN_SLEEP - sleep)) 
 			sleep = jiffies + WAIT_MIN_SLEEP;
 		hwgroup->timer.expires = sleep;
 		add_timer(&hwgroup->timer);
@@ -1189,7 +1193,7 @@
 			handler(drive);
 		else {				/* abort the operation */
 			if (hwgroup->hwif->dmaproc)
-				(void) hwgroup->hwif->dmaproc (ide_dma_abort, drive);
+				(void) hwgroup->hwif->dmaproc (ide_dma_end, drive);
 			ide_error(drive, "irq timeout", GET_STAT());
 		}
 		cli();
@@ -1229,7 +1233,6 @@
 static void unexpected_intr (int irq, ide_hwgroup_t *hwgroup)
 {
 	byte stat;
-	unsigned int unit;
 	ide_hwif_t *hwif = hwgroup->hwif;
 
 	/*
@@ -1237,27 +1240,18 @@
 	 */
 	do {
 		if (hwif->irq == irq) {
-			for (unit = 0; unit < MAX_DRIVES; ++unit) {
-				ide_drive_t *drive = &hwif->drives[unit];
-				if (!drive->present)
-					continue;
-				SELECT_DRIVE(hwif,drive);
-				udelay(100);  /* Ugly, but wait_stat() may not be safe here */
-				if (!OK_STAT(stat=GET_STAT(), drive->ready_stat, BAD_STAT)) {
-					/* Try to not flood the console with msgs */
-					static unsigned long last_msgtime = 0;
-					if ((last_msgtime + (HZ/2)) < jiffies) {
-						last_msgtime = jiffies;
-						(void) ide_dump_status(drive, "unexpected_intr", stat);
-					}
+			stat = IN_BYTE(hwif->io_ports[IDE_STATUS_OFFSET]);
+			if (!OK_STAT(stat, READY_STAT, BAD_STAT)) {
+				/* Try to not flood the console with msgs */
+				static unsigned long last_msgtime = 0;
+				if (0 < (signed long)(jiffies - (last_msgtime + HZ))) {
+					last_msgtime = jiffies;
+					printk("%s%s: unexpected interrupt, status=0x%02x\n",
+					 hwif->name, (hwif->next == hwgroup->hwif) ? "" : "(?)", stat);
 				}
-				if ((stat & DRQ_STAT))
-					try_to_flush_leftover_data(drive);
 			}
 		}
 	} while ((hwif = hwif->next) != hwgroup->hwif);
-	SELECT_DRIVE(hwif,hwgroup->drive); /* Ugh.. probably interrupts current I/O */
-	udelay(100);  /* Ugly, but wait_stat() may not be safe here */
 }
 
 /*
@@ -1266,14 +1260,28 @@
 void ide_intr (int irq, void *dev_id, struct pt_regs *regs)
 {
 	ide_hwgroup_t *hwgroup = dev_id;
+	ide_hwif_t *hwif = hwgroup->hwif;
 	ide_handler_t *handler;
 
-	if (!ide_ack_intr (hwgroup->hwif->io_ports[IDE_STATUS_OFFSET],
-			   hwgroup->hwif->io_ports[IDE_IRQ_OFFSET]))
+	if (!ide_ack_intr(hwif->io_ports[IDE_STATUS_OFFSET], hwif->io_ports[IDE_IRQ_OFFSET]))
 		return;
-
-	if (irq == hwgroup->hwif->irq && (handler = hwgroup->handler) != NULL) {
+	do {
+		if (hwif->irq != irq) disable_irq(hwif->irq);
+	} while ((hwif = hwif->next) != hwgroup->hwif);
+	if (irq == hwif->irq && (handler = hwgroup->handler) != NULL) {
 		ide_drive_t *drive = hwgroup->drive;
+#if 1	/* temporary, remove later -- FIXME */
+		{
+			struct request *rq = hwgroup->rq;
+			if (rq != NULL
+			 &&( MAJOR(rq->rq_dev) != HWIF(drive)->major
+			 || (MINOR(rq->rq_dev) >> PARTN_BITS) != drive->select.b.unit))
+			{
+				printk("ide_intr: got IRQ from wrong device: email mlord@pobox.com!!\n");
+				return;
+			}
+		}
+#endif	/* temporary */
 		hwgroup->handler = NULL;
 		del_timer(&(hwgroup->timer));
 		if (drive->unmask)
@@ -1289,6 +1297,10 @@
 		unexpected_intr(irq, hwgroup);
 	}
 	cli();
+	hwif = hwgroup->hwif;
+	do {
+		if (hwif->irq != irq) enable_irq(hwif->irq);
+	} while ((hwif = hwif->next) != hwgroup->hwif);
 }
 
 /*
@@ -1627,6 +1639,7 @@
 	 */
 	unregister_blkdev(hwif->major, hwif->name);
 	kfree(blksize_size[hwif->major]);
+	kfree(max_sectors[hwif->major]);
 	blk_dev[hwif->major].request_fn = NULL;
 	blk_dev[hwif->major].data = NULL;
 	blk_dev[hwif->major].queue = NULL;
@@ -1686,13 +1699,15 @@
 static int ide_ioctl (struct inode *inode, struct file *file,
 			unsigned int cmd, unsigned long arg)
 {
-	int err;
+	int err, major, minor;
 	ide_drive_t *drive;
 	unsigned long flags;
 	struct request rq;
+	kdev_t dev;
 
-	if (!inode || !(inode->i_rdev))
+	if (!inode || !(dev = inode->i_rdev))
 		return -EINVAL;
+	major = MAJOR(dev); minor = MINOR(dev);
 	if ((drive = get_info_ptr(inode->i_rdev)) == NULL)
 		return -ENODEV;
 	ide_init_drive_cmd (&rq);
@@ -1726,6 +1741,23 @@
 	 	case BLKGETSIZE:   /* Return device size */
 			return put_user(drive->part[MINOR(inode->i_rdev)&PARTN_MASK].nr_sects, (long *) arg);
 
+		case BLKFRASET:
+			if (!suser()) return -EACCES;
+			max_readahead[major][minor] = arg;
+			return 0;
+
+		case BLKFRAGET:
+			return put_user(max_readahead[major][minor], (long *) arg);
+
+		case BLKSECTSET:
+			if (!suser()) return -EACCES;
+			if (!arg || arg > 0xff) return -EINVAL;
+			max_sectors[major][minor] = arg;
+			return 0;
+
+		case BLKSECTGET:
+			return put_user(max_sectors[major][minor], (long *) arg);
+
 		case BLKRRPART: /* Re-read partition tables */
 			if (!suser()) return -EACCES;
 			return ide_revalidate_disk(inode->i_rdev);
@@ -2074,6 +2106,9 @@
  *				This is the default for most chipsets,
  *				except the cmd640.
  * "idex=serialize"	: do not overlap operations on idex and ide(x^1)
+ * "idex=four"		: four drives on idex and ide(x^1) share same ports
+ * "idex=reset"		: reset interface before first use
+ * "idex=nodma"		: do not enable DMA by default on either drive
  *
  * The following are valid ONLY on ide0,
  * and the defaults for the base,ctl ports must not be altered.
@@ -2175,8 +2210,8 @@
 		/*
 		 * Be VERY CAREFUL changing this: note hardcoded indexes below
 		 */
-		const char *ide_words[] = {"noprobe", "serialize", "autotune", "noautotune", "qd6580",
-		 "ht6560b", "cmd640_vlb", "dtc2278", "umc8672", "ali14xx", "dc4030", "four", "reset", NULL};
+		const char *ide_words[] = {"noprobe", "serialize", "autotune", "noautotune", "reset", "nodma", "four",
+			"qd6580", "ht6560b", "cmd640_vlb", "dtc2278", "umc8672", "ali14xx", "dc4030", NULL};
 		hw = s[3] - '0';
 		hwif = &ide_hwifs[hw];
 		i = match_parm(&s[4], ide_words, vals, 3);
@@ -2184,42 +2219,19 @@
 		/*
 		 * Cryptic check to ensure chipset not already set for hwif:
 		 */
-		if (i > 0 || (i <= -5 && i != -13)) {
+		if (i > 0 || i <= -7) {			/* is parameter a chipset name? */
 			if (hwif->chipset != ide_unknown)
-				goto bad_option;
-			if (i <= -5) {
-				if (ide_hwifs[1].chipset != ide_unknown)
-					goto bad_option;
-				/*
-				 * Interface keywords work only for ide0:
-				 */
-				if (hw != 0)
-					goto bad_hwif;
-				printk("\n");
-			}
+				goto bad_option;	/* chipset already specified */
+			if (i != -7 && hw != 0)
+				goto bad_hwif;		/* chipset drivers are for "ide0=" only */
+			if (ide_hwifs[hw^1].chipset != ide_unknown)
+				goto bad_option;	/* chipset for 2nd port already specified */
+			printk("\n");
 		}
 
 		switch (i) {
-			case -13: /* "reset" */
-				hwif->reset = 1;
-				goto done;
-#ifdef CONFIG_BLK_DEV_4DRIVES
-			case -12: /* "four" drives on one set of ports */
-			{
-				ide_hwif_t *mate = &ide_hwifs[hw^1];
-				mate->mate = hwif;
-				hwif->mate = mate;
-				hwif->chipset = mate->chipset = ide_4drives;
-				hwif->serialized = mate->serialized = 1;
-				mate->drives[0].select.all ^= 0x20;
-				mate->drives[1].select.all ^= 0x20;
-				memcpy(mate->io_ports, hwif->io_ports, sizeof(hwif->io_ports));
-				mate->irq = hwif->irq;
-				goto done;
-			}
-#endif /* CONFIG_BLK_DEV_4DRIVES */
 #ifdef CONFIG_BLK_DEV_PDC4030
-			case -11: /* "dc4030" */
+			case -14: /* "dc4030" */
 			{
 				extern void setup_pdc4030(ide_hwif_t *);
 				setup_pdc4030(hwif);
@@ -2227,7 +2239,7 @@
 			}
 #endif /* CONFIG_BLK_DEV_PDC4030 */
 #ifdef CONFIG_BLK_DEV_ALI14XX
-			case -10: /* "ali14xx" */
+			case -13: /* "ali14xx" */
 			{
 				extern void init_ali14xx (void);
 				init_ali14xx();
@@ -2235,7 +2247,7 @@
 			}
 #endif /* CONFIG_BLK_DEV_ALI14XX */
 #ifdef CONFIG_BLK_DEV_UMC8672
-			case -9: /* "umc8672" */
+			case -12: /* "umc8672" */
 			{
 				extern void init_umc8672 (void);
 				init_umc8672();
@@ -2243,7 +2255,7 @@
 			}
 #endif /* CONFIG_BLK_DEV_UMC8672 */
 #ifdef CONFIG_BLK_DEV_DTC2278
-			case -8: /* "dtc2278" */
+			case -11: /* "dtc2278" */
 			{
 				extern void init_dtc2278 (void);
 				init_dtc2278();
@@ -2251,7 +2263,7 @@
 			}
 #endif /* CONFIG_BLK_DEV_DTC2278 */
 #ifdef CONFIG_BLK_DEV_CMD640
-			case -7: /* "cmd640_vlb" */
+			case -10: /* "cmd640_vlb" */
 			{
 				extern int cmd640_vlb; /* flag for cmd640.c */
 				cmd640_vlb = 1;
@@ -2259,7 +2271,7 @@
 			}
 #endif /* CONFIG_BLK_DEV_CMD640 */
 #ifdef CONFIG_BLK_DEV_HT6560B
-			case -6: /* "ht6560b" */
+			case -9: /* "ht6560b" */
 			{
 				extern void init_ht6560b (void);
 				init_ht6560b();
@@ -2267,13 +2279,31 @@
 			}
 #endif /* CONFIG_BLK_DEV_HT6560B */
 #if CONFIG_BLK_DEV_QD6580
-			case -5: /* "qd6580" (has secondary i/f) */
+			case -8: /* "qd6580" */
 			{
 				extern void init_qd6580 (void);
 				init_qd6580();
 				goto done;
 			}
 #endif /* CONFIG_BLK_DEV_QD6580 */
+#ifdef CONFIG_BLK_DEV_4DRIVES
+			case -7: /* "four" drives on one set of ports */
+			{
+				ide_hwif_t *mate = &ide_hwifs[hw^1];
+				mate->drives[0].select.all ^= 0x20;
+				mate->drives[1].select.all ^= 0x20;
+				hwif->chipset = mate->chipset = ide_4drives;
+				mate->irq = hwif->irq;
+				memcpy(mate->io_ports, hwif->io_ports, sizeof(hwif->io_ports));
+				goto do_serialize;
+			}
+#endif /* CONFIG_BLK_DEV_4DRIVES */
+			case -6: /* nodma */
+				hwif->no_autodma = 1;
+				goto done;
+			case -5: /* "reset" */
+				hwif->reset = 1;
+				goto done;
 			case -4: /* "noautotune" */
 				hwif->drives[0].autotune = 2;
 				hwif->drives[1].autotune = 2;
@@ -2284,8 +2314,9 @@
 				goto done;
 			case -2: /* "serialize" */
 			do_serialize:
-				ide_hwifs[hw].serialized = 1;   /* serialize */
-				ide_hwifs[hw^1].serialized = 1; /* with mate */
+				hwif->mate = &ide_hwifs[hw^1];
+				hwif->mate->mate = hwif;
+				hwif->serialized = hwif->mate->serialized = 1;
 				goto done;
 
 			case -1: /* "noprobe" */
@@ -2395,44 +2426,37 @@
 
 /*
  * probe_for_hwifs() finds/initializes "known" IDE interfaces
- *
- * This routine should ideally be using pcibios_find_class() to find all
- * PCI IDE interfaces, but that function causes some systems to "go weird".
  */
 __initfunc(static void probe_for_hwifs (void))
 {
 #ifdef CONFIG_PCI
-	/*
-	 * Find/initialize PCI IDE interfaces
-	 */
 	if (pcibios_present())
 	{
-#ifdef CONFIG_BLK_DEV_IDEDMA
-		{
-			extern void ide_scan_pcibus(void);
-			ide_scan_pcibus();
-		}
-#endif
+#ifdef CONFIG_BLK_DEV_IDEPCI
+		ide_scan_pcibus();
+#else
 #ifdef CONFIG_BLK_DEV_RZ1000
 		{
 			extern void ide_probe_for_rz100x(void);
 			ide_probe_for_rz100x();
 		}
-#endif
+#endif	/* CONFIG_BLK_DEV_RZ1000 */
+#endif	/* CONFIG_BLK_DEV_IDEPCI */
 	}
-#endif /* CONFIG_PCI */
+#endif	/* CONFIG_PCI */
+
 #ifdef CONFIG_BLK_DEV_CMD640
 	{
 		extern void ide_probe_for_cmd640x(void);
 		ide_probe_for_cmd640x();
 	}
-#endif
+#endif	/* CONFIG_BLK_DEV_CMD640 */
 #ifdef CONFIG_BLK_DEV_PDC4030
 	{
 		extern int init_pdc4030(void);
 		(void) init_pdc4030();
 	}
-#endif
+#endif	/* CONFIG_BLK_DEV_PDC4030 */
 }
 
 __initfunc(void ide_init_builtin_drivers (void))
@@ -2460,6 +2484,10 @@
 #endif /* __mc68000__ */
 #endif /* CONFIG_BLK_DEV_IDE */
 
+#ifdef CONFIG_PROC_FS
+	proc_ide_init();
+#endif
+
 	/*
 	 * Attempt to match drivers for the available drives
 	 */
@@ -2552,18 +2580,19 @@
 ide_drive_t *ide_scan_devices (byte media, ide_driver_t *driver, int n)
 {
 	unsigned int unit, index, i;
-	ide_drive_t *drive;
 
 	for (index = 0; index < MAX_HWIFS; ++index)
 		if (ide_hwifs[index].present) goto search;
 	ide_init_module(IDE_PROBE_MODULE);
 search:
 	for (index = 0, i = 0; index < MAX_HWIFS; ++index) {
-		for (unit = 0; unit < MAX_DRIVES; ++unit) {
-			drive = &ide_hwifs[index].drives[unit];
-			if (drive->present && drive->media == media &&
-			    drive->driver == driver && ++i > n)
-				return drive;
+		ide_hwif_t *hwif = &ide_hwifs[index];
+		if (hwif->present) {
+			for (unit = 0; unit < MAX_DRIVES; ++unit) {
+				ide_drive_t *drive = &hwif->drives[unit];
+				if (drive->present && drive->media == media && drive->driver == driver && ++i > n)
+					return drive;
+			}
 		}
 	}
 	return NULL;
@@ -2590,6 +2619,7 @@
 		drive->nice1 = 1;
 	}
 	drive->revalidate = 1;
+	ide_add_proc_entries(drive, driver->proc);
 	return 0;
 }
 
@@ -2603,6 +2633,7 @@
 		restore_flags(flags);
 		return 1;
 	}
+	ide_remove_proc_entries(drive, DRIVER(drive)->proc);
 	drive->driver = NULL;
 	restore_flags(flags);
 	return 0;
@@ -2694,6 +2725,9 @@
 EXPORT_SYMBOL(ide_revalidate_disk);
 EXPORT_SYMBOL(ide_cmd);
 EXPORT_SYMBOL(ide_stall_queue);
+EXPORT_SYMBOL(ide_add_proc_entries);
+EXPORT_SYMBOL(ide_remove_proc_entries);
+EXPORT_SYMBOL(proc_ide_read_geometry);
 
 EXPORT_SYMBOL(ide_register);
 EXPORT_SYMBOL(ide_unregister);
diff -u --recursive --new-file v2.1.72/linux/drivers/block/ide.h linux/drivers/block/ide.h
--- v2.1.72/linux/drivers/block/ide.h	Thu Dec  4 14:53:54 1997
+++ linux/drivers/block/ide.h	Thu Dec 18 11:38:20 1997
@@ -7,10 +7,15 @@
  */
 
 #include <linux/config.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/hdreg.h>
+#include <linux/blkdev.h>
+#include <linux/proc_fs.h>
 #include <asm/ide.h>
 
 /*
- * This is the multiple IDE interface driver, as evolved from hd.c.  
+ * This is the multiple IDE interface driver, as evolved from hd.c.
  * It supports up to four IDE interfaces, on one or more IRQs (usually 14 & 15).
  * There can be up to two drives per interface, as per the ATA-2 spec.
  *
@@ -22,7 +27,7 @@
 
 /******************************************************************************
  * IDE driver configuration options (play with these as desired):
- * 
+ *
  * REALLY_SLOW_IO can be defined in ide.c and ide-cd.c, if necessary
  */
 #undef REALLY_FAST_IO			/* define if ide ports are perfect */
@@ -164,18 +169,13 @@
 #define WAIT_CMD	(10*HZ)	/* 10sec  - maximum wait for an IRQ to happen */
 #define WAIT_MIN_SLEEP	(2*HZ/100)	/* 20msec - minimum sleep time */
 
-#if defined(CONFIG_BLK_DEV_HT6560B) || defined(CONFIG_BLK_DEV_PDC4030) || defined(CONFIG_BLK_DEV_TRM290)
 #define SELECT_DRIVE(hwif,drive)				\
 {								\
 	if (hwif->selectproc)					\
 		hwif->selectproc(drive);			\
-	else							\
-		OUT_BYTE((drive)->select.all, hwif->io_ports[IDE_SELECT_OFFSET]); \
+	OUT_BYTE((drive)->select.all, hwif->io_ports[IDE_SELECT_OFFSET]); \
 }
-#else
-#define SELECT_DRIVE(hwif,drive)  OUT_BYTE((drive)->select.all, hwif->io_ports[IDE_SELECT_OFFSET]);
-#endif	/* CONFIG_BLK_DEV_HT6560B || CONFIG_BLK_DEV_PDC4030 */
-		
+
 /*
  * Now for the data we need to maintain per-drive:  ide_drive_t
  */
@@ -244,7 +244,7 @@
 	byte		bios_sect;	/* BIOS/fdisk/LILO sectors per track */
 	unsigned short	bios_cyl;	/* BIOS/fdisk/LILO number of cyls */
 	unsigned short	cyl;		/* "real" number of cyls */
-	unsigned int	timing_data;	/* for use by tuneproc()'s */
+	unsigned int	drive_data;	/* for use by tuneproc/selectproc as needed */
 	void		  *hwif;	/* actually (ide_hwif_t *) */
 	struct wait_queue *wqueue;	/* used to wait for drive in open() */
 	struct hd_driveid *id;		/* drive model identification info */
@@ -252,6 +252,7 @@
 	char		name[4];	/* drive name, such as "hda" */
 	void 		*driver;	/* (ide_driver_t *) */
 	void		*driver_data;	/* extra driver data */
+	struct proc_dir_entry *proc;	/* /proc/ide/ directory entry */
 	} ide_drive_t;
 
 /*
@@ -265,12 +266,9 @@
  * Returns 1 if DMA read/write could not be started, in which case the caller
  * should either try again later, or revert to PIO for the current request.
  */
-typedef enum {	ide_dma_read = 0,	ide_dma_write = 1,
-		ide_dma_abort = 2,	ide_dma_check = 3,
-		ide_dma_status_bad = 4,	ide_dma_transferred = 5,
-		ide_dma_begin = 6,	ide_dma_on = 7,
-		ide_dma_off = 8,	ide_dma_off_quietly = 9 }
-	ide_dma_action_t;
+typedef enum {	ide_dma_read,	ide_dma_write,	ide_dma_begin,	ide_dma_end,
+		ide_dma_check,	ide_dma_on,	ide_dma_off,	ide_dma_off_quietly
+	} ide_dma_action_t;
 
 typedef int (ide_dmaproc_t)(ide_dma_action_t, ide_drive_t *);
 
@@ -289,7 +287,7 @@
 typedef void (ide_tuneproc_t)(ide_drive_t *, byte);
 
 /*
- * This is used to provide HT6560B & PDC4030 & TRM290 interface support.
+ * This is used to provide support for strange interfaces
  */
 typedef void (ide_selectproc_t) (ide_drive_t *);
 
@@ -301,8 +299,16 @@
 		ide_cmd640,	ide_dtc2278,	ide_ali14xx,
 		ide_qd6580,	ide_umc8672,	ide_ht6560b,
 		ide_pdc4030,	ide_rz1000,	ide_trm290,
-		ide_4drives }
-	hwif_chipset_t;
+		ide_4drives
+	} hwif_chipset_t;
+
+typedef struct ide_pci_devid_s {
+	unsigned short	vid;
+	unsigned short	did;
+} ide_pci_devid_t;
+
+#define IDE_PCI_DEVID_NULL	((ide_pci_devid_t){0,0})
+#define IDE_PCI_DEVID_EQ(a,b)	(a.vid == b.vid && a.did == b.did)
 
 typedef struct hwif_s {
 	struct hwif_s	*next;		/* for linked-list in ide_hwgroup_t */
@@ -311,13 +317,14 @@
 	ide_drive_t	drives[MAX_DRIVES];	/* drive info */
 	struct gendisk	*gd;		/* gendisk structure */
 	ide_tuneproc_t	*tuneproc;	/* routine to tune PIO mode for drives */
-#if defined(CONFIG_BLK_DEV_HT6560B) || defined(CONFIG_BLK_DEV_PDC4030) || defined(CONFIG_BLK_DEV_TRM290)
 	ide_selectproc_t *selectproc;	/* tweaks hardware to select drive */
-#endif
 	ide_dmaproc_t	*dmaproc;	/* dma read/write/abort routine */
 	unsigned long	*dmatable;	/* dma physical region descriptor table */
 	struct hwif_s	*mate;		/* other hwif from same PCI chip */
-	unsigned short	dma_base;	/* base addr for dma ports (triton) */
+	unsigned int	dma_base;	/* base addr for dma ports */
+	unsigned int	config_data;	/* for use by chipset-specific code */
+	unsigned int	select_data;	/* for use by chipset-specific code */
+	struct proc_dir_entry *proc;	/* /proc/ide/ directory entry */
 	int		irq;		/* our irq number */
 	byte		major;		/* our major number */
 	char 		name[6];	/* name of interface, eg. "ide0" */
@@ -327,11 +334,12 @@
 	unsigned	present    : 1;	/* this interface exists */
 	unsigned	serialized : 1;	/* serialized operation with mate hwif */
 	unsigned	sharing_irq: 1;	/* 1 = sharing irq with another hwif */
-#ifdef CONFIG_BLK_DEV_PDC4030
-	unsigned	is_pdc4030_2: 1;/* 2nd i/f on pdc4030 */
-#endif /* CONFIG_BLK_DEV_PDC4030 */
-	unsigned	reset      : 1; /* reset after probe */
-	unsigned	pci_port   : 1; /* for dual-port chips: 0=primary, 1=secondary */
+	unsigned	reset      : 1;	/* reset after probe */
+	unsigned	no_autodma : 1;	/* don't automatically enable DMA at boot */
+	byte		channel;	/* for dual-port chips: 0=primary, 1=secondary */
+	byte		pci_bus;	/* for pci chipsets */
+	byte		pci_fn;		/* for pci chipsets */
+	ide_pci_devid_t	pci_devid;	/* for pci chipsets: {VID,DID} */
 #if (DISK_RECOVERY_TIME > 0)
 	unsigned long	last_time;	/* time when previous rq was done */
 #endif
@@ -354,6 +362,20 @@
 	} ide_hwgroup_t;
 
 /*
+ * /proc/ide interface
+ */
+typedef struct {
+	char *name;
+	read_proc_t *read_proc;
+	write_proc_t *write_proc;
+} ide_proc_entry_t;
+
+void proc_ide_init(void);
+void ide_add_proc_entries(ide_drive_t *drive, ide_proc_entry_t *p);
+void ide_remove_proc_entries(ide_drive_t *drive, ide_proc_entry_t *p);
+read_proc_t proc_ide_read_geometry;
+
+/*
  * Subdrivers support.
  */
 #define IDE_SUBDRIVER_VERSION	1
@@ -370,6 +392,8 @@
 typedef void	(ide_special_proc)(ide_drive_t *);
 
 typedef struct ide_driver_s {
+	const char			*name;
+	const char			*version;
 	byte				media;
 	unsigned busy			: 1;
 	unsigned supports_dma		: 1;
@@ -384,6 +408,7 @@
 	ide_pre_reset_proc		*pre_reset;
 	ide_capacity_proc		*capacity;
 	ide_special_proc		*special;
+	ide_proc_entry_t		*proc;
 	} ide_driver_t;
 
 #define DRIVER(drive)		((ide_driver_t *)((drive)->driver))
@@ -406,7 +431,7 @@
 /*
  * ide_hwifs[] is the master data structure used to keep track
  * of just about everything in ide.c.  Whenever possible, routines
- * should be using pointers to a drive (ide_drive_t *) or 
+ * should be using pointers to a drive (ide_drive_t *) or
  * pointers to a hwif (ide_hwif_t *), rather than indexing this
  * structure directly (the allocation/layout may change!).
  *
@@ -529,7 +554,7 @@
  * If action is ide_next, then the rq is queued immediately after
  * the currently-being-processed-request (if any), and the function
  * returns without waiting for the new rq to be completed.  As above,
- * This is VERY DANGEROUS, and is intended for careful use by the 
+ * This is VERY DANGEROUS, and is intended for careful use by the
  * ATAPI tape/cdrom driver code.
  *
  * If action is ide_end, then the rq is queued at the end of the
@@ -538,7 +563,7 @@
  * use by the ATAPI tape/cdrom driver code.
  */
 int ide_do_drive_cmd (ide_drive_t *drive, struct request *rq, ide_action_t action);
- 
+
 /*
  * Clean up after success/failure of an explicit drive cmd.
  * stat/err are used only when (HWGROUP(drive)->rq->cmd == IDE_DRIVE_CMD).
@@ -613,10 +638,16 @@
 int ide_register_subdriver (ide_drive_t *drive, ide_driver_t *driver, int version);
 int ide_unregister_subdriver (ide_drive_t *drive);
 
+#ifdef CONFIG_BLK_DEV_IDEPCI
+unsigned int ide_find_free_region (unsigned short size) __init;
+void ide_scan_pcibus (void) __init;
+#endif
 #ifdef CONFIG_BLK_DEV_IDEDMA
 int ide_build_dmatable (ide_drive_t *drive);
+void ide_dma_intr  (ide_drive_t *drive);
 int ide_dmaproc (ide_dma_action_t func, ide_drive_t *drive);
-void ide_setup_dma (ide_hwif_t *hwif, unsigned short dmabase, unsigned int num_ports);
+void ide_setup_dma (ide_hwif_t *hwif, unsigned int dmabase, unsigned int num_ports) __init;
+unsigned int ide_get_or_set_dma_base (ide_hwif_t *hwif, int extra, const char *name) __init;
 #endif
 
 #ifdef CONFIG_BLK_DEV_IDE
diff -u --recursive --new-file v2.1.72/linux/drivers/block/ll_rw_blk.c linux/drivers/block/ll_rw_blk.c
--- v2.1.72/linux/drivers/block/ll_rw_blk.c	Tue Dec  2 16:45:18 1997
+++ linux/drivers/block/ll_rw_blk.c	Wed Dec 17 11:11:16 1997
@@ -87,6 +87,18 @@
  */
 int * max_readahead[MAX_BLKDEV] = { NULL, NULL, };
 
+/*
+ * Max number of sectors per request
+ */
+int * max_sectors[MAX_BLKDEV] = { NULL, NULL, };
+
+static inline int get_max_sectors(kdev_t dev)
+{
+	if (!max_sectors[MAJOR(dev)])
+		return 244;	/* 254? */
+	return max_sectors[MAJOR(dev)][MINOR(dev)];
+}
+
 static inline struct request **get_queue(kdev_t dev)
 {
 	int major = MAJOR(dev);
@@ -300,9 +312,7 @@
 	sti();
 }
 
-#define MAX_SECTORS 244
-
-static inline void attempt_merge (struct request *req)
+static inline void attempt_merge (struct request *req, int max_sectors)
 {
 	struct request *next = req->next;
 
@@ -310,7 +320,7 @@
 		return;
 	if (req->sector + req->nr_sectors != next->sector)
 		return;
-	if (next->sem || req->cmd != next->cmd || req->rq_dev != next->rq_dev || req->nr_sectors + next->nr_sectors >= MAX_SECTORS)
+	if (next->sem || req->cmd != next->cmd || req->rq_dev != next->rq_dev || req->nr_sectors + next->nr_sectors > max_sectors)
 		return;
 	req->bhtail->b_reqnext = next->bh;
 	req->bhtail = next->bhtail;
@@ -324,7 +334,7 @@
 {
 	unsigned int sector, count;
 	struct request * req;
-	int rw_ahead, max_req;
+	int rw_ahead, max_req, max_sectors;
 
 	count = bh->b_size >> 9;
 	sector = bh->b_rsector;
@@ -391,6 +401,7 @@
 	/*
 	 * Try to coalesce the new request with old requests
 	 */
+	max_sectors = get_max_sectors(bh->b_rdev);
 	cli();
 	req = *get_queue(bh->b_rdev);
 	if (!req) {
@@ -428,7 +439,7 @@
 				continue;
 			if (req->cmd != rw)
 				continue;
-			if (req->nr_sectors >= MAX_SECTORS)
+			if (req->nr_sectors + count > max_sectors)
 				continue;
 			if (req->rq_dev != bh->b_rdev)
 				continue;
@@ -438,7 +449,7 @@
 				req->bhtail = bh;
 			    	req->nr_sectors += count;
 				/* Can we now merge this req with the next? */
-				attempt_merge(req);
+				attempt_merge(req, max_sectors);
 			/* or to the beginning? */
 			} else if (req->sector - count == sector) {
 			    	bh->b_reqnext = req->bh;
@@ -684,6 +695,7 @@
 	}
 	memset(ro_bits,0,sizeof(ro_bits));
 	memset(max_readahead, 0, sizeof(max_readahead));
+	memset(max_sectors, 0, sizeof(max_sectors));
 #ifdef CONFIG_AMIGA_Z2RAM
 	z2_init();
 #endif
diff -u --recursive --new-file v2.1.72/linux/drivers/block/ns87415.c linux/drivers/block/ns87415.c
--- v2.1.72/linux/drivers/block/ns87415.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/block/ns87415.c	Wed Dec 17 11:11:16 1997
@@ -0,0 +1,228 @@
+/*
+ * linux/drivers/block/ns87415.c	Version 1.00  December 7, 1997
+ *
+ * Copyright (C) 1997-1998  Mark Lord
+ *
+ * Inspired by an earlier effort from David S. Miller (davem@caipfs.rutgers.edu)
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/pci.h>
+#include <linux/bios32.h>
+#include <asm/io.h>
+#include "ide.h"
+
+
+#undef INCLUDE_OBSOLETE_NS87514_STUFF	/* define this if you absolutely *need* the timings stuff */
+
+
+#ifdef INCLUDE_OBSOLETE_NS87514_STUFF
+/*
+ * This part adapted from code from David S. Miller (davem@caipfs.rutgers.edu)
+ * which was in turn adapted from code from Mark Lord.
+ *
+ * Here as a temporary measure only.  Will be removed once /proc/ide/ is working.
+ */
+#include "ide_modes.h"
+
+static void ns87415_program_modes(ide_drive_t *drive, byte active_count, byte recovery_count)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	byte cfg_reg, regval;
+
+	cfg_reg = (0x44 + (8 * HWIF(drive)->channel) + (4 * drive->select.b.unit));
+
+	/* set identical PIO timings for read/write */
+	regval  = (17 - active_count) | ((16 - recovery_count) << 4);
+	pcibios_write_config_byte(hwif->pci_bus, hwif->pci_fn, cfg_reg, regval);
+	pcibios_write_config_byte(hwif->pci_bus, hwif->pci_fn, cfg_reg + 1, regval);
+}
+
+static void set_ide_modes(ide_drive_t *drive, ide_pio_data_t *d, int bus_speed)
+{
+	int setup_time, active_time, cycle_time = d->cycle_time;
+	byte setup_count, active_count, pio_mode = d->pio_mode;
+	byte recovery_count, recovery_count2, cycle_count;
+	int recovery_time, clock_time;
+
+	if(pio_mode > 5)
+		pio_mode = 5;
+
+	setup_time = ide_pio_timings[pio_mode].setup_time;
+	active_time = ide_pio_timings[pio_mode].active_time;
+
+	recovery_time = cycle_time - (setup_time + active_time);
+	clock_time = 1000 / bus_speed;
+
+	cycle_count  = (cycle_time  + clock_time - 1) / clock_time;
+	setup_count  = (setup_time  + clock_time - 1) / clock_time;
+	active_count = (active_time + clock_time - 1) / clock_time;
+
+	if(active_count < 2)
+		active_count = 2;
+
+	recovery_count  = (recovery_time + clock_time - 1) / clock_time;
+	recovery_count2 = cycle_count - (setup_count + active_count);
+
+	if(recovery_count2 > recovery_count)
+		recovery_count = recovery_count2;
+	if(recovery_count < 2)
+		recovery_count = 2;
+	if(recovery_count > 17) {
+		active_count += recovery_count - 17;
+		recovery_count = 17;
+	}
+
+	if(active_count > 16)
+		active_count = 16;
+	if(recovery_count > 16)
+		recovery_count = 16;
+
+	printk("active[%d CLKS] recovery[%d CLKS]\n", active_count, recovery_count);
+
+	ns87415_program_modes(drive, active_count, recovery_count);
+}
+
+/* Configure for best PIO mode. */
+static void ns87415_tuneproc (ide_drive_t *drive, byte mode_wanted)
+{
+	ide_pio_data_t d;
+	int bus_speed = ide_system_bus_speed();
+
+	switch(mode_wanted) {
+	case 6:
+	case 7:
+		/* Changes to Fast-devsel are unsupported. */
+		return;
+
+	case 8:
+	case 9:
+		mode_wanted &= 1;
+		/* XXX set_prefetch_mode(index, mode_wanted); */
+		printk("%s: %sbled NS87415 prefetching...\n", drive->name, mode_wanted ? "en" : "dis");
+		return;
+	};
+
+	(void) ide_get_best_pio_mode(drive, mode_wanted, 5, &d);
+
+	printk("%s: selected NS87415 PIO mode%d (%dns)%s ",
+	       drive->name, d.pio_mode, d.cycle_time,
+	       d.overridden ? " (overriding vendor mode)" : "");
+
+	set_ide_modes(drive, &d, bus_speed);
+}
+#endif	/* INCLUDE_OBSOLETE_NS87514_STUFF */
+
+static unsigned int ns87415_count = 0, ns87415_control[MAX_HWIFS] = {0};
+
+/*
+ * This routine either enables/disables (according to drive->present)
+ * the IRQ associated with the port (HWIF(drive)),
+ * and selects either PIO or DMA handshaking for the next I/O operation.
+ */
+static void ns87415_prepare_drive (ide_drive_t *drive, unsigned int use_dma)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	unsigned int bit, new, *old = (unsigned int *) hwif->select_data;
+	unsigned int flags;
+
+	save_flags(flags);
+	cli();
+
+	new = *old;
+
+	/* adjust IRQ enable bit */
+	bit = 1 << (8 + hwif->channel);
+	new = drive->present ? (new | bit) : (new & ~bit);
+
+	/* select PIO or DMA */
+	bit = 1 << (20 + drive->select.b.unit + (hwif->channel << 1));
+	new = use_dma ? (new | bit) : (new & ~bit);
+
+	if (new != *old) {
+		*old = new;
+		(void) pcibios_write_config_dword(hwif->pci_bus, hwif->pci_fn, 0x40, new);
+	}
+	restore_flags(flags);
+}
+
+static void ns87415_selectproc (ide_drive_t *drive)
+{
+	ns87415_prepare_drive (drive, drive->using_dma);
+}
+
+static int ns87415_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+
+	switch (func) {
+		case ide_dma_end: /* returns 1 on error, 0 otherwise */
+		{
+			byte dma_stat = inb(hwif->dma_base+2);
+			int rc = (dma_stat & 7) != 4;
+			outb(7, hwif->dma_base); /* from errata: stop DMA, clear INTR & ERROR */
+			outb(dma_stat|6, hwif->dma_base+2);	/* clear the INTR & ERROR bits */
+			return rc;	/* verify good DMA status */
+		}
+		case ide_dma_write:
+		case ide_dma_read:
+			ns87415_prepare_drive(drive, 1); /* select DMA xfer */
+			if (!ide_dmaproc(func, drive))	 /* use standard DMA stuff */
+				return 0;
+			ns87415_prepare_drive(drive, 0); /* DMA failed: select PIO xfer */
+			return 1;
+		default:
+			return ide_dmaproc(func, drive); /* use standard DMA stuff */
+	}
+}
+
+__initfunc(void ide_init_ns87415 (ide_hwif_t *hwif))
+{
+	unsigned int ctrl, progif, using_inta;
+
+	/*
+	 * We cannot probe for IRQ: both ports share common IRQ on INTA.
+	 * Also, leave IRQ masked during drive probing, to prevent infinite
+	 * interrupts from a potentially floating INTA..
+	 *
+	 * IRQs get unmasked in selectproc when drive is first used.
+	 */
+	(void) pcibios_read_config_dword(hwif->pci_bus, hwif->pci_fn, 0x40, &ctrl);
+	(void) pcibios_read_config_dword(hwif->pci_bus, hwif->pci_fn, 0x40, &progif);
+	/* is irq in "native" mode? */
+	using_inta = progif & (1 << (hwif->channel << 1));
+	if (!using_inta)
+		using_inta = ctrl & (1 << (4 + hwif->channel));
+	(void) pcibios_write_config_dword(hwif->pci_bus, hwif->pci_fn, 0x40, ctrl);
+	if (hwif->mate) {
+		hwif->select_data = hwif->mate->select_data;
+	} else {
+		hwif->select_data = (unsigned int) &ns87415_control[ns87415_count++];
+		ctrl |= (1 << 8) | (1 << 9);		/* mask both IRQs */
+		if (using_inta)
+			ctrl &= ~(1 << 6);		/* unmask INTA */
+		*((unsigned int *)hwif->select_data) = ctrl;
+		/*
+		 * Set prefetch size to 512 bytes for both ports,
+		 * but don't turn on/off prefetching here.
+		 */
+		pcibios_write_config_byte(hwif->pci_bus, hwif->pci_fn, 0x55, 0xee);
+	}
+	if (!using_inta)
+		hwif->irq = hwif->channel ? 15 : 14;	/* legacy mode */
+	else if (!hwif->irq && hwif->mate && hwif->mate->irq)
+		hwif->irq = hwif->mate->irq;		/* share IRQ with mate */
+
+	hwif->dmaproc = &ns87415_dmaproc;
+	hwif->selectproc = &ns87415_selectproc;
+#ifdef INCLUDE_OBSOLETE_NS87514_STUFF
+	hwif->tuneproc = &ns87415_tuneproc;
+#endif	/* INCLUDE_OBSOLETE_NS87514_STUFF */
+}
diff -u --recursive --new-file v2.1.72/linux/drivers/block/opti621.c linux/drivers/block/opti621.c
--- v2.1.72/linux/drivers/block/opti621.c	Thu Dec  4 14:53:54 1997
+++ linux/drivers/block/opti621.c	Wed Dec 17 11:11:16 1997
@@ -110,7 +110,7 @@
 /* there are stored pio numbers from other calls of opti621_tune_drive */
 
 static void compute_pios(ide_drive_t *drive, byte pio)
-/* Store values into drive->timing_data
+/* Store values into drive->drive_data
  *	second_contr - 0 for primary controller, 1 for secondary
  *	slave_drive - 0 -> pio is for master, 1 -> pio is for slave
  *	pio - PIO mode for selected drive (for other we don't know)
@@ -119,17 +119,17 @@
 	int d;
 	ide_hwif_t *hwif = HWIF(drive);
 
-	drive->timing_data = ide_get_best_pio_mode(drive, pio, OPTI621_MAX_PIO, NULL);
+	drive->drive_data = ide_get_best_pio_mode(drive, pio, OPTI621_MAX_PIO, NULL);
 	for (d = 0; d < 2; ++d) {
 		drive = &hwif->drives[d];
 		if (drive->present) {
-			if (drive->timing_data == PIO_DONT_KNOW)
-				drive->timing_data = ide_get_best_pio_mode(drive, 255, OPTI621_MAX_PIO, NULL);
+			if (drive->drive_data == PIO_DONT_KNOW)
+				drive->drive_data = ide_get_best_pio_mode(drive, 255, OPTI621_MAX_PIO, NULL);
 #ifdef OPTI621_DEBUG
-			printk("%s: Selected PIO mode %d\n", drive->name, drive->timing_data);
+			printk("%s: Selected PIO mode %d\n", drive->name, drive->drive_data);
 #endif
 		} else {
-			drive->timing_data = PIO_NOT_EXIST;
+			drive->drive_data = PIO_NOT_EXIST;
 		}
 	}
 }
@@ -192,7 +192,7 @@
 	  	clks->address_time = cmpt_clk(adr_setup, bus_speed);
 	     	clks->data_time = cmpt_clk(data_pls, bus_speed);
      		clks->recovery_time = cmpt_clk(ide_pio_timings[pio].cycle_time
-     			-adr_setup-data_pls, bus_speed);
+     			- adr_setup-data_pls, bus_speed);
      		if (clks->address_time<1) clks->address_time = 1;
      		if (clks->address_time>4) clks->address_time = 4;
      		if (clks->data_time<1) clks->data_time = 1;
@@ -220,10 +220,10 @@
 	byte cycle1, cycle2, misc;
 	ide_hwif_t *hwif = HWIF(drive);
 
-	/* set drive->timing_data for both drives */
+	/* set drive->drive_data for both drives */
 	compute_pios(drive, pio);
- 	pio1 = hwif->drives[0].timing_data;
- 	pio2 = hwif->drives[1].timing_data;
+ 	pio1 = hwif->drives[0].drive_data;
+ 	pio2 = hwif->drives[1].drive_data;
 
 	compute_clocks(pio1, &first);
 	compute_clocks(pio2, &second);
@@ -274,11 +274,11 @@
 }
 
 /*
- * ide_init_opti621() is Called from idedma.c once for each hwif found at boot.
+ * ide_init_opti621() is called once for each hwif found at boot.
  */
-void ide_init_opti621 (byte bus, byte fn, ide_hwif_t *hwif)
+void ide_init_opti621 (ide_hwif_t *hwif)
 {
-	hwif->drives[0].timing_data = PIO_DONT_KNOW;
-	hwif->drives[1].timing_data = PIO_DONT_KNOW;
+	hwif->drives[0].drive_data = PIO_DONT_KNOW;
+	hwif->drives[1].drive_data = PIO_DONT_KNOW;
 	hwif->tuneproc = &opti621_tune_drive;
 }
diff -u --recursive --new-file v2.1.72/linux/drivers/block/pdc4030.c linux/drivers/block/pdc4030.c
--- v2.1.72/linux/drivers/block/pdc4030.c	Thu Dec  4 14:53:54 1997
+++ linux/drivers/block/pdc4030.c	Wed Dec 17 11:11:16 1997
@@ -72,9 +72,7 @@
 {
 	unsigned int number;
 
-	OUT_BYTE(drive->select.all,IDE_SELECT_REG);
-	udelay(1);	/* paranoia */
-	number = ((HWIF(drive)->is_pdc4030_2)<<1) + drive->select.b.unit;
+	number = (HWIF(drive)->channel << 1) + drive->select.b.unit;
 	OUT_BYTE(number,IDE_FEATURE_REG);
 }
 
@@ -134,7 +132,7 @@
 
 	drive = &hwif->drives[0];
 	second_hwif = &ide_hwifs[hwif->index+1];
-	if(hwif->is_pdc4030_2) /* we've already been found ! */
+	if(hwif->chipset == ide_pdc4030) /* we've already been found ! */
 	    return 1;
 
 	if(IN_BYTE(IDE_NSECTOR_REG) == 0xFF || IN_BYTE(IDE_SECTOR_REG) == 0xFF)
@@ -172,6 +170,7 @@
 	hwif->chipset     = second_hwif->chipset    = ide_pdc4030;
 	hwif->mate        = second_hwif;
 	second_hwif->mate = hwif;
+	second_hwif->channel = 1;
 	hwif->selectproc  = second_hwif->selectproc = &promise_selectproc;
 /* Shift the remaining interfaces down by one */
 	for (i=MAX_HWIFS-1 ; i > hwif->index+1 ; i--) {
@@ -182,7 +181,6 @@
 		h->io_ports[IDE_CONTROL_OFFSET] = (h-1)->io_ports[IDE_CONTROL_OFFSET];
 		h->noprobe = (h-1)->noprobe;
 	}
-	second_hwif->is_pdc4030_2 = 1;
 	ide_init_hwif_ports(second_hwif->io_ports, hwif->io_ports[IDE_DATA_OFFSET], NULL);
 	second_hwif->io_ports[IDE_CONTROL_OFFSET] = hwif->io_ports[IDE_CONTROL_OFFSET];
 	second_hwif->irq = hwif->irq;
diff -u --recursive --new-file v2.1.72/linux/drivers/block/qd6580.c linux/drivers/block/qd6580.c
--- v2.1.72/linux/drivers/block/qd6580.c	Thu Dec  4 14:53:54 1997
+++ linux/drivers/block/qd6580.c	Wed Dec 17 11:11:16 1997
@@ -65,4 +65,5 @@
 	ide_hwifs[0].tuneproc = &tune_qd6580;
 	ide_hwifs[0].mate = &ide_hwifs[1];
 	ide_hwifs[1].mate = &ide_hwifs[0];
+	ide_hwifs[1].channel = 1;
 }
diff -u --recursive --new-file v2.1.72/linux/drivers/block/rz1000.c linux/drivers/block/rz1000.c
--- v2.1.72/linux/drivers/block/rz1000.c	Mon Dec  1 12:04:12 1997
+++ linux/drivers/block/rz1000.c	Wed Dec 17 11:11:51 1997
@@ -1,7 +1,7 @@
 /*
- *  linux/drivers/block/rz1000.c	Version 0.03  Mar 20, 1996
+ *  linux/drivers/block/rz1000.c	Version 0.05  December 8, 1997
  *
- *  Copyright (C) 1995-1996  Linus Torvalds & author (see below)
+ *  Copyright (C) 1995-1998  Linus Torvalds & author (see below)
  */
 
 /*
@@ -9,6 +9,8 @@
  *
  *  This file provides support for disabling the buggy read-ahead
  *  mode of the RZ1000 IDE chipset, commonly used on Intel motherboards.
+ *
+ *  Dunno if this fixes both ports, or only the primary port (?).
  */
 
 #undef REALLY_SLOW_IO		/* most systems can safely undef this */
@@ -26,21 +28,40 @@
 #include <linux/pci.h>
 #include "ide.h"
 
-static void init_rz1000 (byte bus, byte fn, const char *name)
+#ifdef CONFIG_BLK_DEV_IDEPCI
+
+__initfunc(void ide_init_rz1000 (ide_hwif_t *hwif))	/* called from ide-pci.c */
+{
+	unsigned short reg;
+
+	hwif->chipset = ide_rz1000;
+	if (!pcibios_read_config_word (hwif->pci_bus, hwif->pci_fn, 0x40, &reg)
+	 && !pcibios_write_config_word(hwif->pci_bus, hwif->pci_fn, 0x40, reg & 0xdfff))
+	{
+		printk("%s: disabled chipset read-ahead (buggy RZ1000/RZ1001)\n", hwif->name);
+	} else {
+		hwif->serialized = 1;
+		hwif->drives[0].no_unmask = 1;
+		hwif->drives[1].no_unmask = 1;
+		printk("%s: serialized, disabled unmasking (buggy RZ1000/RZ1001)\n", hwif->name);
+	}
+}
+
+#else
+
+__initfunc(static void init_rz1000 (byte bus, byte fn, const char *name))
 {
 	unsigned short reg, h;
 
-	printk("%s: buggy IDE controller: ", name);
 	if (!pcibios_read_config_word (bus, fn, PCI_COMMAND, &reg) && !(reg & 1)) {
-		printk("disabled (BIOS)\n");
+		printk("%s: buggy IDE controller disabled (BIOS)\n", name);
 		return;
 	}
 	if (!pcibios_read_config_word (bus, fn, 0x40, &reg)
 	 && !pcibios_write_config_word(bus, fn, 0x40, reg & 0xdfff))
 	{
-		printk("disabled read-ahead\n");
+		printk("IDE: disabled chipset read-ahead (buggy %s)\n", name);
 	} else {
-		printk("\n");
 		for (h = 0; h < MAX_HWIFS; ++h) {
 			ide_hwif_t *hwif = &ide_hwifs[h];
 			if ((hwif->io_ports[IDE_DATA_OFFSET] == 0x1f0 || hwif->io_ports[IDE_DATA_OFFSET] == 0x170)
@@ -50,13 +71,15 @@
 				hwif->serialized = 1;
 				hwif->drives[0].no_unmask = 1;
 				hwif->drives[1].no_unmask = 1;
-				printk("  %s: serialized, disabled unmasking\n", hwif->name);
+				if (hwif->io_ports[IDE_DATA_OFFSET] == 0x170)
+					hwif->channel = 1;
+				printk("%s: serialized, disabled unmasking (buggy %s)\n", hwif->name, name);
 			}
 		}
 	}
 }
 
-void ide_probe_for_rz100x (void)
+__initfunc(void ide_probe_for_rz100x (void))	/* called from ide.c */
 {
 	byte index, bus, fn;
 
@@ -65,3 +88,5 @@
 	for (index = 0; !pcibios_find_device (PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1001, index, &bus, &fn); ++index)
 		init_rz1000 (bus, fn, "RZ1001");
 }
+
+#endif CONFIG_BLK_DEV_IDEPCI
diff -u --recursive --new-file v2.1.72/linux/drivers/block/trm290.c linux/drivers/block/trm290.c
--- v2.1.72/linux/drivers/block/trm290.c	Thu Dec  4 14:53:54 1997
+++ linux/drivers/block/trm290.c	Wed Dec 17 11:11:16 1997
@@ -1,5 +1,5 @@
 /*
- *  linux/drivers/block/trm290.c	Version 1.00  December 3, 1997
+ *  linux/drivers/block/trm290.c	Version 1.01  December 5, 1997
  *
  *  Copyright (c) 1997-1998  Mark Lord
  *  May be copied or modified under the terms of the GNU General Public License
@@ -34,18 +34,20 @@
  * The configuration registers are addressed in normal I/O port space
  * and are used as follows:
  *
- * 0x3df2 when WRITTEN: chiptest register (byte, write-only)
+ * trm290_base depends on jumper settings, and is probed for by ide-dma.c
+ *
+ * trm290_base+2 when WRITTEN: chiptest register (byte, write-only)
  *	bit7 must always be written as "1"
  *	bits6-2 undefined
  *	bit1 1=legacy_compatible_mode, 0=native_pci_mode
  *	bit0 1=test_mode, 0=normal(default)
  *
- * 0x3df2 when READ: status register (byte, read-only)
+ * trm290_base+2 when READ: status register (byte, read-only)
  *	bits7-2 undefined
  *	bit1 channel0 busmaster interrupt status 0=none, 1=asserted
  *	bit0 channel0 interrupt status 0=none, 1=asserted
  *
- * 0x3df3 Interrupt mask register
+ * trm290_base+3 Interrupt mask register
  *	bits7-5 undefined
  *	bit4 legacy_header: 1=present, 0=absent
  *	bit3 channel1 busmaster interrupt status 0=none, 1=asserted (read only)
@@ -53,7 +55,7 @@
  *	bit1 channel1 interrupt mask: 1=masked, 0=unmasked(default)
  *	bit0 channel0 interrupt mask: 1=masked, 0=unmasked(default)
  *
- * 0x3df1 "CPR" Config Pointer Register (byte)
+ * trm290_base+1 "CPR" Config Pointer Register (byte)
  *	bit7 1=autoincrement CPR bits 2-0 after each access of CDR
  *	bit6 1=min. 1 wait-state posted write cycle (default), 0=0 wait-state
  *	bit5 0=enabled master burst access (default), 1=disable  (write only)
@@ -61,7 +63,7 @@
  *	bit3 0=primary IDE channel, 1=secondary IDE channel
  *	bits2-0 register index for accesses through CDR port
  *
- * 0x3df0 "CDR" Config Data Register (word)
+ * trm290_base+0 "CDR" Config Data Register (word)
  *	two sets of seven config registers,
  *	selected by CPR bit 3 (channel) and CPR bits 2-0 (index 0 to 6),
  *	each index defined below:
@@ -130,98 +132,137 @@
 #include <linux/blkdev.h>
 #include <linux/init.h>
 #include <linux/hdreg.h>
+#include <linux/pci.h>
+#include <linux/bios32.h>
+#include <linux/delay.h>
+
 #include <asm/io.h>
 
 #include "ide.h"
 
-static void select_dma_or_pio(ide_hwif_t *hwif, int dma)
+static void trm290_prepare_drive (ide_drive_t *drive, unsigned int use_dma)
 {
-	static int previous[2] = {-1,-1};
+	ide_hwif_t *hwif = HWIF(drive);
+	unsigned int reg;
 	unsigned long flags;
 
-	if (previous[hwif->pci_port] != dma) {
-		unsigned short cfg1 = dma ? 0xa3 : 0x21;
-		previous[hwif->pci_port] = dma;
-		save_flags(flags);
-		cli();
-		outb(0x51|(hwif->pci_port<<3),0x3df1);
-		outw(cfg1,0x3df0);
-		restore_flags(flags);
+	/* select PIO or DMA */
+	reg = use_dma ? (0x21 | 0x82) : (0x21 & ~0x82);
+
+	save_flags(flags);
+	cli();
+
+	if (reg != hwif->select_data) {
+		hwif->select_data = reg;
+		outb(0x51|(hwif->channel<<3), hwif->config_data+1);	/* set PIO/DMA */
+		outw(reg & 0xff, hwif->config_data);
+	}
+
+	/* enable IRQ if not probing */
+	if (drive->present) {
+		reg = inw(hwif->config_data+3) & 0x13;
+		reg &= ~(1 << hwif->channel);
+		outw(reg, hwif->config_data+3);
 	}
+
+	restore_flags(flags);
 }
 
-/*
- * trm290_dma_intr() is the handler for trm290 disk read/write DMA interrupts
- */
-static void trm290_dma_intr (ide_drive_t *drive)
+static void trm290_selectproc (ide_drive_t *drive)
 {
-	byte stat;
-	int i;
-	struct request *rq = HWGROUP(drive)->rq;
-
-	stat = GET_STAT();	/* get drive status */
-	if (OK_STAT(stat,DRIVE_READY,drive->bad_wstat|DRQ_STAT)) {
-		unsigned short dma_stat = inw(HWIF(drive)->dma_base + 2);
-		if (dma_stat == 0x00ff) {
-			rq = HWGROUP(drive)->rq;
-			for (i = rq->nr_sectors; i > 0;) {
-				i -= rq->current_nr_sectors;
-				ide_end_request(1, HWGROUP(drive));
-			}
-			return;
-		}
-		printk("%s: bad trm290 DMA status: 0x%04x\n", drive->name, dma_stat);
-	}
-	sti();
-	ide_error(drive, "dma_intr", stat);
+	trm290_prepare_drive(drive, drive->using_dma);
 }
 
 static int trm290_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
 {
 	ide_hwif_t *hwif = HWIF(drive);
-	unsigned int count, reading = 1 << 1;
+	unsigned int count, reading = 2, writing = 0;
 
-	if (drive->media == ide_disk) {
-		switch (func) {
-			case ide_dma_write:
-				reading = 0;
+	switch (func) {
+		case ide_dma_write:
+			reading = 0;
+			writing = 1;
 #ifdef TRM290_NO_DMA_WRITES
-				break;	/* always use PIO for writes */
+			break;	/* always use PIO for writes */
 #endif
-			case ide_dma_read:
-				if (!(count = ide_build_dmatable(drive)))
-					break;		/* try PIO instead of DMA */
-				select_dma_or_pio(hwif, 1);	/* select DMA mode */
-				outl_p(virt_to_bus(hwif->dmatable)|reading, hwif->dma_base);
-				outw((count * 2) - 1, hwif->dma_base+2); /* start DMA */
-				ide_set_handler(drive, &trm290_dma_intr, WAIT_CMD);
-				OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG);
+		case ide_dma_read:
+			if (!(count = ide_build_dmatable(drive)))
+				break;		/* try PIO instead of DMA */
+			trm290_prepare_drive(drive, 1);	/* select DMA xfer */
+			outl(virt_to_bus(hwif->dmatable)|reading|writing, hwif->dma_base);
+			outw((count * 2) - 1, hwif->dma_base+2); /* start DMA */
+			if (drive->media != ide_disk)
 				return 0;
-			default:
-				return ide_dmaproc(func, drive);
-		}
+			ide_set_handler(drive, &ide_dma_intr, WAIT_CMD);
+			OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG);
+		case ide_dma_begin:
+			return 0;
+		case ide_dma_end:
+			return (inw(hwif->dma_base+2) != 0x00ff);
+		default:
+			return ide_dmaproc(func, drive);
 	}
-	select_dma_or_pio(hwif, 0);	/* force PIO mode for this operation */
+	trm290_prepare_drive(drive, 0);	/* select PIO xfer */
 	return 1;
 }
 
-static void trm290_selectproc (ide_drive_t *drive)
-{
-	ide_hwif_t *hwif = HWIF(drive);
-
-	select_dma_or_pio(hwif, drive->using_dma);
-	OUT_BYTE(drive->select.all, hwif->io_ports[IDE_SELECT_OFFSET]);
-}
-
 /*
  * Invoked from ide-dma.c at boot time.
  */
-__initfunc(void ide_init_trm290 (byte bus, byte fn, ide_hwif_t *hwif))
+__initfunc(void ide_init_trm290 (ide_hwif_t *hwif))
 {
+	unsigned int cfgbase = 0;
+	unsigned long flags;
+	byte reg, progif;
+
 	hwif->chipset = ide_trm290;
-	hwif->selectproc = trm290_selectproc;
-	hwif->drives[0].autotune = 2;	/* play it safe */
-	hwif->drives[1].autotune = 2;	/* play it safe */
-	ide_setup_dma(hwif, hwif->pci_port ? 0x3d74 : 0x3df4, 2);
+	if (!pcibios_read_config_byte(hwif->pci_bus, hwif->pci_fn, 0x09, &progif) && (progif & 5)
+	 && !pcibios_read_config_dword(hwif->pci_bus, hwif->pci_fn, 0x20, &cfgbase) && cfgbase)
+	{
+		hwif->config_data = cfgbase & ~1;
+		printk("TRM290: chip config base at 0x%04x\n", hwif->config_data);
+	} else {
+		hwif->config_data = 0x3df4;
+		printk("TRM290: using default config base at 0x%04x\n", hwif->config_data);
+	}
+
+	save_flags(flags);
+	cli();
+	/* put config reg into first byte of hwif->select_data */
+	outb(0x51|(hwif->channel<<3), hwif->config_data+1);
+	hwif->select_data = 0x21;			/* select PIO as default */
+	outb(hwif->select_data, hwif->config_data);
+	reg = inb(hwif->config_data+3);			/* get IRQ info */
+	reg = (reg & 0x10) | 0x03;			/* mask IRQs for both ports */
+	outb(reg, hwif->config_data+3);
+	restore_flags(flags);
+
+	if ((reg & 0x10))
+		hwif->irq = hwif->channel ? 15 : 14;	/* legacy mode */
+	else if (!hwif->irq && hwif->mate && hwif->mate->irq)
+		hwif->irq = hwif->mate->irq;		/* sharing IRQ with mate */
+	ide_setup_dma(hwif, (hwif->channel ? hwif->config_data ^ 0x0080 : hwif->config_data) + 4, 2);
 	hwif->dmaproc = &trm290_dmaproc;
+	hwif->selectproc = &trm290_selectproc;
+	hwif->no_autodma = 1;				/* play it safe for now */
+#if 1
+	{
+		/*
+		 * My trm290-based card doesn't seem to work with all possible values
+		 * for the control basereg, so this kludge ensures that we use only
+		 * values that are known to work.  Ugh.		-ml
+		 */
+		unsigned short old, compat = hwif->channel ? 0x374 : 0x3f4;
+		static unsigned short next_offset = 0;
+
+		outb(0x54|(hwif->channel<<3), hwif->config_data+1);
+		old = inw(hwif->config_data) & ~1;
+		if (old != compat && inb(old+2) == 0xff) {
+			compat += (next_offset += 0x400);	/* leave lower 10 bits untouched */
+			hwif->io_ports[IDE_CONTROL_OFFSET] = compat + 2;	/* FIXME: should do a check_region */
+			outw(compat|1, hwif->config_data);
+			printk("%s: control basereg workaround: old=0x%04x, new=0x%04x\n", hwif->name, old, inw(hwif->config_data) & ~1);
+		}
+	}
+#endif
 }
diff -u --recursive --new-file v2.1.72/linux/drivers/block/umc8672.c linux/drivers/block/umc8672.c
--- v2.1.72/linux/drivers/block/umc8672.c	Thu Dec  4 14:53:54 1997
+++ linux/drivers/block/umc8672.c	Wed Dec 17 11:11:16 1997
@@ -153,4 +153,5 @@
 	ide_hwifs[1].tuneproc = &tune_umc;
 	ide_hwifs[0].mate = &ide_hwifs[1];
 	ide_hwifs[1].mate = &ide_hwifs[0];
+	ide_hwifs[1].channel = 1;
 }
diff -u --recursive --new-file v2.1.72/linux/drivers/char/pc_keyb.c linux/drivers/char/pc_keyb.c
--- v2.1.72/linux/drivers/char/pc_keyb.c	Mon Aug  4 16:25:37 1997
+++ linux/drivers/char/pc_keyb.c	Wed Dec 17 15:23:47 1997
@@ -17,6 +17,7 @@
 #include <linux/ioport.h>
 #include <linux/init.h>
 #include <linux/kbd_ll.h>
+#include <linux/delay.h>
 
 #include <asm/keyboard.h>
 #include <asm/bitops.h>
@@ -195,16 +196,21 @@
 
 /*
  *	Wait for keyboard controller input buffer is empty.
+ *
+ *	Don't use 'jiffies' so that we don't depend on
+ *	interrupts..
  */
 
 static inline void kb_wait(void)
 {
-	unsigned long start = jiffies;
+	unsigned long timeout = KBC_TIMEOUT;
 
 	do {
 		if (! (inb_p(KBD_STATUS_REG) & KBD_STAT_IBF))
 			return;
-	} while (jiffies - start < KBC_TIMEOUT);
+		udelay(1000);
+		timeout--;
+	} while (timeout);
 #ifdef KBD_REPORT_TIMEOUTS
 	printk(KERN_WARNING "Keyboard timed out\n");
 #endif
@@ -534,29 +540,34 @@
  * send_data sends a character to the keyboard and waits
  * for an acknowledge, possibly retrying if asked to. Returns
  * the success status.
+ *
+ * Don't use 'jiffies', so that we don't depend on interrupts
  */
 static int send_data(unsigned char data)
 {
 	int retries = 3;
-	unsigned long start;
 
 	do {
+		unsigned long timeout = KBD_TIMEOUT;
+
 		kb_wait();
 		acknowledge = 0;
 		resend = 0;
 		reply_expected = 1;
 		outb_p(data, KBD_DATA_REG);
-		start = jiffies;
-		do {
+		for (;;) {
 			if (acknowledge)
 				return 1;
-			if (jiffies - start >= KBD_TIMEOUT) {
+			if (resend)
+				break;
+			udelay(1000);
+			if (!--timeout) {
 #ifdef KBD_REPORT_TIMEOUTS
 				printk(KERN_WARNING "Keyboard timeout\n");
 #endif
 				return 0;
 			}
-		} while (!resend);
+		}
 	} while (retries-- > 0);
 #ifdef KBD_REPORT_TIMEOUTS
 	printk(KERN_WARNING "keyboard: Too many NACKs -- noisy kbd cable?\n");
diff -u --recursive --new-file v2.1.72/linux/drivers/char/pc_keyb.h linux/drivers/char/pc_keyb.h
--- v2.1.72/linux/drivers/char/pc_keyb.h	Mon Aug  4 16:25:37 1997
+++ linux/drivers/char/pc_keyb.h	Wed Dec 17 15:11:44 1997
@@ -15,9 +15,9 @@
 #define KBD_REPORT_TIMEOUTS		/* Report keyboard timeouts */
 #undef KBD_IS_FOCUS_9000		/* We have the brain-damaged FOCUS-9000 keyboard */
 
-#define KBD_INIT_TIMEOUT HZ		/* Timeout for initializing the keyboard */
-#define KBC_TIMEOUT (HZ/4)		/* Timeout for sending to keyboard controller */
-#define KBD_TIMEOUT (HZ/4)		/* Timeout for keyboard command acknowledge */
+#define KBD_INIT_TIMEOUT HZ		/* Timeout in jiffies for initializing the keyboard */
+#define KBC_TIMEOUT 250			/* Timeout in ms for sending to keyboard controller */
+#define KBD_TIMEOUT 250			/* Timeout in ms for keyboard command acknowledge */
 
 /*
  *	Internal variables of the driver
diff -u --recursive --new-file v2.1.72/linux/drivers/char/pcwd.c linux/drivers/char/pcwd.c
--- v2.1.72/linux/drivers/char/pcwd.c	Mon Dec  1 12:04:12 1997
+++ linux/drivers/char/pcwd.c	Wed Dec 10 09:37:30 1997
@@ -30,6 +30,7 @@
  *		code bits, and added compatibility to 2.1.x.
  * 970912       Enabled board on open and disable on close.
  * 971107	Took account of recent VFS changes (broke read).
+ * 971210       Disable board on initialisation in case board already ticking.
  */
 
 #include <linux/module.h>
@@ -578,6 +579,12 @@
 	debug_off();
 
 	pcwd_showprevstate();
+
+	/*  Disable the board  */
+	if (revision == PCWD_REVISION_C) {
+		outb_p(0xA5, current_readport + 3);
+		outb_p(0xA5, current_readport + 3);
+	}
 
 	if (revision == PCWD_REVISION_A)
 		request_region(current_readport, 2, "PCWD Rev.A (Berkshire)");
diff -u --recursive --new-file v2.1.72/linux/drivers/net/3c505.c linux/drivers/net/3c505.c
--- v2.1.72/linux/drivers/net/3c505.c	Mon Nov  3 13:04:26 1997
+++ linux/drivers/net/3c505.c	Wed Dec 10 09:45:15 1997
@@ -323,7 +323,7 @@
  * never happen in theory, but seems to occur occasionally if the card gets
  * prodded at the wrong time.
  */
-static inline void check_dma(struct device *dev)
+static inline void check_3c505_dma(struct device *dev)
 {
 	elp_device *adapter = dev->priv;
 	if (adapter->dmaing && (jiffies > (adapter->current_dma.start_time + 10))) {
@@ -406,7 +406,7 @@
 	int timeout;
 	elp_device *adapter = dev->priv;
 
-	check_dma(dev);
+	check_3c505_dma(dev);
 
 	if (adapter->dmaing && adapter->current_dma.direction == 0)
 		return FALSE;
@@ -723,7 +723,7 @@
 			}
 		} else {
 			/* has one timed out? */
-			check_dma(dev);
+			check_3c505_dma(dev);
 		}
 
 		sti();
@@ -1088,7 +1088,7 @@
 		return 1;
 	}
 
-	check_dma(dev);
+	check_3c505_dma(dev);
 
 	/*
 	 * if the transmitter is still busy, we have a transmit timeout...
diff -u --recursive --new-file v2.1.72/linux/drivers/net/3c59x.c linux/drivers/net/3c59x.c
--- v2.1.72/linux/drivers/net/3c59x.c	Mon Dec  1 12:04:12 1997
+++ linux/drivers/net/3c59x.c	Wed Dec 10 09:45:16 1997
@@ -1,31 +1,60 @@
-/* 3c59x.c: A 3Com 3c590/3c595 "Vortex" ethernet driver for linux. */
+/* EtherLinkXL.c: A 3Com EtherLink PCI III/XL ethernet driver for linux. */
 /*
-	Written 1995 by Donald Becker.
+	Written 1996-1997 by Donald Becker.
 
 	This software may be used and distributed according to the terms
 	of the GNU Public License, incorporated herein by reference.
 
-	This driver is for the 3Com "Vortex" series ethercards.  Members of
-	the series include the 3c590 PCI EtherLink III and 3c595-Tx PCI Fast
-	EtherLink.
+	This driver is for the 3Com "Vortex" and "Boomerang" series ethercards.
+	Members of the series include Fast EtherLink 3c590/3c592/3c595/3c597
+	and the EtherLink XL 3c900 and 3c905 cards.
 
 	The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O
 	Center of Excellence in Space Data and Information Sciences
 	   Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
 */
 
-static char *version = "3c59x.c:v0.25 5/17/96 becker@cesdis.gsfc.nasa.gov\n";
+static char *version =
+"3c59x.c:v0.46B 9/25/97 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/vortex.html\n";
 
-/* "Knobs" that turn on special features. */
-/* Enable the experimental automatic media selection code. */
+/* "Knobs" that adjust features and parameters. */
+/* Set the copy breakpoint for the copy-only-tiny-frames scheme.
+   Setting to > 1512 effectively disables this feature. */
+static const rx_copybreak = 200;
+/* Allow setting MTU to a larger size, bypassing the normal ethernet setup. */
+static const mtu = 1500;
+/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
+static int max_interrupt_work = 20;
+
+/* Enable the automatic media selection code -- usually set. */
 #define AUTOMEDIA 1
 
-/* Allow the use of bus master transfers instead of programmed-I/O for the
-   Tx process.  Bus master transfers are always disabled by default, but
-   iff this is set they may be turned on using 'options'. */
+/* Allow the use of fragment bus master transfers instead of only
+   programmed-I/O for Vortex cards.  Full-bus-master transfers are always
+   enabled by default on Boomerang cards.  If VORTEX_BUS_MASTER is defined,
+   the feature may be turned on using 'options'. */
 #define VORTEX_BUS_MASTER
+
+/* A few values that may be tweaked. */
+/* Time in jiffies before concluding the transmitter is hung. */
+#define TX_TIMEOUT  ((400*HZ)/1000)
+
+/* Keep the ring sizes a power of two for efficiency. */
+#define TX_RING_SIZE	16
+#define RX_RING_SIZE	32
+#define PKT_BUF_SZ		1536			/* Size of each temporary Rx buffer.*/
+
 #include <linux/config.h>
+#ifdef MODULE
+#ifdef MODVERSIONS
+#include <linux/modversions.h>
+#endif
 #include <linux/module.h>
+#include <linux/version.h>
+#else
+#define MOD_INC_USE_COUNT
+#define MOD_DEC_USE_COUNT
+#endif
 
 #include <linux/kernel.h>
 #include <linux/sched.h>
@@ -36,16 +65,10 @@
 #include <linux/ioport.h>
 #include <linux/malloc.h>
 #include <linux/interrupt.h>
-#include <linux/init.h>
-
-#include <linux/delay.h>
-
-#ifdef CONFIG_PCI
 #include <linux/pci.h>
 #include <linux/bios32.h>
-#endif
-
 #include <linux/timer.h>
+#include <asm/irq.h>			/* For NR_IRQS only. */
 #include <asm/bitops.h>
 #include <asm/io.h>
 
@@ -53,27 +76,60 @@
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 
+/* Kernel compatibility defines, common to David Hind's PCMCIA package.
+   This is only in the support-all-kernels source code. */
+#ifndef LINUX_VERSION_CODE
+#include <linux/version.h>		/* Redundant above, here for easy clean-up. */
+#endif
+#if LINUX_VERSION_CODE < 0x10300
+#define RUN_AT(x) (x)			/* What to put in timer->expires.  */
+#define DEV_ALLOC_SKB(len) alloc_skb(len, GFP_ATOMIC)
+#if defined(__alpha)
+#error "The Alpha architecture is only support with kernel version 2.0."
+#endif
+#define virt_to_bus(addr)  ((unsigned long)addr)
+#define bus_to_virt(addr) ((void*)addr)
+#else  /* 1.3.0 and later */
 #define RUN_AT(x) (jiffies + (x))
 #define DEV_ALLOC_SKB(len) dev_alloc_skb(len + 2)
+#endif
 
+#ifdef SA_SHIRQ
 #define FREE_IRQ(irqnum, dev) free_irq(irqnum, dev)
 #define REQUEST_IRQ(i,h,f,n, instance) request_irq(i,h,f,n, instance)
 #define IRQ(irq, dev_id, pt_regs) (irq, dev_id, pt_regs)
+#else
+#define FREE_IRQ(irqnum, dev) free_irq(irqnum)
+#define REQUEST_IRQ(i,h,f,n, instance) request_irq(i,h,f,n)
+#define IRQ(irq, dev_id, pt_regs) (irq, pt_regs)
+#endif
+
+#if (LINUX_VERSION_CODE >= 0x10344)
+#define NEW_MULTICAST
+#include <linux/delay.h>
+#else
+#define udelay(microsec)	do { int _i = 4*microsec; while (--_i > 0) { __SLOW_DOWN_IO; }} while (0)
+#endif
+
+#if (LINUX_VERSION_CODE < 0x20123)
+#define test_and_set_bit(val, addr) set_bit(val, addr)
+#endif
 
 /* "Knobs" for adjusting internal parameters. */
 /* Put out somewhat more debugging messages. (0 - no msg, 1 minimal msgs). */
-#define VORTEX_DEBUG 2
-
-/* Number of times to check to see if the Tx FIFO has space, used in some
-   limited cases. */
-#define WAIT_TX_AVAIL 200
+#define VORTEX_DEBUG 1
+/* Some values here only for performance evaluation and path-coverage
+   debugging. */
+static int rx_nocopy = 0, rx_copy = 0, queued_packet = 0;
 
 /* Operational parameter that usually are not changed. */
-#define TX_TIMEOUT  40		/* Time in jiffies before concluding Tx hung */
 
-/* The total size is twice that of the original EtherLinkIII series: the
-   runtime register window, window 1, is now always mapped in. */
+/* The Vortex size is twice that of the original EtherLinkIII series: the
+   runtime register window, window 1, is now always mapped in.
+   The Boomerang size is twice as large as the Vortex -- it has additional
+   bus master control registers. */
 #define VORTEX_TOTAL_SIZE 0x20
+#define BOOMERANG_TOTAL_SIZE 0x40
 
 #ifdef HAVE_DEVLIST
 struct netdev_entry tc59x_drv =
@@ -86,27 +142,40 @@
 static int vortex_debug = 1;
 #endif
 
-#ifdef CONFIG_PCI
-static int product_ids[] __initdata = {0x5900, 0x5950, 0x5951, 0x5952, 0, 0};
-#endif
+/* Set iff a MII transceiver on any interface requires mdio preamble. */
+static char mii_preamble_required = 0;
 
+/* Caution!  These entries must be consistent, with the EISA ones last. */
+static const int product_ids[] = {
+	0x5900, 0x5950, 0x5951, 0x5952, 0x9000, 0x9001, 0x9050, 0x9051, 0, 0};
 static const char *product_names[] = {
 	"3c590 Vortex 10Mbps",
 	"3c595 Vortex 100baseTX",
 	"3c595 Vortex 100baseT4",
 	"3c595 Vortex 100base-MII",
-	"EISA Vortex 3c597",
+	"3c900 Boomerang 10baseT",
+	"3c900 Boomerang 10Mbps/Combo",
+	"3c905 Boomerang 100baseTx",
+	"3c905 Boomerang 100baseT4",
+	"3c592 EISA 10mbps Demon/Vortex",
+	"3c597 EISA Fast Demon/Vortex",
 };
-#define DEMON_INDEX 5			/* Caution!  Must be consistent with above! */
+#define DEMON10_INDEX 8
+#define DEMON100_INDEX 9
 
 /*
 				Theory of Operation
 
 I. Board Compatibility
 
-This device driver is designed for the 3Com FastEtherLink, 3Com's PCI to
-10/100baseT adapter.  It also works with the 3c590, a similar product
-with only a 10Mbs interface.
+This device driver is designed for the 3Com FastEtherLink and FastEtherLink
+XL, 3Com's PCI to 10/100baseT adapters.  It also works with the 10Mbs
+versions of the FastEtherLink cards.  The supported product IDs are
+  3c590, 3c592, 3c595, 3c597, 3c900, 3c905
+
+The ISA 3c515 is supported with a seperate driver, 3c515.c, included with
+the kernel source or available from
+    cesdis.gsfc.nasa.gov:/pub/linux/drivers/3c515.html
 
 II. Board-specific settings
 
@@ -122,12 +191,33 @@
 series.  The primary interface is two programmed-I/O FIFOs, with an
 alternate single-contiguous-region bus-master transfer (see next).
 
+The 3c900 "Boomerang" series uses a full-bus-master interface with seperate
+lists of transmit and receive descriptors, similar to the AMD LANCE/PCnet,
+DEC Tulip and Intel Speedo3.  The first chip version retains a compatible
+programmed-I/O interface that will be removed in the 'B' and subsequent
+revisions.
+
 One extension that is advertised in a very large font is that the adapters
-are capable of being bus masters.  Unfortunately this capability is only for
-a single contiguous region making it less useful than the list of transfer
-regions available with the DEC Tulip or AMD PCnet.  Given the significant
-performance impact of taking an extra interrupt for each transfer, using
-DMA transfers is a win only with large blocks.
+are capable of being bus masters.  On the Vortex chip this capability was
+only for a single contiguous region making it far less useful than the full
+bus master capability.  There is a significant performance impact of taking
+an extra interrupt or polling for the completion of each transfer, as well
+as difficulty sharing the single transfer engine between the transmit and
+receive threads.  Using DMA transfers is a win only with large blocks or
+with the flawed versions of the Intel Orion motherboard PCI controller.
+
+The Boomerang chip's full-bus-master interface is useful, and has the
+currently-unused advantages over other similar chips that queued transmit
+packets may be reordered and receive buffer groups are associated with a
+single frame.
+
+With full-bus-master support, this driver uses a "RX_COPYBREAK" scheme.
+Tather than a fixed intermediate receive buffer, this scheme allocates
+full-sized skbuffs as receive buffers.  The value RX_COPYBREAK is used as
+the copying breakpoint: it is chosen to trade-off the memory wasted by
+passing the full-sized skbuff to the queue layer for all frames vs. the
+copying cost of copying a frame to a correctly-sized skbuff.
+
 
 IIIC. Synchronization
 The driver runs as two independent, single-threaded flows of control.  One
@@ -137,8 +227,8 @@
 
 IV. Notes
 
-Thanks to Cameron Spitzer and Terry Murphy of 3Com for providing both
-3c590 and 3c595 boards.
+Thanks to Cameron Spitzer and Terry Murphy of 3Com for providing development
+3c590, 3c595, and 3c900 boards.
 The name "Vortex" is the internal 3Com project name for the PCI ASIC, and
 the EISA version is called "Demon".  According to Terry these names come
 from rides at the local amusement park.
@@ -169,8 +259,10 @@
 
 enum vortex_cmd {
 	TotalReset = 0<<11, SelectWindow = 1<<11, StartCoax = 2<<11,
-	RxDisable = 3<<11, RxEnable = 4<<11, RxReset = 5<<11, RxDiscard = 8<<11,
-	TxEnable = 9<<11, TxDisable = 10<<11, TxReset = 11<<11,
+	RxDisable = 3<<11, RxEnable = 4<<11, RxReset = 5<<11,
+	UpStall = 6<<11, UpUnstall = (6<<11)+1,
+	DownStall = (6<<11)+2, DownUnstall = (6<<11)+3,
+	RxDiscard = 8<<11, TxEnable = 9<<11, TxDisable = 10<<11, TxReset = 11<<11,
 	FakeIntr = 12<<11, AckIntr = 13<<11, SetIntrEnb = 14<<11,
 	SetStatusEnb = 15<<11, SetRxFilter = 16<<11, SetRxThreshold = 17<<11,
 	SetTxThreshold = 18<<11, SetTxStart = 19<<11,
@@ -185,7 +277,8 @@
 enum vortex_status {
 	IntLatch = 0x0001, AdapterFailure = 0x0002, TxComplete = 0x0004,
 	TxAvailable = 0x0008, RxComplete = 0x0010, RxEarly = 0x0020,
-	IntReq = 0x0040, StatsFull = 0x0080, DMADone = 1<<8,
+	IntReq = 0x0040, StatsFull = 0x0080,
+	DMADone = 1<<8, DownComplete = 1<<9, UpComplete = 1<<10,
 	DMAInProgress = 1<<11,			/* DMA controller is still busy.*/
 	CmdInProgress = 1<<12,			/* EL3_CMD is still busy.*/
 };
@@ -200,6 +293,7 @@
 enum Window0 {
 	Wn0EepromCmd = 10,		/* Window 0: EEPROM command register. */
 	Wn0EepromData = 12,		/* Window 0: EEPROM results register. */
+	IntrStatus=0x0E,		/* Valid in all windows. */
 };
 enum Win0_EEPROM_bits {
 	EEPROM_Read = 0x80, EEPROM_WRITE = 0x40, EEPROM_ERASE = 0xC0,
@@ -222,12 +316,12 @@
 		unsigned int ram_size:3, ram_width:1, ram_speed:2, rom_size:2;
 		int pad8:8;
 		unsigned int ram_split:2, pad18:2, xcvr:3, pad21:1, autoselect:1;
-		int pad24:8;
+		int pad24:7;
 	} u;
 };
 
-enum Window4 {
-	Wn4_Media = 0x0A,		/* Window 4: Various transcvr/media bits. */
+enum Window4 {		/* Window 4: Xcvr/media bits. */
+	Wn4_FIFODiag = 4, Wn4_NetDiag = 6, Wn4_PhysicalMgmt=8, Wn4_Media = 10,
 };
 enum Win4_Media_bits {
 	Media_SQE = 0x0008,		/* Enable SQE error counting for AUI. */
@@ -238,12 +332,54 @@
 enum Window7 {					/* Window 7: Bus Master control. */
 	Wn7_MasterAddr = 0, Wn7_MasterLen = 6, Wn7_MasterStatus = 12,
 };
+/* Boomerang bus master control registers. */
+enum MasterCtrl {
+	PktStatus = 0x20, DownListPtr = 0x24, FragAddr = 0x28, FragLen = 0x2c,
+	TxFreeThreshold = 0x2f, UpPktStatus = 0x30, UpListPtr = 0x38,
+};
+
+/* The Rx and Tx descriptor lists.
+   Caution Alpha hackers: these types are 32 bits!  Note also the 8 byte
+   alignment contraint on tx_ring[] and rx_ring[]. */
+#define LAST_FRAG  0x80000000			/* Last Addr/Len pair in descriptor. */
+struct boom_rx_desc {
+	u32 next;					/* Last entry points to 0.   */
+	s32 status;
+	u32 addr;					/* Up to addr/len possible.. */
+	s32 length;					/* set high bit to indicate last pair. */
+};
+/* Values for the Rx status entry. */
+enum rx_desc_status {
+	RxDComplete=0x00008000, RxDError=0x4000,
+	/* See boomerang_rx() for actual error bits */
+};
+
+struct boom_tx_desc {
+	u32 next;					/* Last entry points to 0.   */
+	s32 status;					/* bits 0:12 length, others see below.  */
+	u32 addr;
+	s32 length;
+};
+
+/* Values for the Tx status entry. */
+enum tx_desc_status {
+	CRCDisable=0x2000, TxDComplete=0x8000,
+	TxIntrUploaded=0x80000000,		/* IRQ when in FIFO, but maybe not sent. */
+};
 
 struct vortex_private {
 	char devname[8];			/* "ethN" string, also for kernel debug. */
 	const char *product_name;
 	struct device *next_module;
-	struct net_device_stats stats;
+	/* The Rx and Tx rings are here to keep them quad-word-aligned. */
+	struct boom_rx_desc rx_ring[RX_RING_SIZE];
+	struct boom_tx_desc tx_ring[TX_RING_SIZE];
+	/* The addresses of transmit- and receive-in-place skbuffs. */
+	struct sk_buff* rx_skbuff[RX_RING_SIZE];
+	struct sk_buff* tx_skbuff[TX_RING_SIZE];
+	unsigned int cur_rx, cur_tx;		/* The next free ring entry */
+	unsigned int dirty_rx, dirty_tx;	/* The ring entries to be free()ed. */
+	struct enet_statistics stats;
 	struct sk_buff *tx_skb;		/* Packet being eaten by bus master ctrl.  */
 	struct timer_list timer;	/* Media selection timer. */
 	int options;				/* User-settable misc. driver options. */
@@ -251,12 +387,23 @@
 	unsigned int available_media:8,	/* From Wn3_Options */
 	  media_override:3, 			/* Passed-in media type. */
 	  default_media:3,			/* Read from the EEPROM. */
-	  full_duplex:1, bus_master:1, autoselect:1;
+	  full_duplex:1, autoselect:1,
+	  bus_master:1,				/* Vortex can only do a fragment bus-m. */
+	  full_bus_master_tx:1, full_bus_master_rx:2, /* Boomerang  */
+      tx_full:1;
+	u16 capabilities;			/* Adapter capabilities word. */
+	u16 info1, info2;			/* Software information information. */
+	unsigned char phys[2];		/* MII device addresses. */
 };
 
 /* The action to take with a media selection timer tick.
    Note that we deviate from the 3Com order by checking 10base2 before AUI.
  */
+enum xcvr_types {
+	XCVR_10baseT=0, XCVR_AUI, XCVR_10baseTOnly, XCVR_10base2, XCVR_100baseTx,
+	XCVR_100baseFx, XCVR_MII=6, XCVR_Default=8,
+};
+
 static struct media_table {
   char *name;
   unsigned int media_bits:16,		/* Bits to set in Wn4_Media register. */
@@ -264,30 +411,44 @@
 	next:8;				/* The media type to try next. */
   short wait;			/* Time before we check media status. */
 } media_tbl[] = {
-  {	"10baseT",   Media_10TP,0x08, 3 /* 10baseT->10base2 */, (14*HZ)/10},
-  { "10Mbs AUI", Media_SQE, 0x20, 8 /* AUI->default */, (1*HZ)/10},
-  { "undefined", 0,			0x80, 0 /* Undefined */, 0},
-  { "10base2",   0,			0x10, 1 /* 10base2->AUI. */, (1*HZ)/10},
-  { "100baseTX", Media_Lnk, 0x02, 5 /* 100baseTX->100baseFX */, (14*HZ)/10},
-  { "100baseFX", Media_Lnk, 0x04, 6 /* 100baseFX->MII */, (14*HZ)/10},
-  { "MII",		 0,			0x40, 0 /* MII->10baseT */, (14*HZ)/10},
-  { "undefined", 0,			0x01, 0 /* Undefined/100baseT4 */, 0},
-  { "Default",	 0,			0xFF, 0 /* Use default */, 0},
+  {	"10baseT",   Media_10TP,0x08, XCVR_10base2, (14*HZ)/10},
+  { "10Mbs AUI", Media_SQE, 0x20, XCVR_Default, (1*HZ)/10},
+  { "undefined", 0,			0x80, XCVR_10baseT, 10000},
+  { "10base2",   0,			0x10, XCVR_AUI,		(1*HZ)/10},
+  { "100baseTX", Media_Lnk, 0x02, XCVR_100baseFx, (14*HZ)/10},
+  { "100baseFX", Media_Lnk, 0x04, XCVR_MII,		(14*HZ)/10},
+  { "MII",		 0,			0x40, XCVR_10baseT, 3*HZ },
+  { "undefined", 0,			0x01, XCVR_10baseT, 10000},
+  { "Default",	 0,			0xFF, XCVR_10baseT, 10000},
 };
 
 static int vortex_scan(struct device *dev);
-static int vortex_found_device(struct device *dev, int ioaddr, int irq,
-							   int product_index, int options);
+static struct device *vortex_found_device(struct device *dev, int ioaddr,
+										  int irq, int product_index,
+										  int options, int card_idx);
 static int vortex_probe1(struct device *dev);
 static int vortex_open(struct device *dev);
+static void mdio_sync(int ioaddr, int bits);
+static int mdio_read(int ioaddr, int phy_id, int location);
+#ifdef HAVE_PRIVATE_IOCTL
+static void mdio_write(int ioaddr, int phy_id, int location, int value);
+#endif
 static void vortex_timer(unsigned long arg);
 static int vortex_start_xmit(struct sk_buff *skb, struct device *dev);
+static int boomerang_start_xmit(struct sk_buff *skb, struct device *dev);
 static int vortex_rx(struct device *dev);
+static int boomerang_rx(struct device *dev);
 static void vortex_interrupt IRQ(int irq, void *dev_id, struct pt_regs *regs);
 static int vortex_close(struct device *dev);
 static void update_stats(int addr, struct device *dev);
-static struct net_device_stats *vortex_get_stats(struct device *dev);
+static struct enet_statistics *vortex_get_stats(struct device *dev);
 static void set_rx_mode(struct device *dev);
+#ifdef HAVE_PRIVATE_IOCTL
+static int vortex_ioctl(struct device *dev, struct ifreq *rq, int cmd);
+#endif
+#ifndef NEW_MULTICAST
+static void set_multicast_list(struct device *dev, int num_addrs, void *addrs);
+#endif
 
 
 /* Unlike the other PCI cards the 59x cards don't need a large contiguous
@@ -307,11 +468,15 @@
 /* This driver uses 'options' to pass the media type, full-duplex flag, etc. */
 /* Note: this is the only limit on the number of cards supported!! */
 static int options[8] = { -1, -1, -1, -1, -1, -1, -1, -1,};
+static int full_duplex[8] = {-1, -1, -1, -1, -1, -1, -1, -1};
+/* A list of all installed Vortex devices, for removing the driver module. */
+static struct device *root_vortex_dev = NULL;
+
+/* Variables to work-around the Compaq PCI BIOS32 problem. */
+static int compaq_ioaddr = 0, compaq_irq = 0, compaq_prod_id = 0;
 
 #ifdef MODULE
 static int debug = -1;
-/* A list of all installed Vortex devices, for removing the driver module. */
-static struct device *root_vortex_dev = NULL;
 
 int
 init_module(void)
@@ -329,7 +494,7 @@
 }
 
 #else
-__initfunc(int tc59x_probe(struct device *dev))
+int tc59x_probe(struct device *dev)
 {
 	int cards_found = 0;
 
@@ -342,100 +507,148 @@
 }
 #endif  /* not MODULE */
 
-__initfunc(static int vortex_scan(struct device *dev))
+static int vortex_scan(struct device *dev)
 {
 	int cards_found = 0;
 
-#ifdef CONFIG_PCI
+#ifndef NO_PCI					/* Allow an EISA-only driver. */
+	/* Ideally we would detect all cards in slot order.  That would
+	   be best done a central PCI probe dispatch, which wouldn't work
+	   well with the current structure.  So instead we detect 3Com cards
+	   in slot order. */
 	if (pcibios_present()) {
 		static int pci_index = 0;
-		static int board_index = 0;
-		for (; product_ids[board_index]; board_index++, pci_index = 0) {
-			for (; pci_index < 16; pci_index++) {
-				unsigned char pci_bus, pci_device_fn, pci_irq_line;
-				unsigned char pci_latency;
-				unsigned int pci_ioaddr;
-				unsigned short pci_command;
-
-				if (pcibios_find_device(TCOM_VENDOR_ID,
-										product_ids[board_index], pci_index,
-										&pci_bus, &pci_device_fn))
+		unsigned char pci_bus, pci_device_fn;
+
+		for (;pci_index < 0xff; pci_index++) {
+			unsigned char pci_irq_line, pci_latency;
+			unsigned short pci_command, vendor, device;
+			unsigned int pci_ioaddr;
+
+			int board_index = 0;
+			if (pcibios_find_class (PCI_CLASS_NETWORK_ETHERNET << 8,
+									pci_index, &pci_bus, &pci_device_fn)
+				!= PCIBIOS_SUCCESSFUL)
+				break;
+			pcibios_read_config_word(pci_bus, pci_device_fn,
+									 PCI_VENDOR_ID, &vendor);
+			pcibios_read_config_word(pci_bus, pci_device_fn,
+									 PCI_DEVICE_ID, &device);
+			pcibios_read_config_byte(pci_bus, pci_device_fn,
+									 PCI_INTERRUPT_LINE, &pci_irq_line);
+			pcibios_read_config_dword(pci_bus, pci_device_fn,
+									  PCI_BASE_ADDRESS_0, &pci_ioaddr);
+			/* Remove I/O space marker in bit 0. */
+			pci_ioaddr &= ~3;
+
+			if (vendor != TCOM_VENDOR_ID)
+				continue;
+
+			for (board_index = 0; product_ids[board_index]; board_index++) {
+				if (device == product_ids[board_index])
 					break;
-				pcibios_read_config_byte(pci_bus, pci_device_fn,
-										 PCI_INTERRUPT_LINE, &pci_irq_line);
-				pcibios_read_config_dword(pci_bus, pci_device_fn,
-										  PCI_BASE_ADDRESS_0, &pci_ioaddr);
-				/* Remove I/O space marker in bit 0. */
-				pci_ioaddr &= ~3;
+			}
+			if (product_ids[board_index] == 0) {
+				printk("Unknown 3Com PCI ethernet adapter type %4.4x detected:"
+					   " not configured.\n", device);
+				continue;
+			}
+			if (check_region(pci_ioaddr, VORTEX_TOTAL_SIZE))
+				continue;
 
-#ifdef VORTEX_BUS_MASTER
+			dev = vortex_found_device(dev, pci_ioaddr, pci_irq_line,
+									  board_index, dev && dev->mem_start
+									  ? dev->mem_start : options[cards_found],
+									  cards_found);
+
+			if (dev) {
 				/* Get and check the bus-master and latency values.
 				   Some PCI BIOSes fail to set the master-enable bit, and
 				   the latency timer must be set to the maximum value to avoid
 				   data corruption that occurs when the timer expires during
-				   a transfer.  Yes, it's a bug. */
+				   a transfer -- a bug in the Vortex chip. */
 				pcibios_read_config_word(pci_bus, pci_device_fn,
 										 PCI_COMMAND, &pci_command);
 				if ( ! (pci_command & PCI_COMMAND_MASTER)) {
-					printk("  PCI Master Bit has not been set! Setting...\n");
+					printk("%s:  PCI Master Bit has not been set! "
+						   " Setting...\n", dev->name);
 					pci_command |= PCI_COMMAND_MASTER;
 					pcibios_write_config_word(pci_bus, pci_device_fn,
 											  PCI_COMMAND, pci_command);
 				}
 				pcibios_read_config_byte(pci_bus, pci_device_fn,
 										 PCI_LATENCY_TIMER, &pci_latency);
-				if (pci_latency != 255) {
-					printk("  Overriding PCI latency timer (CFLT) setting of"
-						   " %d, new value is 255.\n", pci_latency);
+				if (pci_latency != 248) {
+					printk("%s: Overriding PCI latency"
+						   " timer (CFLT) setting of %d, new value is 248.\n",
+						   dev->name, pci_latency);
 					pcibios_write_config_byte(pci_bus, pci_device_fn,
-											  PCI_LATENCY_TIMER, 255);
+											  PCI_LATENCY_TIMER, 248);
 				}
-#endif  /* VORTEX_BUS_MASTER */
-				vortex_found_device(dev, pci_ioaddr, pci_irq_line, board_index,
-									dev && dev->mem_start ? dev->mem_start
-									: options[cards_found]);
 				dev = 0;
 				cards_found++;
 			}
 		}
 	}
-#endif /* CONFIG_PCI */
+#endif /* NO_PCI */
 
 	/* Now check all slots of the EISA bus. */
 	if (EISA_bus) {
 		static int ioaddr = 0x1000;
 		for (ioaddr = 0x1000; ioaddr < 0x9000; ioaddr += 0x1000) {
+			int product_id, product_index;
+			if (check_region(ioaddr, VORTEX_TOTAL_SIZE))
+				continue;
 			/* Check the standard EISA ID register for an encoded '3Com'. */
 			if (inw(ioaddr + 0xC80) != 0x6d50)
 				continue;
 			/* Check for a product that we support, 3c59{2,7} any rev. */
-			if ((inw(ioaddr + 0xC82) & 0xF0FF) != 0x7059 		/* 597 */
-				&& (inw(ioaddr + 0xC82) & 0xF0FF) != 0x2059)	/* 592 */
+			product_id = inw(ioaddr + 0xC82) & 0xF0FF;
+			if (product_id == 0x7059) 		/* 597 */
+				product_index = DEMON100_INDEX;
+			else if (product_id == 0x2059)	/* 592 */
+				product_index = DEMON10_INDEX;
+			else
 				continue;
 			vortex_found_device(dev, ioaddr, inw(ioaddr + 0xC88) >> 12,
-								DEMON_INDEX,  dev && dev->mem_start
-								? dev->mem_start : options[cards_found]);
+								product_index,  dev && dev->mem_start
+								? dev->mem_start : options[cards_found],
+								cards_found);
 			dev = 0;
 			cards_found++;
 		}
 	}
 
+	/* Special code to work-around the Compaq PCI BIOS32 problem. */
+	if (compaq_ioaddr) {
+		vortex_found_device(dev, compaq_ioaddr, compaq_irq, compaq_prod_id,
+							dev && dev->mem_start ? dev->mem_start
+							: options[cards_found], cards_found);
+		cards_found++;
+		dev = 0;
+	}
+
+	/* Finally check for a 3c515 on the ISA bus. */
+	/* (3c515 support omitted on this version.) */
+
 	return cards_found;
 }
 
-__initfunc(static int vortex_found_device(struct device *dev, int ioaddr, int irq,
-							   int product_index, int options))
+static struct device *
+vortex_found_device(struct device *dev, int ioaddr, int irq,
+					int product_index, int options, int card_idx)
 {
 	struct vortex_private *vp;
 
 #ifdef MODULE
 	/* Allocate and fill new device structure. */
 	int dev_size = sizeof(struct device) +
-		sizeof(struct vortex_private);
-	
+		sizeof(struct vortex_private) + 15;		/* Pad for alignment */
+
 	dev = (struct device *) kmalloc(dev_size, GFP_KERNEL);
 	memset(dev, 0, dev_size);
-	dev->priv = ((void *)dev) + sizeof(struct device);
+	/* Align the Rx and Tx ring entries.  */
+	dev->priv = (void *)(((long)dev + sizeof(struct device) + 15) & ~15);
 	vp = (struct vortex_private *)dev->priv;
 	dev->name = vp->devname; /* An empty string. */
 	dev->base_addr = ioaddr;
@@ -443,28 +656,36 @@
 	dev->init = vortex_probe1;
 	vp->product_name = product_names[product_index];
 	vp->options = options;
+	if (card_idx >= 0) {
+		if (full_duplex[card_idx] >= 0)
+			vp->full_duplex = full_duplex[card_idx];
+	} else
+		vp->full_duplex = (options >= 0 && (options & 0x10) ? 1 : 0);
+
 	if (options >= 0) {
-		vp->media_override = ((options & 7) == 2)  ?  0  :  options & 7;
-		vp->full_duplex = (options & 8) ? 1 : 0;
+		vp->media_override = ((options & 7) == XCVR_10baseTOnly) ?
+			XCVR_10baseT  :  options & 7;
 		vp->bus_master = (options & 16) ? 1 : 0;
 	} else {
 		vp->media_override = 7;
-		vp->full_duplex = 0;
 		vp->bus_master = 0;
 	}
 	ether_setup(dev);
 	vp->next_module = root_vortex_dev;
 	root_vortex_dev = dev;
 	if (register_netdev(dev) != 0)
-		return -EIO;
+		return 0;
 #else  /* not a MODULE */
 	if (dev) {
+		/* Caution: quad-word alignment required for rings! */
 		dev->priv = kmalloc(sizeof (struct vortex_private), GFP_KERNEL);
 		memset(dev->priv, 0, sizeof (struct vortex_private));
 	}
 	dev = init_etherdev(dev, sizeof(struct vortex_private));
 	dev->base_addr = ioaddr;
 	dev->irq = irq;
+	dev->mtu = mtu;
+
 	vp  = (struct vortex_private *)dev->priv;
 	vp->product_name = product_names[product_index];
 	vp->options = options;
@@ -480,13 +701,14 @@
 
 	vortex_probe1(dev);
 #endif /* MODULE */
-	return 0;
+	return dev;
 }
 
-__initfunc(static int vortex_probe1(struct device *dev))
+static int vortex_probe1(struct device *dev)
 {
 	int ioaddr = dev->base_addr;
 	struct vortex_private *vp = (struct vortex_private *)dev->priv;
+	unsigned int eeprom[0x40], checksum = 0;		/* EEPROM contents */
 	int i;
 
 	printk("%s: 3Com %s at %#3x,", dev->name,
@@ -494,27 +716,33 @@
 
 	/* Read the station address from the EEPROM. */
 	EL3WINDOW(0);
-	for (i = 0; i < 3; i++) {
+	for (i = 0; i < 0x18; i++) {
 		short *phys_addr = (short *)dev->dev_addr;
 		int timer;
-		outw(EEPROM_Read + PhysAddr01 + i, ioaddr + Wn0EepromCmd);
+		outw(EEPROM_Read + i, ioaddr + Wn0EepromCmd);
 		/* Pause for at least 162 us. for the read to take place. */
-		for (timer = 162*4 + 400; timer >= 0; timer--) {
-			udelay(1);
+		for (timer = 4; timer >= 0; timer--) {
+			udelay(162);
 			if ((inw(ioaddr + Wn0EepromCmd) & 0x8000) == 0)
 				break;
 		}
-		phys_addr[i] = htons(inw(ioaddr + Wn0EepromData));
+		eeprom[i] = inw(ioaddr + Wn0EepromData);
+		checksum ^= eeprom[i];
+		if (i >= 10 && i < 13)
+			phys_addr[i - 10] = htons(inw(ioaddr + Wn0EepromData));
 	}
+	checksum = (checksum ^ (checksum >> 8)) & 0xff;
+	if (checksum != 0x00)
+		printk(" ***INVALID CHECKSUM %4.4x*** ", checksum);
 	for (i = 0; i < 6; i++)
 		printk("%c%2.2x", i ? ':' : ' ', dev->dev_addr[i]);
 	printk(", IRQ %d\n", dev->irq);
 	/* Tell them about an invalid IRQ. */
-	if (vortex_debug && (dev->irq <= 0 || dev->irq > 15))
-		printk(" *** Warning: this IRQ is unlikely to work!\n");
+	if (vortex_debug && (dev->irq <= 0 || dev->irq >= NR_IRQS))
+		printk(" *** Warning: this IRQ is unlikely to work! ***\n");
 
 	{
-		char *ram_split[] = {"5:3", "3:1", "1:1", "invalid"};
+		char *ram_split[] = {"5:3", "3:1", "1:1", "3:5"};
 		union wn3_config config;
 		EL3WINDOW(3);
 		vp->available_media = inw(ioaddr + Wn3_Options);
@@ -532,8 +760,46 @@
 		vp->default_media = config.u.xcvr;
 		vp->autoselect = config.u.autoselect;
 	}
+	if (vp->media_override != 7) {
+		printk("  Media override to transceiver type %d (%s).\n",
+			   vp->media_override, media_tbl[vp->media_override].name);
+		dev->if_port = vp->media_override;
+	}
 
-	/* We do a request_region() only to register /proc/ioports info. */
+	if (dev->if_port == XCVR_MII) {
+		int phy, phy_idx = 0;
+		EL3WINDOW(4);
+		for (phy = 0; phy < 32 && phy_idx < sizeof(vp->phys); phy++) {
+			int mii_status;
+			mdio_sync(ioaddr, 32);
+			mii_status = mdio_read(ioaddr, phy, 0);
+			if (mii_status != 0xffff) {
+				vp->phys[phy_idx++] = phy;
+				printk("%s: MII transceiver found at address %d.\n",
+					   dev->name, phy);
+				mdio_sync(ioaddr, 32);
+				if ((mdio_read(ioaddr, phy, 1) & 0x0040) == 0)
+					mii_preamble_required = 1;
+			}
+		}
+		if (phy_idx == 0) {
+			printk("%s: ***WARNING*** No MII transceivers found!\n",
+				   dev->name);
+			vp->phys[0] = 0;
+		}
+	}
+
+	vp->info1 = eeprom[13];
+	vp->info2 = eeprom[15];
+	vp->capabilities = eeprom[16];
+	if ((vp->capabilities & 0x20) && vp->bus_master) {
+	  vp->full_bus_master_tx = 1;
+	  printk("  Enabling bus-master transmits and %s receives.\n",
+			 (vp->info2 & 1) ? "early" : "whole-frame" );
+	  vp->full_bus_master_rx = (vp->info2 & 1) ? 1 : 2;
+	}
+
+	/* We do a request_region() to register /proc/ioports info. */
 	request_region(ioaddr, VORTEX_TOTAL_SIZE, vp->product_name);
 
 	/* The 3c59x-specific entries in the device structure. */
@@ -541,10 +807,97 @@
 	dev->hard_start_xmit = &vortex_start_xmit;
 	dev->stop = &vortex_close;
 	dev->get_stats = &vortex_get_stats;
+#ifdef HAVE_PRIVATE_IOCTL
+	dev->do_ioctl = &vortex_ioctl;
+#endif
+#ifdef NEW_MULTICAST
 	dev->set_multicast_list = &set_rx_mode;
+#else
+	dev->set_multicast_list = &set_multicast_list;
+#endif
 
 	return 0;
 }
+
+/* Read and write the MII registers using software-generated serial
+   MDIO protocol.  The maxium data clock rate is 2.5 Mhz. */
+#define mdio_delay() udelay(1)
+
+#define MDIO_SHIFT_CLK	0x01
+#define MDIO_DIR_WRITE	0x04
+#define MDIO_DATA_WRITE0 (0x00 | MDIO_DIR_WRITE)
+#define MDIO_DATA_WRITE1 (0x02 | MDIO_DIR_WRITE)
+#define MDIO_DATA_READ	0x02
+#define MDIO_ENB_IN		0x00
+
+static void mdio_sync(int ioaddr, int bits)
+{
+	int mdio_addr = ioaddr + Wn4_PhysicalMgmt;
+
+	/* Establish sync by sending at least 32 logic ones. */ 
+	while (-- bits >= 0) {
+		outw(MDIO_DATA_WRITE1, mdio_addr);
+		mdio_delay();
+		outw(MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr);
+		mdio_delay();
+	}
+}
+static int mdio_read(int ioaddr, int phy_id, int location)
+{
+	int i;
+	int read_cmd = (0xf6 << 10) | (phy_id << 5) | location;
+	unsigned int retval = 0;
+	int mdio_addr = ioaddr + Wn4_PhysicalMgmt;
+
+	if (mii_preamble_required)
+		mdio_sync(ioaddr, 32);
+
+	/* Shift the read command bits out. */
+	for (i = 14; i >= 0; i--) {
+		int dataval = (read_cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;
+		outw(dataval, mdio_addr);
+		mdio_delay();
+		outw(dataval | MDIO_SHIFT_CLK, mdio_addr);
+		mdio_delay();
+	}
+	/* Read the two transition, 16 data, and wire-idle bits. */
+	for (i = 19; i > 0; i--) {
+		outw(MDIO_ENB_IN, mdio_addr);
+		mdio_delay();
+		retval = (retval << 1) | ((inw(mdio_addr) & MDIO_DATA_READ) ? 1 : 0);
+		outw(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
+		mdio_delay();
+	}
+	return retval>>1 & 0xffff;
+}
+
+static void mdio_write(int ioaddr, int phy_id, int location, int value)
+{
+	int write_cmd = 0x50020000 | (phy_id << 23) | (location << 18) | value;
+	int mdio_addr = ioaddr + Wn4_PhysicalMgmt;
+	int i;
+
+	if (mii_preamble_required)
+		mdio_sync(ioaddr, 32);
+
+	/* Shift the command bits out. */
+	for (i = 31; i >= 0; i--) {
+		int dataval = (write_cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;
+		outw(dataval, mdio_addr);
+		mdio_delay();
+		outw(dataval | MDIO_SHIFT_CLK, mdio_addr);
+		mdio_delay();
+	}
+	/* Leave the interface idle. */
+	for (i = 1; i >= 0; i--) {
+		outw(MDIO_ENB_IN, mdio_addr);
+		mdio_delay();
+		outw(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
+		mdio_delay();
+	}
+
+	return;
+}
 
 
 static int
@@ -557,8 +910,6 @@
 
 	/* Before initializing select the active media port. */
 	EL3WINDOW(3);
-	if (vp->full_duplex)
-		outb(0x20, ioaddr + Wn3_MAC_Ctrl); /* Set the full-duplex bit. */
 	config.i = inl(ioaddr + Wn3_Config);
 
 	if (vp->media_override != 7) {
@@ -569,7 +920,7 @@
 		dev->if_port = vp->media_override;
 	} else if (vp->autoselect) {
 		/* Find first available media type, starting with 100baseTx. */
-		dev->if_port = 4;
+		dev->if_port = XCVR_100baseTx;
 		while (! (vp->available_media & media_tbl[dev->if_port].mask))
 			dev->if_port = media_tbl[dev->if_port].next;
 
@@ -588,6 +939,30 @@
 	config.u.xcvr = dev->if_port;
 	outl(config.i, ioaddr + Wn3_Config);
 
+	if (dev->if_port == XCVR_MII) {
+		int mii_reg1, mii_reg5;
+		/* We cheat here: we know that we are using the 83840 transceiver
+		   which summarizes the FD status in an extended register. */
+		EL3WINDOW(4);
+		/* Read BMSR (reg1) only to clear old status. */
+		mii_reg1 = mdio_read(ioaddr, vp->phys[0], 1);
+		mii_reg5 = mdio_read(ioaddr, vp->phys[0], 5);
+		if (mii_reg5 == 0xffff  ||  mii_reg5 == 0x0000)
+			;					/* No MII device or no link partner report */
+		else if ((mii_reg5 & 0x0100) != 0	/* 100baseTx-FD */
+				 || (mii_reg5 & 0x00C0) == 0x0040) /* 10T-FD, but not 100-HD */
+			vp->full_duplex = 1;
+		if (vortex_debug > 1)
+			printk("%s: MII #%d status %4.4x, link partner capability %4.4x,"
+				   " setting %s-duplex.\n", dev->name, vp->phys[0],
+				   mii_reg1, mii_reg5, vp->full_duplex ? "full" : "half");
+		EL3WINDOW(3);
+	}
+
+	/* Set the full-duplex bit. */
+	outb(((vp->info1 & 0x8000) || vp->full_duplex ? 0x20 : 0) |
+		 (dev->mtu > 1500 ? 0x40 : 0), ioaddr + Wn3_MAC_Ctrl);
+
 	if (vortex_debug > 1) {
 		printk("%s: vortex_open() InternalConfig %8.8x.\n",
 			dev->name, config.i);
@@ -595,22 +970,32 @@
 
 	outw(TxReset, ioaddr + EL3_CMD);
 	for (i = 20; i >= 0 ; i--)
-		if ( ! inw(ioaddr + EL3_STATUS) & CmdInProgress)
+		if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
 			break;
 
 	outw(RxReset, ioaddr + EL3_CMD);
 	/* Wait a few ticks for the RxReset command to complete. */
 	for (i = 20; i >= 0 ; i--)
-		if ( ! inw(ioaddr + EL3_STATUS) & CmdInProgress)
+		if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
 			break;
 
 	outw(SetStatusEnb | 0x00, ioaddr + EL3_CMD);
 
+#ifdef SA_SHIRQ
 	/* Use the now-standard shared IRQ implementation. */
 	if (request_irq(dev->irq, &vortex_interrupt, SA_SHIRQ,
 					vp->product_name, dev)) {
 		return -EAGAIN;
 	}
+#else
+	if (dev->irq == 0  ||  irq2dev_map[dev->irq] != NULL)
+		return -EAGAIN;
+	irq2dev_map[dev->irq] = dev;
+	if (request_irq(dev->irq, &vortex_interrupt, 0, vp->product_name)) {
+		irq2dev_map[dev->irq] = NULL;
+		return -EAGAIN;
+	}
+#endif
 
 	if (vortex_debug > 1) {
 		EL3WINDOW(4);
@@ -625,7 +1010,7 @@
 	for (; i < 12; i+=2)
 		outw(0, ioaddr + i);
 
-	if (dev->if_port == 3)
+	if (dev->if_port == XCVR_10base2)
 		/* Start the thinnet transceiver. We should really wait 50ms...*/
 		outw(StartCoax, ioaddr + EL3_CMD);
 	EL3WINDOW(4);
@@ -635,18 +1020,52 @@
 	/* Switch to the stats window, and clear all stats by reading. */
 	outw(StatsDisable, ioaddr + EL3_CMD);
 	EL3WINDOW(6);
-	for (i = 0; i < 10; i++)	
+	for (i = 0; i < 10; i++)
 		inb(ioaddr + i);
 	inw(ioaddr + 10);
 	inw(ioaddr + 12);
 	/* New: On the Vortex we must also clear the BadSSD counter. */
 	EL3WINDOW(4);
 	inb(ioaddr + 12);
+	/* ..and on the Boomerang we enable the extra statistics bits. */
+	outw(0x0040, ioaddr + Wn4_NetDiag);
 
 	/* Switch to register set 7 for normal use. */
 	EL3WINDOW(7);
 
-	/* Set receiver mode: presumably accept b-case and phys addr only. */
+	if (vp->full_bus_master_rx) { /* Boomerang bus master. */
+		vp->cur_rx = vp->dirty_rx = 0;
+		/* Initialize the RxEarly register as recommended. */
+		outw(SetRxThreshold + (1536>>2), ioaddr + EL3_CMD);
+		outl(0x0020, ioaddr + PktStatus);
+		if (vortex_debug > 2)
+			printk("%s:  Filling in the Rx ring.\n", dev->name);
+		for (i = 0; i < RX_RING_SIZE; i++) {
+			struct sk_buff *skb;
+			vp->rx_ring[i].next = virt_to_bus(&vp->rx_ring[i+1]);
+			vp->rx_ring[i].status = 0;	/* Clear complete bit. */
+			vp->rx_ring[i].length = PKT_BUF_SZ | LAST_FRAG;
+			skb = dev_alloc_skb(PKT_BUF_SZ);
+			vp->rx_skbuff[i] = skb;
+			if (skb == NULL)
+				break;			/* Bad news!  */
+			skb->dev = dev;			/* Mark as being used by this device. */
+			skb_reserve(skb, 2);	/* Align IP on 16 byte boundaries */
+			vp->rx_ring[i].addr = virt_to_bus(skb->tail);
+		}
+		vp->rx_ring[i-1].next = virt_to_bus(&vp->rx_ring[0]); /* Wrap the ring. */
+		outl(virt_to_bus(&vp->rx_ring[0]), ioaddr + UpListPtr);
+	}
+	if (vp->full_bus_master_tx) { 		/* Boomerang bus master Tx. */
+		dev->hard_start_xmit = &boomerang_start_xmit;
+		vp->cur_tx = vp->dirty_tx = 0;
+		outb(PKT_BUF_SZ>>8, ioaddr + TxFreeThreshold); /* Room for a packet. */
+		/* Clear the Tx ring. */
+		for (i = 0; i < TX_RING_SIZE; i++)
+			vp->tx_skbuff[i] = 0;
+		outl(0, ioaddr + DownListPtr);
+	}
+	/* Set reciever mode: presumably accept b-case and phys addr only. */
 	set_rx_mode(dev);
 	outw(StatsEnable, ioaddr + EL3_CMD); /* Turn on statistics. */
 
@@ -657,12 +1076,18 @@
 	outw(RxEnable, ioaddr + EL3_CMD); /* Enable the receiver. */
 	outw(TxEnable, ioaddr + EL3_CMD); /* Enable transmitter. */
 	/* Allow status bits to be seen. */
-	outw(SetStatusEnb | 0xff, ioaddr + EL3_CMD);
+	outw(SetStatusEnb | AdapterFailure|IntReq|StatsFull|TxComplete|
+		 (vp->full_bus_master_tx ? DownComplete : TxAvailable) |
+		 (vp->full_bus_master_rx ? UpComplete : RxComplete) |
+		 (vp->bus_master ? DMADone : 0),
+		 ioaddr + EL3_CMD);
 	/* Ack all pending events, and set active indicator mask. */
 	outw(AckIntr | IntLatch | TxAvailable | RxEarly | IntReq,
 		 ioaddr + EL3_CMD);
 	outw(SetIntrEnb | IntLatch | TxAvailable | RxComplete | StatsFull
-		 | DMADone, ioaddr + EL3_CMD);
+		 | AdapterFailure | TxComplete
+		 | (vp->bus_master ? DMADone : 0) | UpComplete | DownComplete,
+			ioaddr + EL3_CMD);
 
 	MOD_INC_USE_COUNT;
 
@@ -688,7 +1113,7 @@
 	  EL3WINDOW(4);
 	  media_status = inw(ioaddr + Wn4_Media);
 	  switch (dev->if_port) {
-	  case 0:  case 4:  case 5:		/* 10baseT, 100baseTX, 100baseFX  */
+	  case XCVR_10baseT:  case XCVR_100baseTx:  case XCVR_100baseFx:
 		if (media_status & Media_LnkBeat) {
 		  ok = 1;
 		  if (vortex_debug > 1)
@@ -697,8 +1122,20 @@
 		} else if (vortex_debug > 1)
 		  printk("%s: Media %s is has no link beat, %x.\n",
 				   dev->name, media_tbl[dev->if_port].name, media_status);
- 
+
 		break;
+	  case XCVR_MII:
+		  {
+			  int mii_reg1 = mdio_read(ioaddr, vp->phys[0], 1);
+			  int mii_reg5 = mdio_read(ioaddr, vp->phys[0], 5);
+			  if (vortex_debug > 1)
+				  printk("%s: MII #%d status register is %4.4x, "
+						 "link partner capability %4.4x.\n",
+						 dev->name, vp->phys[0], mii_reg1, mii_reg5);
+			  if (mii_reg1 & 0x0004)
+				  ok = 1;
+			  break;
+		  }
 	  default:					/* Other media types handled by Tx timeouts. */
 		if (vortex_debug > 1)
 		  printk("%s: Media %s is has no indication, %x.\n",
@@ -711,7 +1148,7 @@
 		do {
 			dev->if_port = media_tbl[dev->if_port].next;
 		} while ( ! (vp->available_media & media_tbl[dev->if_port].mask));
-		if (dev->if_port == 8) { /* Go back to default. */
+		if (dev->if_port == XCVR_Default) { /* Go back to default. */
 		  dev->if_port = vp->default_media;
 		  if (vortex_debug > 1)
 			printk("%s: Media selection failing, using default %s port.\n",
@@ -731,7 +1168,8 @@
 		config.u.xcvr = dev->if_port;
 		outl(config.i, ioaddr + Wn3_Config);
 
-		outw(dev->if_port == 3 ? StartCoax : StopCoax, ioaddr + EL3_CMD);
+		outw(dev->if_port == XCVR_10base2 ? StartCoax : StopCoax,
+			 ioaddr + EL3_CMD);
 	  }
 	  EL3WINDOW(old_window);
 	}   restore_flags(flags);
@@ -743,66 +1181,118 @@
 	return;
 }
 
-static int
-vortex_start_xmit(struct sk_buff *skb, struct device *dev)
+static void vortex_tx_timeout(struct device *dev)
 {
 	struct vortex_private *vp = (struct vortex_private *)dev->priv;
 	int ioaddr = dev->base_addr;
+	int i;
 
-	/* Part of the following code is inspired by code from Giuseppe Ciaccio,
-	   ciaccio@disi.unige.it.
-	   It works around a ?bug? in the 8K Vortex that only occurs on some
-	   systems: the TxAvailable interrupt seems to be lost.
-	   The ugly work-around is to busy-wait for room available in the Tx
-	   buffer before deciding the transmitter is actually hung.
-	   This busy-wait should never really occur, since the problem is that
-	   there actually *is*  room in the Tx FIFO.
-
-	   This pointed out an optimization -- we can ignore dev->tbusy if
-	   we actually have room for this packet.
-	   */
-
-#if 0
-	/* unstable optimization */
-	if (inw(ioaddr + TxFree) > skb->len) /* We actually have free room. */
-	  dev->tbusy = 0;			/* Fake out the check below. */
-	else
-#endif
-	if (dev->tbusy) {
-		/* Transmitter timeout, serious problems. */
-		int tickssofar = jiffies - dev->trans_start;
-		int i;
-
-		if (tickssofar < 2)		/* We probably aren't empty. */
-			return 1;
-		/* Wait a while to see if there really is room. */
-		for (i = WAIT_TX_AVAIL; i >= 0; i--)
-			if (inw(ioaddr + TxFree) > skb->len)
-			  break;
-		if ( i < 0) {
-			if (tickssofar < TX_TIMEOUT)
-				return 1;
-			printk("%s: transmit timed out, tx_status %2.2x status %4.4x.\n",
-				   dev->name, inb(ioaddr + TxStatus), inw(ioaddr + EL3_STATUS));
-			/* Issue TX_RESET and TX_START commands. */
-			outw(TxReset, ioaddr + EL3_CMD);
-			for (i = 20; i >= 0 ; i--)
-				if ( ! inw(ioaddr + EL3_STATUS) & CmdInProgress)                                        break;
-			outw(TxEnable, ioaddr + EL3_CMD);
-			dev->trans_start = jiffies;
-			dev->tbusy = 0;
-			vp->stats.tx_errors++;
+	printk("%s: transmit timed out, tx_status %2.2x status %4.4x.\n",
+		   dev->name, inb(ioaddr + TxStatus),
+		   inw(ioaddr + EL3_STATUS));
+	/* Slight code bloat to be user friendly. */
+	if ((inb(ioaddr + TxStatus) & 0x88) == 0x88)
+		printk("%s: Transmitter encountered 16 collisions --"
+			   " network cable problem?\n", dev->name);
+	if (inw(ioaddr + EL3_STATUS) & IntLatch) {
+		printk("%s: Interrupt posted but not handled --"
+			   " IRQ blocked by another device?\n", dev->name);
+		/* Bad idea here.. but we might as well handle a few events. */
+		vortex_interrupt IRQ(dev->irq, dev, 0);
+	}
+#ifndef final_version
+	if (vp->full_bus_master_tx) {
+		printk("  Flags; bus-master %d, full %d; dirty %d current %d.\n",
+			   vp->full_bus_master_tx, vp->tx_full, vp->dirty_tx, vp->cur_tx);
+		printk("  Transmit list %8.8x vs. %p.\n", inl(ioaddr + DownListPtr),
+			   &vp->tx_ring[vp->dirty_tx % TX_RING_SIZE]);
+		for (i = 0; i < TX_RING_SIZE; i++) {
+			printk("  %d: @%p  length %8.8x status %8.8x\n", i,
+				   &vp->tx_ring[i],
+				   vp->tx_ring[i].length,
+				   vp->tx_ring[i].status);
+		}
+	}
+#ifdef notdef
+	if (vp->full_bus_master_rx) {
+		printk("  Switching to non-bus-master receives.\n");
+		outw(SetStatusEnb | AdapterFailure|IntReq|StatsFull |
+			 (vp->full_bus_master_tx ? DownComplete : TxAvailable) |
+			 RxComplete | (vp->bus_master ? DMADone : 0),
+			 ioaddr + EL3_CMD);
+	}
+	/* Issue TX_RESET and TX_START commands. */
+	outw(TxReset, ioaddr + EL3_CMD);
+	for (i = 20; i >= 0 ; i--)
+	  if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
+		break;
+#endif
+#endif
+	if (vp->full_bus_master_tx) {
+	  /*  Change 6/25/97 Michael Sievers sieversm@mail.desy.de
+              The card has been resetted, but the Tx Ring is still full.
+		 Since the card won't know where to resume, 'update' the
+		 Tx Ring. Probably, we'll lose 16 packets this way, these
+		 will be accounted for as 'dropped'. The code to update the
+		 Tx Ring is taken from the Interrupt handler. */
+   
+	  unsigned int dirty_tx = vp->dirty_tx;
+	  
+	  if (vortex_debug > 0)
+		  printk("%s: Freeing Tx ring entries:", dev->name);
+	  while (vp->cur_tx - dirty_tx > 0) {
+		int entry = dirty_tx % TX_RING_SIZE;
+		if (inl(ioaddr + DownListPtr) ==
+			virt_to_bus(&vp->tx_ring[entry]))
+		  break;			/* It still hasn't been processed. */
+		if (vp->tx_skbuff[entry]) {
+			if (vortex_debug > 0)
+				printk(" %d\n", entry);
+			dev_kfree_skb(vp->tx_skbuff[entry], FREE_WRITE);
+			vp->tx_skbuff[entry] = 0;
 			vp->stats.tx_dropped++;
-			return 0;			/* Yes, silently *drop* the packet! */
 		}
-		dev->tbusy = 0;
+		if (vortex_debug > 0)
+			printk(".\n");
+		vp->stats.tx_errors++;
+		dirty_tx++;
+	  }
+	  vp->dirty_tx = dirty_tx;
+	  vp->tx_full= 0;
+	} else {     /* not bus-master, no Tx ring to clear */
+	  vp->stats.tx_errors++;
+	  vp->stats.tx_dropped++;
+	}
+	
+	/* Issue Tx Enable */
+	outw(TxEnable, ioaddr + EL3_CMD);
+	dev->trans_start = jiffies;
+	
+	/* Switch to register set 7 for normal use. */
+	EL3WINDOW(7);
+	
+	/* The TxFreeThreshold has to be set again after a reset! */
+	if (vp->full_bus_master_tx) {  
+	  outb(PKT_BUF_SZ>>8, ioaddr + TxFreeThreshold);
+	  /* This is to be sure that all bus-master Tx features
+		 are correctly re-initialized after a reset, although
+		 the DownListPtr should already be 0 at this point. */
+	  outl(0, ioaddr + DownListPtr);
 	}
+	/* finally, allow new Transmits */
+	dev->tbusy = 0;
+	/* End of Michael Sievers <sieversm@mail.desy.de> changes. */
+}
+
+static int
+vortex_start_xmit(struct sk_buff *skb, struct device *dev)
+{
+	struct vortex_private *vp = (struct vortex_private *)dev->priv;
+	int ioaddr = dev->base_addr;
 
-	/* Block a timer-based transmit from overlapping.  This could better be
-	   done with atomic_swap(1, dev->tbusy), but set_bit() works as well.
-	   If this ever occurs the queue layer is doing something evil! */
 	if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
-		printk("%s: Transmitter access conflict.\n", dev->name);
+		if (jiffies - dev->trans_start >= TX_TIMEOUT)
+			vortex_tx_timeout(dev);
 		return 1;
 	}
 
@@ -855,7 +1345,7 @@
 					int j;
 					outw(TxReset, ioaddr + EL3_CMD);
 					for (j = 20; j >= 0 ; j--)
-						if ( ! inw(ioaddr + EL3_STATUS) & CmdInProgress)
+						if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
 							break;
 				}
 				outw(TxEnable, ioaddr + EL3_CMD);
@@ -866,16 +1356,80 @@
 	return 0;
 }
 
+static int
+boomerang_start_xmit(struct sk_buff *skb, struct device *dev)
+{
+	struct vortex_private *vp = (struct vortex_private *)dev->priv;
+	int ioaddr = dev->base_addr;
+
+	if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
+		if (jiffies - dev->trans_start >= TX_TIMEOUT)
+			vortex_tx_timeout(dev);
+		return 1;
+	} else {
+		/* Calculate the next Tx descriptor entry. */
+		int entry = vp->cur_tx % TX_RING_SIZE;
+		struct boom_tx_desc *prev_entry =
+			&vp->tx_ring[(vp->cur_tx-1) % TX_RING_SIZE];
+		unsigned long flags;
+		int i;
+
+		if (vortex_debug > 3)
+			printk("%s: Trying to send a packet, Tx index %d.\n",
+				   dev->name, vp->cur_tx);
+		if (vp->tx_full) {
+			if (vortex_debug >0)
+				printk("%s: Tx Ring full, refusing to send buffer.\n",
+					   dev->name);
+			return 1;
+		} 
+		/* end change 06/25/97 M. Sievers */	
+		vp->tx_skbuff[entry] = skb;
+		vp->tx_ring[entry].next = 0;
+		vp->tx_ring[entry].addr = virt_to_bus(skb->data);
+		vp->tx_ring[entry].length = skb->len | LAST_FRAG;
+		vp->tx_ring[entry].status = skb->len | TxIntrUploaded;
+
+		save_flags(flags);
+		cli();
+		outw(DownStall, ioaddr + EL3_CMD);
+		/* Wait for the stall to complete. */
+		for (i = 60; i >= 0 ; i--)
+			if ( (inw(ioaddr + EL3_STATUS) & CmdInProgress) == 0)
+				break;
+		prev_entry->next = virt_to_bus(&vp->tx_ring[entry]);
+		if (inl(ioaddr + DownListPtr) == 0) {
+			outl(virt_to_bus(&vp->tx_ring[entry]), ioaddr + DownListPtr);
+			queued_packet++;
+		}
+		outw(DownUnstall, ioaddr + EL3_CMD);
+		restore_flags(flags);
+
+		vp->cur_tx++;
+		if (vp->cur_tx - vp->dirty_tx > TX_RING_SIZE - 1)
+			vp->tx_full = 1;
+		else {					/* Clear previous interrupt enable. */
+			prev_entry->status &= ~TxIntrUploaded;
+			dev->tbusy = 0;
+		}
+		dev->trans_start = jiffies;
+		return 0;
+	}
+}
+
 /* The interrupt handler does all of the Rx thread work and cleans up
    after the Tx thread. */
 static void vortex_interrupt IRQ(int irq, void *dev_id, struct pt_regs *regs)
 {
-	/* Use the now-standard shared IRQ implementation. */
+#ifdef SA_SHIRQ		/* Use the now-standard shared IRQ implementation. */
 	struct device *dev = dev_id;
+#else
+	struct device *dev = (struct device *)(irq2dev_map[irq]);
+#endif
 	struct vortex_private *lp;
 	int ioaddr, status;
 	int latency;
-	int i = 0;
+	int i = max_interrupt_work;
 
 	if (dev->interrupt)
 		printk("%s: Re-entering the interrupt handler.\n", dev->name);
@@ -890,17 +1444,20 @@
 	if (vortex_debug > 4)
 		printk("%s: interrupt, status %4.4x, timer %d.\n", dev->name,
 			   status, latency);
-	if ((status & 0xE000) != 0xE000) {
+#ifdef notdef
+	/* This code guard against bogus hangs, but fails with shared IRQs. */
+	if ((status & ~0xE000) == 0x0000) {
 		static int donedidthis=0;
 		/* Some interrupt controllers store a bogus interrupt from boot-time.
 		   Ignore a single early interrupt, but don't hang the machine for
 		   other interrupt problems. */
-		if (donedidthis++ > 1) {
+		if (donedidthis++ > 100) {
 			printk("%s: Bogus interrupt, bailing. Status %4.4x, start=%d.\n",
 				   dev->name, status, dev->start);
 			FREE_IRQ(dev->irq, dev);
 		}
 	}
+#endif
 
 	do {
 		if (vortex_debug > 5)
@@ -917,13 +1474,53 @@
 			dev->tbusy = 0;
 			mark_bh(NET_BH);
 		}
+		if (status & TxComplete) { /* Really "TxError" for us. */
+			unsigned char tx_status = inb(ioaddr + TxStatus);
+			/* Presumably a tx-timeout. We must merely re-enable. */
+			if (vortex_debug > 2
+				|| (tx_status != 0x88 && vortex_debug > 0))
+				printk("%s: Transmit error, Tx status register %2.2x.\n",
+					   dev->name, tx_status);
+			if (tx_status & 0x04) lp->stats.tx_fifo_errors++;
+			if (tx_status & 0x38) lp->stats.tx_aborted_errors++;
+			outb(0, ioaddr + TxStatus);
+			outw(TxEnable, ioaddr + EL3_CMD);
+		}
+		if (status & DownComplete) {
+			unsigned int dirty_tx = lp->dirty_tx;
+
+			while (lp->cur_tx - dirty_tx > 0) {
+				int entry = dirty_tx % TX_RING_SIZE;
+				if (inl(ioaddr + DownListPtr) ==
+					virt_to_bus(&lp->tx_ring[entry]))
+					break;			/* It still hasn't been processed. */
+				if (lp->tx_skbuff[entry]) {
+					dev_kfree_skb(lp->tx_skbuff[entry], FREE_WRITE);
+					lp->tx_skbuff[entry] = 0;
+				}
+				/* lp->stats.tx_packets++;  Counted below. */
+				dirty_tx++;
+			}
+			lp->dirty_tx = dirty_tx;
+			outw(AckIntr | DownComplete, ioaddr + EL3_CMD);
+			if (lp->tx_full && (lp->cur_tx - dirty_tx <= TX_RING_SIZE - 1)) {
+				lp->tx_full= 0;
+				dev->tbusy = 0;
+				mark_bh(NET_BH);
+			}
+		}
 #ifdef VORTEX_BUS_MASTER
 		if (status & DMADone) {
 			outw(0x1000, ioaddr + Wn7_MasterStatus); /* Ack the event. */
 			dev->tbusy = 0;
+			dev_kfree_skb (lp->tx_skb, FREE_WRITE); /* Release the transfered buffer */
 			mark_bh(NET_BH);
 		}
 #endif
+		if (status & UpComplete) {
+			boomerang_rx(dev);
+			outw(AckIntr | UpComplete, ioaddr + EL3_CMD);
+		}
 		if (status & (AdapterFailure | RxEarly | StatsFull)) {
 			/* Handle all uncommon interrupts at once. */
 			if (status & RxEarly) {				/* Rx early is unused. */
@@ -949,27 +1546,45 @@
 							printk(" %2.2x", inb(ioaddr+reg));
 					}
 					EL3WINDOW(7);
-					outw(SetIntrEnb | 0x18, ioaddr + EL3_CMD);
+					outw(SetIntrEnb | TxAvailable | RxComplete | AdapterFailure
+						 | UpComplete | DownComplete | TxComplete,
+						 ioaddr + EL3_CMD);
 					DoneDidThat++;
 				}
 			}
 			if (status & AdapterFailure) {
-				/* Adapter failure requires Rx reset and reinit. */
-				outw(RxReset, ioaddr + EL3_CMD);
-				/* Set the Rx filter to the current state. */
-				set_rx_mode(dev);
-				outw(RxEnable, ioaddr + EL3_CMD); /* Re-enable the receiver. */
-				outw(AckIntr | AdapterFailure, ioaddr + EL3_CMD);
+				u16 fifo_diag;
+				EL3WINDOW(4);
+				fifo_diag = inw(ioaddr + Wn4_FIFODiag);
+				if (vortex_debug > 0)
+					printk("%s: Host error, FIFO diagnostic register %4.4x.\n",
+						   dev->name, fifo_diag);
+				/* Adapter failure requires Tx/Rx reset and reinit. */
+				if (fifo_diag & 0x0400) {
+					int j;
+					outw(TxReset, ioaddr + EL3_CMD);
+					for (j = 20; j >= 0 ; j--)
+						if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
+							break;
+					outw(TxEnable, ioaddr + EL3_CMD);
+				}
+				if (fifo_diag & 0x2000) {
+					outw(RxReset, ioaddr + EL3_CMD);
+					/* Set the Rx filter to the current state. */
+					set_rx_mode(dev);
+					outw(RxEnable, ioaddr + EL3_CMD); /* Re-enable the receiver. */
+					outw(AckIntr | AdapterFailure, ioaddr + EL3_CMD);
+				}
 			}
 		}
 
-		if (++i > 10) {
-			printk("%s: Infinite loop in interrupt, status %4.4x.  "
+		if (--i < 0) {
+			printk("%s: Too much work in interrupt, status %4.4x.  "
 				   "Disabling functions (%4.4x).\n",
-				   dev->name, status, SetStatusEnb | ((~status) & 0xFE));
+				   dev->name, status, SetStatusEnb | ((~status) & 0x7FE));
 			/* Disable all pending interrupts. */
-			outw(SetStatusEnb | ((~status) & 0xFE), ioaddr + EL3_CMD);
-			outw(AckIntr | 0xFF, ioaddr + EL3_CMD);
+			outw(SetStatusEnb | ((~status) & 0x7FE), ioaddr + EL3_CMD);
+			outw(AckIntr | 0x7FF, ioaddr + EL3_CMD);
 			break;
 		}
 		/* Acknowledge the IRQ. */
@@ -998,7 +1613,7 @@
 	while ((rx_status = inw(ioaddr + RxStatus)) > 0) {
 		if (rx_status & 0x4000) { /* Error, update stats. */
 			unsigned char rx_error = inb(ioaddr + RxErrors);
-			if (vortex_debug > 4)
+			if (vortex_debug > 2)
 				printk(" Rx error: status %2.2x.\n", rx_error);
 			vp->stats.rx_errors++;
 			if (rx_error & 0x01)  vp->stats.rx_over_errors++;
@@ -1017,28 +1632,36 @@
 					   pkt_len, rx_status);
 			if (skb != NULL) {
 				skb->dev = dev;
+#if LINUX_VERSION_CODE >= 0x10300
 				skb_reserve(skb, 2);	/* Align IP on 16 byte boundaries */
 				/* 'skb_put()' points to the start of sk_buff data area. */
 				insl(ioaddr + RX_FIFO, skb_put(skb, pkt_len),
 					 (pkt_len + 3) >> 2);
+				outw(RxDiscard, ioaddr + EL3_CMD); /* Pop top Rx packet. */
 				skb->protocol = eth_type_trans(skb, dev);
-				netif_rx(skb);
+#else
+				skb->len = pkt_len;
+				/* 'skb->data' points to the start of sk_buff data area. */
+				insl(ioaddr + RX_FIFO, skb->data, (pkt_len + 3) >> 2);
 				outw(RxDiscard, ioaddr + EL3_CMD); /* Pop top Rx packet. */
+#endif  /* KERNEL_1_3_0 */
+				netif_rx(skb);
+				dev->last_rx = jiffies;
+				vp->stats.rx_packets++;
 				/* Wait a limited time to go to next packet. */
 				for (i = 200; i >= 0; i--)
-					if ( ! inw(ioaddr + EL3_STATUS) & CmdInProgress)
+					if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
 						break;
-				vp->stats.rx_packets++;
 				continue;
 			} else if (vortex_debug)
 				printk("%s: Couldn't allocate a sk_buff of size %d.\n",
 					   dev->name, pkt_len);
 		}
-		vp->stats.rx_dropped++;
 		outw(RxDiscard, ioaddr + EL3_CMD);
+		vp->stats.rx_dropped++;
 		/* Wait a limited time to skip this packet. */
 		for (i = 200; i >= 0; i--)
-			if ( ! inw(ioaddr + EL3_STATUS) & CmdInProgress)
+			if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
 				break;
 	}
 
@@ -1046,17 +1669,111 @@
 }
 
 static int
+boomerang_rx(struct device *dev)
+{
+	struct vortex_private *vp = (struct vortex_private *)dev->priv;
+	int entry = vp->cur_rx % RX_RING_SIZE;
+	int ioaddr = dev->base_addr;
+	int rx_status;
+
+	if (vortex_debug > 5)
+		printk("   In boomerang_rx(), status %4.4x, rx_status %4.4x.\n",
+			   inw(ioaddr+EL3_STATUS), inw(ioaddr+RxStatus));
+	while ((rx_status = vp->rx_ring[entry].status) & RxDComplete) {
+		if (rx_status & RxDError) { /* Error, update stats. */
+			unsigned char rx_error = rx_status >> 16;
+			if (vortex_debug > 2)
+				printk(" Rx error: status %2.2x.\n", rx_error);
+			vp->stats.rx_errors++;
+			if (rx_error & 0x01)  vp->stats.rx_over_errors++;
+			if (rx_error & 0x02)  vp->stats.rx_length_errors++;
+			if (rx_error & 0x04)  vp->stats.rx_frame_errors++;
+			if (rx_error & 0x08)  vp->stats.rx_crc_errors++;
+			if (rx_error & 0x10)  vp->stats.rx_length_errors++;
+		} else {
+			/* The packet length: up to 4.5K!. */
+			short pkt_len = rx_status & 0x1fff;
+			struct sk_buff *skb;
+
+			if (vortex_debug > 4)
+				printk("Receiving packet size %d status %4.4x.\n",
+					   pkt_len, rx_status);
+
+			/* Check if the packet is long enough to just accept without
+			   copying to a properly sized skbuff. */
+			if (pkt_len < rx_copybreak
+				&& (skb = DEV_ALLOC_SKB(pkt_len + 2)) != 0) {
+				skb->dev = dev;
+				skb_reserve(skb, 2);	/* Align IP on 16 byte boundaries */
+				/* 'skb_put()' points to the start of sk_buff data area. */
+				memcpy(skb_put(skb, pkt_len),
+					   bus_to_virt(vp->rx_ring[entry].addr),
+					   pkt_len);
+				rx_copy++;
+			} else{
+				void *temp;
+				/* Pass up the skbuff already on the Rx ring. */
+				skb = vp->rx_skbuff[entry];
+				vp->rx_skbuff[entry] = NULL;
+				temp = skb_put(skb, pkt_len);
+				/* Remove this checking code for final release. */
+				if (bus_to_virt(vp->rx_ring[entry].addr) != temp)
+					printk("%s: Warning -- the skbuff addresses do not match"
+						   " in boomerang_rx: %p vs. %p / %p.\n", dev->name,
+						   bus_to_virt(vp->rx_ring[entry].addr),
+						   skb->head, temp);
+				rx_nocopy++;
+			}
+#if LINUX_VERSION_CODE > 0x10300
+			skb->protocol = eth_type_trans(skb, dev);
+#else
+			skb->len = pkt_len;
+#endif
+			netif_rx(skb);
+			dev->last_rx = jiffies;
+			vp->stats.rx_packets++;
+		}
+		entry = (++vp->cur_rx) % RX_RING_SIZE;
+	}
+	/* Refill the Rx ring buffers. */
+	for (; vp->dirty_rx < vp->cur_rx; vp->dirty_rx++) {
+		struct sk_buff *skb;
+		entry = vp->dirty_rx % RX_RING_SIZE;
+		if (vp->rx_skbuff[entry] == NULL) {
+			skb = dev_alloc_skb(PKT_BUF_SZ);
+			if (skb == NULL)
+				break;			/* Bad news!  */
+			skb->dev = dev;			/* Mark as being used by this device. */
+#if LINUX_VERSION_CODE > 0x10300
+			skb_reserve(skb, 2);	/* Align IP on 16 byte boundaries */
+			vp->rx_ring[entry].addr = virt_to_bus(skb->tail);
+#else
+			vp->rx_ring[entry].addr = virt_to_bus(skb->data);
+#endif
+			vp->rx_skbuff[entry] = skb;
+		}
+		vp->rx_ring[entry].status = 0;	/* Clear complete bit. */
+	}
+	return 0;
+}
+
+static int
 vortex_close(struct device *dev)
 {
 	struct vortex_private *vp = (struct vortex_private *)dev->priv;
 	int ioaddr = dev->base_addr;
+	int i;
 
 	dev->start = 0;
 	dev->tbusy = 1;
 
-	if (vortex_debug > 1)
+	if (vortex_debug > 1) {
 		printk("%s: vortex_close() status %4.4x, Tx status %2.2x.\n",
 			   dev->name, inw(ioaddr + EL3_STATUS), inb(ioaddr + TxStatus));
+		printk("%s: vortex close stats: rx_nocopy %d rx_copy %d"
+			   " tx_queued %d.\n",
+			   dev->name, rx_nocopy, rx_copy, queued_packet);
+	}
 
 	del_timer(&vp->timer);
 
@@ -1067,27 +1784,57 @@
 	outw(RxDisable, ioaddr + EL3_CMD);
 	outw(TxDisable, ioaddr + EL3_CMD);
 
-	if (dev->if_port == 3)
+	if (dev->if_port == XCVR_10base2)
 		/* Turn off thinnet power.  Green! */
 		outw(StopCoax, ioaddr + EL3_CMD);
 
-	FREE_IRQ(dev->irq, dev);
+#ifdef SA_SHIRQ
+	free_irq(dev->irq, dev);
+#else
+	free_irq(dev->irq);
+	irq2dev_map[dev->irq] = 0;
+#endif
+
+	outw(SetIntrEnb | 0x0000, ioaddr + EL3_CMD);
 
 	update_stats(ioaddr, dev);
+	if (vp->full_bus_master_rx) { /* Free Boomerang bus master Rx buffers. */
+		outl(0, ioaddr + UpListPtr);
+		for (i = 0; i < RX_RING_SIZE; i++)
+			if (vp->rx_skbuff[i]) {
+#if LINUX_VERSION_CODE < 0x20100
+				vp->rx_skbuff[i]->free = 1;
+#endif
+				dev_kfree_skb (vp->rx_skbuff[i], FREE_WRITE);
+				vp->rx_skbuff[i] = 0;
+			}
+	}
+	if (vp->full_bus_master_tx) { /* Free Boomerang bus master Tx buffers. */
+		outl(0, ioaddr + DownListPtr);
+		for (i = 0; i < TX_RING_SIZE; i++)
+			if (vp->tx_skbuff[i]) {
+				dev_kfree_skb(vp->tx_skbuff[i], FREE_WRITE);
+				vp->tx_skbuff[i] = 0;
+			}
+	}
+
 	MOD_DEC_USE_COUNT;
 
 	return 0;
 }
 
-static struct net_device_stats *vortex_get_stats(struct device *dev)
+static struct enet_statistics *
+vortex_get_stats(struct device *dev)
 {
 	struct vortex_private *vp = (struct vortex_private *)dev->priv;
 	unsigned long flags;
 
-	save_flags(flags);
-	cli();
-	update_stats(dev->base_addr, dev);
-	restore_flags(flags);
+	if (dev->start) {
+		save_flags(flags);
+		cli();
+		update_stats(dev->base_addr, dev);
+		restore_flags(flags);
+	}
 	return &vp->stats;
 }
 
@@ -1129,6 +1876,37 @@
 	return;
 }
 
+#ifdef HAVE_PRIVATE_IOCTL
+static int vortex_ioctl(struct device *dev, struct ifreq *rq, int cmd)
+{
+	struct vortex_private *vp = (struct vortex_private *)dev->priv;
+	int ioaddr = dev->base_addr;
+	u16 *data = (u16 *)&rq->ifr_data;
+	int phy = vp->phys[0] & 0x1f;
+
+	if (vortex_debug > 2)
+		printk("%s: In ioct(%-.6s, %#4.4x) %4.4x %4.4x %4.4x %4.4x.\n",
+			   dev->name, rq->ifr_ifrn.ifrn_name, cmd,
+			   data[0], data[1], data[2], data[3]);
+
+    switch(cmd) {
+	case SIOCDEVPRIVATE:		/* Get the address of the PHY in use. */
+		data[0] = phy;
+	case SIOCDEVPRIVATE+1:		/* Read the specified MII register. */
+		EL3WINDOW(4);
+		data[3] = mdio_read(ioaddr, data[0] & 0x1f, data[1] & 0x1f);
+		return 0;
+	case SIOCDEVPRIVATE+2:		/* Write the specified MII register */
+		if (!suser())
+			return -EPERM;
+		mdio_write(ioaddr, data[0] & 0x1f, data[1] & 0x1f, data[2]);
+		return 0;
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+#endif  /* HAVE_PRIVATE_IOCTL */
+
 /* This new version of set_rx_mode() supports v1.4 kernels.
    The Vortex chip has no documented multicast filter, so the only
    multicast setting is to receive all multicast frames.  At least
@@ -1145,11 +1923,19 @@
 		new_mode = SetRxFilter|RxStation|RxMulticast|RxBroadcast|RxProm;
 	} else	if ((dev->mc_list)  ||  (dev->flags & IFF_ALLMULTI)) {
 		new_mode = SetRxFilter|RxStation|RxMulticast|RxBroadcast;
-	} else 
+	} else
 		new_mode = SetRxFilter | RxStation | RxBroadcast;
 
 	outw(new_mode, ioaddr + EL3_CMD);
 }
+#ifndef NEW_MULTICAST
+/* The old interface to set the Rx mode. */
+static void
+set_multicast_list(struct device *dev, int num_addrs, void *addrs)
+{
+	set_rx_mode(dev);
+}
+#endif
 
 #ifdef MODULE
 void
@@ -1167,12 +1953,15 @@
 		root_vortex_dev = next_dev;
 	}
 }
-#endif /* MODULE */
+
+#endif  /* MODULE */
 
 /*
  * Local variables:
- *  compile-command: "gcc -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c 3c59x.c -o ../../modules/3c59x.o"
+ *  compile-command: "gcc -DMODVERSIONS -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c59x.c"
  *  c-indent-level: 4
+ *  c-basic-offset: 4
  *  tab-width: 4
  * End:
  */
+
diff -u --recursive --new-file v2.1.72/linux/drivers/net/Config.in linux/drivers/net/Config.in
--- v2.1.72/linux/drivers/net/Config.in	Wed Dec 10 11:12:43 1997
+++ linux/drivers/net/Config.in	Wed Dec 10 09:18:00 1997
@@ -180,7 +180,6 @@
       bool '  WANPIPE Frame Relay support' CONFIG_WANPIPE_FR
       bool '  WANPIPE PPP support' CONFIG_WANPIPE_PPP
     fi
-    dep_tristate 'High-speed (DMA) SCC driver for AX.25' CONFIG_DMASCC $CONFIG_AX25
   fi
 fi
 #
diff -u --recursive --new-file v2.1.72/linux/drivers/net/eth16i.c linux/drivers/net/eth16i.c
--- v2.1.72/linux/drivers/net/eth16i.c	Mon Nov  3 13:04:26 1997
+++ linux/drivers/net/eth16i.c	Wed Dec 10 09:45:16 1997
@@ -265,7 +265,7 @@
 
 
 /* Macro to slow down io between EEPROM clock transitions */
-#define eeprom_slow_io() do { int _i = 40; while(--_i > 0) { __SLOW_DOWN_IO; }}while(0)
+#define eeprom_slow_io() 	udelay(100)	/* FIXME: smaller but right value here */
 
 /* Jumperless Configuration Register (BMPR19) */
 #define JUMPERLESS_CONFIG      19
diff -u --recursive --new-file v2.1.72/linux/drivers/net/hamradio/Config.in linux/drivers/net/hamradio/Config.in
--- v2.1.72/linux/drivers/net/hamradio/Config.in	Wed Dec 10 11:12:44 1997
+++ linux/drivers/net/hamradio/Config.in	Wed Dec 10 09:18:00 1997
@@ -26,6 +26,7 @@
 #     tristate 'Serial port 6PACK driver' CONFIG_6PACK
       tristate 'BPQ Ethernet driver' CONFIG_BPQETHER
     
+      tristate 'High-speed (DMA) SCC driver for AX.25' CONFIG_DMASCC $CONFIG_AX25
       tristate 'Z8530 SCC driver' CONFIG_SCC
       if [ "$CONFIG_SCC" != "n" ]; then
         bool '   additional delay for PA0HZP OptoSCC compatible boards' CONFIG_SCC_DELAY
diff -u --recursive --new-file v2.1.72/linux/drivers/net/hamradio/dmascc.c linux/drivers/net/hamradio/dmascc.c
--- v2.1.72/linux/drivers/net/hamradio/dmascc.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/hamradio/dmascc.c	Wed Dec 10 09:18:00 1997
@@ -0,0 +1,1260 @@
+/*
+ * $Id: dmascc.c,v 1.2 1997/12/02 16:49:49 oe1kib Exp $
+ *
+ * Driver for high-speed SCC boards (those with DMA support)
+ * Copyright (C) 1997 Klaus Kudielka
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+#include <linux/module.h>
+#include <linux/dmascc.h>
+#include <linux/errno.h>
+#include <linux/if_arp.h>
+#include <linux/in.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/netdevice.h>
+#include <linux/sockios.h>
+#include <linux/tqueue.h>
+#include <linux/version.h>
+#include <asm/atomic.h>
+#include <asm/bitops.h>
+#include <asm/dma.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/segment.h>
+#include <asm/uaccess.h>
+#include <net/ax25.h>
+#include <stdio.h>
+#include "z8530.h"
+
+
+/* Number of buffers per channel */
+
+#define NUM_TX_BUF      2          /* NUM_TX_BUF >= 1 (2 recommended) */
+#define NUM_RX_BUF      2          /* NUM_RX_BUF >= 1 (2 recommended) */
+#define BUF_SIZE        2016
+
+
+/* Cards supported */
+
+#define HW_PI           { "Ottawa PI", 0x300, 0x20, 0x10, 8, \
+                            0, 8, 1843200, 3686400 }
+#define HW_PI2          { "Ottawa PI2", 0x300, 0x20, 0x10, 8, \
+			    0, 8, 3686400, 7372800 }
+#define HW_TWIN         { "Gracilis PackeTwin", 0x200, 0x10, 0x10, 32, \
+			    0, 4, 6144000, 6144000 }
+
+#define HARDWARE        { HW_PI, HW_PI2, HW_TWIN }
+
+#define TYPE_PI         0
+#define TYPE_PI2        1
+#define TYPE_TWIN       2
+#define NUM_TYPES       3
+
+#define MAX_NUM_DEVS    32
+
+
+/* SCC chips supported */
+
+#define Z8530           0
+#define Z85C30          1
+#define Z85230          2
+
+#define CHIPNAMES       { "Z8530", "Z85C30", "Z85230" }
+
+
+/* I/O registers */
+
+/* 8530 registers relative to card base */
+#define SCCB_CMD        0x00
+#define SCCB_DATA       0x01
+#define SCCA_CMD        0x02
+#define SCCA_DATA       0x03
+
+/* 8254 registers relative to card base */
+#define TMR_CNT0        0x00
+#define TMR_CNT1        0x01
+#define TMR_CNT2        0x02
+#define TMR_CTRL        0x03
+
+/* Additional PI/PI2 registers relative to card base */
+#define PI_DREQ_MASK    0x04
+
+/* Additional PackeTwin registers relative to card base */
+#define TWIN_INT_REG    0x08
+#define TWIN_CLR_TMR1   0x09
+#define TWIN_CLR_TMR2   0x0a
+#define TWIN_SPARE_1    0x0b
+#define TWIN_DMA_CFG    0x08
+#define TWIN_SERIAL_CFG 0x09
+#define TWIN_DMA_CLR_FF 0x0a
+#define TWIN_SPARE_2    0x0b
+
+
+/* PackeTwin I/O register values */
+
+/* INT_REG */
+#define TWIN_SCC_MSK       0x01
+#define TWIN_TMR1_MSK      0x02
+#define TWIN_TMR2_MSK      0x04
+#define TWIN_INT_MSK       0x07
+
+/* SERIAL_CFG */
+#define TWIN_DTRA_ON       0x01
+#define TWIN_DTRB_ON       0x02
+#define TWIN_EXTCLKA       0x04
+#define TWIN_EXTCLKB       0x08
+#define TWIN_LOOPA_ON      0x10
+#define TWIN_LOOPB_ON      0x20
+#define TWIN_EI            0x80
+
+/* DMA_CFG */
+#define TWIN_DMA_HDX_T1    0x08
+#define TWIN_DMA_HDX_R1    0x0a
+#define TWIN_DMA_HDX_T3    0x14
+#define TWIN_DMA_HDX_R3    0x16
+#define TWIN_DMA_FDX_T3R1  0x1b
+#define TWIN_DMA_FDX_T1R3  0x1d
+
+
+/* Status values */
+
+/* tx_state */
+#define TX_IDLE    0
+#define TX_OFF     1
+#define TX_TXDELAY 2
+#define TX_ACTIVE  3
+#define TX_SQDELAY 4
+
+
+/* Data types */
+
+struct scc_hardware {
+  char *name;
+  int io_region;
+  int io_delta;
+  int io_size;
+  int num_devs;
+  int scc_offset;
+  int tmr_offset;
+  int tmr_hz;
+  int pclk_hz;
+};
+
+struct scc_priv {
+  char name[10];
+  struct enet_statistics stats;
+  struct scc_info *info;
+  int channel;
+  int cmd, data, tmr;
+  struct scc_param param;
+  char rx_buf[NUM_RX_BUF][BUF_SIZE];
+  int rx_len[NUM_RX_BUF];
+  int rx_ptr;
+  struct tq_struct rx_task;
+  int rx_head, rx_tail, rx_count;
+  int rx_over;
+  char tx_buf[NUM_TX_BUF][BUF_SIZE];
+  int tx_len[NUM_TX_BUF];
+  int tx_ptr;
+  int tx_head, tx_tail, tx_count;
+  int tx_sem, tx_state;
+  unsigned long tx_start;
+  int status;
+};
+
+struct scc_info {
+  int type;
+  int chip;
+  int open;
+  int scc_base;
+  int tmr_base;
+  int twin_serial_cfg;
+  struct device dev[2];
+  struct scc_priv priv[2];
+  struct scc_info *next;
+};
+
+
+/* Function declarations */
+
+int dmascc_init(void) __init;
+static int setup_adapter(int io, int h, int n) __init;
+
+static inline void write_scc(int ctl, int reg, int val);
+static inline int read_scc(int ctl, int reg);
+static int scc_open(struct device *dev);
+static int scc_close(struct device *dev);
+static int scc_ioctl(struct device *dev, struct ifreq *ifr, int cmd);
+static int scc_send_packet(struct sk_buff *skb, struct device *dev);
+static struct enet_statistics *scc_get_stats(struct device *dev);
+static int scc_set_mac_address(struct device *dev, void *sa);
+static void scc_isr(int irq, void *dev_id, struct pt_regs * regs);
+static inline void z8530_isr(struct scc_info *info);
+static void rx_isr(struct device *dev);
+static void special_condition(struct device *dev, int rc);
+static void rx_bh(void *arg);
+static void tx_isr(struct device *dev);
+static void es_isr(struct device *dev);
+static void tm_isr(struct device *dev);
+static inline void delay(struct device *dev, int t);
+static inline unsigned char random(void);
+
+
+/* Initialization variables */
+
+static int io[MAX_NUM_DEVS] __initdata = { 0, };
+/* Beware! hw[] is also used in cleanup_module(). If __initdata also applies
+   to modules, we may not declare hw[] as __initdata */
+static struct scc_hardware hw[NUM_TYPES] __initdata = HARDWARE;
+static char ax25_broadcast[7] __initdata =
+  { 'Q'<<1, 'S'<<1, 'T'<<1, ' '<<1, ' '<<1, ' '<<1, '0'<<1 };
+static char ax25_test[7] __initdata =
+  { 'L'<<1, 'I'<<1, 'N'<<1, 'U'<<1, 'X'<<1, ' '<<1, '1'<<1 };
+
+
+/* Global variables */
+
+static struct scc_info *first = NULL;
+static unsigned long rand;
+
+
+
+/* Module functions */
+
+#ifdef MODULE
+
+
+MODULE_AUTHOR("Klaus Kudielka <oe1kib@oe1xtu.ampr.org>");
+MODULE_DESCRIPTION("Driver for high-speed SCC boards");
+MODULE_PARM(io, "1-" __MODULE_STRING(MAX_NUM_DEVS) "i");
+
+
+int init_module(void)
+{
+  return dmascc_init();
+}
+
+
+void cleanup_module(void)
+{
+  int i;
+  struct scc_info *info;
+
+  while (first) {
+    info = first;
+
+    /* Unregister devices */
+    for (i = 0; i < 2; i++) {
+      if (info->dev[i].name)
+	unregister_netdev(&info->dev[i]);
+    }
+
+    /* Reset board */
+    if (info->type == TYPE_TWIN)
+      outb_p(0, info->dev[0].base_addr + TWIN_SERIAL_CFG);
+    write_scc(info->priv[0].cmd, R9, FHWRES);
+    release_region(info->dev[0].base_addr,
+		   hw[info->type].io_size);
+
+    /* Free memory */
+    first = info->next;
+    kfree_s(info, sizeof(struct scc_info));
+  }
+}
+
+
+#else
+
+
+__initfunc(void dmascc_setup(char *str, int *ints))
+{
+   int i;
+
+   for (i = 0; i < MAX_NUM_DEVS && i < ints[0]; i++)
+      io[i] = ints[i+1];
+}
+
+
+#endif
+
+
+/* Initialization functions */
+
+__initfunc(int dmascc_init(void))
+{
+  int h, i, j, n, base[MAX_NUM_DEVS], tcmd, t0, t1, status;
+  unsigned long time, start[MAX_NUM_DEVS], stop[MAX_NUM_DEVS];
+
+  /* Initialize random number generator */
+  rand = jiffies;
+
+  /* Cards found = 0 */
+  n = 0;
+
+  /* Run autodetection for each card type */
+  for (h = 0; h < NUM_TYPES; h++) {
+
+    if (io[0]) {
+      /* User-specified I/O address regions */
+      for (i = 0; i < hw[h].num_devs; i++) base[i] = 0;
+      for (i = 0; i < MAX_NUM_DEVS && io[i]; i++) {
+	j = (io[i] - hw[h].io_region) / hw[h].io_delta;
+	if (j >= 0 &&
+	    j < hw[h].num_devs && 
+	    hw[h].io_region + j * hw[h].io_delta == io[i])
+	  base[j] = io[i];
+      }
+    } else {
+      /* Default I/O address regions */
+      for (i = 0; i < hw[h].num_devs; i++)
+	base[i] = hw[h].io_region + i * hw[h].io_delta;
+    }
+
+    /* Check valid I/O address regions */
+    for (i = 0; i < hw[h].num_devs; i++)
+      if (base[i] && check_region(base[i], hw[h].io_size))
+	base[i] = 0;
+
+    /* Start timers */
+    for (i = 0; i < hw[h].num_devs; i++)
+      if (base[i]) {
+	tcmd = base[i] + hw[h].tmr_offset + TMR_CTRL;
+	t0   = base[i] + hw[h].tmr_offset + TMR_CNT0;
+	t1   = base[i] + hw[h].tmr_offset + TMR_CNT1;
+	/* Timer 0: LSB+MSB, Mode 3, TMR_0_HZ */
+	outb_p(0x36, tcmd);
+	outb_p((hw[h].tmr_hz/TMR_0_HZ) & 0xFF, t0);
+	outb_p((hw[h].tmr_hz/TMR_0_HZ) >> 8, t0);
+	/* Timer 1: LSB+MSB, Mode 0, HZ/10 */
+	outb_p(0x70, tcmd);
+	outb_p((TMR_0_HZ/HZ*10) & 0xFF, t1);
+	outb_p((TMR_0_HZ/HZ*10) >> 8, t1);
+	/* Timer 2: LSB+MSB, Mode 0 */
+	outb_p(0xb0, tcmd);
+      }
+
+    /* Initialize start values in case we miss the null count bit */
+    time = jiffies;
+    for (i = 0; i < hw[h].num_devs; i++) start[i] = time;
+
+    /* Timing loop */
+    while (jiffies - time < 12) {
+      for (i = 0; i < hw[h].num_devs; i++)
+	if (base[i]) {
+	  /* Read back Timer 1: Status */
+	  outb_p(0xE4, base[i] + hw[h].tmr_offset + TMR_CTRL);
+	  status = inb_p(base[i] + hw[h].tmr_offset + TMR_CNT1);
+	  if ((status & 0x3F) != 0x30) base[i] = 0;
+	  if (status & 0x40) start[i] = jiffies;
+	  if (~status & 0x80) stop[i] = jiffies;
+	}
+    }
+
+    /* Evaluate measurements */
+    for (i = 0; i < hw[h].num_devs; i++)
+      if (base[i]) {
+	time = stop[i] - start[i];
+	if (time < 9 || time > 11)
+	  /* The time expired doesn't match */
+	  base[i] = 0;
+	else {
+	  /* Ok, we have found an adapter */
+	  if (setup_adapter(base[i], h, n) == 0)
+	    n++;
+	}
+      }
+
+  } /* NUM_TYPES */
+
+  /* If any adapter was successfully initialized, return ok */
+  if (n) return 0;
+
+  /* If no adapter found, return error */
+  printk("dmascc: no adapters found\n");
+  return -EIO;
+}
+
+
+__initfunc(int setup_adapter(int io, int h, int n))
+{
+  int i, irq, chip;
+  struct scc_info *info;
+  struct device *dev;
+  struct scc_priv *priv;
+  unsigned long time;
+  unsigned int irqs;
+  int tmr = io + hw[h].tmr_offset;
+  int scc = io + hw[h].scc_offset;
+  int cmd = scc + SCCA_CMD;
+  char *chipnames[] = CHIPNAMES;
+
+  /* Reset 8530 */
+  write_scc(cmd, R9, FHWRES | MIE | NV);
+
+  /* Determine type of chip */
+  write_scc(cmd, R15, 1);
+  if (!read_scc(cmd, R15)) {
+    /* WR7' not present. This is an ordinary Z8530 SCC. */
+    chip = Z8530;
+  } else {
+    /* Put one character in TX FIFO */
+    write_scc(cmd, R8, 0);
+    if (read_scc(cmd, R0) & Tx_BUF_EMP) {
+      /* TX FIFO not full. This is a Z85230 ESCC with a 4-byte FIFO. */
+      chip = Z85230;
+    } else {
+      /* TX FIFO full. This is a Z85C30 SCC with a 1-byte FIFO. */
+      chip = Z85C30;
+    }
+  }
+  write_scc(cmd, R15, 0);
+
+  /* Start IRQ auto-detection */
+  sti();
+  irqs = probe_irq_on();
+
+  /* Enable interrupts */
+  switch (h) {
+  case TYPE_PI:
+  case TYPE_PI2:
+    outb_p(0, io + PI_DREQ_MASK);
+    write_scc(cmd, R15, CTSIE);
+    write_scc(cmd, R0, RES_EXT_INT);
+    write_scc(cmd, R1, EXT_INT_ENAB);
+    break;
+  case TYPE_TWIN:
+    outb_p(0, io + TWIN_DMA_CFG);
+    inb_p(io + TWIN_CLR_TMR1);
+    inb_p(io + TWIN_CLR_TMR2);
+    outb_p(TWIN_EI, io + TWIN_SERIAL_CFG);
+    break;
+  }
+
+  /* Start timer */
+  outb_p(1, tmr + TMR_CNT1);
+  outb_p(0, tmr + TMR_CNT1);
+  /* Wait and detect IRQ */
+  time = jiffies; while (jiffies - time < 2 + HZ / TMR_0_HZ);
+  irq = probe_irq_off(irqs);
+
+  /* Clear pending interrupt, disable interrupts */
+  switch (h) {
+  case TYPE_PI:
+  case TYPE_PI2:
+    write_scc(cmd, R1, 0);
+    write_scc(cmd, R15, 0);
+    write_scc(cmd, R0, RES_EXT_INT);
+    break;
+  case TYPE_TWIN:
+    inb_p(io + TWIN_CLR_TMR1);
+    outb_p(0, io + TWIN_SERIAL_CFG);
+    break;
+  }
+
+  if (irq <= 0) {
+    printk("dmascc: could not find irq of %s at %#3x (irq=%d)\n",
+	   hw[h].name, io, irq);
+    return -1;
+  }
+
+  /* Allocate memory */
+  info = kmalloc(sizeof(struct scc_info), GFP_KERNEL | GFP_DMA);
+  if (!info) {
+    printk("dmascc: could not allocate memory for %s at %#3x\n",
+	   hw[h].name, io);
+    return -1;
+  }
+
+  /* Set up data structures */
+  memset(info, 0, sizeof(struct scc_info));
+  info->type = h;
+  info->chip = chip;
+  info->scc_base = io + hw[h].scc_offset;
+  info->tmr_base = io + hw[h].tmr_offset;
+  info->twin_serial_cfg = 0;
+  for (i = 0; i < 2; i++) {
+    dev = &info->dev[i];
+    priv = &info->priv[i];
+    sprintf(priv->name, "dmascc%i", 2*n+i);
+    priv->info = info;
+    priv->channel = i;
+    priv->cmd = info->scc_base + (i ? SCCB_CMD : SCCA_CMD);
+    priv->data = info->scc_base + (i ? SCCB_DATA : SCCA_DATA);
+    priv->tmr = info->tmr_base + (i ? TMR_CNT2 : TMR_CNT1);
+    priv->param.pclk_hz = hw[h].pclk_hz;
+    priv->param.brg_tc = -1;
+    priv->param.clocks = TCTRxCP | RCRTxCP;
+    priv->param.txdelay = TMR_0_HZ * 10 / 1000;
+    priv->param.txtime = HZ * 3;
+    priv->param.sqdelay = TMR_0_HZ * 1 / 1000;
+    priv->param.slottime = TMR_0_HZ * 10 / 1000;
+    priv->param.waittime = TMR_0_HZ * 100 / 1000;
+    priv->param.persist = 32;
+    priv->rx_task.routine = rx_bh;
+    priv->rx_task.data = dev;
+    dev->priv = priv;
+    dev->name = priv->name;
+    dev->base_addr = io;
+    dev->irq = irq;
+    dev->open = scc_open;
+    dev->stop = scc_close;
+    dev->do_ioctl = scc_ioctl;
+    dev->hard_start_xmit = scc_send_packet;
+    dev->get_stats = scc_get_stats;
+    dev->hard_header = ax25_encapsulate;
+    dev->rebuild_header = ax25_rebuild_header;
+    dev->set_mac_address = scc_set_mac_address;
+    dev->type = ARPHRD_AX25;
+    dev->hard_header_len = 73;
+    dev->mtu = 1500;
+    dev->addr_len = 7;
+    dev->tx_queue_len = 64;
+    memcpy(dev->broadcast, ax25_broadcast, 7);
+    memcpy(dev->dev_addr, ax25_test, 7);
+    dev->flags = 0;
+    dev_init_buffers(dev);
+    if (register_netdev(dev)) {
+      printk("dmascc: could not register %s\n", dev->name);
+      dev->name = NULL;
+    }
+  }
+
+  request_region(io, hw[h].io_size, "dmascc");
+
+  info->next = first;
+  first = info;
+  printk("dmascc: found %s (%s) at %#3x, irq %d\n", hw[h].name,
+	 chipnames[chip], io, irq);
+  return 0;
+}
+
+
+/* Driver functions */
+
+static inline void write_scc(int ctl, int reg, int val)
+{
+  outb_p(reg, ctl);
+  outb_p(val, ctl);
+}
+
+
+static inline int read_scc(int ctl, int reg)
+{
+  outb_p(reg, ctl);
+  return inb_p(ctl);
+}
+
+
+static int scc_open(struct device *dev)
+{
+  struct scc_priv *priv = dev->priv;
+  struct scc_info *info = priv->info;
+  int io = dev->base_addr;
+  int cmd = priv->cmd;
+
+  /* Request IRQ if not already used by other channel */
+  if (!info->open) {
+    if (request_irq(dev->irq, scc_isr, SA_INTERRUPT, "dmascc", info))
+      return -EAGAIN;
+  }
+
+  /* Request DMA if required */
+  if (dev->dma && request_dma(dev->dma, "dmascc")) {
+    if (!info->open) free_irq(dev->irq, info);
+    return -EAGAIN;
+  }
+
+  /* Initialize local variables */
+  dev->tbusy = 0;
+  priv->rx_ptr = 0;
+  priv->rx_over = 0;
+  priv->rx_head = priv->rx_tail = priv->rx_count = 0;
+  priv->tx_state = TX_IDLE;
+  priv->tx_head = priv->tx_tail = priv->tx_count = 0;
+  priv->tx_ptr = 0;
+  priv->tx_sem = 0;
+
+  /* Reset channel */
+  write_scc(cmd, R9, (priv->channel ? CHRB : CHRA) | MIE | NV);
+  /* X1 clock, SDLC mode */
+  write_scc(cmd, R4, SDLC | X1CLK);
+  /* DMA */
+  write_scc(cmd, R1, EXT_INT_ENAB | WT_FN_RDYFN);
+  /* 8 bit RX char, RX disable */
+  write_scc(cmd, R3, Rx8);
+  /* 8 bit TX char, TX disable */
+  write_scc(cmd, R5, Tx8);
+  /* SDLC address field */
+  write_scc(cmd, R6, 0);
+  /* SDLC flag */
+  write_scc(cmd, R7, FLAG);
+  switch (info->chip) {
+  case Z85C30:
+    /* Select WR7' */
+    write_scc(cmd, R15, 1);
+    /* Auto EOM reset */
+    write_scc(cmd, R7, 0x02);
+    write_scc(cmd, R15, 0);
+    break;
+  case Z85230:
+    /* Select WR7' */
+    write_scc(cmd, R15, 1);
+    /* RX FIFO half full (interrupt only), Auto EOM reset,
+       TX FIFO empty (DMA only) */
+    write_scc(cmd, R7, dev->dma ? 0x22 : 0x0a);
+    write_scc(cmd, R15, 0);
+    break;
+  }
+  /* Preset CRC, NRZ(I) encoding */
+  write_scc(cmd, R10, CRCPS | (priv->param.nrzi ? NRZI : NRZ));
+
+  /* Configure baud rate generator */
+  if (priv->param.brg_tc >= 0) {
+    /* Program BR generator */
+    write_scc(cmd, R12, priv->param.brg_tc & 0xFF);
+    write_scc(cmd, R13, (priv->param.brg_tc>>8) & 0xFF);
+    /* BRG source = SYS CLK; enable BRG; DTR REQ function (required by
+       PackeTwin, not connected on the PI2); set DPLL source to BRG */
+    write_scc(cmd, R14, SSBR | DTRREQ | BRSRC | BRENABL);
+    /* Enable DPLL */
+    write_scc(cmd, R14, SEARCH | DTRREQ | BRSRC | BRENABL);
+  } else {
+    /* Disable BR generator */
+    write_scc(cmd, R14, DTRREQ | BRSRC);
+  }
+
+  /* Configure clocks */
+  if (info->type == TYPE_TWIN) {
+    /* Disable external TX clock receiver */
+    outb_p((info->twin_serial_cfg &=
+	    ~(priv->channel ? TWIN_EXTCLKB : TWIN_EXTCLKA)), 
+	   io + TWIN_SERIAL_CFG);
+  }
+  write_scc(cmd, R11, priv->param.clocks);
+  if ((info->type == TYPE_TWIN) && !(priv->param.clocks & TRxCOI)) {
+    /* Enable external TX clock receiver */
+    outb_p((info->twin_serial_cfg |=
+	    (priv->channel ? TWIN_EXTCLKB : TWIN_EXTCLKA)),
+	   io + TWIN_SERIAL_CFG);
+  }
+
+  /* Configure PackeTwin */
+  if (info->type == TYPE_TWIN) {
+    /* Assert DTR, enable interrupts */
+    outb_p((info->twin_serial_cfg |= TWIN_EI |
+	    (priv->channel ? TWIN_DTRB_ON : TWIN_DTRA_ON)),
+	   io + TWIN_SERIAL_CFG);
+  }
+
+  /* Read current status */
+  priv->status = read_scc(cmd, R0);
+  /* Enable SYNC, DCD, and CTS interrupts */
+  write_scc(cmd, R15, DCDIE | CTSIE | SYNCIE);
+
+  /* Configure PI2 DMA */
+  if (info->type <= TYPE_PI2) outb_p(1, io + PI_DREQ_MASK);
+
+  dev->start = 1;
+  info->open++;
+  MOD_INC_USE_COUNT;
+
+  return 0;
+}
+
+
+static int scc_close(struct device *dev)
+{
+  struct scc_priv *priv = dev->priv;
+  struct scc_info *info = priv->info;
+  int io = dev->base_addr;
+  int cmd = priv->cmd;
+
+  dev->start = 0;
+  info->open--;
+  MOD_DEC_USE_COUNT;
+
+  if (info->type == TYPE_TWIN)
+    /* Drop DTR */
+    outb_p((info->twin_serial_cfg &=
+	    (priv->channel ? ~TWIN_DTRB_ON : ~TWIN_DTRA_ON)),
+	   io + TWIN_SERIAL_CFG);
+
+  /* Reset channel, free DMA */
+  write_scc(cmd, R9, (priv->channel ? CHRB : CHRA) | MIE | NV);
+  if (dev->dma) {
+    if (info->type == TYPE_TWIN) outb_p(0, io + TWIN_DMA_CFG);
+    free_dma(dev->dma);
+  }
+
+  if (!info->open) {
+    if (info->type <= TYPE_PI2) outb_p(0, io + PI_DREQ_MASK);
+    free_irq(dev->irq, info);
+  }
+  return 0;
+}
+
+
+static int scc_ioctl(struct device *dev, struct ifreq *ifr, int cmd)
+{
+  int rc;
+  struct scc_priv *priv = dev->priv;
+  
+  switch (cmd) {
+  case SIOCGSCCPARAM:
+    rc = verify_area(VERIFY_WRITE, ifr->ifr_data, sizeof(struct scc_param));
+    if (rc) return rc;
+    copy_to_user(ifr->ifr_data, &priv->param, sizeof(struct scc_param));
+    return 0;
+  case SIOCSSCCPARAM:
+    if (!suser()) return -EPERM;
+    rc = verify_area(VERIFY_READ, ifr->ifr_data, sizeof(struct scc_param));
+    if (rc) return rc;
+    if (dev->start) return -EAGAIN;
+    copy_from_user(&priv->param, ifr->ifr_data, sizeof(struct scc_param));
+    dev->dma = priv->param.dma;
+    return 0;
+  default:
+    return -EINVAL;
+  }
+}
+
+
+static int scc_send_packet(struct sk_buff *skb, struct device *dev)
+{
+  struct scc_priv *priv = dev->priv;
+  struct scc_info *info = priv->info;
+  int cmd = priv->cmd;
+  unsigned long flags;
+  int i;
+
+  /* Block a timer-based transmit from overlapping */
+  if (test_and_set_bit(0, (void *) &priv->tx_sem) != 0) {
+    atomic_inc((void *) &priv->stats.tx_dropped);
+    dev_kfree_skb(skb, FREE_WRITE);
+    return 0;
+  }
+
+  /* Return with an error if we cannot accept more data */
+  if (dev->tbusy) {
+    priv->tx_sem = 0;
+    return -1;
+  }
+
+  /* Transfer data to DMA buffer */
+  i = priv->tx_head;
+  memcpy(priv->tx_buf[i], skb->data+1, skb->len-1);
+  priv->tx_len[i] = skb->len-1;
+
+  save_flags(flags);
+  cli();
+
+  /* Set the busy flag if we just filled up the last buffer */
+  priv->tx_head = (i + 1) % NUM_TX_BUF;
+  priv->tx_count++;
+  if (priv->tx_count == NUM_TX_BUF) dev->tbusy = 1;
+
+  /* Set new TX state */
+  if (priv->tx_state == TX_IDLE) {
+    /* Assert RTS, start timer */
+    priv->tx_state = TX_TXDELAY;
+    if (info->type <= TYPE_PI2) outb_p(0, dev->base_addr + PI_DREQ_MASK);
+    write_scc(cmd, R5, TxCRC_ENAB | RTS | TxENAB | Tx8);
+    if (info->type <= TYPE_PI2) outb_p(1, dev->base_addr + PI_DREQ_MASK);
+    priv->tx_start = jiffies;
+    delay(dev, priv->param.txdelay);
+  }
+
+  restore_flags(flags);
+
+  dev_kfree_skb(skb, FREE_WRITE);
+
+  priv->tx_sem = 0;
+  return 0;
+}
+
+
+static struct enet_statistics *scc_get_stats(struct device *dev)
+{
+  struct scc_priv *priv = dev->priv;
+
+  return &priv->stats;
+}
+
+
+static int scc_set_mac_address(struct device *dev, void *sa)
+{
+  memcpy(dev->dev_addr, ((struct sockaddr *)sa)->sa_data, dev->addr_len);
+  return 0;
+}
+
+
+static void scc_isr(int irq, void *dev_id, struct pt_regs * regs)
+{
+  struct scc_info *info = dev_id;
+  int is, io = info->dev[0].base_addr;
+
+  /* We're a fast IRQ handler and are called with interrupts disabled */
+
+  /* IRQ sharing doesn't make sense due to ISA's edge-triggered
+     interrupts, hence it is safe to return if we have found and
+     processed a single device. */
+
+  /* Interrupt processing: We loop until we know that the IRQ line is
+     low. If another positive edge occurs afterwards during the ISR,
+     another interrupt will be triggered by the interrupt controller
+     as soon as the IRQ level is enabled again (see asm/irq.h). */
+
+  switch (info->type) {
+  case TYPE_PI:
+  case TYPE_PI2:
+    outb_p(0, io + PI_DREQ_MASK);
+    z8530_isr(info);
+    outb_p(1, io + PI_DREQ_MASK);
+    return;
+  case TYPE_TWIN:
+    while ((is = ~inb_p(io + TWIN_INT_REG)) &
+	   TWIN_INT_MSK) {
+      if (is & TWIN_SCC_MSK) {
+	z8530_isr(info);
+      } else if (is & TWIN_TMR1_MSK) {
+	inb_p(io + TWIN_CLR_TMR1);
+	tm_isr(&info->dev[0]);
+      } else {
+	inb_p(io + TWIN_CLR_TMR2);
+	tm_isr(&info->dev[1]);
+      }
+    }
+    /* No interrupts pending from the PackeTwin */
+    return;
+  }
+}
+
+
+static inline void z8530_isr(struct scc_info *info)
+{
+  int is, a_cmd;
+  
+  a_cmd = info->scc_base + SCCA_CMD;
+
+  while ((is = read_scc(a_cmd, R3))) {
+    if (is & CHARxIP) {
+      rx_isr(&info->dev[0]);
+    } else if (is & CHATxIP) {
+      tx_isr(&info->dev[0]);
+    } else if (is & CHAEXT) {
+      es_isr(&info->dev[0]);
+    } else if (is & CHBRxIP) {
+      rx_isr(&info->dev[1]);
+    } else if (is & CHBTxIP) {
+      tx_isr(&info->dev[1]);
+    } else {
+      es_isr(&info->dev[1]);
+    }
+  }
+  /* Ok, no interrupts pending from this 8530. The INT line should
+     be inactive now. */
+}
+
+
+static void rx_isr(struct device *dev)
+{
+  struct scc_priv *priv = dev->priv;
+  int cmd = priv->cmd;
+
+  if (dev->dma) {
+    /* Check special condition and perform error reset. See 2.4.7.5. */
+    special_condition(dev, read_scc(cmd, R1));
+    write_scc(cmd, R0, ERR_RES);
+  } else {
+    /* Check special condition for each character. Error reset not necessary.
+       Same algorithm for SCC and ESCC. See 2.4.7.1 and 2.4.7.4. */
+    int rc;
+    while (read_scc(cmd, R0) & Rx_CH_AV) {
+      rc = read_scc(cmd, R1);
+      if (priv->rx_ptr < BUF_SIZE)
+	priv->rx_buf[priv->rx_head][priv->rx_ptr++] = read_scc(cmd, R8);
+      else {
+	priv->rx_over = 2;
+	read_scc(cmd, R8);
+      }
+      special_condition(dev, rc);
+    }
+  }
+}
+
+
+static void special_condition(struct device *dev, int rc)
+{
+  struct scc_priv *priv = dev->priv;
+  int cb, cmd = priv->cmd;
+
+  /* See Figure 2-15. Only overrun and EOF need to be checked. */
+  
+  if (rc & Rx_OVR) {
+    /* Receiver overrun */
+    priv->rx_over = 1;
+    if (!dev->dma) write_scc(cmd, R0, ERR_RES);
+  } else if (rc & END_FR) {
+    /* End of frame. Get byte count */
+    if (dev->dma) {
+	disable_dma(dev->dma);
+	clear_dma_ff(dev->dma);
+	cb = BUF_SIZE - get_dma_residue(dev->dma) - 2;
+    } else {
+	cb = priv->rx_ptr - 2;
+    }
+    if (priv->rx_over) {
+      /* We had an overrun */
+      priv->stats.rx_errors++;
+      if (priv->rx_over == 2) priv->stats.rx_length_errors++;
+      else priv->stats.rx_fifo_errors++;
+      priv->rx_over = 0;
+    } else if (rc & CRC_ERR) {
+      /* Count invalid CRC only if packet length >= minimum */
+      if (cb >= 8) {
+	priv->stats.rx_errors++;
+	priv->stats.rx_crc_errors++;
+      }
+    } else {
+      if (cb >= 8) {
+	/* Put good frame in FIFO */
+	priv->rx_len[priv->rx_head] = cb;
+	priv->rx_head = (priv->rx_head + 1) % NUM_RX_BUF;
+	priv->rx_count++;
+	if (priv->rx_count == NUM_RX_BUF) {
+	  /* Disable receiver if FIFO full */
+	  write_scc(cmd, R3, Rx8);
+	  priv->stats.rx_errors++;
+	  priv->stats.rx_over_errors++;
+	}
+	/* Mark bottom half handler */
+	queue_task(&priv->rx_task, &tq_immediate);
+	mark_bh(IMMEDIATE_BH);
+      }
+    }
+    /* Get ready for new frame */
+    if (dev->dma) {
+      set_dma_addr(dev->dma, (int) priv->rx_buf[priv->rx_head]);
+      set_dma_count(dev->dma, BUF_SIZE);
+      enable_dma(dev->dma);
+    } else {
+      priv->rx_ptr = 0;
+    }
+  }
+}
+
+
+static void rx_bh(void *arg)
+{
+  struct device *dev = arg;
+  struct scc_priv *priv = dev->priv;
+  struct scc_info *info = priv->info;
+  int cmd = priv->cmd;
+  int i = priv->rx_tail;
+  int cb;
+  unsigned long flags;
+  struct sk_buff *skb;
+  unsigned char *data;
+
+  save_flags(flags);
+  cli();
+
+  while (priv->rx_count) {
+    restore_flags(flags);
+    cb = priv->rx_len[i];
+    /* Allocate buffer */
+    skb = dev_alloc_skb(cb+1);
+    if (skb == NULL) {
+      /* Drop packet */
+      priv->stats.rx_dropped++;
+    } else {
+      /* Fill buffer */
+      data = skb_put(skb, cb+1);
+      data[0] = 0;
+      memcpy(&data[1], priv->rx_buf[i], cb);
+      skb->dev = dev;
+      skb->protocol = ntohs(ETH_P_AX25);
+      skb->mac.raw = skb->data;
+      netif_rx(skb);
+      priv->stats.rx_packets++;
+    }
+    save_flags(flags);
+    cli();
+    /* Enable receiver if RX buffers have been unavailable */
+    if ((priv->rx_count == NUM_RX_BUF) && (priv->status & DCD)) {
+      if (info->type <= TYPE_PI2) outb_p(0, dev->base_addr + PI_DREQ_MASK);
+      write_scc(cmd, R3, RxENABLE | Rx8 | RxCRC_ENAB);
+      if (info->type <= TYPE_PI2) outb_p(1, dev->base_addr + PI_DREQ_MASK);
+    }
+    /* Move tail */
+    priv->rx_tail = i = (i + 1) % NUM_RX_BUF;
+    priv->rx_count--;
+  }
+
+  restore_flags(flags);
+}
+
+
+static void tx_isr(struct device *dev)
+{
+  struct scc_priv *priv = dev->priv;
+  int cmd = priv->cmd;
+  int i = priv->tx_tail, p = priv->tx_ptr;
+
+  /* Suspend TX interrupts if we don't want to send anything.
+     See Figure 2-22. */
+  if (p ==  priv->tx_len[i]) {
+    write_scc(cmd, R0, RES_Tx_P);
+    return;
+  }
+
+  /* Write characters */
+  while ((read_scc(cmd, R0) & Tx_BUF_EMP) && p < priv->tx_len[i]) {
+    write_scc(cmd, R8, priv->tx_buf[i][p++]);
+  }
+  priv->tx_ptr = p;
+
+}
+
+
+static void es_isr(struct device *dev)
+{
+  struct scc_priv *priv = dev->priv;
+  struct scc_info *info = priv->info;
+  int i, cmd = priv->cmd;
+  int st, dst, res;
+
+  /* Read status and reset interrupt bit */
+  st = read_scc(cmd, R0);
+  write_scc(cmd, R0, RES_EXT_INT);
+  dst = priv->status ^ st;
+  priv->status = st;
+
+  /* Since the EOM latch is reset automatically, we assume that
+     it has been zero if and only if we are in the TX_ACTIVE state.
+     Otherwise we follow 2.4.9.6. */
+
+  /* Transmit underrun */
+  if ((priv->tx_state == TX_ACTIVE) && (st & TxEOM)) {
+    /* Get remaining bytes */
+    i = priv->tx_tail;
+    if (dev->dma) {
+      disable_dma(dev->dma);
+      clear_dma_ff(dev->dma);
+      res = get_dma_residue(dev->dma);
+    } else {
+      res = priv->tx_len[i] - priv->tx_ptr;
+      if (res) write_scc(cmd, R0, RES_Tx_P);
+      priv->tx_ptr = 0;
+    }
+    /* Remove frame from FIFO */
+    priv->tx_tail = (i + 1) % NUM_TX_BUF;
+    priv->tx_count--;
+    dev->tbusy = 0;
+    /* Check if another frame is available and we are allowed to transmit */
+    if (priv->tx_count && (jiffies - priv->tx_start) < priv->param.txtime) {
+      if (dev->dma) {
+	set_dma_addr(dev->dma, (int) priv->tx_buf[priv->tx_tail]);
+	set_dma_count(dev->dma, priv->tx_len[priv->tx_tail]);
+	enable_dma(dev->dma);
+      } else {
+	/* If we have an ESCC, we are allowed to write data bytes
+	   immediately. Otherwise we have to wait for the next
+	   TX interrupt. See Figure 2-22. */
+	if (info->chip == Z85230) {
+	  tx_isr(dev);
+	}
+      }
+    } else {
+      /* No frame available. Disable interrupts. */
+      priv->tx_state = TX_SQDELAY;
+      delay(dev, priv->param.sqdelay);
+      write_scc(cmd, R15, DCDIE | CTSIE | SYNCIE);
+      write_scc(cmd, R1, EXT_INT_ENAB | WT_FN_RDYFN);
+    }
+    /* Update packet statistics */
+    if (res) {
+      priv->stats.tx_errors++;
+      priv->stats.tx_fifo_errors++;
+    } else {
+      priv->stats.tx_packets++;
+    }
+    /* Inform upper layers */
+    mark_bh(NET_BH);
+  }
+
+  /* DCD transition */
+  if ((priv->tx_state < TX_TXDELAY) && (dst & DCD)) {
+    /* Transmitter state change */
+    priv->tx_state = TX_OFF;
+    /* Enable or disable receiver */
+    if (st & DCD) {
+      if (dev->dma) {
+	/* Program DMA controller */
+	disable_dma(dev->dma);
+	clear_dma_ff(dev->dma);
+	set_dma_mode(dev->dma, DMA_MODE_READ);
+	set_dma_addr(dev->dma, (int) priv->rx_buf[priv->rx_head]);
+	set_dma_count(dev->dma, BUF_SIZE);
+	enable_dma(dev->dma);
+	/* Configure PackeTwin DMA */
+	if (info->type == TYPE_TWIN) {
+	  outb_p((dev->dma == 1) ? TWIN_DMA_HDX_R1 : TWIN_DMA_HDX_R3,
+		 dev->base_addr + TWIN_DMA_CFG);
+	}
+	/* Sp. cond. intr. only, ext int enable */
+	write_scc(cmd, R1, EXT_INT_ENAB | INT_ERR_Rx |
+		  WT_RDY_RT | WT_FN_RDYFN | WT_RDY_ENAB);
+      } else {
+	/* Intr. on all Rx characters and Sp. cond., ext int enable */
+	write_scc(cmd, R1, EXT_INT_ENAB | INT_ALL_Rx | WT_RDY_RT |
+		  WT_FN_RDYFN);
+      }
+      if (priv->rx_count < NUM_RX_BUF) {
+	/* Enable receiver */
+	write_scc(cmd, R3, RxENABLE | Rx8 | RxCRC_ENAB);
+      }
+    } else {
+      /* Disable DMA */
+      if (dev->dma) disable_dma(dev->dma);
+      /* Disable receiver */
+      write_scc(cmd, R3, Rx8);
+      /* DMA disable, RX int disable, Ext int enable */
+      write_scc(cmd, R1, EXT_INT_ENAB | WT_RDY_RT | WT_FN_RDYFN);
+      /* Transmitter state change */
+      if (random() > priv->param.persist)
+	delay(dev, priv->param.slottime);
+      else {
+	if (priv->tx_count) {
+	  priv->tx_state = TX_TXDELAY;
+	  write_scc(cmd, R5, TxCRC_ENAB | RTS | TxENAB | Tx8);
+	  priv->tx_start = jiffies;
+	  delay(dev, priv->param.txdelay);
+	} else {
+	  priv->tx_state = TX_IDLE;
+	}
+      }
+    }
+  }
+
+  /* CTS transition */
+  if ((info->type <= TYPE_PI2) && (dst & CTS) && (~st & CTS)) {
+    /* Timer has expired */
+    tm_isr(dev);
+  }
+
+  /* /SYNC/HUNT transition */
+  if ((dst & SYNC_HUNT) && (~st & SYNC_HUNT)) {
+    /* Reset current frame and clear RX FIFO */
+    while (read_scc(cmd, R0) & Rx_CH_AV) read_scc(cmd, R8);
+    priv->rx_over = 0;
+    if (dev->dma) {
+      disable_dma(dev->dma);
+      clear_dma_ff(dev->dma);
+      set_dma_addr(dev->dma, (int) priv->rx_buf[priv->rx_head]);
+      set_dma_count(dev->dma, BUF_SIZE);
+      enable_dma(dev->dma);
+    } else {
+      priv->rx_ptr = 0;
+    }
+  }
+}
+
+
+static void tm_isr(struct device *dev)
+{
+  struct scc_priv *priv = dev->priv;
+  struct scc_info *info = priv->info;
+  int cmd = priv->cmd;
+
+  switch (priv->tx_state) {
+  case TX_OFF:
+    if (~priv->status & DCD) {
+      if (random() > priv->param.persist) delay(dev, priv->param.slottime);
+      else {
+	if (priv->tx_count) {
+	  priv->tx_state = TX_TXDELAY;
+	  write_scc(cmd, R5, TxCRC_ENAB | RTS | TxENAB | Tx8);
+	  priv->tx_start = jiffies;
+	  delay(dev, priv->param.txdelay);
+	} else {
+	  priv->tx_state = TX_IDLE;
+	}
+      }
+    }
+    break;
+  case TX_TXDELAY:
+    priv->tx_state = TX_ACTIVE;
+    if (dev->dma) {
+      /* Program DMA controller */
+      disable_dma(dev->dma);
+      clear_dma_ff(dev->dma);
+      set_dma_mode(dev->dma, DMA_MODE_WRITE);
+      set_dma_addr(dev->dma, (int) priv->tx_buf[priv->tx_tail]);
+      set_dma_count(dev->dma, priv->tx_len[priv->tx_tail]);
+      enable_dma(dev->dma);
+      /* Configure PackeTwin DMA */
+      if (info->type == TYPE_TWIN) {
+	outb_p((dev->dma == 1) ? TWIN_DMA_HDX_T1 : TWIN_DMA_HDX_T3,
+	       dev->base_addr + TWIN_DMA_CFG);
+      }
+      /* Enable interrupts and DMA. On the PackeTwin, the DTR//REQ pin
+	 is used for TX DMA requests, but we enable the WAIT/DMA request
+	 pin, anyway */
+      write_scc(cmd, R15, TxUIE | DCDIE | CTSIE | SYNCIE);
+      write_scc(cmd, R1, EXT_INT_ENAB | WT_FN_RDYFN | WT_RDY_ENAB);
+    } else {
+      write_scc(cmd, R15, TxUIE | DCDIE | CTSIE | SYNCIE);
+      write_scc(cmd, R1, EXT_INT_ENAB | WT_FN_RDYFN | TxINT_ENAB);
+      tx_isr(dev);
+    }
+    if (info->chip == Z8530) write_scc(cmd, R0, RES_EOM_L);
+    break;
+  case TX_SQDELAY:
+    /* Disable transmitter */
+    write_scc(cmd, R5, TxCRC_ENAB | Tx8);
+    /* Transmitter state change: Switch to TX_OFF and wait at least
+       1 slottime. */
+    priv->tx_state = TX_OFF;    
+    if (~priv->status & DCD) delay(dev, priv->param.waittime);
+  }
+}
+
+
+static inline void delay(struct device *dev, int t)
+{
+  struct scc_priv *priv = dev->priv;
+  int tmr = priv->tmr;
+
+  outb_p(t & 0xFF, tmr);
+  outb_p((t >> 8) & 0xFF, tmr);
+}
+
+
+static inline unsigned char random(void)
+{
+  /* See "Numerical Recipes in C", second edition, p. 284 */
+  rand = rand * 1664525L + 1013904223L;
+  return (unsigned char) (rand >> 24);
+}
+
+
diff -u --recursive --new-file v2.1.72/linux/drivers/net/ipddp.c linux/drivers/net/ipddp.c
--- v2.1.72/linux/drivers/net/ipddp.c	Sat Nov 29 11:25:10 1997
+++ linux/drivers/net/ipddp.c	Wed Dec 10 09:45:16 1997
@@ -1,5 +1,3 @@
-#warning "Needs new networking merges before it will work"
-#if 0
 /*
  *	ipddp.c: IP-over-DDP driver for Linux
  *
@@ -309,4 +307,3 @@
 }
 
 #endif /* MODULE */
-#endif
diff -u --recursive --new-file v2.1.72/linux/drivers/pci/pci.c linux/drivers/pci/pci.c
--- v2.1.72/linux/drivers/pci/pci.c	Thu Dec  4 14:53:55 1997
+++ linux/drivers/pci/pci.c	Wed Dec 17 11:11:51 1997
@@ -154,8 +154,8 @@
 	DEVICE( PCTECH,		PCTECH_RZ1001,  "RZ1001 (buggy?)"),
 	DEVICE( DPT,		DPT,		"SmartCache/Raid"),
 	DEVICE( OPTI,		OPTI_92C178,	"92C178"),
-	DEVICE( OPTI,		OPTI_82C557,	"82C557"),
-	DEVICE( OPTI,		OPTI_82C558,	"82C558"),
+	DEVICE( OPTI,		OPTI_82C557,	"82C557 Viper-M"),
+	DEVICE( OPTI,		OPTI_82C558,	"82C558 Viper-M ISA+IDE"),
 	DEVICE( OPTI,		OPTI_82C621,	"82C621"),
 	DEVICE( OPTI,		OPTI_82C700,	"82C700"),
 	DEVICE( OPTI,		OPTI_82C701,	"82C701 FireStar Plus"),
@@ -393,15 +393,15 @@
 	DEVICE( INTEL,		INTEL_82865,	"82865"),
 	DEVICE( INTEL,		INTEL_82557,	"82557"),
 	DEVICE( INTEL,		INTEL_82437,	"82437"),
-	DEVICE( INTEL,		INTEL_82371_0,	"82371 Triton PIIX"),
-	DEVICE( INTEL,		INTEL_82371_1,	"82371 Triton PIIX"),
+	DEVICE( INTEL,		INTEL_82371FB_0,"82371FB PIIX ISA"),
+	DEVICE( INTEL,		INTEL_82371FB_1,"82371FB PIIX IDE"),
 	DEVICE( INTEL,		INTEL_82371MX,	"430MX - 82371MX MPIIX"),
 	DEVICE( INTEL,		INTEL_82437MX,	"430MX - 82437MX MTSC"),
 	DEVICE( INTEL,		INTEL_82441,	"82441FX Natoma"),
 	DEVICE( INTEL,		INTEL_82439,	"82439HX Triton II"),
-	DEVICE(	INTEL,		INTEL_82371SB_0,"82371SB Natoma/Triton II PIIX3"),
-	DEVICE(	INTEL,		INTEL_82371SB_1,"82371SB Natoma/Triton II PIIX3"),
-	DEVICE( INTEL,		INTEL_82371SB_2,"82371SB Natoma/Triton II PIIX3"),
+	DEVICE(	INTEL,		INTEL_82371SB_0,"82371SB PIIX3 ISA"),
+	DEVICE(	INTEL,		INTEL_82371SB_1,"82371SB PIIX3 IDE"),
+	DEVICE( INTEL,		INTEL_82371SB_2,"82371SB PIIX3 USB"),
 	DEVICE( INTEL,		INTEL_82437VX,	"82437VX Triton II"),
 	DEVICE( INTEL,		INTEL_82439TX,	"82439TX"),
 	DEVICE( INTEL,		INTEL_82371AB_0,"82371AB PIIX4 ISA"),
@@ -554,11 +554,11 @@
 	      case PCI_CLASS_NOT_DEFINED:		return "Non-VGA device";
 	      case PCI_CLASS_NOT_DEFINED_VGA:		return "VGA compatible device";
 
-	      case PCI_CLASS_STORAGE_SCSI:		return "SCSI storage controller";
-	      case PCI_CLASS_STORAGE_IDE:		return "IDE interface";
+	      case PCI_CLASS_STORAGE_SCSI:		return "SCSI bus controller";
+	      case PCI_CLASS_STORAGE_IDE:		return "IDE controller";
 	      case PCI_CLASS_STORAGE_FLOPPY:		return "Floppy disk controller";
 	      case PCI_CLASS_STORAGE_IPI:		return "IPI bus controller";
-	      case PCI_CLASS_STORAGE_RAID:		return "RAID bus controller";
+	      case PCI_CLASS_STORAGE_RAID:		return "RAID controller";
 	      case PCI_CLASS_STORAGE_OTHER:		return "Unknown mass storage controller";
 
 	      case PCI_CLASS_NETWORK_ETHERNET:		return "Ethernet controller";
@@ -907,7 +907,7 @@
 		if (len + 40 > size) {
 			return -1;
 		}
-		len += sprintf(buf + len, "IRQ %x.  ", dev->irq);
+		len += sprintf(buf + len, "IRQ %d.  ", dev->irq);
 	}
 
 	if (dev->master) {
diff -u --recursive --new-file v2.1.72/linux/drivers/scsi/ide-scsi.c linux/drivers/scsi/ide-scsi.c
--- v2.1.72/linux/drivers/scsi/ide-scsi.c	Tue May 13 22:41:13 1997
+++ linux/drivers/scsi/ide-scsi.c	Wed Dec 17 11:11:17 1997
@@ -1,5 +1,5 @@
 /*
- * linux/drivers/scsi/ide-scsi.c	Version 0.2 - ALPHA	Jan  26, 1997
+ * linux/drivers/scsi/ide-scsi.c	Version 0.4		Dec   7, 1997
  *
  * Copyright (C) 1996, 1997 Gadi Oxman <gadio@netvision.net.il>
  */
@@ -15,9 +15,13 @@
  *                        of MODE_SENSE_6/MODE_SELECT_6 for cdroms. Thanks
  *                        to Janos Farkas for pointing this out.
  *                       Avoid using bitfields in structures for m68k.
- *                       Added Scather/Gather and DMA support.
+ *                       Added Scatter/Gather and DMA support.
+ * Ver 0.4   Dec  7 97   Add support for ATAPI PD/CD drives.
+ *                       Use variable timeout for each command.
  */
 
+#define IDESCSI_VERSION "0.4"
+
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/string.h>
@@ -49,11 +53,12 @@
 	struct request *rq;			/* The corresponding request */
 	byte *buffer;				/* Data buffer */
 	byte *current_position;			/* Pointer into the above buffer */
-	struct scatterlist *sg;			/* Scather gather table */
+	struct scatterlist *sg;			/* Scatter gather table */
 	int b_count;				/* Bytes transferred from current entry */
 	Scsi_Cmnd *scsi_cmd;			/* SCSI command */
 	void (*done)(Scsi_Cmnd *);		/* Scsi completion routine */
 	unsigned int flags;			/* Status/Action flags */
+	unsigned long timeout;			/* Command timeout */
 } idescsi_pc_t;
 
 /*
@@ -149,7 +154,7 @@
 	int i;
 
 	if (drive->media == ide_cdrom) {
-		if (c[0] == READ_6) {
+		if (c[0] == READ_6 || c[0] == WRITE_6) {
 			c[8] = c[4];		c[5] = c[3];		c[4] = c[2];
 			c[3] = c[1] & 0x1f;	c[2] = 0;		c[1] &= 0xe0;
 			c[0] = READ_10;
@@ -226,6 +231,11 @@
 	scsi->pc = NULL;
 }
 
+static inline unsigned long get_timeout(idescsi_pc_t *pc)
+{
+	return IDE_MAX(WAIT_CMD, pc->timeout - jiffies);
+}
+
 /*
  *	Our interrupt handler.
  */
@@ -247,7 +257,7 @@
 		printk ("ide-scsi: %s: DMA complete\n", drive->name);
 #endif /* IDESCSI_DEBUG_LOG */
 		pc->actually_transferred=pc->request_transfer;
-		(void) (HWIF(drive)->dmaproc(ide_dma_abort, drive));
+		(void) (HWIF(drive)->dmaproc(ide_dma_end, drive));
 	}
 
 	status = GET_STAT();						/* Clear the interrupt */
@@ -276,7 +286,7 @@
 			if (temp > pc->buffer_size) {
 				printk (KERN_ERR "ide-scsi: The scsi wants to send us more data than expected - discarding data\n");
 				idescsi_discard_data (drive,bcount);
-				ide_set_handler (drive,&idescsi_pc_intr,WAIT_CMD);
+				ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc));
 				return;
 			}
 #if IDESCSI_DEBUG_LOG
@@ -298,12 +308,13 @@
 	pc->actually_transferred+=bcount;				/* Update the current position */
 	pc->current_position+=bcount;
 
-	ide_set_handler (drive,&idescsi_pc_intr,WAIT_CMD);		/* And set the interrupt handler again */
+	ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc));	/* And set the interrupt handler again */
 }
 
 static void idescsi_transfer_pc (ide_drive_t *drive)
 {
 	idescsi_scsi_t *scsi = drive->driver_data;
+	idescsi_pc_t *pc = scsi->pc;
 	byte ireason;
 
 	if (ide_wait_stat (drive,DRQ_STAT,BUSY_STAT,WAIT_READY)) {
@@ -316,8 +327,8 @@
 		ide_do_reset (drive);
 		return;
 	}
-	ide_set_handler (drive, &idescsi_pc_intr, WAIT_CMD);	/* Set the interrupt routine */
-	atapi_output_bytes (drive, scsi->pc->c, 12);		/* Send the actual packet */
+	ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc));	/* Set the interrupt routine */
+	atapi_output_bytes (drive, scsi->pc->c, 12);			/* Send the actual packet */
 }
 
 /*
@@ -349,7 +360,7 @@
 		(void) (HWIF(drive)->dmaproc(ide_dma_begin, drive));
 	}
 	if (test_bit (IDESCSI_DRQ_INTERRUPT, &scsi->flags)) {
-		ide_set_handler (drive, &idescsi_transfer_pc, WAIT_CMD);
+		ide_set_handler (drive, &idescsi_transfer_pc, get_timeout(pc));
 		OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG);		/* Issue the packet command */
 	} else {
 		OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG);
@@ -426,6 +437,8 @@
  *	IDE subdriver functions, registered with ide.c
  */
 static ide_driver_t idescsi_driver = {
+	"ide-scsi",		/* name */
+	IDESCSI_VERSION,	/* version */
 	ide_scsi,		/* media */
 	0,			/* busy */
 	1,			/* supports_dma */
@@ -439,7 +452,8 @@
 	NULL,			/* media_change */
 	NULL,			/* pre_reset */
 	NULL,			/* capacity */
-	NULL			/* special */
+	NULL,			/* special */
+	NULL			/* proc */
 };
 
 static struct proc_dir_entry idescsi_proc_dir = {PROC_SCSI_IDESCSI, 8, "ide-scsi", S_IFDIR | S_IRUGO | S_IXUGO, 2};
@@ -555,7 +569,7 @@
 	int segments = pc->scsi_cmd->use_sg;
 	struct scatterlist *sg = pc->scsi_cmd->request_buffer;
 
-	if (!drive->using_dma || pc->request_transfer % 1024)
+	if (!drive->using_dma || !pc->request_transfer || pc->request_transfer % 1024)
 		return NULL;
 	if (idescsi_set_direction(pc))
 		return NULL;
@@ -619,6 +633,7 @@
 	pc->request_transfer = pc->buffer_size = cmd->request_bufflen;
 	pc->scsi_cmd = cmd;
 	pc->done = done;
+	pc->timeout = jiffies + cmd->timeout_per_command;
 	idescsi_transform_pc1 (drive, pc);
 
 	ide_init_drive_cmd (rq);
@@ -643,6 +658,18 @@
 int idescsi_reset (Scsi_Cmnd *cmd, unsigned int resetflags)
 {
 	return SCSI_RESET_PUNT;
+}
+
+int idescsi_bios (Disk *disk, kdev_t dev, int *parm)
+{
+	ide_drive_t *drive = idescsi_drives[disk->device->id];
+
+	if (drive->cyl && drive->head && drive->sect) {
+		parm[0] = drive->head;
+		parm[1] = drive->sect;
+		parm[2] = drive->cyl;
+	}
+	return 0;
 }
 
 #ifdef MODULE
diff -u --recursive --new-file v2.1.72/linux/drivers/scsi/ide-scsi.h linux/drivers/scsi/ide-scsi.h
--- v2.1.72/linux/drivers/scsi/ide-scsi.h	Sun Jan 26 02:07:18 1997
+++ linux/drivers/scsi/ide-scsi.h	Wed Dec 17 11:11:17 1997
@@ -13,6 +13,7 @@
 extern int idescsi_queue (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *));
 extern int idescsi_abort (Scsi_Cmnd *cmd);
 extern int idescsi_reset (Scsi_Cmnd *cmd, unsigned int resetflags);
+extern int idescsi_bios (Disk *disk, kdev_t dev, int *parm);
 
 #define IDESCSI								\
 {	NULL,			/* next		*/			\
@@ -28,7 +29,7 @@
 	idescsi_abort,		/* abort	*/			\
 	idescsi_reset,		/* reset	*/			\
 	NULL,			/* slave_attach	*/			\
-	NULL,			/* bios_param	*/			\
+	idescsi_bios,		/* bios_param	*/			\
 	10,			/* can_queue	*/			\
 	-1,			/* this_id	*/			\
 	256,			/* sg_tablesize	*/			\
diff -u --recursive --new-file v2.1.72/linux/drivers/scsi/st.c linux/drivers/scsi/st.c
--- v2.1.72/linux/drivers/scsi/st.c	Mon Nov 17 18:47:21 1997
+++ linux/drivers/scsi/st.c	Thu Dec 11 11:26:53 1997
@@ -580,6 +580,7 @@
       STp->buffer = st_buffers[i];
     (STp->buffer)->in_use = 1;
     (STp->buffer)->writing = 0;
+    (STp->buffer)->last_result_fatal = 0;
 
     flags = filp->f_flags;
     STp->write_prot = ((flags & O_ACCMODE) == O_RDONLY);
diff -u --recursive --new-file v2.1.72/linux/drivers/sgi/Makefile linux/drivers/sgi/Makefile
--- v2.1.72/linux/drivers/sgi/Makefile	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sgi/Makefile	Wed Dec 10 10:31:11 1997
@@ -0,0 +1,22 @@
+#
+# Makefile for the linux kernel.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now in the main makefile...
+
+SUB_DIRS     :=
+MOD_SUB_DIRS := $(SUB_DIRS)
+ALL_SUB_DIRS := $(SUB_DIRS) char
+
+L_OBJS   := 
+L_TARGET := sgi.a
+
+# Character devices for SGI machines.
+#
+SUB_DIRS += char
+L_OBJS += char/sgichar.o
+
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.1.72/linux/drivers/sgi/char/Makefile linux/drivers/sgi/char/Makefile
--- v2.1.72/linux/drivers/sgi/char/Makefile	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sgi/char/Makefile	Wed Dec 10 10:31:11 1997
@@ -0,0 +1,18 @@
+#
+# Makefile for the linux kernel.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now in the main makefile...
+
+O_TARGET := sgichar.o
+O_OBJS   := graphics.o streamable.o newport.o cons_newport.o sgicons.o \
+	vga_font.o rrm.o shmiq.o usema.o
+
+ifeq ($(CONFIG_SGI_SERIAL),y)
+  O_OBJS += sgiserial.o
+endif
+
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.1.72/linux/drivers/sgi/char/cons_newport.c linux/drivers/sgi/char/cons_newport.c
--- v2.1.72/linux/drivers/sgi/char/cons_newport.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sgi/char/cons_newport.c	Wed Dec 10 10:31:11 1997
@@ -0,0 +1,611 @@
+/*
+ * cons_newport.c: Newport graphics console code for the SGI.
+ *
+ * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ *
+ * $Id: cons_newport.c,v 1.1 1997/12/02 02:28:23 ralf Exp $
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/errno.h>
+#include <linux/kd.h>
+#include <linux/tty.h>
+#include <linux/malloc.h>
+#include <linux/major.h>
+#include <linux/mm.h>
+#include <linux/version.h>
+
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/bitops.h>
+#include <asm/sgialib.h>
+#include <asm/ptrace.h>
+
+#include <linux/kbd_kern.h>
+#include <linux/vt_kern.h>
+#include <linux/consolemap.h>
+#include <linux/selection.h>
+#include <linux/console_struct.h>
+
+#include "gconsole.h"
+#include "newport.h"
+#include "graphics.h" /* Just for now */
+#include <asm/gfx.h>
+#include <asm/ng1.h>
+
+#if 0
+#include "linux_logo.h"
+#endif
+
+#define BMASK(c) (c << 24)
+
+#define RENDER(regs, cp) do { \
+(regs)->go.zpattern = BMASK((cp)[0x0]); (regs)->go.zpattern = BMASK((cp)[0x1]); \
+(regs)->go.zpattern = BMASK((cp)[0x2]); (regs)->go.zpattern = BMASK((cp)[0x3]); \
+(regs)->go.zpattern = BMASK((cp)[0x4]); (regs)->go.zpattern = BMASK((cp)[0x5]); \
+(regs)->go.zpattern = BMASK((cp)[0x6]); (regs)->go.zpattern = BMASK((cp)[0x7]); \
+(regs)->go.zpattern = BMASK((cp)[0x8]); (regs)->go.zpattern = BMASK((cp)[0x9]); \
+(regs)->go.zpattern = BMASK((cp)[0xa]); (regs)->go.zpattern = BMASK((cp)[0xb]); \
+(regs)->go.zpattern = BMASK((cp)[0xc]); (regs)->go.zpattern = BMASK((cp)[0xd]); \
+(regs)->go.zpattern = BMASK((cp)[0xe]); (regs)->go.zpattern = BMASK((cp)[0xf]); \
+} while(0)        
+
+#define REVERSE_RENDER(regs, cp) do { \
+(regs)->go.zpattern = BMASK((~(cp)[0x0])); (regs)->go.zpattern = BMASK((~(cp)[0x1])); \
+(regs)->go.zpattern = BMASK((~(cp)[0x2])); (regs)->go.zpattern = BMASK((~(cp)[0x3])); \
+(regs)->go.zpattern = BMASK((~(cp)[0x4])); (regs)->go.zpattern = BMASK((~(cp)[0x5])); \
+(regs)->go.zpattern = BMASK((~(cp)[0x6])); (regs)->go.zpattern = BMASK((~(cp)[0x7])); \
+(regs)->go.zpattern = BMASK((~(cp)[0x8])); (regs)->go.zpattern = BMASK((~(cp)[0x9])); \
+(regs)->go.zpattern = BMASK((~(cp)[0xa])); (regs)->go.zpattern = BMASK((~(cp)[0xb])); \
+(regs)->go.zpattern = BMASK((~(cp)[0xc])); (regs)->go.zpattern = BMASK((~(cp)[0xd])); \
+(regs)->go.zpattern = BMASK((~(cp)[0xe])); (regs)->go.zpattern = BMASK((~(cp)[0xf])); \
+} while(0)        
+
+extern int default_red[16], default_grn[16], default_blu[16];
+extern unsigned char video_type;
+
+static int cursor_pos = -1;
+struct newport_regs *npregs;
+
+#define TESTVAL 0xdeadbeef
+#define XSTI_TO_FXSTART(val) (((val) & 0xffff) << 11)
+
+static inline void
+newport_disable_video(void)
+{
+	unsigned short treg;
+
+	treg = newport_vc2_get(npregs, VC2_IREG_CONTROL);
+	newport_vc2_set(npregs, VC2_IREG_CONTROL, (treg & ~(VC2_CTRL_EVIDEO)));
+}
+
+static inline void
+newport_enable_video(void)
+{
+	unsigned short treg;
+
+	treg = newport_vc2_get(npregs, VC2_IREG_CONTROL);
+	newport_vc2_set(npregs, VC2_IREG_CONTROL, (treg | VC2_CTRL_EVIDEO));
+}
+
+static inline void
+newport_disable_cursor(void)
+{
+	unsigned short treg;
+
+	treg = newport_vc2_get(npregs, VC2_IREG_CONTROL);
+	newport_vc2_set(npregs, VC2_IREG_CONTROL, (treg & ~(VC2_CTRL_ECDISP)));
+}
+
+#if 0
+static inline void
+newport_enable_cursor(void)
+{
+	unsigned short treg;
+
+	treg = newport_vc2_get(npregs, VC2_IREG_CONTROL);
+	newport_vc2_set(npregs, VC2_IREG_CONTROL, (treg | VC2_CTRL_ECDISP));
+}
+#endif
+
+static inline void
+newport_init_cmap(void)
+{
+	unsigned short i;
+
+	for(i = 0; i < 16; i++) {
+		newport_bfwait();
+		newport_cmap_setaddr(npregs, color_table[i]);
+		newport_cmap_setrgb(npregs,
+				    default_red[i],
+				    default_grn[i],
+				    default_blu[i]);
+	}
+}
+
+#if 0
+static inline void
+newport_init_cursor(void)
+{
+	unsigned char cursor[256];
+	unsigned short *cookie;
+	int i;
+
+	for(i = 0; i < 256; i++)
+		cursor[i] = 0x0;
+	for(i = 211; i < 256; i+=4) {
+		cursor[i] = 0xff;
+#if 0
+		cursor[(i + 128) << 2] = 0xff;
+		cursor[((i + 128) << 2) + 1] = 0xff;
+#endif
+	}
+
+	/* Load the SRAM on the VC2 for this new GLYPH. */
+	cookie = (unsigned short *) cursor;
+	newport_vc2_set(npregs, VC2_IREG_RADDR, VC2_CGLYPH_ADDR);
+	npregs->set.dcbmode = (NPORT_DMODE_AVC2 | VC2_REGADDR_RAM |
+			       NPORT_DMODE_W2 | VC2_PROTOCOL);
+	for(i = 0; i < 128; i++) {
+		newport_bfwait();
+		npregs->set.dcbdata0.hwords.s1 = *cookie++;
+	}
+
+	/* Place the cursor at origin. */
+	newport_vc2_set(npregs, VC2_IREG_CURSX, 0);
+	newport_vc2_set(npregs, VC2_IREG_CURSY, 0);
+	newport_enable_cursor();
+}
+#endif
+
+static inline void
+newport_clear_screen(void)
+{
+	newport_wait();
+	npregs->set.wrmask = 0xffffffff;
+	npregs->set.drawmode0 = (NPORT_DMODE0_DRAW | NPORT_DMODE0_BLOCK |
+			      NPORT_DMODE0_DOSETUP | NPORT_DMODE0_STOPX |
+			      NPORT_DMODE0_STOPY);
+	npregs->set.colori = 0;
+	npregs->set.xystarti = 0;
+	npregs->go.xyendi = (((1280 + 63) << 16)|(1024));
+	newport_bfwait();
+}
+
+static inline void
+newport_render_version(void)
+{
+#if 0
+	unsigned short *ush;
+	int currcons = 0;
+	char *p;
+
+	ush = (unsigned short *) video_mem_base + video_num_columns * 2 + 20;
+	for (p = "SGI/Linux version " UTS_RELEASE; *p; p++, ush++) {
+		*ush = (attr << 8) + *p;
+		newport_blitc (*ush, (unsigned long) ush);
+	}
+#endif
+}
+
+#if 0
+static inline void
+newport_render_logo(void)
+{
+	int i, xpos, ypos;
+	unsigned char *bmap;
+
+	xpos = 8;
+	ypos = 18;
+
+	newport_wait();
+	npregs->set.colori = 9;
+	npregs->set.drawmode0 = (NPORT_DMODE0_DRAW | NPORT_DMODE0_BLOCK |
+			      NPORT_DMODE0_STOPX | NPORT_DMODE0_ZPENAB |
+			      NPORT_DMODE0_L32);
+
+	for(i = 0; i < 80; i+=8) {
+		/* Set coordinates for bitmap operation. */
+		npregs->set.xystarti = ((xpos + i) << 16) | ypos;
+		npregs->set.xyendi = (((xpos + i) + 7) << 16);
+		newport_wait();
+
+		bmap = linux_logo + (i * 80);
+		RENDER(npregs, bmap); bmap += 0x10;
+		RENDER(npregs, bmap); bmap += 0x10;
+		RENDER(npregs, bmap); bmap += 0x10;
+		RENDER(npregs, bmap); bmap += 0x10;
+		RENDER(npregs, bmap);
+	}
+	prom_getchar();
+	prom_imode();
+}
+#endif
+
+static inline void
+newport_render_background(int xpos, int ypos, int ci)
+{
+	newport_wait();
+	npregs->set.wrmask = 0xffffffff;
+	npregs->set.drawmode0 = (NPORT_DMODE0_DRAW | NPORT_DMODE0_BLOCK |
+			      NPORT_DMODE0_DOSETUP | NPORT_DMODE0_STOPX |
+			      NPORT_DMODE0_STOPY);
+	npregs->set.colori = ci;
+	npregs->set.xystarti = (xpos << 16) | ypos;
+	npregs->go.xyendi = ((xpos + 7) << 16) | (ypos + 15);
+}
+
+void
+newport_set_origin(unsigned short offset)
+{
+	/* maybe this works... */
+	__origin = offset;
+}
+
+void
+newport_hide_cursor(void)
+{
+	int xpos, ypos, idx;
+	unsigned long flags;
+
+	if(vt_cons[fg_console]->vc_mode == KD_GRAPHICS)
+		return;
+	save_and_cli(flags);
+
+	idx = cursor_pos;
+	if(idx == -1) {
+		restore_flags(flags);
+		return;
+	}
+	xpos = 8 + ((idx % video_num_columns) << 3);
+	ypos = 18 + ((idx / video_num_columns) << 4);
+	newport_render_background(xpos, ypos, 0);
+	restore_flags(flags);
+}
+
+void
+newport_set_cursor(int currcons)
+{
+	int xpos, ypos, idx, oldpos;
+	unsigned short *sp, *osp, cattr;
+	unsigned long flags;
+	unsigned char *p;
+
+	if (currcons != fg_console || console_blanked || vcmode == KD_GRAPHICS)
+		return;
+
+	if (__real_origin != __origin)
+		__set_origin(__real_origin);
+
+	save_and_cli(flags);
+
+	idx = (pos - video_mem_base) >> 1;
+	sp = (unsigned short *) pos;
+	oldpos = cursor_pos;
+	cursor_pos = idx;
+	if(!deccm) {
+		hide_cursor();
+		restore_flags(flags);
+		return;
+	}
+	xpos = 8 + ((idx % video_num_columns) << 3);
+	ypos = 18 + ((idx / video_num_columns) << 4);
+	if(oldpos != -1) {
+		int oxpos, oypos;
+
+		/* Restore old location. */
+		osp = (unsigned short *) ((oldpos << 1) + video_mem_base);
+		oxpos = 8 + ((oldpos % video_num_columns) << 3);
+		oypos = 18 + ((oldpos / video_num_columns) << 4);
+		cattr = *osp;
+		newport_render_background(oxpos, oypos, (cattr & 0xf000) >> 12);
+		p = &vga_font[(cattr & 0xff) << 4];
+		newport_wait();
+		npregs->set.colori = (cattr & 0x0f00) >> 8;
+		npregs->set.drawmode0 = (NPORT_DMODE0_DRAW | NPORT_DMODE0_BLOCK |
+				      NPORT_DMODE0_STOPX | NPORT_DMODE0_ZPENAB |
+				      NPORT_DMODE0_L32);
+		npregs->set.xystarti = (oxpos << 16) | oypos;
+		npregs->set.xyendi = ((oxpos + 7) << 16);
+		newport_wait();
+		RENDER(npregs, p);
+	}
+	cattr = *sp;
+	newport_render_background(xpos, ypos, (cattr & 0xf000) >> 12);
+	p = &vga_font[(cattr & 0xff) << 4];
+	newport_wait();
+	npregs->set.colori = (cattr & 0x0f00) >> 8;
+	npregs->set.drawmode0 = (NPORT_DMODE0_DRAW | NPORT_DMODE0_BLOCK |
+			      NPORT_DMODE0_STOPX | NPORT_DMODE0_ZPENAB |
+			      NPORT_DMODE0_L32);
+	npregs->set.xystarti = (xpos << 16) | ypos;
+	npregs->set.xyendi = ((xpos + 7) << 16);
+	newport_wait();
+	REVERSE_RENDER(npregs, p);
+	restore_flags (flags);
+	return;
+}
+
+void
+newport_get_scrmem(int currcons)
+{
+	memcpyw((unsigned short *)vc_scrbuf[currcons],
+		(unsigned short *)origin, video_screen_size);
+	origin = video_mem_start = (unsigned long)vc_scrbuf[currcons];
+	scr_end = video_mem_end = video_mem_start + video_screen_size;
+	pos = origin + y*video_size_row + (x<<1);
+}
+
+void
+newport_set_scrmem(int currcons, long offset)
+{
+	if (video_mem_term - video_mem_base < offset + video_screen_size)
+		offset = 0;
+	memcpyw((unsigned short *)(video_mem_base + offset),
+		(unsigned short *) origin, video_screen_size);
+	video_mem_start = video_mem_base;
+	video_mem_end = video_mem_term;
+	origin = video_mem_base + offset;
+	scr_end = origin + video_screen_size;
+	pos = origin + y*video_size_row + (x<<1);
+	has_wrapped = 0;
+}
+
+int
+newport_set_get_cmap(unsigned char * arg, int set)
+{
+	unsigned short ent;
+	int i;
+
+	i = verify_area(set ? VERIFY_READ : VERIFY_WRITE, (void *)arg, 16*3);
+	if (i)
+		return i;
+
+	for (i=0; i<16; i++) {
+		if (set) {
+			__get_user(default_red[i], arg++);
+			__get_user(default_grn[i], arg++);
+			__get_user(default_blu[i], arg++);
+		} else {
+			__put_user (default_red[i], arg++);
+			__put_user (default_grn[i], arg++);
+			__put_user (default_blu[i], arg++);
+		}
+	}
+	if (set) {
+		for (i=0; i<MAX_NR_CONSOLES; i++) {
+			if (vc_cons_allocated(i)) {
+				int j, k;
+				for (j = k = 0; j<16; j++) {
+					vc_cons[i].d->vc_palette[k++] =
+						default_red[j];
+					vc_cons[i].d->vc_palette[k++] =
+						default_grn[j];
+					vc_cons[i].d->vc_palette[k++] =
+						default_blu[j];
+				}
+			}
+		}
+		if(console_blanked || vt_cons[fg_console]->vc_mode == KD_GRAPHICS)
+			return 0;
+		for(ent = 0; ent < 16; ent++) {
+			newport_bfwait();
+			newport_cmap_setaddr(npregs, ent);
+			newport_cmap_setrgb(npregs,
+					    default_red[ent],
+					    default_grn[ent],
+					    default_blu[ent]);
+		}
+	}
+
+	return 0;
+}
+
+void
+newport_blitc(unsigned short charattr, unsigned long addr)
+{
+	int idx, xpos, ypos;
+	unsigned char *p;
+
+	idx = (addr - (video_mem_base + (__origin<<1))) >> 1;
+	xpos = 8 + ((idx % video_num_columns) << 3);
+	ypos = 18 + ((idx / video_num_columns) << 4);
+
+	p = &vga_font[(charattr & 0xff) << 4];
+	charattr = (charattr >> 8) & 0xff;
+
+	newport_render_background(xpos, ypos, (charattr & 0xf0) >> 4);
+
+	/* Set the color and drawing mode. */
+	newport_wait();
+	npregs->set.colori = charattr & 0xf;
+	npregs->set.drawmode0 = (NPORT_DMODE0_DRAW | NPORT_DMODE0_BLOCK |
+			      NPORT_DMODE0_STOPX | NPORT_DMODE0_ZPENAB |
+			      NPORT_DMODE0_L32);
+
+	/* Set coordinates for bitmap operation. */
+	npregs->set.xystarti = (xpos << 16) | ypos;
+	npregs->set.xyendi = ((xpos + 7) << 16);
+	newport_wait();
+
+	/* Go, baby, go... */
+	RENDER(npregs, p);
+}
+
+void
+newport_memsetw(void * s, unsigned short c, unsigned int count)
+{
+	unsigned short * addr = (unsigned short *) s;
+
+	count /= 2;
+	if (vt_cons[fg_console]->vc_mode == KD_GRAPHICS) {
+		while (count) {
+			count--;
+			*addr++ = c;
+		}
+		return;
+	}
+	if ((unsigned long) addr + count > video_mem_term ||
+	    (unsigned long) addr < video_mem_base) {
+	    	if ((unsigned long) addr + count <= video_mem_term ||
+	    	    (unsigned long) addr > video_mem_base) {
+			while (count) {
+				count--;
+				*addr++ = c;
+			}
+			return;
+	    	} else {
+			while (count) {
+				count--;
+				scr_writew(c, addr++);
+			}
+		}
+	} else {
+		while (count) {
+			count--;
+			if (*addr != c) {
+				newport_blitc(c, (unsigned long)addr);
+				*addr++ = c;
+			} else
+				addr++;
+		}
+	}
+}
+
+void
+newport_memcpyw(unsigned short *to, unsigned short *from, unsigned int count)
+{
+	if (vt_cons[fg_console]->vc_mode == KD_GRAPHICS) {
+		memcpy(to, from, count);
+		return;
+	}
+	if ((unsigned long) to + count > video_mem_term ||
+	    (unsigned long) to < video_mem_base) {
+	    	if ((unsigned long) to + count <= video_mem_term ||
+	    	    (unsigned long) to > video_mem_base)
+	    	    	memcpy(to, from, count);
+	    	else {
+	    		count /= 2;
+			while (count) {
+				count--;
+				scr_writew(scr_readw(from++), to++);
+			}
+		}
+	} else {
+		count /= 2;
+		while (count) {
+			count--;
+			if (*to != *from) {
+				newport_blitc(*from, (unsigned long)to);
+				*to++ = *from++;
+			} else {
+				from++;
+				to++;
+			}
+		}
+	}
+}
+
+struct console_ops newport_console = {
+	newport_set_origin,
+	newport_hide_cursor,
+	newport_set_cursor,
+	newport_get_scrmem,
+	newport_set_scrmem,
+	newport_set_get_cmap,
+	newport_blitc,
+	newport_memsetw,
+	newport_memcpyw
+};
+
+/* Currently hard-coded values that are the same as those found on my system */
+struct ng1_info newport_board_info = {
+	{ "NG1", "" /* what is the label? */, 1280, 1024, sizeof (struct ng1_info) },
+	6,			/* boardrev */
+	1,			/* rex3rev */
+	0,			/* vc2rev */
+	2,			/* monitor type */
+        0,			/* videoinstalled */
+	3,			/* mcrev */
+	24,			/* bitplanes */
+	0,			/* xmap9rev */
+	2,			/* cmaprev */
+	{ 256, 1280, 1024, 76},	/* ng1_vof_info */
+	13,			/* paneltype */
+	0
+};
+
+void
+newport_reset (void)
+{
+	newport_wait();
+	newport_enable_video();
+
+	/* Init the cursor disappear. */
+	newport_wait();
+#if 0
+	newport_init_cursor();
+#else
+	newport_disable_cursor();
+#endif
+
+	newport_init_cmap();
+
+	/* Clear the screen. */
+	newport_clear_screen();
+}
+
+/* right now the newport does not do anything at all */
+struct graphics_ops newport_graphic_ops = {
+	0,			      /* owner */
+	0,			      /* current user */
+	(void *) &newport_board_info, /* board info */
+	sizeof (struct ng1_info),     /* size of our data structure */
+	0, 0,			      /* g_regs, g_regs_size */
+	newport_save, newport_restore, /* g_save_context, g_restore_context */
+	newport_reset, newport_ioctl /* g_reset_console, g_ioctl */
+};
+
+struct graphics_ops *
+newport_probe (int slot, const char **name)
+{
+	struct newport_regs *p;
+
+	npregs = (struct newport_regs *) (KSEG1 + 0x1f0f0000);
+	
+	p = npregs;
+	p->cset.config = NPORT_CFG_GD0;
+
+	if(newport_wait()) {
+		prom_printf("whoops, timeout, no NEWPORT there?");
+		return 0;
+	}
+
+	p->set.xstarti = TESTVAL; if(p->set._xstart.i != XSTI_TO_FXSTART(TESTVAL)) {
+		prom_printf("newport_probe: read back wrong value ;-(\n");
+		return 0;
+	}
+
+	if (slot == 0){
+		register_gconsole (&newport_console);
+		video_type = VIDEO_TYPE_SGI;
+		can_do_color = 1;
+		*name = "NEWPORT";
+	}
+
+	newport_reset ();
+	newport_render_version();
+#if 0
+	newport_render_logo();
+#endif
+	newport_graphic_ops.g_regs = 0x1f0f0000;
+	newport_graphic_ops.g_regs_size = sizeof (struct newport_regs);
+	return &newport_graphic_ops;
+}
diff -u --recursive --new-file v2.1.72/linux/drivers/sgi/char/gconsole.h linux/drivers/sgi/char/gconsole.h
--- v2.1.72/linux/drivers/sgi/char/gconsole.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sgi/char/gconsole.h	Wed Dec 10 10:31:11 1997
@@ -0,0 +1,33 @@
+/*
+ * This is a temporary measure, we should eventually migrate to
+ * Gert's generic graphic console code.
+ */
+
+#define cmapsz 8192
+#define CHAR_HEIGHT  16
+
+struct console_ops {
+	void (*set_origin)(unsigned short offset);
+	void (*hide_cursor)(void);
+	void (*set_cursor)(int currcons);
+	void (*get_scrmem)(int currcons);
+	void (*set_scrmem)(int currcons, long offset);
+	int  (*set_get_cmap)(unsigned char *arg, int set);
+	void (*blitc)(unsigned short charattr, unsigned long addr);
+	void (*memsetw)(void *s, unsigned short c, unsigned int count);
+	void (*memcpyw)(unsigned short *to, unsigned short *from, unsigned int count);
+};
+
+void register_gconsole (struct console_ops *);
+
+/* This points to the system console */
+extern struct console_ops *gconsole;
+
+extern void gfx_init (const char **name);
+
+extern void __set_origin (unsigned short offset);
+extern void hide_cursor (void);
+extern unsigned char vga_font[];
+
+extern void disable_gconsole (void);
+extern void enable_gconsole (void);
diff -u --recursive --new-file v2.1.72/linux/drivers/sgi/char/graphics.c linux/drivers/sgi/char/graphics.c
--- v2.1.72/linux/drivers/sgi/char/graphics.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sgi/char/graphics.c	Wed Dec 10 10:31:11 1997
@@ -0,0 +1,327 @@
+/*
+ * gfx.c: support for SGI's /dev/graphics, /dev/opengl
+ *
+ * Author: Miguel de Icaza (miguel@nuclecu.unam.mx)
+ *
+ * On IRIX, /dev/graphics is [10, 146]
+ *          /dev/opengl   is [10, 147]
+ *
+ * From a mail with Mark J. Kilgard, /dev/opengl and /dev/graphics are
+ * the same thing, the use of /dev/graphics seems deprecated though.
+ *
+ * The reason that the original SGI programmer had to use only one
+ * device for all the graphic cards on the system will remain a
+ * mistery for the rest of our lives.  Why some ioctls take a board
+ * number and some others not?  Mistery.  Why do they map the hardware
+ * registers into the user address space with an ioctl instead of
+ * mmap?  Mistery too.  Why they did not use the standard way of
+ * making ioctl constants and instead sticked a random constant?
+ * Mistery too.
+ *
+ * We implement those misterious things, and tried not to think about
+ * the reasons behind them.
+ */
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/mman.h>
+#include <asm/uaccess.h>
+#include "gconsole.h"
+#include "graphics.h"
+#include <asm/gfx.h>
+#include <asm/rrm.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+
+/* The boards */
+#include "newport.h"
+
+#ifdef PRODUCTION_DRIVER
+#define enable_gconsole()
+#define disable_gconsole()
+#endif
+
+static struct graphics_ops cards [MAXCARDS];
+static int boards;
+
+#define GRAPHICS_CARD(inode) 0
+
+int
+sgi_graphics_open (struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+int
+sgi_graphics_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+	unsigned int board;
+	unsigned int devnum = GRAPHICS_CARD (inode->i_rdev);
+	int i;
+	
+	if ((cmd >= RRM_BASE) && (cmd <= RRM_CMD_LIMIT))
+		return rrm_command (cmd-RRM_BASE, (void *) arg);
+	
+	switch (cmd){
+	case GFX_GETNUM_BOARDS:
+		return boards;
+
+	case GFX_GETBOARD_INFO: {
+		struct gfx_getboardinfo_args *bia = (void *) arg;
+		void   *dest_buf;
+		int    max_len;
+		
+		i = verify_area (VERIFY_READ, (void *) arg, sizeof (struct gfx_getboardinfo_args));
+		if (i) return i;
+		
+		__get_user_ret (board,    &bia->board, -EFAULT);
+		__get_user_ret (dest_buf, &bia->buf,   -EFAULT);
+		__get_user_ret (max_len,  &bia->len,   -EFAULT);
+
+		if (board >= boards)
+			return -EINVAL;
+		if (max_len < sizeof (struct gfx_getboardinfo_args))
+			return -EINVAL;
+		if (max_len > cards [board].g_board_info_len)
+			max_len = cards [boards].g_board_info_len;
+		i = verify_area (VERIFY_WRITE, dest_buf, max_len);
+		if (i) return i;
+		if (copy_to_user (dest_buf, cards [board].g_board_info, max_len))
+			return -EFAULT;
+		return max_len;
+	}
+
+	case GFX_ATTACH_BOARD: {
+		struct gfx_attach_board_args *att = (void *) arg;
+		void *vaddr;
+		int  r;
+
+		i = verify_area (VERIFY_READ, (void *)arg, sizeof (struct gfx_attach_board_args));
+		if (i) return i;
+
+		__get_user_ret (board, &att->board, -EFAULT);
+		__get_user_ret (vaddr, &att->vaddr, -EFAULT);
+
+		/* Ok for now we are assuming /dev/graphicsN -> head N even
+		 * if the ioctl api suggests that this is not quite the case.
+		 *
+		 * Otherwise we fail, we use this assumption in the mmap code
+		 * below to find our board information.
+		 */
+		if (board != devnum){
+			printk ("Parameter board does not match the current board\n");
+			return -EINVAL;
+		}
+		
+		if (board >= boards)
+			return -EINVAL;
+
+		/* If it is the first opening it, then make it the board owner */
+		if (!cards [board].g_owner)
+			cards [board].g_owner = current;
+
+		/*
+		 * Ok, we now call mmap on this file, which will end up calling
+		 * sgi_graphics_mmap
+		 */
+		disable_gconsole ();
+		r = do_mmap (file, (unsigned long)vaddr, cards [board].g_regs_size,
+			 PROT_READ|PROT_WRITE, MAP_FIXED|MAP_PRIVATE, 0);
+		if (r)
+			return r;
+
+	}
+
+	/* Strange, the real mapping seems to be done at GFX_ATTACH_BOARD,
+	 * GFX_MAPALL is not even used by IRIX X server
+	 */
+	case GFX_MAPALL:
+		return 0;
+
+	case GFX_LABEL:
+		return 0;
+			
+		/* Version check
+		 * for my IRIX 6.2 X server, this is what the kernel returns
+		 */
+	case 1:
+		return 3;
+		
+	/* Xsgi does not use this one, I assume minor is the board being queried */
+	case GFX_IS_MANAGED:
+		if (devnum > boards)
+			return -EINVAL;
+		return (cards [devnum].g_owner != 0);
+
+	default:
+		if (cards [devnum].g_ioctl)
+			return (*cards [devnum].g_ioctl)(devnum, cmd, arg);
+		
+	}
+	return -EINVAL;
+}
+
+int
+sgi_graphics_close (struct inode *inode, struct file *file)
+{
+	int board = GRAPHICS_CARD (inode->i_rdev);
+	
+	/* Tell the rendering manager that one client is going away */
+	rrm_close (inode, file);
+
+	/* Was this file handle from the board owner?, clear it */
+	if (current == cards [board].g_owner){
+		cards [board].g_owner = 0;
+		(*cards [board].g_reset_console)();
+		enable_gconsole ();
+	}
+	return 0;
+}
+
+/* 
+ * This is the core of the direct rendering engine.
+ */
+
+unsigned long
+sgi_graphics_nopage (struct vm_area_struct *vma, unsigned long address, int write_access)
+{
+	unsigned long page;
+	int board = GRAPHICS_CARD (vma->vm_dentry->d_inode->i_rdev);
+
+#ifdef DEBUG_GRAPHICS
+	printk ("Got a page fault for board %d address=%lx guser=%lx\n", board, address,
+		cards [board].g_user);
+#endif
+	
+	/* 1. figure out if another process has this mapped,
+	 * and revoke the mapping in that case.
+	 */
+	if (cards [board].g_user && cards [board].g_user != current){
+		/* FIXME: save graphics context here, dump it to rendering node? */
+		remove_mapping (cards [board].g_user, vma->vm_start, vma->vm_end);
+	}
+	cards [board].g_user = current;
+#if DEBUG_GRAPHICS
+	printk ("Registers: 0x%lx\n", cards [board].g_regs);
+	printk ("vm_start:  0x%lx\n", vma->vm_start);
+	printk ("address:   0x%lx\n", address);
+	printk ("diff:      0x%lx\n", (address - vma->vm_start));
+
+	printk ("page/pfn:  0x%lx\n", page);
+	printk ("TLB entry: %lx\n", pte_val (mk_pte (page + PAGE_OFFSET, PAGE_USERIO)));
+#endif
+	
+	/* 2. Map this into the current process address space */
+	page = ((cards [board].g_regs) + (address - vma->vm_start));
+	return page + PAGE_OFFSET;
+}
+
+/*
+ * We convert a GFX ioctl for mapping hardware registers, in a nice sys_mmap
+ * call, which takes care of everything that must be taken care of.
+ *
+ */
+
+static struct vm_operations_struct graphics_mmap = {
+	NULL,			/* no special mmap-open */
+	NULL,			/* no special mmap-close */
+	NULL,			/* no special mmap-unmap */
+	NULL,			/* no special mmap-protect */
+	NULL,			/* no special mmap-sync */
+	NULL,			/* no special mmap-advise */
+	sgi_graphics_nopage,	/* our magic no-page fault handler */
+	NULL,			/* no special mmap-wppage */
+	NULL,			/* no special mmap-swapout */
+	NULL			/* no special mmap-swapin */
+};
+	
+int
+sgi_graphics_mmap (struct inode *inode, struct file *file, struct vm_area_struct *vma)
+{
+	uint size;
+
+	size = vma->vm_end - vma->vm_start;
+	if (vma->vm_offset & ~PAGE_MASK)
+		return -ENXIO;
+
+	/* 1. Set our special graphic virtualizer  */
+	vma->vm_ops = &graphics_mmap;
+
+	/* 2. Set the special tlb permission bits */
+	vma->vm_page_prot = PAGE_USERIO;
+		
+	/* final setup */
+	vma->vm_dentry = dget (file->f_dentry);
+	return 0;
+}
+	
+/* Do any post card-detection setup on graphics_ops */
+static void
+graphics_ops_post_init (int slot)
+{
+	/* There is no owner for the card initially */
+	cards [slot].g_owner = (struct task_struct *) 0;
+	cards [slot].g_user  = (struct task_struct *) 0;
+}
+
+struct file_operations sgi_graphics_fops = {
+	NULL,			/* llseek */
+	NULL,			/* read */
+	NULL,			/* write */
+	NULL,			/* readdir */
+	NULL,			/* poll */
+	sgi_graphics_ioctl,	/* ioctl */
+	sgi_graphics_mmap,	/* mmap */
+	sgi_graphics_open,	/* open */
+	sgi_graphics_close,	/* release */
+	NULL,			/* fsync */
+	NULL,			/* check_media_change */
+	NULL,			/* revalidate */
+	NULL			/* lock */
+};
+
+/* /dev/graphics */
+static struct miscdevice dev_graphics = {
+        SGI_GRAPHICS_MINOR, "sgi-graphics", &sgi_graphics_fops
+};
+
+/* /dev/opengl */
+static struct miscdevice dev_opengl = {
+        SGI_OPENGL_MINOR, "sgi-opengl", &sgi_graphics_fops
+};
+
+/* This is called later from the misc-init routine */
+void
+gfx_register (void)
+{
+	misc_register (&dev_graphics);
+	misc_register (&dev_opengl);
+}
+
+void 
+gfx_init (const char **name)
+{
+	struct console_ops *console;
+	struct graphics_ops *g;
+
+	printk ("GFX INIT: ");
+	shmiq_init ();
+	usema_init ();
+	
+	if ((g = newport_probe (boards, name)) != 0){
+		cards [boards] = *g;
+		graphics_ops_post_init (boards);
+		boards++;
+		console = 0;
+	}
+	/* Add more graphic drivers here */
+	/* Keep passing console around */
+	
+	if (boards > MAXCARDS){
+		printk ("Too many cards found on the system\n");
+		prom_halt ();
+	}
+}
+
+
diff -u --recursive --new-file v2.1.72/linux/drivers/sgi/char/graphics.h linux/drivers/sgi/char/graphics.h
--- v2.1.72/linux/drivers/sgi/char/graphics.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sgi/char/graphics.h	Wed Dec 10 10:31:11 1997
@@ -0,0 +1,28 @@
+#define MAXCARDS 4
+
+struct graphics_ops {
+	/* SGIism: Board owner, gets the shmiq requests from the kernel */
+	struct task_struct *g_owner;
+
+	/* Last process that got the graphics registers mapped  */
+	struct task_struct *g_user;
+	
+	/* Board info */
+	void               *g_board_info;
+	int                g_board_info_len;
+
+	/* These point to hardware registers that should be mapped with
+	 * GFX_ATTACH_BOARD and the size of the information pointed to
+	 */
+	unsigned long      g_regs;
+	int                g_regs_size;
+
+	void (*g_save_context)(void *);
+	void (*g_restore_context)(void *);
+	void (*g_reset_console)(void);
+	int  (*g_ioctl)(int device, int cmd, unsigned long arg);
+};
+
+void shmiq_init (void);
+void streamable_init (void);
+void usema_init (void);
diff -u --recursive --new-file v2.1.72/linux/drivers/sgi/char/linux_logo.h linux/drivers/sgi/char/linux_logo.h
--- v2.1.72/linux/drivers/sgi/char/linux_logo.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sgi/char/linux_logo.h	Wed Dec 10 10:31:11 1997
@@ -0,0 +1,909 @@
+/* This is a linux logo to be displayed on boot.
+ *
+ * You can put anything here, but:
+ * LINUX_LOGO_COLORS has to be less than 224
+ * image size has to be 80x80
+ * values have to start from0x20
+ * (i.e. RGB(linux_logo_red[0],
+ *	     linux_logo_green[0],
+ *	     linux_logo_blue[0]) is color0x20)
+ */
+
+#define LINUX_LOGO_COLORS 221
+
+unsigned char linux_logo_red[] = {
+  0xF3, 0xF6, 0xF8, 0xF7, 0xEF, 0xE7, 0xE5, 0xE3,
+  0xCA, 0xD4, 0xDD, 0xC8, 0xC7, 0xC4, 0xC2, 0xE5,
+  0xF1, 0xED, 0xEE, 0xE6, 0xC6, 0xDA, 0xDD, 0xE5,
+  0xD9, 0xC6, 0xE3, 0xD0, 0xC6, 0xBA, 0xB0, 0xB6,
+  0xBB, 0xBE, 0xB9, 0xB8, 0xB3, 0xB2, 0xB0, 0xAD,
+  0xAC, 0xA9, 0xA8, 0xA6, 0xA4, 0xA1, 0xA0, 0x9D,
+  0xA0, 0x9F, 0x9E, 0x9C, 0x9B, 0x99, 0x9A, 0x99,
+  0x98, 0x95, 0x96, 0x94, 0x93, 0x92, 0x8F, 0x8D,
+  0x8C, 0x8A, 0x87, 0x86, 0x83, 0x81, 0x0D, 0x03,
+  0x66, 0x44, 0x24, 0x08, 0xD6, 0xE6, 0xE9, 0xE6,
+  0xE7, 0xCA, 0xDC, 0xDB, 0xD5, 0xD0, 0xC9, 0xE2,
+  0xD5, 0xC6, 0xC4, 0xB3, 0xB2, 0xB9, 0xA9, 0x9A,
+  0xB2, 0x9D, 0xE8, 0xEC, 0xF5, 0xF5, 0xF4, 0xF4,
+  0xEC, 0xEE, 0xF0, 0xF5, 0xE0, 0xD6, 0xC5, 0xC2,
+  0xD9, 0xD5, 0xD8, 0xD6, 0xF6, 0xF4, 0xED, 0xEC,
+  0xEB, 0xF1, 0xF6, 0xF5, 0xF5, 0xEE, 0xEF, 0xEC,
+  0xE7, 0xE3, 0xE6, 0xD6, 0xDD, 0xC3, 0xD6, 0xD7,
+  0xCD, 0xCA, 0xC3, 0xAC, 0x95, 0x99, 0xB7, 0xA3,
+  0x8B, 0x88, 0x95, 0x8A, 0x94, 0xD2, 0xCC, 0xC4,
+  0xA8, 0x8E, 0x8F, 0xAE, 0xB8, 0xAC, 0xB6, 0xB4,
+  0xAD, 0xA5, 0xA0, 0x9B, 0x8B, 0xA3, 0x94, 0x87,
+  0x85, 0x89, 0x53, 0x80, 0x7D, 0x7C, 0x7A, 0x78,
+  0x76, 0x71, 0x73, 0x6E, 0x6B, 0x67, 0x65, 0x62,
+  0x4B, 0x5B, 0x5F, 0x53, 0x56, 0x52, 0x4F, 0x46,
+  0x42, 0x0F, 0x75, 0x78, 0x7D, 0x72, 0x5F, 0x6E,
+  0x7A, 0x75, 0x6A, 0x58, 0x48, 0x4F, 0x00, 0x2B,
+  0x37, 0x3E, 0x32, 0x33, 0x25, 0x2C, 0x3B, 0x11,
+  0x1D, 0x14, 0x06, 0x02, 0x00
+};
+
+unsigned char linux_logo_green[] = {
+  0xF3, 0xF6, 0xF8, 0xF7, 0xEF, 0xE7, 0xE5, 0xE3,
+  0xCA, 0xD4, 0xDD, 0xC8, 0xC7, 0xC4, 0xC2, 0xD3,
+  0xDA, 0xD4, 0xD7, 0xCC, 0xC1, 0xCC, 0xCB, 0xC9,
+  0xC5, 0xBC, 0xBC, 0xBB, 0xB7, 0xA5, 0xB0, 0xB6,
+  0xBB, 0xBE, 0xB9, 0xB8, 0xB3, 0xB2, 0xAD, 0xAD,
+  0xAC, 0xA9, 0xA8, 0xA6, 0xA4, 0xA1, 0xA0, 0x95,
+  0xA0, 0x9F, 0x9E, 0x9C, 0x9B, 0x99, 0x9A, 0x99,
+  0x98, 0x95, 0x96, 0x94, 0x93, 0x92, 0x8F, 0x8D,
+  0x8C, 0x8A, 0x87, 0x86, 0x83, 0x81, 0x08, 0x02,
+  0x53, 0x2E, 0x19, 0x06, 0xC6, 0xC8, 0xCF, 0xBD,
+  0xB3, 0xB6, 0xB4, 0xAB, 0xA5, 0xA3, 0x9B, 0xB6,
+  0xA7, 0x99, 0x92, 0xA4, 0x9E, 0x9D, 0x98, 0x8C,
+  0x8A, 0x86, 0xCD, 0xCC, 0xC9, 0xD7, 0xCA, 0xC4,
+  0xCA, 0xC3, 0xC7, 0xC3, 0xC8, 0xB4, 0x91, 0x8E,
+  0x8A, 0x82, 0x87, 0x85, 0xBD, 0xBF, 0xB6, 0xBC,
+  0xAE, 0xB7, 0xBC, 0xB8, 0xBF, 0xB6, 0xBC, 0xB5,
+  0xAB, 0xA6, 0xAD, 0xB2, 0xA5, 0x87, 0x9C, 0x96,
+  0x95, 0x8E, 0x87, 0x8F, 0x86, 0x86, 0x8E, 0x80,
+  0x7A, 0x70, 0x7B, 0x78, 0x78, 0x7F, 0x77, 0x6F,
+  0x70, 0x76, 0x59, 0x77, 0x68, 0x64, 0x7B, 0x7C,
+  0x75, 0x6D, 0x77, 0x69, 0x65, 0x5F, 0x5B, 0x54,
+  0x4F, 0x5B, 0x39, 0x80, 0x7D, 0x7C, 0x7A, 0x78,
+  0x76, 0x71, 0x73, 0x6E, 0x6B, 0x67, 0x65, 0x62,
+  0x4B, 0x5B, 0x5F, 0x53, 0x56, 0x52, 0x4F, 0x46,
+  0x42, 0x0B, 0x69, 0x66, 0x64, 0x57, 0x4A, 0x4E,
+  0x55, 0x4B, 0x46, 0x3B, 0x30, 0x33, 0x00, 0x2B,
+  0x37, 0x3E, 0x32, 0x33, 0x25, 0x2C, 0x29, 0x0D,
+  0x1D, 0x14, 0x06, 0x02, 0x00
+};
+
+unsigned char linux_logo_blue[] = {
+  0xF3, 0xF6, 0xF8, 0xF7, 0xEF, 0xEE, 0xE5, 0xDE,
+  0xD7, 0xD3, 0xDD, 0xC8, 0xC7, 0xC4, 0xC2, 0xB5,
+  0xB0, 0xA6, 0xAC, 0x9B, 0xB5, 0xB5, 0xAE, 0x84,
+  0x90, 0xA9, 0x81, 0x8D, 0x96, 0x86, 0xB0, 0xB6,
+  0xBB, 0xBE, 0xB9, 0xB8, 0xB3, 0xB2, 0xA7, 0xAD,
+  0xAC, 0xA9, 0xA8, 0xA6, 0xA4, 0xA1, 0xA5, 0x87,
+  0xA0, 0x9F, 0x9E, 0x9C, 0x9B, 0x9A, 0x9A, 0x99,
+  0x98, 0x95, 0x96, 0x94, 0x93, 0x92, 0x8F, 0x8D,
+  0x8C, 0x8A, 0x87, 0x86, 0x83, 0x81, 0xC8, 0xD7,
+  0x9B, 0x8E, 0x8C, 0xB2, 0x77, 0x77, 0x4E, 0x77,
+  0x69, 0x71, 0x78, 0x6B, 0x65, 0x66, 0x64, 0x59,
+  0x5C, 0x5A, 0x48, 0x72, 0x7B, 0x6B, 0x67, 0x6E,
+  0x42, 0x5B, 0x29, 0x36, 0x25, 0x10, 0x17, 0x14,
+  0x19, 0x16, 0x13, 0x0E, 0x08, 0x2E, 0x2E, 0x3D,
+  0x24, 0x24, 0x24, 0x24, 0x13, 0x12, 0x14, 0x14,
+  0x0E, 0x08, 0x0D, 0x0F, 0x08, 0x0D, 0x0E, 0x08,
+  0x08, 0x0C, 0x06, 0x06, 0x07, 0x16, 0x07, 0x0E,
+  0x08, 0x0A, 0x07, 0x0D, 0x2D, 0x3E, 0x09, 0x4E,
+  0x68, 0x52, 0x56, 0x58, 0x4B, 0x22, 0x20, 0x20,
+  0x27, 0x39, 0x28, 0x19, 0x1E, 0x1E, 0x08, 0x06,
+  0x07, 0x09, 0x08, 0x08, 0x05, 0x1D, 0x1F, 0x17,
+  0x18, 0x06, 0x79, 0x80, 0x7D, 0x7C, 0x7A, 0x78,
+  0x76, 0x71, 0x73, 0x6E, 0x6B, 0x68, 0x65, 0x62,
+  0x4B, 0x5B, 0x5F, 0x55, 0x56, 0x52, 0x4F, 0x46,
+  0x42, 0x5A, 0x14, 0x23, 0x3D, 0x2B, 0x21, 0x14,
+  0x06, 0x04, 0x03, 0x07, 0x09, 0x13, 0x2A, 0x3A,
+  0x37, 0x3E, 0x32, 0x33, 0x25, 0x2C, 0x07, 0x09,
+  0x1D, 0x14, 0x06, 0x02, 0x00
+};
+
+unsigned char linux_logo[] = {
+  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
+  0x57, 0x57, 0x58, 0x57, 0x57, 0x57, 0x57, 0x57,
+  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x58, 0x57,
+  0x58, 0x58, 0x59, 0x5C, 0x5D, 0x5F, 0x60, 0x61,
+  0x62, 0x61, 0x61, 0x62, 0x62, 0x62, 0x63, 0x63,
+  0x61, 0x61, 0x61, 0x61, 0x61, 0x60, 0x5E, 0x5E,
+  0x5E, 0x5D, 0x5D, 0x5C, 0x5D, 0x5B, 0x58, 0x58,
+  0x58, 0x57, 0x58, 0x57, 0x57, 0x57, 0x57, 0x58,
+  0x57, 0x57, 0x58, 0x57, 0x57, 0x58, 0x57, 0x57,
+  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
+  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
+  0x57, 0x57, 0x58, 0x57, 0x57, 0x57, 0x57, 0x57,
+  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x58, 0x57,
+  0x54, 0x56, 0x57, 0x67, 0xFC, 0xFC, 0xFC, 0xFC,
+  0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0x67, 0x4C,
+  0x4A, 0x49, 0x4A, 0x49, 0x4A, 0x49, 0x49, 0x4A,
+  0x4A, 0x4B, 0x4B, 0x4B, 0x4C, 0x50, 0x51, 0x52,
+  0x54, 0x54, 0x56, 0x57, 0x57, 0x57, 0x57, 0x58,
+  0x57, 0x57, 0x58, 0x57, 0x57, 0x58, 0x57, 0x57,
+  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
+  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
+  0x57, 0x57, 0x58, 0x57, 0x57, 0x57, 0x57, 0x57,
+  0x57, 0x57, 0x57, 0x57, 0x58, 0x56, 0x56, 0x53,
+  0x52, 0x53, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
+  0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFB, 0xFB, 0xFB,
+  0x4B, 0x4B, 0x4B, 0x4A, 0x49, 0x4A, 0x4A, 0x49,
+  0x49, 0x49, 0x48, 0x49, 0x49, 0x4A, 0x4A, 0x4B,
+  0x4C, 0x4D, 0x52, 0x54, 0x56, 0x55, 0x57, 0x58,
+  0x57, 0x57, 0x58, 0x57, 0x57, 0x58, 0x57, 0x57,
+  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
+  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
+  0x57, 0x57, 0x58, 0x57, 0x57, 0x57, 0x57, 0x57,
+  0x57, 0x57, 0x55, 0x54, 0x53, 0x52, 0x51, 0x50,
+  0x50, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
+  0xFC, 0xFC, 0xFC, 0xFC, 0xF8, 0xF0, 0xF4, 0xFB,
+  0xFC, 0x67, 0x53, 0x50, 0x4D, 0x4C, 0x4C, 0x4C,
+  0x4B, 0x4A, 0x4A, 0x48, 0x49, 0x48, 0x48, 0x49,
+  0x49, 0x49, 0x4B, 0x4C, 0x50, 0x52, 0x53, 0x56,
+  0x57, 0x57, 0x58, 0x57, 0x57, 0x58, 0x57, 0x57,
+  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
+  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
+  0x57, 0x57, 0x58, 0x57, 0x57, 0x57, 0x57, 0x57,
+  0x55, 0x54, 0x53, 0x51, 0x51, 0x50, 0x4C, 0x4D,
+  0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
+  0xFC, 0xFC, 0xFC, 0xFC, 0xF4, 0xD2, 0xD7, 0xF5,
+  0xFC, 0xFC, 0x5D, 0x5D, 0x5C, 0x5C, 0x59, 0x58,
+  0x58, 0x56, 0x52, 0x4C, 0x4B, 0x4A, 0x4A, 0x48,
+  0x48, 0x48, 0x48, 0x48, 0x49, 0x4B, 0x4D, 0x51,
+  0x54, 0x56, 0x58, 0x57, 0x57, 0x58, 0x57, 0x57,
+  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
+  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
+  0x57, 0x57, 0x58, 0x57, 0x57, 0x57, 0x55, 0x54,
+  0x53, 0x52, 0x51, 0x4D, 0x4D, 0x4D, 0x50, 0x50,
+  0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
+  0xFC, 0xFC, 0xFC, 0xFC, 0xF4, 0x64, 0xD9, 0xF5,
+  0xF9, 0xFC, 0xFC, 0x64, 0x63, 0x62, 0x61, 0x61,
+  0x61, 0x60, 0x5E, 0x5B, 0x5A, 0x54, 0x52, 0x4C,
+  0x4B, 0x49, 0x49, 0x47, 0x47, 0x48, 0x49, 0x4B,
+  0x4C, 0x51, 0x53, 0x56, 0x57, 0x58, 0x57, 0x57,
+  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
+  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
+  0x57, 0x57, 0x58, 0x57, 0x57, 0x55, 0x53, 0x53,
+  0x51, 0x50, 0x50, 0x50, 0x50, 0x50, 0x53, 0xFC,
+  0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
+  0xFC, 0xFC, 0xFC, 0xFC, 0xF4, 0xF5, 0xF9, 0xFC,
+  0xFC, 0xFC, 0xFC, 0x64, 0x64, 0x64, 0x64, 0x64,
+  0x64, 0x64, 0x64, 0x63, 0x61, 0x61, 0x5E, 0x59,
+  0x55, 0x52, 0x4C, 0x4A, 0x49, 0x47, 0x48, 0x48,
+  0x49, 0x4B, 0x4D, 0x51, 0x54, 0x57, 0x57, 0x57,
+  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
+  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
+  0x57, 0x57, 0x58, 0x55, 0x54, 0x54, 0x52, 0x51,
+  0x51, 0x51, 0x51, 0x51, 0x53, 0x54, 0x59, 0xFC,
+  0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
+  0xFC, 0xFC, 0xFC, 0xFC, 0xF7, 0xFC, 0xFC, 0xFC,
+  0xFC, 0xFC, 0xFC, 0xFC, 0x60, 0x60, 0x60, 0x61,
+  0x62, 0x63, 0x64, 0x64, 0x65, 0x65, 0x64, 0x63,
+  0x61, 0x5E, 0x59, 0x56, 0x4D, 0x4B, 0x48, 0x48,
+  0x48, 0x48, 0x49, 0x4B, 0x50, 0x53, 0x56, 0x56,
+  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
+  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
+  0x57, 0x57, 0x56, 0x54, 0x53, 0x52, 0x51, 0x51,
+  0x51, 0x52, 0x53, 0x55, 0x59, 0x5D, 0x5E, 0xFC,
+  0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
+  0xFC, 0xFC, 0xFC, 0xFB, 0xFB, 0xFB, 0xFC, 0xFC,
+  0xFC, 0xFC, 0xFC, 0xFC, 0x4C, 0x4E, 0x51, 0x52,
+  0x57, 0x5A, 0x5E, 0x60, 0x61, 0x63, 0x65, 0xCB,
+  0x64, 0x64, 0x63, 0x60, 0x5C, 0x57, 0x50, 0x4B,
+  0x48, 0x47, 0x47, 0x47, 0x4A, 0x4C, 0x52, 0x53,
+  0x54, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
+  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
+  0x55, 0x54, 0x53, 0x53, 0x51, 0x52, 0x52, 0x53,
+  0x53, 0x57, 0x5A, 0x5D, 0x5E, 0x5E, 0x60, 0xFC,
+  0xFC, 0xFC, 0xFB, 0xF9, 0xFC, 0xFC, 0xFC, 0xFC,
+  0xFC, 0xFC, 0xFC, 0xFA, 0xF9, 0xF5, 0xFB, 0xFC,
+  0xFC, 0xFC, 0xFC, 0xFC, 0xFB, 0x45, 0x3F, 0x3F,
+  0x45, 0x48, 0x4B, 0x4D, 0x54, 0x5A, 0x5E, 0x61,
+  0x63, 0xCB, 0xCB, 0x65, 0x64, 0x62, 0x5E, 0x57,
+  0x50, 0x4B, 0x48, 0x47, 0x47, 0x48, 0x4B, 0x4D,
+  0x51, 0x56, 0x56, 0x57, 0x57, 0x57, 0x57, 0x57,
+  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x55,
+  0x54, 0x54, 0x53, 0x53, 0x52, 0x53, 0x54, 0x57,
+  0x59, 0x5C, 0x5E, 0x5E, 0x5E, 0x5E, 0x5E, 0xFC,
+  0xFC, 0xFA, 0xFC, 0xFA, 0xE0, 0xFC, 0xFC, 0xFC,
+  0xFB, 0xFB, 0xFB, 0xDF, 0xD8, 0xF9, 0xE0, 0xFC,
+  0xFC, 0xFC, 0xFC, 0xFC, 0xFB, 0x4C, 0x4A, 0x48,
+  0x48, 0x3E, 0x44, 0x43, 0x3F, 0x47, 0x4B, 0x52,
+  0x5A, 0x5E, 0x62, 0x64, 0xCB, 0xCB, 0x64, 0x61,
+  0x5E, 0x57, 0x4D, 0x49, 0x47, 0x47, 0x48, 0x4A,
+  0x4C, 0x52, 0x54, 0x56, 0x57, 0x57, 0x57, 0x57,
+  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x55,
+  0x54, 0x53, 0x53, 0x54, 0x54, 0x55, 0x58, 0x5B,
+  0x5C, 0x5D, 0x5E, 0x5D, 0x5D, 0x5B, 0x58, 0xFC,
+  0xFC, 0xD8, 0x4C, 0x60, 0xFC, 0xF5, 0xFC, 0xFC,
+  0xFC, 0xF7, 0x5F, 0x48, 0x48, 0x2C, 0xF8, 0xF9,
+  0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0x4B, 0x4A, 0x49,
+  0x49, 0x49, 0x49, 0x47, 0x3E, 0x44, 0x42, 0x3F,
+  0x3E, 0x4B, 0x54, 0x5C, 0x61, 0x64, 0xCB, 0xCB,
+  0x64, 0x61, 0x5D, 0x53, 0x4B, 0x49, 0x47, 0x47,
+  0x49, 0x4B, 0x50, 0x53, 0x56, 0x57, 0x57, 0x57,
+  0x57, 0x57, 0x57, 0x57, 0x57, 0x55, 0x55, 0x54,
+  0x53, 0x53, 0x54, 0x56, 0x58, 0x5A, 0x5B, 0x5D,
+  0x5D, 0x5D, 0x5C, 0x5A, 0x54, 0x52, 0x4C, 0xFC,
+  0xF7, 0x4E, 0x2D, 0x29, 0x4E, 0xFC, 0xFC, 0xFC,
+  0xFB, 0x5F, 0x26, 0x24, 0x20, 0x2E, 0x65, 0xFC,
+  0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0x45, 0x3F, 0x45,
+  0x3E, 0x47, 0x47, 0x47, 0x47, 0x47, 0x3E, 0x44,
+  0x43, 0x40, 0x44, 0x49, 0x51, 0x5C, 0x62, 0x64,
+  0xCB, 0xCB, 0x63, 0x60, 0x58, 0x50, 0x49, 0x48,
+  0x48, 0x48, 0x4A, 0x4D, 0x53, 0x54, 0x57, 0x57,
+  0x57, 0x57, 0x57, 0x57, 0x55, 0x54, 0x54, 0x54,
+  0x54, 0x54, 0x55, 0x57, 0x59, 0x5B, 0x5C, 0x5D,
+  0x5C, 0x5A, 0x54, 0x51, 0x4C, 0x4C, 0x54, 0xFC,
+  0xF9, 0x23, 0xDB, 0x2D, 0x23, 0xFA, 0xFB, 0xFA,
+  0xF5, 0x27, 0x21, 0xD9, 0xF8, 0x20, 0x21, 0xFB,
+  0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0x5D, 0x58, 0x55,
+  0x50, 0x48, 0x45, 0x43, 0x44, 0x44, 0x45, 0x45,
+  0x3E, 0x3F, 0x43, 0x41, 0x3F, 0x48, 0x52, 0x5D,
+  0x63, 0x65, 0xCB, 0x65, 0x61, 0x5D, 0x52, 0x4B,
+  0x48, 0x47, 0x47, 0x49, 0x4C, 0x51, 0x54, 0x57,
+  0x57, 0x57, 0x57, 0x57, 0x55, 0x54, 0x54, 0x54,
+  0x54, 0x58, 0x5A, 0x59, 0x5B, 0x5B, 0x5B, 0x5A,
+  0x55, 0x52, 0x4D, 0x4D, 0x55, 0x5B, 0x5D, 0xFC,
+  0xF1, 0xF9, 0xFC, 0xD4, 0x21, 0xCC, 0xF7, 0xF8,
+  0xF2, 0x21, 0xD9, 0xFC, 0xF2, 0xFB, 0x21, 0x45,
+  0xFC, 0xFC, 0xFC, 0xFC, 0xFB, 0xD1, 0xD0, 0xCD,
+  0xCC, 0x63, 0x5E, 0x58, 0x50, 0x47, 0x43, 0x3F,
+  0x3F, 0x3F, 0x3F, 0x3F, 0x40, 0x41, 0x3F, 0x4A,
+  0x56, 0x5E, 0x64, 0xCB, 0x65, 0x63, 0x5E, 0x56,
+  0x4C, 0x48, 0x47, 0x47, 0x49, 0x4C, 0x51, 0x54,
+  0x58, 0x57, 0x57, 0x57, 0x57, 0x55, 0x54, 0x54,
+  0x57, 0x5A, 0x5A, 0x5C, 0x5B, 0x5A, 0x58, 0x54,
+  0x51, 0x4C, 0x55, 0x5D, 0x5D, 0x5B, 0x54, 0xFC,
+  0xF0, 0xF9, 0xFC, 0x65, 0x45, 0xCD, 0xFB, 0xFB,
+  0xF8, 0x26, 0xFB, 0xFC, 0xFC, 0xFC, 0x21, 0x27,
+  0xFB, 0xFC, 0xFC, 0xFC, 0xFB, 0xD7, 0x35, 0x34,
+  0x2F, 0x35, 0x36, 0x2F, 0x2F, 0x36, 0x2F, 0x2F,
+  0x36, 0x36, 0x35, 0x35, 0x43, 0x42, 0x41, 0x2E,
+  0x45, 0x4C, 0x5B, 0x62, 0x65, 0xCC, 0x64, 0x60,
+  0x58, 0x4D, 0x49, 0x47, 0x47, 0x49, 0x4C, 0x51,
+  0x58, 0x57, 0x57, 0x57, 0x57, 0x57, 0x55, 0x57,
+  0x58, 0x5A, 0x5A, 0x5B, 0x5A, 0x55, 0x54, 0x51,
+  0x53, 0x5C, 0x5D, 0x5D, 0x54, 0x4B, 0x4D, 0xFC,
+  0xFC, 0x44, 0xFC, 0xFB, 0x7B, 0xAB, 0xA8, 0xAE,
+  0xAB, 0x7F, 0xFC, 0xFC, 0xFB, 0xFB, 0x22, 0x2A,
+  0xFC, 0xFC, 0xFC, 0xFC, 0x36, 0x2F, 0x30, 0x30,
+  0x32, 0x30, 0x32, 0x30, 0x30, 0x30, 0x30, 0x30,
+  0x30, 0x30, 0x30, 0x30, 0x2F, 0x2F, 0x40, 0x41,
+  0x2E, 0x40, 0x48, 0x56, 0x5F, 0x64, 0xCC, 0x65,
+  0x61, 0x59, 0x50, 0x49, 0x47, 0x47, 0x49, 0x4C,
+  0x5A, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x58,
+  0x5A, 0x5A, 0x5A, 0x58, 0x55, 0x52, 0x51, 0x5A,
+  0x5D, 0x5D, 0x57, 0x4C, 0x51, 0x54, 0x5D, 0xFC,
+  0xFC, 0x2A, 0xFC, 0xC9, 0xAA, 0x8B, 0x8A, 0x8C,
+  0xAB, 0x8C, 0x8C, 0xFB, 0xFB, 0x23, 0x20, 0xF1,
+  0xFC, 0xFC, 0xFC, 0x3B, 0x33, 0x33, 0x32, 0x32,
+  0x31, 0x32, 0x30, 0x32, 0x32, 0x32, 0x32, 0x30,
+  0x31, 0x31, 0x31, 0x32, 0x33, 0x33, 0x3C, 0x41,
+  0x41, 0x2E, 0x2D, 0x45, 0x4D, 0x5D, 0x63, 0xCC,
+  0x65, 0x62, 0x5D, 0x51, 0x49, 0x47, 0x47, 0x4A,
+  0x59, 0x57, 0x57, 0x57, 0x57, 0x58, 0x58, 0x58,
+  0x5A, 0x5A, 0x58, 0x55, 0x53, 0x53, 0x5C, 0x5E,
+  0x59, 0x51, 0x4E, 0x54, 0x59, 0x5E, 0x62, 0xFC,
+  0xFC, 0xDB, 0xAA, 0xA1, 0x95, 0x9C, 0x8C, 0x88,
+  0x82, 0x83, 0x83, 0x8C, 0x88, 0xAE, 0xB9, 0xFB,
+  0xFC, 0xFC, 0xFC, 0x3C, 0x3B, 0x72, 0x38, 0x33,
+  0x33, 0x33, 0x31, 0x33, 0x31, 0x31, 0x31, 0x31,
+  0x33, 0x33, 0x38, 0x33, 0x72, 0x3B, 0x44, 0x2E,
+  0x41, 0x2E, 0x2E, 0x2D, 0x43, 0x4B, 0x5B, 0x63,
+  0xCB, 0xCC, 0x63, 0x5D, 0x51, 0x49, 0x47, 0x49,
+  0x5C, 0x58, 0x57, 0x57, 0x57, 0x57, 0x58, 0x58,
+  0x58, 0x58, 0x57, 0x53, 0x58, 0x5D, 0x5E, 0x55,
+  0x51, 0x53, 0x58, 0x5E, 0x60, 0x63, 0x64, 0xFC,
+  0xFC, 0xC0, 0xA6, 0x9D, 0x8B, 0x9C, 0x8C, 0x8C,
+  0x6E, 0x83, 0x88, 0x8C, 0x8C, 0x8C, 0x83, 0xE8,
+  0xFB, 0xFC, 0xFC, 0xFC, 0x33, 0x70, 0x70, 0x6F,
+  0x6F, 0x6F, 0x6F, 0x3A, 0x6F, 0x6D, 0x6F, 0x6F,
+  0x70, 0x6F, 0x6F, 0x70, 0x6F, 0x32, 0x5A, 0x48,
+  0x41, 0x2D, 0x2D, 0x2D, 0x2C, 0x41, 0x49, 0x5A,
+  0x62, 0xCB, 0xCB, 0x63, 0x5D, 0x50, 0x49, 0x4A,
+  0x5C, 0x58, 0x58, 0x57, 0x55, 0x57, 0x57, 0x57,
+  0x57, 0x55, 0x56, 0x59, 0x5E, 0x5C, 0x52, 0x53,
+  0x55, 0x5B, 0x5E, 0x61, 0x63, 0x64, 0x63, 0xFC,
+  0xE8, 0xBF, 0xA4, 0x99, 0x9C, 0x8C, 0x88, 0x88,
+  0x6E, 0x88, 0x8C, 0x8C, 0x8C, 0xC2, 0xA6, 0xC4,
+  0xFC, 0xFC, 0xFC, 0xFC, 0x36, 0x3A, 0x6F, 0x70,
+  0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70,
+  0x70, 0x70, 0x70, 0x70, 0x37, 0x32, 0xCD, 0x5E,
+  0x4C, 0x43, 0x2C, 0x2D, 0x2D, 0x2C, 0x2E, 0x47,
+  0x57, 0x61, 0x65, 0xCC, 0x63, 0x5C, 0x50, 0x4D,
+  0x5C, 0x5A, 0x57, 0x55, 0x55, 0x55, 0x58, 0x58,
+  0x55, 0x54, 0x5B, 0x5E, 0x5D, 0x53, 0x53, 0x55,
+  0x5D, 0x5E, 0x61, 0x61, 0x61, 0x61, 0x5E, 0xFC,
+  0xEA, 0xBE, 0xA4, 0x9B, 0x8B, 0x85, 0x8C, 0x6E,
+  0x8C, 0x8C, 0x8C, 0xA3, 0xAA, 0xA4, 0xA4, 0xE9,
+  0xFB, 0xFC, 0xFC, 0xFC, 0x36, 0x6D, 0x70, 0x73,
+  0x70, 0x70, 0x70, 0x73, 0x73, 0x73, 0x73, 0x70,
+  0x70, 0x70, 0x73, 0x70, 0x37, 0x38, 0xD1, 0xCF,
+  0x61, 0x4D, 0x44, 0x2C, 0x2D, 0x2E, 0x2C, 0x2E,
+  0x3E, 0x56, 0x61, 0xCB, 0xCC, 0x62, 0x5B, 0x57,
+  0x59, 0x58, 0x55, 0x54, 0x54, 0x55, 0x58, 0x58,
+  0x58, 0x5B, 0x5E, 0x5B, 0x53, 0x55, 0x55, 0x5C,
+  0x5E, 0x61, 0x61, 0x60, 0x5D, 0x5A, 0x4E, 0xFC,
+  0xFC, 0xEA, 0xAA, 0x9C, 0x8A, 0x85, 0x82, 0x8C,
+  0x8C, 0xA8, 0xEB, 0xA8, 0xA4, 0xA4, 0xAA, 0xFC,
+  0xFC, 0xFC, 0x64, 0xFB, 0x39, 0x31, 0x72, 0x78,
+  0x73, 0x78, 0x73, 0x74, 0x74, 0x74, 0x74, 0x73,
+  0x78, 0x70, 0x73, 0x73, 0x33, 0xCC, 0xD2, 0xD1,
+  0xCE, 0x62, 0x53, 0x3F, 0x2D, 0x2D, 0x41, 0x2C,
+  0x2E, 0x3E, 0x56, 0x62, 0xCB, 0xCB, 0x61, 0x5D,
+  0x54, 0x54, 0x54, 0x54, 0x56, 0x58, 0x58, 0x58,
+  0x5C, 0x5E, 0x5A, 0x55, 0x58, 0x58, 0x5B, 0x5E,
+  0x61, 0x5E, 0x5D, 0x5A, 0x52, 0x55, 0xCD, 0xFC,
+  0xFC, 0x34, 0xC9, 0xE8, 0xA8, 0xAE, 0xC2, 0xE8,
+  0xC3, 0xA6, 0xA7, 0xA6, 0xAA, 0x78, 0x2E, 0x42,
+  0xFC, 0xFC, 0xD2, 0x64, 0xF8, 0x31, 0x72, 0x73,
+  0x73, 0x73, 0x73, 0x74, 0x75, 0x75, 0x74, 0x73,
+  0x73, 0x73, 0x73, 0x72, 0x33, 0x5C, 0x64, 0xD2,
+  0xD1, 0xCF, 0x63, 0x54, 0x3F, 0x2C, 0x41, 0x41,
+  0x2C, 0x2E, 0x47, 0x58, 0x63, 0xCB, 0xCB, 0x62,
+  0x52, 0x53, 0x53, 0x56, 0x58, 0x58, 0x5A, 0x5B,
+  0x5E, 0x5A, 0x57, 0x58, 0x58, 0x58, 0x60, 0x60,
+  0x5D, 0x5A, 0x55, 0x4E, 0x64, 0xD2, 0xD1, 0xFC,
+  0xFC, 0x41, 0x3E, 0xC1, 0xC0, 0xA3, 0xA6, 0xA7,
+  0xA7, 0xA9, 0xAA, 0xB8, 0x2E, 0x3F, 0x2C, 0x41,
+  0xFC, 0xFC, 0xF7, 0xCE, 0xCD, 0x36, 0x72, 0x73,
+  0x74, 0x75, 0x78, 0x75, 0x75, 0x75, 0x74, 0x74,
+  0x74, 0x74, 0x78, 0x72, 0x6D, 0x49, 0x59, 0xCB,
+  0xD1, 0xD1, 0xD2, 0xCB, 0x56, 0x3F, 0x2C, 0x41,
+  0x40, 0x2D, 0x2E, 0x49, 0x5B, 0x64, 0xCC, 0x64,
+  0x51, 0x53, 0x53, 0x55, 0x58, 0x59, 0x5B, 0x5E,
+  0x59, 0x58, 0x58, 0x58, 0x55, 0x60, 0x60, 0x5C,
+  0x5A, 0x53, 0x5B, 0xD0, 0xD3, 0xD3, 0xD3, 0xFB,
+  0xFC, 0x40, 0x41, 0x45, 0xC4, 0xC0, 0xBE, 0xBE,
+  0xC1, 0xC0, 0x3C, 0x47, 0x2E, 0x21, 0x22, 0x20,
+  0x65, 0xFC, 0xFC, 0xFC, 0xFC, 0x6D, 0x72, 0x75,
+  0x78, 0x76, 0x75, 0x79, 0x76, 0x76, 0x76, 0x76,
+  0x75, 0x75, 0x75, 0x72, 0x6D, 0x2E, 0x48, 0x5D,
+  0xCE, 0xD1, 0xD4, 0xD3, 0xCB, 0x56, 0x43, 0x2C,
+  0x42, 0x43, 0x2E, 0x2E, 0x4A, 0x5D, 0x64, 0x64,
+  0x50, 0x52, 0x56, 0x58, 0x5C, 0x5D, 0x5E, 0x5D,
+  0x5A, 0x58, 0x58, 0x55, 0x61, 0x60, 0x58, 0x58,
+  0x4E, 0x61, 0xD1, 0xD4, 0xD4, 0xD1, 0xEE, 0xFC,
+  0xFC, 0x2B, 0x29, 0x2E, 0x3F, 0xB0, 0xAD, 0x81,
+  0x46, 0x2D, 0x46, 0x2C, 0x24, 0x22, 0x22, 0x23,
+  0x25, 0xFC, 0xFC, 0xFC, 0xFC, 0x6E, 0x73, 0x76,
+  0x76, 0x79, 0x79, 0x79, 0x76, 0x76, 0x79, 0x76,
+  0x79, 0x79, 0x79, 0x74, 0x3F, 0x41, 0x2C, 0x48,
+  0x5F, 0xCF, 0xD5, 0xD7, 0xD6, 0xCD, 0x57, 0x40,
+  0x2E, 0x3F, 0x44, 0x2E, 0x41, 0x4C, 0x60, 0x61,
+  0x51, 0x53, 0x58, 0x5C, 0x5D, 0x5E, 0x5D, 0x5C,
+  0x58, 0x57, 0x54, 0x5F, 0x5E, 0x55, 0x55, 0x52,
+  0x64, 0xD4, 0xD5, 0xD4, 0xD1, 0x5D, 0xFA, 0xFB,
+  0xF4, 0x21, 0x24, 0x41, 0x40, 0x44, 0x2E, 0x2E,
+  0x42, 0x41, 0x2A, 0x24, 0x22, 0x22, 0x22, 0x22,
+  0x23, 0xD9, 0xFC, 0xFC, 0xFC, 0xFC, 0xE5, 0xB8,
+  0x8F, 0x8F, 0x7A, 0x8F, 0x7A, 0x8F, 0x7A, 0x8F,
+  0x8F, 0x8F, 0xB8, 0xE5, 0x3F, 0x3E, 0x43, 0x2C,
+  0x48, 0x61, 0xD1, 0xD7, 0xD9, 0xD7, 0xD0, 0x57,
+  0x41, 0x2E, 0x3E, 0x44, 0x2D, 0x40, 0x52, 0x5D,
+  0x53, 0x55, 0x59, 0x5D, 0x5E, 0x5E, 0x5D, 0x5A,
+  0x57, 0x53, 0x5E, 0x5E, 0x54, 0x53, 0x54, 0x65,
+  0xD5, 0xD6, 0xD4, 0xCE, 0x53, 0xFB, 0xF9, 0xFC,
+  0x24, 0x22, 0x23, 0x23, 0x41, 0x42, 0x2E, 0x40,
+  0x2B, 0x21, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
+  0x23, 0x23, 0xFC, 0xFC, 0xFC, 0xFC, 0xE7, 0xBD,
+  0xB5, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93,
+  0x93, 0xB5, 0xC6, 0xEB, 0x2D, 0x47, 0x4A, 0x47,
+  0x2C, 0x3E, 0x61, 0xD4, 0xDC, 0xDC, 0xDA, 0xCF,
+  0x54, 0x41, 0x41, 0x3E, 0x45, 0x2C, 0x3F, 0x4A,
+  0x58, 0x5A, 0x5C, 0x5F, 0x60, 0x5E, 0x5D, 0x57,
+  0x51, 0x5D, 0x5D, 0x51, 0x53, 0x53, 0xCB, 0xD5,
+  0xD6, 0xD5, 0x63, 0x55, 0xFC, 0xFC, 0xFC, 0x2C,
+  0x23, 0x22, 0x23, 0x22, 0x20, 0x2D, 0x2C, 0x26,
+  0x21, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
+  0x22, 0x21, 0xF0, 0xFC, 0xFC, 0xFC, 0xE2, 0xC6,
+  0xB5, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93,
+  0x93, 0x93, 0xC7, 0xE3, 0x3E, 0x2E, 0x49, 0x52,
+  0x4C, 0x41, 0x44, 0x62, 0xD6, 0xDE, 0xDE, 0xD9,
+  0xD0, 0x51, 0x2E, 0x40, 0x47, 0x44, 0x2C, 0x42,
+  0x5D, 0x5D, 0x5F, 0x60, 0x60, 0x5D, 0x57, 0x51,
+  0x58, 0x5D, 0x4E, 0x52, 0x55, 0x64, 0xD5, 0xD6,
+  0xD4, 0x61, 0x59, 0x6B, 0xFC, 0xFC, 0xFC, 0x21,
+  0x23, 0x22, 0x23, 0x22, 0x23, 0x21, 0x23, 0x22,
+  0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
+  0x22, 0x21, 0x24, 0xFC, 0xFC, 0xFC, 0xE2, 0xC7,
+  0xB5, 0x90, 0x93, 0x93, 0x93, 0x90, 0x93, 0x93,
+  0x90, 0xB5, 0xC8, 0xE4, 0x5F, 0x45, 0x2E, 0x4D,
+  0x57, 0x57, 0x44, 0x43, 0x63, 0xDA, 0xDF, 0xDF,
+  0xD9, 0xCE, 0x4C, 0x2C, 0x3F, 0x3E, 0x40, 0x40,
+  0x60, 0x5E, 0x61, 0x61, 0x5E, 0x5B, 0x53, 0x52,
+  0x5C, 0x52, 0x52, 0x55, 0x61, 0xD4, 0xD5, 0xD1,
+  0x5E, 0x5B, 0x5C, 0xFB, 0xFC, 0xFC, 0x2A, 0x21,
+  0x23, 0x22, 0x23, 0x22, 0x22, 0x22, 0x23, 0x22,
+  0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
+  0x22, 0x22, 0x22, 0xFB, 0xFC, 0xFC, 0xB3, 0xC8,
+  0xB5, 0x90, 0x92, 0xB5, 0x93, 0x93, 0xB5, 0x93,
+  0x92, 0xB5, 0xC8, 0xB9, 0xD0, 0x5E, 0x44, 0x40,
+  0x52, 0x58, 0x57, 0x48, 0x40, 0x63, 0xD9, 0xE0,
+  0xE0, 0xD9, 0xCB, 0x49, 0x2D, 0x3F, 0x45, 0x3F,
+  0x63, 0x61, 0x62, 0x60, 0x5E, 0x55, 0x4D, 0x59,
+  0x53, 0x4E, 0x54, 0x5D, 0xD2, 0xD4, 0xD2, 0x5E,
+  0x5C, 0x5D, 0xFC, 0xFC, 0xFC, 0xF8, 0x29, 0x23,
+  0x23, 0x23, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
+  0x23, 0x22, 0x22, 0x23, 0x23, 0x23, 0x22, 0x22,
+  0x22, 0x22, 0x22, 0xF0, 0xFC, 0xFC, 0xB3, 0xC7,
+  0xB5, 0x93, 0xB5, 0x93, 0x93, 0x91, 0x93, 0x93,
+  0x91, 0xB5, 0xC7, 0xAD, 0xD6, 0xD2, 0x5E, 0x3F,
+  0x3F, 0x57, 0x57, 0x58, 0x4A, 0x41, 0x64, 0xDC,
+  0xF1, 0xDF, 0xDA, 0x61, 0x45, 0x2E, 0x43, 0x47,
+  0xCB, 0x63, 0x62, 0x5F, 0x58, 0x51, 0x53, 0x54,
+  0x4C, 0x52, 0x5C, 0xCD, 0xD3, 0xD2, 0x60, 0x5D,
+  0x5D, 0xFB, 0xFC, 0xFC, 0xFC, 0xDB, 0x49, 0x24,
+  0x21, 0x23, 0x23, 0x22, 0x26, 0x26, 0x2A, 0x24,
+  0x22, 0x23, 0x22, 0x21, 0x24, 0x26, 0x26, 0x2A,
+  0x29, 0x2B, 0x24, 0x25, 0xFC, 0xFC, 0xB3, 0xC5,
+  0x91, 0x91, 0x92, 0x91, 0x92, 0x92, 0x93, 0x93,
+  0x91, 0x93, 0xC6, 0xAD, 0xDC, 0xD9, 0xD4, 0x60,
+  0x43, 0x45, 0x58, 0x58, 0x57, 0x4B, 0x43, 0xCC,
+  0xDD, 0xF1, 0xD8, 0xD5, 0x5D, 0x43, 0x41, 0x47,
+  0xCD, 0x63, 0x62, 0x5D, 0x54, 0x4C, 0x55, 0x4B,
+  0x51, 0x58, 0x62, 0xD0, 0xD0, 0x62, 0x5D, 0x5D,
+  0x67, 0xFC, 0xFC, 0xFC, 0xFC, 0x58, 0x4E, 0x28,
+  0x2A, 0x20, 0x23, 0x22, 0x23, 0x2A, 0x23, 0x22,
+  0x22, 0x22, 0x23, 0x23, 0x25, 0x2A, 0x2E, 0x2D,
+  0x2E, 0x2E, 0x2E, 0x23, 0xFA, 0xFC, 0xB2, 0xBD,
+  0xB5, 0x90, 0x91, 0x93, 0x92, 0x90, 0x91, 0x93,
+  0x92, 0x91, 0xBD, 0xAD, 0xDE, 0xE0, 0xD8, 0xD7,
+  0x61, 0x40, 0x48, 0x58, 0x58, 0x58, 0x48, 0x44,
+  0xCF, 0xDE, 0xE0, 0xDD, 0xD0, 0x52, 0x41, 0x45,
+  0xCD, 0x63, 0x61, 0x58, 0x4D, 0x51, 0x4C, 0x4B,
+  0x54, 0x5D, 0xCC, 0xCE, 0x63, 0x61, 0x5D, 0x5D,
+  0xFB, 0xFC, 0xFC, 0xFC, 0xFC, 0x4B, 0x27, 0x21,
+  0x22, 0x22, 0x23, 0x22, 0x22, 0x24, 0x23, 0x22,
+  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x20,
+  0x27, 0x2B, 0x41, 0x2B, 0x23, 0xFC, 0xB2, 0xB6,
+  0x93, 0x90, 0x92, 0xB5, 0x92, 0x90, 0xB5, 0x90,
+  0x92, 0x93, 0xBC, 0xAD, 0xDC, 0xF1, 0xF3, 0xF0,
+  0xD9, 0x61, 0x41, 0x4A, 0x58, 0x57, 0x57, 0x44,
+  0x49, 0xD2, 0xDD, 0xD8, 0xDA, 0x63, 0x4A, 0x45,
+  0xCC, 0x63, 0x5E, 0x52, 0x4B, 0x4C, 0x49, 0x51,
+  0x5C, 0x61, 0xCD, 0x65, 0x63, 0x5E, 0x4E, 0xCF,
+  0xFB, 0xFB, 0xF0, 0xFC, 0xD2, 0x2A, 0x22, 0x23,
+  0x22, 0x22, 0x23, 0x22, 0x22, 0x21, 0x22, 0x22,
+  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
+  0x23, 0x22, 0x26, 0x41, 0x27, 0xF9, 0x81, 0xB7,
+  0xB5, 0x91, 0x92, 0xB5, 0x91, 0xB5, 0x93, 0xB5,
+  0x93, 0xB6, 0xB7, 0xB9, 0xCB, 0xD8, 0xF3, 0xF2,
+  0xF2, 0xDB, 0x61, 0x2D, 0x51, 0x58, 0x57, 0x58,
+  0x41, 0x51, 0xD4, 0xDB, 0xDC, 0xD1, 0x5B, 0x4C,
+  0xCB, 0x62, 0x59, 0x4C, 0x4A, 0x49, 0x4B, 0x55,
+  0x60, 0x64, 0xCC, 0x64, 0x5E, 0x55, 0x60, 0xE1,
+  0xFB, 0xF8, 0xFC, 0xFC, 0x21, 0x22, 0x22, 0x23,
+  0x22, 0x22, 0x23, 0x22, 0x22, 0x21, 0x22, 0x22,
+  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
+  0x23, 0x22, 0x21, 0x24, 0x2D, 0x21, 0xB4, 0xBB,
+  0xB6, 0xB5, 0xB6, 0xB7, 0xB7, 0xB7, 0xB7, 0xB6,
+  0xB6, 0xB6, 0xBB, 0xB9, 0x45, 0xCB, 0xDF, 0xF3,
+  0xF3, 0xF3, 0xDB, 0x5E, 0x2C, 0x51, 0x58, 0x58,
+  0x52, 0x2D, 0x5C, 0xD4, 0xD9, 0xD5, 0x63, 0x58,
+  0x64, 0x60, 0x53, 0x49, 0x4A, 0x49, 0x52, 0x5C,
+  0x63, 0xCD, 0xCD, 0x63, 0x5C, 0x4E, 0x65, 0xFC,
+  0xFC, 0xF5, 0xFC, 0xD2, 0x23, 0x22, 0x22, 0x23,
+  0x22, 0x22, 0x23, 0x22, 0x22, 0x21, 0x22, 0x22,
+  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
+  0x23, 0x22, 0x21, 0x22, 0x25, 0x29, 0xB3, 0xC7,
+  0xB5, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6,
+  0xB6, 0xB5, 0xC7, 0xAD, 0x57, 0x3F, 0xCB, 0xF0,
+  0xF3, 0xF3, 0xF2, 0xD9, 0x58, 0x41, 0x4C, 0x58,
+  0x57, 0x47, 0x42, 0x62, 0xD4, 0xD4, 0xCC, 0x60,
+  0x63, 0x5D, 0x50, 0x47, 0x48, 0x4B, 0x58, 0x60,
+  0xCC, 0xCE, 0xCD, 0x60, 0x53, 0x5C, 0x62, 0xFB,
+  0xF9, 0xFC, 0xFC, 0x21, 0x23, 0x22, 0x22, 0x23,
+  0x22, 0x22, 0x23, 0x23, 0x23, 0x21, 0x22, 0x22,
+  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
+  0x23, 0x22, 0x23, 0x23, 0x22, 0x23, 0x81, 0xC7,
+  0xB7, 0xB7, 0xBC, 0xB7, 0xBC, 0xBC, 0xBC, 0xB7,
+  0xB7, 0xB7, 0xC8, 0x80, 0x58, 0x57, 0x40, 0xCE,
+  0xF3, 0xF2, 0xF2, 0xF0, 0xD5, 0x4C, 0x3F, 0x4B,
+  0x52, 0x50, 0x2D, 0x4B, 0x64, 0xD2, 0xCC, 0x61,
+  0x60, 0x58, 0x4A, 0x47, 0x47, 0x4C, 0x59, 0x64,
+  0xD0, 0xD0, 0x64, 0x59, 0x49, 0x5D, 0xFB, 0xFC,
+  0xD9, 0xFC, 0xD6, 0x23, 0x22, 0x22, 0x22, 0x23,
+  0x22, 0x22, 0x23, 0x23, 0x21, 0x21, 0x22, 0x22,
+  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
+  0x23, 0x22, 0x23, 0x23, 0x22, 0x23, 0xB4, 0xC8,
+  0xBD, 0xB7, 0xBD, 0xBC, 0xBD, 0xC5, 0xBC, 0xC5,
+  0xBC, 0xBD, 0xC7, 0xAC, 0x58, 0x57, 0x58, 0x2C,
+  0xD1, 0xF0, 0xF3, 0xF3, 0xE0, 0xCD, 0x45, 0x3E,
+  0x48, 0x4B, 0x3F, 0x41, 0x56, 0x64, 0x65, 0x62,
+  0x5D, 0x52, 0x47, 0x48, 0x48, 0x53, 0x60, 0xCC,
+  0xD2, 0xD0, 0x63, 0x52, 0x4E, 0x53, 0xFB, 0xFB,
+  0xFC, 0xFC, 0x23, 0x23, 0x22, 0x23, 0x22, 0x23,
+  0x22, 0x22, 0x23, 0x23, 0x20, 0x21, 0x22, 0x22,
+  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
+  0x23, 0x22, 0x23, 0x22, 0x23, 0x22, 0xB4, 0xC7,
+  0xC5, 0xBC, 0xC5, 0xBD, 0xC5, 0xC5, 0xBD, 0xC5,
+  0xBC, 0xC6, 0xC7, 0xB9, 0x58, 0x57, 0x58, 0x57,
+  0x2D, 0xD4, 0xF1, 0xF2, 0xF0, 0xD9, 0x5D, 0x47,
+  0x48, 0x3F, 0x42, 0x2C, 0x48, 0x5C, 0x5F, 0x60,
+  0x58, 0x50, 0x47, 0x4A, 0x49, 0x55, 0x63, 0xD0,
+  0xD2, 0xCD, 0x5D, 0x49, 0x4E, 0xE1, 0xFC, 0xF0,
+  0xFC, 0xF8, 0x22, 0x22, 0x22, 0x23, 0x22, 0x23,
+  0x22, 0x22, 0x23, 0x20, 0x21, 0x21, 0x22, 0x22,
+  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x23, 0x22,
+  0x23, 0x22, 0x23, 0x23, 0x23, 0x22, 0xC4, 0xC8,
+  0xBD, 0xBD, 0xC6, 0xBD, 0xC6, 0xC6, 0xC5, 0xC6,
+  0xBD, 0xC6, 0xC7, 0xE4, 0x54, 0x57, 0x58, 0x57,
+  0x57, 0x43, 0xD7, 0xE0, 0xF1, 0xD8, 0xCD, 0x4B,
+  0x4A, 0x47, 0x42, 0x2C, 0x3F, 0x4D, 0x58, 0x5C,
+  0x52, 0x4B, 0x48, 0x4B, 0x4A, 0x58, 0xCB, 0xD3,
+  0xD2, 0xCD, 0x58, 0x47, 0x4A, 0xFC, 0xFC, 0xFB,
+  0xFC, 0x2B, 0x22, 0x22, 0x22, 0x23, 0x22, 0x23,
+  0x22, 0x22, 0x23, 0x26, 0x21, 0x21, 0x23, 0x22,
+  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x23,
+  0x22, 0x23, 0x22, 0x23, 0x22, 0x23, 0xE5, 0xC8,
+  0xBA, 0xC5, 0xC6, 0xC6, 0xC6, 0xC7, 0xC6, 0xC7,
+  0xC5, 0xC6, 0xC8, 0xE5, 0x2E, 0x54, 0x58, 0x57,
+  0x57, 0x4C, 0x4D, 0xDA, 0xD8, 0xD8, 0xD4, 0x5C,
+  0x4B, 0x4B, 0x3F, 0x42, 0x44, 0x4A, 0x51, 0x58,
+  0x4B, 0x48, 0x4B, 0x51, 0x4D, 0x5F, 0xD0, 0xD1,
+  0xD0, 0x64, 0x51, 0x44, 0x6B, 0xFC, 0xFB, 0xFC,
+  0xFC, 0x21, 0x23, 0x22, 0x22, 0x23, 0x22, 0x23,
+  0x22, 0x22, 0x23, 0x26, 0x21, 0x23, 0x23, 0x22,
+  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x23,
+  0x22, 0x23, 0x22, 0x23, 0x23, 0x23, 0xE5, 0xED,
+  0xE7, 0xBA, 0xC8, 0xC6, 0xC6, 0xC6, 0xC6, 0xC7,
+  0xC7, 0xE5, 0xED, 0xE6, 0x61, 0x41, 0x52, 0x58,
+  0x58, 0x57, 0x45, 0x5E, 0xD7, 0xDD, 0xD5, 0x60,
+  0x4B, 0x4C, 0x48, 0x4D, 0x4D, 0x50, 0x4D, 0x56,
+  0x4A, 0x3E, 0x53, 0x53, 0x52, 0x63, 0xD3, 0xD0,
+  0xCE, 0x60, 0x4A, 0x45, 0xFC, 0xFC, 0xF7, 0xFC,
+  0xFC, 0x21, 0x23, 0x23, 0x22, 0x23, 0x22, 0x23,
+  0x22, 0x23, 0x21, 0x2A, 0x20, 0x23, 0x23, 0x22,
+  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
+  0x23, 0x22, 0x23, 0x22, 0x21, 0x23, 0xEB, 0xF6,
+  0xF6, 0xED, 0xED, 0xED, 0xED, 0xED, 0xED, 0xED,
+  0xF6, 0xF6, 0xF6, 0xE6, 0xDB, 0x58, 0x45, 0x4B,
+  0x58, 0x57, 0x4D, 0x4B, 0x64, 0xD4, 0xD0, 0x5C,
+  0x48, 0x51, 0x4C, 0x5D, 0x5E, 0x5C, 0x56, 0x59,
+  0x3E, 0x4A, 0x58, 0x54, 0x52, 0x65, 0xD3, 0xD0,
+  0xCF, 0x5D, 0x48, 0xFC, 0xFC, 0xFC, 0xFA, 0xFC,
+  0xFC, 0x21, 0x22, 0x23, 0x22, 0x23, 0x22, 0x23,
+  0x22, 0x23, 0x21, 0x2A, 0x21, 0x23, 0x23, 0x22,
+  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
+  0x23, 0x22, 0x23, 0x22, 0x21, 0x4F, 0xE6, 0xC6,
+  0xC6, 0xBD, 0xC6, 0xBD, 0xBD, 0xBD, 0xBD, 0xC6,
+  0xC5, 0xBA, 0xC7, 0xE6, 0xF2, 0xD4, 0x49, 0x4B,
+  0x3E, 0x4D, 0x52, 0x3E, 0x52, 0x63, 0x64, 0x56,
+  0x48, 0x54, 0x4D, 0x61, 0xCC, 0xCC, 0x60, 0x60,
+  0x47, 0x4D, 0x5C, 0x53, 0x58, 0xCF, 0xD1, 0xCF,
+  0xD0, 0x59, 0x45, 0xFC, 0xFC, 0xFC, 0xEF, 0xF9,
+  0xFC, 0x21, 0x23, 0x22, 0x23, 0x22, 0x23, 0x22,
+  0x23, 0x22, 0x23, 0x2A, 0x21, 0x23, 0x23, 0x22,
+  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
+  0x23, 0x22, 0x23, 0x22, 0x23, 0x4F, 0xE4, 0xB9,
+  0xAF, 0x80, 0x80, 0x8E, 0x8E, 0x8E, 0x8E, 0x8F,
+  0x80, 0xB4, 0xB9, 0xE4, 0x7F, 0xDE, 0x61, 0x52,
+  0x54, 0x48, 0x3F, 0x43, 0x4D, 0x56, 0x59, 0x4B,
+  0x3E, 0x58, 0x53, 0x61, 0xD3, 0xD4, 0xCF, 0xCD,
+  0x4C, 0x58, 0x5F, 0x53, 0x5E, 0xD3, 0xD0, 0xCE,
+  0xCE, 0x52, 0x3F, 0xFC, 0xFC, 0xFC, 0xF7, 0x65,
+  0xFA, 0x22, 0x23, 0x22, 0x23, 0x22, 0x23, 0x22,
+  0x23, 0x22, 0x21, 0x2A, 0x23, 0x23, 0x23, 0x22,
+  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
+  0x23, 0x22, 0x23, 0x22, 0x21, 0xB1, 0xE4, 0xE6,
+  0x7C, 0xB1, 0x7C, 0xB1, 0xB2, 0xB2, 0xB3, 0x3D,
+  0xB3, 0x3C, 0xE5, 0xB3, 0xB0, 0xF1, 0xD0, 0x58,
+  0x5D, 0x4D, 0x40, 0x41, 0x48, 0x51, 0x4C, 0x3F,
+  0x3F, 0x4D, 0x5A, 0x5A, 0xD5, 0xD9, 0xD7, 0xD4,
+  0x57, 0x5E, 0x61, 0x4C, 0x63, 0xD4, 0xCF, 0xCE,
+  0xCB, 0x4D, 0x4A, 0xFC, 0xFC, 0xFC, 0xFC, 0xF0,
+  0xFB, 0x22, 0x23, 0x22, 0x23, 0x22, 0x23, 0x22,
+  0x23, 0x22, 0x23, 0x2A, 0x21, 0x23, 0x23, 0x22,
+  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
+  0x22, 0x23, 0x22, 0x23, 0x23, 0xB1, 0x81, 0x7D,
+  0x39, 0x35, 0x35, 0x36, 0x36, 0x36, 0x36, 0x36,
+  0x36, 0x36, 0x7C, 0xB2, 0xB0, 0xDF, 0xD2, 0x57,
+  0x60, 0x59, 0x5B, 0x59, 0x52, 0x4C, 0x4A, 0x40,
+  0x42, 0x4A, 0x53, 0x4D, 0xD2, 0xDE, 0xDE, 0xD9,
+  0x5E, 0x5E, 0x60, 0x4A, 0xCD, 0xD1, 0xCF, 0xCE,
+  0x63, 0x49, 0x5C, 0xFB, 0xE8, 0x89, 0x9F, 0xFC,
+  0xD6, 0x21, 0x21, 0x23, 0x22, 0x22, 0x23, 0x22,
+  0x23, 0x22, 0x21, 0x2A, 0x22, 0x23, 0x23, 0x22,
+  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
+  0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x7F, 0xB9,
+  0x71, 0x6C, 0x38, 0x38, 0x33, 0x33, 0x33, 0x38,
+  0x38, 0x71, 0xAD, 0xE4, 0xD3, 0xDA, 0xCC, 0x52,
+  0x63, 0x60, 0xCE, 0xD4, 0xCF, 0x60, 0x4C, 0x40,
+  0x3F, 0x45, 0x4B, 0x5A, 0xCB, 0xD8, 0xDE, 0xDC,
+  0x5E, 0x5E, 0x5F, 0x4C, 0xD2, 0xD2, 0xCF, 0xCF,
+  0x61, 0x45, 0x5E, 0xA7, 0x9D, 0x95, 0x8B, 0x99,
+  0xFC, 0x41, 0x21, 0x23, 0x23, 0x22, 0x23, 0x22,
+  0x23, 0x22, 0x23, 0x2A, 0x23, 0x23, 0x23, 0x22,
+  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
+  0x22, 0x22, 0x23, 0x22, 0x23, 0x77, 0x77, 0xF6,
+  0xFC, 0x7D, 0x7D, 0x7E, 0x7E, 0x7E, 0x7E, 0x7D,
+  0x7D, 0xFC, 0x47, 0x64, 0xD0, 0xD0, 0x5D, 0x4B,
+  0x62, 0xCC, 0xD1, 0xDE, 0xDE, 0xD4, 0x5E, 0x43,
+  0x3F, 0x3E, 0x48, 0x53, 0x58, 0xDB, 0xD8, 0xDC,
+  0x5E, 0x5E, 0x5E, 0x53, 0xD4, 0xD2, 0xD0, 0xD0,
+  0x5E, 0x49, 0xA7, 0xA6, 0x89, 0x95, 0x8B, 0x9C,
+  0x9C, 0xFB, 0xD4, 0x22, 0x22, 0x22, 0x22, 0x23,
+  0x22, 0x23, 0x23, 0x2A, 0x22, 0x23, 0x23, 0x22,
+  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x23,
+  0x23, 0x22, 0x23, 0x23, 0x98, 0x8C, 0x8C, 0x88,
+  0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xF8,
+  0xE9, 0x9C, 0x48, 0x5C, 0xD0, 0xCB, 0x48, 0x49,
+  0x5B, 0xCB, 0xCD, 0xE0, 0xF1, 0xDD, 0xD0, 0x4A,
+  0x41, 0x47, 0x45, 0x4C, 0x48, 0xD7, 0xDE, 0xDC,
+  0x5E, 0x5E, 0x5A, 0x58, 0xD1, 0xD0, 0xD0, 0xD2,
+  0x5C, 0x55, 0xA7, 0xA6, 0x87, 0x86, 0x89, 0x94,
+  0x9C, 0xA9, 0xFC, 0xF4, 0x22, 0x23, 0x22, 0x23,
+  0x22, 0x23, 0x22, 0x2A, 0x21, 0x23, 0x23, 0x22,
+  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x23,
+  0x22, 0x23, 0x22, 0x23, 0xA4, 0x89, 0x8C, 0xAA,
+  0xFB, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xF7,
+  0x85, 0x88, 0x8D, 0x59, 0x64, 0x63, 0x47, 0x3E,
+  0x4C, 0x60, 0x61, 0xE0, 0xF0, 0xDF, 0xD9, 0x5D,
+  0x2E, 0x3E, 0x3E, 0x47, 0x4D, 0xCD, 0xDE, 0xDC,
+  0x5D, 0x5C, 0x51, 0x5D, 0xD1, 0xD2, 0xD2, 0xD4,
+  0x5A, 0xBE, 0xA7, 0x98, 0x8A, 0x8A, 0xA0, 0x8B,
+  0x86, 0x86, 0xF7, 0xFC, 0xF7, 0x26, 0x23, 0x23,
+  0x22, 0x22, 0x22, 0x22, 0x21, 0x22, 0x23, 0x22,
+  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x23,
+  0x22, 0x21, 0x21, 0x21, 0xA1, 0x98, 0x9F, 0xBF,
+  0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xA7,
+  0x8C, 0x86, 0x8D, 0x59, 0x5E, 0x5D, 0x3F, 0x3E,
+  0x47, 0x53, 0x63, 0xD9, 0xF0, 0xF1, 0xDE, 0xD0,
+  0x43, 0x3E, 0x47, 0x45, 0x4A, 0x5B, 0xDC, 0xDA,
+  0x5D, 0x59, 0x49, 0x5F, 0xD1, 0xD2, 0xD3, 0xB9,
+  0xA5, 0xA7, 0x98, 0x9B, 0x96, 0x9D, 0x89, 0x89,
+  0x8B, 0x9C, 0x9D, 0xFC, 0xFC, 0xFC, 0x26, 0x22,
+  0x23, 0x23, 0x22, 0x22, 0x21, 0x22, 0x23, 0x22,
+  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x23,
+  0x22, 0x22, 0x29, 0x2D, 0x99, 0x99, 0xA2, 0xAA,
+  0xC4, 0xFB, 0xFC, 0xFC, 0xFC, 0xF6, 0xBF, 0xA2,
+  0x9C, 0x9C, 0x8E, 0xDC, 0xCD, 0x51, 0x41, 0x3E,
+  0x45, 0x49, 0x58, 0xCD, 0xE0, 0xE0, 0xD8, 0xDA,
+  0x4C, 0x4A, 0x45, 0x45, 0x48, 0x47, 0xDA, 0xDA,
+  0x5C, 0x58, 0x44, 0x69, 0xA9, 0x98, 0xA4, 0xA6,
+  0xA1, 0xA4, 0x99, 0x9E, 0x9D, 0x8B, 0x8A, 0x97,
+  0x87, 0x9A, 0x8A, 0xC2, 0xFC, 0xFC, 0xFC, 0x4D,
+  0x21, 0x21, 0x23, 0x22, 0x21, 0x22, 0x23, 0x22,
+  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x23, 0x22,
+  0x21, 0x22, 0x2D, 0x34, 0xA4, 0xA2, 0xA2, 0xA9,
+  0xBF, 0xC0, 0xC3, 0xC1, 0xC0, 0xBE, 0xA6, 0x9D,
+  0x99, 0x87, 0xA2, 0xF1, 0xDC, 0x64, 0x42, 0x45,
+  0x47, 0x3E, 0x49, 0x4C, 0xDD, 0xDF, 0xD8, 0xDB,
+  0x5E, 0x4C, 0x48, 0x45, 0x45, 0x41, 0xD1, 0xD6,
+  0x5A, 0x55, 0x3F, 0xA7, 0xA1, 0x98, 0x9F, 0x99,
+  0x9F, 0x9D, 0x9A, 0x95, 0x8B, 0x97, 0x89, 0x8A,
+  0x88, 0x94, 0x9C, 0x8C, 0xFC, 0xFC, 0xFC, 0xFC,
+  0xF4, 0x21, 0x23, 0x22, 0x21, 0x22, 0x23, 0x22,
+  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x23,
+  0x23, 0x23, 0x2C, 0x2C, 0xA8, 0xA2, 0xA4, 0xA4,
+  0xA9, 0xAA, 0xAA, 0xAA, 0xA9, 0xA6, 0x98, 0x9C,
+  0x8B, 0x88, 0x98, 0x8D, 0xD8, 0xD6, 0x4E, 0x47,
+  0x47, 0x49, 0x47, 0x3F, 0xDA, 0xDD, 0xDE, 0xDD,
+  0xCC, 0x4A, 0x4B, 0x3E, 0x45, 0x43, 0x61, 0xD4,
+  0x56, 0x51, 0x44, 0xA4, 0x9B, 0x8B, 0x9C, 0x9A,
+  0xA0, 0xA2, 0x98, 0x98, 0x8B, 0x8B, 0x98, 0x98,
+  0x84, 0x8B, 0x94, 0x8A, 0xA4, 0xFC, 0xFC, 0xFC,
+  0xFC, 0xF2, 0x21, 0x22, 0x21, 0x22, 0x23, 0x22,
+  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x23, 0x23,
+  0x23, 0x22, 0x2C, 0x2D, 0xC0, 0xA4, 0xA2, 0xA4,
+  0xA4, 0xA6, 0xA6, 0xA6, 0xA4, 0xA2, 0x9F, 0x89,
+  0x8B, 0x9C, 0x9C, 0x8B, 0x68, 0xDB, 0x5F, 0x4B,
+  0x3E, 0x49, 0x4B, 0x3E, 0xCC, 0xDA, 0xDC, 0xDD,
+  0xD3, 0x49, 0x52, 0x48, 0x45, 0x45, 0x53, 0xD0,
+  0x51, 0x4A, 0x44, 0xA4, 0x9B, 0x8B, 0x9C, 0xA0,
+  0x9B, 0x86, 0x89, 0x98, 0x89, 0x8A, 0x96, 0x8A,
+  0x9C, 0x89, 0x89, 0x9C, 0x8C, 0xF6, 0xFC, 0xFC,
+  0xFC, 0xFC, 0x21, 0x22, 0x21, 0x22, 0x23, 0x22,
+  0x22, 0x22, 0x22, 0x23, 0x22, 0x21, 0x22, 0x23,
+  0x22, 0x21, 0x2B, 0x34, 0xC0, 0xA8, 0xA4, 0xA2,
+  0xA2, 0x98, 0xA1, 0xA0, 0x98, 0x9F, 0x95, 0x8A,
+  0x94, 0xA1, 0x8A, 0x84, 0x9B, 0x68, 0xCC, 0x49,
+  0x4A, 0x47, 0x4C, 0x4B, 0x51, 0xD3, 0xDA, 0xDC,
+  0xD5, 0x56, 0x56, 0x4A, 0x3E, 0x45, 0x48, 0x63,
+  0x4A, 0x47, 0x3E, 0xA7, 0x98, 0x9D, 0x9E, 0x8B,
+  0x95, 0x9B, 0x89, 0x86, 0x9B, 0x8B, 0x89, 0x84,
+  0x9A, 0xA1, 0x95, 0x9A, 0x8C, 0xA4, 0xFC, 0xFC,
+  0xFC, 0xFA, 0x23, 0x22, 0x21, 0x22, 0x23, 0x22,
+  0x22, 0x22, 0x22, 0x23, 0x22, 0x21, 0x22, 0x23,
+  0x21, 0x23, 0x2C, 0xF6, 0xBF, 0xA9, 0xA2, 0x99,
+  0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9B, 0x87, 0x8B,
+  0x9C, 0x86, 0x9C, 0x8A, 0x87, 0x87, 0x89, 0x51,
+  0x54, 0x47, 0x4B, 0x50, 0x4B, 0xCF, 0xD6, 0xDC,
+  0xD5, 0x60, 0x54, 0x52, 0x48, 0x45, 0x40, 0x5A,
+  0x45, 0x43, 0x47, 0xA7, 0x98, 0x9B, 0x95, 0x95,
+  0x9A, 0x87, 0x98, 0x98, 0x8A, 0x86, 0x87, 0x9E,
+  0x9B, 0x95, 0x9D, 0x9D, 0x99, 0x85, 0xA6, 0xFA,
+  0xF2, 0x21, 0x23, 0x22, 0x21, 0x22, 0x23, 0x22,
+  0x22, 0x22, 0x22, 0x23, 0x22, 0x21, 0x22, 0x22,
+  0x21, 0x24, 0xFB, 0xF7, 0xBF, 0xA6, 0xA2, 0x99,
+  0x97, 0x89, 0x86, 0x89, 0x9C, 0x96, 0x9E, 0x94,
+  0x89, 0x99, 0x98, 0x89, 0x9E, 0x9B, 0x89, 0x8B,
+  0x58, 0x4B, 0x4A, 0x52, 0x48, 0xCC, 0xD3, 0xDA,
+  0xD3, 0x65, 0x4C, 0x58, 0x49, 0x3E, 0x2E, 0x4D,
+  0x40, 0x41, 0x45, 0xA9, 0xA1, 0x9B, 0x9E, 0x9C,
+  0x95, 0x8A, 0x94, 0x89, 0x96, 0x87, 0x9C, 0x9A,
+  0x84, 0x9D, 0x9C, 0x9E, 0x9A, 0x9C, 0x9D, 0xBB,
+  0x23, 0x23, 0x22, 0x22, 0x21, 0x22, 0x23, 0x22,
+  0x22, 0x22, 0x22, 0x23, 0x22, 0x21, 0x23, 0x23,
+  0x24, 0xFC, 0xFC, 0xF6, 0xBF, 0xA6, 0x9F, 0x99,
+  0x89, 0x95, 0x87, 0x94, 0x9D, 0x9E, 0x97, 0x9E,
+  0x95, 0x9B, 0x89, 0x95, 0x95, 0x9B, 0x89, 0x87,
+  0x5D, 0x56, 0x3E, 0x51, 0x3E, 0x60, 0xCF, 0xD3,
+  0xD2, 0xCD, 0x5C, 0x49, 0x4B, 0x3E, 0x2C, 0x48,
+  0x3E, 0x43, 0x3E, 0xA9, 0xA1, 0x9B, 0x97, 0x94,
+  0x95, 0x9A, 0x9C, 0x87, 0x87, 0x9B, 0x9C, 0x95,
+  0x9D, 0x89, 0x9A, 0x89, 0x9E, 0x9E, 0x8C, 0xA6,
+  0x20, 0x23, 0x23, 0x22, 0x23, 0x22, 0x23, 0x22,
+  0x22, 0x22, 0x22, 0x22, 0x21, 0x21, 0x20, 0x40,
+  0xFC, 0xFC, 0xFC, 0xEC, 0xBE, 0xA4, 0x9F, 0x99,
+  0x95, 0x9F, 0xA0, 0x88, 0x9D, 0x8B, 0x97, 0x95,
+  0x87, 0x95, 0x96, 0x95, 0x97, 0x94, 0x94, 0x98,
+  0xD3, 0x4C, 0x47, 0x4D, 0x42, 0x4C, 0x60, 0xCC,
+  0xCE, 0xD0, 0x65, 0x4B, 0x47, 0x44, 0x2B, 0x45,
+  0x4B, 0x47, 0x49, 0xA7, 0xA1, 0x9A, 0x97, 0x89,
+  0x95, 0x97, 0x97, 0x9E, 0x89, 0x95, 0x89, 0x9C,
+  0x87, 0x95, 0x97, 0x99, 0x95, 0x99, 0x9F, 0xA4,
+  0xC4, 0x21, 0x21, 0x23, 0x21, 0x23, 0x23, 0x23,
+  0x23, 0x23, 0x23, 0x23, 0x21, 0x20, 0xFC, 0xFC,
+  0xFC, 0xFC, 0xFC, 0xEA, 0xAA, 0xA6, 0xA2, 0x99,
+  0x8B, 0x9A, 0x95, 0x9E, 0x9E, 0x9A, 0x94, 0x87,
+  0x94, 0x94, 0x89, 0x94, 0x9B, 0x9B, 0xA7, 0xDC,
+  0xDB, 0x65, 0x2E, 0x3E, 0x43, 0x44, 0x49, 0x58,
+  0x63, 0xD3, 0xD3, 0x5E, 0x42, 0x42, 0x2D, 0x40,
+  0x54, 0x4C, 0x4A, 0xA7, 0xA0, 0x99, 0x9B, 0x94,
+  0xA0, 0x8A, 0x9B, 0x9D, 0x87, 0x95, 0x94, 0x8B,
+  0x8A, 0x98, 0x9C, 0x8A, 0x9B, 0x99, 0xA2, 0xA6,
+  0xBF, 0xEC, 0x2A, 0x20, 0x21, 0x23, 0x21, 0x20,
+  0x20, 0x20, 0x20, 0x4C, 0xF9, 0xFC, 0xFC, 0xFC,
+  0xFC, 0xFC, 0xFC, 0xEB, 0xAA, 0xA4, 0x9F, 0x9C,
+  0x8B, 0x9B, 0x88, 0x84, 0x9E, 0x9D, 0x96, 0x94,
+  0x94, 0x9A, 0x9B, 0x9B, 0xA4, 0xD5, 0xCD, 0xDE,
+  0xF1, 0xDA, 0x4C, 0x2D, 0x41, 0x2B, 0x42, 0x4C,
+  0x5E, 0xD4, 0xD7, 0xCD, 0x49, 0x2E, 0x2E, 0x41,
+  0x5E, 0x57, 0xA7, 0xA6, 0xA7, 0xA4, 0xA2, 0x98,
+  0x9D, 0x9C, 0xA1, 0x99, 0x9D, 0x88, 0x8B, 0x9C,
+  0x8A, 0x9C, 0x9C, 0x94, 0x9C, 0x89, 0xA0, 0xA6,
+  0xAA, 0xEB, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
+  0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
+  0xFC, 0xFC, 0xFB, 0xE9, 0xAA, 0xA6, 0xA2, 0x8B,
+  0x8B, 0x8A, 0x86, 0x9B, 0x9C, 0x98, 0xA0, 0x9B,
+  0x9B, 0x84, 0xA7, 0xB4, 0x61, 0xD1, 0xD2, 0xE0,
+  0xF1, 0xDC, 0x61, 0x2D, 0x2E, 0x3F, 0x56, 0x62,
+  0x5D, 0xD4, 0xD9, 0xD3, 0x54, 0x41, 0x41, 0x44,
+  0xCB, 0x60, 0x52, 0xA9, 0xA9, 0xA9, 0xA7, 0xA6,
+  0xA6, 0xA4, 0xA4, 0xA2, 0xA2, 0x9D, 0x95, 0x89,
+  0x9C, 0x8A, 0x9E, 0x9C, 0x8A, 0x9E, 0xA0, 0xA8,
+  0xC0, 0xE9, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
+  0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
+  0xFC, 0xFC, 0xFC, 0xE9, 0xAA, 0xA6, 0xA0, 0x99,
+  0x9C, 0x8B, 0x9A, 0x84, 0x9B, 0x9B, 0x98, 0x98,
+  0xA9, 0xB9, 0x49, 0x57, 0xCB, 0xD4, 0xD3, 0xF1,
+  0xD8, 0xDA, 0xCE, 0x3F, 0x41, 0x4B, 0x5D, 0xCB,
+  0x5E, 0xD6, 0xDB, 0xD6, 0x5D, 0x43, 0x3F, 0x49,
+  0xD1, 0xCC, 0x4F, 0xDD, 0xC3, 0xBB, 0xBF, 0xAA,
+  0xAA, 0xA9, 0xAA, 0xA8, 0xA8, 0xA6, 0xA6, 0xA2,
+  0x9C, 0x9F, 0x9B, 0x9A, 0x9D, 0xA2, 0xA8, 0xAA,
+  0xC1, 0xEA, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
+  0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
+  0xFC, 0xFC, 0xFC, 0xEA, 0xC0, 0xAA, 0xA6, 0xA2,
+  0xA2, 0x99, 0xA0, 0xA0, 0xA4, 0xA7, 0xA9, 0xC0,
+  0x67, 0x49, 0x54, 0x60, 0xD0, 0xD4, 0xCC, 0xDF,
+  0xD9, 0xD5, 0xD2, 0x3E, 0x47, 0x56, 0x60, 0xCD,
+  0x5D, 0xD9, 0xD9, 0xD6, 0x61, 0x3F, 0x47, 0x52,
+  0xD6, 0xD3, 0x62, 0x4D, 0x40, 0x4A, 0x57, 0xCA,
+  0xC3, 0xC1, 0xC1, 0xC0, 0xBF, 0xBF, 0xAA, 0xAA,
+  0xA6, 0xA4, 0xA4, 0xA4, 0xA6, 0xA8, 0xBE, 0xC1,
+  0xC9, 0xEB, 0xFB, 0xFB, 0xFC, 0xFC, 0xFC, 0xFC,
+  0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
+  0xFC, 0xFC, 0xFC, 0xEB, 0xC3, 0xC0, 0xAA, 0xA8,
+  0xA6, 0xA6, 0xA6, 0xA9, 0xAA, 0xC0, 0xE8, 0xD0,
+  0xD2, 0x4C, 0x5E, 0x64, 0xD0, 0xD1, 0x5F, 0xD9,
+  0xD5, 0xD1, 0xD0, 0x48, 0x52, 0x5C, 0x64, 0xCD,
+  0x5C, 0xDC, 0xD7, 0xD5, 0x62, 0x3F, 0x4C, 0x53,
+  0xDA, 0xD7, 0xCE, 0x56, 0x40, 0x4B, 0x52, 0x56,
+  0xCE, 0xDF, 0x6A, 0xEB, 0xE9, 0xC9, 0xC3, 0xC0,
+  0xC0, 0xBF, 0xBE, 0xAA, 0xBF, 0xC0, 0xC3, 0xC9,
+  0xEA, 0xF6, 0xEE, 0x58, 0x57, 0x5E, 0xD6, 0xD0,
+  0xD2, 0x61, 0xCB, 0xD6, 0xD6, 0xD4, 0xDF, 0xF3,
+  0xF2, 0xDD, 0xD7, 0xEB, 0xC9, 0xC1, 0xC0, 0xBF,
+  0xAA, 0xAA, 0xAA, 0xBE, 0xC3, 0xF0, 0xD2, 0xD2,
+  0xD2, 0x51, 0x62, 0xCC, 0xD0, 0xCC, 0x61, 0xD3,
+  0xCF, 0xCE, 0xD2, 0x48, 0x5A, 0x61, 0xCC, 0xCE,
+  0x5F, 0xD9, 0xD5, 0xD1, 0x63, 0x44, 0x56, 0x56,
+  0xDC, 0xD9, 0xD4, 0x5E, 0x42, 0x4A, 0x4C, 0x57,
+  0x5D, 0xD8, 0xE0, 0xD8, 0xDC, 0xCB, 0x66, 0xEC,
+  0xE8, 0xC3, 0xC3, 0xC3, 0xC3, 0xC9, 0xE8, 0xEA,
+  0xF6, 0x50, 0x3E, 0x58, 0x57, 0x5A, 0xD6, 0xD4,
+  0xCC, 0x4B, 0x53, 0x5C, 0x64, 0xD1, 0xDF, 0xF3,
+  0xF1, 0xDE, 0xD9, 0xF6, 0xEB, 0xC9, 0xC1, 0xC1,
+  0xC0, 0xC0, 0xC1, 0xC9, 0xF0, 0xD6, 0xCD, 0xD6,
+  0xD3, 0x53, 0xCB, 0xCF, 0xCD, 0x5F, 0x5F, 0xCE,
+  0xCF, 0xCD, 0xD0, 0x47, 0x5F, 0xCB, 0xCE, 0xCD,
+  0x63, 0xD6, 0xD3, 0xD1, 0x63, 0x3F, 0x58, 0x58,
+  0xDB, 0xDC, 0xDA, 0x65, 0x3E, 0x49, 0x49, 0x4D,
+  0x49, 0xDC, 0xDF, 0xE0, 0xDE, 0xD5, 0x47, 0x47,
+  0x46, 0x6B, 0xEB, 0xEA, 0xE9, 0xEA, 0xEB, 0xF6,
+  0xD0, 0x57, 0x57, 0x47, 0x47, 0x5B, 0xD4, 0xD4,
+  0xCD, 0x44, 0x3E, 0x4B, 0x50, 0x4B, 0x51, 0xD5,
+  0xDB, 0xD8, 0xDE, 0x4B, 0xF6, 0xF6, 0xEA, 0xE9,
+  0xE8, 0xEA, 0xEB, 0x67, 0x5E, 0xCC, 0xD6, 0xDC,
+  0xD5, 0x58, 0xCE, 0xCE, 0x62, 0x50, 0xCC, 0xD3,
+  0xD2, 0xCD, 0xCD, 0x4B, 0x64, 0xCE, 0xCE, 0x64,
+  0xCC, 0xD3, 0xD2, 0xD2, 0x61, 0x47, 0x5D, 0x5C,
+  0xDD, 0xDD, 0xD9, 0xD1, 0x4C, 0x47, 0x49, 0x4A,
+  0x4B, 0xD1, 0xD8, 0xE0, 0xDF, 0xDD, 0x5D, 0x4A,
+  0x48, 0x52, 0x51, 0x3F, 0xF6, 0xEC, 0xE0, 0xE0,
+  0xD3, 0x5E, 0x5F, 0x50, 0x4B, 0x50, 0xCB, 0xCE,
+  0x64, 0x45, 0x4C, 0x57, 0x57, 0x58, 0x52, 0xD6,
+  0xD3, 0xDE, 0xDF, 0xD1, 0x3E, 0x4B, 0xF6, 0xF6,
+  0xEC, 0x66, 0x53, 0x43, 0x56, 0xD1, 0xD9, 0xDE,
+  0xD4, 0x5E, 0xCE, 0xCC, 0x5B, 0x2C, 0xD4, 0xD5,
+  0xD2, 0xD0, 0x63, 0x5D, 0xCD, 0xD0, 0xCD, 0x5E,
+  0xD0, 0xCF, 0xCE, 0xD2, 0x5E, 0x50, 0x60, 0x5D,
+  0xDE, 0xDD, 0xDC, 0xD7, 0x5D, 0x45, 0x47, 0x3E,
+  0x4B, 0x5E, 0xDE, 0xDF, 0xE0, 0xD8, 0xCF, 0x3E,
+  0x45, 0x51, 0x58, 0x42, 0xCB, 0xDA, 0xDE, 0xD8,
+  0xD2, 0x61, 0xCC, 0xCF, 0xD6, 0xDA, 0xDA, 0xD5,
+  0xD0, 0x50, 0x44, 0x57, 0x57, 0x58, 0x45, 0xD1,
+  0xD1, 0xD7, 0xDF, 0xDF, 0xD7, 0xCF, 0x64, 0x60,
+  0xCE, 0xCE, 0xCE, 0x63, 0xCF, 0xDA, 0xDE, 0xD9,
+  0xCF, 0x63, 0xCD, 0x63, 0x4D, 0x4B, 0xD6, 0xD5,
+  0xCE, 0xD3, 0x60, 0xCB, 0xD0, 0xD0, 0x65, 0x47,
+  0xD0, 0xCC, 0xCC, 0xD1, 0x59, 0x5D, 0x63, 0x5E,
+  0xDD, 0xDD, 0xDE, 0xDC, 0xCB, 0x40, 0x48, 0x45,
+  0x3E, 0x3E, 0xD9, 0xDF, 0xE0, 0xDF, 0xDA, 0x51,
+  0x4C, 0x48, 0x56, 0x4C, 0x5B, 0xD2, 0xDA, 0xDB,
+  0xCB, 0x5F, 0xD0, 0xCC, 0xDC, 0xF0, 0xF3, 0xE0,
+  0xDD, 0xCC, 0x41, 0x50, 0x57, 0x57, 0x4B, 0x5D,
+  0xD3, 0xD1, 0xDE, 0xDF, 0xDE, 0xD7, 0xD0, 0xD0,
+  0xD5, 0xD6, 0xD6, 0xCE, 0xD7, 0xDC, 0xDA, 0xD5,
+  0x60, 0x63, 0x64, 0x5E, 0x47, 0x61, 0xD5, 0xD2,
+  0xCF, 0xD0, 0x59, 0xCD, 0xD1, 0xCF, 0x61, 0x4D,
+  0xCC, 0xCE, 0xCD, 0xD0, 0x52, 0x61, 0x64, 0x60,
+  0xDA, 0xDE, 0xDE, 0xDD, 0xD1, 0x4B, 0x4A, 0x45,
+  0x3E, 0x41, 0xCD, 0xDE, 0xE0, 0xF1, 0xDE, 0x63,
+  0x4A, 0x4A, 0x4A, 0x4B, 0x50, 0xCB, 0xD4, 0xD7,
+  0x5E, 0x54, 0x62, 0xD3, 0xD4, 0xF0, 0xF3, 0xF3,
+  0xF2, 0xDE, 0x61, 0x40, 0x49, 0x56, 0x4D, 0x3E,
+  0x4B, 0xCE, 0xD9, 0xD8, 0xD9, 0xD5, 0xCF, 0xD2,
+  0xD6, 0xD6, 0xD1, 0xD1, 0xD7, 0xD5, 0xCF, 0xD0,
+  0x54, 0x64, 0x63, 0x56, 0x2C, 0xCB, 0xD1, 0xCC,
+  0xD3, 0xCD, 0x54, 0xCF, 0xD1, 0xCE, 0x5E, 0x5C,
+  0xCE, 0xCE, 0xCE, 0xCB, 0x4B, 0x63, 0xCC, 0x61,
+  0xD4, 0xDC, 0xDE, 0xDE, 0xDA, 0x5D, 0x45, 0x45,
+  0x48, 0x3F, 0x52, 0xD9, 0xD8, 0xDF, 0xDF, 0xD2,
+  0x52, 0x4B, 0x3E, 0x2E, 0x47, 0x60, 0xCF, 0xD3,
+  0x59, 0x48, 0x50, 0x5E, 0xCC, 0xDE, 0xF2, 0xF2,
+  0xF3, 0xF3, 0xDD, 0x5D, 0x3E, 0x48, 0x47, 0x47,
+  0x58, 0xD1, 0xDA, 0xDA, 0xD5, 0xD1, 0xCD, 0xD2,
+  0xD3, 0xCF, 0xD3, 0xD1, 0xCD, 0xD3, 0xD2, 0x5E,
+  0x52, 0x64, 0x60, 0x4B, 0x45, 0x61, 0xCD, 0xD3,
+  0xD3, 0x64, 0x61, 0xD0, 0xD0, 0x64, 0x45, 0x63,
+  0xD0, 0xCE, 0xD0, 0x60, 0x56, 0xCB, 0xCC, 0x62,
+  0xCE, 0xDA, 0xDE, 0xD8, 0xDD, 0xCC, 0x45, 0x49,
+  0x3E, 0x47, 0x42, 0xD1, 0xDC, 0xD8, 0xD8, 0xD3,
+  0x5D, 0x4C, 0x49, 0x3F, 0x47, 0x59, 0xCD, 0xCF,
+  0x59, 0x2E, 0x48, 0x47, 0x52, 0x63, 0xF0, 0xF2,
+  0xF3, 0xF3, 0xF2, 0xDA, 0x52, 0x4B, 0x52, 0x58,
+  0x5E, 0x63, 0xD0, 0xD0, 0xD0, 0xCF, 0xCE, 0xCE,
+  0xCF, 0x65, 0x61, 0xD6, 0xD6, 0xD6, 0xCB, 0x4B,
+  0x61, 0x62, 0x5D, 0x43, 0x4B, 0x61, 0xD0, 0xD4,
+  0xD1, 0x61, 0xCE, 0xD2, 0xCD, 0x5E, 0x4A, 0xCE,
+  0xD0, 0xCC, 0xD0, 0x59, 0x61, 0xCC, 0xCC, 0x62,
+  0xD1, 0xD5, 0xDE, 0xD8, 0xDD, 0xCF, 0x4B, 0x4A,
+  0x45, 0x3E, 0x2D, 0xCB, 0xDC, 0xDE, 0xD8, 0xD5,
+  0x60, 0x54, 0x51, 0x4C, 0x4D, 0x5C, 0xCC, 0xCE,
+  0x5A, 0x2C, 0x50, 0x53, 0x3E, 0x59, 0xD8, 0xF3,
+  0xF2, 0xF3, 0xF3, 0xE0, 0x5E, 0x4A, 0x4C, 0x53,
+  0x5E, 0x63, 0xCC, 0xCC, 0xCC, 0xCD, 0xCF, 0xD3,
+  0x62, 0x53, 0xD6, 0xD6, 0xD6, 0xD6, 0x5B, 0x48,
+  0x64, 0x63, 0x59, 0x44, 0x57, 0x63, 0xD2, 0xD3,
+  0xD0, 0x5E, 0xD0, 0xD1, 0xCB, 0x58, 0x4C, 0xCF,
+  0xCF, 0xCE, 0xCE, 0x57, 0x63, 0xCC, 0xCD, 0x57,
+};
+
diff -u --recursive --new-file v2.1.72/linux/drivers/sgi/char/newport.c linux/drivers/sgi/char/newport.c
--- v2.1.72/linux/drivers/sgi/char/newport.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sgi/char/newport.c	Wed Dec 10 10:31:11 1997
@@ -0,0 +1,217 @@
+/*
+ * newport.c: context switching the newport graphics card and
+ *            newport graphics support.
+ *
+ * Author: Miguel de Icaza
+ */
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <asm/types.h>
+#include <asm/gfx.h>
+#include <asm/ng1.h>
+#include <asm/uaccess.h>
+#include "newport.h"
+
+/* Kernel routines for supporting graphics context switching */
+
+void newport_save (void *y)
+{
+	newport_ctx *x = y;
+	newport_wait ();
+
+#define LOAD(val) x->val = npregs->set.val;
+#define LOADI(val) x->val = npregs->set.val.i;
+#define LOADC(val) x->val = npregs->cset.val;
+	
+	LOAD(drawmode1);
+	LOAD(drawmode0);
+	LOAD(lsmode);
+	LOAD(lspattern);
+	LOAD(lspatsave);
+	LOAD(zpattern);
+	LOAD(colorback);
+	LOAD(colorvram);
+	LOAD(alpharef);
+	LOAD(smask0x);
+	LOAD(smask0y);
+	LOADI(_xstart);
+	LOADI(_ystart);
+	LOADI(_xend);
+	LOADI(_yend);
+	LOAD(xsave);
+	LOAD(xymove);
+	LOADI(bresd);
+	LOADI(bress1);
+	LOAD(bresoctinc1);
+	LOAD(bresrndinc2);
+	LOAD(brese1);
+	LOAD(bress2);
+	LOAD(aweight0);
+	LOAD(aweight1);
+	LOADI(colorred);
+	LOADI(coloralpha);
+	LOADI(colorgrn);
+	LOADI(colorblue);
+	LOADI(slopered);
+	LOADI(slopealpha);
+	LOADI(slopegrn);
+	LOADI(slopeblue);
+	LOAD(wrmask);
+	LOAD(hostrw0);
+	LOAD(hostrw1);
+	
+        /* configregs */
+	
+	LOADC(smask1x);
+	LOADC(smask1y);
+	LOADC(smask2x);
+	LOADC(smask2y);
+	LOADC(smask3x);
+	LOADC(smask3y);
+	LOADC(smask4x);
+	LOADC(smask4y);
+	LOADC(topscan);
+	LOADC(xywin);
+	LOADC(clipmode);
+	LOADC(config);
+
+	/* Mhm, maybe I am missing something, but it seems that
+	 * saving/restoring the DCB is only a matter of saving these
+	 * registers
+	 */
+
+	newport_bfwait ();
+	LOAD (dcbmode);
+	newport_bfwait ();
+	x->dcbdata0 = npregs->set.dcbdata0.all;
+	newport_bfwait ();
+	LOAD(dcbdata1);
+}
+
+/*
+ * Importat things to keep in mind when restoring the newport context:
+ *
+ * 1. slopered register is stored as a 2's complete (s12.11);
+ *    needs to be converted to a signed magnitude (s(8)12.11).
+ *
+ * 2. xsave should be stored after xstart.
+ *
+ * 3. None of the registers should be written with the GO address.
+ *    (read the docs for more details on this).
+ */
+void newport_restore (void *y)
+{
+	newport_ctx *x = y;
+#define STORE(val) npregs->set.val = x->val
+#define STOREI(val) npregs->set.val.i = x->val
+#define STOREC(val) npregs->cset.val = x->val
+	newport_wait ();
+	
+	STORE(drawmode1);
+	STORE(drawmode0);
+	STORE(lsmode);
+	STORE(lspattern);
+	STORE(lspatsave);
+	STORE(zpattern);
+	STORE(colorback);
+	STORE(colorvram);
+	STORE(alpharef);
+	STORE(smask0x);
+	STORE(smask0y);
+	STOREI(_xstart);
+	STOREI(_ystart);
+	STOREI(_xend);
+	STOREI(_yend);
+	STORE(xsave);
+	STORE(xymove);
+	STOREI(bresd);
+	STOREI(bress1);
+	STORE(bresoctinc1);
+	STORE(bresrndinc2);
+	STORE(brese1);
+	STORE(bress2);
+	STORE(aweight0);
+	STORE(aweight1);
+	STOREI(colorred);
+	STOREI(coloralpha);
+	STOREI(colorgrn);
+	STOREI(colorblue);
+	STOREI(slopered);
+	STOREI(slopealpha);
+	STOREI(slopegrn);
+	STOREI(slopeblue);
+	STORE(wrmask);
+	STORE(hostrw0);
+	STORE(hostrw1);
+	
+        /* configregs */
+	
+	STOREC(smask1x);
+	STOREC(smask1y);
+	STOREC(smask2x);
+	STOREC(smask2y);
+	STOREC(smask3x);
+	STOREC(smask3y);
+	STOREC(smask4x);
+	STOREC(smask4y);
+	STOREC(topscan);
+	STOREC(xywin);
+	STOREC(clipmode);
+	STOREC(config);
+
+	/* FIXME: restore dcb thingies */
+}
+
+int
+newport_ioctl (int card, int cmd, unsigned long arg)
+{
+	switch (cmd){
+	case NG1_SETDISPLAYMODE: {
+		int i;
+		struct ng1_setdisplaymode_args request;
+		
+		if (copy_from_user (&request, (void *) arg, sizeof (request)))
+			return -EFAULT;
+
+		newport_wait ();
+		newport_bfwait ();
+		npregs->set.dcbmode = DCB_XMAP0 | XM9_CRS_FIFO_AVAIL |
+			DCB_DATAWIDTH_1 | R_DCB_XMAP9_PROTOCOL;
+		xmap9FIFOWait (npregs);
+		
+		/* FIXME: timing is wrong, just be extracted from 
+		 * the per-board timing table.  I still have to figure
+		 * out where this comes from
+		 *
+		 * This is used to select the protocol used to talk to
+		 * the xmap9.  For now I am using 60, selecting the
+		 * WSLOW_DCB_XMAP9_PROTOCOL.
+		 *
+		 * Robert Tray comments on this issue:
+		 *
+		 * cfreq refers to the frequency of the monitor
+		 * (ie. the refresh rate).  Our monitors run typically
+		 * between 60 Hz and 76 Hz.  But it will be as low as
+		 * 50 Hz if you're displaying NTSC/PAL and as high as
+		 * 120 Hz if you are runining in stereo mode.  You
+		 * might want to try the WSLOW values.
+		 */
+		xmap9SetModeReg (npregs, request.wid, request.mode, 60);
+		return 0;
+	}
+	case NG1_SET_CURSOR_HOTSPOT: {
+		struct ng1_set_cursor_hotspot request;
+		
+		if (copy_from_user (&request, (void *) arg, sizeof (request)))
+			return -EFAULT;
+		/* FIXME: make request.xhot, request.yhot the hot spot */
+		return 0;
+	}
+	
+	case NG1_SETGAMMARAMP0:
+		/* FIXME: load the gamma ramps :-) */
+		return 0;
+
+	}
+	return -EINVAL;
+}
diff -u --recursive --new-file v2.1.72/linux/drivers/sgi/char/newport.h linux/drivers/sgi/char/newport.h
--- v2.1.72/linux/drivers/sgi/char/newport.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sgi/char/newport.h	Wed Dec 10 10:31:11 1997
@@ -0,0 +1,585 @@
+/* $Id: newport.h,v 1.2 1996/06/10 16:38:34 dm Exp $
+ * newport.h: Defines and register layout for NEWPORT graphics
+ *            hardware.
+ *
+ * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ */
+
+#ifndef _SGI_NEWPORT_H
+#define _SGI_NEWPORT_H
+
+
+typedef volatile unsigned long npireg_t;
+
+union npfloat {
+	volatile float f;
+	npireg_t       i;
+};
+
+typedef union npfloat npfreg_t;
+
+union np_dcb {
+	npireg_t all;
+	struct { volatile unsigned short s0, s1; } hwords;
+	struct { volatile unsigned char b0, b1, b2, b3; } bytes;
+};
+
+struct newport_rexregs {
+	npireg_t drawmode1;      /* GL extra mode bits */
+	
+#define DM1_PLANES         0x00000007
+#define    DM1_NOPLANES    0x00000000
+#define    DM1_RGBPLANES   0x00000001
+#define    DM1_RGBAPLANES  0x00000002
+#define    DM1_OLAYPLANES  0x00000004
+#define    DM1_PUPPLANES   0x00000005
+#define    DM1_CIDPLANES   0x00000006
+	
+#define NPORT_DMODE1_DDMASK      0x00000018
+#define NPORT_DMODE1_DD4         0x00000000
+#define NPORT_DMODE1_DD8         0x00000008
+#define NPORT_DMODE1_DD12        0x00000010
+#define NPORT_DMODE1_DD24        0x00000018
+#define NPORT_DMODE1_DSRC        0x00000020
+#define NPORT_DMODE1_YFLIP       0x00000040
+#define NPORT_DMODE1_RWPCKD      0x00000080
+#define NPORT_DMODE1_HDMASK      0x00000300
+#define NPORT_DMODE1_HD4         0x00000000
+#define NPORT_DMODE1_HD8         0x00000100
+#define NPORT_DMODE1_HD12        0x00000200
+#define NPORT_DMODE1_HD32        0x00000300
+#define NPORT_DMODE1_RWDBL       0x00000400
+#define NPORT_DMODE1_ESWAP       0x00000800 /* Endian swap */
+#define NPORT_DMODE1_CCMASK      0x00007000
+#define NPORT_DMODE1_CCLT        0x00001000
+#define NPORT_DMODE1_CCEQ        0x00002000
+#define NPORT_DMODE1_CCGT        0x00004000
+#define NPORT_DMODE1_RGBMD       0x00008000
+#define NPORT_DMODE1_DENAB       0x00010000 /* Dither enable */
+#define NPORT_DMODE1_FCLR        0x00020000 /* Fast clear */
+#define NPORT_DMODE1_BENAB       0x00040000 /* Blend enable */
+#define NPORT_DMODE1_SFMASK      0x00380000
+#define NPORT_DMODE1_SF0         0x00000000
+#define NPORT_DMODE1_SF1         0x00080000
+#define NPORT_DMODE1_SFDC        0x00100000
+#define NPORT_DMODE1_SFMDC       0x00180000
+#define NPORT_DMODE1_SFSA        0x00200000
+#define NPORT_DMODE1_SFMSA       0x00280000
+#define NPORT_DMODE1_DFMASK      0x01c00000
+#define NPORT_DMODE1_DF0         0x00000000
+#define NPORT_DMODE1_DF1         0x00400000
+#define NPORT_DMODE1_DFSC        0x00800000
+#define NPORT_DMODE1_DFMSC       0x00c00000
+#define NPORT_DMODE1_DFSA        0x01000000
+#define NPORT_DMODE1_DFMSA       0x01400000
+#define NPORT_DMODE1_BBENAB      0x02000000 /* Back blend enable */
+#define NPORT_DMODE1_PFENAB      0x04000000 /* Pre-fetch enable */
+#define NPORT_DMODE1_ABLEND      0x08000000 /* Alpha blend */
+#define NPORT_DMODE1_LOMASK      0xf0000000
+#define NPORT_DMODE1_LOZERO      0x00000000
+#define NPORT_DMODE1_LOAND       0x10000000
+#define NPORT_DMODE1_LOANDR      0x20000000
+#define NPORT_DMODE1_LOSRC       0x30000000
+#define NPORT_DMODE1_LOANDI      0x40000000
+#define NPORT_DMODE1_LODST       0x50000000
+#define NPORT_DMODE1_LOXOR       0x60000000
+#define NPORT_DMODE1_LOOR        0x70000000
+#define NPORT_DMODE1_LONOR       0x80000000
+#define NPORT_DMODE1_LOXNOR      0x90000000
+#define NPORT_DMODE1_LONDST      0xa0000000
+#define NPORT_DMODE1_LOORR       0xb0000000
+#define NPORT_DMODE1_LONSRC      0xc0000000
+#define NPORT_DMODE1_LOORI       0xd0000000
+#define NPORT_DMODE1_LONAND      0xe0000000
+#define NPORT_DMODE1_LOONE       0xf0000000
+
+	npireg_t drawmode0;      /* REX command register */
+
+	/* These bits define the graphics opcode being performed. */
+#define NPORT_DMODE0_OPMASK   0x00000003 /* Opcode mask */
+#define NPORT_DMODE0_NOP      0x00000000 /* No operation */
+#define NPORT_DMODE0_RD       0x00000001 /* Read operation */
+#define NPORT_DMODE0_DRAW     0x00000002 /* Draw operation */
+#define NPORT_DMODE0_S2S      0x00000003 /* Screen to screen operation */
+
+	/* The following decide what addressing mode(s) are to be used */
+#define NPORT_DMODE0_AMMASK   0x0000001c /* Address mode mask */
+#define NPORT_DMODE0_SPAN     0x00000000 /* Spanning address mode */
+#define NPORT_DMODE0_BLOCK    0x00000004 /* Block address mode */
+#define NPORT_DMODE0_ILINE    0x00000008 /* Iline address mode */
+#define NPORT_DMODE0_FLINE    0x0000000c /* Fline address mode */
+#define NPORT_DMODE0_ALINE    0x00000010 /* Aline address mode */
+#define NPORT_DMODE0_TLINE    0x00000014 /* Tline address mode */
+#define NPORT_DMODE0_BLINE    0x00000018 /* Bline address mode */
+
+	/* And now some misc. operation control bits. */
+#define NPORT_DMODE0_DOSETUP  0x00000020
+#define NPORT_DMODE0_CHOST    0x00000040
+#define NPORT_DMODE0_AHOST    0x00000080
+#define NPORT_DMODE0_STOPX    0x00000100
+#define NPORT_DMODE0_STOPY    0x00000200
+#define NPORT_DMODE0_SK1ST    0x00000400
+#define NPORT_DMODE0_SKLST    0x00000800
+#define NPORT_DMODE0_ZPENAB   0x00001000
+#define NPORT_DMODE0_LISPENAB 0x00002000
+#define NPORT_DMODE0_LISLST   0x00004000
+#define NPORT_DMODE0_L32      0x00008000
+#define NPORT_DMODE0_ZOPQ     0x00010000
+#define NPORT_DMODE0_LISOPQ   0x00020000
+#define NPORT_DMODE0_SHADE    0x00040000
+#define NPORT_DMODE0_LRONLY   0x00080000
+#define NPORT_DMODE0_XYOFF    0x00100000
+#define NPORT_DMODE0_CLAMP    0x00200000
+#define NPORT_DMODE0_ENDPF    0x00400000
+#define NPORT_DMODE0_YSTR     0x00800000
+
+	npireg_t lsmode;      /* Mode for line stipple ops */
+	npireg_t lspattern;   /* Pattern for line stipple ops */
+	npireg_t lspatsave;   /* Backup save pattern */
+	npireg_t zpattern;    /* Pixel zpattern */
+	npireg_t colorback;   /* Background color */
+	npireg_t colorvram;   /* Clear color for fast vram */
+	npireg_t alpharef;    /* Reference value for afunctions */
+	unsigned long pad0;
+	npireg_t smask0x;     /* Window GL relative screen mask 0 */
+	npireg_t smask0y;     /* Window GL relative screen mask 0 */
+	npireg_t _setup;
+	npireg_t _stepz;
+	npireg_t _lsrestore;
+	npireg_t _lssave;
+
+	unsigned long _pad1[0x30];
+
+	/* Iterators, full state for context switch */
+	npfreg_t _xstart;	/* X-start point (current) */
+	npfreg_t _ystart;	/* Y-start point (current) */
+	npfreg_t _xend;		/* x-end point */
+	npfreg_t _yend;		/* y-end point */
+	npireg_t xsave;		/* copy of xstart integer value for BLOCk addressing MODE */
+	npireg_t xymove;	/* x.y offset from xstart, ystart for relative operations */
+	npfreg_t bresd;
+	npfreg_t bress1;;
+	npireg_t bresoctinc1;
+	volatile int bresrndinc2;
+	npireg_t brese1;
+	npireg_t bress2;
+	npireg_t aweight0;
+	npireg_t aweight1;
+	npfreg_t xstartf;
+	npfreg_t ystartf;
+	npfreg_t xendf;
+	npfreg_t yendf;
+	npireg_t xstarti;
+	npfreg_t xendf1;
+	npireg_t xystarti;
+	npireg_t xyendi;
+	npireg_t xstartendi;
+
+	unsigned long _unused2[0x29];
+
+	npfreg_t colorred;
+	npfreg_t coloralpha;
+	npfreg_t colorgrn;
+	npfreg_t colorblue;
+	npfreg_t slopered;
+	npfreg_t slopealpha;
+	npfreg_t slopegrn;
+	npfreg_t slopeblue;
+	npireg_t wrmask;
+	npireg_t colori;
+	npfreg_t colorx;
+	npfreg_t slopered1;
+	npireg_t hostrw0;
+	npireg_t hostrw1;
+	npireg_t dcbmode;
+#define NPORT_DMODE_WMASK   0x00000003
+#define NPORT_DMODE_W4      0x00000000
+#define NPORT_DMODE_W1      0x00000001
+#define NPORT_DMODE_W2      0x00000002
+#define NPORT_DMODE_W3      0x00000003
+#define NPORT_DMODE_EDPACK  0x00000004
+#define NPORT_DMODE_ECINC   0x00000008
+#define NPORT_DMODE_CMASK   0x00000070
+#define NPORT_DMODE_AMASK   0x00000780
+#define NPORT_DMODE_AVC2    0x00000000
+#define NPORT_DMODE_ACMALL  0x00000080
+#define NPORT_DMODE_ACM0    0x00000100
+#define NPORT_DMODE_ACM1    0x00000180
+#define NPORT_DMODE_AXMALL  0x00000200
+#define NPORT_DMODE_AXM0    0x00000280
+#define NPORT_DMODE_AXM1    0x00000300
+#define NPORT_DMODE_ABT     0x00000380
+#define NPORT_DMODE_AVCC1   0x00000400
+#define NPORT_DMODE_AVAB1   0x00000480
+#define NPORT_DMODE_ALG3V0  0x00000500
+#define NPORT_DMODE_A1562   0x00000580
+#define NPORT_DMODE_ESACK   0x00000800
+#define NPORT_DMODE_EASACK  0x00001000
+#define NPORT_DMODE_CWMASK  0x0003e000
+#define NPORT_DMODE_CHMASK  0x007c0000
+#define NPORT_DMODE_CSMASK  0x0f800000
+#define NPORT_DMODE_SENDIAN 0x10000000
+
+	unsigned long _unused3;
+
+	union np_dcb dcbdata0;
+	npireg_t dcbdata1;
+};
+
+struct newport_cregs {
+	npireg_t smask1x;
+	npireg_t smask1y;
+	npireg_t smask2x;
+	npireg_t smask2y;
+	npireg_t smask3x;
+	npireg_t smask3y;
+	npireg_t smask4x;
+	npireg_t smask4y;
+	npireg_t topscan;
+	npireg_t xywin;
+	npireg_t clipmode;
+#define NPORT_CMODE_SM0   0x00000001
+#define NPORT_CMODE_SM1   0x00000002
+#define NPORT_CMODE_SM2   0x00000004
+#define NPORT_CMODE_SM3   0x00000008
+#define NPORT_CMODE_SM4   0x00000010
+#define NPORT_CMODE_CMSK  0x00001e00
+
+	unsigned long _unused0;
+	unsigned long config;
+#define NPORT_CFG_G32MD   0x00000001
+#define NPORT_CFG_BWIDTH  0x00000002
+#define NPORT_CFG_ERCVR   0x00000004
+#define NPORT_CFG_BDMSK   0x00000078
+#define NPORT_CFG_GDMSK   0x00000f80
+#define NPORT_CFG_GD0     0x00000080
+#define NPORT_CFG_GD1     0x00000100
+#define NPORT_CFG_GD2     0x00000200
+#define NPORT_CFG_GD3     0x00000400
+#define NPORT_CFG_GD4     0x00000800
+#define NPORT_CFG_GFAINT  0x00001000
+#define NPORT_CFG_TOMSK   0x0000e000
+#define NPORT_CFG_VRMSK   0x00070000
+#define NPORT_CFG_FBTYP   0x00080000
+
+	npireg_t _unused1;
+	npireg_t stat;
+#define NPORT_STAT_VERS   0x00000007
+#define NPORT_STAT_GBUSY  0x00000008
+#define NPORT_STAT_BBUSY  0x00000010
+#define NPORT_STAT_VRINT  0x00000020
+#define NPORT_STAT_VIDINT 0x00000040
+#define NPORT_STAT_GLMSK  0x00001f80
+#define NPORT_STAT_BLMSK  0x0007e000
+#define NPORT_STAT_BFIRQ  0x00080000
+#define NPORT_STAT_GFIRQ  0x00100000
+
+	npireg_t ustat;
+	npireg_t dreset;
+};
+
+struct newport_regs {
+	struct newport_rexregs set;
+	unsigned long _unused0[0x16e];
+	struct newport_rexregs go;
+	unsigned long _unused1[0x22e];
+	struct newport_cregs cset;
+	unsigned long _unused2[0x1ef];
+	struct newport_cregs cgo;
+};
+extern struct newport_regs *npregs;
+
+
+typedef struct {
+	unsigned int drawmode1;
+	unsigned int drawmode0;
+	unsigned int lsmode;   
+	unsigned int lspattern;
+	unsigned int lspatsave;
+	unsigned int zpattern; 
+	unsigned int colorback;
+	unsigned int colorvram;
+	unsigned int alpharef; 
+	unsigned int smask0x;  
+	unsigned int smask0y;  
+	unsigned int _xstart;  
+	unsigned int _ystart;  
+	unsigned int _xend;    
+	unsigned int _yend;    
+	unsigned int xsave;    
+	unsigned int xymove;   
+	unsigned int bresd;    
+	unsigned int bress1;   
+	unsigned int bresoctinc1;
+	unsigned int bresrndinc2;
+	unsigned int brese1;     
+	unsigned int bress2;     
+	
+	unsigned int aweight0;    
+	unsigned int aweight1;    
+	unsigned int colorred;    
+	unsigned int coloralpha;  
+	unsigned int colorgrn;    
+	unsigned int colorblue;   
+	unsigned int slopered;    
+	unsigned int slopealpha;  
+	unsigned int slopegrn;    
+	unsigned int slopeblue;   
+	unsigned int wrmask;      
+	unsigned int hostrw0;     
+	unsigned int hostrw1;     
+	
+        /* configregs */
+	
+	unsigned int smask1x;    
+	unsigned int smask1y;    
+	unsigned int smask2x;    
+	unsigned int smask2y;    
+	unsigned int smask3x;    
+	unsigned int smask3y;    
+	unsigned int smask4x;    
+	unsigned int smask4y;    
+	unsigned int topscan;    
+	unsigned int xywin;      
+	unsigned int clipmode;   
+	unsigned int config;     
+	
+        /* dcb registers */
+	unsigned int dcbmode;   
+	unsigned int dcbdata0;  
+	unsigned int dcbdata1;
+} newport_ctx;
+
+/* Reading/writing VC2 registers. */
+#define VC2_REGADDR_INDEX      0x00000000
+#define VC2_REGADDR_IREG       0x00000010
+#define VC2_REGADDR_RAM        0x00000030
+#define VC2_PROTOCOL           (NPORT_DMODE_EASACK | 0x00800000 | 0x00040000)
+
+#define VC2_VLINET_ADDR        0x000
+#define VC2_VFRAMET_ADDR       0x400
+#define VC2_CGLYPH_ADDR        0x500
+
+/* Now the Indexed registers of the VC2. */
+#define VC2_IREG_VENTRY        0x00
+#define VC2_IREG_CENTRY        0x01
+#define VC2_IREG_CURSX         0x02
+#define VC2_IREG_CURSY         0x03
+#define VC2_IREG_CCURSX        0x04
+#define VC2_IREG_DENTRY        0x05
+#define VC2_IREG_SLEN          0x06
+#define VC2_IREG_RADDR         0x07
+#define VC2_IREG_VFPTR         0x08
+#define VC2_IREG_VLSPTR        0x09
+#define VC2_IREG_VLIR          0x0a
+#define VC2_IREG_VLCTR         0x0b
+#define VC2_IREG_CTPTR         0x0c
+#define VC2_IREG_WCURSY        0x0d
+#define VC2_IREG_DFPTR         0x0e
+#define VC2_IREG_DLTPTR        0x0f
+#define VC2_IREG_CONTROL       0x10
+#define VC2_IREG_CONFIG        0x20
+
+extern inline void newport_vc2_set(struct newport_regs *regs, unsigned char vc2ireg,
+				   unsigned short val)
+{
+	regs->set.dcbmode = (NPORT_DMODE_AVC2 | VC2_REGADDR_INDEX | NPORT_DMODE_W3 |
+			   NPORT_DMODE_ECINC | VC2_PROTOCOL);
+	regs->set.dcbdata0.all = (vc2ireg << 24) | (val << 8);
+}
+
+extern inline unsigned short newport_vc2_get(struct newport_regs *regs,
+					     unsigned char vc2ireg)
+{
+	regs->set.dcbmode = (NPORT_DMODE_AVC2 | VC2_REGADDR_INDEX | NPORT_DMODE_W1 |
+			   NPORT_DMODE_ECINC | VC2_PROTOCOL);
+	regs->set.dcbdata0.bytes.b3 = vc2ireg;
+	regs->set.dcbmode = (NPORT_DMODE_AVC2 | VC2_REGADDR_IREG | NPORT_DMODE_W2 |
+			   NPORT_DMODE_ECINC | VC2_PROTOCOL);
+	return regs->set.dcbdata0.hwords.s1;
+}
+
+/* VC2 Control register bits */
+#define VC2_CTRL_EVIRQ     0x0001
+#define VC2_CTRL_EDISP     0x0002
+#define VC2_CTRL_EVIDEO    0x0004
+#define VC2_CTRL_EDIDS     0x0008
+#define VC2_CTRL_ECURS     0x0010
+#define VC2_CTRL_EGSYNC    0x0020
+#define VC2_CTRL_EILACE    0x0040
+#define VC2_CTRL_ECDISP    0x0080
+#define VC2_CTRL_ECCURS    0x0100
+#define VC2_CTRL_ECG64     0x0200
+#define VC2_CTRL_GLSEL     0x0400
+
+/* Controlling the color map on NEWPORT. */
+#define NCMAP_REGADDR_AREG   0x00000000
+#define NCMAP_REGADDR_ALO    0x00000000
+#define NCMAP_REGADDR_AHI    0x00000010
+#define NCMAP_REGADDR_PBUF   0x00000020
+#define NCMAP_REGADDR_CREG   0x00000030
+#define NCMAP_REGADDR_SREG   0x00000040
+#define NCMAP_REGADDR_RREG   0x00000060
+#define NCMAP_PROTOCOL       (0x00008000 | 0x00040000 | 0x00800000)
+
+static inline void newport_cmap_setaddr(struct newport_regs *regs,
+					unsigned short addr)
+{
+	regs->set.dcbmode = (NPORT_DMODE_ACMALL | NCMAP_PROTOCOL |
+			   NPORT_DMODE_SENDIAN | NPORT_DMODE_ECINC |
+			   NCMAP_REGADDR_AREG | NPORT_DMODE_W2);
+	regs->set.dcbdata0.hwords.s1 = addr;
+	regs->set.dcbmode = (NPORT_DMODE_ACMALL | NCMAP_PROTOCOL |
+			   NCMAP_REGADDR_PBUF | NPORT_DMODE_W3);
+}
+
+static inline void newport_cmap_setrgb(struct newport_regs *regs,
+				       unsigned char red,
+				       unsigned char green,
+				       unsigned char blue)
+{
+	regs->set.dcbdata0.all =
+		(red << 24) |
+		(green << 16) |
+		(blue << 8);
+}
+
+/* Miscellaneous NEWPORT routines. */
+#define BUSY_TIMEOUT 100000
+static inline int newport_wait(void)
+{
+	int i = 0;
+
+	while(i < BUSY_TIMEOUT)
+		if(!(npregs->cset.stat & NPORT_STAT_GBUSY))
+			break;
+	if(i == BUSY_TIMEOUT)
+		return 1;
+	return 0;
+}
+
+static inline int newport_bfwait(void)
+{
+	int i = 0;
+
+	while(i < BUSY_TIMEOUT)
+		if(!(npregs->cset.stat & NPORT_STAT_BBUSY))
+			break;
+	if(i == BUSY_TIMEOUT)
+		return 1;
+	return 0;
+}
+
+/* newport.c and cons_newport.c routines */
+extern struct graphics_ops *newport_probe (int, const char **);
+
+void newport_save    (void *);
+void newport_restore (void *);
+void newport_reset   (void);
+int  newport_ioctl   (int card, int cmd, unsigned long arg);
+
+/*
+ * DCBMODE register defines:
+ */
+
+/* Widht of the data being transfered for each DCBDATA[01] word */
+#define DCB_DATAWIDTH_4 0x0
+#define DCB_DATAWIDTH_1 0x1
+#define DCB_DATAWIDTH_2 0x2
+#define DCB_DATAWIDTH_3 0x3
+
+/* If set, all of DCBDATA will be moved, otherwise only DATAWIDTH bytes */
+#define DCB_ENDATAPACK   (1 << 2)
+
+/* Enables DCBCRS auto increment after each DCB transfer */
+#define DCB_ENCRSINC     (1 << 3)
+
+/* shift for accessing the control register select address (DBCCRS, 3 bits) */
+#define DCB_CRS_SHIFT    4
+
+/* DCBADDR (4 bits): display bus slave address */
+#define DCB_ADDR_SHIFT   7
+#define DCB_VC2          (0 <<  DCB_ADDR_SHIFT)
+#define DCB_CMAP_ALL     (1 <<  DCB_ADDR_SHIFT)
+#define DCB_CMAP0        (2 <<  DCB_ADDR_SHIFT)
+#define DCB_CMAP1        (3 <<  DCB_ADDR_SHIFT)
+#define DCB_XMAP_ALL     (4 <<  DCB_ADDR_SHIFT)
+#define DCB_XMAP0        (5 <<  DCB_ADDR_SHIFT)
+#define DCB_XMAP1        (6 <<  DCB_ADDR_SHIFT)
+#define DCB_BT445        (7 <<  DCB_ADDR_SHIFT)
+#define DCB_VCC1         (8 <<  DCB_ADDR_SHIFT)
+#define DCB_VAB1         (9 <<  DCB_ADDR_SHIFT)
+#define DCB_LG3_BDVERS0  (10 << DCB_ADDR_SHIFT)
+#define DCB_LG3_ICS1562  (11 << DCB_ADDR_SHIFT)
+#define DCB_RESERVED     (15 << DCB_ADDR_SHIFT)
+
+/* DCB protocol ack types */
+#define DCB_ENSYNCACK    (1 << 11)
+#define DCB_ENASYNCACK   (1 << 12)
+
+#define DCB_CSWIDTH_SHIFT 13
+#define DCB_CSHOLD_SHIFT  18
+#define DCB_CSSETUP_SHIFT 23
+
+/* XMAP9 specific defines */
+/*   XMAP9 -- registers as seen on the DCBMODE register*/
+#   define XM9_CRS_CONFIG            (0 << DCB_CRS_SHIFT)
+#       define XM9_PUPMODE           (1 << 0)
+#       define XM9_ODD_PIXEL         (1 << 1)
+#       define XM9_8_BITPLANES       (1 << 2)
+#       define XM9_SLOW_DCB          (1 << 3)
+#       define XM9_VIDEO_RGBMAP_MASK (3 << 4)
+#       define XM9_EXPRESS_VIDEO     (1 << 6)
+#       define XM9_VIDEO_OPTION      (1 << 7)
+#   define XM9_CRS_REVISION          (1 << DCB_CRS_SHIFT)
+#   define XM9_CRS_FIFO_AVAIL        (2 << DCB_CRS_SHIFT)
+#       define XM9_FIFO_0_AVAIL      0
+#       define XM9_FIFO_1_AVAIL      1
+#       define XM9_FIFO_2_AVAIL      3
+#       define XM9_FIFO_3_AVAIL      2
+#       define XM9_FIFO_FULL         XM9_FIFO_0_AVAIL
+#       define XM9_FIFO_EMPTY        XM9_FIFO_3_AVAIL
+#   define XM9_CRS_CURS_CMAP_MSB     (3 << DCB_CRS_SHIFT)
+#   define XM9_CRS_PUP_CMAP_MSB      (4 << DCB_CRS_SHIFT)
+#   define XM9_CRS_MODE_REG_DATA     (5 << DCB_CRS_SHIFT)
+#   define XM9_CRS_MODE_REG_INDEX    (7 << DCB_CRS_SHIFT)
+
+
+#define DCB_CYCLES(setup,hold,width)                \
+                  ((hold << DCB_CSHOLD_SHIFT)  |    \
+		   (setup << DCB_CSSETUP_SHIFT)|    \
+		   (width << DCB_CSWIDTH_SHIFT))
+
+#define W_DCB_XMAP9_PROTOCOL       DCB_CYCLES (2, 1, 0)
+#define WSLOW_DCB_XMAP9_PROTOCOL   DCB_CYCLES (5, 5, 0)
+#define WAYSLOW_DCB_XMAP9_PROTOCOL DCB_CYCLES (12, 12, 0)
+#define R_DCB_XMAP9_PROTOCOL       DCB_CYCLES (2, 1, 3)
+
+static inline void
+xmap9FIFOWait (struct newport_regs *rex)
+{
+        rex->set.dcbmode = DCB_XMAP0 | XM9_CRS_FIFO_AVAIL |
+		DCB_DATAWIDTH_1 | R_DCB_XMAP9_PROTOCOL;
+        newport_bfwait ();
+	
+        while ((rex->set.dcbdata0.bytes.b3 & 3) != XM9_FIFO_EMPTY)
+		;
+}
+
+static inline void
+xmap9SetModeReg (struct newport_regs *rex, unsigned int modereg, unsigned int data24, int cfreq)
+{
+        if (cfreq > 119)
+            rex->set.dcbmode = DCB_XMAP_ALL | XM9_CRS_MODE_REG_DATA |
+                        DCB_DATAWIDTH_4 | W_DCB_XMAP9_PROTOCOL;
+        else if (cfreq > 59)
+            rex->set.dcbmode = DCB_XMAP_ALL | XM9_CRS_MODE_REG_DATA |
+		    DCB_DATAWIDTH_4 | WSLOW_DCB_XMAP9_PROTOCOL;    
+        else
+            rex->set.dcbmode = DCB_XMAP_ALL | XM9_CRS_MODE_REG_DATA |
+                        DCB_DATAWIDTH_4 | WAYSLOW_DCB_XMAP9_PROTOCOL; 
+        rex->set.dcbdata0.all = ((modereg) << 24) | (data24 & 0xffffff);
+}
+
+#endif /* !(_SGI_NEWPORT_H) */
+
diff -u --recursive --new-file v2.1.72/linux/drivers/sgi/char/rrm.c linux/drivers/sgi/char/rrm.c
--- v2.1.72/linux/drivers/sgi/char/rrm.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sgi/char/rrm.c	Wed Dec 10 10:31:11 1997
@@ -0,0 +1,69 @@
+/*
+ * Linux Rendering Resource Manager 
+ *
+ *          Implements the SGI-compatible rendering resource manager.
+ *          This takes care of implementing the virtualized video hardware
+ *          access required for OpenGL direct rendering.
+ *
+ * Author:  Miguel de Icaza (miguel@nuclecu.unam.mx)
+ *
+ * Fixes:
+ */
+#include <asm/uaccess.h>
+#include <asm/rrm.h>
+
+int
+rrm_open_rn (int rnid, void *arg)
+{
+	return 0;
+}
+
+int
+rrm_close_rn (int rnid, void *arg)
+{
+	return 0;
+}
+
+int
+rrm_bind_proc_to_rn (int rnid, void *arg)
+{
+	return 0;
+}
+
+typedef int (*rrm_function )(void *arg);
+
+struct {
+	int (*r_fn)(int rnid, void *arg);
+	int arg_size;
+} rrm_functions [] = {
+	{ rrm_open_rn,         sizeof (struct RRM_OpenRN) },
+	{ rrm_close_rn,        sizeof (struct RRM_CloseRN) },
+	{ rrm_bind_proc_to_rn, sizeof (struct RRM_BindProcToRN) }
+};
+
+#define RRM_FUNCTIONS (sizeof (rrm_functions)/sizeof (rrm_functions [0]))
+
+/* cmd is a number in the range [0..RRM_CMD_LIMIT-RRM_BASE] */
+int
+rrm_command (unsigned int cmd, void *arg)
+{
+	int i, rnid;
+	
+	if (cmd > RRM_FUNCTIONS){
+		printk ("Called unimplemented rrm ioctl: %d\n", cmd + RRM_BASE);
+		return -EINVAL;
+	}
+	i = verify_area (VERIFY_READ, arg, rrm_functions [cmd].arg_size);
+	if (i) return i;
+
+	__get_user_ret (rnid, (int *) arg, -EFAULT);
+	return (*(rrm_functions [cmd].r_fn))(rnid, arg);
+}
+
+int
+rrm_close (struct inode *inode, struct file *file)
+{
+	/* This routine is invoked when the device is closed */
+	return 0;
+}
+
diff -u --recursive --new-file v2.1.72/linux/drivers/sgi/char/sgicons.c linux/drivers/sgi/char/sgicons.c
--- v2.1.72/linux/drivers/sgi/char/sgicons.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sgi/char/sgicons.c	Wed Dec 10 10:31:11 1997
@@ -0,0 +1,183 @@
+/*
+ * sgicons.c: Setting up and registering console I/O on the SGI.
+ *
+ * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ * Copyright (C) 1997 Miguel de Icaza (miguel@nuclecu.unam.mx)
+ *
+ * This implement a virtual console interface.
+ *
+ * This should be replaced with Gert's all-singing all-dancing
+ * graphics console code in the future
+ *
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <asm/uaccess.h>
+#include "gconsole.h"
+
+/* To make psaux code cleaner */
+int aux_device_present = 0xaa;
+
+/* This is the system graphics console (the first adapter found) */
+struct console_ops *gconsole = 0;
+struct console_ops *real_gconsole = 0;
+
+void
+enable_gconsole (void)
+{
+	if (!gconsole)
+		gconsole = real_gconsole;
+}
+
+void
+disable_gconsole (void)
+{
+	if (gconsole){
+		real_gconsole = gconsole;
+		gconsole = 0;
+	}
+}
+
+void
+register_gconsole (struct console_ops *gc)
+{
+	if (gconsole)
+		return;
+	gconsole = gc;
+}
+
+void
+__set_origin (unsigned short offset)
+{
+	if (gconsole)
+		(*gconsole->set_origin)(offset);
+}
+
+void
+hide_cursor (void)
+{
+
+	if (gconsole)
+		(*gconsole->hide_cursor)();
+}
+
+void
+set_cursor (int currcons)
+{
+	if (gconsole)
+		(*gconsole->set_cursor)(currcons);
+}
+
+void
+get_scrmem (int currcons)
+{
+	if (gconsole)
+		(*gconsole->get_scrmem)(currcons);
+}
+
+void
+set_scrmem (int currcons, long offset)
+{
+	if (gconsole)
+		(*gconsole->set_scrmem)(currcons, offset);
+}
+
+int
+set_get_cmap (unsigned char *arg, int set)
+{
+	if (gconsole)
+		return (*gconsole->set_get_cmap)(arg, set);
+	return 0;
+}
+
+void
+blitc (unsigned short charattr, unsigned long addr)
+{
+	if (gconsole)
+		(*gconsole->blitc)(charattr, addr);
+}
+
+void
+memsetw (void *s, unsigned short c, unsigned int count)
+{
+	if (gconsole)
+		(*gconsole->memsetw)(s, c, count);
+}
+
+void
+memcpyw (unsigned short *to, unsigned short *from, unsigned int count)
+{
+	if (gconsole)
+		(*gconsole->memcpyw)(to, from, count);
+}
+
+int
+con_adjust_height (unsigned long fontheight)
+{
+	return -EINVAL;
+}
+
+int
+set_get_font (char *arg, int set, int ch512)
+{
+	int error, i, line;
+
+	if (!arg)
+		return -EINVAL;
+	error = verify_area (set ? VERIFY_READ : VERIFY_WRITE, (void *) arg,
+			     ch512 ? 2* cmapsz : cmapsz);
+	if (error)
+		return error;
+
+	/* download the current font */
+	if (!set) {
+		memset (arg, 0, cmapsz);
+		for (i = 0; i < 256; i++) {
+			for (line = 0; line < CHAR_HEIGHT; line++)
+				__put_user (vga_font [i], arg+(i*32+line));
+		}
+		return 0;
+	}
+	
+        /* set the font */
+	for (i = 0; i < 256; i++) {
+		for (line = 0; line < CHAR_HEIGHT; line++) {
+			__get_user(vga_font [i*CHAR_HEIGHT + line],
+			           arg + (i * 32 + line));
+		}
+	}
+	return 0;
+}
+
+/*
+ * dummy routines for the VESA blanking code, which is VGA only,
+ * so we don't have to carry that stuff around for the Sparc...  */
+void vesa_blank(void) { }
+void vesa_unblank(void) { }
+void set_vesa_blanking(const unsigned long arg) { }
+void vesa_powerdown(void) { }
+void set_palette (void) { }
+
+extern unsigned long video_mem_base, video_screen_size, video_mem_term;
+
+__initfunc(unsigned long con_type_init(unsigned long start_mem, const char **name))
+{
+	extern int serial_console;
+
+	if (serial_console)
+		*name = "NONE";
+	else {
+		gfx_init (name);
+		printk("Video screen size is %08lx at %08lx\n",
+		       video_screen_size, start_mem);
+		video_mem_base = start_mem;
+		start_mem += (video_screen_size * 2);
+		video_mem_term = start_mem;
+	}
+	return start_mem;
+}
+
+__initfunc(void con_type_init_finish(void))
+{
+}
diff -u --recursive --new-file v2.1.72/linux/drivers/sgi/char/sgiserial.c linux/drivers/sgi/char/sgiserial.c
--- v2.1.72/linux/drivers/sgi/char/sgiserial.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sgi/char/sgiserial.c	Wed Dec 10 10:31:11 1997
@@ -0,0 +1,2019 @@
+/* sgiserial.c: Serial port driver for SGI machines.
+ *
+ * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ */
+
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/mm.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/sgialib.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <asm/sgihpc.h>
+#include <asm/sgint23.h>
+#include <asm/uaccess.h>
+
+#include "sgiserial.h"
+
+#define NUM_SERIAL 1     /* One chip on board. */
+#define NUM_CHANNELS (NUM_SERIAL * 2)
+
+extern struct wait_queue * keypress_wait;
+
+struct sgi_zslayout *zs_chips[NUM_SERIAL] = { 0, };
+struct sgi_zschannel *zs_channels[NUM_CHANNELS] = { 0, 0, };
+struct sgi_zschannel *zs_conschan;
+struct sgi_zschannel *zs_kgdbchan;
+int zs_nodes[NUM_SERIAL] = { 0, };
+
+struct sgi_serial zs_soft[NUM_CHANNELS];
+struct sgi_serial *zs_chain;  /* IRQ servicing chain */
+static int zilog_irq = 21;
+
+struct tty_struct zs_ttys[NUM_CHANNELS];
+/** struct tty_struct *zs_constty; **/
+
+/* Console hooks... */
+static int zs_cons_chanout = 0;
+static int zs_cons_chanin = 0;
+struct sgi_serial *zs_consinfo = 0;
+
+static unsigned char kgdb_regs[16] = {
+	0, 0, 0,                     /* write 0, 1, 2 */
+	(Rx8 | RxENABLE),            /* write 3 */
+	(X16CLK | SB1 | PAR_EVEN),   /* write 4 */
+	(Tx8 | TxENAB),              /* write 5 */
+	0, 0, 0,                     /* write 6, 7, 8 */
+	(NV),                        /* write 9 */
+	(NRZ),                       /* write 10 */
+	(TCBR | RCBR),               /* write 11 */
+	0, 0,                        /* BRG time constant, write 12 + 13 */
+	(BRENABL),                   /* write 14 */
+	(DCDIE)                      /* write 15 */
+};
+
+#define ZS_CLOCK         3672000   /* Zilog input clock rate */
+
+DECLARE_TASK_QUEUE(tq_serial);
+
+struct tty_driver serial_driver, callout_driver;
+static int serial_refcount;
+
+/* serial subtype definitions */
+#define SERIAL_TYPE_NORMAL	1
+#define SERIAL_TYPE_CALLOUT	2
+  
+/* number of characters left in xmit buffer before we ask for more */
+#define WAKEUP_CHARS 256
+
+/* Debugging... DEBUG_INTR is bad to use when one of the zs
+ * lines is your console ;(
+ */
+#undef SERIAL_DEBUG_INTR
+#undef SERIAL_DEBUG_OPEN
+#undef SERIAL_DEBUG_FLOW
+
+#define RS_STROBE_TIME 10
+#define RS_ISR_PASS_LIMIT 256
+
+#define _INLINE_ inline
+
+static void change_speed(struct sgi_serial *info);
+
+static struct tty_struct *serial_table[NUM_CHANNELS];
+static struct termios *serial_termios[NUM_CHANNELS];
+static struct termios *serial_termios_locked[NUM_CHANNELS];
+
+#ifndef MIN
+#define MIN(a,b)	((a) < (b) ? (a) : (b))
+#endif
+
+/*
+ * tmp_buf is used as a temporary buffer by serial_write.  We need to
+ * lock it in case the memcpy_fromfs blocks while swapping in a page,
+ * and some other program tries to do a serial write at the same time.
+ * Since the lock will only come under contention when the system is
+ * swapping and available memory is low, it makes sense to share one
+ * buffer across all the serial ports, since it significantly saves
+ * memory if large numbers of serial ports are open.
+ */
+static unsigned char tmp_buf[4096]; /* This is cheating */
+static struct semaphore tmp_buf_sem = MUTEX;
+
+static inline int serial_paranoia_check(struct sgi_serial *info,
+					dev_t device, const char *routine)
+{
+#ifdef SERIAL_PARANOIA_CHECK
+	static const char *badmagic =
+		"Warning: bad magic number for serial struct (%d, %d) in %s\n";
+	static const char *badinfo =
+		"Warning: null sun_serial for (%d, %d) in %s\n";
+
+	if (!info) {
+		printk(badinfo, MAJOR(device), MINOR(device), routine);
+		return 1;
+	}
+	if (info->magic != SERIAL_MAGIC) {
+		printk(badmagic, MAJOR(device), MINOR(device), routine);
+		return 1;
+	}
+#endif
+	return 0;
+}
+
+/*
+ * This is used to figure out the divisor speeds and the timeouts
+ */
+static int baud_table[] = {
+	0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
+	9600, 19200, 38400, 57600, 115200, 0 };
+
+/* 
+ * Reading and writing Zilog8530 registers.  The delays are to make this
+ * driver work on the Sun4 which needs a settling delay after each chip
+ * register access, other machines handle this in hardware via auxiliary
+ * flip-flops which implement the settle time we do in software.
+ */
+static inline unsigned char read_zsreg(struct sgi_zschannel *channel, unsigned char reg)
+{
+	unsigned char retval;
+	volatile unsigned char junk;
+
+	udelay(2);
+	channel->control = reg;
+	junk = ioc_icontrol->istat0;
+	udelay(1);
+	retval = channel->control;
+	return retval;
+}
+
+static inline void write_zsreg(struct sgi_zschannel *channel, unsigned char reg, unsigned char value)
+{
+	volatile unsigned char junk;
+
+	udelay(2);
+	channel->control = reg;
+	junk = ioc_icontrol->istat0;
+	udelay(1);
+	channel->control = value;
+	junk = ioc_icontrol->istat0;
+	return;
+}
+
+static inline void load_zsregs(struct sgi_zschannel *channel, unsigned char *regs)
+{
+	ZS_CLEARERR(channel);
+	ZS_CLEARFIFO(channel);
+	/* Load 'em up */
+	write_zsreg(channel, R4, regs[R4]);
+	write_zsreg(channel, R10, regs[R10]);
+	write_zsreg(channel, R3, regs[R3] & ~RxENABLE);
+	write_zsreg(channel, R5, regs[R5] & ~TxENAB);
+	write_zsreg(channel, R1, regs[R1]);
+	write_zsreg(channel, R9, regs[R9]);
+	write_zsreg(channel, R11, regs[R11]);
+	write_zsreg(channel, R12, regs[R12]);
+	write_zsreg(channel, R13, regs[R13]);
+	write_zsreg(channel, R14, regs[R14]);
+	write_zsreg(channel, R15, regs[R15]);
+	write_zsreg(channel, R3, regs[R3]);
+	write_zsreg(channel, R5, regs[R5]);
+	return;
+}
+
+/* Sets or clears DTR/RTS on the requested line */
+static inline void zs_rtsdtr(struct sgi_serial *ss, int set)
+{
+	if(set) {
+		ss->curregs[5] |= (RTS | DTR);
+		ss->pendregs[5] = ss->curregs[5];
+		write_zsreg(ss->zs_channel, 5, ss->curregs[5]);
+	} else {
+		ss->curregs[5] &= ~(RTS | DTR);
+		ss->pendregs[5] = ss->curregs[5];
+		write_zsreg(ss->zs_channel, 5, ss->curregs[5]);
+	}
+	return;
+}
+
+static inline void kgdb_chaninit(struct sgi_serial *ss, int intson, int bps)
+{
+	int brg;
+
+	if(intson) {
+		kgdb_regs[R1] = INT_ALL_Rx;
+		kgdb_regs[R9] |= MIE;
+	} else {
+		kgdb_regs[R1] = 0;
+		kgdb_regs[R9] &= ~MIE;
+	}
+	brg = BPS_TO_BRG(bps, ZS_CLOCK/16);
+	kgdb_regs[R12] = (brg & 255);
+	kgdb_regs[R13] = ((brg >> 8) & 255);
+	load_zsregs(ss->zs_channel, kgdb_regs);
+}
+
+/* Utility routines for the Zilog */
+static inline int get_zsbaud(struct sgi_serial *ss)
+{
+	struct sgi_zschannel *channel = ss->zs_channel;
+	int brg;
+
+	/* The baud rate is split up between two 8-bit registers in
+	 * what is termed 'BRG time constant' format in my docs for
+	 * the chip, it is a function of the clk rate the chip is
+	 * receiving which happens to be constant.
+	 */
+	brg = ((read_zsreg(channel, 13)&0xff) << 8);
+	brg |= (read_zsreg(channel, 12)&0xff);
+	return BRG_TO_BPS(brg, (ZS_CLOCK/(ss->clk_divisor)));
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_stop() and rs_start()
+ *
+ * This routines are called before setting or resetting tty->stopped.
+ * They enable or disable transmitter interrupts, as necessary.
+ * ------------------------------------------------------------
+ */
+static void rs_stop(struct tty_struct *tty)
+{
+	struct sgi_serial *info = (struct sgi_serial *)tty->driver_data;
+	unsigned long flags;
+
+	if (serial_paranoia_check(info, tty->device, "rs_stop"))
+		return;
+	
+	save_flags(flags); cli();
+	if (info->curregs[5] & TxENAB) {
+		info->curregs[5] &= ~TxENAB;
+		info->pendregs[5] &= ~TxENAB;
+		write_zsreg(info->zs_channel, 5, info->curregs[5]);
+	}
+	restore_flags(flags);
+}
+
+static void rs_start(struct tty_struct *tty)
+{
+	struct sgi_serial *info = (struct sgi_serial *)tty->driver_data;
+	unsigned long flags;
+	
+	if (serial_paranoia_check(info, tty->device, "rs_start"))
+		return;
+	
+	save_flags(flags); cli();
+	if (info->xmit_cnt && info->xmit_buf && !(info->curregs[5] & TxENAB)) {
+		info->curregs[5] |= TxENAB;
+		info->pendregs[5] = info->curregs[5];
+		write_zsreg(info->zs_channel, 5, info->curregs[5]);
+	}
+	restore_flags(flags);
+}
+
+/* Drop into either the boot monitor or kadb upon receiving a break
+ * from keyboard/console input.
+ */
+static void batten_down_hatches(void)
+{
+	prom_imode();
+#if 0
+	/* If we are doing kadb, we call the debugger
+	 * else we just drop into the boot monitor.
+	 * Note that we must flush the user windows
+	 * first before giving up control.
+	 */
+	printk("\n");
+	if((((unsigned long)linux_dbvec)>=DEBUG_FIRSTVADDR) &&
+	   (((unsigned long)linux_dbvec)<=DEBUG_LASTVADDR))
+		sp_enter_debugger();
+	else
+		prom_halt();
+
+	/* XXX We want to notify the keyboard driver that all
+	 * XXX keys are in the up state or else weird things
+	 * XXX happen...
+	 */
+#endif
+	return;
+}
+
+/* On receive, this clears errors and the receiver interrupts */
+static inline void rs_recv_clear(struct sgi_zschannel *zsc)
+{
+	volatile unsigned char junk;
+
+	udelay(2);
+	zsc->control = ERR_RES;
+	junk = ioc_icontrol->istat0;
+	udelay(2);
+	zsc->control = RES_H_IUS;
+	junk = ioc_icontrol->istat0;
+}
+
+/*
+ * ----------------------------------------------------------------------
+ *
+ * Here starts the interrupt handling routines.  All of the following
+ * subroutines are declared as inline and are folded into
+ * rs_interrupt().  They were separated out for readability's sake.
+ *
+ * Note: rs_interrupt() is a "fast" interrupt, which means that it
+ * runs with interrupts turned off.  People who may want to modify
+ * rs_interrupt() should try to keep the interrupt handler as fast as
+ * possible.  After you are done making modifications, it is not a bad
+ * idea to do:
+ * 
+ * gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer serial.c
+ *
+ * and look at the resulting assemble code in serial.s.
+ *
+ * 				- Ted Ts'o (tytso@mit.edu), 7-Mar-93
+ * -----------------------------------------------------------------------
+ */
+
+/*
+ * This routine is used by the interrupt handler to schedule
+ * processing in the software interrupt portion of the driver.
+ */
+static _INLINE_ void rs_sched_event(struct sgi_serial *info,
+				    int event)
+{
+	info->event |= 1 << event;
+	queue_task(&info->tqueue, &tq_serial);
+	mark_bh(SERIAL_BH);
+}
+
+#ifdef CONFIG_REMOTE_DEBUG
+extern void set_async_breakpoint(unsigned int epc);
+#endif
+
+static _INLINE_ void receive_chars(struct sgi_serial *info, struct pt_regs *regs)
+{
+	struct tty_struct *tty = info->tty;
+	volatile unsigned char junk;
+	unsigned char ch, stat;
+
+	udelay(2);
+	ch = info->zs_channel->data;
+	junk = ioc_icontrol->istat0;
+	udelay(2);
+	stat = read_zsreg(info->zs_channel, R1);
+
+	/* If this is the console keyboard, we need to handle
+	 * L1-A's here.
+	 */
+	if(info->is_cons) {
+		if(ch==0) { /* whee, break received */
+			batten_down_hatches();
+			rs_recv_clear(info->zs_channel);
+			return;
+		} else if (ch == 1) {
+			show_state();
+			return;
+		} else if (ch == 2) {
+			show_buffers();
+			return;
+		}
+		/* It is a 'keyboard interrupt' ;-) */
+		wake_up(&keypress_wait);
+	}
+	/* Look for kgdb 'stop' character, consult the gdb documentation
+	 * for remote target debugging and arch/sparc/kernel/sparc-stub.c
+	 * to see how all this works.
+	 */
+#ifdef CONFIG_REMOTE_DEBUG
+	if((info->kgdb_channel) && (ch =='\003')) {
+		set_async_breakpoint(read_32bit_cp0_register(CP0_EPC));
+		goto clear_and_exit;
+	}
+#endif
+	if(!tty)
+		goto clear_and_exit;
+
+	if (tty->flip.count >= TTY_FLIPBUF_SIZE)
+		queue_task(&tty->flip.tqueue, &tq_timer);
+	tty->flip.count++;
+	if(stat & PAR_ERR)
+		*tty->flip.flag_buf_ptr++ = TTY_PARITY;
+	else if(stat & Rx_OVR)
+		*tty->flip.flag_buf_ptr++ = TTY_OVERRUN;
+	else if(stat & CRC_ERR)
+		*tty->flip.flag_buf_ptr++ = TTY_FRAME;
+	else
+		*tty->flip.flag_buf_ptr++ = 0; /* XXX */
+	*tty->flip.char_buf_ptr++ = ch;
+
+	queue_task(&tty->flip.tqueue, &tq_timer);
+
+clear_and_exit:
+	rs_recv_clear(info->zs_channel);
+	return;
+}
+
+static _INLINE_ void transmit_chars(struct sgi_serial *info)
+{
+	volatile unsigned char junk;
+
+	/* P3: In theory we have to test readiness here because a
+	 * serial console can clog the chip through rs_put_char().
+	 * David did not do this. I think he relies on 3-chars FIFO in 8530.
+	 * Let's watch for lost _output_ characters. XXX
+	 */
+
+	/* SGI ADDENDUM: On most SGI machines, the Zilog does possess
+	 *               a 16 or 17 byte fifo, so no worries. -dm
+	 */
+
+	if (info->x_char) {
+		/* Send next char */
+		udelay(2);
+		info->zs_channel->data = info->x_char;
+		junk = ioc_icontrol->istat0;
+
+		info->x_char = 0;
+		goto clear_and_return;
+	}
+
+	if((info->xmit_cnt <= 0) || info->tty->stopped) {
+		/* That's peculiar... */
+		udelay(2);
+		info->zs_channel->control = RES_Tx_P;
+		junk = ioc_icontrol->istat0;
+		goto clear_and_return;
+	}
+
+	/* Send char */
+	udelay(2);
+	info->zs_channel->data = info->xmit_buf[info->xmit_tail++];
+	junk = ioc_icontrol->istat0;
+
+	info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1);
+	info->xmit_cnt--;
+
+	if (info->xmit_cnt < WAKEUP_CHARS)
+		rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
+
+	if(info->xmit_cnt <= 0) {
+		udelay(2);
+		info->zs_channel->control = RES_Tx_P;
+		junk = ioc_icontrol->istat0;
+		goto clear_and_return;
+	}
+
+clear_and_return:
+	/* Clear interrupt */
+	udelay(2);
+	info->zs_channel->control = RES_H_IUS;
+	junk = ioc_icontrol->istat0;
+	return;
+}
+
+static _INLINE_ void status_handle(struct sgi_serial *info)
+{
+	volatile unsigned char junk;
+	unsigned char status;
+
+	/* Get status from Read Register 0 */
+	udelay(2);
+	status = info->zs_channel->control;
+	junk = ioc_icontrol->istat0;
+	/* Clear status condition... */
+	udelay(2);
+	info->zs_channel->control = RES_EXT_INT;
+	junk = ioc_icontrol->istat0;
+	/* Clear the interrupt */
+	udelay(2);
+	info->zs_channel->control = RES_H_IUS;
+	junk = ioc_icontrol->istat0;
+
+#if 0
+	if(status & DCD) {
+		if((info->tty->termios->c_cflag & CRTSCTS) &&
+		   ((info->curregs[3] & AUTO_ENAB)==0)) {
+			info->curregs[3] |= AUTO_ENAB;
+			info->pendregs[3] |= AUTO_ENAB;
+			write_zsreg(info->zs_channel, 3, info->curregs[3]);
+		}
+	} else {
+		if((info->curregs[3] & AUTO_ENAB)) {
+			info->curregs[3] &= ~AUTO_ENAB;
+			info->pendregs[3] &= ~AUTO_ENAB;
+			write_zsreg(info->zs_channel, 3, info->curregs[3]);
+		}
+	}
+#endif
+	/* Whee, if this is console input and this is a
+	 * 'break asserted' status change interrupt, call
+	 * the boot prom.
+	 */
+	if((status & BRK_ABRT) && info->break_abort)
+		batten_down_hatches();
+
+	/* XXX Whee, put in a buffer somewhere, the status information
+	 * XXX whee whee whee... Where does the information go...
+	 */
+	return;
+}
+
+/*
+ * This is the serial driver's generic interrupt routine
+ */
+void rs_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+{
+	struct sgi_serial * info = (struct sgi_serial *) dev_id;
+	unsigned char zs_intreg;
+
+	zs_intreg = read_zsreg(info->zs_channel, 3);
+
+	/* NOTE: The read register 3, which holds the irq status,
+	 *       does so for both channels on each chip.  Although
+	 *       the status value itself must be read from the A
+	 *       channel and is only valid when read from channel A.
+	 *       Yes... broken hardware...
+	 */
+#define CHAN_A_IRQMASK (CHARxIP | CHATxIP | CHAEXT)
+#define CHAN_B_IRQMASK (CHBRxIP | CHBTxIP | CHBEXT)
+
+	/* *** Chip 1 *** */
+	/* Channel A -- /dev/ttya, could be the console */
+	if(zs_intreg & CHAN_A_IRQMASK) {
+		if (zs_intreg & CHARxIP)
+			receive_chars(info, regs);
+		if (zs_intreg & CHATxIP)
+			transmit_chars(info);
+		if (zs_intreg & CHAEXT)
+			status_handle(info);
+	}
+
+	info=info->zs_next;
+
+	/* Channel B -- /dev/ttyb, could be the console */
+	if(zs_intreg & CHAN_B_IRQMASK) {
+		if (zs_intreg & CHBRxIP)
+			receive_chars(info, regs);
+		if (zs_intreg & CHBTxIP)
+			transmit_chars(info);
+		if (zs_intreg & CHBEXT)
+			status_handle(info);
+	}
+}
+
+/*
+ * -------------------------------------------------------------------
+ * Here ends the serial interrupt routines.
+ * -------------------------------------------------------------------
+ */
+
+/*
+ * This routine is used to handle the "bottom half" processing for the
+ * serial driver, known also the "software interrupt" processing.
+ * This processing is done at the kernel interrupt level, after the
+ * rs_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON.  This
+ * is where time-consuming activities which can not be done in the
+ * interrupt driver proper are done; the interrupt driver schedules
+ * them using rs_sched_event(), and they get done here.
+ */
+static void do_serial_bh(void)
+{
+	run_task_queue(&tq_serial);
+}
+
+static void do_softint(void *private_)
+{
+	struct sgi_serial	*info = (struct sgi_serial *) private_;
+	struct tty_struct	*tty;
+	
+	tty = info->tty;
+	if (!tty)
+		return;
+
+	if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) {
+		if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+		    tty->ldisc.write_wakeup)
+			(tty->ldisc.write_wakeup)(tty);
+		wake_up_interruptible(&tty->write_wait);
+	}
+}
+
+/*
+ * This routine is called from the scheduler tqueue when the interrupt
+ * routine has signalled that a hangup has occurred.  The path of
+ * hangup processing is:
+ *
+ * 	serial interrupt routine -> (scheduler tqueue) ->
+ * 	do_serial_hangup() -> tty->hangup() -> rs_hangup()
+ * 
+ */
+static void do_serial_hangup(void *private_)
+{
+	struct sgi_serial	*info = (struct sgi_serial *) private_;
+	struct tty_struct	*tty;
+	
+	tty = info->tty;
+	if (!tty)
+		return;
+
+	tty_hangup(tty);
+}
+
+
+/*
+ * This subroutine is called when the RS_TIMER goes off.  It is used
+ * by the serial driver to handle ports that do not have an interrupt
+ * (irq=0).  This doesn't work at all for 16450's, as a sun has a Z8530.
+ */
+ 
+static void rs_timer(void)
+{
+	printk("rs_timer called\n");
+	prom_halt();
+	return;
+}
+
+static int startup(struct sgi_serial * info)
+{
+	volatile unsigned char junk;
+	unsigned long flags;
+
+	if (info->flags & ZILOG_INITIALIZED)
+		return 0;
+
+	if (!info->xmit_buf) {
+		info->xmit_buf = (unsigned char *) get_free_page(GFP_KERNEL);
+		if (!info->xmit_buf)
+			return -ENOMEM;
+	}
+
+	save_flags(flags); cli();
+
+#ifdef SERIAL_DEBUG_OPEN
+	printk("starting up ttys%d (irq %d)...", info->line, info->irq);
+#endif
+
+	/*
+	 * Clear the FIFO buffers and disable them
+	 * (they will be reenabled in change_speed())
+	 */
+	ZS_CLEARFIFO(info->zs_channel);
+	info->xmit_fifo_size = 1;
+
+	/*
+	 * Clear the interrupt registers.
+	 */
+	udelay(2);
+	info->zs_channel->control = ERR_RES;
+	junk = ioc_icontrol->istat0;
+	udelay(2);
+	info->zs_channel->control = RES_H_IUS;
+	junk = ioc_icontrol->istat0;
+
+	/*
+	 * Now, initialize the Zilog
+	 */
+	zs_rtsdtr(info, 1);
+
+	/*
+	 * Finally, enable sequencing and interrupts
+	 */
+	info->curregs[1] |= (info->curregs[1] & ~0x18) | (EXT_INT_ENAB|INT_ALL_Rx);
+	info->pendregs[1] = info->curregs[1];
+	info->curregs[3] |= (RxENABLE | Rx8);
+	info->pendregs[3] = info->curregs[3];
+	/* We enable Tx interrupts as needed. */
+	info->curregs[5] |= (TxENAB | Tx8);
+	info->pendregs[5] = info->curregs[5];
+	info->curregs[9] |= (NV | MIE);
+	info->pendregs[9] = info->curregs[9];
+	write_zsreg(info->zs_channel, 3, info->curregs[3]);
+	write_zsreg(info->zs_channel, 5, info->curregs[5]);
+	write_zsreg(info->zs_channel, 9, info->curregs[9]);
+	
+	/*
+	 * And clear the interrupt registers again for luck.
+	 */
+	udelay(2);
+	info->zs_channel->control = ERR_RES;
+	junk = ioc_icontrol->istat0;
+	udelay(2);
+	info->zs_channel->control = RES_H_IUS;
+	junk = ioc_icontrol->istat0;
+
+	if (info->tty)
+		clear_bit(TTY_IO_ERROR, &info->tty->flags);
+	info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+
+	/*
+	 * Set up serial timers...
+	 */
+#if 0  /* Works well and stops the machine. */
+	timer_table[RS_TIMER].expires = jiffies + 2;
+	timer_active |= 1 << RS_TIMER;
+#endif
+
+	/*
+	 * and set the speed of the serial port
+	 */
+	change_speed(info);
+
+	info->flags |= ZILOG_INITIALIZED;
+	restore_flags(flags);
+	return 0;
+}
+
+/*
+ * This routine will shutdown a serial port; interrupts are disabled, and
+ * DTR is dropped if the hangup on close termio flag is on.
+ */
+static void shutdown(struct sgi_serial * info)
+{
+	unsigned long	flags;
+
+	if (!(info->flags & ZILOG_INITIALIZED))
+		return;
+
+#ifdef SERIAL_DEBUG_OPEN
+	printk("Shutting down serial port %d (irq %d)....", info->line,
+	       info->irq);
+#endif
+	
+	save_flags(flags); cli(); /* Disable interrupts */
+	
+	if (info->xmit_buf) {
+		free_page((unsigned long) info->xmit_buf);
+		info->xmit_buf = 0;
+	}
+
+	if (info->tty)
+		set_bit(TTY_IO_ERROR, &info->tty->flags);
+	
+	info->flags &= ~ZILOG_INITIALIZED;
+	restore_flags(flags);
+}
+
+/*
+ * This routine is called to set the UART divisor registers to match
+ * the specified baud rate for a serial port.
+ */
+static void change_speed(struct sgi_serial *info)
+{
+	unsigned short port;
+	unsigned cflag;
+	int	i;
+	int	brg;
+
+	if (!info->tty || !info->tty->termios)
+		return;
+	cflag = info->tty->termios->c_cflag;
+	if (!(port = info->port))
+		return;
+	i = cflag & CBAUD;
+	if (i & CBAUDEX) {
+		/* XXX CBAUDEX is not obeyed.
+		 * It is impossible at a 32bits SPARC.
+		 * But we have to report this to user ... someday.
+		 */
+		i = B9600;
+	}
+	if (i == 0) {
+		/* XXX B0, hangup the line. */
+		do_serial_hangup(info);
+	} else if (baud_table[i]) {
+		info->zs_baud = baud_table[i];
+		info->clk_divisor = 16;
+
+		info->curregs[4] = X16CLK;
+		info->curregs[11] = TCBR | RCBR;
+		brg = BPS_TO_BRG(info->zs_baud, ZS_CLOCK/info->clk_divisor);
+		info->curregs[12] = (brg & 255);
+		info->curregs[13] = ((brg >> 8) & 255);
+		info->curregs[14] = BRENABL;
+	}
+
+	/* byte size and parity */
+	switch (cflag & CSIZE) {
+	case CS5:
+		info->curregs[3] &= ~(0xc0);
+		info->curregs[3] |= Rx5;
+		info->pendregs[3] = info->curregs[3];
+		info->curregs[5] &= ~(0xe0);
+		info->curregs[5] |= Tx5;
+		info->pendregs[5] = info->curregs[5];
+		break;
+	case CS6:
+		info->curregs[3] &= ~(0xc0);
+		info->curregs[3] |= Rx6;
+		info->pendregs[3] = info->curregs[3];
+		info->curregs[5] &= ~(0xe0);
+		info->curregs[5] |= Tx6;
+		info->pendregs[5] = info->curregs[5];
+		break;
+	case CS7:
+		info->curregs[3] &= ~(0xc0);
+		info->curregs[3] |= Rx7;
+		info->pendregs[3] = info->curregs[3];
+		info->curregs[5] &= ~(0xe0);
+		info->curregs[5] |= Tx7;
+		info->pendregs[5] = info->curregs[5];
+		break;
+	case CS8:
+	default: /* defaults to 8 bits */
+		info->curregs[3] &= ~(0xc0);
+		info->curregs[3] |= Rx8;
+		info->pendregs[3] = info->curregs[3];
+		info->curregs[5] &= ~(0xe0);
+		info->curregs[5] |= Tx8;
+		info->pendregs[5] = info->curregs[5];
+		break;
+	}
+	info->curregs[4] &= ~(0x0c);
+	if (cflag & CSTOPB) {
+		info->curregs[4] |= SB2;
+	} else {
+		info->curregs[4] |= SB1;
+	}
+	info->pendregs[4] = info->curregs[4];
+	if (cflag & PARENB) {
+		info->curregs[4] |= PAR_ENA;
+		info->pendregs[4] |= PAR_ENA;
+	} else {
+		info->curregs[4] &= ~PAR_ENA;
+		info->pendregs[4] &= ~PAR_ENA;
+	}
+	if (!(cflag & PARODD)) {
+		info->curregs[4] |= PAR_EVEN;
+		info->pendregs[4] |= PAR_EVEN;
+	} else {
+		info->curregs[4] &= ~PAR_EVEN;
+		info->pendregs[4] &= ~PAR_EVEN;
+	}
+
+	/* Load up the new values */
+	load_zsregs(info->zs_channel, info->curregs);
+
+	return;
+}
+
+/* This is for console output over ttya/ttyb */
+static void rs_put_char(char ch)
+{
+	struct sgi_zschannel *chan = zs_conschan;
+	volatile unsigned char junk;
+	int flags, loops = 0;
+
+	save_flags(flags); cli();
+	while(((junk = chan->control) & Tx_BUF_EMP)==0 && loops < 10000) {
+		loops++;
+		udelay(2);
+	}
+
+	udelay(2);
+	chan->data = ch;
+	junk = ioc_icontrol->istat0;
+	restore_flags(flags);
+}
+
+/* These are for receiving and sending characters under the kgdb
+ * source level kernel debugger.
+ */
+void putDebugChar(char kgdb_char)
+{
+	struct sgi_zschannel *chan = zs_kgdbchan;
+	volatile unsigned char junk;
+	unsigned long flags;
+
+	save_flags(flags); cli();
+	udelay(2);
+	while((chan->control & Tx_BUF_EMP)==0)
+		udelay(2);
+
+	udelay(2);
+	chan->data = kgdb_char;
+	junk = ioc_icontrol->istat0;
+	restore_flags(flags);
+}
+
+char getDebugChar(void)
+{
+	struct sgi_zschannel *chan = zs_kgdbchan;
+	unsigned char junk;
+
+	while((chan->control & Rx_CH_AV)==0)
+		udelay(2);
+
+	junk = ioc_icontrol->istat0;
+	udelay(2);
+	return chan->data;
+}
+
+/*
+ * Fair output driver allows a process to speak.
+ */
+static void rs_fair_output(void)
+{
+	int left;		/* Output no more than that */
+	unsigned long flags;
+	struct sgi_serial *info = zs_consinfo;
+	volatile unsigned char junk;
+	char c;
+
+	if (info == 0) return;
+	if (info->xmit_buf == 0) return;
+
+	save_flags(flags);  cli();
+	left = info->xmit_cnt;
+	while (left != 0) {
+		c = info->xmit_buf[info->xmit_tail];
+		info->xmit_tail = (info->xmit_tail+1) & (SERIAL_XMIT_SIZE-1);
+		info->xmit_cnt--;
+		restore_flags(flags);
+
+		rs_put_char(c);
+
+		save_flags(flags);  cli();
+		left = MIN(info->xmit_cnt, left-1);
+	}
+
+	/* Last character is being transmitted now (hopefully). */
+	udelay(2);
+	zs_conschan->control = RES_Tx_P;
+	junk = ioc_icontrol->istat0;
+
+	restore_flags(flags);
+	return;
+}
+
+/*
+ * zs_console_print is registered for printk.
+ */
+static void zs_console_print(const char *p)
+{
+	char c;
+
+	while((c=*(p++)) != 0) {
+		if(c == '\n')
+			rs_put_char('\r');
+		rs_put_char(c);
+	}
+
+	/* Comment this if you want to have a strict interrupt-driven output */
+	rs_fair_output();
+}
+
+static void rs_flush_chars(struct tty_struct *tty)
+{
+	struct sgi_serial *info = (struct sgi_serial *)tty->driver_data;
+	unsigned long flags;
+
+	if (serial_paranoia_check(info, tty->device, "rs_flush_chars"))
+		return;
+
+	if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
+	    !info->xmit_buf)
+		return;
+
+	/* Enable transmitter */
+	save_flags(flags); cli();
+	info->curregs[1] |= TxINT_ENAB|EXT_INT_ENAB;
+	info->pendregs[1] |= TxINT_ENAB|EXT_INT_ENAB;
+	write_zsreg(info->zs_channel, 1, info->curregs[1]);
+	info->curregs[5] |= TxENAB;
+	info->pendregs[5] |= TxENAB;
+	write_zsreg(info->zs_channel, 5, info->curregs[5]);
+
+	/*
+	 * Send a first (bootstrapping) character. A best solution is
+	 * to call transmit_chars() here which handles output in a
+	 * generic way. Current transmit_chars() not only transmits,
+	 * but resets interrupts also what we do not desire here.
+	 * XXX Discuss with David.
+	 */
+	if (info->zs_channel->control & Tx_BUF_EMP) {
+		volatile unsigned char junk;
+
+		/* Send char */
+		udelay(2);
+		info->zs_channel->data = info->xmit_buf[info->xmit_tail++];
+		junk = ioc_icontrol->istat0;
+		info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1);
+		info->xmit_cnt--;
+	}
+	restore_flags(flags);
+}
+
+static int rs_write(struct tty_struct * tty, int from_user,
+		    const unsigned char *buf, int count)
+{
+	int	c, total = 0;
+	struct sgi_serial *info = (struct sgi_serial *)tty->driver_data;
+	unsigned long flags;
+
+	if (serial_paranoia_check(info, tty->device, "rs_write"))
+		return 0;
+
+	if (!tty || !info->xmit_buf)
+		return 0;
+
+	save_flags(flags);
+	while (1) {
+		cli();		
+		c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+				   SERIAL_XMIT_SIZE - info->xmit_head));
+		if (c <= 0)
+			break;
+
+		if (from_user) {
+			down(&tmp_buf_sem);
+			copy_from_user(tmp_buf, buf, c);
+			c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+				       SERIAL_XMIT_SIZE - info->xmit_head));
+			memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c);
+			up(&tmp_buf_sem);
+		} else
+			memcpy(info->xmit_buf + info->xmit_head, buf, c);
+		info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
+		info->xmit_cnt += c;
+		restore_flags(flags);
+		buf += c;
+		count -= c;
+		total += c;
+	}
+	if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped &&
+	    !(info->curregs[5] & TxENAB)) {
+		/* Enable transmitter */
+		info->curregs[1] |= TxINT_ENAB|EXT_INT_ENAB;
+		info->pendregs[1] |= TxINT_ENAB|EXT_INT_ENAB;
+		write_zsreg(info->zs_channel, 1, info->curregs[1]);
+		info->curregs[5] |= TxENAB;
+		info->pendregs[5] |= TxENAB;
+		write_zsreg(info->zs_channel, 5, info->curregs[5]);
+	}
+	restore_flags(flags);
+	return total;
+}
+
+static int rs_write_room(struct tty_struct *tty)
+{
+	struct sgi_serial *info = (struct sgi_serial *)tty->driver_data;
+	int	ret;
+				
+	if (serial_paranoia_check(info, tty->device, "rs_write_room"))
+		return 0;
+	ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
+	if (ret < 0)
+		ret = 0;
+	return ret;
+}
+
+static int rs_chars_in_buffer(struct tty_struct *tty)
+{
+	struct sgi_serial *info = (struct sgi_serial *)tty->driver_data;
+				
+	if (serial_paranoia_check(info, tty->device, "rs_chars_in_buffer"))
+		return 0;
+	return info->xmit_cnt;
+}
+
+static void rs_flush_buffer(struct tty_struct *tty)
+{
+	struct sgi_serial *info = (struct sgi_serial *)tty->driver_data;
+				
+	if (serial_paranoia_check(info, tty->device, "rs_flush_buffer"))
+		return;
+	cli();
+	info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+	sti();
+	wake_up_interruptible(&tty->write_wait);
+	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+	    tty->ldisc.write_wakeup)
+		(tty->ldisc.write_wakeup)(tty);
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_throttle()
+ * 
+ * This routine is called by the upper-layer tty layer to signal that
+ * incoming characters should be throttled.
+ * ------------------------------------------------------------
+ */
+static void rs_throttle(struct tty_struct * tty)
+{
+	struct sgi_serial *info = (struct sgi_serial *)tty->driver_data;
+#ifdef SERIAL_DEBUG_THROTTLE
+	char	buf[64];
+	
+	printk("throttle %s: %d....\n", _tty_name(tty, buf),
+	       tty->ldisc.chars_in_buffer(tty));
+#endif
+
+	if (serial_paranoia_check(info, tty->device, "rs_throttle"))
+		return;
+	
+	if (I_IXOFF(tty))
+		info->x_char = STOP_CHAR(tty);
+
+	/* Turn off RTS line */
+	cli();
+	info->curregs[5] &= ~RTS;
+	info->pendregs[5] &= ~RTS;
+	write_zsreg(info->zs_channel, 5, info->curregs[5]);
+	sti();
+}
+
+static void rs_unthrottle(struct tty_struct * tty)
+{
+	struct sgi_serial *info = (struct sgi_serial *)tty->driver_data;
+#ifdef SERIAL_DEBUG_THROTTLE
+	char	buf[64];
+	
+	printk("unthrottle %s: %d....\n", _tty_name(tty, buf),
+	       tty->ldisc.chars_in_buffer(tty));
+#endif
+
+	if (serial_paranoia_check(info, tty->device, "rs_unthrottle"))
+		return;
+	
+	if (I_IXOFF(tty)) {
+		if (info->x_char)
+			info->x_char = 0;
+		else
+			info->x_char = START_CHAR(tty);
+	}
+
+	/* Assert RTS line */
+	cli();
+	info->curregs[5] |= RTS;
+	info->pendregs[5] |= RTS;
+	write_zsreg(info->zs_channel, 5, info->curregs[5]);
+	sti();
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_ioctl() and friends
+ * ------------------------------------------------------------
+ */
+
+static int get_serial_info(struct sgi_serial * info,
+			   struct serial_struct * retinfo)
+{
+	struct serial_struct tmp;
+  
+	if (!retinfo)
+		return -EFAULT;
+	memset(&tmp, 0, sizeof(tmp));
+	tmp.type = info->type;
+	tmp.line = info->line;
+	tmp.port = info->port;
+	tmp.irq = info->irq;
+	tmp.flags = info->flags;
+	tmp.baud_base = info->baud_base;
+	tmp.close_delay = info->close_delay;
+	tmp.closing_wait = info->closing_wait;
+	tmp.custom_divisor = info->custom_divisor;
+	return copy_to_user(retinfo,&tmp,sizeof(*retinfo));
+}
+
+static int set_serial_info(struct sgi_serial * info,
+			   struct serial_struct * new_info)
+{
+	struct serial_struct new_serial;
+	struct sgi_serial old_info;
+	int 			retval = 0;
+
+	if (!new_info)
+		return -EFAULT;
+	copy_from_user(&new_serial,new_info,sizeof(new_serial));
+	old_info = *info;
+
+	if (!suser()) {
+		if ((new_serial.baud_base != info->baud_base) ||
+		    (new_serial.type != info->type) ||
+		    (new_serial.close_delay != info->close_delay) ||
+		    ((new_serial.flags & ~ZILOG_USR_MASK) !=
+		     (info->flags & ~ZILOG_USR_MASK)))
+			return -EPERM;
+		info->flags = ((info->flags & ~ZILOG_USR_MASK) |
+			       (new_serial.flags & ZILOG_USR_MASK));
+		info->custom_divisor = new_serial.custom_divisor;
+		goto check_and_exit;
+	}
+
+	if (info->count > 1)
+		return -EBUSY;
+
+	/*
+	 * OK, past this point, all the error checking has been done.
+	 * At this point, we start making changes.....
+	 */
+
+	info->baud_base = new_serial.baud_base;
+	info->flags = ((info->flags & ~ZILOG_FLAGS) |
+			(new_serial.flags & ZILOG_FLAGS));
+	info->type = new_serial.type;
+	info->close_delay = new_serial.close_delay;
+	info->closing_wait = new_serial.closing_wait;
+
+check_and_exit:
+	retval = startup(info);
+	return retval;
+}
+
+/*
+ * get_lsr_info - get line status register info
+ *
+ * Purpose: Let user call ioctl() to get info when the UART physically
+ * 	    is emptied.  On bus types like RS485, the transmitter must
+ * 	    release the bus after transmitting. This must be done when
+ * 	    the transmit shift register is empty, not be done when the
+ * 	    transmit holding register is empty.  This functionality
+ * 	    allows an RS485 driver to be written in user space. 
+ */
+static int get_lsr_info(struct sgi_serial * info, unsigned int *value)
+{
+	volatile unsigned char junk;
+	unsigned char status;
+
+	cli();
+	udelay(2);
+	status = info->zs_channel->control;
+	junk = ioc_icontrol->istat0;
+	sti();
+	return put_user(status,value);
+}
+
+/*
+ * This routine sends a break character out the serial port.
+ */
+static void send_break(	struct sgi_serial * info, int duration)
+{
+	if (!info->port)
+		return;
+	current->state = TASK_INTERRUPTIBLE;
+	current->timeout = jiffies + duration;
+	cli();
+	write_zsreg(info->zs_channel, 5, (info->curregs[5] | SND_BRK));
+	schedule();
+	write_zsreg(info->zs_channel, 5, info->curregs[5]);
+	sti();
+}
+
+static int rs_ioctl(struct tty_struct *tty, struct file * file,
+		    unsigned int cmd, unsigned long arg)
+{
+	int error;
+	struct sgi_serial * info = (struct sgi_serial *)tty->driver_data;
+	int retval;
+
+	if (serial_paranoia_check(info, tty->device, "rs_ioctl"))
+		return -ENODEV;
+
+	if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
+	    (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD)  &&
+	    (cmd != TIOCSERSWILD) && (cmd != TIOCSERGSTRUCT)) {
+		if (tty->flags & (1 << TTY_IO_ERROR))
+		    return -EIO;
+	}
+	
+	switch (cmd) {
+		case TCSBRK:	/* SVID version: non-zero arg --> no break */
+			retval = tty_check_change(tty);
+			if (retval)
+				return retval;
+			tty_wait_until_sent(tty, 0);
+			if (!arg)
+				send_break(info, HZ/4);	/* 1/4 second */
+			return 0;
+		case TCSBRKP:	/* support for POSIX tcsendbreak() */
+			retval = tty_check_change(tty);
+			if (retval)
+				return retval;
+			tty_wait_until_sent(tty, 0);
+			send_break(info, arg ? arg*(HZ/10) : HZ/4);
+			return 0;
+		case TIOCGSOFTCAR:
+			error = verify_area(VERIFY_WRITE, (void *) arg,sizeof(long));
+			if (error)
+				return error;
+			put_user(C_CLOCAL(tty) ? 1 : 0,
+			         (unsigned long *) arg);
+			return 0;
+		case TIOCSSOFTCAR:
+			error = get_user(arg, (unsigned long *)arg);
+			if (error)
+				return error;
+			tty->termios->c_cflag =
+				((tty->termios->c_cflag & ~CLOCAL) |
+				 (arg ? CLOCAL : 0));
+			return 0;
+		case TIOCGSERIAL:
+			error = verify_area(VERIFY_WRITE, (void *) arg,
+						sizeof(struct serial_struct));
+			if (error)
+				return error;
+			return get_serial_info(info,
+					       (struct serial_struct *) arg);
+		case TIOCSSERIAL:
+			return set_serial_info(info,
+					       (struct serial_struct *) arg);
+		case TIOCSERGETLSR: /* Get line status register */
+			error = verify_area(VERIFY_WRITE, (void *) arg,
+				sizeof(unsigned int));
+			if (error)
+				return error;
+			else
+			    return get_lsr_info(info, (unsigned int *) arg);
+
+		case TIOCSERGSTRUCT:
+			error = verify_area(VERIFY_WRITE, (void *) arg,
+						sizeof(struct sgi_serial));
+			if (error)
+				return error;
+			copy_to_user((struct sun_serial *) arg,
+				    info, sizeof(struct sgi_serial));
+			return 0;
+			
+		default:
+			return -ENOIOCTLCMD;
+		}
+	return 0;
+}
+
+static void rs_set_termios(struct tty_struct *tty, struct termios *old_termios)
+{
+	struct sgi_serial *info = (struct sgi_serial *)tty->driver_data;
+
+	if (tty->termios->c_cflag == old_termios->c_cflag)
+		return;
+
+	change_speed(info);
+
+	if ((old_termios->c_cflag & CRTSCTS) &&
+	    !(tty->termios->c_cflag & CRTSCTS)) {
+		tty->hw_stopped = 0;
+		rs_start(tty);
+	}
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_close()
+ * 
+ * This routine is called when the serial port gets closed.  First, we
+ * wait for the last remaining data to be sent.  Then, we unlink its
+ * ZILOG structure from the interrupt chain if necessary, and we free
+ * that IRQ if nothing is left in the chain.
+ * ------------------------------------------------------------
+ */
+static void rs_close(struct tty_struct *tty, struct file * filp)
+{
+	struct sgi_serial * info = (struct sgi_serial *)tty->driver_data;
+	unsigned long flags;
+
+	if (!info || serial_paranoia_check(info, tty->device, "rs_close"))
+		return;
+	
+	save_flags(flags); cli();
+	
+	if (tty_hung_up_p(filp)) {
+		restore_flags(flags);
+		return;
+	}
+	
+#ifdef SERIAL_DEBUG_OPEN
+	printk("rs_close ttys%d, count = %d\n", info->line, info->count);
+#endif
+	if ((tty->count == 1) && (info->count != 1)) {
+		/*
+		 * Uh, oh.  tty->count is 1, which means that the tty
+		 * structure will be freed.  Info->count should always
+		 * be one in these conditions.  If it's greater than
+		 * one, we've got real problems, since it means the
+		 * serial port won't be shutdown.
+		 */
+		printk("rs_close: bad serial port count; tty->count is 1, "
+		       "info->count is %d\n", info->count);
+		info->count = 1;
+	}
+	if (--info->count < 0) {
+		printk("rs_close: bad serial port count for ttys%d: %d\n",
+		       info->line, info->count);
+		info->count = 0;
+	}
+	if (info->count) {
+		restore_flags(flags);
+		return;
+	}
+	info->flags |= ZILOG_CLOSING;
+	/*
+	 * Save the termios structure, since this port may have
+	 * separate termios for callout and dialin.
+	 */
+	if (info->flags & ZILOG_NORMAL_ACTIVE)
+		info->normal_termios = *tty->termios;
+	if (info->flags & ZILOG_CALLOUT_ACTIVE)
+		info->callout_termios = *tty->termios;
+	/*
+	 * Now we wait for the transmit buffer to clear; and we notify 
+	 * the line discipline to only process XON/XOFF characters.
+	 */
+	tty->closing = 1;
+	if (info->closing_wait != ZILOG_CLOSING_WAIT_NONE)
+		tty_wait_until_sent(tty, info->closing_wait);
+	/*
+	 * At this point we stop accepting input.  To do this, we
+	 * disable the receive line status interrupts, and tell the
+	 * interrupt driver to stop checking the data ready bit in the
+	 * line status register.
+	 */
+	/** if (!info->iscons) ... **/
+	info->curregs[3] &= ~RxENABLE;
+	info->pendregs[3] = info->curregs[3];
+	write_zsreg(info->zs_channel, 3, info->curregs[3]);
+	info->curregs[1] &= ~(0x18);
+	info->pendregs[1] = info->curregs[1];
+	write_zsreg(info->zs_channel, 1, info->curregs[1]);
+	ZS_CLEARFIFO(info->zs_channel);
+
+	shutdown(info);
+	if (tty->driver.flush_buffer)
+		tty->driver.flush_buffer(tty);
+	if (tty->ldisc.flush_buffer)
+		tty->ldisc.flush_buffer(tty);
+	tty->closing = 0;
+	info->event = 0;
+	info->tty = 0;
+	if (tty->ldisc.num != ldiscs[N_TTY].num) {
+		if (tty->ldisc.close)
+			(tty->ldisc.close)(tty);
+		tty->ldisc = ldiscs[N_TTY];
+		tty->termios->c_line = N_TTY;
+		if (tty->ldisc.open)
+			(tty->ldisc.open)(tty);
+	}
+	if (info->blocked_open) {
+		if (info->close_delay) {
+			current->state = TASK_INTERRUPTIBLE;
+			current->timeout = jiffies + info->close_delay;
+			schedule();
+		}
+		wake_up_interruptible(&info->open_wait);
+	}
+	info->flags &= ~(ZILOG_NORMAL_ACTIVE|ZILOG_CALLOUT_ACTIVE|
+			 ZILOG_CLOSING);
+	wake_up_interruptible(&info->close_wait);
+	restore_flags(flags);
+}
+
+/*
+ * rs_hangup() --- called by tty_hangup() when a hangup is signaled.
+ */
+void rs_hangup(struct tty_struct *tty)
+{
+	struct sgi_serial * info = (struct sgi_serial *)tty->driver_data;
+	
+	if (serial_paranoia_check(info, tty->device, "rs_hangup"))
+		return;
+	
+	rs_flush_buffer(tty);
+	shutdown(info);
+	info->event = 0;
+	info->count = 0;
+	info->flags &= ~(ZILOG_NORMAL_ACTIVE|ZILOG_CALLOUT_ACTIVE);
+	info->tty = 0;
+	wake_up_interruptible(&info->open_wait);
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_open() and friends
+ * ------------------------------------------------------------
+ */
+static int block_til_ready(struct tty_struct *tty, struct file * filp,
+			   struct sgi_serial *info)
+{
+	struct wait_queue wait = { current, NULL };
+	int		retval;
+	int		do_clocal = 0;
+
+	/*
+	 * If the device is in the middle of being closed, then block
+	 * until it's done, and then try again.
+	 */
+	if (info->flags & ZILOG_CLOSING) {
+		interruptible_sleep_on(&info->close_wait);
+#ifdef SERIAL_DO_RESTART
+		if (info->flags & ZILOG_HUP_NOTIFY)
+			return -EAGAIN;
+		else
+			return -ERESTARTSYS;
+#else
+		return -EAGAIN;
+#endif
+	}
+
+	/*
+	 * If this is a callout device, then just make sure the normal
+	 * device isn't being used.
+	 */
+	if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) {
+		if (info->flags & ZILOG_NORMAL_ACTIVE)
+			return -EBUSY;
+		if ((info->flags & ZILOG_CALLOUT_ACTIVE) &&
+		    (info->flags & ZILOG_SESSION_LOCKOUT) &&
+		    (info->session != current->session))
+		    return -EBUSY;
+		if ((info->flags & ZILOG_CALLOUT_ACTIVE) &&
+		    (info->flags & ZILOG_PGRP_LOCKOUT) &&
+		    (info->pgrp != current->pgrp))
+		    return -EBUSY;
+		info->flags |= ZILOG_CALLOUT_ACTIVE;
+		return 0;
+	}
+	
+	/*
+	 * If non-blocking mode is set, or the port is not enabled,
+	 * then make the check up front and then exit.
+	 */
+	if ((filp->f_flags & O_NONBLOCK) ||
+	    (tty->flags & (1 << TTY_IO_ERROR))) {
+		if (info->flags & ZILOG_CALLOUT_ACTIVE)
+			return -EBUSY;
+		info->flags |= ZILOG_NORMAL_ACTIVE;
+		return 0;
+	}
+
+	if (info->flags & ZILOG_CALLOUT_ACTIVE) {
+		if (info->normal_termios.c_cflag & CLOCAL)
+			do_clocal = 1;
+	} else {
+		if (tty->termios->c_cflag & CLOCAL)
+			do_clocal = 1;
+	}
+	
+	/*
+	 * Block waiting for the carrier detect and the line to become
+	 * free (i.e., not in use by the callout).  While we are in
+	 * this loop, info->count is dropped by one, so that
+	 * rs_close() knows when to free things.  We restore it upon
+	 * exit, either normal or abnormal.
+	 */
+	retval = 0;
+	add_wait_queue(&info->open_wait, &wait);
+#ifdef SERIAL_DEBUG_OPEN
+	printk("block_til_ready before block: ttys%d, count = %d\n",
+	       info->line, info->count);
+#endif
+	info->count--;
+	info->blocked_open++;
+	while (1) {
+		cli();
+		if (!(info->flags & ZILOG_CALLOUT_ACTIVE))
+			zs_rtsdtr(info, 1);
+		sti();
+		current->state = TASK_INTERRUPTIBLE;
+		if (tty_hung_up_p(filp) ||
+		    !(info->flags & ZILOG_INITIALIZED)) {
+#ifdef SERIAL_DO_RESTART
+			if (info->flags & ZILOG_HUP_NOTIFY)
+				retval = -EAGAIN;
+			else
+				retval = -ERESTARTSYS;	
+#else
+			retval = -EAGAIN;
+#endif
+			break;
+		}
+		if (!(info->flags & ZILOG_CALLOUT_ACTIVE) &&
+		    !(info->flags & ZILOG_CLOSING) && do_clocal)
+			break;
+		if (current->signal & ~current->blocked) {
+			retval = -ERESTARTSYS;
+			break;
+		}
+#ifdef SERIAL_DEBUG_OPEN
+		printk("block_til_ready blocking: ttys%d, count = %d\n",
+		       info->line, info->count);
+#endif
+		schedule();
+	}
+	current->state = TASK_RUNNING;
+	remove_wait_queue(&info->open_wait, &wait);
+	if (!tty_hung_up_p(filp))
+		info->count++;
+	info->blocked_open--;
+#ifdef SERIAL_DEBUG_OPEN
+	printk("block_til_ready after blocking: ttys%d, count = %d\n",
+	       info->line, info->count);
+#endif
+	if (retval)
+		return retval;
+	info->flags |= ZILOG_NORMAL_ACTIVE;
+	return 0;
+}	
+
+/*
+ * This routine is called whenever a serial port is opened.  It
+ * enables interrupts for a serial port, linking in its ZILOG structure into
+ * the IRQ chain.   It also performs the serial-specific
+ * initialization for the tty structure.
+ */
+int rs_open(struct tty_struct *tty, struct file * filp)
+{
+	struct sgi_serial	*info;
+	int 			retval, line;
+
+	line = MINOR(tty->device) - tty->driver.minor_start;
+	/* The zilog lines for the mouse/keyboard must be
+	 * opened using their respective drivers.
+	 */
+	if ((line < 0) || (line >= NUM_CHANNELS))
+		return -ENODEV;
+	info = zs_soft + line;
+	/* Is the kgdb running over this line? */
+	if (info->kgdb_channel)
+		return -ENODEV;
+	if (serial_paranoia_check(info, tty->device, "rs_open"))
+		return -ENODEV;
+#ifdef SERIAL_DEBUG_OPEN
+	printk("rs_open %s%d, count = %d\n", tty->driver.name, info->line,
+	       info->count);
+#endif
+	info->count++;
+	tty->driver_data = info;
+	info->tty = tty;
+
+	/*
+	 * Start up serial port
+	 */
+	retval = startup(info);
+	if (retval)
+		return retval;
+
+	retval = block_til_ready(tty, filp, info);
+	if (retval) {
+#ifdef SERIAL_DEBUG_OPEN
+		printk("rs_open returning after block_til_ready with %d\n",
+		       retval);
+#endif
+		return retval;
+	}
+
+	if ((info->count == 1) && (info->flags & ZILOG_SPLIT_TERMIOS)) {
+		if (tty->driver.subtype == SERIAL_TYPE_NORMAL)
+			*tty->termios = info->normal_termios;
+		else 
+			*tty->termios = info->callout_termios;
+		change_speed(info);
+	}
+
+	info->session = current->session;
+	info->pgrp = current->pgrp;
+
+#ifdef SERIAL_DEBUG_OPEN
+	printk("rs_open ttys%d successful...", info->line);
+#endif
+	return 0;
+}
+
+/* Finally, routines used to initialize the serial driver. */
+
+static void show_serial_version(void)
+{
+	printk("SGI Zilog8530 serial driver version 1.00\n");
+}
+
+/* Return layout for the requested zs chip number. */
+static inline struct sgi_zslayout *get_zs(int chip)
+{
+	extern struct hpc3_miscregs *hpc3mregs;
+
+	if(chip > 0) {
+		prom_printf("Wheee, bogus zs chip number requested.\n");
+		prom_getchar();
+		romvec->imode();
+	}
+	return (struct sgi_zslayout *) (&hpc3mregs->ser1cmd);
+
+}
+
+extern void register_console(void (*proc)(const char *));
+
+static inline void
+rs_cons_check(struct sgi_serial *ss, int channel)
+{
+	int i, o, io;
+	static consout_registered = 0;
+	static msg_printed = 0;
+
+	i = o = io = 0;
+
+	/* Is this one of the serial console lines? */
+	if((zs_cons_chanout != channel) &&
+	   (zs_cons_chanin != channel))
+		return;
+	zs_conschan = ss->zs_channel;
+	zs_consinfo = ss;
+
+	/* Register the console output putchar, if necessary */
+	if((zs_cons_chanout == channel)) {
+		o = 1;
+		/* double whee.. */
+		if(!consout_registered) {
+			register_console(zs_console_print);
+			consout_registered = 1;
+		}
+	}
+
+	/* If this is console input, we handle the break received
+	 * status interrupt on this line to mean prom_halt().
+	 */
+	if(zs_cons_chanin == channel) {
+		ss->break_abort = 1;
+		i = 1;
+	}
+	if(o && i)
+		io = 1;
+	if(ss->zs_baud != 9562) { /* Don't ask... */
+		prom_printf("BAD console baud rate %d\n", ss->zs_baud);
+		prom_getchar();
+		prom_imode();
+		panic("Console baud rate weirdness");
+	}
+
+	/* Set flag variable for this port so that it cannot be
+	 * opened for other uses by accident.
+	 */
+	ss->is_cons = 1;
+
+	if(io) {
+		if(!msg_printed) {
+			printk("zs%d: console I/O\n", ((channel>>1)&1));
+			msg_printed = 1;
+		}
+	} else {
+		printk("zs%d: console %s\n", ((channel>>1)&1),
+		       (i==1 ? "input" : (o==1 ? "output" : "WEIRD")));
+	}
+}
+
+volatile int test_done;
+
+/* rs_init inits the driver */
+int rs_init(void)
+{
+	int chip, channel, i, flags;
+	struct sgi_serial *info;
+
+	/* Setup base handler, and timer table. */
+	init_bh(SERIAL_BH, do_serial_bh);
+	timer_table[RS_TIMER].fn = rs_timer;
+	timer_table[RS_TIMER].expires = 0;
+
+	show_serial_version();
+
+	/* Initialize the tty_driver structure */
+	/* SGI: Not all of this is exactly right for us. */
+	
+	memset(&serial_driver, 0, sizeof(struct tty_driver));
+	serial_driver.magic = TTY_DRIVER_MAGIC;
+	serial_driver.name = "ttyS";
+	serial_driver.major = TTY_MAJOR;
+	serial_driver.minor_start = 64;
+	serial_driver.num = NUM_CHANNELS;
+	serial_driver.type = TTY_DRIVER_TYPE_SERIAL;
+	serial_driver.subtype = SERIAL_TYPE_NORMAL;
+	serial_driver.init_termios = tty_std_termios;
+
+	serial_driver.init_termios.c_cflag =
+		B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+	serial_driver.flags = TTY_DRIVER_REAL_RAW;
+	serial_driver.refcount = &serial_refcount;
+	serial_driver.table = serial_table;
+	serial_driver.termios = serial_termios;
+	serial_driver.termios_locked = serial_termios_locked;
+
+	serial_driver.open = rs_open;
+	serial_driver.close = rs_close;
+	serial_driver.write = rs_write;
+	serial_driver.flush_chars = rs_flush_chars;
+	serial_driver.write_room = rs_write_room;
+	serial_driver.chars_in_buffer = rs_chars_in_buffer;
+	serial_driver.flush_buffer = rs_flush_buffer;
+	serial_driver.ioctl = rs_ioctl;
+	serial_driver.throttle = rs_throttle;
+	serial_driver.unthrottle = rs_unthrottle;
+	serial_driver.set_termios = rs_set_termios;
+	serial_driver.stop = rs_stop;
+	serial_driver.start = rs_start;
+	serial_driver.hangup = rs_hangup;
+
+	/*
+	 * The callout device is just like normal device except for
+	 * major number and the subtype code.
+	 */
+	callout_driver = serial_driver;
+	callout_driver.name = "cua";
+	callout_driver.major = TTYAUX_MAJOR;
+	callout_driver.subtype = SERIAL_TYPE_CALLOUT;
+
+	if (tty_register_driver(&serial_driver))
+		panic("Couldn't register serial driver\n");
+	if (tty_register_driver(&callout_driver))
+		panic("Couldn't register callout driver\n");
+	
+	save_flags(flags); cli();
+
+	/* Set up our interrupt linked list */
+	zs_chain = &zs_soft[0];
+	zs_soft[0].zs_next = &zs_soft[1];
+	zs_soft[1].zs_next = 0;
+
+	for(chip = 0; chip < NUM_SERIAL; chip++) {
+		/* If we are doing kgdb over one of the channels on
+		 * chip zero, kgdb_channel will be set to 1 by the
+		 * rs_kgdb_hook() routine below.
+		 */
+		if(!zs_chips[chip]) {
+			zs_chips[chip] = get_zs(chip);
+			/* Two channels per chip */
+			zs_channels[(chip*2)] = &zs_chips[chip]->channelA;
+			zs_channels[(chip*2)+1] = &zs_chips[chip]->channelB;
+			zs_soft[(chip*2)].kgdb_channel = 0;
+			zs_soft[(chip*2)+1].kgdb_channel = 0;
+		}
+		/* First, set up channel A on this chip. */
+		channel = chip * 2;
+		zs_soft[channel].zs_channel = zs_channels[channel];
+		zs_soft[channel].change_needed = 0;
+		zs_soft[channel].clk_divisor = 16;
+		zs_soft[channel].zs_baud = get_zsbaud(&zs_soft[channel]);
+		zs_soft[channel].cons_mouse = 0;
+		/* If not keyboard/mouse and is console serial
+		 * line, then enable receiver interrupts.
+		 */
+		if(zs_soft[channel].is_cons) {
+			write_zsreg(zs_soft[channel].zs_channel, R1,
+				    (EXT_INT_ENAB | INT_ALL_Rx));
+			write_zsreg(zs_soft[channel].zs_channel, R9, (NV | MIE));
+			write_zsreg(zs_soft[channel].zs_channel, R10, (NRZ));
+			write_zsreg(zs_soft[channel].zs_channel, R3, (Rx8|RxENABLE));
+			write_zsreg(zs_soft[channel].zs_channel, R5, (Tx8 | TxENAB));
+		}
+		/* If this is the kgdb line, enable interrupts because we
+		 * now want to receive the 'control-c' character from the
+		 * client attached to us asynchronously.
+		 */
+		if(zs_soft[channel].kgdb_channel)
+			kgdb_chaninit(&zs_soft[channel], 1,
+				      zs_soft[channel].zs_baud);
+
+		/* Now, channel B */
+		channel++;
+		zs_soft[channel].zs_channel = zs_channels[channel];
+		zs_soft[channel].change_needed = 0;
+		zs_soft[channel].clk_divisor = 16;
+		zs_soft[channel].zs_baud = get_zsbaud(&zs_soft[channel]);
+		zs_soft[channel].cons_keyb = 0;
+		/* If console serial line, then enable receiver interrupts. */
+		if(zs_soft[channel].is_cons) {
+			write_zsreg(zs_soft[channel].zs_channel, R1,
+				    (EXT_INT_ENAB | INT_ALL_Rx));
+			write_zsreg(zs_soft[channel].zs_channel, R9,
+				    (NV | MIE));
+			write_zsreg(zs_soft[channel].zs_channel, R10,
+				    (NRZ));
+			write_zsreg(zs_soft[channel].zs_channel, R3,
+				    (Rx8|RxENABLE));
+			write_zsreg(zs_soft[channel].zs_channel, R5,
+				    (Tx8 | TxENAB | RTS | DTR));
+		}
+	}
+
+	for(info=zs_chain, i=0; info; info = info->zs_next, i++)
+	{
+		info->magic = SERIAL_MAGIC;
+		info->port = (int) info->zs_channel;
+		info->line = i;
+		info->tty = 0;
+		info->irq = zilog_irq;
+		info->custom_divisor = 16;
+		info->close_delay = 50;
+		info->closing_wait = 3000;
+		info->x_char = 0;
+		info->event = 0;
+		info->count = 0;
+		info->blocked_open = 0;
+		info->tqueue.routine = do_softint;
+		info->tqueue.data = info;
+		info->tqueue_hangup.routine = do_serial_hangup;
+		info->tqueue_hangup.data = info;
+		info->callout_termios =callout_driver.init_termios;
+		info->normal_termios = serial_driver.init_termios;
+		info->open_wait = 0;
+		info->close_wait = 0;
+		printk("tty%02d at 0x%04x (irq = %d)", info->line, 
+		       info->port, info->irq);
+		printk(" is a Zilog8530\n");
+	}
+
+	if (request_irq(zilog_irq, rs_interrupt, (SA_INTERRUPT),
+			"Zilog8530", zs_chain))
+		panic("Unable to attach zs intr\n");
+	restore_flags(flags);
+
+	return 0;
+}
+
+/*
+ * register_serial and unregister_serial allows for serial ports to be
+ * configured at run-time, to support PCMCIA modems.
+ */
+/* SGI: Unused at this time, just here to make things link. */
+int register_serial(struct serial_struct *req)
+{
+	return -1;
+}
+
+void unregister_serial(int line)
+{
+	return;
+}
+
+/* Hooks for running a serial console.  con_init() calls this if the
+ * console is being run over one of the ttya/ttyb serial ports.
+ * 'chip' should be zero, as chip 1 drives the mouse/keyboard.
+ * 'channel' is decoded as 0=TTYA 1=TTYB, note that the channels
+ * are addressed backwards, channel B is first, then channel A.
+ */
+void
+rs_cons_hook(int chip, int out, int line)
+{
+	int channel;
+
+	if(chip)
+		panic("rs_cons_hook called with chip not zero");
+	if(line != 1 && line != 2)
+		panic("rs_cons_hook called with line not ttya or ttyb");
+	channel = line - 1;
+	if(!zs_chips[chip]) {
+		zs_chips[chip] = get_zs(chip);
+		/* Two channels per chip */
+		zs_channels[(chip*2)] = &zs_chips[chip]->channelA;
+		zs_channels[(chip*2)+1] = &zs_chips[chip]->channelB;
+	}
+	zs_soft[channel].zs_channel = zs_channels[channel];
+	zs_soft[channel].change_needed = 0;
+	zs_soft[channel].clk_divisor = 16;
+	zs_soft[channel].zs_baud = get_zsbaud(&zs_soft[channel]);
+	if(out)
+		zs_cons_chanout = ((chip * 2) + channel);
+	else
+		zs_cons_chanin = ((chip * 2) + channel);
+	rs_cons_check(&zs_soft[channel], channel);
+}
+
+/* This is called at boot time to prime the kgdb serial debugging
+ * serial line.  The 'tty_num' argument is 0 for /dev/ttyd2 and 1 for
+ * /dev/ttyd1 (yes they are backwards on purpose) which is determined
+ * in setup_arch() from the boot command line flags.
+ */
+void
+rs_kgdb_hook(int tty_num)
+{
+	int chip = 0;
+
+	if(!zs_chips[chip]) {
+		zs_chips[chip] = get_zs(chip);
+		/* Two channels per chip */
+		zs_channels[(chip*2)] = &zs_chips[chip]->channelA;
+		zs_channels[(chip*2)+1] = &zs_chips[chip]->channelB;
+	}
+	zs_soft[tty_num].zs_channel = zs_channels[tty_num];
+	zs_kgdbchan = zs_soft[tty_num].zs_channel;
+	zs_soft[tty_num].change_needed = 0;
+	zs_soft[tty_num].clk_divisor = 16;
+	zs_soft[tty_num].zs_baud = get_zsbaud(&zs_soft[tty_num]);
+	zs_soft[tty_num].kgdb_channel = 1;     /* This runs kgdb */
+	zs_soft[tty_num ^ 1].kgdb_channel = 0; /* This does not */
+
+	/* Turn on transmitter/receiver at 8-bits/char */
+	kgdb_chaninit(&zs_soft[tty_num], 0, 9600);
+	ZS_CLEARERR(zs_kgdbchan);
+	udelay(5);
+	ZS_CLEARFIFO(zs_kgdbchan);
+}
diff -u --recursive --new-file v2.1.72/linux/drivers/sgi/char/sgiserial.h linux/drivers/sgi/char/sgiserial.h
--- v2.1.72/linux/drivers/sgi/char/sgiserial.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sgi/char/sgiserial.h	Wed Dec 10 10:31:11 1997
@@ -0,0 +1,444 @@
+/* sgiserial.h: Definitions for the SGI Zilog85C30 serial driver.
+ *
+ * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ */
+#ifndef _SGI_SERIAL_H
+#define _SGI_SERIAL_H
+
+/* Just one channel */
+struct sgi_zschannel {
+#ifdef __MIPSEB__
+	volatile unsigned char unused0[3];
+	volatile unsigned char control;
+	volatile unsigned char unused1[3];
+	volatile unsigned char data;
+#else /* __MIPSEL__ */
+	volatile unsigned char control;
+	volatile unsigned char unused0[3];
+	volatile unsigned char data;
+	volatile unsigned char unused1[3];
+#endif
+};
+
+/* The address space layout for each zs chip.  Yes they are
+ * backwards.
+ */
+struct sgi_zslayout {
+	struct sgi_zschannel channelB;
+	struct sgi_zschannel channelA;
+};
+
+#define NUM_ZSREGS    16
+
+struct serial_struct {
+	int	type;
+	int	line;
+	int	port;
+	int	irq;
+	int	flags;
+	int	xmit_fifo_size;
+	int	custom_divisor;
+	int	baud_base;
+	unsigned short	close_delay;
+	char	reserved_char[2];
+	int	hub6;
+	unsigned short	closing_wait; /* time to wait before closing */
+	unsigned short	closing_wait2; /* no longer used... */
+	int	reserved[4];
+};
+
+/*
+ * For the close wait times, 0 means wait forever for serial port to
+ * flush its output.  65535 means don't wait at all.
+ */
+#define ZILOG_CLOSING_WAIT_INF	0
+#define ZILOG_CLOSING_WAIT_NONE	65535
+
+/*
+ * Definitions for ZILOG_struct (and serial_struct) flags field
+ */
+#define ZILOG_HUP_NOTIFY 0x0001 /* Notify getty on hangups and closes 
+				   on the callout port */
+#define ZILOG_FOURPORT  0x0002	/* Set OU1, OUT2 per AST Fourport settings */
+#define ZILOG_SAK	0x0004	/* Secure Attention Key (Orange book) */
+#define ZILOG_SPLIT_TERMIOS 0x0008 /* Separate termios for dialin/callout */
+
+#define ZILOG_SPD_MASK	0x0030
+#define ZILOG_SPD_HI	0x0010	/* Use 56000 instead of 38400 bps */
+
+#define ZILOG_SPD_VHI	0x0020  /* Use 115200 instead of 38400 bps */
+#define ZILOG_SPD_CUST	0x0030  /* Use user-specified divisor */
+
+#define ZILOG_SKIP_TEST	0x0040 /* Skip UART test during autoconfiguration */
+#define ZILOG_AUTO_IRQ  0x0080 /* Do automatic IRQ during autoconfiguration */
+#define ZILOG_SESSION_LOCKOUT 0x0100 /* Lock out cua opens based on session */
+#define ZILOG_PGRP_LOCKOUT    0x0200 /* Lock out cua opens based on pgrp */
+#define ZILOG_CALLOUT_NOHUP   0x0400 /* Don't do hangups for cua device */
+
+#define ZILOG_FLAGS	0x0FFF	/* Possible legal ZILOG flags */
+#define ZILOG_USR_MASK 0x0430	/* Legal flags that non-privileged
+				 * users can set or reset */
+
+/* Internal flags used only by kernel/chr_drv/serial.c */
+#define ZILOG_INITIALIZED	0x80000000 /* Serial port was initialized */
+#define ZILOG_CALLOUT_ACTIVE	0x40000000 /* Call out device is active */
+#define ZILOG_NORMAL_ACTIVE	0x20000000 /* Normal device is active */
+#define ZILOG_BOOT_AUTOCONF	0x10000000 /* Autoconfigure port on bootup */
+#define ZILOG_CLOSING		0x08000000 /* Serial port is closing */
+#define ZILOG_CTS_FLOW		0x04000000 /* Do CTS flow control */
+#define ZILOG_CHECK_CD		0x02000000 /* i.e., CLOCAL */
+
+/* Software state per channel */
+
+#ifdef __KERNEL__
+/*
+ * This is our internal structure for each serial port's state.
+ * 
+ * Many fields are paralleled by the structure used by the serial_struct
+ * structure.
+ *
+ * For definitions of the flags field, see tty.h
+ */
+
+struct sgi_serial {
+	struct sgi_serial *zs_next;       /* For IRQ servicing chain */
+	struct sgi_zschannel *zs_channel; /* Channel registers */
+	unsigned char read_reg_zero;
+
+	char soft_carrier;  /* Use soft carrier on this channel */
+	char cons_keyb;     /* Channel runs the keyboard */
+	char cons_mouse;    /* Channel runs the mouse */
+	char break_abort;   /* Is serial console in, so process brk/abrt */
+	char kgdb_channel;  /* Kgdb is running on this channel */
+	char is_cons;       /* Is this our console. */
+
+	/* We need to know the current clock divisor
+	 * to read the bps rate the chip has currently
+	 * loaded.
+	 */
+	unsigned char clk_divisor;  /* May be 1, 16, 32, or 64 */
+	int zs_baud;
+
+	/* Current write register values */
+	unsigned char curregs[NUM_ZSREGS];
+
+	/* Values we need to set next opportunity */
+	unsigned char pendregs[NUM_ZSREGS];
+
+	char change_needed;
+
+	int			magic;
+	int			baud_base;
+	int			port;
+	int			irq;
+	int			flags; 		/* defined in tty.h */
+	int			type; 		/* UART type */
+	struct tty_struct 	*tty;
+	int			read_status_mask;
+	int			ignore_status_mask;
+	int			timeout;
+	int			xmit_fifo_size;
+	int			custom_divisor;
+	int			x_char;	/* xon/xoff character */
+	int			close_delay;
+	unsigned short		closing_wait;
+	unsigned short		closing_wait2;
+	unsigned long		event;
+	unsigned long		last_active;
+	int			line;
+	int			count;	    /* # of fd on device */
+	int			blocked_open; /* # of blocked opens */
+	long			session; /* Session of opening process */
+	long			pgrp; /* pgrp of opening process */
+	unsigned char 		*xmit_buf;
+	int			xmit_head;
+	int			xmit_tail;
+	int			xmit_cnt;
+	struct tq_struct	tqueue;
+	struct tq_struct	tqueue_hangup;
+	struct termios		normal_termios;
+	struct termios		callout_termios;
+	struct wait_queue	*open_wait;
+	struct wait_queue	*close_wait;
+};
+
+
+#define SERIAL_MAGIC 0x5301
+
+/*
+ * The size of the serial xmit buffer is 1 page, or 4096 bytes
+ */
+#define SERIAL_XMIT_SIZE 4096
+
+/*
+ * Events are used to schedule things to happen at timer-interrupt
+ * time, instead of at rs interrupt time.
+ */
+#define RS_EVENT_WRITE_WAKEUP	0
+
+#endif /* __KERNEL__ */
+
+/* Conversion routines to/from brg time constants from/to bits
+ * per second.
+ */
+#define BRG_TO_BPS(brg, freq) ((freq) / 2 / ((brg) + 2))
+#define BPS_TO_BRG(bps, freq) ((((freq) + (bps)) / (2 * (bps))) - 2)
+
+/* The Zilog register set */
+
+#define	FLAG	0x7e
+
+/* Write Register 0 */
+#define	R0	0		/* Register selects */
+#define	R1	1
+#define	R2	2
+#define	R3	3
+#define	R4	4
+#define	R5	5
+#define	R6	6
+#define	R7	7
+#define	R8	8
+#define	R9	9
+#define	R10	10
+#define	R11	11
+#define	R12	12
+#define	R13	13
+#define	R14	14
+#define	R15	15
+
+#define	NULLCODE	0	/* Null Code */
+#define	POINT_HIGH	0x8	/* Select upper half of registers */
+#define	RES_EXT_INT	0x10	/* Reset Ext. Status Interrupts */
+#define	SEND_ABORT	0x18	/* HDLC Abort */
+#define	RES_RxINT_FC	0x20	/* Reset RxINT on First Character */
+#define	RES_Tx_P	0x28	/* Reset TxINT Pending */
+#define	ERR_RES		0x30	/* Error Reset */
+#define	RES_H_IUS	0x38	/* Reset highest IUS */
+
+#define	RES_Rx_CRC	0x40	/* Reset Rx CRC Checker */
+#define	RES_Tx_CRC	0x80	/* Reset Tx CRC Checker */
+#define	RES_EOM_L	0xC0	/* Reset EOM latch */
+
+/* Write Register 1 */
+
+#define	EXT_INT_ENAB	0x1	/* Ext Int Enable */
+#define	TxINT_ENAB	0x2	/* Tx Int Enable */
+#define	PAR_SPEC	0x4	/* Parity is special condition */
+
+#define	RxINT_DISAB	0	/* Rx Int Disable */
+#define	RxINT_FCERR	0x8	/* Rx Int on First Character Only or Error */
+#define	INT_ALL_Rx	0x10	/* Int on all Rx Characters or error */
+#define	INT_ERR_Rx	0x18	/* Int on error only */
+
+#define	WT_RDY_RT	0x20	/* Wait/Ready on R/T */
+#define	WT_FN_RDYFN	0x40	/* Wait/FN/Ready FN */
+#define	WT_RDY_ENAB	0x80	/* Wait/Ready Enable */
+
+/* Write Register #2 (Interrupt Vector) */
+
+/* Write Register 3 */
+
+#define	RxENABLE	0x1	/* Rx Enable */
+#define	SYNC_L_INH	0x2	/* Sync Character Load Inhibit */
+#define	ADD_SM		0x4	/* Address Search Mode (SDLC) */
+#define	RxCRC_ENAB	0x8	/* Rx CRC Enable */
+#define	ENT_HM		0x10	/* Enter Hunt Mode */
+#define	AUTO_ENAB	0x20	/* Auto Enables */
+#define	Rx5		0x0	/* Rx 5 Bits/Character */
+#define	Rx7		0x40	/* Rx 7 Bits/Character */
+#define	Rx6		0x80	/* Rx 6 Bits/Character */
+#define	Rx8		0xc0	/* Rx 8 Bits/Character */
+
+/* Write Register 4 */
+
+#define	PAR_ENA		0x1	/* Parity Enable */
+#define	PAR_EVEN	0x2	/* Parity Even/Odd* */
+
+#define	SYNC_ENAB	0	/* Sync Modes Enable */
+#define	SB1		0x4	/* 1 stop bit/char */
+#define	SB15		0x8	/* 1.5 stop bits/char */
+#define	SB2		0xc	/* 2 stop bits/char */
+
+#define	MONSYNC		0	/* 8 Bit Sync character */
+#define	BISYNC		0x10	/* 16 bit sync character */
+#define	SDLC		0x20	/* SDLC Mode (01111110 Sync Flag) */
+#define	EXTSYNC		0x30	/* External Sync Mode */
+
+#define	X1CLK		0x0	/* x1 clock mode */
+#define	X16CLK		0x40	/* x16 clock mode */
+#define	X32CLK		0x80	/* x32 clock mode */
+#define	X64CLK		0xC0	/* x64 clock mode */
+
+/* Write Register 5 */
+
+#define	TxCRC_ENAB	0x1	/* Tx CRC Enable */
+#define	RTS		0x2	/* RTS */
+#define	SDLC_CRC	0x4	/* SDLC/CRC-16 */
+#define	TxENAB		0x8	/* Tx Enable */
+#define	SND_BRK		0x10	/* Send Break */
+#define	Tx5		0x0	/* Tx 5 bits (or less)/character */
+#define	Tx7		0x20	/* Tx 7 bits/character */
+#define	Tx6		0x40	/* Tx 6 bits/character */
+#define	Tx8		0x60	/* Tx 8 bits/character */
+#define	DTR		0x80	/* DTR */
+
+/* Write Register 6 (Sync bits 0-7/SDLC Address Field) */
+
+/* Write Register 7 (Sync bits 8-15/SDLC 01111110) */
+
+/* Write Register 8 (transmit buffer) */
+
+/* Write Register 9 (Master interrupt control) */
+#define	VIS	1	/* Vector Includes Status */
+#define	NV	2	/* No Vector */
+#define	DLC	4	/* Disable Lower Chain */
+#define	MIE	8	/* Master Interrupt Enable */
+#define	STATHI	0x10	/* Status high */
+#define	NORESET	0	/* No reset on write to R9 */
+#define	CHRB	0x40	/* Reset channel B */
+#define	CHRA	0x80	/* Reset channel A */
+#define	FHWRES	0xc0	/* Force hardware reset */
+
+/* Write Register 10 (misc control bits) */
+#define	BIT6	1	/* 6 bit/8bit sync */
+#define	LOOPMODE 2	/* SDLC Loop mode */
+#define	ABUNDER	4	/* Abort/flag on SDLC xmit underrun */
+#define	MARKIDLE 8	/* Mark/flag on idle */
+#define	GAOP	0x10	/* Go active on poll */
+#define	NRZ	0	/* NRZ mode */
+#define	NRZI	0x20	/* NRZI mode */
+#define	FM1	0x40	/* FM1 (transition = 1) */
+#define	FM0	0x60	/* FM0 (transition = 0) */
+#define	CRCPS	0x80	/* CRC Preset I/O */
+
+/* Write Register 11 (Clock Mode control) */
+#define	TRxCXT	0	/* TRxC = Xtal output */
+#define	TRxCTC	1	/* TRxC = Transmit clock */
+#define	TRxCBR	2	/* TRxC = BR Generator Output */
+#define	TRxCDP	3	/* TRxC = DPLL output */
+#define	TRxCOI	4	/* TRxC O/I */
+#define	TCRTxCP	0	/* Transmit clock = RTxC pin */
+#define	TCTRxCP	8	/* Transmit clock = TRxC pin */
+#define	TCBR	0x10	/* Transmit clock = BR Generator output */
+#define	TCDPLL	0x18	/* Transmit clock = DPLL output */
+#define	RCRTxCP	0	/* Receive clock = RTxC pin */
+#define	RCTRxCP	0x20	/* Receive clock = TRxC pin */
+#define	RCBR	0x40	/* Receive clock = BR Generator output */
+#define	RCDPLL	0x60	/* Receive clock = DPLL output */
+#define	RTxCX	0x80	/* RTxC Xtal/No Xtal */
+
+/* Write Register 12 (lower byte of baud rate generator time constant) */
+
+/* Write Register 13 (upper byte of baud rate generator time constant) */
+
+/* Write Register 14 (Misc control bits) */
+#define	BRENABL	1	/* Baud rate generator enable */
+#define	BRSRC	2	/* Baud rate generator source */
+#define	DTRREQ	4	/* DTR/Request function */
+#define	AUTOECHO 8	/* Auto Echo */
+#define	LOOPBAK	0x10	/* Local loopback */
+#define	SEARCH	0x20	/* Enter search mode */
+#define	RMC	0x40	/* Reset missing clock */
+#define	DISDPLL	0x60	/* Disable DPLL */
+#define	SSBR	0x80	/* Set DPLL source = BR generator */
+#define	SSRTxC	0xa0	/* Set DPLL source = RTxC */
+#define	SFMM	0xc0	/* Set FM mode */
+#define	SNRZI	0xe0	/* Set NRZI mode */
+
+/* Write Register 15 (external/status interrupt control) */
+#define	ZCIE	2	/* Zero count IE */
+#define	DCDIE	8	/* DCD IE */
+#define	SYNCIE	0x10	/* Sync/hunt IE */
+#define	CTSIE	0x20	/* CTS IE */
+#define	TxUIE	0x40	/* Tx Underrun/EOM IE */
+#define	BRKIE	0x80	/* Break/Abort IE */
+
+
+/* Read Register 0 */
+#define	Rx_CH_AV	0x1	/* Rx Character Available */
+#define	ZCOUNT		0x2	/* Zero count */
+#define	Tx_BUF_EMP	0x4	/* Tx Buffer empty */
+#define	DCD		0x8	/* DCD */
+#define	SYNC_HUNT	0x10	/* Sync/hunt */
+#define	CTS		0x20	/* CTS */
+#define	TxEOM		0x40	/* Tx underrun */
+#define	BRK_ABRT	0x80	/* Break/Abort */
+
+/* Read Register 1 */
+#define	ALL_SNT		0x1	/* All sent */
+/* Residue Data for 8 Rx bits/char programmed */
+#define	RES3		0x8	/* 0/3 */
+#define	RES4		0x4	/* 0/4 */
+#define	RES5		0xc	/* 0/5 */
+#define	RES6		0x2	/* 0/6 */
+#define	RES7		0xa	/* 0/7 */
+#define	RES8		0x6	/* 0/8 */
+#define	RES18		0xe	/* 1/8 */
+#define	RES28		0x0	/* 2/8 */
+/* Special Rx Condition Interrupts */
+#define	PAR_ERR		0x10	/* Parity error */
+#define	Rx_OVR		0x20	/* Rx Overrun Error */
+#define	CRC_ERR		0x40	/* CRC/Framing Error */
+#define	END_FR		0x80	/* End of Frame (SDLC) */
+
+/* Read Register 2 (channel b only) - Interrupt vector */
+
+/* Read Register 3 (interrupt pending register) ch a only */
+#define	CHBEXT	0x1		/* Channel B Ext/Stat IP */
+#define	CHBTxIP	0x2		/* Channel B Tx IP */
+#define	CHBRxIP	0x4		/* Channel B Rx IP */
+#define	CHAEXT	0x8		/* Channel A Ext/Stat IP */
+#define	CHATxIP	0x10		/* Channel A Tx IP */
+#define	CHARxIP	0x20		/* Channel A Rx IP */
+
+/* Read Register 8 (receive data register) */
+
+/* Read Register 10  (misc status bits) */
+#define	ONLOOP	2		/* On loop */
+#define	LOOPSEND 0x10		/* Loop sending */
+#define	CLK2MIS	0x40		/* Two clocks missing */
+#define	CLK1MIS	0x80		/* One clock missing */
+
+/* Read Register 12 (lower byte of baud rate generator constant) */
+
+/* Read Register 13 (upper byte of baud rate generator constant) */
+
+/* Read Register 15 (value of WR 15) */
+
+/* Misc inlines */
+extern inline void ZS_CLEARERR(struct sgi_zschannel *channel)
+{
+	volatile unsigned char junk;
+
+	udelay(2);
+	channel->control = ERR_RES;
+	junk = ioc_icontrol->istat0;
+}
+
+extern inline void ZS_CLEARFIFO(struct sgi_zschannel *channel)
+{
+	volatile unsigned char junk;
+
+	udelay(2);
+	junk = channel->data;
+	udelay(2); junk = ioc_icontrol->istat0;
+	junk = channel->data;
+	udelay(2); junk = ioc_icontrol->istat0;
+	junk = channel->data;
+	udelay(2); junk = ioc_icontrol->istat0;
+}
+
+#if 0
+
+#define ZS_CLEARERR(channel)    (channel->control = ERR_RES)
+#define ZS_CLEARFIFO(channel)   do { volatile unsigned char garbage; \
+				     garbage = channel->data; \
+				     udelay(2); \
+				     garbage = channel->data; \
+				     udelay(2); \
+				     garbage = channel->data; \
+				     udelay(2); } while(0)
+
+#endif
+
+#endif /* !(_SPARC_SERIAL_H) */
diff -u --recursive --new-file v2.1.72/linux/drivers/sgi/char/shmiq.c linux/drivers/sgi/char/shmiq.c
--- v2.1.72/linux/drivers/sgi/char/shmiq.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sgi/char/shmiq.c	Wed Dec 10 10:31:11 1997
@@ -0,0 +1,460 @@
+/*
+ * shmiq.c: shared memory input queue driver
+ * written 1997 Miguel de Icaza (miguel@nuclecu.unam.mx)
+ *
+ * We implement /dev/shmiq, /dev/qcntlN here
+ * this is different from IRIX that has shmiq as a misc
+ * streams device and the and qcntl devices as a major device.
+ *
+ * minor number 0 implements /dev/shmiq,
+ * any other number implements /dev/qcntl${minor-1}
+ *
+ * /dev/shmiq is used by the X server for two things:
+ * 
+ *    1. for I_LINK()ing trough ioctl the file handle of a
+ *       STREAMS device.
+ *
+ *    2. To send STREAMS-commands to the devices with the
+ *       QIO ioctl interface.
+ *
+ * I have not yet figured how to make multiple X servers share
+ * /dev/shmiq for having different servers running.  So, for now
+ * I keep a kernel-global array of inodes that are pushed into
+ * /dev/shmiq.
+ *
+ * /dev/qcntlN is used by the X server for two things:
+ *
+ *    1. Issuing the QIOCATTACH for mapping the shared input
+ *       queue into the address space of the X server (yeah, yeah,
+ *       I did not invent this interface).
+ *
+ *    2. used by select.  I bet it is used for checking for events on
+ *       the queue.
+ *
+ * Now the problem is that there does not seem anything that
+ * establishes a connection between /dev/shmiq and the qcntlN file.  I
+ * need an strace from an X server that runs on a machine with more
+ * than one keyboard.  And this is a problem since the file handles
+ * are pushed in /dev/shmiq, while the events should be dispatched to
+ * the /dev/qcntlN device. 
+ *
+ * Until then, I just allow for 1 qcntl device.
+ *
+ */
+
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/sched.h>
+#include <linux/file.h>
+#include <linux/interrupt.h>
+#include <linux/vmalloc.h>
+#include <linux/wait.h>
+#include <linux/major.h>
+
+#include <asm/smp_lock.h>
+#include <asm/shmiq.h>
+#include <asm/mman.h>
+#include <asm/uaccess.h>
+#include <asm/poll.h>
+#include "graphics.h"
+
+/* we are not really getting any more than a few files in the shmiq */
+#define MAX_SHMIQ_DEVS 10
+
+/*
+ * One per X server running, not going to get very big.
+ * Even if we have this we now assume just 1 /dev/qcntl can be
+ * active, I need to find how this works on multi-headed machines.
+ */
+#define MAX_SHMI_QUEUES 4
+
+static struct {
+	int                 used;
+	struct file         *filp;
+	struct shmiqsetcpos cpos;
+} shmiq_pushed_devices [MAX_SHMIQ_DEVS];
+
+/* /dev/qcntlN attached memory regions, location and size of the event queue */
+static struct {
+	int    opened;		/* if this device has been opened */
+	void   *shmiq_vaddr;	/* mapping in kernel-land */
+	int    tail;		/* our copy of the shmiq->tail */
+	int    events;
+	int    mapped;
+	
+	struct wait_queue    *proc_list;
+	struct fasync_struct *fasync;
+} shmiqs [MAX_SHMI_QUEUES];
+
+void
+shmiq_push_event (struct shmqevent *e)
+{
+	struct sharedMemoryInputQueue *s;
+	int    device = 0;	/* FIXME: here is the assumption /dev/shmiq == /dev/qcntl0 */
+	int    tail_next;
+
+	if (!shmiqs [device].mapped)
+		return;
+	s = shmiqs [device].shmiq_vaddr;
+
+	s->flags = 0;
+	if (s->tail != shmiqs [device].tail){
+		s->flags |= SHMIQ_CORRUPTED;
+		return;
+	}
+	tail_next = (s->tail + 1) % (shmiqs [device].events);
+	
+	if (tail_next == s->head){
+		s->flags |= SHMIQ_OVERFLOW;
+		return;
+	}
+	
+	e->un.time = jiffies;
+	s->events [s->tail] = *e;
+	printk ("KERNEL: dev=%d which=%d type=%d flags=%d\n",
+		e->data.device, e->data.which, e->data.type, e->data.flags);
+	s->tail = tail_next;
+	shmiqs [device].tail = tail_next;
+	if (shmiqs [device].fasync)
+		kill_fasync (shmiqs [device].fasync, SIGIO);
+	wake_up_interruptible (&shmiqs [device].proc_list);
+}
+
+static int
+shmiq_manage_file (struct file *filp)
+{
+	int i;
+
+	if (!filp->f_op || !filp->f_op->ioctl)
+		return -ENOSR;
+
+	for (i = 0; i < MAX_SHMIQ_DEVS; i++){
+		if (shmiq_pushed_devices [i].used)
+			continue;
+		if ((*filp->f_op->ioctl)(filp->f_dentry->d_inode, filp, SHMIQ_ON, i) != 0)
+			return -ENOSR;
+		shmiq_pushed_devices [i].used = 1;
+		shmiq_pushed_devices [i].filp = filp;
+		shmiq_pushed_devices [i].cpos.x = 0;
+		shmiq_pushed_devices [i].cpos.y = 0;
+		return i;
+	}
+	return -ENOSR;
+}
+
+static int
+shmiq_forget_file (unsigned long fdes)
+{
+	struct file *filp;
+
+	if (fdes > MAX_SHMIQ_DEVS)
+		return -EINVAL;
+	
+	if (!shmiq_pushed_devices [fdes].used)
+		return -EINVAL;
+
+	filp = shmiq_pushed_devices [fdes].filp;
+	if (filp){
+		(*filp->f_op->ioctl)(filp->f_dentry->d_inode, filp, SHMIQ_OFF, 0);
+		shmiq_pushed_devices [fdes].filp = 0;
+		fput (filp);
+	}
+	shmiq_pushed_devices [fdes].used = 0;
+
+	return 0;
+}
+
+static int
+shmiq_sioc (int device, int cmd, struct strioctl *s)
+{
+	switch (cmd){
+	case QIOCGETINDX:
+		/*
+		 * Ok, we just return the index they are providing us
+		 */
+		printk ("QIOCGETINDX: returning %d\n", *(int *)s->ic_dp);
+		return 0;
+
+	case QIOCIISTR: {
+		struct muxioctl *mux = (struct muxioctl *) s->ic_dp;
+		
+		printk ("Double indirect ioctl: [%d, %x\n", mux->index, mux->realcmd);
+		return -EINVAL;
+	}
+
+	case QIOCSETCPOS: {
+		if (copy_from_user (&shmiq_pushed_devices [device].cpos, s->ic_dp,
+				    sizeof (struct shmiqsetcpos)))
+			return -EFAULT;
+		return 0;
+	}
+	}
+	printk ("Unknown I_STR request for shmiq device: 0x%x\n", cmd);
+	return -EINVAL;
+}
+
+static int
+shmiq_ioctl (struct inode *inode, struct file *f, unsigned int cmd, unsigned long arg)
+{
+	struct file *file;
+	struct strioctl sioc;
+	int v;
+
+	switch (cmd){
+		/*
+		 * They are giving us the file descriptor for one
+		 * of their streams devices
+		 */
+
+	case I_LINK:
+		file = fget (arg);
+		if (!file)
+			goto bad_file;
+
+		v = shmiq_manage_file (file);
+		return v;
+
+		/*
+		 * Remove a device from our list of managed
+		 * stream devices
+		 */
+	case I_UNLINK:
+		v = shmiq_forget_file (arg);
+		return v;
+		
+	case I_STR:
+		v = get_sioc (&sioc, arg);
+		if (v)
+			return v;
+		
+		/* FIXME: This forces device = 0 */
+		return shmiq_sioc (0, sioc.ic_cmd, &sioc);
+	}
+
+	return -EINVAL;
+bad_file:
+	unlock_kernel ();
+	return -EBADF;
+}
+
+extern sys_munmap(unsigned long addr, size_t len);
+
+static int
+qcntl_ioctl (struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg, int minor)
+{
+	struct shmiqreq req;
+	struct vm_area_struct *vma;
+	int v;
+	
+	switch (cmd){
+		/*
+		 * The address space is already mapped as a /dev/zero
+		 * mapping.  FIXME: check that /dev/zero is what the user
+		 * had mapped before :-)
+		 */
+	case QIOCATTACH: {
+		unsigned long vaddr;
+		int s;
+		
+		v = verify_area (VERIFY_READ, (void *) arg, sizeof (struct shmiqreq));
+		if (v)
+			return v;
+		if (copy_from_user (&req, (void *) arg, sizeof (req)))
+			return -EFAULT;
+		/* Do not allow to attach to another region if it has been already attached */
+		if (shmiqs [minor].mapped){
+			printk ("SHMIQ:The thingie is already mapped\n");
+			return -EINVAL;
+		}
+
+		vaddr = (unsigned long) req.user_vaddr;
+		vma = find_vma (current->mm, vaddr);
+		if (!vma){
+			printk ("SHMIQ: could not find %lx the vma\n", vaddr);
+			return -EINVAL;
+		}
+		s = req.arg * sizeof (struct shmqevent) + sizeof (struct sharedMemoryInputQueue);
+		v = sys_munmap (vaddr, s);
+		do_mmap (filp, vaddr, s, PROT_READ | PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 0);
+		shmiqs [minor].events = req.arg;
+		shmiqs [minor].mapped = 1;
+		return 0;
+	}
+	}
+	return -EINVAL;
+}
+
+unsigned long
+shmiq_nopage (struct vm_area_struct *vma, unsigned long address, int write_access)
+{
+	/* Do not allow for mremap to expand us */
+	return 0;
+}
+
+static struct vm_operations_struct qcntl_mmap = {
+	NULL,			/* no special mmap-open */
+	NULL,			/* no special mmap-close */
+	NULL,			/* no special mmap-unmap */
+	NULL,			/* no special mmap-protect */
+	NULL,			/* no special mmap-sync */
+	NULL,			/* no special mmap-advise */
+	shmiq_nopage,		/* our magic no-page fault handler */
+	NULL,			/* no special mmap-wppage */
+	NULL,			/* no special mmap-swapout */
+	NULL			/* no special mmap-swapin */
+};
+
+static int
+shmiq_qcntl_mmap (struct file *file, struct vm_area_struct *vma)
+{
+	int           minor = MINOR (file->f_dentry->d_inode->i_rdev), error;
+	unsigned int  size;
+	unsigned long mem, start;
+	
+	/* mmap is only supported on the qcntl devices */
+	if (minor-- == 0)
+		return -EINVAL;
+
+	if (vma->vm_offset != 0)
+		return -EINVAL;
+
+	size  = vma->vm_end - vma->vm_start;
+	start = vma->vm_start; 
+	mem = (unsigned long) shmiqs [minor].shmiq_vaddr =  vmalloc_uncached (size);
+	if (!mem)
+		return -EINVAL;
+
+	/* Prevent the swapper from considering these pages for swap and touching them */
+	vma->vm_flags    |= (VM_SHM  | VM_LOCKED | VM_IO);
+	vma->vm_ops = &qcntl_mmap;
+	
+	/* Uncache the pages */
+	vma->vm_page_prot = PAGE_USERIO;
+
+	error = vmap_page_range (vma->vm_start, size, mem);
+
+	shmiqs [minor].tail = 0;
+	/* Init the shared memory input queue */
+	memset (shmiqs [minor].shmiq_vaddr, 0, size);
+	
+	return error;
+}
+		  
+static int
+shmiq_qcntl_ioctl (struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
+{
+	int minor = MINOR (inode->i_rdev);
+
+	lock_kernel ();
+
+	if (minor-- == 0)
+		return shmiq_ioctl (inode, filp, cmd, arg);
+
+	return qcntl_ioctl (inode, filp, cmd, arg, minor);
+}
+
+static unsigned int
+shmiq_qcntl_poll (struct file *filp, poll_table *wait)
+{
+	struct sharedMemoryInputQueue *s;
+	int minor = MINOR (filp->f_dentry->d_inode->i_rdev);
+
+	if (minor-- == 0)
+		return 0;
+
+	if (!shmiqs [minor].mapped)
+		return 0;
+	
+	poll_wait (&shmiqs [minor].proc_list, wait);
+	s = shmiqs [minor].shmiq_vaddr;
+	if (s->head != s->tail)
+		return POLLIN | POLLRDNORM;
+	return 0;
+}
+
+static int
+shmiq_qcntl_open (struct inode *inode, struct file *filp)
+{
+	int minor = MINOR (inode->i_rdev);
+
+	if (minor == 0)
+		return 0;
+
+	minor--;
+	if (minor > MAX_SHMI_QUEUES)
+		return -EINVAL;
+	if (shmiqs [minor].opened)
+		return -EBUSY;
+
+	lock_kernel ();
+	shmiqs [minor].opened      = 1;
+	shmiqs [minor].shmiq_vaddr = 0;
+	unlock_kernel ();
+	return 0;
+}
+
+static int
+shmiq_qcntl_fasync (struct file *file, int on)
+{
+	int retval;
+	int minor = MINOR (file->f_dentry->d_inode->i_rdev);
+
+	retval = fasync_helper (file, on, &shmiqs [minor].fasync);
+	if (retval < 0)
+		return retval;
+	return 0;
+}
+
+static int
+shmiq_qcntl_close (struct inode *inode, struct file *filp)
+{
+	int minor = MINOR (inode->i_rdev);
+	int j;
+	
+	if (minor-- == 0){
+		for (j = 0; j < MAX_SHMIQ_DEVS; j++)
+			shmiq_forget_file (j);
+	}
+
+	if (minor > MAX_SHMI_QUEUES)
+		return -EINVAL;
+	if (shmiqs [minor].opened == 0)
+		return -EINVAL;
+
+	lock_kernel ();
+	shmiq_qcntl_fasync (filp, 0);
+	shmiqs [minor].opened      = 0;
+	shmiqs [minor].mapped      = 0;
+	shmiqs [minor].events      = 0;
+	shmiqs [minor].fasync      = 0;
+	vfree (shmiqs [minor].shmiq_vaddr);
+	shmiqs [minor].shmiq_vaddr = 0;
+	unlock_kernel ();
+	return 0;
+}
+
+
+static struct
+file_operations shmiq_fops =
+{
+        NULL,                   /* seek */
+        NULL,                   /* read */
+        NULL,                   /* write */
+        NULL,                   /* readdir */
+        shmiq_qcntl_poll,       /* poll */
+        shmiq_qcntl_ioctl,      /* ioctl */
+        shmiq_qcntl_mmap,       /* mmap */
+        shmiq_qcntl_open,       /* open */
+        shmiq_qcntl_close,      /* close */
+        NULL,                   /* fsync */
+        shmiq_qcntl_fasync,     /* fasync */
+        NULL,                   /* check_media_change */
+        NULL,                   /* revalidate */
+};
+
+void
+shmiq_init (void)
+{
+	printk ("SHMIQ setup\n");
+	register_chrdev (SHMIQ_MAJOR, "shmiq", &shmiq_fops);
+}
diff -u --recursive --new-file v2.1.72/linux/drivers/sgi/char/streamable.c linux/drivers/sgi/char/streamable.c
--- v2.1.72/linux/drivers/sgi/char/streamable.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sgi/char/streamable.c	Wed Dec 10 10:31:11 1997
@@ -0,0 +1,363 @@
+/*
+ * streamable.c: streamable devices. /dev/gfx
+ * (C) 1997 Miguel de Icaza (miguel@nuclecu.unam.mx)
+ *
+ * Major 10 is the streams clone device.  The IRIX Xsgi server just
+ * opens /dev/gfx and closes it inmediately.
+ *
+ */
+
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/sched.h>
+#include <linux/kbd_kern.h>
+#include <linux/vt_kern.h>
+#include <asm/uaccess.h>
+#include <asm/shmiq.h>
+#include <asm/keyboard.h>
+#include "graphics.h"
+
+
+extern struct kbd_struct kbd_table [MAX_NR_CONSOLES];
+
+/* console number where forwarding is enabled */
+int forward_chars;
+
+/* To which shmiq this keyboard is assigned */
+int kbd_assigned_device;
+
+/* previous kbd_mode for the forward_chars terminal */
+int kbd_prev_mode;
+
+/* Fetchs the strioctl information from user space for I_STR ioctls */
+int
+get_sioc (struct strioctl *sioc, unsigned long arg)
+{
+	int v;
+	
+	v = verify_area (VERIFY_WRITE, (void *) arg, sizeof (struct strioctl));
+	if (v)
+		return v;
+	if (copy_from_user (sioc, (void *) arg, sizeof (struct strioctl)))
+		return -EFAULT;
+		
+	v = verify_area (VERIFY_WRITE, (void *) sioc->ic_dp, sioc->ic_len);
+	if (v)
+		return v;
+	return 0;
+}
+
+/* /dev/gfx device */
+static int
+sgi_gfx_open (struct inode *inode, struct file *file)
+{
+	printk ("GFX: Opened by %d\n", current->pid);
+	return 0;
+}
+
+static int
+sgi_gfx_close (struct inode *inode, struct file *file)
+{
+	printk ("GFX: Closed by %d\n", current->pid);
+	return 0;
+}
+
+static int
+sgi_gfx_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+	printk ("GFX: ioctl 0x%x %ld called\n", cmd, arg);
+	return 0;
+	return -EINVAL;
+}
+
+struct file_operations sgi_gfx_fops = {
+	NULL,			/* llseek */
+	NULL,			/* read */
+	NULL,			/* write */
+	NULL,			/* readdir */
+	NULL,			/* poll */
+	sgi_gfx_ioctl,		/* ioctl */
+	NULL,			/* mmap */
+	sgi_gfx_open,		/* open */
+	sgi_gfx_close,		/* release */
+	NULL,			/* fsync */
+	NULL,			/* check_media_change */
+	NULL,			/* revalidate */
+	NULL			/* lock */
+};
+ 
+static struct miscdevice dev_gfx = {
+	SGI_GFX_MINOR, "sgi-gfx", &sgi_gfx_fops
+};
+
+/* /dev/input/keyboard streams device */
+static idevDesc sgi_kbd_desc = {
+        "keyboard",             /* devName */
+        "KEYBOARD",             /* devType */
+        240,                    /* nButtons */
+        0,                      /* nValuators */
+        0,                      /* nLEDs */
+        0,                      /* nStrDpys */
+        0,                      /* nIntDpys */
+        0,                      /* nBells */
+	IDEV_HAS_KEYMAP | IDEV_HAS_PCKBD
+};
+
+static int
+sgi_kbd_sioc (idevInfo *dinfo, int cmd, int size, char *data, int *found)
+{
+	*found = 1;
+	
+	switch (cmd){
+
+	case IDEVINITDEVICE:
+		return 0;
+			
+	case IDEVGETDEVICEDESC:
+		if (size >= sizeof (idevDesc)){
+			if (copy_to_user (data, &sgi_kbd_desc, sizeof (sgi_kbd_desc)))
+				return -EFAULT;
+			return 0;
+		}
+		return -EINVAL;
+
+	case IDEVGETKEYMAPDESC:
+		if (size >= sizeof (idevKeymapDesc)){
+			if (copy_to_user (data, "US", 3))
+				return -EFAULT;
+			return 0;
+		}
+		return -EINVAL;
+	}
+	*found = 0;
+	return -EINVAL;
+}
+
+static int
+sgi_keyb_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct strioctl sioc;
+	int    f, v;
+	
+	/* IRIX calls I_PUSH on the opened device, go figure */
+	if (cmd == I_PUSH)
+		return 0;
+
+	if (cmd == I_STR){
+		v = get_sioc (&sioc, arg);
+		if (v)
+			return v;
+
+		/* Why like this?  Because this is a sample piece of code
+		 * that can be copied into other drivers and shows how to
+		 * call a stock IRIX xxx_wioctl routine
+		 *
+		 * The NULL is supposed to be a idevInfo, right now we
+		 * do not support this in our kernel.  
+		 */
+		return sgi_kbd_sioc (NULL, sioc.ic_cmd, sioc.ic_len, sioc.ic_dp, &f);
+	}
+	
+	if (cmd == SHMIQ_ON){
+		kbd_assigned_device = arg;
+		forward_chars = fg_console + 1;
+		kbd_prev_mode = kbd_table [fg_console].kbdmode;
+		
+	        kbd_table [fg_console].kbdmode = VC_RAW;
+	} else if (cmd == SHMIQ_OFF && forward_chars){
+		kbd_table [forward_chars-1].kbdmode = kbd_prev_mode;
+		forward_chars = 0;
+	} else
+		return -EINVAL;
+	return 0;
+}
+
+void
+kbd_forward_char (int ch)
+{
+	static struct shmqevent ev;
+
+	ev.data.flags  = (ch & 0200) ? 0 : 1;
+	ev.data.which  = ch;
+	ev.data.device = kbd_assigned_device + 0x11;
+	shmiq_push_event (&ev);
+}
+
+static int
+sgi_keyb_open (struct inode *inode, struct file *file)
+{
+	/* Nothing, but required by the misc driver */
+	return 0;
+}
+
+struct file_operations sgi_keyb_fops = {
+	NULL,			/* llseek */
+	NULL,			/* read */
+	NULL,			/* write */
+	NULL,			/* readdir */
+	NULL,			/* poll */
+	sgi_keyb_ioctl,		/* ioctl */
+	NULL,			/* mmap */
+	sgi_keyb_open,		/* open */
+	NULL,			/* release */
+	NULL,			/* fsync */
+	NULL,			/* check_media_change */
+	NULL,			/* revalidate */
+	NULL			/* lock */
+};
+
+static struct miscdevice dev_input_keyboard = {
+	SGI_STREAMS_KEYBOARD, "streams-keyboard", &sgi_keyb_fops
+};
+
+/* /dev/input/mouse streams device */
+#define MOUSE_VALUATORS 2
+static idevDesc sgi_mouse_desc = {
+        "mouse",                /* devName */
+        "MOUSE",                /* devType */
+        3,                      /* nButtons */
+        MOUSE_VALUATORS,	/* nValuators */
+        0,                      /* nLEDs */
+        0,                      /* nStrDpys */
+        0,                      /* nIntDpys */
+        0,                      /* nBells */
+	0			/* flags */
+};
+
+static idevValuatorDesc mouse_default_valuator = {
+	200,			/* hwMinRes */
+        200,			/* hwMaxRes */
+        0,			/* hwMinVal */
+        65000,			/* hwMaxVal */
+        IDEV_EITHER,		/* possibleModes */
+        IDEV_ABSOLUTE,		/* default mode */
+        200,			/* resolution */
+        0,			/* minVal */
+        65000			/* maxVal */
+};
+
+static int mouse_opened;
+static idevValuatorDesc mouse_valuators [MOUSE_VALUATORS];
+	
+int
+sgi_mouse_open (struct inode *inode, struct file *file)
+{
+	int i;
+	
+	if (mouse_opened)
+		return -EBUSY;
+	
+	mouse_opened = 1;
+	for (i = 0; i < MOUSE_VALUATORS; i++)
+		mouse_valuators [i] = mouse_default_valuator;
+	return 0;
+}
+
+static int
+sgi_mouse_close (struct inode *inode, struct file *filp)
+{
+	mouse_opened = 0;
+	return 0;
+}
+
+static int
+sgi_mouse_sioc (idevInfo *dinfo, int cmd, int size, char *data, int *found)
+{
+	*found = 1;
+
+	switch (cmd){
+	case IDEVINITDEVICE:
+		return 0;
+			
+	case IDEVGETDEVICEDESC:
+		if (size >= sizeof (idevDesc)){
+			if (copy_to_user (data, &sgi_mouse_desc, sizeof (sgi_mouse_desc)))
+				return -EFAULT;
+			return 0;
+		}
+		return -EINVAL;
+
+	case IDEVGETVALUATORDESC: {
+		idevGetSetValDesc request, *ureq = (idevGetSetValDesc *) data;
+		
+		if (size < sizeof (idevGetSetValDesc))
+			return -EINVAL;
+
+		if (copy_from_user (&request, data, sizeof (request)))
+			return -EFAULT;
+		if (request.valNum >= MOUSE_VALUATORS)
+			return -EINVAL;
+		if (copy_to_user ((void *)&ureq->desc, 
+				  (void *)&mouse_valuators [request.valNum],
+				  sizeof (idevValuatorDesc)))
+			return -EFAULT;
+		return 0;
+	}
+	}
+	*found = 0;
+	return -EINVAL;
+}
+
+static int
+sgi_mouse_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct strioctl sioc;
+	int    f, v;
+
+	/* IRIX calls I_PUSH on the opened device, go figure */
+	switch (cmd){
+	case I_PUSH:
+		return 0;
+
+	case I_STR:
+		v = get_sioc (&sioc, arg);
+		if (v)
+			return v;
+		
+		/* Why like this?  Because this is a sample piece of code
+		 * that can be copied into other drivers and shows how to
+		 * call a stock IRIX xxx_wioctl routine
+		 *
+		 * The NULL is supposed to be a idevInfo, right now we
+		 * do not support this in our kernel.  
+		 */
+		return sgi_mouse_sioc (NULL, sioc.ic_cmd, sioc.ic_len, sioc.ic_dp, &f);
+		
+	case SHMIQ_ON:
+	case SHMIQ_OFF:
+		return 0;
+	}
+	return 0;
+}
+
+struct file_operations sgi_mouse_fops = {
+	NULL,			/* llseek */
+	NULL,			/* read */
+	NULL,			/* write */
+	NULL,			/* readdir */
+	NULL,			/* poll */
+	sgi_mouse_ioctl,	/* ioctl */
+	NULL,			/* mmap */
+	sgi_mouse_open,		/* open */
+	sgi_mouse_close,	/* release */
+	NULL,			/* fsync */
+	NULL,			/* check_media_change */
+	NULL,			/* revalidate */
+	NULL			/* lock */
+};
+
+/* /dev/input/mouse */
+static struct miscdevice dev_input_mouse = {
+	SGI_STREAMS_KEYBOARD, "streams-mouse", &sgi_mouse_fops
+};
+
+void
+streamable_init (void)
+{
+	printk ("streamable misc devices registered (keyb:%d, gfx:%d)\n",
+		SGI_STREAMS_KEYBOARD, SGI_GFX_MINOR);
+	
+	misc_register (&dev_gfx);
+	misc_register (&dev_input_keyboard);
+	misc_register (&dev_input_mouse);
+}
diff -u --recursive --new-file v2.1.72/linux/drivers/sgi/char/usema.c linux/drivers/sgi/char/usema.c
--- v2.1.72/linux/drivers/sgi/char/usema.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sgi/char/usema.c	Wed Dec 10 10:31:11 1997
@@ -0,0 +1,191 @@
+/*
+ * usema.c: software semaphore driver (see IRIX's usema(7M))
+ * written 1997 Mike Shaver (shaver@neon.ingenia.ca)
+ *         1997 Miguel de Icaza (miguel@kernel.org)
+ *
+ * This file contains the implementation of /dev/usemaclone,
+ * the devices used by IRIX's us* semaphore routines.
+ *
+ * /dev/usemaclone is used to create a new semaphore device, and then
+ * the semaphore is manipulated via ioctls.
+ *
+ * At least for the zero-contention case, lock set and unset as well
+ * as semaphore P and V are done in userland, which makes things a
+ * little bit better.  I suspect that the ioctls are used to register
+ * the process as blocking, etc.
+ *
+ * Much inspiration and structure stolen from Miguel's shmiq work.
+ *
+ * For more information:
+ * usema(7m), usinit(3p), usnewsema(3p)
+ * /usr/include/sys/usioctl.h 
+ *
+*/
+
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/sched.h>
+#include <linux/file.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/dcache.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+
+#include <asm/smp_lock.h>
+#include <asm/usioctl.h>
+#include <asm/mman.h>
+#include <asm/uaccess.h>
+
+struct irix_usema {
+	struct file *filp;
+	struct wait_queue *proc_list;
+};
+
+static int
+sgi_usema_attach (usattach_t * attach, struct irix_usema *usema)
+{
+	int newfd;
+	newfd = get_unused_fd();
+	if (newfd < 0)
+		return newfd;
+	
+	current->files->fd [newfd] = usema->filp;
+	usema->filp->f_count++;
+	/* Is that it? */
+	printk("UIOCATTACHSEMA: new usema fd is %d", newfd);
+	return newfd;
+}
+
+static int
+sgi_usemaclone_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+		unsigned long arg)
+{
+	struct irix_usema *usema = file->private_data;
+	int retval;
+	
+	printk("[%s:%d] wants ioctl 0x%xd (arg 0x%lx)",
+	       current->comm, current->pid, cmd, arg);
+
+	switch(cmd) {
+	case UIOCATTACHSEMA: {
+		/* They pass us information about the semaphore to
+		   which they wish to be attached, and we create&return
+		   a new fd corresponding to the appropriate semaphore.
+		   */
+		usattach_t *attach = (usattach_t *)arg;
+		retval = verify_area(VERIFY_READ, attach, sizeof(usattach_t));
+		if (retval) {
+			printk("[%s:%d] sgi_usema_ioctl(UIOCATTACHSEMA): "
+			       "verify_area failure",
+			       current->comm, current->pid);
+			return retval;
+		}
+		if (usema == 0)
+			return -EINVAL;
+
+		printk("UIOCATTACHSEMA: attaching usema %p to process %d\n", usema, current->pid);
+		/* XXX what is attach->us_handle for? */
+		return sgi_usema_attach(attach, usema);
+		break;
+	}
+	case UIOCABLOCK:	/* XXX make `async' */
+	case UIOCNOIBLOCK:	/* XXX maybe? */
+	case UIOCBLOCK: {
+		/* Block this process on the semaphore */
+		usattach_t *attach = (usattach_t *)arg;
+
+		retval = verify_area(VERIFY_READ, attach, sizeof(usattach_t));
+		if (retval) {
+			printk("[%s:%d] sgi_usema_ioctl(UIOC*BLOCK): "
+			       "verify_area failure",
+			       current->comm, current->pid);
+			return retval;
+		}
+		printk("UIOC*BLOCK: putting process %d to sleep on usema %p",
+		       current->pid, usema);
+		if (cmd == UIOCNOIBLOCK)
+			interruptible_sleep_on(&usema->proc_list);
+		else
+			sleep_on(&usema->proc_list);
+		return 0;
+	}
+	case UIOCAUNBLOCK:	/* XXX make `async' */
+	case UIOCUNBLOCK: {
+		/* Wake up all process waiting on this semaphore */
+		usattach_t *attach = (usattach_t *)arg;
+
+		retval = verify_area(VERIFY_READ, attach, sizeof(usattach_t));
+		if (retval) {
+			printk("[%s:%d] sgi_usema_ioctl(UIOC*BLOCK): "
+			       "verify_area failure",
+			       current->comm, current->pid);
+			return retval;
+		}
+
+		printk("[%s:%d] releasing usema %p",
+		       current->comm, current->pid, usema);
+		wake_up(&usema->proc_list);
+		return 0;
+	}
+	}
+	return -ENOSYS;
+}
+
+static unsigned int
+sgi_usemaclone_poll(struct file *filp, poll_table *wait)
+{
+	struct irix_usema *usema = filp->private_data;
+	
+	printk("[%s:%d] wants to poll usema %p", current->comm, current->pid, usema);
+	
+	return 0;
+}
+
+static int
+sgi_usemaclone_open(struct inode *inode, struct file *filp)
+{
+	struct irix_usema *usema;
+
+	usema = kmalloc (sizeof (struct irix_usema), GFP_KERNEL);
+	if (!usema)
+		return -ENOMEM;
+	
+	usema->filp        = filp;
+	usema->proc_list   = NULL;
+	filp->private_data = usema;
+	return 0;
+}	
+
+static int
+sgi_usemaclone_release(struct inode *inode, struct file *filp)
+{
+	return 0;
+}
+
+struct file_operations sgi_usemaclone_fops = {
+	NULL,			/* llseek */
+	NULL,			/* read */
+	NULL,			/* write */
+	NULL,			/* readdir */
+	sgi_usemaclone_poll,	/* poll */
+	sgi_usemaclone_ioctl,	/* ioctl */
+	NULL,			/* mmap */
+	sgi_usemaclone_open,	/* open */
+	sgi_usemaclone_release,	/* release */
+	NULL,			/* fsync */
+	NULL,			/* check_media_change */
+	NULL,			/* revalidate */
+	NULL			/* lock */
+};
+
+static struct miscdevice dev_usemaclone = {
+	SGI_USEMACLONE, "usemaclone", &sgi_usemaclone_fops
+};
+
+void
+usema_init(void)
+{
+	printk("usemaclone misc device registered (minor: %d)\n", SGI_USEMACLONE);
+	misc_register(&dev_usemaclone);
+}
diff -u --recursive --new-file v2.1.72/linux/drivers/sgi/char/vga_font.c linux/drivers/sgi/char/vga_font.c
--- v2.1.72/linux/drivers/sgi/char/vga_font.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sgi/char/vga_font.c	Wed Dec 10 10:31:11 1997
@@ -0,0 +1,346 @@
+#include "gconsole.h"
+
+unsigned char vga_font[cmapsz] = {
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x81, 0xa5, 0x81, 0x81, 0xbd, 
+0x99, 0x81, 0x81, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xff, 
+0xdb, 0xff, 0xff, 0xc3, 0xe7, 0xff, 0xff, 0x7e, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x6c, 0xfe, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x7c, 0xfe, 
+0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 
+0x3c, 0x3c, 0xe7, 0xe7, 0xe7, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x7e, 0x18, 0x18, 0x3c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 
+0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 
+0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0x99, 0xbd, 
+0xbd, 0x99, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x1e, 0x0e, 
+0x1a, 0x32, 0x78, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x18, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x30, 
+0x30, 0x70, 0xf0, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x63, 
+0x7f, 0x63, 0x63, 0x63, 0x63, 0x67, 0xe7, 0xe6, 0xc0, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x18, 0x18, 0xdb, 0x3c, 0xe7, 0x3c, 0xdb, 0x18, 0x18, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfe, 0xf8, 
+0xf0, 0xe0, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x0e, 
+0x1e, 0x3e, 0xfe, 0x3e, 0x1e, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 
+0x66, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xdb, 
+0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x7c, 0xc6, 0x60, 0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x38, 0x0c, 0xc6, 
+0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0xfe, 0xfe, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 
+0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, 
+0xc0, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x38, 0x7c, 0x7c, 0xfe, 0xfe, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x7c, 0x7c, 
+0x38, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 
+0x6c, 0xfe, 0x6c, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 
+0x18, 0x18, 0x7c, 0xc6, 0xc2, 0xc0, 0x7c, 0x06, 0x06, 0x86, 0xc6, 0x7c, 
+0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc2, 0xc6, 0x0c, 0x18, 
+0x30, 0x60, 0xc6, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 
+0x6c, 0x38, 0x76, 0xdc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x30, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 
+0x30, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x18, 
+0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 
+0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x02, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0xc6, 0xc6, 0x7c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 
+0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x7c, 0xc6, 0x06, 0x06, 0x3c, 0x06, 0x06, 0x06, 0xc6, 0x7c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 
+0x0c, 0x0c, 0x0c, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0, 
+0xc0, 0xc0, 0xfc, 0x06, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x38, 0x60, 0xc0, 0xc0, 0xfc, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc6, 0x06, 0x06, 0x0c, 0x18, 
+0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 
+0xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x06, 0x06, 0x0c, 0x78, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 
+0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x06, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 
+0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 
+0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x0c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xde, 0xde, 
+0xde, 0xdc, 0xc0, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 
+0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x66, 0x66, 0x66, 0x66, 0xfc, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0, 
+0xc0, 0xc2, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x6c, 
+0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x62, 0x66, 0xfe, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 
+0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 
+0xc2, 0xc0, 0xc0, 0xde, 0xc6, 0xc6, 0x66, 0x3a, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x0c, 
+0x0c, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0xe6, 0x66, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0x66, 0xe6, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x60, 0x60, 0x60, 0x60, 0x60, 
+0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xe7, 
+0xff, 0xff, 0xdb, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0xc6, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 
+0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66, 
+0x66, 0x66, 0x7c, 0x60, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xd6, 0xde, 0x7c, 
+0x0c, 0x0e, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x6c, 
+0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 
+0xc6, 0x60, 0x38, 0x0c, 0x06, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0xff, 0xdb, 0x99, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 
+0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 
+0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x66, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x18, 
+0x3c, 0x66, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 
+0xc3, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0xff, 0xc3, 0x86, 0x0c, 0x18, 0x30, 0x60, 0xc1, 0xc3, 0xff, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, 
+0x30, 0x30, 0x30, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 
+0xc0, 0xe0, 0x70, 0x38, 0x1c, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c, 
+0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 
+0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0c, 0x7c, 
+0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x60, 
+0x60, 0x78, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc0, 0xc6, 0x7c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x0c, 0x0c, 0x3c, 0x6c, 0xcc, 
+0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xf0, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 
+0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xcc, 0x78, 0x00, 0x00, 0x00, 0xe0, 0x60, 
+0x60, 0x6c, 0x76, 0x66, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x18, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x00, 0x0e, 0x06, 0x06, 
+0x06, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0xe0, 0x60, 
+0x60, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe6, 0xff, 0xdb, 
+0xdb, 0xdb, 0xdb, 0xdb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, 
+0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x76, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0x0c, 0x1e, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0x60, 0x60, 0xf0, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0x60, 
+0x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x30, 
+0x30, 0xfc, 0x30, 0x30, 0x30, 0x30, 0x36, 0x1c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0xc3, 
+0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0x3c, 0x66, 0xc3, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 
+0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0xfe, 0xcc, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x0e, 0x18, 0x18, 0x18, 0x70, 0x18, 0x18, 0x18, 0x18, 0x0e, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 
+0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x18, 
+0x18, 0x18, 0x0e, 0x18, 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 
+0xc6, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 
+0xc2, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x0c, 0x06, 0x7c, 0x00, 0x00, 
+0x00, 0x00, 0xcc, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x00, 0x7c, 0xc6, 0xfe, 
+0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 
+0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0xcc, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0x78, 0x0c, 0x7c, 
+0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x38, 
+0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x60, 0x60, 0x66, 0x3c, 0x0c, 0x06, 
+0x3c, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xfe, 
+0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 
+0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x38, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x66, 
+0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x60, 0x30, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 
+0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x38, 0x00, 
+0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 
+0x18, 0x30, 0x60, 0x00, 0xfe, 0x66, 0x60, 0x7c, 0x60, 0x60, 0x66, 0xfe, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x3b, 0x1b, 
+0x7e, 0xd8, 0xdc, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x6c, 
+0xcc, 0xcc, 0xfe, 0xcc, 0xcc, 0xcc, 0xcc, 0xce, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 
+0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 
+0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x30, 0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0xcc, 0xcc, 0xcc, 
+0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 
+0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0x78, 0x00, 
+0x00, 0xc6, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 
+0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 
+0xc3, 0xc0, 0xc0, 0xc0, 0xc3, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xe6, 0xfc, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0xff, 0x18, 
+0xff, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66, 0x66, 
+0x7c, 0x62, 0x66, 0x6f, 0x66, 0x66, 0x66, 0xf3, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x0e, 0x1b, 0x18, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 
+0xd8, 0x70, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0x00, 0x78, 0x0c, 0x7c, 
+0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 
+0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x18, 0x30, 0x60, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0x00, 0xcc, 0xcc, 0xcc, 
+0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 
+0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 
+0x76, 0xdc, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x6c, 0x6c, 0x3e, 0x00, 0x7e, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x6c, 
+0x38, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x60, 0xc0, 0xc6, 0xc6, 0x7c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0, 
+0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0xfe, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, 0x60, 0xce, 0x9b, 0x06, 
+0x0c, 0x1f, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, 
+0x66, 0xce, 0x96, 0x3e, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 
+0x00, 0x18, 0x18, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x6c, 0xd8, 0x6c, 0x36, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x6c, 0x36, 
+0x6c, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x44, 0x11, 0x44, 
+0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 
+0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 
+0x55, 0xaa, 0x55, 0xaa, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 
+0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, 
+0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36, 0x36, 
+0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0xf8, 
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, 
+0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
+0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
+0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0xf6, 
+0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
+0x36, 0xf6, 0x06, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 
+0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
+0x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 
+0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xff, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
+0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 
+0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36, 
+0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
+0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36, 0x36, 
+0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3f, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 
+0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
+0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
+0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, 0xf0, 
+0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 
+0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 
+0x0f, 0x0f, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x76, 0xdc, 0xd8, 0xd8, 0xd8, 0xdc, 0x76, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0xd8, 0xcc, 0xc6, 0xc6, 0xc6, 0xcc, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc6, 0xc6, 0xc0, 0xc0, 0xc0, 
+0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0xfe, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0xfe, 0xc6, 0x60, 0x30, 0x18, 0x30, 0x60, 0xc6, 0xfe, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xd8, 0xd8, 
+0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x66, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x18, 0x3c, 0x66, 0x66, 
+0x66, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 
+0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x6c, 0x6c, 0x6c, 0xee, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x30, 0x18, 0x0c, 0x3e, 0x66, 
+0x66, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x7e, 0xdb, 0xdb, 0xdb, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x03, 0x06, 0x7e, 0xdb, 0xdb, 0xf3, 0x7e, 0x60, 0xc0, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x30, 0x60, 0x60, 0x7c, 0x60, 
+0x60, 0x60, 0x30, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 
+0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 
+0x18, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 
+0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x00, 0x7e, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x1b, 0x1b, 0x1b, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x7e, 0x00, 0x18, 0x18, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00, 
+0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x6c, 
+0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0c, 0x0c, 
+0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x6c, 0x3c, 0x1c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0xd8, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0xd8, 0x30, 0x60, 0xc8, 0xf8, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+};
diff -u --recursive --new-file v2.1.72/linux/drivers/sound/lowlevel/awe_wave.c linux/drivers/sound/lowlevel/awe_wave.c
--- v2.1.72/linux/drivers/sound/lowlevel/awe_wave.c	Wed Dec 10 11:12:44 1997
+++ linux/drivers/sound/lowlevel/awe_wave.c	Wed Dec 10 09:45:16 1997
@@ -564,7 +564,7 @@
 	synth_devs[my_dev] = &awe_operations;
 
 #ifdef CONFIG_AWE32_MIXER
-	if ((my_mixerdev=sound_alloc_mixerdev())==-1) {
+	if ((my_mixerdev=sound_alloc_mixerdev())!=-1) {
 		mixer_devs[my_mixerdev] = &awe_mixer_operations;
 	}
 #endif
diff -u --recursive --new-file v2.1.72/linux/fs/dcache.c linux/fs/dcache.c
--- v2.1.72/linux/fs/dcache.c	Mon Dec  1 12:04:14 1997
+++ linux/fs/dcache.c	Wed Dec 10 10:14:29 1997
@@ -744,6 +744,42 @@
 	return retval;
 }
 
+/*
+ * Check whether a dentry already exists for the given name,
+ * and return the inode number if it has an inode.
+ *
+ * This routine is used to post-process directory listings for
+ * filesystems using synthetic inode numbers, and is necessary
+ * to keep getcwd() working.
+ */
+ino_t find_inode_number(struct dentry *dir, struct qstr *name)
+{
+	struct dentry * dentry;
+	ino_t ino = 0;
+
+	/*
+	 * Check for a fs-specific hash function. Note that we must
+	 * calculate the standard hash first, as the d_op->d_hash()
+	 * routine may choose to leave the hash value unchanged.
+	 */
+	name->hash = full_name_hash(name->name, name->len);
+	if (dir->d_op && dir->d_op->d_hash)
+	{
+		if (dir->d_op->d_hash(dir, name) != 0)
+			goto out;
+	}
+
+	dentry = d_lookup(dir, name);
+	if (dentry)
+	{
+		if (dentry->d_inode)
+			ino = dentry->d_inode->i_ino;
+		dput(dentry);
+	}
+out:
+	return ino;
+}
+
 __initfunc(void dcache_init(void))
 {
 	int i;
diff -u --recursive --new-file v2.1.72/linux/fs/ext2/fsync.c linux/fs/ext2/fsync.c
--- v2.1.72/linux/fs/ext2/fsync.c	Wed Nov 26 16:24:03 1997
+++ linux/fs/ext2/fsync.c	Wed Dec 10 13:13:30 1997
@@ -57,6 +57,72 @@
 	return 0;
 }
 
+#ifndef __LITTLE_ENDIAN
+static int sync_block_swab32 (struct inode * inode, u32 * block, int wait)
+{
+	struct buffer_head * bh;
+	
+	if (!le32_to_cpu(*block))
+		return 0;
+	bh = get_hash_table (inode->i_dev, le32_to_cpu(*block), blocksize);
+	if (!bh)
+		return 0;
+	if (wait && buffer_req(bh) && !buffer_uptodate(bh)) {
+		brelse (bh);
+		return -1;
+	}
+	if (wait || !buffer_uptodate(bh) || !buffer_dirty(bh)) {
+		brelse (bh);
+		return 0;
+	}
+	ll_rw_block (WRITE, 1, &bh);
+	bh->b_count--;
+	return 0;
+}
+#else
+#define sync_block_swab32 sync_block
+#endif
+
+
+static int sync_iblock (struct inode * inode, u32 * iblock, 
+			struct buffer_head ** bh, int wait) 
+{
+	int rc, tmp;
+	
+	*bh = NULL;
+	tmp = *iblock;
+	if (!tmp)
+		return 0;
+	rc = sync_block (inode, iblock, wait);
+	if (rc)
+		return rc;
+	*bh = bread (inode->i_dev, tmp, blocksize);
+	if (!*bh)
+		return -1;
+	return 0;
+}
+
+#ifndef __LITTLE_ENDIAN
+static int sync_iblock_swab32 (struct inode * inode, u32 * iblock, 
+			       struct buffer_head ** bh, int wait) 
+{
+	int rc, tmp;
+	
+	*bh = NULL;
+	tmp = le32_to_cpu(*iblock);
+	if (!tmp)
+		return 0;
+	rc = sync_block_swab32 (inode, iblock, wait);
+	if (rc)
+		return rc;
+	*bh = bread (inode->i_dev, tmp, blocksize);
+	if (!*bh)
+		return -1;
+	return 0;
+}
+#else
+#define sync_iblock_swab32 sync_iblock
+#endif
 
 static int sync_direct (struct inode * inode, int wait)
 {
@@ -71,15 +137,122 @@
 	return err;
 }
 
+static int sync_indirect (struct inode * inode, u32 * iblock, int wait)
+{
+	int i;
+	struct buffer_head * ind_bh;
+	int rc, err = 0;
+
+	rc = sync_iblock (inode, iblock, &ind_bh, wait);
+	if (rc || !ind_bh)
+		return rc;
+	
+	for (i = 0; i < addr_per_block; i++) {
+		rc = sync_block_swab32 (inode, 
+					((u32 *) ind_bh->b_data) + i,
+					wait);
+		if (rc)
+			err = rc;
+	}
+	brelse (ind_bh);
+	return err;
+}
+
+#ifndef __LITTLE_ENDIAN
+static __inline__ int sync_indirect_swab32 (struct inode * inode, u32 * iblock, int wait)
+{
+	int i;
+	struct buffer_head * ind_bh;
+	int rc, err = 0;
+
+	rc = sync_iblock_swab32 (inode, iblock, &ind_bh, wait);
+	if (rc || !ind_bh)
+		return rc;
+	
+	for (i = 0; i < addr_per_block; i++) {
+		rc = sync_block_swab32 (inode, 
+					((u32 *) ind_bh->b_data) + i,
+					wait);
+		if (rc)
+			err = rc;
+	}
+	brelse (ind_bh);
+	return err;
+}
+#else
+#define sync_indirect_swab32 sync_indirect
+#endif
+
+static int sync_dindirect (struct inode * inode, u32 * diblock, int wait)
+{
+	int i;
+	struct buffer_head * dind_bh;
+	int rc, err = 0;
+
+	rc = sync_iblock (inode, diblock, &dind_bh, wait);
+	if (rc || !dind_bh)
+		return rc;
+	
+	for (i = 0; i < addr_per_block; i++) {
+		rc = sync_indirect_swab32 (inode,
+					   ((u32 *) dind_bh->b_data) + i,
+					   wait);
+		if (rc)
+			err = rc;
+	}
+	brelse (dind_bh);
+	return err;
+}
+
+#ifndef __LITTLE_ENDIAN
+static __inline__ int sync_dindirect_swab32 (struct inode * inode, u32 * diblock, int wait)
+{
+	int i;
+	struct buffer_head * dind_bh;
+	int rc, err = 0;
+
+	rc = sync_iblock_swab32 (inode, diblock, &dind_bh, wait);
+	if (rc || !dind_bh)
+		return rc;
+	
+	for (i = 0; i < addr_per_block; i++) {
+		rc = sync_indirect_swab32 (inode,
+					   ((u32 *) dind_bh->b_data) + i,
+					   wait);
+		if (rc)
+			err = rc;
+	}
+	brelse (dind_bh);
+	return err;
+}
+#else
+#define sync_dindirect_swab32 sync_dindirect
+#endif
+
+static int sync_tindirect (struct inode * inode, u32 * tiblock, int wait)
+{
+	int i;
+	struct buffer_head * tind_bh;
+	int rc, err = 0;
+
+	rc = sync_iblock (inode, tiblock, &tind_bh, wait);
+	if (rc || !tind_bh)
+		return rc;
+	
+	for (i = 0; i < addr_per_block; i++) {
+		rc = sync_dindirect_swab32 (inode,
+					    ((u32 *) tind_bh->b_data) + i,
+					    wait);
+		if (rc)
+			err = rc;
+	}
+	brelse (tind_bh);
+	return err;
+}
+
 /*
  *	File may be NULL when we are called. Perhaps we shouldn't
  *	even pass file to fsync ?
- *
- *	This currently falls back to synching the whole device when
- *	the file is larger than can fit directly in the inode. This
- *	is because dirty-buffer handling is indexed by the device
- *	of the buffer, which makes it much faster to sync the whole
- *	device than to sync just one large file.
  */
 
 int ext2_sync_file(struct file * file, struct dentry *dentry)
@@ -96,12 +269,18 @@
 		 */
 		goto skip;
 
-	if (inode->i_size > EXT2_NDIR_BLOCKS*blocksize)
-		return file_fsync(file, dentry);
-
 	for (wait=0; wait<=1; wait++)
 	{
 		err |= sync_direct (inode, wait);
+		err |= sync_indirect (inode,
+				      inode->u.ext2_i.i_data+EXT2_IND_BLOCK,
+				      wait);
+		err |= sync_dindirect (inode,
+				       inode->u.ext2_i.i_data+EXT2_DIND_BLOCK, 
+				       wait);
+		err |= sync_tindirect (inode, 
+				       inode->u.ext2_i.i_data+EXT2_TIND_BLOCK, 
+				       wait);
 	}
 skip:
 	err |= ext2_sync_inode (inode);
diff -u --recursive --new-file v2.1.72/linux/fs/fat/inode.c linux/fs/fat/inode.c
--- v2.1.72/linux/fs/fat/inode.c	Wed Nov 12 13:34:27 1997
+++ linux/fs/fat/inode.c	Wed Dec 10 09:13:24 1997
@@ -117,6 +117,16 @@
 
 void fat_delete_inode(struct inode *inode)
 {
+	/*
+	 * Make sure there are no active dependencies ...
+	 */
+	if (MSDOS_I(inode)->i_old)
+		printk("fat_delete_inode: inode %ld, old=%p??\n",
+			inode->i_ino, MSDOS_I(inode)->i_old);
+	if (MSDOS_I(inode)->i_oldlink)
+		printk("fat_delete_inode: inode %ld, oldlink=%p??\n",
+			inode->i_ino, MSDOS_I(inode)->i_oldlink);
+
 	fat_cache_inval_inode(inode);
 	inode->i_size = 0;
 	fat_truncate(inode);
diff -u --recursive --new-file v2.1.72/linux/fs/isofs/dir.c linux/fs/isofs/dir.c
--- v2.1.72/linux/fs/isofs/dir.c	Sat Nov  1 11:04:27 1997
+++ linux/fs/isofs/dir.c	Thu Dec 18 16:37:02 1997
@@ -207,22 +207,22 @@
 			}
 		}
 
+		map = 1;
+		if (inode->i_sb->u.isofs_sb.s_rock) {
+			len = get_rock_ridge_filename(de, tmpname, inode);
+			if (len != 0) {
+				p = tmpname;
+				map = 0;
+			}
+		}
+		if (map) {
 #ifdef CONFIG_JOLIET
-		if (inode->i_sb->u.isofs_sb.s_joliet_level) {
-			len = get_joliet_filename(de, inode, tmpname);
-			p = tmpname;
-		} else 
+			if (inode->i_sb->u.isofs_sb.s_joliet_level) {
+				len = get_joliet_filename(de, inode, tmpname);
+				p = tmpname;
+			} else
 #endif
-		/* if not joliet */ {
-			map = 1;
-			if (inode->i_sb->u.isofs_sb.s_rock) {
-				len = get_rock_ridge_filename(de, tmpname, inode);
-				if (len != 0) {
-					p = tmpname;
-					map = 0;
-				}
-			}
-			if (map) {
+			{
 				if (inode->i_sb->u.isofs_sb.s_mapping == 'n') {
 					len = isofs_name_translate(de->name, de->name_len[0],
 								   tmpname);
diff -u --recursive --new-file v2.1.72/linux/fs/isofs/inode.c linux/fs/isofs/inode.c
--- v2.1.72/linux/fs/isofs/inode.c	Tue Dec  2 16:45:20 1997
+++ linux/fs/isofs/inode.c	Thu Dec 18 16:37:02 1997
@@ -283,7 +283,7 @@
 	struct iso_supplementary_descriptor *sec = NULL;
 	struct iso_volume_descriptor  * vdp;
 	unsigned int			vol_desc_start;
-
+	struct inode		      * inode;
 
 
 	MOD_INC_USE_COUNT;
@@ -384,7 +384,6 @@
 		    sec = (struct iso_supplementary_descriptor *)vdp;
 		    if (sec->escape[0] == 0x25 && sec->escape[1] == 0x2f) {
 			if (opt.joliet == 'y') {
-			    opt.rock = 'n';
 			    if (sec->escape[2] == 0x40) {
 				joliet_level = 1;
 			    } else if (sec->escape[2] == 0x43) {
@@ -418,16 +417,12 @@
 
 	s->u.isofs_sb.s_joliet_level = joliet_level;
 
-#ifdef CONFIG_JOLIET
-	if (joliet_level) {
-	    /* Note: In theory, it is possible to have Rock Ridge
-	     * extensions mixed with Joliet. All character strings
-	     * would just be saved as Unicode. Until someone sees such
-	     * a disc, do not allow the two to be mixed
+	if (joliet_level && opt.rock == 'n') {
+	    /* This is the case of Joliet with the norock mount flag.
+	     * A disc with both Joliet and Rock Ridge is handled later
 	     */
 	    pri = (struct iso_primary_descriptor *) sec;
 	}
-#endif
 
 	if(high_sierra){
 	  rootp = (struct iso_directory_record *) h_pri->root_directory_record;
@@ -486,11 +481,6 @@
 	      goto out;
 	  }
 
-	/* RDE: data zone now byte offset! */
-
-	s->u.isofs_sb.s_firstdatazone = ((isonum_733 (rootp->extent) +
-					   isonum_711 (rootp->ext_attr_length))
-					 << s -> u.isofs_sb.s_log_zone_size);
 	s->s_magic = ISOFS_SUPER_MAGIC;
 
 	/* The CDROM is read-only, has no nodes (devices) on it, and since
@@ -502,14 +492,18 @@
 
 	brelse(bh);
 	
+	/* RDE: data zone now byte offset! */
+
+	s->u.isofs_sb.s_firstdatazone = ((isonum_733 (rootp->extent) +
+					   isonum_711 (rootp->ext_attr_length))
+					 << s -> u.isofs_sb.s_log_zone_size);
 #ifndef BEQUIET
 	printk(KERN_DEBUG "Max size:%ld   Log zone size:%ld\n",
 	       s->u.isofs_sb.s_max_size,
 	       1UL << s->u.isofs_sb.s_log_zone_size);
 	printk(KERN_DEBUG "First datazone:%ld   Root inode number %d\n",
 	       s->u.isofs_sb.s_firstdatazone >> s -> u.isofs_sb.s_log_zone_size,
-	       (isonum_733(rootp->extent) + isonum_711(rootp->ext_attr_length))
-			<< s -> u.isofs_sb.s_log_zone_size);
+	       s->u.isofs_sb.s_firstdatazone);
 	if(high_sierra) printk(KERN_DEBUG "Disc in High Sierra format.\n");
 #endif
 	unlock_super(s);
@@ -549,8 +543,9 @@
 #endif
 	  }
 
-#ifdef CONFIG_JOLIET
 	s->u.isofs_sb.s_nls_iocharset = NULL;
+
+#ifdef CONFIG_JOLIET
 	if (joliet_level == 0) {
 		if (opt.iocharset) {
 			kfree(opt.iocharset);
@@ -574,7 +569,7 @@
 	s->s_dev = dev;
 	s->s_op = &isofs_sops;
 	s->u.isofs_sb.s_mapping = opt.map;
-	s->u.isofs_sb.s_rock = (opt.rock == 'y' ? 1 : 0);
+	s->u.isofs_sb.s_rock = (opt.rock == 'y' ? 2 : 0);
 	s->u.isofs_sb.s_name_check = opt.check;
 	s->u.isofs_sb.s_conversion = opt.conversion;
 	s->u.isofs_sb.s_cruft = opt.cruft;
@@ -589,9 +584,30 @@
 	s->u.isofs_sb.s_mode = opt.mode & 0777;
 	s->s_blocksize = opt.blocksize;
 	s->s_blocksize_bits = blocksize_bits;
-	s->s_root = d_alloc_root(iget(s, (isonum_733(rootp->extent) +
-			    isonum_711(rootp->ext_attr_length))
-				<< s -> u.isofs_sb.s_log_zone_size), NULL);
+	inode = iget(s, s->u.isofs_sb.s_firstdatazone);
+
+	/*
+	 * If this disk has both Rock Ridge and Joliet on it, then we
+	 * want to use Rock Ridge by default.  This can be overridden
+	 * by using the norock mount option.  There is still one other
+	 * possibility that is not taken into account: a Rock Ridge
+	 * CD with Unicode names.  Until someone sees such a beast, it
+	 * will not be supported.
+	 */
+	if (joliet_level && opt.rock == 'y' && s->u.isofs_sb.s_rock != 1) {
+		iput(inode);
+		pri = (struct iso_primary_descriptor *) sec;
+		rootp = (struct iso_directory_record *)
+			pri->root_directory_record;
+		s->u.isofs_sb.s_firstdatazone =
+			((isonum_733 (rootp->extent) +
+			  isonum_711 (rootp->ext_attr_length))
+			 << s -> u.isofs_sb.s_log_zone_size);
+		inode = iget(s, s->u.isofs_sb.s_firstdatazone);
+		s->u.isofs_sb.s_rock = 0;
+	}
+
+	s->s_root = d_alloc_root(inode, NULL);
 	unlock_super(s);
 
 	if (!(s->s_root)) {
diff -u --recursive --new-file v2.1.72/linux/fs/isofs/rock.c linux/fs/isofs/rock.c
--- v2.1.72/linux/fs/isofs/rock.c	Sat Oct 25 02:44:17 1997
+++ linux/fs/isofs/rock.c	Thu Dec 18 16:37:02 1997
@@ -265,6 +265,7 @@
 	CHECK_CE;
 	break;
       case SIG('E','R'):
+	inode->i_sb->u.isofs_sb.s_rock = 1;
 	printk(KERN_DEBUG"ISO9660 Extensions: ");
 	{ int p;
 	  for(p=0;p<rr->u.ER.len_id;p++) printk("%c",rr->u.ER.data[p]);
diff -u --recursive --new-file v2.1.72/linux/fs/msdos/namei.c linux/fs/msdos/namei.c
--- v2.1.72/linux/fs/msdos/namei.c	Wed Nov 12 13:34:27 1997
+++ linux/fs/msdos/namei.c	Wed Dec 10 09:13:24 1997
@@ -173,56 +173,60 @@
 	return fat_scan(dir,msdos_name,bh,de,ino,scantype);
 }
 
-
+/*
+ * Compute the hash for the msdos name corresponding to the dentry.
+ * Note: if the name is invalid, we leave the hash code unchanged so
+ * that the existing dentry can be used. The msdos fs routines will
+ * return ENOENT or EINVAL as appropriate.
+ */
 static int msdos_hash(struct dentry *dentry, struct qstr *qstr)
 {
-	unsigned long hash;
-	char msdos_name[MSDOS_NAME];
+	struct fat_mount_options *options = & (MSDOS_SB(dentry->d_sb)->options);
 	int error;
-	int i;
-	struct fat_mount_options *options = 
-		& (MSDOS_SB(dentry->d_inode->i_sb)->options);
+	char msdos_name[MSDOS_NAME];
 	
-	error = msdos_format_name(options->name_check,
-				  qstr->name, qstr->len, msdos_name,1,
-				  options->dotsOK);
-	if(error)
-		return error;
-	hash = init_name_hash();
-	for(i=0; i< MSDOS_NAME; i++)
-		hash = partial_name_hash(msdos_name[i], hash);
-	qstr->hash = end_name_hash(hash);
+	error = msdos_format_name(options->name_check, qstr->name, qstr->len,
+					msdos_name, 1, options->dotsOK);
+	if (!error)
+		qstr->hash = full_name_hash(msdos_name, MSDOS_NAME);
 	return 0;
 }
 
-
-static int msdos_cmp(struct dentry *dentry,       
-		     struct qstr *a, struct qstr *b)
+/*
+ * Compare two msdos names. If either of the names are invalid,
+ * we fall back to doing the standard name comparison.
+ */
+static int msdos_cmp(struct dentry *dentry, struct qstr *a, struct qstr *b)
 {
-	char a_msdos_name[MSDOS_NAME],b_msdos_name[MSDOS_NAME];
+	struct fat_mount_options *options = & (MSDOS_SB(dentry->d_sb)->options);
 	int error;
-	struct fat_mount_options *options = 
-		& (MSDOS_SB(dentry->d_inode->i_sb)->options);
+	char a_msdos_name[MSDOS_NAME], b_msdos_name[MSDOS_NAME];
 
-	error = msdos_format_name(options->name_check,
-				  a->name, a->len, a_msdos_name,1,
-				  options->dotsOK);
-	if(error)
-		return error;
-	error = msdos_format_name(options->name_check,
-				  b->name, b->len, b_msdos_name,1,
-				  options->dotsOK);
-	if(error)
-		return error;
-
-	return memcmp(a_msdos_name, b_msdos_name, MSDOS_NAME);
+	error = msdos_format_name(options->name_check, a->name, a->len,
+					a_msdos_name, 1, options->dotsOK);
+	if (error)
+		goto old_compare;
+	error = msdos_format_name(options->name_check, b->name, b->len,
+					b_msdos_name, 1, options->dotsOK);
+	if (error)
+		goto old_compare;
+	error = memcmp(a_msdos_name, b_msdos_name, MSDOS_NAME);
+out:
+	return error;
+
+old_compare:
+	error = 1;
+	if (a->len == b->len)
+		error = memcmp(a->name, b->name, a->len);
+	goto out;
 }
 
 
 static struct dentry_operations msdos_dentry_operations = {
-	0, 		/* d_revalidate */
+	NULL, 		/* d_revalidate */
 	msdos_hash,
-	msdos_cmp
+	msdos_cmp,
+	NULL		/* d_delete */
 };
 
 struct super_block *msdos_read_super(struct super_block *sb,void *data, int silent)
@@ -233,14 +237,16 @@
 
 	MSDOS_SB(sb)->options.isvfat = 0;
 	sb->s_op = &msdos_sops;
-	res =  fat_read_super(sb, data, silent);
-	if (res == NULL) {
-		sb->s_dev = 0;
-		MOD_DEC_USE_COUNT;
-		return NULL;
-	}
+	res = fat_read_super(sb, data, silent);
+	if (res == NULL)
+		goto out_fail;
 	sb->s_root->d_op = &msdos_dentry_operations;
 	return res;
+
+out_fail:
+	sb->s_dev = 0;
+	MOD_DEC_USE_COUNT;
+	return NULL;
 }
 
 
@@ -290,11 +296,14 @@
 	PRINTK (("msdos_lookup 6\n"));
 	while (MSDOS_I(inode)->i_old) {
 		next = MSDOS_I(inode)->i_old;
+#ifdef MSDOS_PARANOIA
+printk("msdos_lookup: ino %ld, old ino=%ld\n", inode->i_ino, next->i_ino);
+if (MSDOS_I(next)->i_depend != inode)
+printk("msdos_lookup: depend=%p, inode=%p??\n", MSDOS_I(next)->i_depend, inode);
+#endif
+		next->i_count++;
 		iput(inode);
-		if (!(inode = iget(next->i_sb,next->i_ino))) {
-			fat_fs_panic(dir->i_sb,"msdos_lookup: Can't happen");
-			return -ENOENT; /* N.B. Maybe ENOMEM is better? */
-		}
+		inode = next;
 	}
 	PRINTK (("msdos_lookup 7\n"));
 	d_add(dentry, inode);
diff -u --recursive --new-file v2.1.72/linux/fs/namei.c linux/fs/namei.c
--- v2.1.72/linux/fs/namei.c	Wed Dec 10 11:12:44 1997
+++ linux/fs/namei.c	Wed Dec 17 11:01:35 1997
@@ -73,6 +73,10 @@
  * and in the old Linux semantics.
  */
 
+/* [16-Dec-97 Kevin Buhr] For security reasons, we change some symlink
+ * semantics.  See the comments in "open_namei" and "do_link" below.
+ */
+
 static char * quicklist = NULL;
 static int quickcount = 0;
 struct semaphore quicklock = MUTEX;
@@ -530,7 +534,13 @@
 	mode &= S_IALLUGO & ~current->fs->umask;
 	mode |= S_IFREG;
 
-	dentry = lookup_dentry(pathname, NULL, 1);
+	/* 
+	 * Special case: O_CREAT|O_EXCL on a dangling symlink should
+	 * give EEXIST for security reasons.  While inconsistent, this
+	 * is the same scheme used by, for example, Solaris 2.5.1.  --KAB
+	 */
+	dentry = lookup_dentry(pathname, NULL,
+			       (flag & (O_CREAT|O_EXCL)) != (O_CREAT|O_EXCL));
 	if (IS_ERR(dentry))
 		return dentry;
 
@@ -731,7 +741,7 @@
 	struct dentry *dir;
 	struct dentry *dentry;
 
-	dentry = lookup_dentry(pathname, NULL, 1);
+	dentry = lookup_dentry(pathname, NULL, 0);
 	error = PTR_ERR(dentry);
 	if (IS_ERR(dentry))
 		goto exit;
@@ -1010,7 +1020,16 @@
 	if (IS_ERR(old_dentry))
 		goto exit;
 
-	new_dentry = lookup_dentry(newname, NULL, 1);
+	/*
+	 * Hardlinks are often used in delicate situations.  We avoid
+	 * security-related surprises by not following symlinks on the
+	 * newname.  We *do* follow them on the oldname.  This is
+	 * the same as Digital Unix 4.0, for example.
+	 *
+	 * Solaris 2.5.1 is similar, but for a laugh try linking from
+	 * a dangling symlink.                              --KAB
+	 */
+	new_dentry = lookup_dentry(newname, NULL, 0);
 	error = PTR_ERR(new_dentry);
 	if (IS_ERR(new_dentry))
 		goto exit_old;
diff -u --recursive --new-file v2.1.72/linux/fs/nfs/dir.c linux/fs/nfs/dir.c
--- v2.1.72/linux/fs/nfs/dir.c	Wed Dec 10 11:12:44 1997
+++ linux/fs/nfs/dir.c	Fri Dec 12 09:17:09 1997
@@ -471,11 +471,11 @@
 
 static int nfs_lookup(struct inode *dir, struct dentry * dentry)
 {
+	int len = dentry->d_name.len;
 	struct inode *inode;
+	int error;
 	struct nfs_fh fhandle;
 	struct nfs_fattr fattr;
-	int len = dentry->d_name.len;
-	int error;
 
 	dfprintk(VFS, "NFS: lookup(%x/%ld, %.*s)\n",
 			dir->i_dev, dir->i_ino, len, dentry->d_name.name);
@@ -516,10 +516,38 @@
 }
 
 /*
+ * Attempt to patch up certain errors following a create or
+ * mkdir operation. We clear the original error if the new
+ * lookup succeeds and has the correct mode.
+ */
+static int nfs_fixup(struct inode *dir, struct dentry *dentry, int mode,
+		struct nfs_fh *fhandle, struct nfs_fattr *fattr, int error)
+{
+	int newerr;
+
+#ifdef NFS_PARANOIA
+printk("nfs_fixup: %s/%s, error=%d, mode=%x\n",
+dentry->d_parent->d_name.name, dentry->d_name.name, error, mode);
+#endif
+	if (error == -EEXIST) {
+		newerr = nfs_proc_lookup(NFS_SERVER(dir), NFS_FH(dir), 
+					dentry->d_name.name, fhandle, fattr);
+		if (!newerr) {
+#ifdef NFS_PARANOIA
+printk("nfs_fixup: lookup OK, got mode=%x, want mode=%x\n", fattr->mode, mode);
+#endif
+			if ((fattr->mode & S_IFMT) == (mode & S_IFMT))
+				error = 0;
+		}
+	}
+	return error;
+}
+
+/*
  * Code common to create, mkdir, and mknod.
  */
-static int nfs_instantiate(struct dentry *dentry, struct nfs_fattr *fattr,
-				struct nfs_fh *fhandle)
+static int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fhandle,
+				struct nfs_fattr *fattr)
 {
 	struct inode *inode;
 	int error = -EACCES;
@@ -545,12 +573,12 @@
  * that the operation succeeded on the server, but an error in the
  * reply path made it appear to have failed.
  */
-static int nfs_create(struct inode *dir, struct dentry * dentry, int mode)
+static int nfs_create(struct inode *dir, struct dentry *dentry, int mode)
 {
+	int error;
 	struct nfs_sattr sattr;
 	struct nfs_fattr fattr;
 	struct nfs_fh fhandle;
-	int error;
 
 	dfprintk(VFS, "NFS: create(%x/%ld, %s\n",
 				dir->i_dev, dir->i_ino, dentry->d_name.name);
@@ -574,9 +602,11 @@
 	nfs_invalidate_dircache(dir);
 	error = nfs_proc_create(NFS_SERVER(dir), NFS_FH(dir),
 			dentry->d_name.name, &sattr, &fhandle, &fattr);
+	if (error)
+		error = nfs_fixup(dir, dentry, mode, &fhandle, &fattr, error);
 	if (!error)
-		error = nfs_instantiate(dentry, &fattr, &fhandle);
-	else
+		error = nfs_instantiate(dentry, &fhandle, &fattr);
+	if (error)
 		d_drop(dentry);
 out:
 	return error;
@@ -587,10 +617,10 @@
  */
 static int nfs_mknod(struct inode *dir, struct dentry *dentry, int mode, int rdev)
 {
+	int error;
 	struct nfs_sattr sattr;
 	struct nfs_fattr fattr;
 	struct nfs_fh fhandle;
-	int error;
 
 	dfprintk(VFS, "NFS: mknod(%x/%ld, %s\n",
 				dir->i_dev, dir->i_ino, dentry->d_name.name);
@@ -612,9 +642,11 @@
 	nfs_invalidate_dircache(dir);
 	error = nfs_proc_create(NFS_SERVER(dir), NFS_FH(dir),
 				dentry->d_name.name, &sattr, &fhandle, &fattr);
+	if (error)
+		error = nfs_fixup(dir, dentry, mode, &fhandle, &fattr, error);
 	if (!error)
-		error = nfs_instantiate(dentry, &fattr, &fhandle);
-	else
+		error = nfs_instantiate(dentry, &fhandle, &fattr);
+	if (error)
 		d_drop(dentry);
 	return error;
 }
@@ -624,10 +656,10 @@
  */
 static int nfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
 {
+	int error;
 	struct nfs_sattr sattr;
 	struct nfs_fattr fattr;
 	struct nfs_fh fhandle;
-	int error;
 
 	dfprintk(VFS, "NFS: mkdir(%x/%ld, %s\n",
 				dir->i_dev, dir->i_ino, dentry->d_name.name);
@@ -640,6 +672,8 @@
 	if (dentry->d_name.len > NFS_MAXNAMLEN)
 		return -ENAMETOOLONG;
 
+	/* For some reason mode doesn't have the S_IFDIR flag ... */
+	mode |= S_IFDIR;
 	sattr.mode = mode;
 	sattr.uid = sattr.gid = sattr.size = (unsigned) -1;
 	sattr.atime.seconds = sattr.mtime.seconds = (unsigned) -1;
@@ -647,6 +681,8 @@
 	nfs_invalidate_dircache(dir);
 	error = nfs_proc_mkdir(NFS_SERVER(dir), NFS_FH(dir),
 				dentry->d_name.name, &sattr, &fhandle, &fattr);
+	if (error)
+		error = nfs_fixup(dir, dentry, mode, &fhandle, &fattr, error);
 	if (!error) {
 		/*
 		 * Some AIX servers reportedly fail to fill out the fattr.
@@ -660,8 +696,9 @@
 					fattr.mode);
 			goto drop;
 		}
-		error = nfs_instantiate(dentry, &fattr, &fhandle);
-	} else {
+		error = nfs_instantiate(dentry, &fhandle, &fattr);
+	}
+	if (error) {
 	drop:
 		d_drop(dentry);
 	}
@@ -858,11 +895,8 @@
  * Remove a file after making sure there are no pending writes,
  * and after checking that the file has only one user. 
  *
- * Updating inode->i_nlink here rather than waiting for the next
- * nfs_refresh_inode() is not merely cosmetic; once an object has
- * been deleted, we want to get rid of the inode locally.  The NFS
- * server may reuse the fileid for a new inode, and we don't want
- * that to be confused with this inode.
+ * We update inode->i_nlink and free the inode prior to the operation
+ * to avoid possible races if the server reuses the inode.
  */
 static int nfs_safe_remove(struct dentry *dentry)
 {
@@ -870,6 +904,7 @@
 	struct inode *inode = dentry->d_inode;
 	int error, rehash = 0;
 		
+	/* N.B. not needed now that d_delete is done in advance? */
 	error = -EBUSY;
 	if (inode) {
 		if (NFS_WRITEBACK(inode)) {
@@ -897,7 +932,7 @@
 		goto out;
 	}
 #ifdef NFS_PARANOIA
-if (inode && inode->i_count > 1)
+if (inode && inode->i_count > inode->i_nlink)
 printk("nfs_safe_remove: %s/%s inode busy?? i_count=%d, i_nlink=%d\n",
 dentry->d_parent->d_name.name, dentry->d_name.name,
 inode->i_count, inode->i_nlink);
diff -u --recursive --new-file v2.1.72/linux/fs/nfs/inode.c linux/fs/nfs/inode.c
--- v2.1.72/linux/fs/nfs/inode.c	Mon Nov 17 18:47:22 1997
+++ linux/fs/nfs/inode.c	Fri Dec 12 09:17:09 1997
@@ -35,9 +35,6 @@
 #define NFSDBG_FACILITY		NFSDBG_VFS
 #define NFS_PARANOIA 1
 
-extern void nfs_invalidate_dircache_sb(struct super_block *);
-extern int  check_failed_request(struct inode *);
-
 static void nfs_read_inode(struct inode *);
 static void nfs_put_inode(struct inode *);
 static void nfs_delete_inode(struct inode *);
@@ -99,8 +96,9 @@
 	 */
 	if (NFS_WRITEBACK(inode) != NULL) {
 		unsigned long timeout = jiffies + 5*HZ;
-		printk("NFS: inode %ld, invalidating pending RPC requests\n",
-			inode->i_ino);
+#ifdef NFS_DEBUG_VERBOSE
+printk("nfs_delete_inode: inode %ld has pending RPC requests\n", inode->i_ino);
+#endif
 		nfs_invalidate_pages(inode);
 		while (NFS_WRITEBACK(inode) != NULL && jiffies < timeout) {
 			current->state = TASK_INTERRUPTIBLE;
@@ -112,7 +110,7 @@
 			printk("NFS: Arghhh, stuck RPC requests!\n");
 	}
 
-	failed = check_failed_request(inode);
+	failed = nfs_check_failed_request(inode);
 	if (failed)
 		printk("NFS: inode %ld had %d failed requests\n",
 			inode->i_ino, failed);
@@ -355,8 +353,6 @@
  * instead of inode number.  We use this technique instead of using
  * the vfs read_inode function because there is no way to pass the
  * file handle or current attributes into the read_inode function.
- * We just have to be careful not to subvert iget's special handling
- * of mount points.
  */
 struct inode *
 nfs_fhget(struct super_block *sb, struct nfs_fh *fhandle,
@@ -422,8 +418,10 @@
 		inode->i_size  = fattr->size;
 		inode->i_mtime = fattr->mtime.seconds;
 		NFS_OLDMTIME(inode) = fattr->mtime.seconds;
+		*NFS_FH(inode) = *fhandle;
 	}
-	*NFS_FH(inode) = *fhandle;
+	if (memcmp(NFS_FH(inode), fhandle, sizeof(struct nfs_fh)))
+		printk("nfs_fhget: fhandle changed!\n");
 	nfs_refresh_inode(inode, fattr);
 	dprintk("NFS: fhget(%x/%ld ct=%d)\n",
 		inode->i_dev, inode->i_ino,
diff -u --recursive --new-file v2.1.72/linux/fs/nfs/write.c linux/fs/nfs/write.c
--- v2.1.72/linux/fs/nfs/write.c	Sat Nov  1 11:04:27 1997
+++ linux/fs/nfs/write.c	Fri Dec 12 09:17:09 1997
@@ -68,8 +68,6 @@
 
 #define NFSDBG_FACILITY		NFSDBG_PAGECACHE
 
-int check_failed_request(struct inode *);
-
 static void			nfs_wback_lock(struct rpc_task *task);
 static void			nfs_wback_result(struct rpc_task *task);
 
@@ -331,7 +329,7 @@
  * Find and release all failed requests for this inode.
  */
 int
-check_failed_request(struct inode * inode)
+nfs_check_failed_request(struct inode * inode)
 {
 	struct nfs_wreq * req;
 	int found = 0;
@@ -496,8 +494,7 @@
 	}
 	remove_wait_queue(&page->wait, &wait);
 	current->state = TASK_RUNNING;
-	if (atomic_read(&page->count) == 1)
-		printk("NFS: page unused while waiting\n");
+	/* N.B. page may have been unused, so we must use free_page() */
 	free_page(page_address(page));
 	return retval;
 }
diff -u --recursive --new-file v2.1.72/linux/fs/nfsd/vfs.c linux/fs/nfsd/vfs.c
--- v2.1.72/linux/fs/nfsd/vfs.c	Wed Dec 10 11:12:45 1997
+++ linux/fs/nfsd/vfs.c	Wed Dec 10 09:15:30 1997
@@ -62,7 +62,8 @@
 struct raparms {
 	struct raparms		*p_next;
 	unsigned int		p_count;
-	struct dentry		*p_dentry;
+	ino_t			p_ino;
+	dev_t			p_dev;
 	unsigned long		p_reada,
 				p_ramax,
 				p_raend,
@@ -316,29 +317,27 @@
 }
 
 /*
- * Obtain the readahead parameters for the given file
- *
- * N.B. is raparm cache for a file cleared when the file closes??
- * (dentry might be reused later.)
+ * Obtain the readahead parameters for the file
+ * specified by (dev, ino).
  */
 static inline struct raparms *
-nfsd_get_raparms(struct dentry *dentry)
+nfsd_get_raparms(dev_t dev, ino_t ino)
 {
 	struct raparms	*ra, **rap, **frap = NULL;
 
 	for (rap = &raparm_cache; (ra = *rap); rap = &ra->p_next) {
-		if (ra->p_dentry != dentry) {
-			if (ra->p_count == 0)
-				frap = rap;
-		} else
+		if (ra->p_ino == ino && ra->p_dev == dev)
 			goto found;
+		if (ra->p_count == 0)
+			frap = rap;
 	}
 	if (!frap)
 		return NULL;
 	rap = frap;
 	ra = *frap;
 	memset(ra, 0, sizeof(*ra));
-	ra->p_dentry = dentry;
+	ra->p_dev = dev;
+	ra->p_ino = ino;
 found:
 	if (rap != &raparm_cache) {
 		*rap = ra->p_next;
@@ -359,23 +358,20 @@
 						unsigned long *count)
 {
 	struct raparms	*ra;
-	struct dentry	*dentry;
-	struct inode	*inode;
-	struct file	file;
 	mm_segment_t	oldfs;
 	int		err;
+	struct file	file;
 
-	if ((err = nfsd_open(rqstp, fhp, S_IFREG, OPEN_READ, &file)) != 0)
-		return err;
-	dentry = file.f_dentry;
-	inode = dentry->d_inode;
-	if (!file.f_op->read) {
-		nfsd_close(&file);
-		return nfserr_perm;
-	}
+	err = nfsd_open(rqstp, fhp, S_IFREG, OPEN_READ, &file);
+	if (err)
+		goto out;
+	err = nfserr_perm;
+	if (!file.f_op->read)
+		goto out_close;
 
 	/* Get readahead parameters */
-	if ((ra = nfsd_get_raparms(dentry)) != NULL) {
+	ra = nfsd_get_raparms(fhp->fh_handle.fh_dev, fhp->fh_handle.fh_ino);
+	if (ra) {
 		file.f_reada = ra->p_reada;
 		file.f_ramax = ra->p_ramax;
 		file.f_raend = ra->p_raend;
@@ -401,12 +397,15 @@
 		ra->p_count -= 1;
 	}
 
+	if (err >= 0) {
+		*count = err;
+		err = 0;
+	} else 
+		err = nfserrno(-err);
+out_close:
 	nfsd_close(&file);
-
-	if (err < 0)
-		return nfserrno(-err);
-	*count = err;
-	return 0;
+out:
+	return err;
 }
 
 /*
@@ -423,16 +422,16 @@
 	struct dentry		*dentry;
 	struct inode		*inode;
 	mm_segment_t		oldfs;
-	int			err;
+	int			err = 0;
 
 	if (!cnt)
-		return 0;
-	if ((err = nfsd_open(rqstp, fhp, S_IFREG, OPEN_WRITE, &file)) != 0)
-		return err;
-	if (!file.f_op->write) {
-		nfsd_close(&file);
-		return nfserr_perm;
-	}
+		goto out;
+	err = nfsd_open(rqstp, fhp, S_IFREG, OPEN_WRITE, &file);
+	if (err)
+		goto out;
+	err = nfserr_perm;
+	if (!file.f_op->write)
+		goto out_close;
 
 	dentry = file.f_dentry;
 	inode = dentry->d_inode;
@@ -507,10 +506,15 @@
 		last_dev = inode->i_dev;
 	}
 
-	nfsd_close(&file);
-
 	dprintk("nfsd: write complete\n");
-	return (err < 0)? nfserrno(-err) : 0;
+	if (err >= 0)
+		err = 0;
+	else 
+		err = nfserrno(-err);
+out_close:
+	nfsd_close(&file);
+out:
+	return err;
 }
 
 /*
@@ -824,20 +828,27 @@
 	return err;
 }
 
-/* More "hidden treasure" from the generic VFS. -DaveM */
-/* N.B. VFS double_down was modified to fix a bug ... should use VFS one */
+/*
+ * This follows the model of double_lock() in the VFS.
+ */
 static inline void nfsd_double_down(struct semaphore *s1, struct semaphore *s2)
 {
-	if((unsigned long) s1 < (unsigned long) s2) {
-		down(s1);
-		down(s2);
-	} else if(s1 == s2) {
-		down(s1);
-		atomic_dec(&s1->count);
-	} else {
-		down(s2);
+	if (s1 != s2) {
+		if ((unsigned long) s1 < (unsigned long) s2) {
+			struct semaphore *tmp = s1;
+			s1 = s2;
+			s2 = tmp;
+		}
 		down(s1);
 	}
+	down(s2);
+}
+
+static inline void nfsd_double_up(struct semaphore *s1, struct semaphore *s2)
+{
+	up(s1);
+	if (s1 != s2)
+		up(s2);
 }
 
 /*
@@ -866,43 +877,47 @@
 	tdir = tdentry->d_inode;
 
 	/* N.B. We shouldn't need this ... dentry layer handles it */
+	err = nfserr_perm;
 	if (!flen || (fname[0] == '.' && 
 	    (flen == 1 || (flen == 2 && fname[1] == '.'))) ||
 	    !tlen || (tname[0] == '.' && 
 	    (tlen == 1 || (tlen == 2 && tname[1] == '.'))))
-		return nfserr_perm;
+		goto out;
+
+	err = -EXDEV;
+	if (fdir->i_dev != tdir->i_dev)
+		goto out_nfserr;
+	err = -EPERM;
+	if (!fdir->i_op || !fdir->i_op->rename)
+		goto out_nfserr;
 
 	odentry = lookup_dentry(fname, dget(fdentry), 0);
 	err = PTR_ERR(odentry);
 	if (IS_ERR(odentry))
-		goto out_no_unlock;
+		goto out_nfserr;
 
 	ndentry = lookup_dentry(tname, dget(tdentry), 0);
 	err = PTR_ERR(ndentry);
 	if (IS_ERR(ndentry))
 		goto out_dput_old;
 
-	/* N.B. check this ... problems in locking?? */
+	/*
+	 * Lock the parent directories.
+	 */
 	nfsd_double_down(&tdir->i_sem, &fdir->i_sem);
-	err = -EXDEV;
-	if (fdir->i_dev != tdir->i_dev)
-		goto out_unlock;
-	err = -EPERM;
-	if (!fdir->i_op || !fdir->i_op->rename)
-		goto out_unlock;
+	/* N.B. check for parent changes after locking?? */
+
 	err = fdir->i_op->rename(fdir, odentry, tdir, ndentry);
 	if (!err && EX_ISSYNC(tfhp->fh_export)) {
 		write_inode_now(fdir);
 		write_inode_now(tdir);
 	}
-out_unlock:
-	up(&tdir->i_sem);
-	up(&fdir->i_sem);
-
+	nfsd_double_up(&tdir->i_sem, &fdir->i_sem);
 	dput(ndentry);
+
 out_dput_old:
 	dput(odentry);
-out_no_unlock:
+out_nfserr:
 	if (err)
 		err = nfserrno(-err);
 out:
diff -u --recursive --new-file v2.1.72/linux/fs/proc/generic.c linux/fs/proc/generic.c
--- v2.1.72/linux/fs/proc/generic.c	Sat Oct 25 02:44:18 1997
+++ linux/fs/proc/generic.c	Wed Dec 17 11:11:16 1997
@@ -154,7 +154,7 @@
 			break;
 		}
 		
-		n -= copy_to_user(buf, start, n);
+		n -= copy_to_user(buf, start, n);	/* BUG ??? */
 		if (n == 0) {
 			if (retval == 0)
 				retval = -EFAULT;
diff -u --recursive --new-file v2.1.72/linux/fs/smbfs/dir.c linux/fs/smbfs/dir.c
--- v2.1.72/linux/fs/smbfs/dir.c	Wed Nov 26 16:24:03 1997
+++ linux/fs/smbfs/dir.c	Thu Dec 11 11:25:54 1997
@@ -85,7 +85,18 @@
 	struct dentry * dentry;
 	ino_t ino = 0;
 
+	/*
+	 * Check for a fs-specific hash function. Note that we must
+	 * calculate the standard hash first, as the d_op->d_hash()
+	 * routine may choose to leave the hash value unchanged.
+	 */
 	name->hash = full_name_hash(name->name, name->len);
+	if (dir->d_op && dir->d_op->d_hash)
+	{
+		if (dir->d_op->d_hash(dir, name) != 0)
+			goto out;
+	}
+
 	dentry = d_lookup(dir, name);
 	if (dentry)
 	{
@@ -93,6 +104,7 @@
 			ino = dentry->d_inode->i_ino;
 		dput(dentry);
 	}
+out:
 	return ino;
 }
 
@@ -179,27 +191,51 @@
 	return result;
 }
 
+/*
+ * Note: in order to allow the smbclient process to open the
+ * mount point, we don't revalidate for the connection pid.
+ */
 static int
 smb_dir_open(struct inode *dir, struct file *file)
 {
+	struct dentry *dentry = file->f_dentry;
+	struct smb_sb_info *server = server_from_dentry(dentry);
+	int error = 0;
 #ifdef SMBFS_DEBUG_VERBOSE
-printk("smb_dir_open: (%s/%s)\n", file->f_dentry->d_parent->d_name.name, 
+printk("smb_dir_open: (%s/%s)\n", dentry->d_parent->d_name.name, 
 file->f_dentry->d_name.name);
 #endif
-	return smb_revalidate_inode(dir);
+	/*
+	 * Directory timestamps in the core protocol aren't updated
+	 * when a file is added, so we give them a very short TTL.
+	 */
+	if (server->opt.protocol < SMB_PROTOCOL_LANMAN2)
+	{
+		unsigned long age = jiffies - dir->u.smbfs_i.oldmtime;
+		if (age > 2*HZ)
+			smb_invalid_dir_cache(dir);
+	}
+
+	if (server->conn_pid)
+		error = smb_revalidate_inode(dir);
+	else
+		printk("smb_dir_open: smbclient process\n");
+	return error;
 }
 
 /*
  * Dentry operations routines
  */
 static int smb_lookup_validate(struct dentry *);
+static int smb_hash_dentry(struct dentry *, struct qstr *);
+static int smb_compare_dentry(struct dentry *, struct qstr *, struct qstr *);
 static void smb_delete_dentry(struct dentry *);
 
 static struct dentry_operations smbfs_dentry_operations =
 {
 	smb_lookup_validate,	/* d_validate(struct dentry *) */
-	NULL,			/* d_hash */
-	NULL,			/* d_compare */
+	smb_hash_dentry,	/* d_hash */
+	smb_compare_dentry,	/* d_compare */
 	smb_delete_dentry	/* d_delete(struct dentry *) */
 };
 
@@ -218,7 +254,7 @@
 	 * we believe in dentries for 5 seconds.  (But each
 	 * successful server lookup renews the timestamp.)
 	 */
-	valid = (age <= SMBFS_MAX_AGE) || IS_ROOT(dentry);
+	valid = (age <= SMBFS_MAX_AGE);
 #ifdef SMBFS_DEBUG_VERBOSE
 if (!valid)
 printk("smb_lookup_validate: %s/%s not valid, age=%lu\n", 
@@ -234,7 +270,8 @@
 dentry->d_parent->d_name.name, dentry->d_name.name);
 #endif
 			valid = 0;
-		}
+		} else if (!valid)
+			valid = (smb_revalidate_inode(inode) == 0);
 	} else
 	{
 	/*
@@ -245,21 +282,49 @@
 }
 
 /*
+ * XXX: It would be better to use the tolower from linux/ctype.h,
+ * but _ctype is needed and it is not exported.
+ */
+#define tolower(c) (((c) >= 'A' && (c) <= 'Z') ? (c)-('A'-'a') : (c))
+
+static int 
+smb_hash_dentry(struct dentry *dir, struct qstr *this)
+{
+	unsigned long hash;
+	int i;
+
+	hash = init_name_hash();
+	for (i=0; i < this->len ; i++)
+		hash = partial_name_hash(tolower(this->name[i]), hash);
+	this->hash = end_name_hash(hash);
+  
+	return 0;
+}
+
+static int
+smb_compare_dentry(struct dentry *dir, struct qstr *a, struct qstr *b)
+{
+	int i, result = 1;
+
+	if (a->len != b->len)
+		goto out;
+	for (i=0; i < a->len; i++)
+	{
+		if (tolower(a->name[i]) != tolower(b->name[i]))
+			goto out;
+	}
+	result = 0;
+out:
+	return result;
+}
+
+/*
  * This is the callback from dput() when d_count is going to 0.
  * We use this to unhash dentries with bad inodes and close files.
  */
 static void
 smb_delete_dentry(struct dentry * dentry)
 {
-	if ((jiffies - dentry->d_time) > SMBFS_MAX_AGE)
-	{
-#ifdef SMBFS_DEBUG_VERBOSE
-printk("smb_delete_dentry: %s/%s expired, d_time=%lu, now=%lu\n", 
-dentry->d_parent->d_name.name, dentry->d_name.name, dentry->d_time, jiffies);
-#endif
-		d_drop(dentry);
-	}
-
 	if (dentry->d_inode)
 	{
 		if (is_bad_inode(dentry->d_inode))
@@ -305,7 +370,7 @@
 	if (dentry->d_name.len > SMB_MAXNAMELEN)
 		goto out;
 
-	error = smb_proc_getattr(dentry->d_parent, &(dentry->d_name), &finfo);
+	error = smb_proc_getattr(dentry, &finfo);
 #ifdef SMBFS_PARANOIA
 if (error && error != -ENOENT)
 printk("smb_lookup: find %s/%s failed, error=%d\n",
@@ -350,7 +415,7 @@
 printk("smb_instantiate: file %s/%s, fileid=%u\n",
 dentry->d_parent->d_name.name, dentry->d_name.name, fileid);
 #endif
-	error = smb_proc_getattr(dentry->d_parent, &(dentry->d_name), &fattr);
+	error = smb_proc_getattr(dentry, &fattr);
 	if (error)
 		goto out_close;
 
@@ -402,9 +467,9 @@
 		goto out;
 
 	smb_invalid_dir_cache(dir);
-	error = smb_proc_create(dentry->d_parent, &(dentry->d_name), 
-				0, CURRENT_TIME, &fileid);
-	if (!error) {
+	error = smb_proc_create(dentry, 0, CURRENT_TIME, &fileid);
+	if (!error)
+	{
 		error = smb_instantiate(dentry, fileid, 1);
 	} else
 	{
@@ -428,7 +493,7 @@
 		goto out;
 
 	smb_invalid_dir_cache(dir);
-	error = smb_proc_mkdir(dentry->d_parent, &(dentry->d_name));
+	error = smb_proc_mkdir(dentry);
 	if (!error)
 	{
 		error = smb_instantiate(dentry, 0, 0);
@@ -440,17 +505,17 @@
 static int
 smb_rmdir(struct inode *dir, struct dentry *dentry)
 {
+	struct inode *inode = dentry->d_inode;
 	int error;
 
-	error = -ENAMETOOLONG;
-	if (dentry->d_name.len > SMB_MAXNAMELEN)
+	error = -ENOTDIR;
+	if (!S_ISDIR(inode->i_mode))
 		goto out;
 
 	/*
-	 * Since the dentry is holding an inode, the file
-	 * is in use, so we have to close it first.
+	 * Close the directory if it's open.
 	 */
-	smb_close(dentry->d_inode);
+	smb_close(inode);
 
 	/*
 	 * Prune any child dentries so this dentry can become negative.
@@ -463,7 +528,7 @@
  	}
 
 	smb_invalid_dir_cache(dir);
-	error = smb_proc_rmdir(dentry->d_parent, &(dentry->d_name));
+	error = smb_proc_rmdir(dentry);
 	if (!error)
 	{
 		smb_renew_times(dentry);
@@ -478,24 +543,18 @@
 {
 	int error;
 
-	error = -ENAMETOOLONG;
-	if (dentry->d_name.len > SMB_MAXNAMELEN)
-		goto out;
-
 	/*
-	 * Since the dentry is holding an inode, the file
-	 * is in use, so we have to close it first.
+	 * Close the file if it's open.
 	 */
 	smb_close(dentry->d_inode);
 
 	smb_invalid_dir_cache(dir);
-	error = smb_proc_unlink(dentry->d_parent, &(dentry->d_name));
+	error = smb_proc_unlink(dentry);
 	if (!error)
 	{
 		smb_renew_times(dentry);
 		d_delete(dentry);
 	}
-out:
 	return error;
 }
 
@@ -511,50 +570,33 @@
 		goto out;
 
 	/*
-	 * Since the old and new dentries are holding the files open,
-	 * we have to close the files first.
+	 * Close any open files, and check whether to delete the
+	 * target before attempting the rename.
 	 */
 	if (old_dentry->d_inode)
 		smb_close(old_dentry->d_inode);
 	if (new_dentry->d_inode)
-		smb_close(new_dentry->d_inode);
-
-	smb_invalid_dir_cache(old_dir);
-	smb_invalid_dir_cache(new_dir);
-	error = smb_proc_mv(old_dentry->d_parent, &(old_dentry->d_name),
-			    new_dentry->d_parent, &(new_dentry->d_name));
-	/*
-	 * If the new file exists, attempt to delete it.
-	 */
-	if (error == -EEXIST)
 	{
+		smb_close(new_dentry->d_inode);
+		error = smb_proc_unlink(new_dentry);
+		if (error)
+		{
 #ifdef SMBFS_DEBUG_VERBOSE
-printk("smb_rename: existing file %s/%s, d_count=%d\n",
-new_dentry->d_parent->d_name.name, new_dentry->d_name.name, 
-new_dentry->d_count);
-#endif
-		error = smb_proc_unlink(new_dentry->d_parent, 
-					&(new_dentry->d_name));
-#ifdef SMBFS_DEBUG_VERBOSE
-printk("smb_rename: after unlink error=%d\n", error);
+printk("smb_rename: unlink %s/%s, error=%d\n",
+new_dentry->d_parent->d_name.name, new_dentry->d_name.name, error);
 #endif
-		if (!error)
-		{
-			d_delete(new_dentry);
-			error = smb_proc_mv(old_dentry->d_parent, 
-						&(old_dentry->d_name),
-				   	    new_dentry->d_parent, 
-						&(new_dentry->d_name));
+			goto out;
 		}
+		d_delete(new_dentry);
 	}
 
-	/*
-	 * Update the dcache
-	 */
+	smb_invalid_dir_cache(old_dir);
+	smb_invalid_dir_cache(new_dir);
+	error = smb_proc_mv(old_dentry, new_dentry);
 	if (!error)
 	{
 		smb_renew_times(old_dentry);
-		smb_renew_times(new_dentry->d_parent);
+		smb_renew_times(new_dentry);
 		d_move(old_dentry, new_dentry);
 	}
 out:
diff -u --recursive --new-file v2.1.72/linux/fs/smbfs/file.c linux/fs/smbfs/file.c
--- v2.1.72/linux/fs/smbfs/file.c	Wed Nov 26 16:24:03 1997
+++ linux/fs/smbfs/file.c	Thu Dec 11 11:25:54 1997
@@ -306,9 +306,9 @@
 	ssize_t	result;
 
 #ifdef SMBFS_DEBUG_VERBOSE
-printk("smb_file_write: file %s/%s, count=%lu@%lu\n",
+printk("smb_file_write: file %s/%s, count=%lu@%lu, pages=%ld\n",
 dentry->d_parent->d_name.name, dentry->d_name.name,
-(unsigned long) count, (unsigned long) *ppos);
+(unsigned long) count, (unsigned long) *ppos, inode->i_nrpages);
 #endif
 
 	result = smb_revalidate_inode(inode);
diff -u --recursive --new-file v2.1.72/linux/fs/smbfs/inode.c linux/fs/smbfs/inode.c
--- v2.1.72/linux/fs/smbfs/inode.c	Wed Nov 26 16:24:03 1997
+++ linux/fs/smbfs/inode.c	Thu Dec 11 11:25:54 1997
@@ -55,12 +55,12 @@
 unsigned long
 smb_invent_inos(unsigned long n)
 {
-	static unsigned long ino = 1;
+	static unsigned long ino = 2;
 
 	if (ino + 2*n < ino)
 	{
 		/* wrap around */
-		ino += n;
+		ino = 2;
 	}
 	ino += n;
 	return ino;
@@ -93,6 +93,7 @@
 	memset(fattr, 0, sizeof(struct smb_fattr));
 	fattr->f_mode	= inode->i_mode;
 	fattr->f_nlink	= inode->i_nlink;
+	fattr->f_ino	= inode->i_ino;
 	fattr->f_uid	= inode->i_uid;
 	fattr->f_gid	= inode->i_gid;
 	fattr->f_rdev	= inode->i_rdev;
@@ -102,6 +103,15 @@
 	fattr->f_atime	= inode->i_atime;
 	fattr->f_blksize= inode->i_blksize;
 	fattr->f_blocks	= inode->i_blocks;
+
+	fattr->attr	= inode->u.smbfs_i.attr;
+	/*
+	 * Keep the attributes in sync with the inode permissions.
+	 */
+	if (fattr->f_mode & S_IWUSR)
+		fattr->attr &= ~aRONLY;
+	else
+		fattr->attr |= aRONLY;
 }
 
 static void
@@ -112,13 +122,22 @@
 	inode->i_uid	= fattr->f_uid;
 	inode->i_gid	= fattr->f_gid;
 	inode->i_rdev	= fattr->f_rdev;
-	inode->i_size	= fattr->f_size;
-	inode->i_mtime	= fattr->f_mtime;
 	inode->i_ctime	= fattr->f_ctime;
-	inode->i_atime	= fattr->f_atime;
 	inode->i_blksize= fattr->f_blksize;
 	inode->i_blocks = fattr->f_blocks;
 	/*
+	 * Don't change the size and mtime/atime fields
+	 * if we're writing to the file.
+	 */
+	if (!(inode->u.smbfs_i.cache_valid & SMB_F_LOCALWRITE))
+	{
+		inode->i_size  = fattr->f_size;
+		inode->i_mtime = fattr->f_mtime;
+		inode->i_atime = fattr->f_atime;
+	}
+
+	inode->u.smbfs_i.attr = fattr->attr;
+	/*
 	 * Update the "last time refreshed" field for revalidation.
 	 */
 	inode->u.smbfs_i.oldmtime = jiffies;
@@ -177,9 +196,9 @@
 	 * If this is a file opened with write permissions,
 	 * the inode will be up-to-date.
 	 */
-	if (S_ISREG(inode->i_mode) && smb_is_open(inode)) {
-		if (inode->u.smbfs_i.access == SMB_O_RDWR ||
-		    inode->u.smbfs_i.access == SMB_O_WRONLY)
+	if (S_ISREG(inode->i_mode) && smb_is_open(inode))
+	{
+		if (inode->u.smbfs_i.access != SMB_O_RDONLY)
 			goto out;
 	}
 
@@ -237,15 +256,7 @@
 		goto out;
 	}
 
-	/*
-	 * Kludge alert ... for some reason we can't get attributes
-	 * for the root directory, so just return success.
-	 */
-	error = 0;
-	if (IS_ROOT(dentry))
-		goto out;
-
-	error = smb_proc_getattr(dentry->d_parent, &(dentry->d_name), &fattr);
+	error = smb_proc_getattr(dentry, &fattr);
 	if (!error)
 	{
 		smb_renew_times(dentry);
@@ -261,12 +272,8 @@
 			 * Big trouble! The inode has become a new object,
 			 * so any operations attempted on it are invalid.
 			 *
-			 * Take a couple of steps to limit damage:
-			 * (1) Mark the inode as bad so that subsequent
-			 *     lookup validations will fail.
-			 * (2) Clear i_nlink so the inode will be released
-			 *     at iput() time. (Unhash it as well?)
-			 * We also invalidate the caches for good measure.
+			 * To limit damage, mark the inode as bad so that
+			 * subsequent lookup validations will fail.
 			 */
 #ifdef SMBFS_PARANOIA
 printk("smb_refresh_inode: %s/%s changed mode, %07o to %07o\n",
@@ -354,7 +361,7 @@
 	}
 
 	if (server->conn_pid)
-	       kill_proc(server->conn_pid, SIGTERM, 0);
+	       kill_proc(server->conn_pid, SIGTERM, 1);
 
 	kfree(server->mnt);
 	if (server->packet)
@@ -487,7 +494,8 @@
 	struct smb_sb_info *server = SMB_SERVER(inode);
 	struct dentry *dentry = inode->u.smbfs_i.dentry;
 	unsigned int mask = (S_IFREG | S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO);
-	int error, refresh = 0;
+	int error, changed, refresh = 0;
+	struct smb_fattr fattr;
 
 	error = -EIO;
 	if (!dentry)
@@ -515,14 +523,14 @@
 
 	if ((attr->ia_valid & ATTR_SIZE) != 0)
 	{
-		error = smb_open(dentry, O_WRONLY);
-		if (error)
-			goto out;
 #ifdef SMBFS_DEBUG_VERBOSE
 printk("smb_notify_change: changing %s/%s, old size=%ld, new size=%ld\n",
 dentry->d_parent->d_name.name, dentry->d_name.name,
 (long) inode->i_size, (long) attr->ia_size);
 #endif
+		error = smb_open(dentry, O_WRONLY);
+		if (error)
+			goto out;
 		error = smb_proc_trunc(server, inode->u.smbfs_i.fileid,
 					 attr->ia_size);
 		if (error)
@@ -531,31 +539,75 @@
 		 * We don't implement an i_op->truncate operation,
 		 * so we have to update the page cache here.
 		 */
-		if (attr->ia_size < inode->i_size) {
+		if (attr->ia_size < inode->i_size)
+		{
 			truncate_inode_pages(inode, attr->ia_size);
 			inode->i_size = attr->ia_size;
 		}
 		refresh = 1;
 	}
 
-	if ((attr->ia_valid & (ATTR_CTIME | ATTR_MTIME | ATTR_ATIME)) != 0)
-	{
-		struct smb_fattr fattr;
-
-		smb_get_inode_attr(inode, &fattr);
-		if ((attr->ia_valid & ATTR_CTIME) != 0)
-			fattr.f_ctime = attr->ia_ctime;
-
-		if ((attr->ia_valid & ATTR_MTIME) != 0)
-			fattr.f_mtime = attr->ia_mtime;
-
-		if ((attr->ia_valid & ATTR_ATIME) != 0)
-			fattr.f_atime = attr->ia_atime;
+	/*
+	 * Initialize the fattr and check for changed fields.
+	 * Note: CTIME under SMB is creation time rather than
+	 * change time, so we don't attempt to change it.
+	 */
+	smb_get_inode_attr(inode, &fattr);
 
-		error = smb_proc_setattr(server, dentry, &fattr);
+	changed = 0;
+	if ((attr->ia_valid & ATTR_MTIME) != 0)
+	{
+		fattr.f_mtime = attr->ia_mtime;
+		changed = 1;
+	}
+	if ((attr->ia_valid & ATTR_ATIME) != 0)
+	{
+		fattr.f_atime = attr->ia_atime;
+		/* Earlier protocols don't have an access time */
+		if (server->opt.protocol >= SMB_PROTOCOL_LANMAN2)
+			changed = 1;
+	}
+	if (changed)
+	{
+		error = smb_proc_settime(dentry, &fattr);
 		if (error)
 			goto out;
 		refresh = 1;
+	}
+
+	/*
+	 * Check for mode changes ... we're extremely limited in
+	 * what can be set for SMB servers: just the read-only bit.
+	 */
+	if ((attr->ia_valid & ATTR_MODE) != 0)
+	{
+#ifdef SMBFS_DEBUG_VERBOSE
+printk("smb_notify_change: %s/%s mode change, old=%x, new=%lx\n",
+dentry->d_parent->d_name.name, dentry->d_name.name, fattr.f_mode,attr->ia_mode);
+#endif
+		changed = 0;
+		if (attr->ia_mode & S_IWUSR)
+		{
+			if (fattr.attr & aRONLY)
+			{
+				fattr.attr &= ~aRONLY;
+				changed = 1;
+			}
+		} else
+		{
+			if (!(fattr.attr & aRONLY))
+			{
+				fattr.attr |= aRONLY;
+				changed = 1;
+			}
+		}
+		if (changed)
+		{
+			error = smb_proc_setattr(dentry, &fattr);
+			if (error)
+				goto out;
+			refresh = 1;
+		}
 	}
 	error = 0;
 
diff -u --recursive --new-file v2.1.72/linux/fs/smbfs/ioctl.c linux/fs/smbfs/ioctl.c
--- v2.1.72/linux/fs/smbfs/ioctl.c	Sat Nov  1 11:04:27 1997
+++ linux/fs/smbfs/ioctl.c	Thu Dec 11 11:25:54 1997
@@ -11,6 +11,7 @@
 #include <linux/ioctl.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
+
 #include <linux/smb_fs.h>
 #include <linux/smb_mount.h>
 
@@ -20,29 +21,33 @@
 smb_ioctl(struct inode *inode, struct file *filp,
 	  unsigned int cmd, unsigned long arg)
 {
+	struct smb_sb_info *server = SMB_SERVER(inode);
 	int result = -EINVAL;
 
 	switch (cmd)
 	{
 	case SMB_IOC_GETMOUNTUID:
-		result = put_user(SMB_SERVER(inode)->mnt->mounted_uid,
-				(uid_t *) arg);
+		result = put_user(server->mnt->mounted_uid, (uid_t *) arg);
 		break;
 
 	case SMB_IOC_NEWCONN:
 	{
 		struct smb_conn_opt opt;
 
-		if (arg == 0)
+		if (arg)
 		{
-			/* The process offers a new connection upon SIGUSR1 */
-			result = smb_offerconn(SMB_SERVER(inode));
+			result = -EFAULT;
+			if (!copy_from_user(&opt, (void *)arg, sizeof(opt)))
+				result = smb_newconn(server, &opt);
 		}
 		else
 		{
-			result = -EFAULT;
-			if (!copy_from_user(&opt, (void *)arg, sizeof(opt)))
-				result = smb_newconn(SMB_SERVER(inode), &opt);
+#if 0
+			/* obsolete option ... print a warning */
+			printk("SMBFS: ioctl deprecated, please upgrade "
+				"smbfs package\n");
+#endif
+			result = 0;
 		}
 		break;
 	}
diff -u --recursive --new-file v2.1.72/linux/fs/smbfs/proc.c linux/fs/smbfs/proc.c
--- v2.1.72/linux/fs/smbfs/proc.c	Wed Nov 26 16:24:03 1997
+++ linux/fs/smbfs/proc.c	Thu Dec 11 11:25:54 1997
@@ -38,9 +38,8 @@
 #define SMB_DIRINFO_SIZE 43
 #define SMB_STATUS_SIZE  21
 
-static int smb_proc_setfile_trans2(struct smb_sb_info *, struct inode *,
+static int smb_proc_setattr_ext(struct smb_sb_info *, struct inode *,
 				struct smb_fattr *);
-
 static inline int
 min(int a, int b)
 {
@@ -237,7 +236,6 @@
 	*date = nl_day - day_n[month - 1] + 1 + (month << 5) + (year << 9);
 }
 
-
 /*****************************************************************************/
 /*                                                                           */
 /*  Support section.                                                         */
@@ -349,7 +347,7 @@
 	return size;
 }
 
-static int
+int
 smb_errno(struct smb_sb_info *server)
 {
 	int errcls = server->rcls;
@@ -402,7 +400,7 @@
 		case 123:		/* Invalid name?? e.g. .tmp* */
 			return ENOENT;
 		case 145:		/* Win NT 4.0: non-empty directory? */
-			return EBUSY;
+			return ENOTEMPTY;
 			/* This next error seems to occur on an mv when
 			 * the destination exists */
 		case 183:
@@ -413,6 +411,7 @@
 	} else if (errcls == ERRSRV)
 		switch (error)
 		{
+		/* N.B. This is wrong ... EIO ? */
 		case ERRerror:
 			return ENFILE;
 		case ERRbadpw:
@@ -421,6 +420,13 @@
 			return EIO;
 		case ERRaccess:
 			return EACCES;
+		/*
+		 * This is a fatal error, as it means the "tree ID"
+		 * for this connection is no longer valid. We map
+		 * to a special error code and get a new connection.
+		 */
+		case ERRinvnid:
+			return EBADSLT;
 		default:
 			class = "ERRSRV";
 			goto err_unknown;
@@ -474,62 +480,54 @@
    of any use.
  * N.B. The server must be locked for this call.
  */
-
 static int
 smb_retry(struct smb_sb_info *server)
 {
-	struct wait_queue wait = { current, NULL };
-	unsigned long timeout;
-	int result = 0;
+	pid_t pid = server->conn_pid;
+	int error, result = 0;
 
 	if (server->state != CONN_INVALID)
 		goto out;
 
 	smb_close_socket(server);
 
-	if (server->conn_pid == 0)
+	if (pid == 0)
 	{
 		printk("smb_retry: no connection process\n");
 		server->state = CONN_RETRIED;
 		goto out;
 	}
 
-	kill_proc(server->conn_pid, SIGUSR1, 0);
-#if 0
+	/*
+	 * Clear the pid to enable the ioctl.
+	 */
 	server->conn_pid = 0;
-#endif
 
+	/*
+	 * Note: use the "priv" flag, as a user process may need to reconnect.
+	 */
+	error = kill_proc(pid, SIGUSR1, 1);
+	if (error)
+	{
+		printk("smb_retry: signal failed, error=%d\n", error);
+		goto out_restore;
+	}
 #ifdef SMBFS_DEBUG_VERBOSE
 printk("smb_retry: signalled pid %d, waiting for new connection\n",
 server->conn_pid);
 #endif
 	/*
-	 * Wait here for a new connection.
+	 * Wait for the new connection.
 	 */
-	timeout = jiffies + 10*HZ;
-	add_wait_queue(&server->wait, &wait);
-	while (1)
-	{
-		current->state = TASK_INTERRUPTIBLE;
-		current->timeout = jiffies + HZ;
-		if (server->state != CONN_INVALID)
-			break;
-		if (jiffies > timeout)
-		{
-			printk("smb_retry: timed out, try again later\n");
-			break;
-		}
-		if (signal_pending(current))
-		{
-			printk("smb_retry: caught signal\n");
-			break;
-		}
-		schedule();
-	}
-	remove_wait_queue(&server->wait, &wait);
+	current->timeout = jiffies + 5*HZ;
+	interruptible_sleep_on(&server->wait);
 	current->timeout = 0;
-	current->state = TASK_RUNNING;
+	if (signal_pending(current))
+		printk("smb_retry: caught signal\n");
 
+	/*
+	 * Check for a valid connection.
+	 */
 	if (server->state == CONN_VALID)
 	{
 #ifdef SMBFS_PARANOIA
@@ -538,6 +536,13 @@
 		result = 1;
 	}
 
+	/*
+	 * Restore the original pid if we didn't get a new one.
+	 */
+out_restore:
+	if (!server->conn_pid)
+		server->conn_pid = pid;
+
 out:
 	return result;
 }
@@ -599,43 +604,12 @@
 }
 
 /*
- * This is called with the server locked after a successful smb_newconn().
- * It installs the new connection pid, sets server->state to CONN_VALID,
- * and wakes up the process waiting for the new connection.
- * N.B. The first call is made without locking the server -- need to fix!
- */
-int
-smb_offerconn(struct smb_sb_info *server)
-{
-	int error;
-
-	error = -EACCES;
-	if ((current->uid != server->mnt->mounted_uid) && !suser()) 
-		goto out;
-	if (atomic_read(&server->sem.count) == 1)
-	{
-		printk("smb_offerconn: server not locked, count=%d\n",
-			atomic_read(&server->sem.count));
-#if 0
-		goto out;
-#endif
-	}
-
-	server->conn_pid = current->pid;
-	server->state = CONN_VALID;
-	wake_up_interruptible(&server->wait);
-#ifdef SMBFS_PARANOIA
-printk("smb_offerconn: state valid, pid=%d\n", server->conn_pid);
-#endif
-	error = 0;
-
-out:
-	return error;
-}
-
-/*
- * This must be called with the server locked.
- * N.B. The first call is made without locking the server -- need to fix!
+ * This implements the NEWCONN ioctl. It installs the server pid,
+ * sets server->state to CONN_VALID, and wakes up the waiting process.
+ *
+ * Note that this must be called with the server locked, except for
+ * the first call made after mounting the volume. The server pid
+ * will be set to zero to indicate that smbfs is awaiting a connection.
  */
 int
 smb_newconn(struct smb_sb_info *server, struct smb_conn_opt *opt)
@@ -643,8 +617,13 @@
 	struct file *filp;
 	int error;
 
+#ifdef SMBFS_DEBUG_VERBOSE
+printk("smb_newconn: fd=%d, pid=%d\n", opt->fd, current->pid);
+#endif
 	error = -EBADF;
-	if (opt->fd >= NR_OPEN || !(filp = current->files->fd[opt->fd]))
+	if (opt->fd < 0 || opt->fd >= NR_OPEN)
+		goto out;
+	if (!(filp = current->files->fd[opt->fd]))
 		goto out;
 	if (!smb_valid_socket(filp->f_dentry->d_inode))
 		goto out;
@@ -652,19 +631,22 @@
 	error = -EACCES;
 	if ((current->uid != server->mnt->mounted_uid) && !suser())
 		goto out;
-	if (atomic_read(&server->sem.count) == 1)
+
+	/*
+	 * Make sure we don't already have a pid ...
+	 */
+	error = -EINVAL;
+	if (server->conn_pid)
 	{
-		printk("smb_newconn: server not locked, count=%d\n",
-			atomic_read(&server->sem.count));
-#if 0
+		printk("SMBFS: invalid ioctl call\n");
 		goto out;
-#endif
 	}
+	server->conn_pid = current->pid;
 
-	/*
-	 * Make sure the old socket is closed
-	 */
-	smb_close_socket(server);
+#ifdef SMBFS_PARANOIA
+if (server->sock_file)
+printk("smb_newconn: old socket not closed!\n");
+#endif
 
 	filp->f_count += 1;
 	server->sock_file = filp;
@@ -675,9 +657,14 @@
 server->opt.protocol, server->opt.max_xmit);
 #endif
 	server->generation += 1;
+	server->state = CONN_VALID;
+#ifdef SMBFS_PARANOIA
+printk("smb_newconn: state valid, pid=%d\n", server->conn_pid);
+#endif
 	error = 0;
 
 out:
+	wake_up_interruptible(&server->wait);
 	return error;
 }
 
@@ -774,13 +761,14 @@
 		if (mode == read_write &&
 		    (error == -EACCES || error == -ETXTBSY || error == -EROFS))
 		{
-#ifdef SMBFS_PARANOIA
+#ifdef SMBFS_DEBUG_VERBOSE
 printk("smb_proc_open: %s/%s R/W failed, error=%d, retrying R/O\n",
 dentry->d_parent->d_name.name, dentry->d_name.name, error);
 #endif
 			mode = read_only;
 			goto retry;
 		}
+		goto out;
 	}
 	/* We should now have data in vwv[0..6]. */
 
@@ -788,17 +776,10 @@
 	ino->u.smbfs_i.attr   = WVAL(server->packet, smb_vwv1);
 	/* smb_vwv2 has mtime */
 	/* smb_vwv4 has size  */
-	ino->u.smbfs_i.access = WVAL(server->packet, smb_vwv6);
-	ino->u.smbfs_i.access &= SMB_ACCMASK;
-
-	/* N.B. Suppose the open failed?? */
+	ino->u.smbfs_i.access = (WVAL(server->packet, smb_vwv6) & SMB_ACCMASK);
 	ino->u.smbfs_i.open = server->generation;
 
-#ifdef SMBFS_PARANOIA
-if (error)
-printk("smb_proc_open: %s/%s failed, error=%d, access=%d\n",
-dentry->d_parent->d_name.name, dentry->d_name.name,error,ino->u.smbfs_i.access);
-#endif
+out:
 	return error;
 }
 
@@ -881,8 +862,8 @@
  *
  * Win NT 4.0 has an apparent bug in that it fails to update the
  * modify time when writing to a file. As a workaround, we update
- * the attributes if the file has been modified locally (we want to
- * keep modify and access times in sync ...)
+ * both modify and access time locally, and post the times to the
+ * server when closing the file.
  */
 static int 
 smb_proc_close_inode(struct smb_sb_info *server, struct inode * ino)
@@ -891,33 +872,32 @@
 	if (smb_is_open(ino))
 	{
 		/*
-		 * Check whether to update locally-modified attributes at
-		 * closing time. This is necessary to keep the modify and
-		 * access times in sync.
-		 *
-		 * Kludge alert: If we're using trans2 getattr messages,
-		 * the timestamps are accurate only to two seconds ...
-		 * we must round the time to avoid cache invalidations!
+		 * We clear the open flag in advance, in case another
+ 		 * process observes the value while we block below.
 		 */
-		if (ino->u.smbfs_i.access == SMB_O_RDWR ||
-		    ino->u.smbfs_i.access == SMB_O_WRONLY) {
-			struct smb_fattr fattr;
+		ino->u.smbfs_i.open = 0;
 
-			if (server->opt.protocol >= SMB_PROTOCOL_LANMAN2) {
-				if (ino->i_mtime & 1)
-					ino->i_mtime--;
-				if (ino->i_atime & 1)
-					ino->i_atime--;
-			}
+		/*
+		 * Kludge alert: SMB timestamps are accurate only to
+		 * two seconds ... round the times to avoid needless
+		 * cache invalidations!
+		 */
+		if (ino->i_mtime & 1)
+			ino->i_mtime--;
+		if (ino->i_atime & 1)
+			ino->i_atime--;
+		/*
+		 * If the file is open with write permissions,
+		 * update the time stamps to sync mtime and atime.
+		 */
+		if ((server->opt.protocol >= SMB_PROTOCOL_LANMAN2) &&
+		    !(ino->u.smbfs_i.access == SMB_O_RDONLY))
+		{
+			struct smb_fattr fattr;
 			smb_get_inode_attr(ino, &fattr);
-			smb_proc_setfile_trans2(server, ino, &fattr);
+			smb_proc_setattr_ext(server, ino, &fattr);
 		}
 
-		/*
-		 * We clear the open flag in advance, in case another
- 		 * process observes the value while we block below.
-		 */
-		ino->u.smbfs_i.open = 0;
 		result = smb_proc_close(server, ino->u.smbfs_i.fileid,
 						ino->i_mtime);
 		ino->u.smbfs_i.cache_valid &= ~SMB_F_LOCALWRITE;
@@ -1082,14 +1062,12 @@
 }
 
 int
-smb_proc_create(struct dentry *dir, struct qstr *name,
-		__u16 attr, time_t ctime, __u16 *fileid)
+smb_proc_create(struct dentry *dentry, __u16 attr, time_t ctime, __u16 *fileid)
 {
-	struct smb_sb_info *server;
+	struct smb_sb_info *server = server_from_dentry(dentry);
 	char *p;
 	int error;
 
-	server = server_from_dentry(dir);
 	smb_lock_server(server);
 
       retry:
@@ -1097,7 +1075,7 @@
 	WSET(server->packet, smb_vwv0, attr);
 	DSET(server->packet, smb_vwv1, utc2local(ctime));
 	*p++ = 4;
-	p = smb_encode_path(server, p, dir, name);
+	p = smb_encode_path(server, p, dentry, NULL);
 	smb_setup_bcc(server, p);
 
 	error = smb_request_ok(server, SMBcreate, 1, 0);
@@ -1116,23 +1094,21 @@
 }
 
 int
-smb_proc_mv(struct dentry *odir, struct qstr *oname,
-	    struct dentry *ndir, struct qstr *nname)
+smb_proc_mv(struct dentry *old_dentry, struct dentry *new_dentry)
 {
-	struct smb_sb_info *server;
+	struct smb_sb_info *server = server_from_dentry(old_dentry);
 	char *p;
 	int result;
 
-	server = server_from_dentry(odir);
 	smb_lock_server(server);
 
       retry:
 	p = smb_setup_header(server, SMBmv, 1, 0);
 	WSET(server->packet, smb_vwv0, aSYSTEM | aHIDDEN);
 	*p++ = 4;
-	p = smb_encode_path(server, p, odir, oname);
+	p = smb_encode_path(server, p, old_dentry, NULL);
 	*p++ = 4;
-	p = smb_encode_path(server, p, ndir, nname);
+	p = smb_encode_path(server, p, new_dentry, NULL);
 	smb_setup_bcc(server, p);
 
 	if ((result = smb_request_ok(server, SMBmv, 0, 0)) < 0)
@@ -1147,23 +1123,26 @@
 	return result;
 }
 
-int
-smb_proc_mkdir(struct dentry *dir, struct qstr *name)
+/*
+ * Code common to mkdir and rmdir.
+ */
+static int
+smb_proc_generic_command(struct dentry *dentry, __u8 command)
 {
-	struct smb_sb_info *server;
+	struct smb_sb_info *server = server_from_dentry(dentry);
 	char *p;
 	int result;
 
-	server = server_from_dentry(dir);
 	smb_lock_server(server);
 
       retry:
-	p = smb_setup_header(server, SMBmkdir, 0, 0);
+	p = smb_setup_header(server, command, 0, 0);
 	*p++ = 4;
-	p = smb_encode_path(server, p, dir, name);
+	p = smb_encode_path(server, p, dentry, NULL);
 	smb_setup_bcc(server, p);
 
-	if ((result = smb_request_ok(server, SMBmkdir, 0, 0)) < 0)
+	result = smb_request_ok(server, command, 0, 0);
+	if (result < 0)
 	{
 		if (smb_retry(server))
 			goto retry;
@@ -1176,48 +1155,31 @@
 }
 
 int
-smb_proc_rmdir(struct dentry *dir, struct qstr *name)
+smb_proc_mkdir(struct dentry *dentry)
 {
-	struct smb_sb_info *server;
-	char *p;
-	int result;
-
-	server = server_from_dentry(dir);
-	smb_lock_server(server);
-
-      retry:
-	p = smb_setup_header(server, SMBrmdir, 0, 0);
-	*p++ = 4;
-	p = smb_encode_path(server, p, dir, name);
-	smb_setup_bcc(server, p);
+	return smb_proc_generic_command(dentry, SMBmkdir);
+}
 
-	if ((result = smb_request_ok(server, SMBrmdir, 0, 0)) < 0)
-	{
-		if (smb_retry(server))
-			goto retry;
-		goto out;
-	}
-	result = 0;
-out:
-	smb_unlock_server(server);
-	return result;
+int
+smb_proc_rmdir(struct dentry *dentry)
+{
+	return smb_proc_generic_command(dentry, SMBrmdir);
 }
 
 int
-smb_proc_unlink(struct dentry *dir, struct qstr *name)
+smb_proc_unlink(struct dentry *dentry)
 {
-	struct smb_sb_info *server;
+	struct smb_sb_info *server = server_from_dentry(dentry);
 	char *p;
 	int result;
 
-	server = server_from_dentry(dir);
 	smb_lock_server(server);
 
       retry:
 	p = smb_setup_header(server, SMBunlink, 1, 0);
 	WSET(server->packet, smb_vwv0, aSYSTEM | aHIDDEN);
 	*p++ = 4;
-	p = smb_encode_path(server, p, dir, name);
+	p = smb_encode_path(server, p, dentry, NULL);
 	smb_setup_bcc(server, p);
 
 	if ((result = smb_request_ok(server, SMBunlink, 0, 0)) < 0)
@@ -1276,17 +1238,15 @@
 static void
 smb_finish_dirent(struct smb_sb_info *server, struct smb_fattr *fattr)
 {
+	fattr->f_mode = server->mnt->file_mode;
 	if (fattr->attr & aDIR)
 	{
-		/* N.B. check for read-only directories */
 		fattr->f_mode = server->mnt->dir_mode;
 		fattr->f_size = 512;
-	} else
-	{
-		fattr->f_mode = server->mnt->file_mode;
-		if (fattr->attr & aRONLY)
-			fattr->f_mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
 	}
+	/* Check the read-only flag */
+	if (fattr->attr & aRONLY)
+		fattr->f_mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
 
 	fattr->f_blocks = 0;
 	if ((fattr->f_blksize != 0) && (fattr->f_size != 0))
@@ -1302,7 +1262,7 @@
 {
 	smb_init_dirent(server, fattr);
 	fattr->attr = aDIR;
-	fattr->f_ino = 1;
+	fattr->f_ino = 2; /* traditional root inode number */
 	fattr->f_mtime = CURRENT_TIME;
 	smb_finish_dirent(server, fattr);
 }
@@ -1475,11 +1435,17 @@
  * Interpret a long filename structure using the specified info level:
  *   level 1   -- Win NT, Win 95, OS/2
  *   level 259 -- File name and length only, Win NT, Win 95
- * There seem to be numerous inconsistencies and bugs in implementation.
  *
  * We return a reference to the name string to avoid copying, and perform
  * any needed upper/lower casing in place.  Note!! Level 259 entries may
  * not have any space beyond the name, so don't try to write a null byte!
+ *
+ * Bugs Noted:
+ * (1) Win NT 4.0 appends a null byte to names and counts it in the length!
+ * (2) When using Info Level 1 Win NT 4.0 truncates directory listings 
+ * for certain patterns of names and/or lengths. The breakage pattern is
+ * completely reproducible and can be toggled by the addition of a single
+ * file to the directory. (E.g. echo hi >foo breaks, rm -f foo works.)
  */
 static char *
 smb_decode_long_dirent(struct smb_sb_info *server, char *p,
@@ -1791,7 +1757,7 @@
  */
 static int
 smb_proc_getattr_core(struct smb_sb_info *server, struct dentry *dir,
-			struct qstr *name, struct smb_fattr *fattr)
+			struct smb_fattr *fattr)
 {
 	int result;
 	char *p;
@@ -1799,7 +1765,7 @@
       retry:
 	p = smb_setup_header(server, SMBgetatr, 0, 0);
 	*p++ = 4;
-	p = smb_encode_path(server, p, dir, name);
+	p = smb_encode_path(server, p, dir, NULL);
 	smb_setup_bcc(server, p);
 
 	if ((result = smb_request_ok(server, SMBgetatr, 10, 0)) < 0)
@@ -1825,10 +1791,13 @@
 
 /*
  * Note: called with the server locked.
+ *
+ * Bugs Noted:
+ * (1) Win 95 swaps the date and time fields in the standard info level.
  */
 static int
 smb_proc_getattr_trans2(struct smb_sb_info *server, struct dentry *dir,
-			struct qstr *name, struct smb_fattr *attr)
+			struct smb_fattr *attr)
 {
 	char *p;
 	int result;
@@ -1843,7 +1812,7 @@
       retry:
 	WSET(param, 0, 1);	/* Info level SMB_INFO_STANDARD */
 	DSET(param, 2, 0);
-	p = smb_encode_path(server, param + 6, dir, name);
+	p = smb_encode_path(server, param + 6, dir, NULL);
 
 	result = smb_trans2_request(server, TRANSACT2_QPATHINFO,
 				    0, NULL, p - param, param,
@@ -1906,8 +1875,7 @@
 }
 
 int
-smb_proc_getattr(struct dentry *dir, struct qstr *name,
-		     struct smb_fattr *fattr)
+smb_proc_getattr(struct dentry *dir, struct smb_fattr *fattr)
 {
 	struct smb_sb_info *server = server_from_dentry(dir);
 	int result;
@@ -1921,9 +1889,9 @@
  	 */
 	if (server->opt.protocol >= SMB_PROTOCOL_LANMAN2 &&
 	    !(server->mnt->version & SMB_FIX_OLDATTR))
-		result = smb_proc_getattr_trans2(server, dir, name, fattr);
+		result = smb_proc_getattr_trans2(server, dir, fattr);
 	else
-		result = smb_proc_getattr_core(server, dir, name, fattr);
+		result = smb_proc_getattr_core(server, dir, fattr);
 
 	smb_finish_dirent(server, fattr);
 
@@ -1932,35 +1900,42 @@
 }
 
 /*
- * In the core protocol there is only one time to be set,
- * so we use fattr->f_mtime to make `touch' work.
- * Note: called with the server locked.
+ * Called with the server locked. Because of bugs in the
+ * core protocol, we use this only to set attributes. See
+ * smb_proc_settime() below for timestamp handling.
+ *
+ * Bugs Noted:
+ * (1) If mtime is non-zero, both Win 3.1 and Win 95 fail
+ * with an undocumented error (ERRDOS code 50). Setting
+ * mtime to 0 allows the attributes to be set.
+ * (2) The extra parameters following the name string aren't
+ * in the CIFS docs, but seem to be necessary for operation.
  */
 static int
-smb_proc_setattr_core(struct smb_sb_info *server,
-		      struct dentry *dir, struct smb_fattr *fattr)
+smb_proc_setattr_core(struct smb_sb_info *server, struct dentry *dentry,
+			__u16 attr)
 {
 	char *p;
-	char *buf;
 	int result;
 
-#ifdef SMBFS_DEBUG_TIMESTAMP
-printk("setattr_core: %s/%s, mtime=%ld\n", 
-dir->d_parent->d_name.name, dir->d_name.name, fattr->f_mtime);
-#endif
-
       retry:
-	buf = server->packet;
 	p = smb_setup_header(server, SMBsetatr, 8, 0);
-	WSET(buf, smb_vwv0, fattr->attr);
-	DSET(buf, smb_vwv1, utc2local(fattr->f_mtime));
-	WSET(buf, smb_vwv3, 0); /* reserved values */
-	WSET(buf, smb_vwv4, 0);
-	WSET(buf, smb_vwv5, 0);
-	WSET(buf, smb_vwv6, 0);
-	WSET(buf, smb_vwv7, 0);
+	WSET(server->packet, smb_vwv0, attr);
+	DSET(server->packet, smb_vwv1, 0); /* mtime */
+	WSET(server->packet, smb_vwv3, 0); /* reserved values */
+	WSET(server->packet, smb_vwv4, 0);
+	WSET(server->packet, smb_vwv5, 0);
+	WSET(server->packet, smb_vwv6, 0);
+	WSET(server->packet, smb_vwv7, 0);
 	*p++ = 4;
-	p = smb_encode_path(server, p, dir, NULL);
+	/*
+	 * Samba uses three leading '\', so we'll do it too.
+	 */
+	*p++ = '\\';
+	*p++ = '\\';
+	p = smb_encode_path(server, p, dentry, NULL);
+	*p++ = 4;
+	*p++ = 0;
 	smb_setup_bcc(server, p);
 
 	result = smb_request_ok(server, SMBsetatr, 0, 0);
@@ -1976,50 +1951,55 @@
 }
 
 /*
- * Note: called with the server locked.
+ * Because of bugs in the trans2 setattr messages, we must set
+ * attributes and timestamps separately. The core SMBsetatr
+ * message seems to be the only reliable way to set attributes.
+ */
+int
+smb_proc_setattr(struct dentry *dir, struct smb_fattr *fattr)
+{
+	struct smb_sb_info *server = server_from_dentry(dir);
+	int result;
+
+#ifdef SMBFS_DEBUG_VERBOSE
+printk("smb_proc_setattr: setting %s/%s, open=%d\n", 
+dir->d_parent->d_name.name, dir->d_name.name, smb_is_open(dir->d_inode));
+#endif
+	smb_lock_server(server);
+	result = smb_proc_setattr_core(server, dir, fattr->attr);
+	smb_unlock_server(server);
+	return result;
+}
+
+/*
+ * Called with the server locked. Sets the timestamps for an
+ * file open with write permissions.
  */
 static int
-smb_proc_setattr_trans2(struct smb_sb_info *server,
-			struct dentry *dir, struct smb_fattr *fattr)
+smb_proc_setattr_ext(struct smb_sb_info *server,
+		      struct inode *inode, struct smb_fattr *fattr)
 {
 	__u16 date, time;
-	char *p;
 	int result;
 
-	unsigned char *resp_data = NULL;
-	unsigned char *resp_param = NULL;
-	int resp_data_len = 0;
-	int resp_param_len = 0;
-	char param[SMB_MAXPATHLEN + 20]; /* too long for the stack! */
-	char data[26];
-
       retry:
-	WSET(param, 0, 1);	/* Info level SMB_INFO_STANDARD */
-	DSET(param, 2, 0);
-	p = smb_encode_path(server, param + 6, dir, NULL);
-
-	date_unix2dos(fattr->f_ctime, &date, &time);
-	WSET(data, 0, date);
-	WSET(data, 2, time);
+	smb_setup_header(server, SMBsetattrE, 7, 0);
+	WSET(server->packet, smb_vwv0, inode->u.smbfs_i.fileid);
+	/* We don't change the creation time */
+	WSET(server->packet, smb_vwv1, 0);
+	WSET(server->packet, smb_vwv2, 0);
 	date_unix2dos(fattr->f_atime, &date, &time);
-	WSET(data, 4, date);
-	WSET(data, 6, time);
+	WSET(server->packet, smb_vwv3, date);
+	WSET(server->packet, smb_vwv4, time);
 	date_unix2dos(fattr->f_mtime, &date, &time);
-	WSET(data, 8, date);
-	WSET(data, 10, time);
+	WSET(server->packet, smb_vwv5, date);
+	WSET(server->packet, smb_vwv6, time);
 #ifdef SMBFS_DEBUG_TIMESTAMP
-printk("setattr_trans2: %s/%s, date=%x, time=%x, mtime=%ld\n", 
-dir->d_parent->d_name.name, dir->d_name.name, date, time, fattr->f_mtime);
+printk("smb_proc_setattr_ext: date=%d, time=%d, mtime=%ld\n", 
+date, time, fattr->f_mtime);
 #endif
-	DSET(data, 12, fattr->f_size);
-	DSET(data, 16, fattr->f_blksize);
-	WSET(data, 20, fattr->attr);
-	DSET(data, 22, 0); /* ULONG EA size */
 
-	result = smb_trans2_request(server, TRANSACT2_SETPATHINFO,
-				    26, data, p - param, param,
-				    &resp_data_len, &resp_data,
-				    &resp_param_len, &resp_param);
+	result = smb_request_ok(server, SMBsetattrE, 0, 0);
 	if (result < 0)
 	{
 		if (smb_retry(server))
@@ -2027,54 +2007,58 @@
 		goto out;
 	}
 	result = 0;
-	if (server->rcls != 0)
-		result = -smb_errno(server);
-
 out:
 	return result;
 }
 
 /*
- * Set the attributes for an open file.
+ * Note: called with the server locked.
+ *
+ * Bugs Noted:
+ * (1) The TRANSACT2_SETPATHINFO message under Win NT 4.0 doesn't
+ * set the file's attribute flags.
  */
 static int
-smb_proc_setfile_trans2(struct smb_sb_info *server,
-			struct inode * inode, struct smb_fattr *fattr)
+smb_proc_setattr_trans2(struct smb_sb_info *server,
+			struct dentry *dir, struct smb_fattr *fattr)
 {
 	__u16 date, time;
+	char *p;
+	int result;
+
 	unsigned char *resp_data = NULL;
-	unsigned char *resp_parm = NULL;
+	unsigned char *resp_param = NULL;
 	int resp_data_len = 0;
-	int resp_parm_len = 0;
-	int result;
-	char parm[6], data[26];
+	int resp_param_len = 0;
+	char param[SMB_MAXPATHLEN + 20]; /* too long for the stack! */
+	char data[26];
 
       retry:
-	WSET(parm, 0, inode->u.smbfs_i.fileid);
-	WSET(parm, 2, 1);	/* Info level SMB_INFO_STANDARD */
+	WSET(param, 0, 1);	/* Info level SMB_INFO_STANDARD */
+	DSET(param, 2, 0);
+	p = smb_encode_path(server, param + 6, dir, NULL);
 
-	date_unix2dos(fattr->f_ctime, &date, &time);
-	WSET(data, 0, date);
-	WSET(data, 2, time);
+	WSET(data, 0, 0); /* creation time */
+	WSET(data, 2, 0);
 	date_unix2dos(fattr->f_atime, &date, &time);
 	WSET(data, 4, date);
 	WSET(data, 6, time);
-#ifdef SMBFS_DEBUG_TIMESTAMP
-printk("smb_proc_setfile_trans2: date=%x, time=%x, atime=%ld\n", 
-date, time, fattr->f_atime);
-#endif
 	date_unix2dos(fattr->f_mtime, &date, &time);
 	WSET(data, 8, date);
 	WSET(data, 10, time);
-	DSET(data, 12, fattr->f_size);
-	DSET(data, 16, fattr->f_blksize);
-	WSET(data, 20, fattr->attr);
+#ifdef SMBFS_DEBUG_TIMESTAMP
+printk("setattr_trans2: %s/%s, date=%x, time=%x, mtime=%ld\n", 
+dir->d_parent->d_name.name, dir->d_name.name, date, time, fattr->f_mtime);
+#endif
+	DSET(data, 12, 0); /* size */
+	DSET(data, 16, 0); /* blksize */
+	WSET(data, 20, 0); /* attr */
 	DSET(data, 22, 0); /* ULONG EA size */
 
-	result = smb_trans2_request(server, TRANSACT2_SETFILEINFO,
-				    26, data, 6, parm,
+	result = smb_trans2_request(server, TRANSACT2_SETPATHINFO,
+				    26, data, p - param, param,
 				    &resp_data_len, &resp_data,
-				    &resp_parm_len, &resp_parm);
+				    &resp_param_len, &resp_param);
 	if (result < 0)
 	{
 		if (smb_retry(server))
@@ -2089,27 +2073,70 @@
 	return result;
 }
 
+/*
+ * Set the modify and access timestamps for a file.
+ *
+ * Incredibly enough, in all of SMB there is no message to allow
+ * setting both attributes and timestamps at once. 
+ *
+ * Bugs Noted:
+ * (1) Win 95 doesn't support the TRANSACT2_SETFILEINFO message 
+ * with info level 1 (INFO_STANDARD).
+ * (2) Under the core protocol apparently the only way to set the
+ * timestamp is to open and close the file.
+ */
 int
-smb_proc_setattr(struct smb_sb_info *server, struct dentry *dir,
-		 struct smb_fattr *fattr)
+smb_proc_settime(struct dentry *dentry, struct smb_fattr *fattr)
 {
+	struct smb_sb_info *server = server_from_dentry(dentry);
+	struct inode *inode = dentry->d_inode;
 	int result;
 
-#ifdef SMBFS_DEBUG_VERBOSE
-printk("smb_proc_setattr: setting %s/%s, open=%d\n", 
-dir->d_parent->d_name.name, dir->d_name.name, smb_is_open(dir->d_inode));
+#ifdef SMBFS_DEBUG_TIMESTAMP
+printk("smb_proc_settime: setting %s/%s, open=%d\n", 
+dentry->d_parent->d_name.name, dentry->d_name.name, smb_is_open(inode));
 #endif
 	smb_lock_server(server);
-	if (server->opt.protocol >= SMB_PROTOCOL_LANMAN2) {
-		struct inode *inode = dir->d_inode;
-
-		if (smb_is_open(inode))
-			result = smb_proc_setfile_trans2(server, inode, fattr);
+	if (server->opt.protocol >= SMB_PROTOCOL_LANMAN2)
+	{
+		if (smb_is_open(inode) &&
+		    inode->u.smbfs_i.access != SMB_O_RDONLY)
+			result = smb_proc_setattr_ext(server, inode, fattr);
 		else
-			result = smb_proc_setattr_trans2(server, dir, fattr);
+			result = smb_proc_setattr_trans2(server, dentry, fattr);
 	} else
-		result = smb_proc_setattr_core(server, dir, fattr);
+	{
+		/*
+		 * Fail silently on directories ... timestamp can't be set?
+		 */
+		result = 0;
+		if (S_ISREG(inode->i_mode))
+		{
+			/*
+			 * Set the mtime by opening and closing the file.
+			 */
+			result = -EACCES;
+			if (!smb_is_open(inode))
+				smb_proc_open(server, dentry, SMB_O_WRONLY);
+			if (smb_is_open(inode) &&
+			    inode->u.smbfs_i.access != SMB_O_RDONLY)
+			{
+				inode->i_mtime = fattr->f_mtime;
+				result = smb_proc_close_inode(server, inode);
+			}
+		}
+	}
 
+#if 1 	/* temporary */
+	if (result)
+	{
+printk("smb_proc_settime: %s/%s failed, open=%d, res=%d, rcls=%d, err=%d\n", 
+dentry->d_parent->d_name.name, dentry->d_name.name, smb_is_open(inode),
+result, server->rcls, server->err);
+		/* squash errors for now */
+		result = 0;
+	}
+#endif
 	smb_unlock_server(server);
 	return result;
 }
@@ -2133,8 +2160,8 @@
 		goto out;
 	}
 	p = SMB_VWV(server->packet);
-	attr->f_bsize = WVAL(p, 2) * WVAL(p, 4);
 	attr->f_blocks = WVAL(p, 0);
+	attr->f_bsize  = WVAL(p, 2) * WVAL(p, 4);
 	attr->f_bavail = attr->f_bfree = WVAL(p, 6);
 	error = 0;
 
diff -u --recursive --new-file v2.1.72/linux/fs/smbfs/sock.c linux/fs/smbfs/sock.c
--- v2.1.72/linux/fs/smbfs/sock.c	Tue Dec  2 09:49:40 1997
+++ linux/fs/smbfs/sock.c	Thu Dec 11 11:25:54 1997
@@ -397,10 +397,6 @@
 	{
 		int new_len = smb_round_length(len + 4);
 
-#ifdef SMBFS_PARANOIA
-printk("smb_receive: Increase packet size from %d to %d\n",
-server->packet_size, new_len);
-#endif
 		result = -ENOMEM;
 		packet = smb_vmalloc(new_len);
 		if (packet == NULL)
@@ -655,6 +651,17 @@
 	}
 	if (result < 0)
 		goto bad_conn;
+	/*
+	 * Check for fatal server errors ...
+	 */
+	if (server->rcls) {
+		int error = smb_errno(server);
+		if (error == EBADSLT) {
+			printk("smb_request: tree ID invalid\n");
+			result = error;
+			goto bad_conn;
+		}
+	}
 
 out:
 	pr_debug("smb_request: result = %d\n", result);
@@ -827,6 +834,17 @@
 	}
 	if (result < 0)
 		goto bad_conn;
+	/*
+	 * Check for fatal server errors ...
+	 */
+	if (server->rcls) {
+		int error = smb_errno(server);
+		if (error == EBADSLT) {
+			printk("smb_request: tree ID invalid\n");
+			result = error;
+			goto bad_conn;
+		}
+	}
 
 out:
 	return result;
diff -u --recursive --new-file v2.1.72/linux/fs/sysv/namei.c linux/fs/sysv/namei.c
--- v2.1.72/linux/fs/sysv/namei.c	Wed Dec 10 11:12:45 1997
+++ linux/fs/sysv/namei.c	Tue Dec 16 09:43:36 1997
@@ -9,10 +9,10 @@
  *
  *  sysv/namei.c
  *  Copyright (C) 1993  Bruno Haible
- */
-/*
-  7 Dec 1997 - updated to use dentries by Krzysztof G. Baranowski
-	       <kgb@manjak.knm.org.pl>
+ *
+ *
+ *  Revised: 15 Dec 1997 by Krzysztof G. Baranowski <kgb@manjak.knm.org.pl>
+ *    Driver updated to use dentries.
  */
 	 
 
@@ -107,7 +107,6 @@
 
 int sysv_lookup(struct inode * dir, struct dentry * dentry)
 {
-	int ino;
 	struct inode * inode = NULL;
 	struct sysv_dir_entry * de;
 	struct buffer_head * bh;
@@ -117,16 +116,16 @@
 	if (!S_ISDIR(dir->i_mode)) {
 		return -ENOENT;
 	}
-	if (!(bh = sysv_find_entry(dir, dentry->d_name.name, 
-				   dentry->d_name.len, &de))) {
-		return -ENOENT;
-	}
-	ino = de->inode;
-	brelse(bh);
-	inode = iget(dir->i_sb,ino);
+	bh = sysv_find_entry(dir, dentry->d_name.name, dentry->d_name.len, &de);
+
+	if (bh) {
+		int ino = de->inode;
+		brelse(bh);
+		inode = iget(dir->i_sb,ino);
 	
-	if (!inode) 
-		return -EACCES;
+		if (!inode) 
+			return -EACCES;
+	}
 	d_add(dentry, inode);
 	return 0;
 }
@@ -302,9 +301,8 @@
 		brelse(bh);
 		return -EEXIST;
 	}
-	if (dir->i_nlink >= dir->i_sb->sv_link_max) {
+	if (dir->i_nlink >= dir->i_sb->sv_link_max) 
 		return -EMLINK;
-	}
 	inode = sysv_new_inode(dir);
 	if (!inode)
 		return -ENOSPC;
@@ -595,6 +593,7 @@
 	error = sysv_add_entry(dir, dentry->d_name.name,
                                dentry->d_name.len, &bh, &de);
 	if (error) {
+		brelse(bh);
 		return error;
 	}
 	de->inode = oldinode->i_ino;
@@ -652,8 +651,6 @@
 	brelse(old_bh);
 	brelse(new_bh);
 	brelse(dir_bh);
-	iput(old_inode);
-	iput(new_inode);
 	current->counter = 0;
 	schedule();
 start_up:
@@ -759,15 +756,12 @@
 			mark_inode_dirty(new_dir);
 		}
 	}
+	d_move(old_dentry, new_dentry);
 	retval = 0;
 end_rename:
 	brelse(dir_bh);
 	brelse(old_bh);
 	brelse(new_bh);
-	iput(old_inode);
-	iput(new_inode);
-	iput(old_dir);
-	iput(new_dir);
 	return retval;
 }
 
diff -u --recursive --new-file v2.1.72/linux/include/asm-i386/math_emu.h linux/include/asm-i386/math_emu.h
--- v2.1.72/linux/include/asm-i386/math_emu.h	Thu Oct 10 22:35:15 1996
+++ linux/include/asm-i386/math_emu.h	Tue Dec  9 17:57:09 1997
@@ -3,17 +3,8 @@
 
 #include <asm/sigcontext.h>
 
-void restore_i387_soft(struct _fpstate *buf);
-struct _fpstate * save_i387_soft(struct _fpstate * buf);
-
-struct fpu_reg {
-	char sign;
-	char tag;
-	long exp;
-	unsigned sigl;
-	unsigned sigh;
-};
-
+void restore_i387_soft(void *s387, struct _fpstate *buf);
+struct _fpstate * save_i387_soft(void *s387, struct _fpstate * buf);
 
 /* This structure matches the layout of the data saved to the stack
    following a device-not-present interrupt, part of it saved
@@ -42,5 +33,4 @@
 	long ___vm86_fs;
 	long ___vm86_gs;
 };
-
 #endif
diff -u --recursive --new-file v2.1.72/linux/include/asm-i386/processor.h linux/include/asm-i386/processor.h
--- v2.1.72/linux/include/asm-i386/processor.h	Tue Dec  2 09:49:40 1997
+++ linux/include/asm-i386/processor.h	Tue Dec  9 17:57:09 1997
@@ -76,9 +76,8 @@
 	long	fcs;
 	long	foo;
 	long	fos;
-	long    top;
-	struct fpu_reg	regs[8];	/* 8*16 bytes for each FP-reg = 128 bytes */
-	unsigned char	lookahead;
+	long	st_space[20];	/* 8*10 bytes for each FP-reg = 80 bytes */
+	unsigned char	ftop, changed, lookahead, no_update, rm, alimit;
 	struct info	*info;
 	unsigned long	entry_eip;
 };
diff -u --recursive --new-file v2.1.72/linux/include/asm-i386/ptrace.h linux/include/asm-i386/ptrace.h
--- v2.1.72/linux/include/asm-i386/ptrace.h	Sat Oct  5 04:34:11 1996
+++ linux/include/asm-i386/ptrace.h	Tue Dec  9 17:57:09 1997
@@ -41,6 +41,12 @@
 	int  xss;
 };
 
+/* Arbitrarily choose the same ptrace numbers as used by the Sparc code. */
+#define PTRACE_GETREGS            12
+#define PTRACE_SETREGS            13
+#define PTRACE_GETFPREGS          14
+#define PTRACE_SETFPREGS          15
+
 #ifdef __KERNEL__
 #define user_mode(regs) ((VM_MASK & (regs)->eflags) || (3 & (regs)->xcs))
 #define instruction_pointer(regs) ((regs)->eip)
diff -u --recursive --new-file v2.1.72/linux/include/asm-i386/system.h linux/include/asm-i386/system.h
--- v2.1.72/linux/include/asm-i386/system.h	Wed Dec 10 11:12:45 1997
+++ linux/include/asm-i386/system.h	Mon Dec 15 18:37:15 1997
@@ -275,22 +275,20 @@
 		((limit) & 0x0ffff); }
 
 #define _set_tssldt_desc(n,addr,limit,type) \
-__asm__ __volatile__ ("movw $" #limit ",%1\n\t" \
-	"movw %%ax,%2\n\t" \
+__asm__ __volatile__ ("movw %3,0(%2)\n\t" \
+	"movw %%ax,2(%2)\n\t" \
 	"rorl $16,%%eax\n\t" \
-	"movb %%al,%3\n\t" \
-	"movb $" type ",%4\n\t" \
-	"movb $0x00,%5\n\t" \
-	"movb %%ah,%6\n\t" \
+	"movb %%al,4(%2)\n\t" \
+	"movb %4,5(%2)\n\t" \
+	"movb $0,6(%2)\n\t" \
+	"movb %%ah,7(%2)\n\t" \
 	"rorl $16,%%eax" \
-	: /* no output */ \
-	:"a" (addr), "m" (*(n)), "m" (*(n+2)), "m" (*(n+4)), \
-	 "m" (*(n+5)), "m" (*(n+6)), "m" (*(n+7)) \
-	)
+	: "=m"(*(n)) : "a" (addr), "r"(n), "i"(limit), "i"(type))
 
-#define set_tss_desc(n,addr) _set_tssldt_desc(((char *) (n)),((int)(addr)),235,"0x89")
+#define set_tss_desc(n,addr) \
+	_set_tssldt_desc(((char *) (n)),((int)(addr)),235,0x89)
 #define set_ldt_desc(n,addr,size) \
-	_set_tssldt_desc(((char *) (n)),((int)(addr)),((size << 3) - 1),"0x82")
+	_set_tssldt_desc(((char *) (n)),((int)(addr)),((size << 3) - 1),0x82)
 
 /*
  * This is the ldt that every process will get unless we need
diff -u --recursive --new-file v2.1.72/linux/include/asm-mips/asmmacro.h linux/include/asm-mips/asmmacro.h
--- v2.1.72/linux/include/asm-mips/asmmacro.h	Thu Jun 26 12:33:39 1997
+++ linux/include/asm-mips/asmmacro.h	Wed Dec 10 10:31:10 1997
@@ -1,4 +1,4 @@
-/* $Id: asmmacro.h,v 1.1 1997/06/06 09:38:18 ralf Exp $
+/* $Id: asmmacro.h,v 1.1.1.1 1997/06/01 03:17:13 ralf Exp $
  * asmmacro.h: Assembler macros to make things easier to read.
  *
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
diff -u --recursive --new-file v2.1.72/linux/include/asm-mips/atomic.h linux/include/asm-mips/atomic.h
--- v2.1.72/linux/include/asm-mips/atomic.h	Mon Jul  7 08:18:55 1997
+++ linux/include/asm-mips/atomic.h	Tue Dec 16 12:45:55 1997
@@ -11,7 +11,7 @@
  *
  * Copyright (C) 1996 by Ralf Baechle
  *
- * $Id: atomic.h,v 1.2 1997/06/25 19:10:33 ralf Exp $
+ * $Id: atomic.h,v 1.2 1997/06/20 03:05:12 ralf Exp $
  */
 #ifndef __ASM_MIPS_ATOMIC_H
 #define __ASM_MIPS_ATOMIC_H
@@ -99,7 +99,7 @@
  * on us. We need to use _exactly_ the address the user gave us,
  * not some alias that contains the same information.
  */
-#define __atomic_fool_gcc(x) (*(struct { int a[100]; } *)x)
+#define __atomic_fool_gcc(x) (*(volatile struct { int a[100]; } *)x)
 
 extern __inline__ void atomic_add(int i, volatile atomic_t * v)
 {
diff -u --recursive --new-file v2.1.72/linux/include/asm-mips/bitops.h linux/include/asm-mips/bitops.h
--- v2.1.72/linux/include/asm-mips/bitops.h	Mon Aug 18 18:19:46 1997
+++ linux/include/asm-mips/bitops.h	Tue Dec 16 12:45:55 1997
@@ -5,11 +5,14 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (c) 1994, 1995, 1996  Ralf Baechle
+ * Copyright (c) 1994 - 1997  Ralf Baechle (ralf@gnu.org)
  */
 #ifndef __ASM_MIPS_BITOPS_H
 #define __ASM_MIPS_BITOPS_H
 
+#include <linux/types.h>
+#include <linux/byteorder/swab.h>		/* sigh ... */
+
 #ifdef __KERNEL__
 
 #include <asm/sgidefs.h>
@@ -466,11 +469,6 @@
 
 #define ext2_find_first_zero_bit(addr, size) \
         ext2_find_next_zero_bit((addr), (size), 0)
-
-static __inline__ unsigned long __swab32(unsigned long val)
-{
-	return ((val>>24)|((val>>8)&0xff00)|((val<<8)&0xff0000)|(val<<24));
-}
 
 extern __inline__ unsigned long ext2_find_next_zero_bit(void *addr, unsigned long size, unsigned long offset)
 {
diff -u --recursive --new-file v2.1.72/linux/include/asm-mips/bootinfo.h linux/include/asm-mips/bootinfo.h
--- v2.1.72/linux/include/asm-mips/bootinfo.h	Thu Jun 26 12:33:39 1997
+++ linux/include/asm-mips/bootinfo.h	Tue Dec 16 12:45:55 1997
@@ -7,6 +7,8 @@
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file COPYING in the main directory of this archive
  * for more details.
+ *
+ * $Id: bootinfo.h,v 1.3 1997/09/19 08:37:44 ralf Exp $
  */
 #ifndef __ASM_MIPS_BOOTINFO_H
 #define __ASM_MIPS_BOOTINFO_H
@@ -14,28 +16,6 @@
 /* XXX */
 #include <linux/config.h>
 
-#if 0
-/*
- * Valid machtype values
- * FIXME: note that we really need a hierarchy for this stuff, as there are 
- * several models of DECStation (for example). PMA
- */
-#define MACH_UNKNOWN		0	/* whatever...                   */
-#define MACH_DESKSTATION_RPC44	1	/* Deskstation rPC44             */
-#define MACH_DESKSTATION_TYNE	2	/* Deskstation Tyne              */
-#define MACH_ACER_PICA_61	3	/* Acer PICA-61 (PICA1)          */
-#define MACH_MIPS_MAGNUM_4000	4	/* Mips Magnum 4000 "RC4030"     */
-#define MACH_OLIVETTI_M700	4	/* almost a clone ...            */
-#define MACH_DECSTATION		5	/* DECStation 5000/2x for now    */
-#define MACH_SNI_RM200_PCI	6	/* RM200/RM300/RM400 PCI series  */
-#define MACH_SGI_INDY		7	/* R4?K and R5K Indy workstaions */
-#define MACH_LAST		7
-
-#define MACH_NAMES {"unknown", "Deskstation rPC44", "Deskstation Tyne", \
-	"Acer PICA 61", "Mips Magnum 4000", "DECStation", "RM200 PCI", \
-        "SGI INDY" }
-#endif
-
 /*
  * Values for machgroup
  */
@@ -47,7 +27,8 @@
 #define MACH_GROUP_ACN		5
 #define MACH_GROUP_SGI          6 /* Silicon Graphics workstations and servers */
 
-#define GROUP_NAMES { "unknown", "Jazz", "Digital", "ARC", "SNI", "ACN" }
+#define GROUP_NAMES { "unknown", "Jazz", "Digital", "ARC", \
+                      "SNI", "ACN", "SGI" }
 
 /*
  * Valid machtype values for group unknown (low order halfword of mips_machtype)
@@ -101,6 +82,10 @@
  */
 #define MACH_SGI_INDY		0	/* R4?K and R5K Indy workstaions */
 
+#define GROUP_SGI_NAMES { "Indy" }
+
+#define GROUP_SGI_NAMES { "Indy" }
+
 /*
  * Valid cputype values
  */
@@ -131,13 +116,14 @@
 #define CPU_R5000		24
 #define CPU_R5000A		25
 #define CPU_R4640		26
-#define CPU_LAST                27
+#define CPU_NEVADA		27	/* RM5230, RM5260 */
+#define CPU_LAST		27
 
 #define CPU_NAMES { "unknown", "R2000", "R3000", "R3000A", "R3041", "R3051", \
         "R3052", "R3081", "R3081E", "R4000PC", "R4000SC", "R4000MC",         \
         "R4200", "R4400PC", "R4400SC", "R4400MC", "R4600", "R6000",          \
         "R6000A", "R8000", "R10000", "R4300", "R4650", "R4700", "R5000",     \
-	"R5000A", "R4640" }
+        "R5000A", "R4640", "Nevada" }
 
 #define CL_SIZE      (80)
 
diff -u --recursive --new-file v2.1.72/linux/include/asm-mips/bugs.h linux/include/asm-mips/bugs.h
--- v2.1.72/linux/include/asm-mips/bugs.h	Thu Jun 26 12:33:39 1997
+++ linux/include/asm-mips/bugs.h	Tue Dec 16 12:45:55 1997
@@ -2,7 +2,9 @@
  *  include/asm-mips/bugs.h
  *
  *  Copyright (C) 1995  Waldorf Electronics
- *  written by Ralf Baechle
+ *  Copyright (C) 1997  Ralf Baechle
+ *
+ * $Id: bugs.h,v 1.2 1997/09/07 04:13:53 ralf Exp $
  */
 #include <asm/bootinfo.h>
 
@@ -14,21 +16,25 @@
  */
 
 
-static void check_wait(void)
+static inline void check_wait(void)
 {
 	printk("Checking for 'wait' instruction... ");
 	switch(mips_cputype) {
-		case CPU_R4200: 
-		case CPU_R4300: 
-		case CPU_R4600: 
-		case CPU_R5000: 
-			wait_available = 1;
-			printk(" available.\n");
-			break;
-		default:
-			printk(" unavailable.\n");
-			break;
-		}
+	case CPU_R4200: 
+	case CPU_R4300: 
+	case CPU_R4600: 
+	case CPU_R4640: 
+	case CPU_R4650: 
+	case CPU_R4700: 
+	case CPU_R5000: 
+	case CPU_NEVADA:
+		wait_available = 1;
+		printk(" available.\n");
+		break;
+	default:
+		printk(" unavailable.\n");
+		break;
+	}
 }
 
 static void check_bugs(void)
diff -u --recursive --new-file v2.1.72/linux/include/asm-mips/byteorder.h linux/include/asm-mips/byteorder.h
--- v2.1.72/linux/include/asm-mips/byteorder.h	Wed Dec 10 11:12:45 1997
+++ linux/include/asm-mips/byteorder.h	Tue Dec 16 12:45:55 1997
@@ -8,7 +8,7 @@
 #elif defined (__MIPSEL__)
 #  include <linux/byteorder/little_endian.h>
 #else
-#  error What's that? MIPS, but neither MIPSEB, nor MIPSEL???
+#  error "MIPS, but neither __MIPSEB__, nor __MIPSEL__???"
 #endif
 
 #endif /* _MIPS_BYTEORDER_H */
diff -u --recursive --new-file v2.1.72/linux/include/asm-mips/checksum.h linux/include/asm-mips/checksum.h
--- v2.1.72/linux/include/asm-mips/checksum.h	Mon Aug 18 18:19:46 1997
+++ linux/include/asm-mips/checksum.h	Tue Dec 16 12:46:01 1997
@@ -5,9 +5,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1995, 1996, 1997 by Ralf Baechle
- *
- * $Id: checksum.h,v 1.5 1997/08/08 20:22:28 miguel Exp $
+ * Copyright (C) 1995 by Ralf Baechle
  */
 #ifndef __ASM_MIPS_CHECKSUM_H
 #define __ASM_MIPS_CHECKSUM_H
@@ -167,10 +165,7 @@
  */
 static inline unsigned short ip_compute_csum(unsigned char * buff, int len)
 {
-	unsigned int sum;
-
-	sum = csum_partial(buff, len, 0);
-	return csum_fold(sum);
+	return csum_fold(csum_partial(buff, len, 0));
 }
 
 #define _HAVE_ARCH_IPV6_CSUM
diff -u --recursive --new-file v2.1.72/linux/include/asm-mips/cpu.h linux/include/asm-mips/cpu.h
--- v2.1.72/linux/include/asm-mips/cpu.h	Thu Jun 26 12:33:39 1997
+++ linux/include/asm-mips/cpu.h	Wed Dec 10 10:31:10 1997
@@ -1,4 +1,4 @@
-/* $Id: cpu.h,v 1.1 1997/06/06 09:38:41 ralf Exp $
+/* $Id: cpu.h,v 1.1.1.1 1997/06/01 03:17:12 ralf Exp $
  * cpu.h: Values of the PRId register used to match up
  *        various MIPS cpu types.
  *
diff -u --recursive --new-file v2.1.72/linux/include/asm-mips/decstation.h linux/include/asm-mips/decstation.h
--- v2.1.72/linux/include/asm-mips/decstation.h	Thu Jun 26 12:33:39 1997
+++ linux/include/asm-mips/decstation.h	Wed Dec 31 16:00:00 1969
@@ -1,254 +0,0 @@
-/*
- * Hardware info about DEC Personal DECStation systems (otherwise known
- * as maxine or pmax (internal DEC codenames).
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 1995 by Paul M. Antoine, some code and definitions are
- * by curteousy of Chris Fraser.
- *
- * This file is under construction - you were warned!
- */
-
-#ifndef __ASM_MIPS_PMAX_H 
-#define __ASM_MIPS_PMAX_H 
-
-/*
- * The addresses below are virtual address. The mappings are
- * created on startup via wired entries in the tlb.
- */
-
-#define PMAX_LOCAL_IO_SPACE     0xe0000000
-
-/*
- * Motherboard regs (kseg1 addresses)
- */
-#define PMAX_SSR_ADDR		0xbc040100		/* system support reg */
-
-/*
- * SSR defines
- */
-#define PMAX_SSR_LEDMASK	0x00000001		/* power LED */
-
-/*
- * REX functions -- these are for the new TURBOchannel style ROMs
- */
-#define REX_PROM_MAGIC  0x30464354			/* passed in a2 */
-
-#define REX_GETBITMAP		0x84			/* get mem bitmap */
-#define REX_GETCHAR		0x24			/* getch() */
-#define REX_PUTCHAR		0x13			/* putch() */
-#define REX_HALT		0x9c			/* halt the system */
-#define REX_PRINTF		0x30			/* printf() */
-#define REX_PUTS		0x2c			/* puts() */
-#define REX_SLOTADDR		0x6c			/* slotaddr */
-
-#ifndef __LANGUAGE_ASSEMBLY__
-
-extern __inline__ void pmax_set_led(unsigned int bits)
-{
-	volatile unsigned int *led_register = (unsigned int *) PMAX_SSR_ADDR;
-
-	*led_register = bits & PMAX_SSR_LEDMASK;
-}
-
-/*
- * Glue code to call the PMAX boot proms.
- */
-extern asmlinkage void pmax_printf(const char *);
-
-#endif
-
-/*
- * These are just hacked out of the JAZZ ones, no ideas really.
- */
-#define PMAX_KEYBOARD_ADDRESS   0xe0005000
-#define PMAX_KEYBOARD_DATA      0xe0005000
-#define PMAX_KEYBOARD_COMMAND   0xe0005001
-
-#ifndef __LANGUAGE_ASSEMBLY__
-
-typedef struct {
-	unsigned char data;
-	unsigned char command;
-} pmax_keyboard_hardware;
-
-typedef struct {
-	unsigned char pad0[3];
-	unsigned char data;
-	unsigned char pad1[3];
-	unsigned char command;
-} mips_keyboard_hardware;
-
-/*
- * For now.
- */
-#define keyboard_hardware       pmax_keyboard_hardware
-
-#endif
-
-/*
- * Serial ports on DEC - maybe!
- */
-
-#define PMAX_SERIAL1_BASE       (unsigned int)0xe0006000
-#define PMAX_SERIAL2_BASE       (unsigned int)0xe0007000
-
-/*
- * Dummy Device Address. Used in pmaxdma.c
- */
-
-#define PMAX_DUMMY_DEVICE       0xe000d000
-     
-/*
- * PMAX timer registers and interrupt no.
- * Note that the hardware timer interrupt is actually on
- * cpu level 6, but to keep compatibility with PC stuff
- * it is remapped to vector 0. See arch/mips/kernel/entry.S.
- */
-#define PMAX_TIMER_INTERVAL     0xe0000228
-#define PMAX_TIMER_REGISTER     0xe0000230
-
-/*
- * DRAM configuration register
- */
-#ifndef __LANGUAGE_ASSEMBLY__
-#ifdef __MIPSEL__
-typedef struct {
-	unsigned int bank2 : 3;
-	unsigned int bank1 : 3;
-	unsigned int mem_bus_width : 1;
-	unsigned int reserved2 : 1;
-	unsigned int page_mode : 1;
-	unsigned int reserved1 : 23;
-} dram_configuration;
-#else /* defined (__MIPSEB__) */
-typedef struct {
-	unsigned int reserved1 : 23;
-	unsigned int page_mode : 1;
-	unsigned int reserved2 : 1;
-	unsigned int mem_bus_width : 1;
-	unsigned int bank1 : 3;
-	unsigned int bank2 : 3;
-} dram_configuration;
-#endif
-#endif /* __LANGUAGE_ASSEMBLY__ */
-
-#define PMAX_DRAM_CONFIG        0xe00fffe0
-
-/*
- * PMAX interrupt control registers
- */
-#define PMAX_IO_IRQ_SOURCE      0xe0100000
-#define PMAX_IO_IRQ_ENABLE      0xe0100002
-
-/*
- * PMAX interrupt enable bits
- */
-#define PMAX_IE_PARALLEL            (1 << 0)
-#define PMAX_IE_FLOPPY              (1 << 1)
-#define PMAX_IE_SOUND               (1 << 2)
-#define PMAX_IE_VIDEO               (1 << 3)
-#define PMAX_IE_ETHERNET            (1 << 4)
-#define PMAX_IE_SCSI                (1 << 5)
-#define PMAX_IE_KEYBOARD            (1 << 6)
-#define PMAX_IE_MOUSE               (1 << 7)
-#define PMAX_IE_SERIAL1             (1 << 8)
-#define PMAX_IE_SERIAL2             (1 << 9)
-
-/*
- * PMAX Interrupt Level definitions
- */
-
-#define PMAX_TIMER_IRQ          0
-#define PMAX_KEYBOARD_IRQ       1
-#define PMAX_ETHERNET_IRQ       2 /* 15 */
-#define PMAX_SERIAL1_IRQ        3
-#define PMAX_SERIAL2_IRQ        4
-#define PMAX_PARALLEL_IRQ       5
-#define PMAX_FLOPPY_IRQ         6 /* needs to be consistent with floppy driver! */
-
-/*
- * PMAX DMA Channels
- * Note: Channels 4...7 are not used with respect to the Acer PICA-61
- * chipset which does not provide these DMA channels.
- */
-
-#define PMAX_SCSI_DMA           0              /* SCSI */
-#define PMAX_FLOPPY_DMA         1              /* FLOPPY */
-#define PMAX_AUDIOL_DMA         2              /* AUDIO L */
-#define PMAX_AUDIOR_DMA         3              /* AUDIO R */
-
-/*
- * PMAX R4030 MCT_ADR chip (DMA controller)
- * Note: Virtual Addresses !
- */
-
-#define PMAX_R4030_CONFIG	0xE0000000	/* R4030 config register */
-#define PMAX_R4030_REVISION     0xE0000008	/* same as PICA_ASIC_REVISION */
-#define PMAX_R4030_INV_ADDR	0xE0000010	/* Invalid Address register */
-
-#define PMAX_R4030_TRSTBL_BASE  0xE0000018	/* Translation Table Base */
-#define PMAX_R4030_TRSTBL_LIM   0xE0000020	/* Translation Table Limit */
-#define PMAX_R4030_TRSTBL_INV   0xE0000028	/* Translation Table Invalidate */
-
-#define PMAX_R4030_CACHE_MTNC   0xE0000030	/* Cache Maintenance */
-#define PMAX_R4030_R_FAIL_ADDR  0xE0000038	/* Remote Failed Address */
-#define PMAX_R4030_M_FAIL_ADDR  0xE0000040	/* Memory Failed Adresss */
-
-#define PMAX_R4030_CACHE_PTAG   0xE0000048	/* I/O Cache Physical Tag */
-#define PMAX_R4030_CACHE_LTAG   0xE0000050	/* I/O Cache Logical Tag */
-#define PMAX_R4030_CACHE_BMASK  0xE0000058	/* I/O Cache Byte Mask */
-#define PMAX_R4030_CACHE_BWIN   0xE0000060	/* I/O Cache Buffer Window */
-
-/*
- * Remote Speed Registers. 
- *
- *  0: free,      1: Ethernet,  2: SCSI,      3: Floppy,
- *  4: RTC,       5: Kb./Mouse  6: serial 1,  7: serial 2,
- *  8: parallel,  9: NVRAM,    10: CPU,      11: PROM,
- * 12: reserved, 13: free,     14: 7seg LED, 15: ???
- */
-
-#define PMAX_R4030_REM_SPEED	0xE0000070	/* 16 Remote Speed Registers */
-						/* 0xE0000070,78,80... 0xE00000E8 */
-#define PMAX_R4030_IRQ_ENABLE   0xE00000E8	/* Internal Interrupt Enable */
-
-#define PMAX_R4030_IRQ_SOURCE   0xE0000200	/* Interrupt Source Reg */
-#define PMAX_R4030_I386_ERROR   0xE0000208	/* i386/EISA Bus Error */
-
-
-/*
- * Access the R4030 DMA and I/O Controller
- */
-
-#ifndef __LANGUAGE_ASSEMBLY__
-
-extern inline unsigned short r4030_read_reg16(unsigned addr) {
-	unsigned short ret = *((volatile unsigned short *)addr);
-	__asm__ __volatile__("nop; nop; nop; nop;");
-	return ret;
-}
-
-extern inline unsigned int r4030_read_reg32(unsigned addr) {
-	unsigned int ret = *((volatile unsigned int *)addr);
-	__asm__ __volatile__("nop; nop; nop; nop;");
-	return ret;
-}
-
-extern inline void r4030_write_reg16(unsigned addr, unsigned val) {
-	*((volatile unsigned short *)addr) = val;
-	__asm__ __volatile__("nop; nop; nop; nop;");
-}
-
-extern inline unsigned int r4030_write_reg32(unsigned addr, unsigned val) {
-	*((volatile unsigned int *)addr) = val;
-	__asm__ __volatile__("nop; nop; nop; nop;");
-}
-
-#endif /* !LANGUAGE_ASSEMBLY__ */
-
-	
-#endif /* __ASM_MIPS_PMAX_H */
diff -u --recursive --new-file v2.1.72/linux/include/asm-mips/deskstation.h linux/include/asm-mips/deskstation.h
--- v2.1.72/linux/include/asm-mips/deskstation.h	Thu Jun 26 12:33:39 1997
+++ linux/include/asm-mips/deskstation.h	Wed Dec 31 16:00:00 1969
@@ -1,15 +0,0 @@
-/*
- * SNI specific definitions
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 1997 by Ralf Baechle
- */
-#ifndef __ASM_MIPS_DESKSTATION_H 
-#define __ASM_MIPS_DESKSTATION_H 
-
-#define RPC44_PORT_BASE	0xe2000000
-
-#endif /* __ASM_MIPS_DESKSTATION_H */
diff -u --recursive --new-file v2.1.72/linux/include/asm-mips/dma.h linux/include/asm-mips/dma.h
--- v2.1.72/linux/include/asm-mips/dma.h	Thu Jun 26 12:33:39 1997
+++ linux/include/asm-mips/dma.h	Wed Dec 10 10:31:10 1997
@@ -1,4 +1,4 @@
-/* $Id: dma.h,v 1.7 1992/12/14 00:29:34 root Exp root $
+/* $Id: dma.h,v 1.1.1.1 1997/06/01 03:17:12 ralf Exp $
  * linux/include/asm/dma.h: Defines for using and allocating dma channels.
  * Written by Hennus Bergman, 1992.
  * High DMA channel support & info by Hannu Savolainen
diff -u --recursive --new-file v2.1.72/linux/include/asm-mips/elf.h linux/include/asm-mips/elf.h
--- v2.1.72/linux/include/asm-mips/elf.h	Wed Sep 24 20:05:48 1997
+++ linux/include/asm-mips/elf.h	Tue Dec 16 12:46:01 1997
@@ -1,3 +1,6 @@
+/*
+ * $Id: elf.h,v 1.4 1997/12/16 05:36:40 ralf Exp $
+ */
 #ifndef __ASM_MIPS_ELF_H
 #define __ASM_MIPS_ELF_H
 
diff -u --recursive --new-file v2.1.72/linux/include/asm-mips/floppy.h linux/include/asm-mips/floppy.h
--- v2.1.72/linux/include/asm-mips/floppy.h	Sun Sep  7 13:10:43 1997
+++ linux/include/asm-mips/floppy.h	Tue Dec 16 12:46:01 1997
@@ -5,7 +5,9 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1995
+ * Copyright (C) 1995, 1996, 1997 Ralf Baechle
+ *
+ * $Id: floppy.h,v 1.3 1997/09/07 03:59:02 ralf Exp $
  */
 #ifndef __ASM_MIPS_FLOPPY_H
 #define __ASM_MIPS_FLOPPY_H
@@ -20,26 +22,29 @@
 #define fd_inb(port)			feature->fd_inb(port)
 #define fd_outb(value,port)		feature->fd_outb(value,port)
 
-#define fd_enable_dma()			feature->fd_enable_dma()
-#define fd_disable_dma()		feature->fd_disable_dma()
-#define fd_request_dma()		feature->fd_request_dma()
-#define fd_free_dma()			feature->fd_free_dma()
-#define fd_clear_dma_ff()		feature->fd_clear_dma_ff()
-#define fd_set_dma_mode(mode)		feature->fd_set_dma_mode(mode)
-#define fd_set_dma_addr(addr)		feature->fd_set_dma_addr(virt_to_bus(addr))
-#define fd_set_dma_count(count)		feature->fd_set_dma_count(count)
-#define fd_get_dma_residue()		feature->fd_get_dma_residue()
-#define fd_enable_irq()			feature->fd_enable_irq()
-#define fd_disable_irq()		feature->fd_disable_irq()
-#define fd_request_irq()        request_irq(FLOPPY_IRQ, floppy_interrupt, \
-					    SA_INTERRUPT|SA_SAMPLE_RANDOM, \
-				            "floppy", NULL)
-#define fd_free_irq()           free_irq(FLOPPY_IRQ, NULL);
+#define fd_enable_dma(channel)		feature->fd_enable_dma(channel)
+#define fd_disable_dma(channel)		feature->fd_disable_dma(channel)
+#define fd_request_dma(channel)		feature->fd_request_dma(channel)
+#define fd_free_dma(channel)		feature->fd_free_dma(channel)
+#define fd_clear_dma_ff(channel)	feature->fd_clear_dma_ff(channel)
+#define fd_set_dma_mode(channel, mode)	feature->fd_set_dma_mode(channel, mode)
+#define fd_set_dma_addr(channel, addr)	feature->fd_set_dma_addr(channel, \
+					         virt_to_bus(addr))
+#define fd_set_dma_count(channel,count)	feature->fd_set_dma_count(channel,count)
+#define fd_get_dma_residue(channel)	feature->fd_get_dma_residue(channel)
+
+#define fd_enable_irq(irq)		feature->fd_enable_irq(irq)
+#define fd_disable_irq(irq)		feature->fd_disable_irq(irq)
+#define fd_request_irq(irq)		request_irq(irq, floppy_interrupt, \
+						    SA_INTERRUPT \
+					            | SA_SAMPLE_RANDOM, \
+				                    "floppy", NULL)
+#define fd_free_irq(irq)		free_irq(irq, NULL);
 
 #define MAX_BUFFER_SECTORS 24
 
 /* Pure 2^n version of get_order */
-extern __inline__ int __get_order(unsigned long size)
+extern inline int __get_order(unsigned long size)
 {
 	int order;
 
@@ -52,7 +57,7 @@
 	return order;
 }
 
-extern __inline__ unsigned long mips_dma_mem_alloc(unsigned long size)
+extern inline unsigned long mips_dma_mem_alloc(unsigned long size)
 {
 	int order = __get_order(size);
 	unsigned long mem;
@@ -67,11 +72,11 @@
 	return mem;
 }
 
-extern __inline__ void mips_dma_mem_free(unsigned long addr, unsigned long size)
+extern inline void mips_dma_mem_free(unsigned long addr, unsigned long size)
 {       
 #ifdef CONFIG_MIPS_JAZZ
         if (mips_machgroup == MACH_GROUP_JAZZ)
-		vdma_free(vdma_phys2log(PHYSADDR(addr)));
+		vdma_free(PHYSADDR(addr));
 #endif
 	free_pages(addr, __get_order(size));	
 }
diff -u --recursive --new-file v2.1.72/linux/include/asm-mips/gdb-stub.h linux/include/asm-mips/gdb-stub.h
--- v2.1.72/linux/include/asm-mips/gdb-stub.h	Wed Dec 13 02:39:45 1995
+++ linux/include/asm-mips/gdb-stub.h	Tue Dec 16 12:46:04 1997
@@ -116,8 +116,8 @@
 #define GDB_FR_CP0_RANDOM	((GDB_FR_CP0_INDEX) + 4)	/* 75 */
 #define GDB_FR_CP0_ENTRYLO0	((GDB_FR_CP0_RANDOM) + 4)	/* 76 */
 #define GDB_FR_CP0_ENTRYLO1	((GDB_FR_CP0_ENTRYLO0) + 4)	/* 77 */
-#define GDB_FR_CP0_REG4		((GDB_FR_CP0_ENTRYLO1) + 4)	/* 78 */
-#define GDB_FR_CP0_PAGEMASK	((GDB_FR_CP0_REG4) + 4)		/* 79 */
+#define GDB_FR_CP0_CONTEXT	((GDB_FR_CP0_ENTRYLO1) + 4)	/* 78 */
+#define GDB_FR_CP0_PAGEMASK	((GDB_FR_CP0_CONTEXT) + 4)	/* 79 */
 #define GDB_FR_CP0_WIRED	((GDB_FR_CP0_PAGEMASK) + 4)	/* 80 */
 #define GDB_FR_CP0_REG7		((GDB_FR_CP0_WIRED) + 4)	/* 81 */
 #define GDB_FR_CP0_REG8		((GDB_FR_CP0_REG7) + 4)		/* 82 */
@@ -187,7 +187,7 @@
 	long	cp0_random;
 	long	cp0_entrylo0;
 	long	cp0_entrylo1;
-	long	cp0_reg4;
+	long	cp0_context;
 	long	cp0_pagemask;
 	long	cp0_wired;
 	long	cp0_reg7;
diff -u --recursive --new-file v2.1.72/linux/include/asm-mips/gfx.h linux/include/asm-mips/gfx.h
--- v2.1.72/linux/include/asm-mips/gfx.h	Mon Aug 18 18:19:46 1997
+++ linux/include/asm-mips/gfx.h	Tue Dec 16 12:46:06 1997
@@ -16,6 +16,7 @@
 #define GFX_IS_MANAGED       (GFX_BASE + 5)
 
 #define GFX_MAPALL           (GFX_BASE + 10)
+#define GFX_LABEL            (GFX_BASE + 11)
 
 #define GFX_INFO_NAME_SIZE  16
 #define GFX_INFO_LABEL_SIZE 16
diff -u --recursive --new-file v2.1.72/linux/include/asm-mips/inventory.h linux/include/asm-mips/inventory.h
--- v2.1.72/linux/include/asm-mips/inventory.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-mips/inventory.h	Tue Dec 16 12:46:06 1997
@@ -0,0 +1,56 @@
+/*
+ * $Id: inventory.h,v 1.2 1997/12/06 23:55:49 ralf Exp $
+ */
+#ifndef __ASM_MIPS_INVENTORY_H
+#define __ASM_MIPS_INVENTORY_H
+
+#include <linux/config.h>
+
+#ifdef CONFIG_BINFMT_IRIX
+typedef struct inventory_s {
+	struct inventory_s *inv_next;
+	int    inv_class;
+	int    inv_type;
+	int    inv_controller;
+	int    inv_unit;
+	int    inv_state;
+} inventory_t;
+
+extern int inventory_items;
+void add_to_inventory (int class, int type, int controller, int unit, int state);
+int dump_inventory_to_user (void *userbuf, int size);
+void init_inventory (void);
+
+#else
+#define add_to_inventory(c,t,o,u,s)
+#define init_inventory()
+#endif
+#endif /* defined(CONFIG_BINFMT_IRIX) */
+/*
+ * $Id: inventory.h,v 1.2 1997/12/06 12:39:03 ralf Exp $
+ */
+#ifndef __ASM_MIPS_INVENTORY_H
+#define __ASM_MIPS_INVENTORY_H
+
+#include <linux/config.h>
+
+#ifdef CONFIG_BINFMT_IRIX
+typedef struct inventory_s {
+	struct inventory_s *inv_next;
+	int    inv_class;
+	int    inv_type;
+	int    inv_controller;
+	int    inv_unit;
+	int    inv_state;
+} inventory_t;
+
+extern int inventory_items;
+void add_to_inventory (int class, int type, int controller, int unit, int state);
+int dump_inventory_to_user (void *userbuf, int size);
+void init_inventory (void);
+
+#else
+#define add_to_inventory(c,t,o,u,s)
+#define init_inventory()
+#endif
+#endif /* defined(CONFIG_BINFMT_IRIX) */
diff -u --recursive --new-file v2.1.72/linux/include/asm-mips/io.h linux/include/asm-mips/io.h
--- v2.1.72/linux/include/asm-mips/io.h	Thu Jun 26 12:33:39 1997
+++ linux/include/asm-mips/io.h	Tue Dec 16 12:46:07 1997
@@ -32,6 +32,26 @@
  */
 
 /*
+ * On MIPS I/O ports are memory mapped, so we access them using normal
+ * load/store instructions. mips_io_port_base is the virtual address to
+ * which all ports are being mapped.  For sake of efficiency some code
+ * assumes that this is an address that can be loaded with a single lui
+ * instruction, so the lower 16 bits must be zero.  Should be true on
+ * on any sane architecture; generic code does not use this assumption.
+ */
+extern unsigned long mips_io_port_base;
+
+/*
+ * On MIPS I/O ports are memory mapped, so we access them using normal
+ * load/store instructions. mips_io_port_base is the virtual address to
+ * which all ports are being mapped.  For sake of efficiency some code
+ * assumes that this is an address that can be loaded with a single lui
+ * instruction, so the lower 16 bits must be zero.  Should be true on
+ * on any sane architecture; generic code does not use this assumption.
+ */
+extern unsigned long mips_io_port_base;
+
+/*
  * Thanks to James van Artsdalen for a better timing-fix than
  * the two short jumps: using outb's to a nonexistent port seems
  * to guarantee better timings even on fast machines.
@@ -46,7 +66,7 @@
 #define __SLOW_DOWN_IO \
 	__asm__ __volatile__( \
 		"sb\t$0,0x80(%0)" \
-		: : "r" (PORT_BASE));
+		: : "r" (mips_io_port_base));
 
 #ifdef CONF_SLOWDOWN_IO
 #ifdef REALLY_SLOW_IO
@@ -176,11 +196,11 @@
 __asm__ __volatile__ ("s" #m "\t%0,%1(%2)"
 
 #define __OUT(m,s) \
-__OUT1(s) __OUT2(m) : : "r" (value), "i" (0), "r" (PORT_BASE+port)); } \
-__OUT1(s##c) __OUT2(m) : : "r" (value), "ir" (port), "r" (PORT_BASE)); } \
-__OUT1(s##_p) __OUT2(m) : : "r" (value), "i" (0), "r" (PORT_BASE+port)); \
+__OUT1(s) __OUT2(m) : : "r" (value), "i" (0), "r" (mips_io_port_base+port)); } \
+__OUT1(s##c) __OUT2(m) : : "r" (value), "ir" (port), "r" (mips_io_port_base)); } \
+__OUT1(s##_p) __OUT2(m) : : "r" (value), "i" (0), "r" (mips_io_port_base+port)); \
 	SLOW_DOWN_IO; } \
-__OUT1(s##c_p) __OUT2(m) : : "r" (value), "ir" (port), "r" (PORT_BASE)); \
+__OUT1(s##c_p) __OUT2(m) : : "r" (value), "ir" (port), "r" (mips_io_port_base)); \
 	SLOW_DOWN_IO; }
 
 #define __IN1(t,s) \
@@ -193,10 +213,10 @@
 __asm__ __volatile__ ("l" #m "\t%0,%1(%2)"
 
 #define __IN(t,m,s) \
-__IN1(t,s) __IN2(m) : "=r" (_v) : "i" (0), "r" (PORT_BASE+port)); return _v; } \
-__IN1(t,s##c) __IN2(m) : "=r" (_v) : "ir" (port), "r" (PORT_BASE)); return _v; } \
-__IN1(t,s##_p) __IN2(m) : "=r" (_v) : "i" (0), "r" (PORT_BASE+port)); SLOW_DOWN_IO; return _v; } \
-__IN1(t,s##c_p) __IN2(m) : "=r" (_v) : "ir" (port), "r" (PORT_BASE)); SLOW_DOWN_IO; return _v; }
+__IN1(t,s) __IN2(m) : "=r" (_v) : "i" (0), "r" (mips_io_port_base+port)); return _v; } \
+__IN1(t,s##c) __IN2(m) : "=r" (_v) : "ir" (port), "r" (mips_io_port_base)); return _v; } \
+__IN1(t,s##_p) __IN2(m) : "=r" (_v) : "i" (0), "r" (mips_io_port_base+port)); SLOW_DOWN_IO; return _v; } \
+__IN1(t,s##c_p) __IN2(m) : "=r" (_v) : "ir" (port), "r" (mips_io_port_base)); SLOW_DOWN_IO; return _v; }
 
 #define __INS1(s) \
 extern inline void __ins##s(unsigned int port, void * addr, unsigned long count) {
@@ -217,11 +237,11 @@
 #define __INS(m,s,i) \
 __INS1(s) __INS2(m) \
 	: "=r" (addr), "=r" (count) \
-	: "0" (addr), "1" (count), "i" (0), "r" (PORT_BASE+port), "I" (i) \
+	: "0" (addr), "1" (count), "i" (0), "r" (mips_io_port_base+port), "I" (i) \
 	: "$1");} \
 __INS1(s##c) __INS2(m) \
 	: "=r" (addr), "=r" (count) \
-	: "0" (addr), "1" (count), "ir" (port), "r" (PORT_BASE), "I" (i) \
+	: "0" (addr), "1" (count), "ir" (port), "r" (mips_io_port_base), "I" (i) \
 	: "$1");}
 
 #define __OUTS1(s) \
@@ -243,11 +263,11 @@
 #define __OUTS(m,s,i) \
 __OUTS1(s) __OUTS2(m) \
 	: "=r" (addr), "=r" (count) \
-	: "0" (addr), "1" (count), "i" (0), "r" (PORT_BASE+port), "I" (i) \
+	: "0" (addr), "1" (count), "i" (0), "r" (mips_io_port_base+port), "I" (i) \
 	: "$1");} \
 __OUTS1(s##c) __OUTS2(m) \
 	: "=r" (addr), "=r" (count) \
-	: "0" (addr), "1" (count), "ir" (port), "r" (PORT_BASE), "I" (i) \
+	: "0" (addr), "1" (count), "ir" (port), "r" (mips_io_port_base), "I" (i) \
 	: "$1");}
 
 __IN(unsigned char,b,b)
diff -u --recursive --new-file v2.1.72/linux/include/asm-mips/ioctls.h linux/include/asm-mips/ioctls.h
--- v2.1.72/linux/include/asm-mips/ioctls.h	Thu Dec  4 14:53:56 1997
+++ linux/include/asm-mips/ioctls.h	Tue Dec 16 12:46:07 1997
@@ -98,7 +98,6 @@
 #define TIOCTTYGSTRUCT	0x5487  /* For debugging only */
 #define TIOCSBRK	0x5427  /* BSD compatibility */
 #define TIOCCBRK	0x5428  /* BSD compatibility */
-#define TIOCGSID	0x5429  /* Return the session ID of FD */
 
 #define TIOCSERCONFIG	0x5488
 #define TIOCSERGWILD	0x5489
@@ -111,7 +110,5 @@
 #define TIOCSERSETMULTI 0x5490 /* Set multiport config */
 #define TIOCMIWAIT      0x5491 /* wait for a change on serial input line(s) */
 #define TIOCGICOUNT     0x5492 /* read serial port inline interrupt counts */
-#define TIOCSBRK	0x5491 /* BSD compatibility */ 
-#define TIOCCBRK	0x5492 /* BSD compatibility */
 
 #endif /* __ASM_MIPS_IOCTLS_H */
diff -u --recursive --new-file v2.1.72/linux/include/asm-mips/irq.h linux/include/asm-mips/irq.h
--- v2.1.72/linux/include/asm-mips/irq.h	Thu Jun 26 12:33:39 1997
+++ linux/include/asm-mips/irq.h	Tue Dec 16 12:46:08 1997
@@ -24,4 +24,22 @@
 extern void disable_irq(unsigned int);
 extern void enable_irq(unsigned int);
 
+extern unsigned int local_irq_count[];
+
+#ifdef __SMP__
+#error Send superfluous SMP boxes to ralf@uni-koblenz.de
+#else
+#define irq_enter(cpu, irq)     (++local_irq_count[cpu])
+#define irq_exit(cpu, irq)      (--local_irq_count[cpu])
+#endif
+
+extern unsigned int local_irq_count[];
+
+#ifdef __SMP__
+#error Send superfluous SMP boxes to ralf@uni-koblenz.de
+#else
+#define irq_enter(cpu, irq)     (++local_irq_count[cpu])
+#define irq_exit(cpu, irq)      (--local_irq_count[cpu])
+#endif
+
 #endif /* __ASM_MIPS_IRQ_H */
diff -u --recursive --new-file v2.1.72/linux/include/asm-mips/jazz.h linux/include/asm-mips/jazz.h
--- v2.1.72/linux/include/asm-mips/jazz.h	Mon Aug  4 16:25:39 1997
+++ linux/include/asm-mips/jazz.h	Tue Dec 16 12:46:08 1997
@@ -8,6 +8,8 @@
  * Copyright (C) 1995 by Andreas Busse and Ralf Baechle
  *
  * This file is a mess. It really needs some reorganisation!
+ *
+ * $Id: jazz.h,v 1.5 1997/12/01 21:26:48 ralf Exp $
  */
 #ifndef __ASM_MIPS_JAZZ_H 
 #define __ASM_MIPS_JAZZ_H 
@@ -183,8 +185,8 @@
 /*
  * JAZZ interrupt control registers
  */
-#define JAZZ_IO_IRQ_SOURCE      0xe0100000
-#define JAZZ_IO_IRQ_ENABLE      0xe0100002
+#define JAZZ_IO_IRQ_SOURCE      0xe0010000
+#define JAZZ_IO_IRQ_ENABLE      0xe0010002
 
 /*
  * JAZZ interrupt enable bits
@@ -205,12 +207,12 @@
  */
 #define JAZZ_TIMER_IRQ          0
 #define JAZZ_KEYBOARD_IRQ       1
-#define JAZZ_ETHERNET_IRQ       13
-#define JAZZ_SERIAL1_IRQ        3
-#define JAZZ_SERIAL2_IRQ        4
-#define JAZZ_PARALLEL_IRQ       5
 #define JAZZ_FLOPPY_IRQ         6 /* needs to be consistent with floppy driver! */
-#define JAZZ_SCSI_INTERRUPT     12
+#define JAZZ_SCSI_IRQ           16
+#define JAZZ_ETHERNET_IRQ       17
+#define JAZZ_SERIAL1_IRQ        18
+#define JAZZ_SERIAL2_IRQ        19
+#define JAZZ_PARALLEL_IRQ       20
 
 /*
  * JAZZ DMA Channels
diff -u --recursive --new-file v2.1.72/linux/include/asm-mips/jazzdma.h linux/include/asm-mips/jazzdma.h
--- v2.1.72/linux/include/asm-mips/jazzdma.h	Mon Aug 18 18:19:46 1997
+++ linux/include/asm-mips/jazzdma.h	Tue Dec 16 12:46:09 1997
@@ -21,7 +21,6 @@
 void vdma_set_addr(int channel, long addr);
 void vdma_set_count(int channel, int count);
 int vdma_get_residue(int channel);
-int vdma_get_enable(int channel);
 
 /*
  * some definitions used by the driver functions
diff -u --recursive --new-file v2.1.72/linux/include/asm-mips/keyboard.h linux/include/asm-mips/keyboard.h
--- v2.1.72/linux/include/asm-mips/keyboard.h	Mon Aug 18 18:19:46 1997
+++ linux/include/asm-mips/keyboard.h	Tue Dec 16 12:46:09 1997
@@ -5,7 +5,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * $Id: keyboard.h,v 1.5 1997/08/08 20:22:31 miguel Exp $
+ * $Id: keyboard.h,v 1.8 1997/12/02 05:51:14 ralf Exp $
  */
 #ifndef __ASM_MIPS_KEYBOARD_H
 #define __ASM_MIPS_KEYBOARD_H
@@ -78,8 +78,7 @@
 
 #endif /* CONFIG_SGI */
 
-#if defined(CONFIG_ACER_PICA_61) || defined(CONFIG_SNI_RM200_PCI) \
-    || defined(CONFIG_DESKSTATION_RPC44) || defined(CONFIG_DESKSTATION_TYNE)
+#if defined(CONFIG_ACER_PICA_61) || defined(CONFIG_SNI_RM200_PCI)
 #define CONF_KEYBOARD_USES_IO_PORTS
 #endif
 
diff -u --recursive --new-file v2.1.72/linux/include/asm-mips/mipsconfig.h linux/include/asm-mips/mipsconfig.h
--- v2.1.72/linux/include/asm-mips/mipsconfig.h	Thu Jun 26 12:33:39 1997
+++ linux/include/asm-mips/mipsconfig.h	Tue Dec 16 12:46:10 1997
@@ -10,17 +10,6 @@
 #ifndef __ASM_MIPS_MIPSCONFIG_H
 #define __ASM_MIPS_MIPSCONFIG_H
 
-/*
- * This is the virtual address to which all ports are being mapped.
- * Must be a value that can be load with a lui instruction.
- */
-#ifndef PORT_BASE
-#if !defined (__LANGUAGE_ASSEMBLY__)
-extern unsigned long port_base;
-#endif
-#define PORT_BASE port_base
-#endif
-
 /* Pgdir is 1 page mapped at 0xff800000. */
 #define TLBMAP			0xff800000
 
diff -u --recursive --new-file v2.1.72/linux/include/asm-mips/mipsregs.h linux/include/asm-mips/mipsregs.h
--- v2.1.72/linux/include/asm-mips/mipsregs.h	Thu Jun 26 12:33:40 1997
+++ linux/include/asm-mips/mipsregs.h	Tue Dec 16 12:46:10 1997
@@ -5,8 +5,10 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1994, 1995, 1996 by Ralf Baechle
+ * Copyright (C) 1994, 1995, 1996, 1997 by Ralf Baechle
  * Modified for further R[236]000 support by Paul M. Antoine, 1996.
+ *
+ * $Id: mipsregs.h,v 1.4 1997/09/20 19:02:46 root Exp $
  */
 #ifndef __ASM_MIPS_MIPSREGS_H
 #define __ASM_MIPS_MIPSREGS_H
@@ -160,7 +162,7 @@
  * Manipulate the status register.
  * Mostly used to access the interrupt bits.
  */
-#define BUILD_SET_CP0(name,register)                            \
+#define __BUILD_SET_CP0(name,register)                          \
 extern __inline__ unsigned int                                  \
 set_cp0_##name(unsigned int change, unsigned int new)           \
 {                                                               \
@@ -175,8 +177,9 @@
 	return res;                                             \
 }
 
-BUILD_SET_CP0(status,CP0_STATUS)
-BUILD_SET_CP0(cause,CP0_CAUSE)
+__BUILD_SET_CP0(status,CP0_STATUS)
+__BUILD_SET_CP0(cause,CP0_CAUSE)
+__BUILD_SET_CP0(config,CP0_CONFIG)
 
 #endif /* defined (__LANGUAGE_ASSEMBLY__) */
 
@@ -251,6 +254,22 @@
  * Status register bits available in all MIPS CPUs.
  */
 #define ST0_IM			0x0000ff00
+#define  STATUSB_IP0		8
+#define  STATUSF_IP0		(1   <<  8)
+#define  STATUSB_IP1		9
+#define  STATUSF_IP1		(1   <<  9)
+#define  STATUSB_IP2		10
+#define  STATUSF_IP2		(1   << 10)
+#define  STATUSB_IP3		11
+#define  STATUSF_IP3		(1   << 11)
+#define  STATUSB_IP4		12
+#define  STATUSF_IP4		(1   << 12)
+#define  STATUSB_IP5		13
+#define  STATUSF_IP5		(1   << 13)
+#define  STATUSB_IP6		14
+#define  STATUSF_IP6		(1   << 14)
+#define  STATUSB_IP7		15
+#define  STATUSF_IP7		(1   << 15)
 #define ST0_DE			0x00010000
 #define ST0_CE			0x00020000
 #define ST0_CH			0x00040000
@@ -290,6 +309,8 @@
 #define  CAUSEF_IP6		(1   << 14)
 #define  CAUSEB_IP7		15
 #define  CAUSEF_IP7		(1   << 15)
+#define  CAUSEB_IV		23
+#define  CAUSEF_IV		(1   << 23)
 #define  CAUSEB_CE		28
 #define  CAUSEF_CE		(3   << 28)
 #define  CAUSEB_BD		31
@@ -298,9 +319,18 @@
 /*
  * Bits in the coprozessor 0 config register.
  */
-#define CONFIG_DB		(1 <<  4)
-#define CONFIG_IB		(1 <<  5)
-#define CONFIG_SC		(1 << 17)
+#define CONFIG_CM_CACHABLE_NO_WA	0
+#define CONFIG_CM_CACHABLE_WA		1
+#define CONFIG_CM_UNCACHED		2
+#define CONFIG_CM_CACHABLE_NONCOHERENT	3
+#define CONFIG_CM_CACHABLE_CE		4
+#define CONFIG_CM_CACHABLE_COW		5
+#define CONFIG_CM_CACHABLE_CUW		6
+#define CONFIG_CM_CACHABLE_ACCELERATED	7
+#define CONFIG_CM_CMASK			7
+#define CONFIG_DB			(1 <<  4)
+#define CONFIG_IB			(1 <<  5)
+#define CONFIG_SC			(1 << 17)
 
 /*
  * R10000 performance counter definitions.
diff -u --recursive --new-file v2.1.72/linux/include/asm-mips/namei.h linux/include/asm-mips/namei.h
--- v2.1.72/linux/include/asm-mips/namei.h	Sun Sep  7 13:10:43 1997
+++ linux/include/asm-mips/namei.h	Tue Dec 16 12:46:10 1997
@@ -2,6 +2,8 @@
  * linux/include/asm-mips/namei.h
  *
  * Included from linux/fs/namei.c
+ *
+ * $Id: namei.h,v 1.6 1997/09/18 07:59:31 root Exp $
  */
 #ifndef __ASM_MIPS_NAMEI_H
 #define __ASM_MIPS_NAMEI_H
@@ -14,7 +16,6 @@
 static inline struct dentry *
 __mips_lookup_dentry(const char *name, int follow_link)
 {
-	int error;
 	struct dentry *base;
 
 	if (current->personality != PER_IRIX32)
diff -u --recursive --new-file v2.1.72/linux/include/asm-mips/ng1.h linux/include/asm-mips/ng1.h
--- v2.1.72/linux/include/asm-mips/ng1.h	Mon Aug 18 18:19:46 1997
+++ linux/include/asm-mips/ng1.h	Tue Dec 16 12:46:10 1997
@@ -24,3 +24,51 @@
         u8 bt445rev;
         u8 paneltype;
 };
+
+#define GFX_NAME_NEWPORT "NG1"
+
+/* ioctls */
+#define NG1_SET_CURSOR_HOTSPOT 21001
+struct ng1_set_cursor_hotspot {
+	unsigned short xhot;
+        unsigned short yhot;
+};
+
+#define NG1_SETDISPLAYMODE     21006
+struct ng1_setdisplaymode_args {
+        int wid;
+        unsigned int mode;
+};
+
+#define NG1_SETGAMMARAMP0      21007
+struct ng1_setgammaramp_args {
+        unsigned char red   [256];
+        unsigned char green [256];
+        unsigned char blue  [256];
+};
+
+
+
+#define GFX_NAME_NEWPORT "NG1"
+
+/* ioctls */
+#define NG1_SET_CURSOR_HOTSPOT 21001
+struct ng1_set_cursor_hotspot {
+	unsigned short xhot;
+        unsigned short yhot;
+};
+
+#define NG1_SETDISPLAYMODE     21006
+struct ng1_setdisplaymode_args {
+        int wid;
+        unsigned int mode;
+};
+
+#define NG1_SETGAMMARAMP0      21007
+struct ng1_setgammaramp_args {
+        unsigned char red   [256];
+        unsigned char green [256];
+        unsigned char blue  [256];
+};
+
+
diff -u --recursive --new-file v2.1.72/linux/include/asm-mips/offset.h linux/include/asm-mips/offset.h
--- v2.1.72/linux/include/asm-mips/offset.h	Mon Jul  7 08:18:55 1997
+++ linux/include/asm-mips/offset.h	Tue Dec 16 12:46:10 1997
@@ -53,32 +53,32 @@
 #define TASK_SIGNAL        12
 #define TASK_BLOCKED       16
 #define TASK_FLAGS         20
-#define TASK_MM            912
+#define TASK_MM            920
 
 /* MIPS specific thread_struct offsets. */
-#define THREAD_REG16   544
-#define THREAD_REG17   548
-#define THREAD_REG18   552
-#define THREAD_REG19   556
-#define THREAD_REG20   560
-#define THREAD_REG21   564
-#define THREAD_REG22   568
-#define THREAD_REG23   572
-#define THREAD_REG28   576
-#define THREAD_REG29   580
-#define THREAD_REG30   584
-#define THREAD_REG31   588
-#define THREAD_STATUS  592
-#define THREAD_FPU     600
-#define THREAD_BVADDR  864
-#define THREAD_ECODE   868
-#define THREAD_TRAPNO  872
-#define THREAD_KSP     876
-#define THREAD_PGDIR   880
-#define THREAD_MFLAGS  884
-#define THREAD_CURDS   888
-#define THREAD_TRAMP   892
-#define THREAD_OLDCTX  896
+#define THREAD_REG16   552
+#define THREAD_REG17   556
+#define THREAD_REG18   560
+#define THREAD_REG19   564
+#define THREAD_REG20   568
+#define THREAD_REG21   572
+#define THREAD_REG22   576
+#define THREAD_REG23   580
+#define THREAD_REG28   584
+#define THREAD_REG29   588
+#define THREAD_REG30   592
+#define THREAD_REG31   596
+#define THREAD_STATUS  600
+#define THREAD_FPU     608
+#define THREAD_BVADDR  872
+#define THREAD_ECODE   876
+#define THREAD_TRAPNO  880
+#define THREAD_KSP     884
+#define THREAD_PGDIR   888
+#define THREAD_MFLAGS  892
+#define THREAD_CURDS   896
+#define THREAD_TRAMP   900
+#define THREAD_OLDCTX  904
 
 /* Linux mm_struct offsets. */
 #define MM_COUNT      12
diff -u --recursive --new-file v2.1.72/linux/include/asm-mips/pci.h linux/include/asm-mips/pci.h
--- v2.1.72/linux/include/asm-mips/pci.h	Thu Jun 26 12:33:40 1997
+++ linux/include/asm-mips/pci.h	Tue Dec 16 12:46:10 1997
@@ -4,36 +4,41 @@
  * for more details.
  *
  * Declarations for the MIPS specific implementation of the PCI BIOS32 services.
+ *
+ * $Id: pci.h,v 1.2 1997/09/20 21:16:37 ralf Exp $
  */
 #ifndef __ASM_MIPS_PCI_H
 #define __ASM_MIPS_PCI_H
 
-extern unsigned long (*_pcibios_init)(unsigned long memory_start, unsigned long memory_end);
-extern unsigned long (*_pcibios_fixup) (unsigned long memory_start,
-                                        unsigned long memory_end);
-extern int (*_pcibios_read_config_byte) (unsigned char bus,
-                                         unsigned char dev_fn,
-                                         unsigned char where,
-                                         unsigned char *val);
-extern int (*_pcibios_read_config_word) (unsigned char bus,
-                                         unsigned char dev_fn,
-                                         unsigned char where,
-                                         unsigned short *val);
-extern int (*_pcibios_read_config_dword) (unsigned char bus,
-                                          unsigned char dev_fn,
-                                          unsigned char where,
-                                          unsigned int *val);
-extern int (*_pcibios_write_config_byte) (unsigned char bus,
-                                          unsigned char dev_fn,
-                                          unsigned char where,
-                                          unsigned char val);
-extern int (*_pcibios_write_config_word) (unsigned char bus,
-                                          unsigned char dev_fn,
-                                          unsigned char where,
-                                          unsigned short val);
-extern int (*_pcibios_write_config_dword) (unsigned char bus,
-                                           unsigned char dev_fn,
-                                           unsigned char where,
-                                           unsigned int val);
+struct pci_ops {
+	unsigned long (*pcibios_fixup) (unsigned long memory_start,
+	                                unsigned long memory_end);
+	int (*pcibios_read_config_byte) (unsigned char bus,
+	                                 unsigned char dev_fn,
+	                                 unsigned char where,
+	                                 unsigned char *val);
+	int (*pcibios_read_config_word) (unsigned char bus,
+	                                 unsigned char dev_fn,
+	                                 unsigned char where,
+	                                 unsigned short *val);
+	int (*pcibios_read_config_dword) (unsigned char bus,
+	                                  unsigned char dev_fn,
+	                                  unsigned char where,
+	                                  unsigned int *val);
+	int (*pcibios_write_config_byte) (unsigned char bus,
+	                                  unsigned char dev_fn,
+	                                  unsigned char where,
+	                                  unsigned char val);
+	int (*pcibios_write_config_word) (unsigned char bus,
+	                                  unsigned char dev_fn,
+	                                  unsigned char where,
+	                                  unsigned short val);
+	int (*pcibios_write_config_dword) (unsigned char bus,
+	                                   unsigned char dev_fn,
+	                                   unsigned char where,
+	                                   unsigned int val);
+};
+
+extern struct pci_ops *pci_ops;
 
 #endif /* __ASM_MIPS_PCI_H */
diff -u --recursive --new-file v2.1.72/linux/include/asm-mips/pgtable.h linux/include/asm-mips/pgtable.h
--- v2.1.72/linux/include/asm-mips/pgtable.h	Mon Aug 18 18:19:46 1997
+++ linux/include/asm-mips/pgtable.h	Tue Dec 16 12:46:11 1997
@@ -16,7 +16,6 @@
  *  - flush_cache_page(mm, vmaddr) flushes a single page
  *  - flush_cache_range(mm, start, end) flushes a range of pages
  *  - flush_page_to_ram(page) write back kernel page to ram
- *
  */
 extern void (*flush_cache_all)(void);
 extern void (*flush_cache_mm)(struct mm_struct *mm);
@@ -25,7 +24,13 @@
 extern void (*flush_cache_page)(struct vm_area_struct *vma, unsigned long page);
 extern void (*flush_cache_sigtramp)(unsigned long addr);
 extern void (*flush_page_to_ram)(unsigned long page);
-#define flush_icache_range(start, end)		do { } while (0)
+#define flush_icache_range(start, end) flush_cache_all()
+
+/*
+ * Prototype of the DMA related cacheflushing stuff.
+ */
+extern void (*flush_cache_pre_dma_out)(unsigned long start, unsigned long size);
+extern void (*flush_cache_post_dma_in)(unsigned long start, unsigned long size);
 
 /* TLB flushing:
  *
diff -u --recursive --new-file v2.1.72/linux/include/asm-mips/posix_types.h linux/include/asm-mips/posix_types.h
--- v2.1.72/linux/include/asm-mips/posix_types.h	Wed Dec 10 11:12:45 1997
+++ linux/include/asm-mips/posix_types.h	Tue Dec 16 12:46:11 1997
@@ -37,7 +37,6 @@
 typedef long		__kernel_clock_t;
 typedef long		__kernel_daddr_t;
 typedef char *		__kernel_caddr_t;
-/* typedef unsigned long	__kernel_sigset_t;  anybody using this type? */
 
 #ifdef __GNUC__
 typedef long long      __kernel_loff_t;
diff -u --recursive --new-file v2.1.72/linux/include/asm-mips/prctl.h linux/include/asm-mips/prctl.h
--- v2.1.72/linux/include/asm-mips/prctl.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-mips/prctl.h	Tue Dec 16 12:46:11 1997
@@ -0,0 +1,84 @@
+/*
+ * IRIX prctl interface
+ *
+ * The IRIX kernel maps a page at PRDA_ADDRESS with the
+ * contents of prda and fills it the bits on prda_sys.
+ * $Id: prctl.h,v 1.1 1997/09/21 22:27:19 miguel Exp $
+ */
+
+#ifndef __PRCTL_H__
+#define __PRCTL_H__
+
+#define PRDA_ADDRESS 0x200000L
+#define PRDA ((struct prda *) PRDA_ADDRESS)
+
+struct prda_sys {
+	pid_t t_pid; 
+        u32   t_hint;
+        u32   t_dlactseq;
+        u32   t_fpflags;
+        u32   t_prid;		/* processor type, $prid CP0 register */
+        u32   t_dlendseq;
+        u64   t_unused1[5];
+        pid_t t_rpid;   
+        s32   t_resched;
+        u32   t_unused[8];
+        u32   t_cpu;		/* current/last cpu */
+
+	/* FIXME: The signal information, not supported by Linux now */
+	u32   t_flags;		/* if true, then the sigprocmask is in userspace */
+	u32   t_sigprocmask [1]; /* the sigprocmask */
+};
+
+struct prda {
+	char fill [0xe00];
+	struct prda_sys prda_sys;
+};
+
+#define t_sys           prda_sys
+
+ptrdiff_t prctl (int op, int v1, int v2);
+
+#endif
+/*
+ * IRIX prctl interface
+ *
+ * The IRIX kernel maps a page at PRDA_ADDRESS with the
+ * contents of prda and fills it the bits on prda_sys.
+ * $Id: prctl.h,v 1.1 1997/12/02 02:28:28 ralf Exp $
+ */
+
+#ifndef __PRCTL_H__
+#define __PRCTL_H__
+
+#define PRDA_ADDRESS 0x200000L
+#define PRDA ((struct prda *) PRDA_ADDRESS)
+
+struct prda_sys {
+	pid_t t_pid; 
+        u32   t_hint;
+        u32   t_dlactseq;
+        u32   t_fpflags;
+        u32   t_prid;		/* processor type, $prid CP0 register */
+        u32   t_dlendseq;
+        u64   t_unused1[5];
+        pid_t t_rpid;   
+        s32   t_resched;
+        u32   t_unused[8];
+        u32   t_cpu;		/* current/last cpu */
+
+	/* FIXME: The signal information, not supported by Linux now */
+	u32   t_flags;		/* if true, then the sigprocmask is in userspace */
+	u32   t_sigprocmask [1]; /* the sigprocmask */
+};
+
+struct prda {
+	char fill [0xe00];
+	struct prda_sys prda_sys;
+};
+
+#define t_sys           prda_sys
+
+ptrdiff_t prctl (int op, int v1, int v2);
+
+#endif
diff -u --recursive --new-file v2.1.72/linux/include/asm-mips/processor.h linux/include/asm-mips/processor.h
--- v2.1.72/linux/include/asm-mips/processor.h	Thu Jun 26 12:33:40 1997
+++ linux/include/asm-mips/processor.h	Tue Dec 16 12:46:11 1997
@@ -4,6 +4,8 @@
  * Copyright (C) 1994  Waldorf Electronics
  * written by Ralf Baechle
  * Modified further for R[236]000 compatibility by Paul M. Antoine
+ *
+ * $Id: processor.h,v 1.5 1997/12/01 16:48:39 ralf Exp $
  */
 #ifndef __ASM_MIPS_PROCESSOR_H
 #define __ASM_MIPS_PROCESSOR_H
@@ -15,9 +17,11 @@
 #include <asm/system.h>
 
 /*
- * System setup and hardware bug flags..
+ * System setup and hardware flags..
  */
 extern char wait_available;		/* only available on R4[26]00 */
+extern char cyclecounter_available;	/* only available from R4000 upwards. */
+extern char dedicated_iv_available;	/* some embedded MIPS like Nevada */
 
 /*
  * Bus types (default is ISA, but people can check others with these..)
@@ -77,6 +81,10 @@
 	{{0,},} \
 }
 
+typedef struct {
+	unsigned long seg;
+} mm_segment_t;
+
 /*
  * If you change thread_struct remember to change the #defines below too!
  */
@@ -101,7 +109,7 @@
 #define MF_FIXADE 1			/* Fix address errors in software */
 #define MF_LOGADE 2			/* Log address errors to syslog */
 	unsigned long mflags;
-	int current_ds;
+	mm_segment_t current_ds;
 	unsigned long irix_trampoline;  /* Wheee... */
 	unsigned long irix_oldctx;
 };
@@ -128,7 +136,7 @@
 	/* \
 	 * Other stuff associated with the process \
 	 */ \
-	0, 0, 0, (unsigned long)&init_task_union + KERNEL_STACK_SIZE - 8, \
+	0, 0, 0, (unsigned long)&init_task_union + KERNEL_STACK_SIZE - 32, \
 	(unsigned long) swapper_pg_dir, \
 	/* \
 	 * For now the default is to fix address errors \
@@ -150,7 +158,13 @@
  */
 extern inline unsigned long thread_saved_pc(struct thread_struct *t)
 {
-	return ((struct pt_regs *)(long)t->reg29)->cp0_epc;
+	extern void ret_from_sys_call(void);
+
+	/* New born processes are a special case */
+	if (t->reg31 == (unsigned long) ret_from_sys_call)
+		return t->reg31;
+
+	return ((unsigned long*)t->reg29)[17];
 }
 
 /*
@@ -161,7 +175,8 @@
 /*
  * Does the process account for user or for system time?
  */
-#define USES_USER_TIME(regs) (!((regs)->cp0_status & 0x18))
+extern int (*running_in_user_mode)(void);
+#define USES_USER_TIME(regs) running_in_user_mode()
 
 /* Allocation and freeing of basic task resources. */
 /*
diff -u --recursive --new-file v2.1.72/linux/include/asm-mips/r4kcache.h linux/include/asm-mips/r4kcache.h
--- v2.1.72/linux/include/asm-mips/r4kcache.h	Mon Jul  7 08:18:55 1997
+++ linux/include/asm-mips/r4kcache.h	Tue Dec 16 12:46:12 1997
@@ -1,11 +1,16 @@
-/* $Id: r4kcache.h,v 1.2 1997/06/25 17:04:19 ralf Exp $
+/*
  * r4kcache.h: Inline assembly cache operations.
  *
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ *
+ * $Id: r4kcache.h,v 1.5 1997/12/01 16:47:05 ralf Exp $
+ *
+ * FIXME: Handle split L2 caches.
  */
 #ifndef _MIPS_R4KCACHE_H
 #define _MIPS_R4KCACHE_H
 
+#include <asm/asm.h>
 #include <asm/cacheops.h>
 
 extern inline void flush_icache_line_indexed(unsigned long addr)
@@ -73,6 +78,58 @@
 		  "i" (Hit_Writeback_Inv_D));
 }
 
+extern inline void invalidate_dcache_line(unsigned long addr)
+{
+	__asm__ __volatile__(
+		".set noreorder\n\t"
+		".set mips3\n\t"
+		"cache %1, (%0)\n\t"
+		".set mips0\n\t"
+		".set reorder"
+		:
+		: "r" (addr),
+		  "i" (Hit_Invalidate_D));
+}
+
+extern inline void invalidate_scache_line(unsigned long addr)
+{
+	__asm__ __volatile__(
+		".set noreorder\n\t"
+		".set mips3\n\t"
+		"cache %1, (%0)\n\t"
+		".set mips0\n\t"
+		".set reorder"
+		:
+		: "r" (addr),
+		  "i" (Hit_Invalidate_SD));
+}
+
+extern inline void invalidate_dcache_line(unsigned long addr)
+{
+	__asm__ __volatile__(
+		".set noreorder\n\t"
+		".set mips3\n\t"
+		"cache %1, (%0)\n\t"
+		".set mips0\n\t"
+		".set reorder"
+		:
+		: "r" (addr),
+		  "i" (Hit_Invalidate_D));
+}
+
+extern inline void invalidate_scache_line(unsigned long addr)
+{
+	__asm__ __volatile__(
+		".set noreorder\n\t"
+		".set mips3\n\t"
+		"cache %1, (%0)\n\t"
+		".set mips0\n\t"
+		".set reorder"
+		:
+		: "r" (addr),
+		  "i" (Hit_Invalidate_SD));
+}
+
 extern inline void flush_scache_line(unsigned long addr)
 {
 	__asm__ __volatile__(
@@ -86,6 +143,76 @@
 		  "i" (Hit_Writeback_Inv_SD));
 }
 
+/*
+ * The next two are for badland addresses like signal trampolines.
+ */
+extern inline void protected_flush_icache_line(unsigned long addr)
+{
+	__asm__ __volatile__(
+		".set noreorder\n\t"
+		".set mips3\n"
+		"1:\tcache %1,(%0)\n"
+		"2:\t.set mips0\n\t"
+		".set reorder\n\t"
+		".section\t__ex_table,\"a\"\n\t"
+		STR(PTR)"\t1b,2b\n\t"
+		".previous"
+		:
+		: "r" (addr),
+		  "i" (Hit_Invalidate_I));
+}
+
+extern inline void protected_writeback_dcache_line(unsigned long addr)
+{
+	__asm__ __volatile__(
+		".set noreorder\n\t"
+		".set mips3\n"
+		"1:\tcache %1,(%0)\n"
+		"2:\t.set mips0\n\t"
+		".set reorder\n\t"
+		".section\t__ex_table,\"a\"\n\t"
+		STR(PTR)"\t1b,2b\n\t"
+		".previous"
+		:
+		: "r" (addr),
+		  "i" (Hit_Writeback_D));
+}
+
+/*
+ * The next two are for badland addresses like signal trampolines.
+ */
+extern inline void protected_flush_icache_line(unsigned long addr)
+{
+	__asm__ __volatile__(
+		".set noreorder\n\t"
+		".set mips3\n"
+		"1:\tcache %1,(%0)\n"
+		"2:\t.set mips0\n\t"
+		".set reorder\n\t"
+		".section\t__ex_table,\"a\"\n\t"
+		STR(PTR)"\t1b,2b\n\t"
+		".previous"
+		:
+		: "r" (addr),
+		  "i" (Hit_Invalidate_I));
+}
+
+extern inline void protected_writeback_dcache_line(unsigned long addr)
+{
+	__asm__ __volatile__(
+		".set noreorder\n\t"
+		".set mips3\n"
+		"1:\tcache %1,(%0)\n"
+		"2:\t.set mips0\n\t"
+		".set reorder\n\t"
+		".section\t__ex_table,\"a\"\n\t"
+		STR(PTR)"\t1b,2b\n\t"
+		".previous"
+		:
+		: "r" (addr),
+		  "i" (Hit_Writeback_D));
+}
+
 extern inline void blast_dcache16(void)
 {
 	unsigned long start = KSEG0;
@@ -334,10 +461,27 @@
 	}
 }
 
+/*
+ * Call this function only with interrupts disabled or R4600 V2.0 may blow
+ * you up.
+ *
+ * R4600 v2.0 bug: "The CACHE instructions Hit_Writeback_Inv_D,
+ * Hit_Writeback_D, Hit_Invalidate_D and Create_Dirty_Excl_D will only
+ * operate correctly if the internal data cache refill buffer is empty.  These
+ * CACHE instructions should be separated from any potential data cache miss
+ * by a load instruction to an uncached address to empty the response buffer."
+ * (Revision 2.0 device errata from IDT available on http://www.idt.com/
+ * in .pdf format.)
+ */
 extern inline void blast_dcache32_page(unsigned long page)
 {
 	unsigned long start = page;
 	unsigned long end = (start + PAGE_SIZE);
+
+	/*
+	 * Sigh ... workaround for R4600 v1.7 bug.  Explanation see above.
+	 */
+	*(volatile unsigned long *)KSEG1;
 
 	__asm__ __volatile__("nop;nop;nop;nop");
 	while(start < end) {
diff -u --recursive --new-file v2.1.72/linux/include/asm-mips/scatterlist.h linux/include/asm-mips/scatterlist.h
--- v2.1.72/linux/include/asm-mips/scatterlist.h	Thu Jun 26 12:33:40 1997
+++ linux/include/asm-mips/scatterlist.h	Tue Dec 16 12:46:12 1997
@@ -6,6 +6,15 @@
     char * alt_address; /* Location of actual if address is a 
 			 * dma indirect buffer.  NULL otherwise */
     unsigned int length;
+    
+    __u32 dvma_address;
+};
+
+struct mmu_sglist {
+        char *addr;
+        char *__dont_touch;
+        unsigned int len;
+        __u32 dvma_addr;
 };
 
 #define ISA_DMA_THRESHOLD (0x00ffffff)
diff -u --recursive --new-file v2.1.72/linux/include/asm-mips/sgi.h linux/include/asm-mips/sgi.h
--- v2.1.72/linux/include/asm-mips/sgi.h	Thu Jun 26 12:33:40 1997
+++ linux/include/asm-mips/sgi.h	Wed Dec 10 10:31:11 1997
@@ -1,4 +1,4 @@
-/* $Id: sgi.h,v 1.1 1997/06/06 09:39:54 ralf Exp $
+/* $Id: sgi.h,v 1.1.1.1 1997/06/01 03:17:12 ralf Exp $
  * sgi.h: Definitions specific to SGI machines.
  *
  * Copyright (C) 1996 David S. Miller (dm@sgi.com)
diff -u --recursive --new-file v2.1.72/linux/include/asm-mips/sgialib.h linux/include/asm-mips/sgialib.h
--- v2.1.72/linux/include/asm-mips/sgialib.h	Thu Jun 26 12:33:40 1997
+++ linux/include/asm-mips/sgialib.h	Wed Dec 10 10:31:11 1997
@@ -1,4 +1,4 @@
-/* $Id: sgialib.h,v 1.1 1997/06/06 09:39:56 ralf Exp $
+/* $Id: sgialib.h,v 1.1.1.1 1997/06/01 03:17:13 ralf Exp $
  * sgialib.h: SGI ARCS firmware interface library for the Linux kernel.
  *
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
diff -u --recursive --new-file v2.1.72/linux/include/asm-mips/sgiarcs.h linux/include/asm-mips/sgiarcs.h
--- v2.1.72/linux/include/asm-mips/sgiarcs.h	Thu Jun 26 12:33:40 1997
+++ linux/include/asm-mips/sgiarcs.h	Wed Dec 10 10:31:11 1997
@@ -1,4 +1,4 @@
-/* $Id: sgiarcs.h,v 1.1 1997/06/06 09:39:58 ralf Exp $
+/* $Id: sgiarcs.h,v 1.1.1.1 1997/06/01 03:17:12 ralf Exp $
  * SGI ARCS firmware interface defines.
  *
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
diff -u --recursive --new-file v2.1.72/linux/include/asm-mips/sgihpc.h linux/include/asm-mips/sgihpc.h
--- v2.1.72/linux/include/asm-mips/sgihpc.h	Thu Jun 26 12:33:40 1997
+++ linux/include/asm-mips/sgihpc.h	Wed Dec 10 10:31:11 1997
@@ -1,4 +1,4 @@
-/* $Id: sgihpc.h,v 1.1 1997/06/06 09:40:02 ralf Exp $
+/* $Id: sgihpc.h,v 1.1.1.1 1997/06/01 03:17:12 ralf Exp $
  * sgihpc.h: Various HPC I/O controller defines.  The HPC is basically
  *           the approximate functional equivalent of the Sun SYSIO
  *           on SGI INDY machines.
diff -u --recursive --new-file v2.1.72/linux/include/asm-mips/sgimc.h linux/include/asm-mips/sgimc.h
--- v2.1.72/linux/include/asm-mips/sgimc.h	Thu Jun 26 12:33:40 1997
+++ linux/include/asm-mips/sgimc.h	Wed Dec 10 10:31:11 1997
@@ -1,4 +1,4 @@
-/* $Id: sgimc.h,v 1.1 1997/06/06 09:40:04 ralf Exp $
+/* $Id: sgimc.h,v 1.1.1.1 1997/06/01 03:17:13 ralf Exp $
  * sgimc.h: Definitions for memory controller hardware found on
  *          SGI IP20, IP22, IP26, and IP28 machines.
  *
diff -u --recursive --new-file v2.1.72/linux/include/asm-mips/sgint23.h linux/include/asm-mips/sgint23.h
--- v2.1.72/linux/include/asm-mips/sgint23.h	Thu Jun 26 12:33:40 1997
+++ linux/include/asm-mips/sgint23.h	Wed Dec 10 10:31:11 1997
@@ -1,4 +1,4 @@
-/* $Id: sgint23.h,v 1.1 1997/06/06 09:40:06 ralf Exp $
+/* $Id: sgint23.h,v 1.1.1.1 1997/06/01 03:17:12 ralf Exp $
  * sgint23.h: Defines for the SGI INT2 and INT3 chipsets.
  *
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
diff -u --recursive --new-file v2.1.72/linux/include/asm-mips/shmiq.h linux/include/asm-mips/shmiq.h
--- v2.1.72/linux/include/asm-mips/shmiq.h	Mon Aug 18 18:19:46 1997
+++ linux/include/asm-mips/shmiq.h	Tue Dec 16 12:46:13 1997
@@ -174,13 +174,43 @@
 	char *nothing_for_now;
 } idevInfo;
 
+#define IDEV_KEYMAP_NAME_LEN 15
+
 typedef struct {
-        char name [16];
+        char name[IDEV_KEYMAP_NAME_LEN+1];
 } idevKeymapDesc;
 
-#define IDEVINITDEVICE		_IOW('i', 51, unsigned int)
-#define IDEVGETDEVICEDESC	_IOWR('i', 0, idevDesc)
-#define IDEVGETKEYMAPDESC	_IOWR('i', 2, idevKeymapDesc)
+/* The valuator definition */
+typedef struct {
+        unsigned        hwMinRes;
+        unsigned        hwMaxRes;
+        int             hwMinVal;
+        int             hwMaxVal;
+	
+        unsigned char   possibleModes;
+#define IDEV_ABSOLUTE           0x0
+#define IDEV_RELATIVE           0x1
+#define IDEV_EITHER             0x2
+	
+        unsigned char   mode;	/* One of: IDEV_ABSOLUTE, IDEV_RELATIVE */
+	
+        unsigned short  resolution;
+        int             minVal;
+        int             maxVal;
+} idevValuatorDesc;
+
+/* This is used to query a specific valuator with the IDEVGETVALUATORDESC ioctl */
+typedef struct {
+        short                   valNum;
+        unsigned short          flags;
+        idevValuatorDesc        desc;
+} idevGetSetValDesc;
+
+#define IDEVGETDEVICEDESC	_IOWR('i', 0,  idevDesc)
+#define IDEVGETVALUATORDESC     _IOWR('i', 1,  idevGetSetValDesc)
+#define IDEVGETKEYMAPDESC	_IOWR('i', 2,  idevKeymapDesc)
+#define IDEVINITDEVICE		_IOW ('i', 51, unsigned int)
+
 
 #ifdef __KERNEL__
 
diff -u --recursive --new-file v2.1.72/linux/include/asm-mips/sigcontext.h linux/include/asm-mips/sigcontext.h
--- v2.1.72/linux/include/asm-mips/sigcontext.h	Mon Jul  7 08:18:55 1997
+++ linux/include/asm-mips/sigcontext.h	Tue Dec 16 12:46:14 1997
@@ -1,5 +1,5 @@
 /*
- * include/asm-mips/uaccess.h
+ * include/asm-mips/sigcontext.h
  *
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
@@ -7,7 +7,7 @@
  *
  * Copyright (C) 1996, 1997 by Ralf Baechle
  *
- * $Id: sigcontext.h,v 1.3 1997/06/25 16:57:31 ralf Exp $
+ * $Id: sigcontext.h,v 1.4 1997/12/01 16:46:19 ralf Exp $
  */
 #ifndef __ASM_MIPS_SIGCONTEXT_H
 #define __ASM_MIPS_SIGCONTEXT_H
@@ -32,7 +32,7 @@
 	unsigned int       sc_cause;		/* Unused */
 	unsigned int       sc_badvaddr;		/* Unused */
 
-	sigset_t           sc_sigset;
+	unsigned long      sc_sigset;		/* kernel's sigset_t */
 	unsigned long      __pad0[3];		/* pad for constant size */
 };
 
diff -u --recursive --new-file v2.1.72/linux/include/asm-mips/siginfo.h linux/include/asm-mips/siginfo.h
--- v2.1.72/linux/include/asm-mips/siginfo.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-mips/siginfo.h	Tue Dec 16 12:46:14 1997
@@ -0,0 +1,195 @@
+#ifndef __ASM_MIPS_SIGINFO_H
+#define __ASM_MIPS_SIGINFO_H
+
+#include <linux/types.h>
+
+/* This structure matches OSF/1 for binary compatibility. */
+
+typedef union sigval {
+	int sival_int;
+	void *sival_ptr;
+} sigval_t;
+
+#define SI_MAX_SIZE	128
+#define SI_PAD_SIZE	((SI_MAX_SIZE/sizeof(int)) - 4)
+
+typedef struct siginfo {
+	int si_signo;
+	int si_errno;
+	int si_code;
+
+	union {
+		int _pad[SI_PAD_SIZE];
+
+		/* kill() */
+		struct {
+			pid_t _pid;		/* sender's pid */
+			uid_t _uid;		/* sender's uid */
+		} _kill;
+
+		/* POSIX.1b timers */
+		struct {
+			unsigned int _timer1;
+			unsigned int _timer2;
+		} _timer;
+
+		/* POSIX.1b signals */
+		struct {
+			pid_t _pid;		/* sender's pid */
+			uid_t _uid;		/* sender's uid */
+			sigval_t _sigval;
+		} _rt;
+
+		/* SIGCHLD */
+		struct {
+			pid_t _pid;		/* which child */
+			int _status;		/* exit code */
+			clock_t _utime;
+			clock_t _stime;
+		} _sigchld;
+
+		/* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
+		struct {
+			void *_addr; /* faulting insn/memory ref. */
+		} _sigfault;
+
+		/* SIGPOLL */
+		struct {
+			int _band;	/* POLL_IN, POLL_OUT, POLL_MSG */
+			int _fd;
+		} _sigpoll;
+	} _sifields;
+} siginfo_t;
+
+/*
+ * How these fields are to be accessed.
+ */
+#define si_pid		_sifields._kill._pid
+#define si_uid		_sifields._kill._uid
+#define si_status	_sifields._sigchld._status
+#define si_utime	_sifields._sigchld._utime
+#define si_stime	_sifields._sigchld._stime
+#define si_value	_sifields._rt._sigval
+#define si_int		_sifields._rt._sigval.sival_int
+#define si_ptr		_sifields._rt._sigval.sival_ptr
+#define si_addr		_sifields._sigfault._addr
+#define si_band		_sifields._sigpoll._band
+#define si_fd		_sifields._sigpoll._fd
+
+/*
+ * si_code values
+ * Digital reserves positive values for kernel-generated signals.
+ */
+#define SI_USER		0	/* sent by kill, sigsend, raise */
+#define SI_KERNEL	0x80	/* sent by the kernel from somewhere */
+#define SI_QUEUE	-1	/* sent by sigqueue */
+#define SI_TIMER	-2	/* sent by timer expiration */
+#define SI_MESGQ	-3	/* sent by real time mesq state change */
+#define SI_ASYNCIO	-4	/* sent by AIO completion */
+
+#define SI_FROMUSER(siptr)	((siptr)->si_code <= 0)
+#define SI_FROMKERNEL(siptr)	((siptr)->si_code > 0)
+
+/*
+ * SIGILL si_codes
+ */
+#define ILL_ILLOPC	1	/* illegal opcode */
+#define ILL_ILLOPN	2	/* illegal operand */
+#define ILL_ILLADR	3	/* illegal addressing mode */
+#define ILL_ILLTRP	4	/* illegal trap */
+#define ILL_PRVOPC	5	/* privileged opcode */
+#define ILL_PRVREG	6	/* privileged register */
+#define ILL_COPROC	7	/* coprocessor error */
+#define ILL_BADSTK	8	/* internal stack error */
+#define NSIGILL		8
+
+/*
+ * SIGFPE si_codes
+ */
+#define FPE_INTDIV	1	/* integer divide by zero */
+#define FPE_INTOVF	2	/* integer overflow */
+#define FPE_FLTDIV	3	/* floating point divide by zero */
+#define FPE_FLTOVF	4	/* floating point overflow */
+#define FPE_FLTUND	5	/* floating point underflow */
+#define FPE_FLTRES	6	/* floating point inexact result */
+#define FPE_FLTINV	7	/* floating point invalid operation */
+#define FPE_FLTSUB	8	/* subscript out of range */
+#define NSIGFPE		8
+
+/*
+ * SIGSEGV si_codes
+ */
+#define SEGV_MAPERR	1	/* address not mapped to object */
+#define SEGV_ACCERR	2	/* invalid permissions for mapped object */
+#define NSIGSEGV	2
+
+/*
+ * SIGBUS si_codes
+ */
+#define BUS_ADRALN	1	/* invalid address alignment */
+#define BUS_ADRERR	2	/* non-existant physical address */
+#define BUS_OBJERR	3	/* object specific hardware error */
+#define NSIGBUS		3
+
+/*
+ * SIGTRAP si_codes
+ */
+#define TRAP_BRKPT	1	/* process breakpoint */
+#define TRAP_TRACE	2	/* process trace trap */
+#define NSIGTRAP
+
+/*
+ * SIGCHLD si_codes
+ */
+#define CLD_EXITED	1	/* child has exited */
+#define CLD_KILLED	2	/* child was killed */
+#define CLD_DUMPED	3	/* child terminated abnormally */
+#define CLD_TRAPPED	4	/* traced child has trapped */
+#define CLD_STOPPED	5	/* child has stopped */
+#define CLD_CONTINUED	6	/* stopped child has continued */
+#define NSIGCHLD
+
+/*
+ * SIGPOLL si_codes
+ */
+#define POLL_IN		1	/* data input available */
+#define POLL_OUT	2	/* output buffers available */
+#define POLL_MSG	3	/* input message available */
+#define POLL_ERR	4	/* i/o error */
+#define POLL_PRI	5	/* high priority input available */
+#define POLL_HUP	6	/* device disconnected */
+#define NSIGPOLL	6
+
+/*
+ * sigevent definitions
+ * 
+ * It seems likely that SIGEV_THREAD will have to be handled from 
+ * userspace, libpthread transmuting it to SIGEV_SIGNAL, which the
+ * thread manager then catches and does the appropriate nonsense.
+ * However, everything is written out here so as to not get lost.
+ */
+#define SIGEV_SIGNAL	0	/* notify via signal */
+#define SIGEV_NONE	1	/* other notification: meaningless */
+#define SIGEV_THREAD	2	/* deliver via thread creation */
+
+#define SIGEV_MAX_SIZE	64
+#define SIGEV_PAD_SIZE	((SIGEV_MAX_SIZE/sizeof(int)) - 4)
+
+typedef struct sigevent {
+	sigval_t sigev_value;
+	int sigev_signo;
+	int sigev_notify;
+	union {
+		int _pad[SIGEV_PAD_SIZE];
+
+		struct {
+			void (*_function)(sigval_t);
+			void *_attribute;	/* really pthread_attr_t */
+		} _sigev_thread;
+	} _sigev_un;
+} sigevent_t;
+
+#define sigev_notify_function	_sigev_un._sigev_thread._function
+#define sigev_notify_attributes	_sigev_un._sigev_thread._attribute
+
+#endif /* __ASM_MIPS_SIGINFO_H */
diff -u --recursive --new-file v2.1.72/linux/include/asm-mips/signal.h linux/include/asm-mips/signal.h
--- v2.1.72/linux/include/asm-mips/signal.h	Thu Jun 26 12:33:40 1997
+++ linux/include/asm-mips/signal.h	Tue Dec 16 12:46:14 1997
@@ -5,40 +5,20 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1995, 1996 by Ralf Baechle
+ * Copyright (C) 1995, 1996, 1997 by Ralf Baechle
+ *
+ * $Id: signal.h,v 1.2 1997/09/07 05:27:50 ralf Exp $
  */
 #ifndef __ASM_MIPS_SIGNAL_H
+#define __ASM_MIPS_SIGNAL_H
 
 #include <asm/sgidefs.h>
 
-/* Any one of these symbols __need_* means that GNU libc
-   wants us just to define one data type.  So don't define
-   the symbols that indicate this file's entire job has been done.  */
-#if !defined(__need_signums) && !defined(__need_fake_sigfuns) && \
-    !defined(__need__nsig)
-#define __ASM_MIPS_SIGNAL_H
-#endif
-
-#ifdef __ASM_MIPS_SIGNAL_H
 typedef unsigned long sigset_t;
-#endif /* __ASM_MIPS_SIGNAL_H */
 
-#if !defined (___nsig_defined) && \
-    (defined (__ASM_MIPS_SIGNAL_H) || defined (__need__nsig))
-#define ___nsig_defined
-#define _NSIG		65
-#endif
-#undef __need__nsig
-#ifdef __KERNEL__
+#define _NSIG		32
 #define NSIG		_NSIG
-#endif
 
-#if !defined (__signums_defined) && \
-    (defined (__ASM_MIPS_SIGNAL_H) || defined (__need_signums))
-#define __signums_defined
-/*
- * For 1.3.0 Linux/MIPS changed the signal numbers to be compatible the ABI.
- */
 #define SIGHUP		 1	/* Hangup (POSIX).  */
 #define SIGINT		 2	/* Interrupt (ANSI).  */
 #define SIGQUIT		 3	/* Quit (POSIX).  */
@@ -73,10 +53,7 @@
 #define SIGPROF		29	/* Profiling alarm clock (4.2 BSD).  */
 #define SIGXCPU		30	/* CPU limit exceeded (4.2 BSD).  */
 #define SIGXFSZ		31	/* File size limit exceeded (4.2 BSD).  */
-#endif /* need signums */
-#undef __need_signums
 
-#ifdef __ASM_MIPS_SIGNAL_H
 /*
  * sa_flags values: SA_STACK is not currently supported, but will allow the
  * usage of signal stacks by using the (now obsolete) sa_restorer field in
@@ -113,24 +90,14 @@
 #define SIG_SETMASK32	256	/* Goodie from SGI for BSD compatibility:
 				   set only the low 32 bit of the sigset.  */
 
-#ifndef __sighandler_t_defined
-#define __sighandler_t_defined
 /* Type of a signal handler.  */
 typedef void (*__sighandler_t)(int);
-#endif
-#endif
 
-#if !defined (__fake_sigfuns_defined) && \
-    (defined (__ASM_MIPS_SIGNAL_H) || defined (__need_fake_sigfuns))
-#define __fake_sigfuns_defined
 /* Fake signal functions */
 #define SIG_DFL	((__sighandler_t)0)	/* default signal handling */
 #define SIG_IGN	((__sighandler_t)1)	/* ignore signal */
 #define SIG_ERR	((__sighandler_t)-1)	/* error return from signal */
-#endif
-#undef __need_fake_sigfuns
 
-#ifdef __ASM_MIPS_SIGNAL_H
 struct sigaction {
 	unsigned int	sa_flags;
 	__sighandler_t	sa_handler;
@@ -173,6 +140,5 @@
 #define _BRK_THREADBP	11	/* For threads, user bp (used by debuggers) */
 #define BRK_MULOVF	1023	/* Multiply overflow */
 #endif /* defined (__KERNEL__) || defined (__USE_MISC) */
-#endif /* defined (__ASM_MIPS_SIGNAL_H) */
 
 #endif /* !defined (__ASM_MIPS_SIGNAL_H) */
diff -u --recursive --new-file v2.1.72/linux/include/asm-mips/socket.h linux/include/asm-mips/socket.h
--- v2.1.72/linux/include/asm-mips/socket.h	Thu Jul 17 10:06:08 1997
+++ linux/include/asm-mips/socket.h	Tue Dec 16 12:46:14 1997
@@ -1,3 +1,9 @@
+/*
+ * $Id: socket.h,v 1.4 1997/12/06 20:32:40 ralf Exp $
+ */
+/*
+ * $Id: socket.h,v 1.4 1997/12/06 23:55:49 ralf Exp $
+ */
 #ifndef __ASM_MIPS_SOCKET_H
 #define __ASM_MIPS_SOCKET_H
 
@@ -47,20 +53,19 @@
 #define SO_SECURITY_ENCRYPTION_TRANSPORT	23
 #define SO_SECURITY_ENCRYPTION_NETWORK		24
 
+#define SO_BINDTODEVICE		25
+
 /* Types of sockets.  */
-enum __socket_type
-{
-  SOCK_DGRAM = 1,               /* Connectionless, unreliable datagrams
-                                   of fixed maximum length.  */
-  SOCK_STREAM = 2,              /* Sequenced, reliable, connection-based
-                                   byte streams.  */
-  SOCK_RAW = 3,                 /* Raw protocol interface.  */
-  SOCK_RDM = 4,                 /* Reliably-delivered messages.  */
-  SOCK_SEQPACKET = 5,           /* Sequenced, reliable, connection-based,
-                                   datagrams of fixed maximum length.  */
-  SOCK_PACKET = 10,		/* linux specific way of getting packets at
+#define SOCK_DGRAM 1		/* Connectionless, unreliable datagrams
+				   of fixed maximum length.  */
+#define SOCK_STREAM 2		/* Sequenced, reliable, connection-based
+				   byte streams.  */
+#define SOCK_RAW 3		/* Raw protocol interface.  */
+#define SOCK_RDM 4		/* Reliably-delivered messages.  */
+#define SOCK_SEQPACKET 5	/* Sequenced, reliable, connection-based,
+				   datagrams of fixed maximum length.  */
+#define SOCK_PACKET 10		/* Linux specific way of getting packets at
 				   the dev level.  For writing rarp and
 				   other similar things on the user level.  */
-};
 
 #endif /* __ASM_MIPS_SOCKET_H */
diff -u --recursive --new-file v2.1.72/linux/include/asm-mips/stackframe.h linux/include/asm-mips/stackframe.h
--- v2.1.72/linux/include/asm-mips/stackframe.h	Thu Jun 26 12:33:40 1997
+++ linux/include/asm-mips/stackframe.h	Wed Dec 10 10:31:11 1997
@@ -10,8 +10,11 @@
 #include <asm/offset.h>
 
 #define SAVE_ALL                                         \
+		.set	push;                            \
+		.set	reorder;                         \
 		mfc0	k0, CP0_STATUS;                  \
 		sll	k0, 3;     /* extract cu0 bit */ \
+		.set	pop;                             \
 		bltz	k0, 8f;                          \
 		 move	k1, sp;                          \
 		/* Called from user mode, new stack. */  \
@@ -68,7 +71,10 @@
  * that a modified IE mask will be nullified.
  */
 #define RESTORE_ALL                                      \
+		.set	push;                            \
+		.set	reorder;                         \
 		mfc0	t0, CP0_STATUS;                  \
+		.set	pop;                             \
 		ori	t0, 0x1f;                        \
 		xori	t0, 0x1f;                        \
 		mtc0	t0, CP0_STATUS;                  \
diff -u --recursive --new-file v2.1.72/linux/include/asm-mips/string.h linux/include/asm-mips/string.h
--- v2.1.72/linux/include/asm-mips/string.h	Mon Aug 18 18:19:46 1997
+++ linux/include/asm-mips/string.h	Wed Dec 10 10:31:11 1997
@@ -7,7 +7,7 @@
  *
  * Copyright (c) 1994, 1995, 1996, 1997 by Ralf Baechle
  *
- * $Id: string.h,v 1.4 1997/08/08 20:22:34 miguel Exp $
+ * $Id: string.h,v 1.3 1997/08/11 04:11:53 ralf Exp $
  */
 #ifndef __ASM_MIPS_STRING_H
 #define __ASM_MIPS_STRING_H
@@ -94,25 +94,25 @@
 #define __HAVE_ARCH_STRNCMP
 extern __inline__ int strncmp(__const__ char *__cs, __const__ char *__ct, size_t __count)
 {
-  char __res;
+  int __res;
 
   __asm__ __volatile__(
 	".set\tnoreorder\n\t"
 	".set\tnoat\n"
-       	"1:\tlbu\t%3,(%0)\n\t"
+	"1:\tlbu\t%3,(%0)\n\t"
 	"beqz\t%2,2f\n\t"
-        "lbu\t$1,(%1)\n\t"
-       	"subu\t%2,1\n\t"
-        "bne\t$1,%3,3f\n\t"
-        "addiu\t%0,1\n\t"
-        "bnez\t%3,1b\n\t"
-        "addiu\t%1,1\n"
+	"lbu\t$1,(%1)\n\t"
+	"subu\t%2,1\n\t"
+	"bne\t$1,%3,3f\n\t"
+	"addiu\t%0,1\n\t"
+	"bnez\t%3,1b\n\t"
+	"addiu\t%1,1\n"
 	"2:\tmove\t%3,$1\n"
 	"3:\tsubu\t%3,$1\n\t"
 	".set\tat\n\t"
 	".set\treorder"
-        : "=r" (__cs), "=r" (__ct), "=r" (__count), "=r" (__res)
-        : "0" (__cs), "1" (__ct), "2" (__count)
+	: "=r" (__cs), "=r" (__ct), "=r" (__count), "=r" (__res)
+	: "0" (__cs), "1" (__ct), "2" (__count)
 	: "$1");
 
   return __res;
diff -u --recursive --new-file v2.1.72/linux/include/asm-mips/system.h linux/include/asm-mips/system.h
--- v2.1.72/linux/include/asm-mips/system.h	Mon Aug 18 18:19:46 1997
+++ linux/include/asm-mips/system.h	Wed Dec 10 10:31:11 1997
@@ -252,13 +252,6 @@
 	return x;
 }
 
-extern unsigned long IRQ_vectors[32];
-extern unsigned long exception_handlers[32];
-
-#define set_int_vector(n,addr) \
-	IRQ_vectors[n] = (unsigned long) (addr)
-
-#define set_except_vector(n,addr) \
-	exception_handlers[n] = (unsigned long) (addr)
+extern void set_except_vector(int n, void *addr);
 
 #endif /* __ASM_MIPS_SYSTEM_H */
diff -u --recursive --new-file v2.1.72/linux/include/asm-mips/termbits.h linux/include/asm-mips/termbits.h
--- v2.1.72/linux/include/asm-mips/termbits.h	Thu Jun 26 12:33:40 1997
+++ linux/include/asm-mips/termbits.h	Wed Dec 10 10:31:11 1997
@@ -158,7 +158,7 @@
 #define  B230400 0010003
 #define  B460800 0010004
 #define CIBAUD	  002003600000	/* input baud rate (not used) */
-#define CISPAR    010000000000	/* mark or space (stick) parity */
+#define CMSPAR    010000000000	/* mark or space (stick) parity */
 #define CRTSCTS	  020000000000		/* flow control */
 #endif
 
diff -u --recursive --new-file v2.1.72/linux/include/asm-mips/uaccess.h linux/include/asm-mips/uaccess.h
--- v2.1.72/linux/include/asm-mips/uaccess.h	Mon Jul  7 08:18:55 1997
+++ linux/include/asm-mips/uaccess.h	Wed Dec 10 10:31:11 1997
@@ -7,7 +7,7 @@
  *
  * Copyright (C) 1996, 1997 by Ralf Baechle
  *
- * $Id: uaccess.h,v 1.4 1997/07/01 08:23:56 ralf Exp $
+ * $Id: uaccess.h,v 1.5 1997/12/01 16:44:08 ralf Exp $
  */
 #ifndef __ASM_MIPS_UACCESS_H
 #define __ASM_MIPS_UACCESS_H
@@ -321,23 +321,23 @@
 	void *__cu_end; \
 	__asm__ __volatile__( \
 		".set\tnoreorder\n\t" \
-		"1:\tsb\t$0,(%0)\n\t" \
+		"1:\taddiu\t%0,1\n" \
 		"bne\t%0,%1,1b\n\t" \
-		"addiu\t%0,1\n" \
+		"sb\t$0,-1(%0)\n\t" \
 		"2:\t.set\treorder\n\t" \
 		".section\t.fixup,\"ax\"\n" \
 		"3:\t.set\tnoat\n\t" \
-		"la\t$1,2b\n\t" \
-		"jr\t$1\n\t" \
+		"subu\t%0,1\n\t" \
+		"j\t2b\n\t" \
 		".set\tat\n\t" \
 		".previous\n\t" \
 		".section\t__ex_table,\"a\"\n\t" \
 		STR(PTR)"\t1b,3b\n\t" \
 		".previous" \
 		:"=r" (addr), "=r" (__cu_end) \
-		:"0" (addr), "1" (addr + size - 1), "i" (-EFAULT) \
+		:"0" (addr), "1" (addr + size), "i" (-EFAULT) \
 		:"$1","memory"); \
-		size = __cu_end - (addr) - 1; \
+		size = __cu_end - (addr); \
 })
 
 #define clear_user(addr,n) ({ \
diff -u --recursive --new-file v2.1.72/linux/include/asm-mips/unaligned.h linux/include/asm-mips/unaligned.h
--- v2.1.72/linux/include/asm-mips/unaligned.h	Thu Jun 26 12:33:40 1997
+++ linux/include/asm-mips/unaligned.h	Wed Dec 10 10:31:11 1997
@@ -15,7 +15,7 @@
 /*
  * Load quad unaligned.
  */
-extern __inline__ unsigned long ldq_u(unsigned long long * __addr)
+extern __inline__ unsigned long ldq_u(const unsigned long long * __addr)
 {
 	unsigned long long __res;
 
@@ -29,7 +29,7 @@
 /*
  * Load long unaligned.
  */
-extern __inline__ unsigned long ldl_u(unsigned int * __addr)
+extern __inline__ unsigned long ldl_u(const unsigned int * __addr)
 {
 	unsigned long __res;
 
@@ -43,7 +43,7 @@
 /*
  * Load word unaligned.
  */
-extern __inline__ unsigned long ldw_u(unsigned short * __addr)
+extern __inline__ unsigned long ldw_u(const unsigned short * __addr)
 {
 	unsigned long __res;
 
@@ -90,12 +90,50 @@
 		 "r" (__addr));
 }
 
-#define get_unaligned(ptr) \
-  ({ __typeof__(*(ptr)) __tmp; memcpy(&__tmp, (ptr), sizeof(*(ptr))); __tmp; })
+extern inline unsigned long __get_unaligned(const void *ptr, size_t size)
+{
+	unsigned long val;
+	switch (size) {
+	      case 1:
+		val = *(const unsigned char *)ptr;
+		break;
+	      case 2:
+		val = ldw_u((const unsigned short *)ptr);
+		break;
+	      case 4:
+		val = ldl_u((const unsigned int *)ptr);
+		break;
+	      case 8:
+		val = ldq_u((const unsigned long long *)ptr);
+		break;
+	}
+	return val;
+}
+
+extern inline void __put_unaligned(unsigned long val, void *ptr, size_t size)
+{
+	switch (size) {
+	      case 1:
+		*(unsigned char *)ptr = (val);
+	        break;
+	      case 2:
+		stw_u(val, (unsigned short *)ptr);
+		break;
+	      case 4:
+		stl_u(val, (unsigned int *)ptr);
+		break;
+	      case 8:
+		stq_u(val, (unsigned long long *)ptr);
+		break;
+	}
+}
 
-#define put_unaligned(val, ptr)				\
-  ({ __typeof__(*(ptr)) __tmp = (val);			\
-     memcpy((ptr), &__tmp, sizeof(*(ptr)));		\
-     (void)0; })
+/* 
+ * The main single-value unaligned transfer routines.
+ */
+#define get_unaligned(ptr) \
+	((__typeof__(*(ptr)))__get_unaligned((ptr), sizeof(*(ptr))))
+#define put_unaligned(x,ptr) \
+	__put_unaligned((unsigned long)(x), (ptr), sizeof(*(ptr)))
 
 #endif /* __ASM_MIPS_UNALIGNED_H */
diff -u --recursive --new-file v2.1.72/linux/include/asm-mips/usioctl.h linux/include/asm-mips/usioctl.h
--- v2.1.72/linux/include/asm-mips/usioctl.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-mips/usioctl.h	Wed Dec 10 10:31:11 1997
@@ -0,0 +1,25 @@
+/*
+ * usema/usemaclone-related stuff.
+ *
+ * `Inspired' by IRIX's sys/usioctl.h
+ *
+ * Mike.
+ */
+
+/* ioctls */
+#define UIOC	('u' << 16 | 's' << 8)
+
+#define UIOCATTACHSEMA	(UIOC|2)	/* attach to sema */
+#define UIOCBLOCK	(UIOC|3)	/* block sync "intr"? */
+#define UIOCABLOCK	(UIOC|4)	/* block async */
+#define UIOCNOIBLOCK	(UIOC|5)	/* IRIX: block sync intr
+					   Linux: block sync nointr */
+#define UIOCUNBLOCK	(UIOC|6)	/* unblock sync */
+#define UIOCAUNBLOCK	(UIOC|7)	/* unblock async */
+#define UIOCINIT	(UIOC|8)	/* init sema (async) */
+
+typedef struct usattach_s {
+  dev_t	us_dev;		/* attach dev */
+  void	*us_handle;	/* userland semaphore handle */
+} usattach_t;
+
diff -u --recursive --new-file v2.1.72/linux/include/asm-mips/vector.h linux/include/asm-mips/vector.h
--- v2.1.72/linux/include/asm-mips/vector.h	Thu Jun 26 12:33:40 1997
+++ linux/include/asm-mips/vector.h	Wed Dec 10 10:31:11 1997
@@ -31,17 +31,17 @@
 	/*
 	 * How to access the floppy DMA functions.
 	 */
-	void (*fd_enable_dma)(void);
-	void (*fd_disable_dma)(void);
-	int (*fd_request_dma)(void);
-	void (*fd_free_dma)(void);
-	void (*fd_clear_dma_ff)(void);
-	void (*fd_set_dma_mode)(char mode);
-	void (*fd_set_dma_addr)(unsigned int a);
-	void (*fd_set_dma_count)(unsigned int count);
-	int (*fd_get_dma_residue)(void);
-	void (*fd_enable_irq)(void);
-	void (*fd_disable_irq)(void);
+	void (*fd_enable_dma)(int channel);
+	void (*fd_disable_dma)(int channel);
+	int (*fd_request_dma)(int channel);
+	void (*fd_free_dma)(int channel);
+	void (*fd_clear_dma_ff)(int channel);
+	void (*fd_set_dma_mode)(int channel, char mode);
+	void (*fd_set_dma_addr)(int channel, unsigned int a);
+	void (*fd_set_dma_count)(int channel, unsigned int count);
+	int (*fd_get_dma_residue)(int channel);
+	void (*fd_enable_irq)(int irq);
+	void (*fd_disable_irq)(int irq);
 	/*
 	 * How to access the RTC register of the DS1287?
 	 */
diff -u --recursive --new-file v2.1.72/linux/include/asm-mips/watch.h linux/include/asm-mips/watch.h
--- v2.1.72/linux/include/asm-mips/watch.h	Thu Jun 26 12:33:40 1997
+++ linux/include/asm-mips/watch.h	Wed Dec 10 10:31:11 1997
@@ -5,7 +5,9 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1996 by Ralf Baechle
+ * Copyright (C) 1996, 1997 by Ralf Baechle
+ *
+ * $Id: watch.h,v 1.2 1997/09/19 08:37:44 ralf Exp $
  */
 #ifndef __ASM_WATCH_H
 #define __ASM_WATCH_H
@@ -20,7 +22,8 @@
 	wr_load = 2
 };
 
-extern asmlinkage unsigned int watch_available;
+extern char watch_available;
+
 extern asmlinkage __watch_set(unsigned long addr, enum wref_type ref);
 extern asmlinkage __watch_clear(void);
 extern asmlinkage __watch_reenable(void);
diff -u --recursive --new-file v2.1.72/linux/include/linux/blkdev.h linux/include/linux/blkdev.h
--- v2.1.72/linux/include/linux/blkdev.h	Wed Nov 12 13:34:27 1997
+++ linux/include/linux/blkdev.h	Thu Dec 18 11:38:01 1997
@@ -70,4 +70,6 @@
 
 extern int * max_readahead[MAX_BLKDEV];
 
+extern int * max_sectors[MAX_BLKDEV];
+
 #endif
diff -u --recursive --new-file v2.1.72/linux/include/linux/dmascc.h linux/include/linux/dmascc.h
--- v2.1.72/linux/include/linux/dmascc.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/dmascc.h	Tue Dec  9 09:49:59 1997
@@ -0,0 +1,43 @@
+/*
+ * $Id: dmascc.h,v 1.1 1997/12/01 10:44:55 oe1kib Exp $
+ *
+ * Driver for high-speed SCC boards (those with DMA support)
+ * Copyright (C) 1997 Klaus Kudielka
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* Ioctls */
+#define SIOCGSCCPARAM SIOCDEVPRIVATE
+#define SIOCSSCCPARAM (SIOCDEVPRIVATE+1)
+
+/* Frequency of timer 0 */
+#define TMR_0_HZ      25600
+
+/* Configurable parameters */
+struct scc_param {
+  int pclk_hz;  /* frequency of BRG input (read-only - don't change) */
+  int brg_tc;   /* baud rate generator terminal count - BRG disabled if < 0 */
+  int nrzi;     /* 0 (nrz), 1 (nrzi) */
+  int clocks;   /* see documentation */
+  int txdelay;  /* [1/TMR_0_HZ] */
+  int txtime;   /* [1/HZ] */
+  int sqdelay;  /* [1/TMR_0_HZ] */
+  int waittime; /* [1/TMR_0_HZ] */
+  int slottime; /* [1/TMR_0_HZ] */
+  int persist;  /* 0 ... 255 */
+  int dma;      /* 1, 3 */
+};
+
diff -u --recursive --new-file v2.1.72/linux/include/linux/fs.h linux/include/linux/fs.h
--- v2.1.72/linux/include/linux/fs.h	Wed Dec 10 11:12:46 1997
+++ linux/include/linux/fs.h	Thu Dec 18 11:38:01 1997
@@ -138,6 +138,10 @@
 #define BLKFLSBUF  _IO(0x12,97)	/* flush buffer cache */
 #define BLKRASET   _IO(0x12,98)	/* Set read ahead for block device */
 #define BLKRAGET   _IO(0x12,99)	/* get current read ahead setting */
+#define BLKFRASET  _IO(0x12,100)/* set filesystem (mm/filemap.c) read-ahead */
+#define BLKFRAGET  _IO(0x12,101)/* get filesystem (mm/filemap.c) read-ahead */
+#define BLKSECTSET _IO(0x12,102)/* set max sectors per request (ll_rw_blk.c) */
+#define BLKSECTGET _IO(0x12,103)/* get max sectors per request (ll_rw_blk.c) */
 
 #define BMAP_IOCTL 1		/* obsolete - kept for compatibility */
 #define FIBMAP	   _IO(0x00,1)	/* bmap access */
@@ -709,6 +713,7 @@
 extern struct dentry * open_namei(const char * pathname, int flag, int mode);
 extern struct dentry * do_mknod(const char * filename, int mode, dev_t dev);
 extern int do_pipe(int *);
+extern ino_t find_inode_number(struct dentry *, struct qstr *);
 
 /*
  * Kernel pointers have redundant information, so we can use a
diff -u --recursive --new-file v2.1.72/linux/include/linux/hdreg.h linux/include/linux/hdreg.h
--- v2.1.72/linux/include/linux/hdreg.h	Mon Dec  1 12:04:14 1997
+++ linux/include/linux/hdreg.h	Thu Dec 18 11:38:01 1997
@@ -195,10 +195,6 @@
 void hd_setup(char *, int *);
 #endif	/* CONFIG_BLK_DEV_HD */
 
-#ifdef CONFIG_BLK_DEV_IDE
-void ide_setup(char *);
-#endif	/* CONFIG_BLK_DEV_IDE */
-
 #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
 int ide_register(int io_port, int ctl_port, int irq);
 void ide_unregister(unsigned int);
diff -u --recursive --new-file v2.1.72/linux/include/linux/ip_fw.h linux/include/linux/ip_fw.h
--- v2.1.72/linux/include/linux/ip_fw.h	Thu Sep 11 09:02:24 1997
+++ linux/include/linux/ip_fw.h	Thu Dec 18 11:41:39 1997
@@ -126,7 +126,8 @@
 #define IP_FW_IN		1
 #define IP_FW_OUT		2
 #define IP_FW_ACCT		3
-#define IP_FW_CHAINS		4	/* total number of ip_fw chains */
+#define IP_FW_MASQ		4
+#define IP_FW_CHAINS		5	/* total number of ip_fw chains */
 
 #define IP_FW_INSERT		(IP_FW_BASE_CTL)
 #define IP_FW_APPEND		(IP_FW_BASE_CTL+1)
@@ -167,6 +168,11 @@
 #define IP_ACCT_FLUSH		(IP_FW_FLUSH  | (IP_FW_ACCT << IP_FW_SHIFT))
 #define IP_ACCT_ZERO		(IP_FW_ZERO   | (IP_FW_ACCT << IP_FW_SHIFT))
 
+#define IP_FW_MASQ_INSERT	(IP_FW_INSERT | (IP_FW_MASQ << IP_FW_SHIFT))
+#define IP_FW_MASQ_ADD		(IP_FW_APPEND | (IP_FW_MASQ << IP_FW_SHIFT))
+#define IP_FW_MASQ_DEL		(IP_FW_DELETE | (IP_FW_MASQ << IP_FW_SHIFT))
+#define IP_FW_MASQ_FLUSH  	(IP_FW_FLUSH  | (IP_FW_MASQ << IP_FW_SHIFT))
+
 struct ip_fwpkt
 {
 	struct iphdr fwp_iph;			/* IP header */
@@ -179,6 +185,20 @@
 	char           fwp_vianame[IFNAMSIZ];	/* interface name */
 };
 
+#define IP_FW_MASQCTL_MAX 256
+#define IP_MASQ_MOD_NMAX  32
+
+struct ip_fw_masqctl
+{
+	int mctl_action;
+	union {
+		struct {
+			char name[IP_MASQ_MOD_NMAX];
+			char data[1];
+		} mod;
+	} u;
+};
+
 /*
  * timeouts for ip masquerading
  */
@@ -211,9 +231,13 @@
 extern struct ip_fw *ip_acct_chain;
 extern int ip_acct_ctl(int, void *, int);
 #endif
+#ifdef CONFIG_IP_MASQUERADE
+extern int ip_masq_ctl(int, void *, int);
+#endif
 
 extern int ip_fw_chk(struct iphdr *, struct device *, __u16 *, struct ip_fw *, int, int);
 extern void ip_fw_init(void);
 #endif /* KERNEL */
+
 
 #endif /* _IP_FW_H */
diff -u --recursive --new-file v2.1.72/linux/include/linux/mm.h linux/include/linux/mm.h
--- v2.1.72/linux/include/linux/mm.h	Mon Oct 20 10:36:53 1997
+++ linux/include/linux/mm.h	Thu Dec 18 11:38:01 1997
@@ -144,7 +144,6 @@
 #define PageLocked(page)	(test_bit(PG_locked, &(page)->flags))
 #define PageError(page)		(test_bit(PG_error, &(page)->flags))
 #define PageReferenced(page)	(test_bit(PG_referenced, &(page)->flags))
-#define PageDirty(page)		(test_bit(PG_dirty, &(page)->flags))
 #define PageUptodate(page)	(test_bit(PG_uptodate, &(page)->flags))
 #define PageFreeAfter(page)	(test_bit(PG_free_after, &(page)->flags))
 #define PageDecrAfter(page)	(test_bit(PG_decr_after, &(page)->flags))
diff -u --recursive --new-file v2.1.72/linux/include/linux/nfs_fs.h linux/include/linux/nfs_fs.h
--- v2.1.72/linux/include/linux/nfs_fs.h	Wed Nov 12 13:34:28 1997
+++ linux/include/linux/nfs_fs.h	Thu Dec 18 11:38:01 1997
@@ -168,6 +168,7 @@
  * linux/fs/nfs/write.c
  */
 extern int  nfs_writepage(struct inode *, struct page *);
+extern int  nfs_check_failed_request(struct inode *);
 extern int  nfs_check_error(struct inode *);
 extern int  nfs_flush_dirty_pages(struct inode *, pid_t, off_t, off_t);
 extern int  nfs_truncate_dirty_pages(struct inode *, unsigned long);
diff -u --recursive --new-file v2.1.72/linux/include/linux/pci.h linux/include/linux/pci.h
--- v2.1.72/linux/include/linux/pci.h	Thu Dec  4 14:53:57 1997
+++ linux/include/linux/pci.h	Wed Dec 17 11:11:51 1997
@@ -786,8 +786,8 @@
 #define PCI_DEVICE_ID_INTEL_82865	0x1227
 #define PCI_DEVICE_ID_INTEL_82557	0x1229
 #define PCI_DEVICE_ID_INTEL_82437	0x122d
-#define PCI_DEVICE_ID_INTEL_82371_0	0x122e
-#define PCI_DEVICE_ID_INTEL_82371_1	0x1230
+#define PCI_DEVICE_ID_INTEL_82371FB_0	0x122e
+#define PCI_DEVICE_ID_INTEL_82371FB_1	0x1230
 #define PCI_DEVICE_ID_INTEL_82371MX	0x1234
 #define PCI_DEVICE_ID_INTEL_82437MX	0x1235
 #define PCI_DEVICE_ID_INTEL_82441	0x1237
diff -u --recursive --new-file v2.1.72/linux/include/linux/proc_fs.h linux/include/linux/proc_fs.h
--- v2.1.72/linux/include/linux/proc_fs.h	Mon Dec  1 12:04:15 1997
+++ linux/include/linux/proc_fs.h	Thu Dec 18 11:38:01 1997
@@ -247,6 +247,11 @@
 	int deleted;		/* delete flag */
 };
 
+typedef	int (read_proc_t)(char *page, char **start, off_t off,
+			  int count, int *eof, void *data);
+typedef	int (write_proc_t)(struct file *file, const char *buffer,
+			   unsigned long count, void *data);
+
 extern int (* dispatch_scsi_info_ptr) (int ino, char *buffer, char **start,
 				off_t offset, int length, int inout);
 
diff -u --recursive --new-file v2.1.72/linux/include/linux/smb_fs.h linux/include/linux/smb_fs.h
--- v2.1.72/linux/include/linux/smb_fs.h	Wed Nov 26 16:24:03 1997
+++ linux/include/linux/smb_fs.h	Thu Dec 18 11:41:07 1997
@@ -106,22 +106,23 @@
 __u8 *smb_setup_header(struct smb_sb_info *, __u8, __u16, __u16);
 int smb_get_rsize(struct smb_sb_info *);
 int smb_get_wsize(struct smb_sb_info *);
-int smb_offerconn(struct smb_sb_info *);
 int smb_newconn(struct smb_sb_info *, struct smb_conn_opt *);
+int smb_errno(struct smb_sb_info *);
 int smb_close(struct inode *);
 void smb_close_dentry(struct dentry *);
 int smb_close_fileid(struct dentry *, __u16);
 int smb_open(struct dentry *, int);
 int smb_proc_read(struct inode *, off_t, int, char *);
 int smb_proc_write(struct inode *, off_t, int, const char *);
-int smb_proc_create(struct dentry *, struct qstr *, __u16, time_t, __u16 *);
-int smb_proc_mv(struct dentry *, struct qstr *, struct dentry *, struct qstr *);
-int smb_proc_mkdir(struct dentry *, struct qstr *);
-int smb_proc_rmdir(struct dentry *, struct qstr *);
-int smb_proc_unlink(struct dentry *dir, struct qstr *);
+int smb_proc_create(struct dentry *, __u16, time_t, __u16 *);
+int smb_proc_mv(struct dentry *, struct dentry *);
+int smb_proc_mkdir(struct dentry *);
+int smb_proc_rmdir(struct dentry *);
+int smb_proc_unlink(struct dentry *);
 int smb_proc_readdir(struct dentry *, int, void *);
-int smb_proc_getattr(struct dentry *, struct qstr *, struct smb_fattr *);
-int smb_proc_setattr(struct smb_sb_info *, struct dentry *, struct smb_fattr *);
+int smb_proc_getattr(struct dentry *, struct smb_fattr *);
+int smb_proc_setattr(struct dentry *, struct smb_fattr *);
+int smb_proc_settime(struct dentry *, struct smb_fattr *);
 int smb_proc_dskattr(struct super_block *, struct statfs *);
 int smb_proc_reconnect(struct smb_sb_info *);
 int smb_proc_connect(struct smb_sb_info *);
diff -u --recursive --new-file v2.1.72/linux/include/linux/socket.h linux/include/linux/socket.h
--- v2.1.72/linux/include/linux/socket.h	Mon Dec  1 12:04:15 1997
+++ linux/include/linux/socket.h	Wed Dec 10 09:45:16 1997
@@ -233,7 +233,7 @@
 extern int csum_partial_copy_fromiovecend(unsigned char *kdata, 
 					  struct iovec *iov, 
 					  int offset, 
-					  int len, int *csump);
+					  unsigned int len, int *csump);
 
 extern int verify_iovec(struct msghdr *m, struct iovec *iov, char *address, int mode);
 extern int memcpy_toiovec(struct iovec *v, unsigned char *kdata, int len);
diff -u --recursive --new-file v2.1.72/linux/include/linux/sysctl.h linux/include/linux/sysctl.h
--- v2.1.72/linux/include/linux/sysctl.h	Tue Dec  2 16:45:20 1997
+++ linux/include/linux/sysctl.h	Wed Dec 10 09:45:16 1997
@@ -173,6 +173,8 @@
 	NET_IPV4_IGMP_MAX_HOST_REPORT_DELAY,
 	NET_IPV4_IGMP_TIMER_SCALE,
 	NET_IPV4_IGMP_AGE_THRESHOLD,
+	NET_IPV4_IP_DYNADDR,
+	NET_IPV4_IP_MASQ_DEBUG,
 	NET_TCP_SYNCOOKIES,
 	NET_TCP_STDURG,
 	NET_TCP_SYN_TAILDROP,
diff -u --recursive --new-file v2.1.72/linux/include/net/ip_autofw.h linux/include/net/ip_autofw.h
--- v2.1.72/linux/include/net/ip_autofw.h	Wed Dec 31 16:00:00 1969
+++ linux/include/net/ip_autofw.h	Wed Dec 10 09:45:16 1997
@@ -0,0 +1,33 @@
+#include <linux/types.h>
+#include <linux/kernel.h>
+
+#ifndef _IP_AUTOFW_H
+#define _IP_AUTOFW_H
+
+#define IP_AUTOFW_EXPIRE	     15*HZ
+
+#define IP_FWD_RANGE 		1
+#define IP_FWD_PORT		2
+#define IP_FWD_DIRECT		3
+
+#define IP_AUTOFW_ACTIVE	1
+#define IP_AUTOFW_USETIME	2
+#define IP_AUTOFW_SECURE	4
+
+struct ip_autofw {
+	struct ip_autofw * next;
+	__u16 type;
+	__u16 low;
+	__u16 hidden;
+	__u16 high;
+	__u16 visible;
+	__u16 protocol;
+	__u32 lastcontact;
+	__u32 where;
+	__u16 ctlproto;
+	__u16 ctlport;
+	__u16 flags;
+	struct timer_list timer;
+};
+int ip_autofw_init(void);
+#endif /* _IP_AUTOFW_H */
diff -u --recursive --new-file v2.1.72/linux/include/net/ip_masq.h linux/include/net/ip_masq.h
--- v2.1.72/linux/include/net/ip_masq.h	Mon Dec  1 12:04:15 1997
+++ linux/include/net/ip_masq.h	Thu Dec 18 11:41:39 1997
@@ -5,9 +5,23 @@
 #ifndef _IP_MASQ_H
 #define _IP_MASQ_H
 
+#ifdef __KERNEL__
 #include <linux/types.h>
 #include <linux/netdevice.h>
+#include <linux/ip.h>
 #include <linux/skbuff.h>
+#endif /* __KERNEL__ */
+
+/*
+ * This define affects the number of ports that can be handled
+ * by each of the protocol helper modules.
+ */
+#define MAX_MASQ_APP_PORTS 12
+
+/*
+ *	Linux ports don't normally get allocated above 32K.
+ *	I used an extra 4K port-space
+ */
 
 /*
  *	Linux ports don't normally get allocated above 32K.
@@ -20,18 +34,21 @@
 #define MASQUERADE_EXPIRE_TCP     15*60*HZ
 #define MASQUERADE_EXPIRE_TCP_FIN  2*60*HZ
 #define MASQUERADE_EXPIRE_UDP      5*60*HZ
+/* 
+ * ICMP can no longer be modified on the fly using an ioctl - this
+ * define is the only way to change the timeouts 
+ */
+#define MASQUERADE_EXPIRE_ICMP      125*HZ
 
 #define IP_MASQ_F_OUT_SEQ              	0x01	/* must do output seq adjust */
 #define IP_MASQ_F_IN_SEQ              	0x02	/* must do input seq adjust */
-#define IP_MASQ_F_NO_DPORT    		0x04	/* no dport set yet */
-#define IP_MASQ_F_NO_DADDR      	0x08 	/* no daddr yet */
-#define IP_MASQ_F_HASHED		0x10 	/* hashed entry */
-#define IP_MASQ_F_SAW_RST		0x20 	/* tcp rst pkt seen */
-#define IP_MASQ_F_SAW_FIN_IN		0x40 	/* tcp fin pkt seen incoming */
-#define IP_MASQ_F_SAW_FIN_OUT		0x80 	/* tcp fin pkt seen outgoing */
-#define IP_MASQ_F_SAW_FIN		(IP_MASQ_F_SAW_FIN_IN | \
-					 IP_MASQ_F_SAW_FIN_OUT)
-						/* tcp fin pkts seen */
+#define IP_MASQ_F_NO_DPORT     	        0x04	/* no dport set yet */
+#define IP_MASQ_F_NO_DADDR	        0x08 	/* no daddr yet */
+#define IP_MASQ_F_HASHED	        0x10 	/* hashed entry */
+
+#define IP_MASQ_F_NO_SPORT	       0x200	/* no sport set yet */
+#define IP_MASQ_F_NO_REPLY	       0x800	/* no reply yet from outside */
+#define IP_MASQ_F_MPORT		      0x1000 	/* own mport specified */
 
 #ifdef __KERNEL__
 
@@ -51,6 +68,7 @@
  */
 struct ip_masq {
         struct ip_masq  *m_link, *s_link; /* hashed link ptrs */
+	atomic_t refcnt;		/* reference count */
 	struct timer_list timer;	/* Expiration timer */
 	__u16 		protocol;	/* Which protocol are we talking? */
 	__u16		sport, dport, mport;	/* src, dst & masq ports */
@@ -58,7 +76,12 @@
         struct ip_masq_seq out_seq, in_seq;
 	struct ip_masq_app *app;	/* bound ip_masq_app object */
 	void		*app_data;	/* Application private data */
-	unsigned  flags;        	/* status flags */
+	struct ip_masq	*control;	/* Master control connection */
+	atomic_t        n_control;	/* Number of "controlled" masqs */
+	unsigned  	flags;        	/* status flags */
+	unsigned	timeout;	/* timeout */
+	unsigned	state;		/* state info */
+	struct ip_masq_timeout_table *timeout_table;
 };
 
 /*
@@ -76,9 +99,10 @@
 /*
  *	[0]: UDP free_ports
  *	[1]: TCP free_ports
+ *	[2]: ICMP free_ports
  */
 
-extern int ip_masq_free_ports[2];
+extern atomic_t ip_masq_free_ports[3];
 
 /*
  *	ip_masq initializer (registers symbols and /proc/net entries)
@@ -89,14 +113,17 @@
  *	functions called from ip layer
  */
 extern int ip_fw_masquerade(struct sk_buff **, __u32 maddr);
-extern int ip_fw_masq_icmp(struct sk_buff **);
+extern int ip_fw_masq_icmp(struct sk_buff **, __u32 maddr);
 extern int ip_fw_demasquerade(struct sk_buff **);
 
 /*
  *	ip_masq obj creation/deletion functions.
  */
-extern struct ip_masq *ip_masq_new(__u32 maddr, int proto, __u32 saddr, __u16 sport, __u32 daddr, __u16 dport, unsigned flags);
-extern void ip_masq_set_expire(struct ip_masq *ms, unsigned long tout);
+extern struct ip_masq *ip_masq_new(int proto, __u32 maddr, __u16 mport, __u32 saddr, __u16 sport, __u32 daddr, __u16 dport, unsigned flags);
+
+extern void ip_masq_control_add(struct ip_masq *ms, struct ip_masq* ctl_ms);
+extern void ip_masq_control_del(struct ip_masq *ms);
+extern struct ip_masq * ip_masq_control_get(struct ip_masq *ms);
 
 
 /*
@@ -118,7 +145,7 @@
         int (*pkt_out)          /* output (masquerading) hook */
                 (struct ip_masq_app *, struct ip_masq *, struct sk_buff **, __u32);
         int (*pkt_in)           /* input (demasq) hook */
-                (struct ip_masq_app *, struct ip_masq *, struct sk_buff **);
+                (struct ip_masq_app *, struct ip_masq *, struct sk_buff **, __u32);
 };
 
 /*
@@ -148,13 +175,109 @@
  *	
  */
 extern int ip_masq_app_pkt_out(struct ip_masq *, struct sk_buff **skb_p, __u32 maddr);
-extern int ip_masq_app_pkt_in(struct ip_masq *, struct sk_buff **skb_p);
+extern int ip_masq_app_pkt_in(struct ip_masq *, struct sk_buff **skb_p, __u32 maddr);
 
 /*
  *	service routine(s).
  */
-extern struct ip_masq * ip_masq_out_get_2(int protocol, __u32 s_addr, __u16 s_port, __u32 d_addr, __u16 d_port);
-extern struct ip_masq * ip_masq_in_get_2(int protocol, __u32 s_addr, __u16 s_port, __u32 d_addr, __u16 d_port);
+
+extern struct ip_masq * ip_masq_out_get(int protocol, __u32 s_addr, __u16 s_port, __u32 d_addr, __u16 d_port);
+extern struct ip_masq * ip_masq_in_get(int protocol, __u32 s_addr, __u16 s_port, __u32 d_addr, __u16 d_port);
+
+extern int ip_masq_listen(struct ip_masq *);
+
+static __inline__ struct ip_masq * ip_masq_in_get_iph(const struct iphdr *iph)
+{
+ 	const __u16 *portp = (__u16 *)&(((char *)iph)[iph->ihl*4]);
+        return ip_masq_in_get(iph->protocol, 
+				iph->saddr, portp[0], 
+				iph->daddr, portp[1]);
+}
+
+static __inline__ struct ip_masq * ip_masq_out_get_iph(const struct iphdr *iph)
+{
+ 	const __u16 *portp  = (__u16 *)&(((char *)iph)[iph->ihl*4]);
+        return ip_masq_out_get(iph->protocol, 
+				iph->saddr, portp[0], 
+				iph->daddr, portp[1]);
+}
+
+extern void ip_masq_put(struct ip_masq *ms);
+
+
+/* 
+ *	Locking stuff
+ */
+
+
+static __inline__ void ip_masq_lock(atomic_t *lock, int rw)
+{
+#if 0
+	if (rw) 
+#endif
+		start_bh_atomic();
+	atomic_inc(lock);
+}
+
+static __inline__ void ip_masq_unlock(atomic_t *lock, int rw)
+{
+	atomic_dec(lock);
+#if 0
+	if (rw) 
+#endif
+		end_bh_atomic();
+}
+
+/*
+ *	Sleep-able lockzzz...
+ */
+static __inline__ void ip_masq_lockz(atomic_t *lock, struct wait_queue ** waitq, int rw)
+{
+	if (rw)
+		while(atomic_read(lock)) sleep_on(waitq);
+	ip_masq_lock(lock, rw);
+}
+
+static __inline__ void ip_masq_unlockz(atomic_t *lock, struct wait_queue ** waitq, int rw)
+{
+	ip_masq_unlock(lock, rw);
+	if (rw)
+		wake_up(waitq);
+}
+	
+/*
+ *	Perfect for winning races ... ;)
+ */
+static __inline__ int ip_masq_nlocks(atomic_t *lock)
+{
+	return atomic_read(lock);
+}
+
+extern atomic_t __ip_masq_lock;
+
+/*
+ *	Debugging stuff
+ */
+
+extern int ip_masq_get_debug_level(void);
+
+#ifndef CONFIG_IP_MASQ_NDEBUG
+#define IP_MASQ_DEBUG(level, msg...) \
+	if (level <= ip_masq_get_debug_level()) \
+		printk(KERN_DEBUG "IP_MASQ:" ## msg)
+#else	/* NO DEBUGGING at ALL */
+#define IP_MASQ_DEBUG(level, msg...) do { } while (0)
+#endif
+
+#define IP_MASQ_INFO(msg...) \
+	printk(KERN_INFO "IP_MASQ:" ## msg)
+
+#define IP_MASQ_ERR(msg...) \
+	printk(KERN_ERR "IP_MASQ:" ## msg)
+
+#define IP_MASQ_WARNING(msg...) \
+	printk(KERN_WARNING "IP_MASQ:" ## msg)
+
 
 /*
  *	/proc/net entry
@@ -166,6 +289,71 @@
  *	a segment of skb.
  */
 extern struct sk_buff * ip_masq_skb_replace(struct sk_buff *skb, int pri, char *o_buf, int o_len, char *n_buf, int n_len);
+
+/*
+ * masq_proto_num returns 0 for UDP, 1 for TCP, 2 for ICMP
+ */
+
+static __inline__ int masq_proto_num(unsigned proto)
+{
+   switch (proto)
+   {
+      case IPPROTO_UDP:  return (0); break;
+      case IPPROTO_TCP:  return (1); break;
+      case IPPROTO_ICMP: return (2); break;
+      default:           return (-1); break;
+   }
+}
+
+static __inline__ const char *masq_proto_name(unsigned proto)
+{
+	static char buf[20];
+	static const char *strProt[] = {"UDP","TCP","ICMP"};
+	int msproto = masq_proto_num(proto);
+
+	if (msproto<0||msproto>2)  {
+		sprintf(buf, "IP_%d", proto);
+		return buf;
+	}
+        return strProt[msproto];
+}
+
+enum {
+	IP_MASQ_S_NONE = 0,
+	IP_MASQ_S_ESTABLISHED,
+	IP_MASQ_S_SYN_SENT,
+	IP_MASQ_S_SYN_RECV,
+	IP_MASQ_S_FIN_WAIT,
+	IP_MASQ_S_TIME_WAIT,
+	IP_MASQ_S_CLOSE,
+	IP_MASQ_S_CLOSE_WAIT,
+	IP_MASQ_S_LAST_ACK,
+	IP_MASQ_S_LISTEN,
+	IP_MASQ_S_UDP,
+	IP_MASQ_S_ICMP,
+	IP_MASQ_S_LAST
+};
+
+struct ip_masq_timeout_table {
+	atomic_t refcnt;
+	int scale;
+	int timeout[IP_MASQ_S_LAST+1];
+};
+
+static __inline__ void ip_masq_timeout_attach(struct ip_masq *ms, struct ip_masq_timeout_table *mstim)
+{
+	atomic_inc (&mstim->refcnt);
+	ms->timeout_table=mstim;
+}
+
+static __inline__ void ip_masq_timeout_detach(struct ip_masq *ms)
+{
+	struct ip_masq_timeout_table *mstim = ms->timeout_table;
+
+	if (!mstim)
+		return;
+	atomic_dec(&mstim->refcnt);
+}
 
 #endif /* __KERNEL__ */
 
diff -u --recursive --new-file v2.1.72/linux/include/net/ip_masq_mod.h linux/include/net/ip_masq_mod.h
--- v2.1.72/linux/include/net/ip_masq_mod.h	Wed Dec 31 16:00:00 1969
+++ linux/include/net/ip_masq_mod.h	Wed Dec 10 09:45:16 1997
@@ -0,0 +1,78 @@
+/*
+ *	IP Masquerading Modules Support
+ *
+ * Version:	@(#)ip_masq_mod.h  0.01      97/10/30
+ *
+ * Author:	Juan Jose Ciarlante, <jjciarla@raiz.uncu.edu.ar>
+ *
+ */
+
+
+#ifdef __KERNEL__
+#include <linux/types.h>
+#include <linux/ip_fw.h>
+#include <linux/proc_fs.h>
+#include <net/ip_masq.h>
+
+enum {
+	IP_MASQ_MOD_NOP,
+	IP_MASQ_MOD_ACCEPT,
+	IP_MASQ_MOD_REJECT
+};
+
+struct ip_masq_mod {
+	struct ip_masq_mod *next;	/* next mod for addrs. lookups */
+	struct ip_masq_mod *next_reg;	/* next mod for configuration ctls */
+	char *mmod_name;
+	atomic_t refcnt;
+	atomic_t mmod_nent;		/* number of entries */
+	struct proc_dir_entry *mmod_proc_ent;
+	int (*mmod_ctl) (int optname, struct ip_fw_masqctl *, int optlen);
+	int (*mmod_init) (void);
+	int (*mmod_done) (void);
+	int (*mmod_in_rule) (struct iphdr *, __u16 *);
+	int (*mmod_in_update) (struct iphdr *, struct ip_masq *);
+	struct ip_masq * (*mmod_in_create) (struct iphdr *, __u16 *, __u32);
+	int (*mmod_out_rule) (struct iphdr *, __u16 *);
+	int (*mmod_out_update) (struct iphdr *, __u16 *, struct ip_masq *);
+	struct ip_masq * (*mmod_out_create) (struct iphdr *, __u16 *, __u32);
+};
+
+/*
+ *	Service routines (called from ip_masq.c)
+ */
+int ip_masq_mod_out_rule(struct iphdr *iph, __u16 *portp);
+int ip_masq_mod_out_update(struct iphdr *iph, __u16 *portp, struct ip_masq *ms);
+struct ip_masq * ip_masq_mod_out_create(struct iphdr *iph, __u16 *portp, __u32 maddr);
+
+int ip_masq_mod_in_rule(struct iphdr *iph, __u16 *portp);
+int ip_masq_mod_in_update(struct iphdr *iph, __u16 *portp, struct ip_masq *ms);
+struct ip_masq * ip_masq_mod_in_create(struct iphdr *iph, __u16 *portp, __u32 maddr);
+
+extern int ip_masq_mod_ctl(int optname, struct ip_fw_masqctl *, int len);
+
+/*
+ * 	ip_masq_mod registration functions 
+ */
+extern int register_ip_masq_mod(struct ip_masq_mod *mmod);
+extern int unregister_ip_masq_mod(struct ip_masq_mod *mmod);
+extern int ip_masq_mod_lkp_unlink(struct ip_masq_mod *mmod);
+extern int ip_masq_mod_lkp_link(struct ip_masq_mod *mmod);
+
+/*
+ *	Utility ...
+ */
+static __inline__ void ip_masq_mod_dec_nent(struct ip_masq_mod *mmod)
+{
+	if (atomic_dec_and_test(&mmod->mmod_nent)) {
+		ip_masq_mod_lkp_unlink(mmod);
+	}
+}
+static __inline__ void ip_masq_mod_inc_nent(struct ip_masq_mod *mmod)
+{
+	atomic_inc(&mmod->mmod_nent);
+	if (atomic_read(&mmod->mmod_nent)==1)
+		ip_masq_mod_lkp_link(mmod);
+}
+
+#endif /* __KERNEL__ */
diff -u --recursive --new-file v2.1.72/linux/include/net/ip_portfw.h linux/include/net/ip_portfw.h
--- v2.1.72/linux/include/net/ip_portfw.h	Wed Dec 31 16:00:00 1969
+++ linux/include/net/ip_portfw.h	Wed Dec 10 09:45:16 1997
@@ -0,0 +1,29 @@
+#ifndef _IP_PORTFW_H
+#define  _IP_PORTFW_H
+
+#include <linux/types.h>
+
+#define IP_PORTFW_PORT_MIN 1
+#define IP_PORTFW_PORT_MAX 60999
+
+#ifdef __KERNEL__
+struct ip_portfw {
+	struct 		list_head list;
+	__u32           laddr, raddr;
+	__u16           lport, rport;
+	atomic_t	pref_cnt;	/* pref "counter" down to 0 */
+	int 		pref;		/* user set pref */
+};
+extern int ip_portfw_init(void);
+
+#endif /* __KERNEL__ */
+
+struct ip_portfw_edits {
+	__u16           protocol;       /* Which protocol are we talking? */
+	__u32           laddr, raddr;   /* Remote address */
+	__u16           lport, rport;   /* Local and remote port */
+	__u16           dummy;          /* Make up to multiple of 4 */
+	int 		pref;		/* Preference value */
+};
+
+#endif
diff -u --recursive --new-file v2.1.72/linux/include/net/llc.h linux/include/net/llc.h
--- v2.1.72/linux/include/net/llc.h	Thu Jan  2 05:13:27 1997
+++ linux/include/net/llc.h	Wed Dec 10 09:45:16 1997
@@ -13,6 +13,7 @@
 { 
 	char eye[4];			/* To recognize llc area in dump */
 	int retry_count;		/* LLC link state variables */
+	unsigned char name[9];		/* name of this llc instance */
 	unsigned char s_flag;
 	unsigned char p_flag;
 	unsigned char f_flag;
@@ -68,9 +69,7 @@
 	char * client_data;		/* Pointer to clients context */
 	unsigned char local_sap;
 	unsigned char remote_sap ;
-	char remote_mac[MAX_ADDR_LEN];  /* MAC address of remote session partner */
-	int  remote_mac_len;		/* Actual length of mac address */
-	int  mac_offset;		/* Source mac offset in skb */ 
+	char remote_mac[MAX_ADDR_LEN];  /* MAC address of remote session partner */ 
 	struct device *dev;		/* Device we are attached to */
 		     
 	unsigned char llc_mode;		/* See doc 7.1 on p70 */
@@ -132,3 +131,5 @@
 
 int		register_cl2llc_client(llcptr llc, const char *device, void (*ops)(llcptr), u8 *rmac, u8 ssap, u8 dsap);
 void		unregister_cl2llc_client(llcptr lp);
+int 		llc_mac_data_indicate(llcptr lp, struct sk_buff *skb );
+
diff -u --recursive --new-file v2.1.72/linux/include/net/tcp.h linux/include/net/tcp.h
--- v2.1.72/linux/include/net/tcp.h	Mon Dec  1 12:04:15 1997
+++ linux/include/net/tcp.h	Thu Dec 18 11:41:17 1997
@@ -181,6 +181,9 @@
 				 * to be no checksum			*/
 
 #define TCP_SYNACK_PERIOD	(HZ/2)
+#define TCP_QUICK_TRIES		8  /* How often we try to retransmit, until
+				    * we tell the LL layer that it is something
+				    * wrong (e.g. that it can expire redirects) */
 
 /*
  *	TCP option
@@ -462,8 +465,6 @@
 /* tcp_timer.c */
 #define     tcp_reset_msl_timer(x,y,z)	net_reset_timer(x,y,z)
 extern void tcp_reset_xmit_timer(struct sock *, int, unsigned long);
-extern void tcp_clear_xmit_timer(struct sock *, int);
-extern int  tcp_timer_is_set(struct sock *, int);
 extern void tcp_init_xmit_timers(struct sock *);
 extern void tcp_clear_xmit_timers(struct sock *);
 
@@ -743,5 +744,50 @@
 
 	atomic_dec(&slt->count);
 }
+
+extern const char timer_bug_msg[];
+
+static inline void tcp_clear_xmit_timer(struct sock *sk, int what)
+{
+	struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
+	struct timer_list *timer;
+	
+	switch (what) {
+	case TIME_RETRANS:
+		timer = &tp->retransmit_timer;
+		break;
+	case TIME_DACK:
+		timer = &tp->delack_timer;
+		break;
+	case TIME_PROBE0:
+		timer = &tp->probe_timer;
+		break;	
+	default:
+		printk(timer_bug_msg);
+		return;
+	};
+	del_timer(timer);
+}
+
+static inline int tcp_timer_is_set(struct sock *sk, int what)
+{
+	struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
+
+	switch (what) {
+	case TIME_RETRANS:
+		return tp->retransmit_timer.next != NULL;
+		break;
+	case TIME_DACK:
+		return tp->delack_timer.next != NULL;
+		break;
+	case TIME_PROBE0:
+		return tp->probe_timer.next != NULL;
+		break;	
+	default:
+		printk(timer_bug_msg);
+	};
+	return 0;
+}
+
 
 #endif	/* _TCP_H */
diff -u --recursive --new-file v2.1.72/linux/init/main.c linux/init/main.c
--- v2.1.72/linux/init/main.c	Wed Dec 10 11:12:46 1997
+++ linux/init/main.c	Wed Dec 17 11:11:17 1997
@@ -105,6 +105,9 @@
 extern void decnet_setup(char *str, int *ints);
 #endif
 extern void xd_setup(char *str, int *ints);
+#ifdef CONFIG_BLK_DEV_IDE
+extern void ide_setup(char *);
+#endif
 #ifdef CONFIG_BLK_DEV_EZ
 extern void ez_setup(char *str, int *ints);
 #endif
diff -u --recursive --new-file v2.1.72/linux/kernel/ksyms.c linux/kernel/ksyms.c
--- v2.1.72/linux/kernel/ksyms.c	Tue Dec  2 16:45:20 1997
+++ linux/kernel/ksyms.c	Wed Dec 17 11:11:17 1997
@@ -202,6 +202,7 @@
 EXPORT_SYMBOL(prune_dcache);
 EXPORT_SYMBOL(shrink_dcache_sb);
 EXPORT_SYMBOL(shrink_dcache_parent);
+EXPORT_SYMBOL(find_inode_number);
 
 #if !defined(CONFIG_NFSD) && defined(CONFIG_NFSD_MODULE)
 EXPORT_SYMBOL(do_nfsservctl);
@@ -239,6 +240,7 @@
 EXPORT_SYMBOL(tq_disk);
 EXPORT_SYMBOL(efind_buffer);
 EXPORT_SYMBOL(init_buffer);
+EXPORT_SYMBOL(max_sectors);
 
 /* tty routines */
 EXPORT_SYMBOL(tty_hangup);
diff -u --recursive --new-file v2.1.72/linux/kernel/printk.c linux/kernel/printk.c
--- v2.1.72/linux/kernel/printk.c	Wed Dec 10 11:12:46 1997
+++ linux/kernel/printk.c	Thu Dec 18 11:30:57 1997
@@ -109,7 +109,7 @@
  */
 asmlinkage int sys_syslog(int type, char * buf, int len)
 {
-	unsigned long i, j, count;
+	unsigned long i, j, count, flags;
 	int do_clear = 0;
 	char c;
 	int error = -EPERM;
@@ -170,12 +170,19 @@
 		error = verify_area(VERIFY_WRITE,buf,len);
 		if (error)
 			goto out;
+		/*
+		 * The logged_chars, log_start, and log_size values may
+		 * change from an interrupt, so we disable interrupts.
+		 */
+		__save_flags(flags);
+		__cli();
 		count = len;
 		if (count > LOG_BUF_LEN)
 			count = LOG_BUF_LEN;
 		if (count > logged_chars)
 			count = logged_chars;
 		j = log_start + log_size - count;
+		__restore_flags(flags);
 		for (i = 0; i < count; i++) {
 			c = *((char *) log_buf+(j++ & (LOG_BUF_LEN-1)));
 			__put_user(c, buf++);
diff -u --recursive --new-file v2.1.72/linux/kernel/signal.c linux/kernel/signal.c
--- v2.1.72/linux/kernel/signal.c	Thu Dec  4 14:53:57 1997
+++ linux/kernel/signal.c	Thu Dec 11 11:35:38 1997
@@ -118,14 +118,15 @@
 
 	case 2: if ((x = s[0] &~ m[0]) != 0)
 			sig = 1;
-		else if ((x = s[1] &~ m[0]) != 0)
+		else if ((x = s[1] &~ m[1]) != 0)
 			sig = _NSIG_BPW + 1;
 		else
 			break;
 		sig += ffz(~x);
 		break;
 
-	case 1: if ((x = *s &~ *m) != 0) sig = ffz(~x) + 1;
+	case 1: if ((x = *s &~ *m) != 0)
+			sig = ffz(~x) + 1;
 		break;
 	}
 
diff -u --recursive --new-file v2.1.72/linux/linux/include/linux/dmascc.h linux/linux/include/linux/dmascc.h
--- v2.1.72/linux/linux/include/linux/dmascc.h	Wed Dec 10 11:12:46 1997
+++ linux/linux/include/linux/dmascc.h	Wed Dec 31 16:00:00 1969
@@ -1,43 +0,0 @@
-/*
- * $Id: dmascc.h,v 1.1 1997/12/01 10:44:55 oe1kib Exp $
- *
- * Driver for high-speed SCC boards (those with DMA support)
- * Copyright (C) 1997 Klaus Kudielka
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-/* Ioctls */
-#define SIOCGSCCPARAM SIOCDEVPRIVATE
-#define SIOCSSCCPARAM (SIOCDEVPRIVATE+1)
-
-/* Frequency of timer 0 */
-#define TMR_0_HZ      25600
-
-/* Configurable parameters */
-struct scc_param {
-  int pclk_hz;  /* frequency of BRG input (read-only - don't change) */
-  int brg_tc;   /* baud rate generator terminal count - BRG disabled if < 0 */
-  int nrzi;     /* 0 (nrz), 1 (nrzi) */
-  int clocks;   /* see documentation */
-  int txdelay;  /* [1/TMR_0_HZ] */
-  int txtime;   /* [1/HZ] */
-  int sqdelay;  /* [1/TMR_0_HZ] */
-  int waittime; /* [1/TMR_0_HZ] */
-  int slottime; /* [1/TMR_0_HZ] */
-  int persist;  /* 0 ... 255 */
-  int dma;      /* 1, 3 */
-};
-
diff -u --recursive --new-file v2.1.72/linux/net/Config.in linux/net/Config.in
--- v2.1.72/linux/net/Config.in	Wed Dec 10 11:12:46 1997
+++ linux/net/Config.in	Wed Dec 10 09:22:20 1997
@@ -16,7 +16,7 @@
   fi
 fi
 bool 'Network aliasing'  CONFIG_NET_ALIAS
-tristate 'BSD Unix domain sockets' CONFIG_UNIX
+tristate 'Unix domain sockets' CONFIG_UNIX
 bool 'TCP/IP networking' CONFIG_INET
 if [ "$CONFIG_INET" = "y" ]; then
   source net/ipv4/Config.in
diff -u --recursive --new-file v2.1.72/linux/net/appletalk/ddp.c linux/net/appletalk/ddp.c
--- v2.1.72/linux/net/appletalk/ddp.c	Sat Nov 29 11:25:12 1997
+++ linux/net/appletalk/ddp.c	Wed Dec 10 09:45:16 1997
@@ -56,7 +56,7 @@
 #include <linux/if_ether.h>
 #include <linux/notifier.h>
 #include <linux/netdevice.h>
-/*#include <linux/inetdevice.h> -- coming soon */
+#include <linux/inetdevice.h>
 #include <linux/route.h>
 #include <linux/inet.h>
 #include <linux/etherdevice.h>
@@ -1843,11 +1843,9 @@
 		case SIOCGIFMTU:
 		case SIOCGIFCONF:
 		case SIOCADDMULTI:
-		case SIOCDELMULTI:		
+		case SIOCDELMULTI:
 		case SIOCGIFCOUNT:
-#if 0			/* Also coming in the IP merge */
 		case SIOCGIFINDEX:
-#endif		
 		case SIOCGIFNAME:
 			return ((dev_ioctl(cmd,(void *) arg)));
 
diff -u --recursive --new-file v2.1.72/linux/net/core/iovec.c linux/net/core/iovec.c
--- v2.1.72/linux/net/core/iovec.c	Mon Dec  1 12:04:16 1997
+++ linux/net/core/iovec.c	Wed Dec 10 09:45:16 1997
@@ -13,6 +13,7 @@
  *					csum_..._fromiovecend.
  *		Andi Kleen	:	fixed error handling for 2.1
  *		Alexey Kuznetsov:	2.1 optimisations
+ *		Andi Kleen	:	Fix csum*fromiovecend for IPv6.
  */
 
 
@@ -196,7 +197,7 @@
 
 int csum_partial_copy_fromiovecend(unsigned char *kdata, 
 				   struct iovec *iov, int offset, 
-				   int len, int *csump)
+				   unsigned int len, int *csump)
 {
 	int partial_cnt = 0;
 	int err = 0;
@@ -238,7 +239,15 @@
 	while (len>0)
 	{
 		u8 *base = iov->iov_base;
-		int copy = min(len, iov->iov_len);
+		unsigned int copy = min(len, iov->iov_len);
+
+		/* FIXME: more sanity checking is needed here, because
+                 * the iovs are copied from the user.
+		 */
+		if (base == NULL) {
+			printk(KERN_DEBUG "%s: iov too short\n",current->comm);
+			return -EINVAL;
+		}
 		
 		/* There is a remnant from previous iov. */
 		if (partial_cnt)
@@ -276,6 +285,9 @@
 				err |= copy_from_user(kdata+copy, base + copy, partial_cnt);
 			}
 		}
+
+		if (copy == 0)
+			break;
 
 		csum = csum_partial_copy_from_user(base, kdata, copy, csum, &err);
 		len   -= copy + partial_cnt;
diff -u --recursive --new-file v2.1.72/linux/net/ipv4/Config.in linux/net/ipv4/Config.in
--- v2.1.72/linux/net/ipv4/Config.in	Mon Dec  1 12:04:16 1997
+++ linux/net/ipv4/Config.in	Wed Dec 10 09:45:16 1997
@@ -36,6 +36,12 @@
 bool 'IP: masquerading' CONFIG_IP_MASQUERADE
 if [ "$CONFIG_IP_MASQUERADE" != "n" ]; then
   comment 'Protocol-specific masquerading support will be built as modules.'
+  bool 'IP: ICMP masquerading' CONFIG_IP_MASQUERADE_ICMP
+  comment 'Protocol-specific masquerading support will be built as modules.'
+  if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+    tristate 'IP: ipautofw masq support (EXPERIMENTAL)' CONFIG_IP_MASQUERADE_IPAUTOFW
+    tristate 'IP: ipportfw masq support (EXPERIMENTAL)' CONFIG_IP_MASQUERADE_IPPORTFW
+  fi
 fi
 bool 'IP: optimize as router not host' CONFIG_IP_ROUTER
 tristate 'IP: tunneling' CONFIG_NET_IPIP
diff -u --recursive --new-file v2.1.72/linux/net/ipv4/Makefile linux/net/ipv4/Makefile
--- v2.1.72/linux/net/ipv4/Makefile	Mon Dec  1 12:04:16 1997
+++ linux/net/ipv4/Makefile	Wed Dec 10 09:45:16 1997
@@ -56,8 +56,26 @@
 endif
 
 ifeq ($(CONFIG_IP_MASQUERADE),y)
-IPV4X_OBJS += ip_masq.o ip_masq_app.o
+IPV4X_OBJS += ip_masq.o ip_masq_mod.o ip_masq_app.o 
+
+ifeq ($(CONFIG_IP_MASQUERADE_IPAUTOFW),y)
+IPV4_OBJS += ip_masq_autofw.o
+else
+  ifeq ($(CONFIG_IP_MASQUERADE_IPAUTOFW),m)
+  M_OBJS += ip_masq_autofw.o
+  endif
+endif
+
+ifeq ($(CONFIG_IP_MASQUERADE_IPPORTFW),y)
+IPV4_OBJS += ip_masq_portfw.o
+else
+  ifeq ($(CONFIG_IP_MASQUERADE_IPPORTFW),m)
+  M_OBJS += ip_masq_portfw.o
+  endif
+endif
+
 M_OBJS += ip_masq_ftp.o ip_masq_irc.o ip_masq_raudio.o ip_masq_quake.o
+M_OBJS += ip_masq_vdolive.o ip_masq_cuseeme.o
 endif
 
 ifeq ($(CONFIG_SYN_COOKIES),y)
diff -u --recursive --new-file v2.1.72/linux/net/ipv4/arp.c linux/net/ipv4/arp.c
--- v2.1.72/linux/net/ipv4/arp.c	Mon Dec  1 12:04:16 1997
+++ linux/net/ipv4/arp.c	Wed Dec 10 09:45:16 1997
@@ -1,6 +1,6 @@
 /* linux/net/inet/arp.c
  *
- * Version:	$Id: arp.c,v 1.56 1997/11/24 12:51:47 freitag Exp $
+ * Version:	$Id: arp.c,v 1.57 1997/12/09 16:11:30 jes Exp $
  *
  * Copyright (C) 1994 by Florian  La Roche
  *
@@ -1532,7 +1532,8 @@
 		int err;
 
 		if ((r->arp_flags & ATF_PERM) && !(r->arp_flags & ATF_COM))
-			return -EINVAL;
+			r->arp_flags |= ATF_COM;
+
 		err = ip_route_output(&rt, ip, 0, 1, dev ? dev->ifindex : 0);
 		if (err)
 			return err;
diff -u --recursive --new-file v2.1.72/linux/net/ipv4/fib_frontend.c linux/net/ipv4/fib_frontend.c
--- v2.1.72/linux/net/ipv4/fib_frontend.c	Mon Dec  1 12:04:16 1997
+++ linux/net/ipv4/fib_frontend.c	Fri Dec 12 12:52:57 1997
@@ -259,7 +259,7 @@
 		if (copy_from_user(&r, arg, sizeof(struct rtentry)))
 			return -EFAULT;
 		rtnl_lock();
-		err = fib_convert_rtentry(cmd, &req.nlh, &req.rtm, &rta, arg);
+		err = fib_convert_rtentry(cmd, &req.nlh, &req.rtm, &rta, &r);
 		if (err == 0) {
 			if (cmd == SIOCDELRT) {
 				struct fib_table *tb = fib_get_table(req.rtm.rtm_table);
diff -u --recursive --new-file v2.1.72/linux/net/ipv4/icmp.c linux/net/ipv4/icmp.c
--- v2.1.72/linux/net/ipv4/icmp.c	Mon Dec  1 12:04:16 1997
+++ linux/net/ipv4/icmp.c	Wed Dec 10 09:45:16 1997
@@ -3,7 +3,7 @@
  *	
  *		Alan Cox, <alan@cymru.net>
  *
- *	Version: $Id: icmp.c,v 1.35 1997/10/19 18:17:13 freitag Exp $
+ *	Version: $Id: icmp.c,v 1.36 1997/12/04 03:42:03 freitag Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *	modify it under the terms of the GNU General Public License
@@ -44,7 +44,7 @@
  *					and moved all kfree_skb() up to
  *					icmp_rcv.
  *		Andi Kleen	:	Move the rate limit bookkeeping
- *					into the dest entry and use a tocken
+ *					into the dest entry and use a token
  *					bucket filter (thanks to ANK). Make
  *					the rates sysctl configurable.
  *
@@ -549,7 +549,8 @@
 	/* XXX: use a more aggressive expire for routes created by 
 	 * this call (not longer than the rate limit timeout). 
 	 * It could be also worthwhile to not put them into ipv4
-	 * fast routing cache at first.
+	 * fast routing cache at first. Otherwise an attacker can
+	 * grow the routing table.
 	 */
 	if (ip_route_output(&rt, iph->saddr, saddr, RT_TOS(tos), 0))
 		return;
@@ -1021,8 +1022,11 @@
 
 /* 
  * 	Configurable rate limits.
- *	Send at most one packets per time.
  *	Someone should check if these default values are correct.
+ *	Note that these values interact with the routing cache GC timeout.
+ *	If you chose them too high they won't take effect, because the
+ *	dst_entry gets expired too early. The same should happen when
+ *	the cache grows too big.
  */
 int sysctl_icmp_sourcequench_time = 1*HZ; 
 int sysctl_icmp_destunreach_time = 1*HZ;
diff -u --recursive --new-file v2.1.72/linux/net/ipv4/ip_forward.c linux/net/ipv4/ip_forward.c
--- v2.1.72/linux/net/ipv4/ip_forward.c	Mon Dec  1 12:04:16 1997
+++ linux/net/ipv4/ip_forward.c	Wed Dec 10 09:45:16 1997
@@ -5,7 +5,7 @@
  *
  *		The IP forwarding functionality.
  *		
- * Version:	$Id: ip_forward.c,v 1.32 1997/10/24 17:16:06 kuznet Exp $
+ * Version:	$Id: ip_forward.c,v 1.33 1997/11/28 15:32:03 alan Exp $
  *
  * Authors:	see ip.c
  *
@@ -175,7 +175,16 @@
 			 *	and skip the firewall checks
 			 */
 			if (iph->protocol == IPPROTO_ICMP) {
-				if ((fw_res = ip_fw_masq_icmp(&skb)) < 0) {
+				__u32 maddr;
+#ifdef CONFIG_IP_MASQUERADE_ICMP
+#define icmph ((struct icmphdr *)((char *)iph + (iph->ihl<<2)))
+			    if ((icmph->type==ICMP_DEST_UNREACH)||
+				(icmph->type==ICMP_SOURCE_QUENCH)||
+				(icmph->type==ICMP_TIME_EXCEEDED))
+			        {
+#endif
+				maddr = inet_select_addr(dev2, rt->rt_gateway, RT_SCOPE_UNIVERSE);
+			        if (fw_res = ip_fw_masq_icmp(&skb, maddr) < 0) {
 					kfree_skb(skb, FREE_READ);
 					return -1;
 				}
@@ -183,6 +192,9 @@
 				if (fw_res)
 					/* ICMP matched - skip firewall */
 					goto skip_call_fw_firewall;
+#ifdef CONFIG_IP_MASQUERADE_ICMP
+			       }
+#endif				
 			}
 			if (rt->rt_flags&RTCF_MASQ)
 				goto skip_call_fw_firewall;
@@ -225,6 +237,12 @@
 			if (ip_fw_masquerade(&skb, maddr) < 0) {
 				kfree_skb(skb, FREE_READ);
 				return -1;
+			} else {
+				/*
+				 *      Masquerader may have changed skb 
+				 */
+				iph = skb->nh.iph;
+				opt = &(IPCB(skb)->opt);
 			}
 		}
 #endif
diff -u --recursive --new-file v2.1.72/linux/net/ipv4/ip_masq.c linux/net/ipv4/ip_masq.c
--- v2.1.72/linux/net/ipv4/ip_masq.c	Mon Dec  1 12:04:16 1997
+++ linux/net/ipv4/ip_masq.c	Wed Dec 10 09:45:16 1997
@@ -4,6 +4,9 @@
  *
  * 	Copyright (c) 1994 Pauline Middelink
  *
+ * Version:	@(#)ip_masq.c  0.12      97/11/30
+ *
+ *
  *	See ip_fw.c for original log
  *
  * Fixes:
@@ -12,10 +15,24 @@
  *	Juan Jose Ciarlante	:	Added hashed lookup by proto,maddr,mport and proto,saddr,sport
  *	Juan Jose Ciarlante	:	Fixed deadlock if free ports get exhausted
  *	Juan Jose Ciarlante	:	Added NO_ADDR status flag.
+ *	Richard Lynch		:	Added IP Autoforward
  *	Nigel Metheringham	:	Added ICMP handling for demasquerade
  *	Nigel Metheringham	:	Checksum checking of masqueraded data
  *	Nigel Metheringham	:	Better handling of timeouts of TCP conns
- *
+ *	Delian Delchev		:	Added support for ICMP requests and replys
+ *	Nigel Metheringham	:	ICMP in ICMP handling, tidy ups, bug fixes, made ICMP optional
+ *	Juan Jose Ciarlante	:	re-assign maddr if no packet received from outside
+ *	Juan Jose Ciarlante	:	ported to 2.1 tree
+ *	Juan Jose Ciarlante	:	reworked control connections
+ *	Steven Clarke		:	Added Port Forwarding
+ *	Juan Jose Ciarlante	:	Just ONE ip_masq_new (!)
+ *	Juan Jose Ciarlante	:	IP masq modules support
+ *	Juan Jose Ciarlante	:	don't go into search loop if mport specified
+ *	Juan Jose Ciarlante	:	locking
+ *	Steven Clarke		:	IP_MASQ_S_xx state design
+ *	Juan Jose Ciarlante	:	IP_MASQ_S state implementation 
+ *	Juan Jose Ciarlante	: 	xx_get() clears timer, _put() inserts it
+ *	
  *
  */
 
@@ -38,21 +55,252 @@
 #include <net/udp.h>
 #include <net/checksum.h>
 #include <net/ip_masq.h>
+#include <net/ip_masq_mod.h>
+#include <linux/sysctl.h>
+#include <linux/ip_fw.h>
+
+#ifdef CONFIG_IP_MASQUERADE_IPAUTOFW
+#include <net/ip_autofw.h>
+#endif
+#ifdef CONFIG_IP_MASQUERADE_IPPORTFW
+#include <net/ip_portfw.h>
+#endif
+
+
+int sysctl_ip_masq_debug = 0;
+
+/*
+ *	Exported wrapper 
+ */
+int ip_masq_get_debug_level(void)
+{
+	return sysctl_ip_masq_debug;
+}
+
+/*
+ *	Timeout table[state]
+ */
+/* static int masq_timeout_table[IP_MASQ_S_LAST+1] = { */
+static struct ip_masq_timeout_table masq_timeout_table = {
+	ATOMIC_INIT(0),	/* refcnt */
+	0,		/* scale  */
+	{
+		30*60*HZ,	/*	IP_MASQ_S_NONE,	*/
+		15*60*HZ,	/*	IP_MASQ_S_ESTABLISHED,	*/
+		2*60*HZ,	/*	IP_MASQ_S_SYN_SENT,	*/
+		1*60*HZ,	/*	IP_MASQ_S_SYN_RECV,	*/
+		2*60*HZ,	/*	IP_MASQ_S_FIN_WAIT,	*/
+		2*60*HZ,	/*	IP_MASQ_S_TIME_WAIT,	*/
+		10*HZ,		/*	IP_MASQ_S_CLOSE,	*/
+		60*HZ,		/*	IP_MASQ_S_CLOSE_WAIT,	*/
+		30*HZ,		/*	IP_MASQ_S_LAST_ACK,	*/
+		2*60*HZ,	/*	IP_MASQ_S_LISTEN,	*/
+		5*60*HZ,	/*	IP_MASQ_S_UDP,	*/
+		1*60*HZ,	/*	IP_MASQ_S_ICMP,	*/
+		2*HZ,/*	IP_MASQ_S_LAST	*/
+	},
+};
+
+#define MASQUERADE_EXPIRE_RETRY      masq_timeout_table.timeout[IP_MASQ_S_TIME_WAIT]
+
+static const char * state_name_table[IP_MASQ_S_LAST+1] = {
+	"NONE",		/*	IP_MASQ_S_NONE,	*/
+	"ESTABLISHED",	/*	IP_MASQ_S_ESTABLISHED,	*/
+	"SYN_SENT",	/*	IP_MASQ_S_SYN_SENT,	*/
+	"SYN_RECV",	/*	IP_MASQ_S_SYN_RECV,	*/
+	"FIN_WAIT",	/*	IP_MASQ_S_FIN_WAIT,	*/
+	"TIME_WAIT",	/*	IP_MASQ_S_TIME_WAIT,	*/
+	"CLOSE",	/*	IP_MASQ_S_CLOSE,	*/
+	"CLOSE_WAIT",	/*	IP_MASQ_S_CLOSE_WAIT,	*/
+	"LAST_ACK",	/*	IP_MASQ_S_LAST_ACK,	*/
+	"LISTEN",	/*	IP_MASQ_S_LISTEN,	*/
+	"UDP",		/*	IP_MASQ_S_UDP,	*/
+	"ICMP",		/*	IP_MASQ_S_ICMP,	*/
+	"BUG!",		/*	IP_MASQ_S_LAST	*/
+};
+
+#define mNO IP_MASQ_S_NONE
+#define mES IP_MASQ_S_ESTABLISHED
+#define mSS IP_MASQ_S_SYN_SENT
+#define mSR IP_MASQ_S_SYN_RECV
+#define mFW IP_MASQ_S_FIN_WAIT
+#define mTW IP_MASQ_S_TIME_WAIT
+#define mCL IP_MASQ_S_CLOSE
+#define mCW IP_MASQ_S_CLOSE_WAIT
+#define mLA IP_MASQ_S_LAST_ACK
+#define mLI IP_MASQ_S_LISTEN
+
+struct masq_tcp_states_t {
+	int next_state[IP_MASQ_S_LAST];	/* should be _LAST_TCP */
+};
+
+static const char * masq_state_name(int state)
+{
+	if (state >= IP_MASQ_S_LAST)
+		return "ERR!";
+	return state_name_table[state];
+}
+
+struct masq_tcp_states_t masq_tcp_states [] = {
+/*	INPUT */
+/* 	  mNO, mES, mSS, mSR, mFW, mTW, mCL, mCW, mLA, mLI 	*/
+/*syn*/	{{mSR, mES, mES, mSR, mSR, mSR, mSR, mSR, mSR, mSR }},
+/*fin*/	{{mCL, mCW, mSS, mTW, mTW, mTW, mCL, mCW, mLA, mLI }},
+/*ack*/	{{mCL, mES, mSS, mSR, mFW, mTW, mCL, mCW, mCL, mLI }},
+/*rst*/ {{mCL, mCL, mCL, mSR, mCL, mCL, mCL, mCL, mLA, mLI }},
+
+/*	OUTPUT */
+/* 	  mNO, mES, mSS, mSR, mFW, mTW, mCL, mCW, mLA, mLI 	*/
+/*syn*/	{{mSS, mES, mSS, mES, mSS, mSS, mSS, mSS, mSS, mLI }},
+/*fin*/	{{mTW, mFW, mSS, mTW, mFW, mTW, mCL, mTW, mLA, mLI }},
+/*ack*/	{{mES, mES, mSS, mSR, mFW, mTW, mCL, mCW, mLA, mES }},
+/*rst*/ {{mCL, mCL, mSS, mCL, mCL, mTW, mCL, mCL, mCL, mCL }},
+};
+
+static __inline__ int masq_tcp_state_idx(struct tcphdr *th, int output) 
+{
+	/*
+	 *	[0-3]: input states, [4-7]: output.
+	 */
+	if (output) 
+		output=4;
+
+	if (th->rst)
+		return output+3;
+	if (th->syn)
+		return output+0;
+	if (th->fin)
+		return output+1;
+	if (th->ack)
+		return output+2;
+	return -1;
+}
+
+
+
+static int masq_set_state_timeout(struct ip_masq *ms, int state)
+{
+	struct ip_masq_timeout_table *mstim = ms->timeout_table;
+	int scale;
+
+	/*
+	 *	Use default timeout table if no specific for this entry
+	 */
+	if (!mstim) 
+		mstim = &masq_timeout_table;
+
+	ms->timeout = mstim->timeout[ms->state=state];
+	scale = mstim->scale;
+
+	if (scale<0)
+		ms->timeout >>= -scale;
+	else if (scale > 0)
+		ms->timeout <<= scale;
+
+	return state;
+}
+
+static int masq_tcp_state(struct ip_masq *ms, int output, struct tcphdr *th)
+{
+	int state_idx;
+	int new_state = IP_MASQ_S_CLOSE;
+
+	if ((state_idx = masq_tcp_state_idx(th, output)) < 0) {
+		IP_MASQ_DEBUG(1, "masq_state_idx(%d)=%d!!!\n", 
+			output, state_idx);
+		goto tcp_state_out;
+	}
+
+	new_state = masq_tcp_states[state_idx].next_state[ms->state];
+	
+tcp_state_out:
+	if (new_state!=ms->state)
+		IP_MASQ_DEBUG(1, "%s %s [%c%c%c%c] %08lX:%04X-%08lX:%04X state: %s->%s\n",
+				masq_proto_name(ms->protocol),
+				output? "output" : "input ",
+				th->syn? 'S' : '.',
+				th->fin? 'F' : '.',
+				th->ack? 'A' : '.',
+				th->rst? 'R' : '.',
+				ntohl(ms->saddr), ntohs(ms->sport),
+				ntohl(ms->daddr), ntohs(ms->dport),
+				masq_state_name(ms->state),
+				masq_state_name(new_state));
+	return masq_set_state_timeout(ms, new_state);
+}
+
+
+/*
+ *	Handle state transitions
+ */
+static int masq_set_state(struct ip_masq *ms, int output, struct iphdr *iph, void *tp)
+{
+	struct tcphdr	*th = tp;
+	switch (iph->protocol) {
+		case IPPROTO_ICMP:
+			return masq_set_state_timeout(ms, IP_MASQ_S_ICMP);
+		case IPPROTO_UDP:
+			return masq_set_state_timeout(ms, IP_MASQ_S_UDP);
+		case IPPROTO_TCP:
+			return masq_tcp_state(ms, output, th);
+	}
+	return -1;
+}
+
+/*
+ *	Moves tunnel to listen state
+ */
+int ip_masq_listen(struct ip_masq *ms)
+{
+	masq_set_state_timeout(ms, IP_MASQ_S_LISTEN);
+	return ms->timeout;
+}
 
 #define IP_MASQ_TAB_SIZE 256    /* must be power of 2 */
 
+/* 
+ *	Dynamic address rewriting 
+ */
+extern int sysctl_ip_dynaddr;
+
 /*
- *	Implement IP packet masquerading
+ *	Lookup lock
  */
+static struct wait_queue *masq_wait;
+atomic_t __ip_masq_lock = ATOMIC_INIT(0);
 
-static const char *strProt[] = {"UDP","TCP"};
 
-static __inline__ const char * masq_proto_name(unsigned proto)
+/*
+ *	Implement IP packet masquerading
+ */
+
+/*
+ * Converts an ICMP reply code into the equivalent request code
+ */
+static __inline__ const __u8 icmp_type_request(__u8 type)
 {
-        return strProt[proto==IPPROTO_TCP];
+   switch (type)
+   {
+      case ICMP_ECHOREPLY: return ICMP_ECHO; break;
+      case ICMP_TIMESTAMPREPLY: return ICMP_TIMESTAMP; break;
+      case ICMP_INFO_REPLY: return ICMP_INFO_REQUEST; break;
+      case ICMP_ADDRESSREPLY: return ICMP_ADDRESS; break;
+      default: return (255); break;
+   }
 }
 
 /*
+ * Helper macros - attempt to make code clearer! 
+ */
+
+/* ID used in ICMP lookups */
+#define icmp_id(icmph)		((icmph->un).echo.id)
+/* (port) hash value using in ICMP lookups for requests */
+#define icmp_hv_req(icmph)	((__u16)(icmph->code+(__u16)(icmph->type<<8)))
+/* (port) hash value using in ICMP lookups for replies */
+#define icmp_hv_rep(icmph)	((__u16)(icmph->code+(__u16)(icmp_type_request(icmph->type)<<8)))
+
+/*
  *	Last masq_port number in use.
  *	Will cycle in MASQ_PORT boundaries.
  */
@@ -68,18 +316,38 @@
  *	Greater values could lower MASQ_EXPIRATION setting as a way to
  *	manage 'masq_entries resource'.
  *
+ *	By default we will reuse masq.port iff (output) connection
+ *	(5-upla) if not duplicated. 
+ *	This may break midentd and others ...
  */
 
-int ip_masq_free_ports[2] = {
-        PORT_MASQ_END - PORT_MASQ_BEGIN, 	/* UDP */
-        PORT_MASQ_END - PORT_MASQ_BEGIN 	/* TCP */
+#ifdef CONFIG_IP_MASQ_NREUSE
+#define PORT_MASQ_MUL 1
+#else
+#define PORT_MASQ_MUL 10
+#endif
+
+atomic_t ip_masq_free_ports[3] = {
+        ATOMIC_INIT((PORT_MASQ_END-PORT_MASQ_BEGIN) * PORT_MASQ_MUL),/* UDP */
+        ATOMIC_INIT((PORT_MASQ_END-PORT_MASQ_BEGIN) * PORT_MASQ_MUL),/* TCP */
+        ATOMIC_INIT((PORT_MASQ_END-PORT_MASQ_BEGIN) * PORT_MASQ_MUL),/* ICMP */
 };
 
+EXPORT_SYMBOL(ip_masq_get_debug_level);
 EXPORT_SYMBOL(ip_masq_new);
+EXPORT_SYMBOL(ip_masq_listen);
+/*
 EXPORT_SYMBOL(ip_masq_set_expire);
+*/
 EXPORT_SYMBOL(ip_masq_free_ports);
 EXPORT_SYMBOL(ip_masq_expire);
-EXPORT_SYMBOL(ip_masq_out_get_2);
+EXPORT_SYMBOL(ip_masq_out_get);
+EXPORT_SYMBOL(ip_masq_in_get);
+EXPORT_SYMBOL(ip_masq_put);
+EXPORT_SYMBOL(ip_masq_control_add);
+EXPORT_SYMBOL(ip_masq_control_del);
+EXPORT_SYMBOL(ip_masq_control_get);
+EXPORT_SYMBOL(__ip_masq_lock);
 
 /*
  *	2 ip_masq hash tables: for input and output pkts lookups.
@@ -100,12 +368,29 @@
 
 struct ip_fw_masq *ip_masq_expire = &ip_masq_dummy;
 
+
 /*
- *	Returns hash value
+ * 	Set masq expiration (deletion) and adds timer,
+ *	if timeout==0 cancel expiration.
+ *	Warning: it does not check/delete previous timer!
  */
 
-static __inline__ unsigned
+void __ip_masq_set_expire(struct ip_masq *ms, unsigned long tout)
+{
+        if (tout) {
+                ms->timer.expires = jiffies+tout;
+                add_timer(&ms->timer);
+        } else {
+                del_timer(&ms->timer);
+        }
+}
+
 
+/*
+ *	Returns hash value
+ */
+
+static __inline__ unsigned 
 ip_masq_hash_key(unsigned proto, __u32 addr, __u16 port)
 {
         return (proto^ntohl(addr)^ntohs(port)) & (IP_MASQ_TAB_SIZE-1);
@@ -117,13 +402,13 @@
  *	returns bool success.
  */
 
-static __inline__ int
-ip_masq_hash(struct ip_masq *ms)
+static int ip_masq_hash(struct ip_masq *ms)
 {
         unsigned hash;
 
         if (ms->flags & IP_MASQ_F_HASHED) {
-                printk(KERN_INFO "ip_masq_hash(): request for already hashed\n");
+                IP_MASQ_ERR( "ip_masq_hash(): request for already hashed, called from %p\n",
+			__builtin_return_address(0));
                 return 0;
         }
         /*
@@ -131,6 +416,7 @@
          */
         hash = ip_masq_hash_key(ms->protocol, ms->maddr, ms->mport);
         ms->m_link = ip_masq_m_tab[hash];
+	atomic_inc(&ms->refcnt);
         ip_masq_m_tab[hash] = ms;
 
         /*
@@ -138,6 +424,7 @@
          */
         hash = ip_masq_hash_key(ms->protocol, ms->saddr, ms->sport);
         ms->s_link = ip_masq_s_tab[hash];
+	atomic_inc(&ms->refcnt);
         ip_masq_s_tab[hash] = ms;
 
 
@@ -151,12 +438,13 @@
  *	returns bool success.
  */
 
-static __inline__ int ip_masq_unhash(struct ip_masq *ms)
+static int ip_masq_unhash(struct ip_masq *ms)
 {
         unsigned hash;
         struct ip_masq ** ms_p;
         if (!(ms->flags & IP_MASQ_F_HASHED)) {
-                printk(KERN_INFO "ip_masq_unhash(): request for unhash flagged\n");
+                IP_MASQ_ERR( "ip_masq_unhash(): request for unhash flagged, called from %p\n",
+			__builtin_return_address(0));
                 return 0;
         }
         /*
@@ -165,16 +453,19 @@
         hash = ip_masq_hash_key(ms->protocol, ms->maddr, ms->mport);
         for (ms_p = &ip_masq_m_tab[hash]; *ms_p ; ms_p = &(*ms_p)->m_link)
                 if (ms == (*ms_p))  {
-                        *ms_p = ms->m_link;
+			atomic_dec(&ms->refcnt);
+			*ms_p = ms->m_link;
                         break;
                 }
+
         /*
          *	UNhash by s{addr,port}
          */
         hash = ip_masq_hash_key(ms->protocol, ms->saddr, ms->sport);
         for (ms_p = &ip_masq_s_tab[hash]; *ms_p ; ms_p = &(*ms_p)->s_link)
                 if (ms == (*ms_p))  {
-                        *ms_p = ms->s_link;
+			atomic_dec(&ms->refcnt);
+			*ms_p = ms->s_link;
                         break;
                 }
 
@@ -183,40 +474,14 @@
 }
 
 /*
- *	Returns ip_masq associated with addresses found in iph.
- *	called for pkts coming from outside-to-INside the firewall
- *
- * 	NB. Cannot check destination address, just for the incoming port.
- * 	reason: archie.doc.ac.uk has 6 interfaces, you send to
- * 	phoenix and get a reply from any other interface(==dst)!
- *
- * 	[Only for UDP] - AC
- */
-
-struct ip_masq *
-ip_masq_in_get(struct iphdr *iph)
-{
- 	__u16 *portptr;
-        int protocol;
-        __u32 s_addr, d_addr;
-        __u16 s_port, d_port;
-
- 	portptr = (__u16 *)&(((char *)iph)[iph->ihl*4]);
-        protocol = iph->protocol;
-        s_addr = iph->saddr;
-        s_port = portptr[0];
-        d_addr = iph->daddr;
-        d_port = portptr[1];
-
-        return ip_masq_in_get_2(protocol, s_addr, s_port, d_addr, d_port);
-}
-
-/*
  *	Returns ip_masq associated with supplied parameters, either
  *	broken out of the ip/tcp headers or directly supplied for those
  *	pathological protocols with address/port in the data stream
  *	(ftp, irc).  addresses and ports are in network order.
- *	called for pkts coming from INside-to-outside the firewall.
+ *	called for pkts coming from OUTside-to-INside the firewall.
+ *
+ *	s_addr, s_port: pkt source address (foreign host)
+ *	d_addr, d_port: pkt dest address (firewall)
  *
  * 	NB. Cannot check destination address, just for the incoming port.
  * 	reason: archie.doc.ac.uk has 6 interfaces, you send to
@@ -225,44 +490,39 @@
  * 	[Only for UDP] - AC
  */
 
-struct ip_masq *
-ip_masq_in_get_2(int protocol, __u32 s_addr, __u16 s_port, __u32 d_addr, __u16 d_port)
+struct ip_masq * __ip_masq_in_get(int protocol, __u32 s_addr, __u16 s_port, __u32 d_addr, __u16 d_port)
 {
         unsigned hash;
-        struct ip_masq *ms;
+        struct ip_masq *ms = NULL;
+
+	ip_masq_lock(&__ip_masq_lock, 0);
 
         hash = ip_masq_hash_key(protocol, d_addr, d_port);
         for(ms = ip_masq_m_tab[hash]; ms ; ms = ms->m_link) {
- 		if ( protocol==ms->protocol &&
-		    (s_addr==ms->daddr || ms->flags & IP_MASQ_F_NO_DADDR) &&
-                    (s_port==ms->dport || ms->flags & IP_MASQ_F_NO_DPORT) &&
-                    (d_addr==ms->maddr && d_port==ms->mport))
-                        return ms;
+ 		if (protocol==ms->protocol &&
+		    ((s_addr==ms->daddr || ms->flags & IP_MASQ_F_NO_DADDR)) &&
+		    (s_port==ms->dport || ms->flags & IP_MASQ_F_NO_DPORT) &&
+		    (d_addr==ms->maddr && d_port==ms->mport)) {
+			IP_MASQ_DEBUG(2, "look/in %d %08X:%04hX->%08X:%04hX OK\n",
+			       protocol,
+			       s_addr,
+			       s_port,
+			       d_addr,
+			       d_port);
+			atomic_inc(&ms->refcnt);
+                        goto out;
+		}
         }
-        return NULL;
-}
-
-/*
- *	Returns ip_masq associated with addresses found in iph.
- *	called for pkts coming from inside-to-OUTside the firewall.
- */
-
-struct ip_masq *
-ip_masq_out_get(struct iphdr *iph)
-{
- 	__u16 *portptr;
-        int protocol;
-        __u32 s_addr, d_addr;
-        __u16 s_port, d_port;
-
- 	portptr = (__u16 *)&(((char *)iph)[iph->ihl*4]);
-        protocol = iph->protocol;
-        s_addr = iph->saddr;
-        s_port = portptr[0];
-        d_addr = iph->daddr;
-        d_port = portptr[1];
-
-        return ip_masq_out_get_2(protocol, s_addr, s_port, d_addr, d_port);
+	IP_MASQ_DEBUG(2, "look/in %d %08X:%04hX->%08X:%04hX fail\n",
+	       protocol,
+	       s_addr,
+	       s_port,
+	       d_addr,
+	       d_port);
+
+out:
+	ip_masq_unlock(&__ip_masq_lock, 0);
+        return ms;
 }
 
 /*
@@ -271,66 +531,209 @@
  *	pathological protocols with address/port in the data stream
  *	(ftp, irc).  addresses and ports are in network order.
  *	called for pkts coming from inside-to-OUTside the firewall.
+ *
+ *	Normally we know the source address and port but for some protocols
+ *	(e.g. ftp PASV) we do not know the source port initially.  Alas the
+ *	hash is keyed on source port so if the first lookup fails then try again
+ *	with a zero port, this time only looking at entries marked "no source
+ *	port".
  */
 
-struct ip_masq *
-ip_masq_out_get_2(int protocol, __u32 s_addr, __u16 s_port, __u32 d_addr, __u16 d_port)
+struct ip_masq * __ip_masq_out_get(int protocol, __u32 s_addr, __u16 s_port, __u32 d_addr, __u16 d_port)
 {
         unsigned hash;
-        struct ip_masq *ms;
+        struct ip_masq *ms = NULL;
 
+	/*	
+	 *	Check for "full" addressed entries
+	 */
         hash = ip_masq_hash_key(protocol, s_addr, s_port);
+	
+	ip_masq_lock(&__ip_masq_lock, 0);
+
         for(ms = ip_masq_s_tab[hash]; ms ; ms = ms->s_link) {
 		if (protocol == ms->protocol &&
 		    s_addr == ms->saddr && s_port == ms->sport &&
-                    d_addr == ms->daddr && d_port == ms->dport )
-                        return ms;
+                    d_addr == ms->daddr && d_port == ms->dport ) {
+			IP_MASQ_DEBUG(2, "lk/out1 %d %08X:%04hX->%08X:%04hX OK\n",
+			       protocol,
+			       s_addr,
+			       s_port,
+			       d_addr,
+			       d_port);
+
+			atomic_inc(&ms->refcnt);
+			goto out;
+		}
+
         }
 
-        return NULL;
+	/*	
+	 *	Check for NO_SPORT entries
+	 */
+        hash = ip_masq_hash_key(protocol, s_addr, 0);
+        for(ms = ip_masq_s_tab[hash]; ms ; ms = ms->s_link) {
+		if (ms->flags & IP_MASQ_F_NO_SPORT &&
+		    protocol == ms->protocol &&
+		    s_addr == ms->saddr && 
+                    d_addr == ms->daddr && d_port == ms->dport ) {
+			IP_MASQ_DEBUG(2, "lk/out2 %d %08X:%04hX->%08X:%04hX OK\n",
+			       protocol,
+			       s_addr,
+			       s_port,
+			       d_addr,
+			       d_port);
+
+			atomic_inc(&ms->refcnt);
+                        goto out;
+		}
+        }
+	IP_MASQ_DEBUG(2, "lk/out1 %d %08X:%04hX->%08X:%04hX fail\n",
+	       protocol,
+	       s_addr,
+	       s_port,
+	       d_addr,
+	       d_port);
+
+out:
+	ip_masq_unlock(&__ip_masq_lock, 0);
+        return ms;
 }
 
+#ifdef CONFIG_IP_MASQUERADE_NREUSE
 /*
  *	Returns ip_masq for given proto,m_addr,m_port.
  *      called by allocation routine to find an unused m_port.
  */
 
-struct ip_masq *
-ip_masq_getbym(int protocol, __u32 m_addr, __u16 m_port)
+static struct ip_masq * __ip_masq_getbym(int protocol, __u32 m_addr, __u16 m_port)
 {
         unsigned hash;
-        struct ip_masq *ms;
+        struct ip_masq *ms = NULL;
 
         hash = ip_masq_hash_key(protocol, m_addr, m_port);
+
+	ip_masq_lock(&__ip_masq_lock, 0);
+
         for(ms = ip_masq_m_tab[hash]; ms ; ms = ms->m_link) {
  		if ( protocol==ms->protocol &&
-                    (m_addr==ms->maddr && m_port==ms->mport))
-                        return ms;
+                    (m_addr==ms->maddr && m_port==ms->mport)) {
+			atomic_inc(&ms->refcnt);
+			goto out;
+		}
         }
-        return NULL;
+
+out:
+	ip_masq_unlock(&__ip_masq_lock, 0);
+        return ms;
+}
+#endif
+
+struct ip_masq * ip_masq_out_get(int protocol, __u32 s_addr, __u16 s_port, __u32 d_addr, __u16 d_port) 
+{
+	struct ip_masq *ms;
+	ms = __ip_masq_out_get(protocol, s_addr, s_port, d_addr, d_port);
+	if (ms)
+		__ip_masq_set_expire(ms, 0);
+	return ms;
+}
+
+struct ip_masq * ip_masq_in_get(int protocol, __u32 s_addr, __u16 s_port, __u32 d_addr, __u16 d_port)
+{
+	struct ip_masq *ms;
+	ms =  __ip_masq_in_get(protocol, s_addr, s_port, d_addr, d_port);
+	if (ms)
+		__ip_masq_set_expire(ms, 0);
+	return ms;
+}
+
+static __inline__ void __ip_masq_put(struct ip_masq *ms) 
+{
+	atomic_dec(&ms->refcnt);
+}
+
+void ip_masq_put(struct ip_masq *ms)
+{
+	/*
+	 *	Decrement refcnt
+	 */
+	__ip_masq_put(ms);
+
+	/*
+	 *	if refcnt==2  (2 hashes)	
+	 */
+	if (atomic_read(&ms->refcnt)==2) {
+		__ip_masq_set_expire(ms, ms->timeout);
+	} else {
+		IP_MASQ_DEBUG(0, "did not set timer with refcnt=%d, called from %p\n",
+			atomic_read(&ms->refcnt),
+			__builtin_return_address(0));
+	}
 }
 
 static void masq_expire(unsigned long data)
 {
 	struct ip_masq *ms = (struct ip_masq *)data;
-	unsigned long flags;
+	ms->timeout = MASQUERADE_EXPIRE_RETRY;
 
-#ifdef DEBUG_CONFIG_IP_MASQUERADE
-	printk("Masqueraded %s %lX:%X expired\n",
+	/*
+	 *	hey, I'm using it
+	 */
+	atomic_inc(&ms->refcnt);
+
+	IP_MASQ_DEBUG(1, "Masqueraded %s %08lX:%04X expired\n",
 			masq_proto_name(ms->protocol),
 			ntohl(ms->saddr),ntohs(ms->sport));
-#endif
 
-	save_flags(flags);
-	cli();
+	ip_masq_lock(&__ip_masq_lock, 1);
+
+	/*
+	 *	Already locked, do bounce ...
+	 */
+	if (ip_masq_nlocks(&__ip_masq_lock) != 1) {
+		goto masq_expire_later;
+	}
+
+	/*
+	 * 	do I control anybody?
+	 */
+	if (atomic_read(&ms->n_control)) 
+		goto masq_expire_later;
+
+	/* 	
+	 *	does anybody controls me?
+	 */
+
+	if (ms->control) 
+		ip_masq_control_del(ms);
 
         if (ip_masq_unhash(ms)) {
-                ip_masq_free_ports[ms->protocol==IPPROTO_TCP]++;
-                ip_masq_unbind_app(ms);
-                kfree_s(ms,sizeof(*ms));
+		if (!(ms->flags&IP_MASQ_F_MPORT))
+			atomic_inc(ip_masq_free_ports + masq_proto_num(ms->protocol));
+		ip_masq_unbind_app(ms);
         }
 
-	restore_flags(flags);
+	/*
+	 *	refcnt==1 implies I'm the only one referrer
+	 */
+	if (atomic_read(&ms->refcnt) == 1) {
+		kfree_s(ms,sizeof(*ms));
+		goto masq_expire_out;
+	}
+
+masq_expire_later:
+	IP_MASQ_DEBUG(0, "masq_expire delayed: %s %08lX:%04X->%08lX:%04X nlocks-1=%d masq.refcnt-1=%d masq.n_control=%d\n",
+		masq_proto_name(ms->protocol),
+		ntohl(ms->saddr), ntohs(ms->sport),
+		ntohl(ms->daddr), ntohs(ms->dport),
+		ip_masq_nlocks(&__ip_masq_lock)-1,
+		atomic_read(&ms->refcnt)-1,
+		atomic_read(&ms->n_control));
+
+	ip_masq_put(ms);
+
+masq_expire_out:
+	ip_masq_unlock(&__ip_masq_lock, 1);
 }
 
 /*
@@ -339,25 +742,28 @@
  * 	given boundaries MASQ_BEGIN and MASQ_END.
  */
 
-struct ip_masq * ip_masq_new(__u32 maddr, int proto, __u32 saddr, __u16 sport, __u32 daddr, __u16 dport, unsigned mflags)
+struct ip_masq * ip_masq_new(int proto, __u32 maddr, __u16 mport, __u32 saddr, __u16 sport, __u32 daddr, __u16 dport, unsigned mflags)
 {
         struct ip_masq *ms, *mst;
-        int ports_tried, *free_ports_p;
-	unsigned long flags;
+        int ports_tried;
+	atomic_t *free_ports_p = NULL;
         static int n_fails = 0;
 
-        free_ports_p = &ip_masq_free_ports[proto==IPPROTO_TCP];
 
-        if (*free_ports_p == 0) {
-                if (++n_fails < 5)
-                        printk(KERN_ERR "ip_masq_new(proto=%s): no free ports.\n",
-                               masq_proto_name(proto));
-                return NULL;
-        }
+	if (masq_proto_num(proto)!=-1 && mport == 0) {
+		free_ports_p = ip_masq_free_ports + masq_proto_num(proto);
+
+		if (atomic_read(free_ports_p) == 0) {
+			if (++n_fails < 5)
+				IP_MASQ_ERR( "ip_masq_new(proto=%s): no free ports.\n",
+				       masq_proto_name(proto));
+			return NULL;
+		}
+	}
         ms = (struct ip_masq *) kmalloc(sizeof(struct ip_masq), GFP_ATOMIC);
         if (ms == NULL) {
                 if (++n_fails < 5)
-                        printk(KERN_ERR "ip_masq_new(proto=%s): no memory available.\n",
+                        IP_MASQ_ERR("ip_masq_new(proto=%s): no memory available.\n",
                                masq_proto_name(proto));
                 return NULL;
         }
@@ -372,73 +778,115 @@
         ms->dport	   = dport;
         ms->flags	   = mflags;
         ms->app_data	   = NULL;
+        ms->control	   = NULL;
+	
+	atomic_set(&ms->n_control,0);
+	atomic_set(&ms->refcnt,0);
 
-        if (proto == IPPROTO_UDP)
+        if (proto == IPPROTO_UDP && !mport)
                 ms->flags |= IP_MASQ_F_NO_DADDR;
 
+        
         /* get masq address from rif */
         ms->maddr	   = maddr;
 
-        for (ports_tried = 0; ports_tried < *free_ports_p; ports_tried++){
-                save_flags(flags);
-                cli();
+        /*
+         *	This flag will allow masq. addr (ms->maddr)
+         *	to follow forwarding interface address.
+         */
+        ms->flags         |= IP_MASQ_F_NO_REPLY;
+  
+  	/*
+	 * 	We want a specific mport. Be careful.
+	 */
+	if (masq_proto_num(proto) == -1 || mport) {
+		ms->mport = mport;
 
-		/*
-                 *	Try the next available port number
-                 */
+		/* 
+		 *	Check 5-upla uniqueness
+		 */
+		ip_masq_lock(&__ip_masq_lock, 1);
+
+                mst = __ip_masq_in_get(proto, daddr, dport, maddr, mport);
+		if (mst==NULL) {
+			ms->flags |= IP_MASQ_F_MPORT;
+
+                        ip_masq_hash(ms);
+			ip_masq_unlock(&__ip_masq_lock, 1);
+
+			ip_masq_bind_app(ms);
+			atomic_inc(&ms->refcnt);
+			masq_set_state_timeout(ms, IP_MASQ_S_NONE);
+			return ms;
+		}
+
+		ip_masq_unlock(&__ip_masq_lock, 1);
+		__ip_masq_put(mst);
+
+		IP_MASQ_ERR( "Already used connection: %s, %d.%d.%d.%d:%d => %d.%d.%d.%d:%d, called from %p\n",
+			masq_proto_name(proto),
+			NIPQUAD(maddr), ntohs(mport),
+			NIPQUAD(daddr), ntohs(dport),
+			__builtin_return_address(0));
+
+
+		goto mport_nono;
+	}
+	
 
-		ms->mport = htons(masq_port++);
+        for (ports_tried = 0; 
+	     (atomic_read(free_ports_p) && (ports_tried <= (PORT_MASQ_END - PORT_MASQ_BEGIN)));
+	     ports_tried++){
+
+		cli();
+		/*
+		 *	Try the next available port number
+		 */
+		mport = ms->mport = htons(masq_port++);
 		if (masq_port==PORT_MASQ_END) masq_port = PORT_MASQ_BEGIN;
 
-                restore_flags(flags);
+		sti();
 
-                /*
-                 *	lookup to find out if this port is used.
-                 */
+		/*
+		 *	lookup to find out if this connection is used.
+		 */
 
-                mst = ip_masq_getbym(proto, ms->maddr, ms->mport);
-                if (mst == NULL) {
-                        save_flags(flags);
-                        cli();
-
-                        if (*free_ports_p == 0) {
-                                restore_flags(flags);
-                                break;
-                        }
-                        (*free_ports_p)--;
-                        ip_masq_hash(ms);
+		ip_masq_lock(&__ip_masq_lock, 1);
 
-                        restore_flags(flags);
+#ifdef CONFIG_IP_MASQUERADE_NREUSE
+		mst = __ip_masq_getbym(proto, maddr, mport);
+#else
+		mst = __ip_masq_in_get(proto, daddr, dport, maddr, mport);
+#endif
+		if (mst == NULL) {
 
-                        ip_masq_bind_app(ms);
-                        n_fails = 0;
-                        return ms;
-                }
+			if (atomic_read(free_ports_p) == 0) {
+				ip_masq_unlock(&__ip_masq_lock, 1);
+				break;
+			}
+			atomic_dec(free_ports_p);
+			ip_masq_hash(ms);
+			ip_masq_unlock(&__ip_masq_lock, 1);
+
+			ip_masq_bind_app(ms);
+			n_fails = 0;
+			atomic_inc(&ms->refcnt);
+			masq_set_state_timeout(ms, IP_MASQ_S_NONE);
+			return ms;
+		}
+		ip_masq_unlock(&__ip_masq_lock, 1);
+		__ip_masq_put(mst);
         }
 
         if (++n_fails < 5)
-                printk(KERN_ERR "ip_masq_new(proto=%s): could not get free masq entry (free=%d).\n",
-                       masq_proto_name(ms->protocol), *free_ports_p);
+                IP_MASQ_ERR( "ip_masq_new(proto=%s): could not get free masq entry (free=%d).\n",
+                       masq_proto_name(ms->protocol), 
+		       atomic_read(free_ports_p));
+mport_nono:
         kfree_s(ms, sizeof(*ms));
         return NULL;
 }
 
-/*
- * 	Set masq expiration (deletion) and adds timer,
- *	if timeout==0 cancel expiration.
- *	Warning: it does not check/delete previous timer!
- */
-
-void ip_masq_set_expire(struct ip_masq *ms, unsigned long tout)
-{
-        if (tout) {
-                ms->timer.expires = jiffies+tout;
-                add_timer(&ms->timer);
-        } else {
-                del_timer(&ms->timer);
-        }
-}
-
 static void recalc_check(struct udphdr *uh, __u32 saddr,
 	__u32 daddr, int len)
 {
@@ -456,7 +904,6 @@
 	__u16	*portptr;
 	struct ip_masq	*ms;
 	int		size;
-        unsigned long 	timeout;
 
 	/*
 	 * We can only masquerade protocols with ports...
@@ -464,6 +911,9 @@
 	 * We may need to consider masq-ing some ICMP related to masq-ed protocols
 	 */
 
+        if (iph->protocol==IPPROTO_ICMP) 
+            return (ip_fw_masq_icmp(skb_ptr, maddr));
+
 	if (iph->protocol!=IPPROTO_UDP && iph->protocol!=IPPROTO_TCP)
 		return -1;
 
@@ -472,31 +922,72 @@
 	 */
 
 	portptr = (__u16 *)&(((char *)iph)[iph->ihl*4]);
-#ifdef DEBUG_CONFIG_IP_MASQUERADE
-	printk("Outgoing %s %lX:%X -> %lX:%X\n",
-		masq_proto_name(iph->protocol),
-		ntohl(iph->saddr), ntohs(portptr[0]),
-		ntohl(iph->daddr), ntohs(portptr[1]));
-#endif
+ 	IP_MASQ_DEBUG(2, "Outgoing %s %08lX:%04X -> %08lX:%04X\n",
+  		masq_proto_name(iph->protocol),
+  		ntohl(iph->saddr), ntohs(portptr[0]),
+  		ntohl(iph->daddr), ntohs(portptr[1]));
 
-        ms = ip_masq_out_get(iph);
-        if (ms!=NULL)
-                ip_masq_set_expire(ms,0);
+        ms = ip_masq_out_get_iph(iph);
+        if (ms!=NULL) {
 
-	/*
-	 *	Nope, not found, create a new entry for it
-	 */
+                /*
+                 *	If sysctl !=0 and no pkt has been received yet
+                 *	in this tunnel and routing iface address has changed...
+                 *	 "You are welcome, diald".
+                 */
+                if ( sysctl_ip_dynaddr && ms->flags & IP_MASQ_F_NO_REPLY && maddr != ms->maddr) {
 
-	if (ms==NULL)
-	{
-                ms = ip_masq_new(maddr, iph->protocol,
-                                 iph->saddr, portptr[0],
-                                 iph->daddr, portptr[1],
-                                 0);
+                        if (sysctl_ip_dynaddr > 1) {
+                                IP_MASQ_INFO( "ip_fw_masquerade(): change masq.addr from %d.%d.%d.%d to %d.%d.%d.%d\n",
+                                       NIPQUAD(ms->maddr),NIPQUAD(maddr));
+                        }
+
+			ip_masq_lock(&__ip_masq_lock, 1);
+
+                        ip_masq_unhash(ms);
+                        ms->maddr = maddr;
+                        ip_masq_hash(ms);
+
+			ip_masq_unlock(&__ip_masq_lock, 1);
+                }
+                
+		/*
+		 *      Set sport if not defined yet (e.g. ftp PASV).  Because
+		 *	masq entries are hashed on sport, unhash with old value
+		 *	and hash with new.
+		 */
+
+		if ( ms->flags & IP_MASQ_F_NO_SPORT && ms->protocol == IPPROTO_TCP ) {
+			ms->flags &= ~IP_MASQ_F_NO_SPORT;
+
+			ip_masq_lock(&__ip_masq_lock, 1);
+			
+			ip_masq_unhash(ms);
+			ms->sport = portptr[0];
+			ip_masq_hash(ms);	/* hash on new sport */
+
+			ip_masq_unlock(&__ip_masq_lock, 1);
+			
+			IP_MASQ_DEBUG(1, "ip_fw_masquerade(): filled sport=%d\n",
+			       ntohs(ms->sport));
+		}
+        } else {
+		/*
+		 *	Nope, not found, create a new entry for it
+		 */
+
+		if (!(ms = ip_masq_mod_out_create(iph, portptr, maddr))) 
+			ms = ip_masq_new(iph->protocol,
+					maddr, 0,
+					iph->saddr, portptr[0],
+					iph->daddr, portptr[1],
+					0);
                 if (ms == NULL)
 			return -1;
  	}
 
+	ip_masq_mod_out_update(iph, portptr, ms);
+
  	/*
  	 *	Change the fragments origin
  	 */
@@ -527,40 +1018,12 @@
  	 *	Adjust packet accordingly to protocol
  	 */
 
- 	if (iph->protocol==IPPROTO_UDP)
+ 	if (iph->protocol == IPPROTO_UDP)
  	{
-                timeout = ip_masq_expire->udp_timeout;
  		recalc_check((struct udphdr *)portptr,iph->saddr,iph->daddr,size);
- 	}
- 	else
- 	{
- 		struct tcphdr *th;
- 		th = (struct tcphdr *)portptr;
-
-		/* Set the flags up correctly... */
-		if (th->fin)
-		{
-			ms->flags |= IP_MASQ_F_SAW_FIN_OUT;
-		}
+ 	} else {
+ 		struct tcphdr *th = (struct tcphdr *)portptr;
 
-		if (th->rst)
-		{
-			ms->flags |= IP_MASQ_F_SAW_RST;
-		}
-
- 		/*
- 		 *	Timeout depends if FIN packet has been seen
-		 *	Very short timeout if RST packet seen.
- 		 */
- 		if (ms->flags & IP_MASQ_F_SAW_RST)
-		{
-                        timeout = 1;
-		}
- 		else if ((ms->flags & IP_MASQ_F_SAW_FIN) == IP_MASQ_F_SAW_FIN)
-		{
-                        timeout = ip_masq_expire->tcp_fin_timeout;
-		}
- 		else timeout = ip_masq_expire->tcp_timeout;
 
 		skb->csum = csum_partial((void *)(th + 1), size - sizeof(*th), 0);
 		th->check = 0;
@@ -568,12 +1031,14 @@
 					 csum_partial((char *)th, sizeof(*th),
 						      skb->csum));
  	}
-        ip_masq_set_expire(ms, timeout);
- 	ip_send_check(iph);
 
- #ifdef DEBUG_CONFIG_IP_MASQUERADE
- 	printk("O-routed from %lX:%X via %lX\n",ntohl(ms->maddr),ntohs(ms->mport),ntohl(maddr));
- #endif
+	ip_send_check(iph);
+
+  	IP_MASQ_DEBUG(2, "O-routed from %08lX:%04X with masq.addr %08lX\n",
+		ntohl(ms->maddr),ntohs(ms->mport),ntohl(maddr));
+
+	masq_set_state(ms, 1, iph, portptr);
+	ip_masq_put(ms);
 
 	return 0;
  }
@@ -586,7 +1051,7 @@
  *	Currently handles error types - unreachable, quench, ttl exceeded
  */
 
-int ip_fw_masq_icmp(struct sk_buff **skb_p)
+int ip_fw_masq_icmp(struct sk_buff **skb_p, __u32 maddr)
 {
         struct sk_buff 	*skb   = *skb_p;
  	struct iphdr	*iph   = skb->nh.iph;
@@ -596,10 +1061,78 @@
 	struct ip_masq	*ms;
 	unsigned short   len   = ntohs(iph->tot_len) - (iph->ihl * 4);
 
-#ifdef DEBUG_CONFIG_IP_MASQUERADE
- 	printk("Incoming forward ICMP (%d) %lX -> %lX\n",
-	        icmph->type,
+ 	IP_MASQ_DEBUG(2, "Incoming forward ICMP (%d,%d) %lX -> %lX\n",
+	        icmph->type, ntohs(icmp_id(icmph)),
  		ntohl(iph->saddr), ntohl(iph->daddr));
+
+#ifdef CONFIG_IP_MASQUERADE_ICMP		
+	if ((icmph->type == ICMP_ECHO ) ||
+	    (icmph->type == ICMP_TIMESTAMP ) ||
+	    (icmph->type == ICMP_INFO_REQUEST ) ||
+	    (icmph->type == ICMP_ADDRESS )) {
+
+		IP_MASQ_DEBUG(2, "icmp request rcv %lX->%lX  id %d type %d\n",
+		       ntohl(iph->saddr),
+		       ntohl(iph->daddr),
+		       ntohs(icmp_id(icmph)),
+		       icmph->type);
+
+		ms = ip_masq_out_get(iph->protocol,
+				       iph->saddr,
+				       icmp_id(icmph),
+				       iph->daddr,
+				       icmp_hv_req(icmph));
+		if (ms == NULL) {
+			ms = ip_masq_new(iph->protocol,
+					 maddr, 0,
+					 iph->saddr, icmp_id(icmph),
+					 iph->daddr, icmp_hv_req(icmph),
+					 0);
+			if (ms == NULL)
+				return (-1);
+			IP_MASQ_DEBUG(1, "Created new icmp entry\n");
+		}
+		/* Rewrite source address */
+                
+                /*
+                 *	If sysctl !=0 and no pkt has been received yet
+                 *	in this tunnel and routing iface address has changed...
+                 *	 "You are welcome, diald".
+                 */
+                if ( sysctl_ip_dynaddr && ms->flags & IP_MASQ_F_NO_REPLY && maddr != ms->maddr) {
+
+                        if (sysctl_ip_dynaddr > 1) {
+				IP_MASQ_INFO( "ip_fw_masq_icmp(): change masq.addr %d.%d.%d.%d to %d.%d.%d.%d",
+				       NIPQUAD(ms->maddr), NIPQUAD(maddr));
+			}
+
+			ip_masq_lock(&__ip_masq_lock, 1);
+			
+                        ip_masq_unhash(ms);
+                        ms->maddr = maddr;
+                        ip_masq_hash(ms);
+
+			ip_masq_unlock(&__ip_masq_lock, 1);
+                }
+                
+		iph->saddr = ms->maddr;
+		ip_send_check(iph);
+		/* Rewrite port (id) */
+		(icmph->un).echo.id = ms->mport;
+		icmph->checksum = 0;
+		icmph->checksum = ip_compute_csum((unsigned char *)icmph, len);
+
+		IP_MASQ_DEBUG(2, "icmp request rwt %lX->%lX id %d type %d\n",
+		       ntohl(iph->saddr),
+		       ntohl(iph->daddr),
+		       ntohs(icmp_id(icmph)),
+		       icmph->type);
+
+		masq_set_state(ms, 1, iph, icmph);
+		ip_masq_put(ms);
+
+		return 1;
+	}
 #endif
 
 	/*
@@ -618,6 +1151,59 @@
 	/* Now find the contained IP header */
 	ciph = (struct iphdr *) (icmph + 1);
 
+#ifdef CONFIG_IP_MASQUERADE_ICMP
+	if (ciph->protocol == IPPROTO_ICMP) {
+		/*
+		 * This section handles ICMP errors for ICMP packets
+		 */
+		struct icmphdr  *cicmph = (struct icmphdr *)((char *)ciph + 
+							     (ciph->ihl<<2));
+
+
+		IP_MASQ_DEBUG(2, "fw icmp/icmp rcv %lX->%lX id %d type %d\n",
+		       ntohl(ciph->saddr),
+		       ntohl(ciph->daddr),
+		       ntohs(icmp_id(cicmph)),
+		       cicmph->type);
+
+		ms = __ip_masq_out_get(ciph->protocol, 
+				      ciph->daddr,
+				      icmp_id(cicmph),
+				      ciph->saddr,
+				      icmp_hv_rep(cicmph));
+
+		if (ms == NULL)
+			return 0;
+
+		/* Now we do real damage to this packet...! */
+		/* First change the source IP address, and recalc checksum */
+		iph->saddr = ms->maddr;
+		ip_send_check(iph);
+	
+		/* Now change the *dest* address in the contained IP */
+		ciph->daddr = ms->maddr;
+		__ip_masq_put(ms);
+
+		ip_send_check(ciph);
+
+		/* Change the ID to the masqed one! */
+		(cicmph->un).echo.id = ms->mport;
+	
+		/* And finally the ICMP checksum */
+		icmph->checksum = 0;
+		icmph->checksum = ip_compute_csum((unsigned char *) icmph, len);
+
+
+		IP_MASQ_DEBUG(2, "fw icmp/icmp rwt %lX->%lX id %d type %d\n",
+		       ntohl(ciph->saddr),
+		       ntohl(ciph->daddr),
+		       ntohs(icmp_id(cicmph)),
+		       cicmph->type);
+
+		return 1;
+	}
+#endif /* CONFIG_IP_MASQUERADE_ICMP */
+
 	/* We are only interested ICMPs generated from TCP or UDP packets */
 	if ((ciph->protocol != IPPROTO_UDP) && (ciph->protocol != IPPROTO_TCP))
 		return 0;
@@ -628,27 +1214,36 @@
 	 * (but reversed relative to outer IP header!)
 	 */
 	pptr = (__u16 *)&(((char *)ciph)[ciph->ihl*4]);
+#if 0
 	if (ntohs(pptr[1]) < PORT_MASQ_BEGIN ||
  	    ntohs(pptr[1]) > PORT_MASQ_END)
  		return 0;
+#endif
 
 	/* Ensure the checksum is correct */
 	if (ip_compute_csum((unsigned char *) icmph, len))
 	{
 		/* Failed checksum! */
-		printk(KERN_INFO "MASQ: forward ICMP: failed checksum from %s!\n",
-		       in_ntoa(iph->saddr));
+		IP_MASQ_WARNING( "forward ICMP: failed checksum from %d.%d.%d.%d!\n",
+		       NIPQUAD(iph->saddr));
 		return(-1);
 	}
 
-#ifdef DEBUG_CONFIG_IP_MASQUERADE
- 	printk("Handling forward ICMP for %lX:%X -> %lX:%X\n",
+
+ 	IP_MASQ_DEBUG(2, "Handling forward ICMP for %08lX:%04X -> %08lX:%04X\n",
 	       ntohl(ciph->saddr), ntohs(pptr[0]),
 	       ntohl(ciph->daddr), ntohs(pptr[1]));
-#endif
 
-	/* This is pretty much what ip_masq_in_get() does */
-	ms = ip_masq_in_get_2(ciph->protocol, ciph->saddr, pptr[0], ciph->daddr, pptr[1]);
+
+#if 0
+	/* This is pretty much what __ip_masq_in_get_iph() does */
+	ms = __ip_masq_in_get(ciph->protocol, ciph->saddr, pptr[0], ciph->daddr, pptr[1]);
+#endif
+	ms = __ip_masq_out_get(ciph->protocol,
+			       ciph->daddr,
+			       pptr[1],
+			       ciph->saddr,
+			       pptr[0]);
 
 	if (ms == NULL)
 		return 0;
@@ -664,16 +1259,17 @@
 
 	/* the TCP/UDP dest port - cannot redo check */
 	pptr[1] = ms->mport;
+	__ip_masq_put(ms);
 
 	/* And finally the ICMP checksum */
 	icmph->checksum = 0;
 	icmph->checksum = ip_compute_csum((unsigned char *) icmph, len);
 
-#ifdef DEBUG_CONFIG_IP_MASQUERADE
- 	printk("Rewrote forward ICMP to %lX:%X -> %lX:%X\n",
+
+ 	IP_MASQ_DEBUG(2, "Rewrote forward ICMP to %08lX:%04X -> %08lX:%04X\n",
 	       ntohl(ciph->saddr), ntohs(pptr[0]),
 	       ntohl(ciph->daddr), ntohs(pptr[1]));
-#endif
+
 
 	return 1;
 }
@@ -695,22 +1291,133 @@
 	struct ip_masq	*ms;
 	unsigned short   len   = ntohs(iph->tot_len) - (iph->ihl * 4);
 
-#ifdef DEBUG_CONFIG_IP_MASQUERADE
- 	printk("Incoming reverse ICMP (%d) %lX -> %lX\n",
-	        icmph->type,
+
+ 	IP_MASQ_DEBUG(2, "icmp in/rev (%d,%d) %lX -> %lX\n",
+	        icmph->type, ntohs(icmp_id(icmph)),
  		ntohl(iph->saddr), ntohl(iph->daddr));
-#endif
 
-	if ((icmph->type != ICMP_DEST_UNREACH) &&
-	    (icmph->type != ICMP_SOURCE_QUENCH) &&
-	    (icmph->type != ICMP_TIME_EXCEEDED))
-		return 0;
 
-	/* Now find the contained IP header */
+#ifdef CONFIG_IP_MASQUERADE_ICMP		
+	if ((icmph->type == ICMP_ECHOREPLY) ||
+	    (icmph->type == ICMP_TIMESTAMPREPLY) ||
+	    (icmph->type == ICMP_INFO_REPLY) ||
+	    (icmph->type == ICMP_ADDRESSREPLY))	{
+
+		IP_MASQ_DEBUG(2, "icmp reply rcv %lX->%lX id %d type %d, req %d\n",
+		       ntohl(iph->saddr),
+		       ntohl(iph->daddr),
+		       ntohs(icmp_id(icmph)),
+		       icmph->type,
+		       icmp_type_request(icmph->type));
+
+		ms = ip_masq_in_get(iph->protocol,
+				      iph->saddr,
+				      icmp_hv_rep(icmph),
+				      iph->daddr,
+				      icmp_id(icmph));
+		if (ms == NULL)
+			return 0;
+
+                /*
+                 *	got reply, so clear flag
+                 */
+                ms->flags &= ~IP_MASQ_F_NO_REPLY;
+
+		/* Reset source address */
+		iph->daddr = ms->saddr;
+		/* Redo IP header checksum */
+		ip_send_check(iph);
+		/* Set ID to fake port number */
+		(icmph->un).echo.id = ms->sport;
+		/* Reset ICMP checksum and set expiry */
+		icmph->checksum=0;
+		icmph->checksum=ip_compute_csum((unsigned char *)icmph,len);
+
+
+
+		IP_MASQ_DEBUG(2, "icmp reply rwt %lX->%lX id %d type %d\n",
+		       ntohl(iph->saddr),
+		       ntohl(iph->daddr),
+		       ntohs(icmp_id(icmph)),
+		       icmph->type);
+
+		masq_set_state(ms, 0, iph, icmph);
+		ip_masq_put(ms);
+
+		return 1;
+	} else {
+#endif
+		if ((icmph->type != ICMP_DEST_UNREACH) &&
+		    (icmph->type != ICMP_SOURCE_QUENCH) &&
+		    (icmph->type != ICMP_TIME_EXCEEDED))
+			return 0;
+#ifdef CONFIG_IP_MASQUERADE_ICMP
+	}
+#endif
+	/*
+	 * If we get here we have an ICMP error of one of the above 3 types
+	 * Now find the contained IP header
+	 */
+
 	ciph = (struct iphdr *) (icmph + 1);
 
+#ifdef CONFIG_IP_MASQUERADE_ICMP
+	if (ciph->protocol == IPPROTO_ICMP) {
+		/*
+		 * This section handles ICMP errors for ICMP packets
+		 *
+		 * First get a new ICMP header structure out of the IP packet
+		 */
+		struct icmphdr  *cicmph = (struct icmphdr *)((char *)ciph + 
+							     (ciph->ihl<<2));
+
+
+		IP_MASQ_DEBUG(2, "rv icmp/icmp rcv %lX->%lX id %d type %d\n",
+		       ntohl(ciph->saddr),
+		       ntohl(ciph->daddr),
+		       ntohs(icmp_id(cicmph)),
+		       cicmph->type);
+
+		ms = __ip_masq_in_get(ciph->protocol, 
+				      ciph->daddr, 
+				      icmp_hv_req(cicmph),
+				      ciph->saddr, 
+				      icmp_id(cicmph));
+
+		if (ms == NULL)
+			return 0;
+
+		/* Now we do real damage to this packet...! */
+		/* First change the dest IP address, and recalc checksum */
+		iph->daddr = ms->saddr;
+		ip_send_check(iph);
+	
+		/* Now change the *source* address in the contained IP */
+		ciph->saddr = ms->saddr;
+		ip_send_check(ciph);
+
+		/* Change the ID to the original one! */
+		(cicmph->un).echo.id = ms->sport;
+		__ip_masq_put(ms);
+
+		/* And finally the ICMP checksum */
+		icmph->checksum = 0;
+		icmph->checksum = ip_compute_csum((unsigned char *) icmph, len);
+
+
+		IP_MASQ_DEBUG(2, "rv icmp/icmp rwt %lX->%lX id %d type %d\n",
+		       ntohl(ciph->saddr),
+		       ntohl(ciph->daddr),
+		       ntohs(icmp_id(cicmph)),
+		       cicmph->type);
+
+		return 1;
+	}
+#endif /* CONFIG_IP_MASQUERADE_ICMP */
+
 	/* We are only interested ICMPs generated from TCP or UDP packets */
-	if ((ciph->protocol != IPPROTO_UDP) && (ciph->protocol != IPPROTO_TCP))
+	if ((ciph->protocol != IPPROTO_UDP) && 
+	    (ciph->protocol != IPPROTO_TCP))
 		return 0;
 
 	/*
@@ -726,19 +1433,23 @@
 	if (ip_compute_csum((unsigned char *) icmph, len))
 	{
 		/* Failed checksum! */
-		printk(KERN_INFO "MASQ: reverse ICMP: failed checksum from %s!\n",
-		       in_ntoa(iph->saddr));
+		IP_MASQ_ERR( "reverse ICMP: failed checksum from %d.%d.%d.%d!\n",
+		       NIPQUAD(iph->saddr));
 		return(-1);
 	}
 
-#ifdef DEBUG_CONFIG_IP_MASQUERADE
- 	printk("Handling reverse ICMP for %lX:%X -> %lX:%X\n",
+
+ 	IP_MASQ_DEBUG(2, "Handling reverse ICMP for %08lX:%04X -> %08lX:%04X\n",
 	       ntohl(ciph->saddr), ntohs(pptr[0]),
 	       ntohl(ciph->daddr), ntohs(pptr[1]));
-#endif
 
-	/* This is pretty much what ip_masq_in_get() does, except params are wrong way round */
-	ms = ip_masq_in_get_2(ciph->protocol, ciph->daddr, pptr[1], ciph->saddr, pptr[0]);
+
+	/* This is pretty much what __ip_masq_in_get_iph() does, except params are wrong way round */
+	ms = __ip_masq_in_get(ciph->protocol,
+			      ciph->daddr,
+			      pptr[1],
+			      ciph->saddr,
+			      pptr[0]);
 
 	if (ms == NULL)
 		return 0;
@@ -754,16 +1465,17 @@
 
 	/* the TCP/UDP source port - cannot redo check */
 	pptr[0] = ms->sport;
+	__ip_masq_put(ms);
 
 	/* And finally the ICMP checksum */
 	icmph->checksum = 0;
 	icmph->checksum = ip_compute_csum((unsigned char *) icmph, len);
 
-#ifdef DEBUG_CONFIG_IP_MASQUERADE
- 	printk("Rewrote reverse ICMP to %lX:%X -> %lX:%X\n",
+
+ 	IP_MASQ_DEBUG(2, "Rewrote reverse ICMP to %08lX:%04X -> %08lX:%04X\n",
 	       ntohl(ciph->saddr), ntohs(pptr[0]),
 	       ntohl(ciph->daddr), ntohs(pptr[1]));
-#endif
+
 
 	return 1;
 }
@@ -785,7 +1497,10 @@
  	__u16	*portptr;
  	struct ip_masq	*ms;
 	unsigned short len;
-	unsigned long 	timeout;
+
+	__u32 maddr;
+
+	maddr = iph->daddr;
 
 	switch (iph->protocol) {
 	case IPPROTO_ICMP:
@@ -794,9 +1509,11 @@
 	case IPPROTO_UDP:
 		/* Make sure packet is in the masq range */
 		portptr = (__u16 *)&(((char *)iph)[iph->ihl*4]);
-		if (ntohs(portptr[1]) < PORT_MASQ_BEGIN ||
-		    ntohs(portptr[1]) > PORT_MASQ_END)
+		if ((ntohs(portptr[1]) < PORT_MASQ_BEGIN
+				|| ntohs(portptr[1]) > PORT_MASQ_END)
+				&& (ip_masq_mod_in_rule(iph, portptr) != 1))
 			return 0;
+
 		/* Check that the checksum is OK */
 		len = ntohs(iph->tot_len) - (iph->ihl * 4);
 		if ((iph->protocol == IPPROTO_UDP) && (portptr[3] == 0))
@@ -811,8 +1528,8 @@
 				if (csum_tcpudp_magic(iph->saddr, iph->daddr, len,
 						      iph->protocol, skb->csum))
 				{
-					printk(KERN_INFO "MASQ: failed TCP/UDP checksum from %s!\n",
-					       in_ntoa(iph->saddr));
+					IP_MASQ_WARNING( "failed TCP/UDP checksum from %d.%d.%d.%d!\n",
+					       NIPQUAD(iph->saddr));
 					return -1;
 				}
 			default:
@@ -824,42 +1541,50 @@
 	}
 
 
-#ifdef DEBUG_CONFIG_IP_MASQUERADE
- 	printk("Incoming %s %lX:%X -> %lX:%X\n",
+
+ 	IP_MASQ_DEBUG(2, "Incoming %s %08lX:%04X -> %08lX:%04X\n",
  		masq_proto_name(iph->protocol),
  		ntohl(iph->saddr), ntohs(portptr[0]),
  		ntohl(iph->daddr), ntohs(portptr[1]));
-#endif
+
  	/*
  	 * reroute to original host:port if found...
          */
 
-        ms = ip_masq_in_get(iph);
+        ms = ip_masq_in_get_iph(iph);
+
+	if (!ms) 
+		ms = ip_masq_mod_in_create(iph, portptr, maddr);
+
+	ip_masq_mod_in_update(iph, portptr, ms);
 
         if (ms != NULL)
         {
-		/* Stop the timer ticking.... */
-		ip_masq_set_expire(ms,0);
 
                 /*
+                 *	got reply, so clear flag
+                 */
+                ms->flags &= ~IP_MASQ_F_NO_REPLY;
+                
+                /*
                  *	Set dport if not defined yet.
                  */
 
-                if ( ms->flags & IP_MASQ_F_NO_DPORT && ms->protocol == IPPROTO_TCP ) {
+                if ( ms->flags & IP_MASQ_F_NO_DPORT ) { /*  && ms->protocol == IPPROTO_TCP ) { */
                         ms->flags &= ~IP_MASQ_F_NO_DPORT;
                         ms->dport = portptr[0];
-#if DEBUG_CONFIG_IP_MASQUERADE
-                        printk("ip_fw_demasquerade(): filled dport=%d\n",
+
+                        IP_MASQ_DEBUG(1, "ip_fw_demasquerade(): filled dport=%d\n",
                                ntohs(ms->dport));
-#endif
+
                 }
-                if (ms->flags & IP_MASQ_F_NO_DADDR && ms->protocol == IPPROTO_TCP)  {
+                if (ms->flags & IP_MASQ_F_NO_DADDR ) { /*  && ms->protocol == IPPROTO_TCP)  { */
                         ms->flags &= ~IP_MASQ_F_NO_DADDR;
                         ms->daddr = iph->saddr;
-#if DEBUG_CONFIG_IP_MASQUERADE
-                        printk("ip_fw_demasquerade(): filled daddr=%X\n",
+
+                        IP_MASQ_DEBUG(1, "ip_fw_demasquerade(): filled daddr=%X\n",
                                ntohs(ms->daddr));
-#endif
+
                 }
                 iph->daddr = ms->saddr;
                 portptr[1] = ms->sport;
@@ -869,7 +1594,7 @@
                  *	will fix ip_masq and iph ack_seq stuff
                  */
 
-                if (ip_masq_app_pkt_in(ms, skb_p) != 0)
+                if (ip_masq_app_pkt_in(ms, skb_p, maddr) != 0)
                 {
                         /*
                          *	skb has changed, update pointers.
@@ -886,50 +1611,27 @@
 		 * timeouts.
 		 * If a TCP RST is seen collapse the tunnel (by using short timeout)!
                  */
-                if (iph->protocol==IPPROTO_UDP)
-		{
+                if (iph->protocol == IPPROTO_UDP) {
                         recalc_check((struct udphdr *)portptr,iph->saddr,iph->daddr,len);
-			timeout = ip_masq_expire->udp_timeout;
-		}
-                else
-                {
-			struct tcphdr *th;
-                        skb->csum = csum_partial((void *)(((struct tcphdr *)portptr) + 1),
+		} else {
+			struct tcphdr *th = (struct tcphdr *)portptr;
+                        skb->csum = csum_partial((void *)(th + 1),
                                                  len - sizeof(struct tcphdr), 0);
-			th = (struct tcphdr *) portptr;
+
 			th->check = 0;
-                        th->check = tcp_v4_check(th, len, iph->saddr,
-						 iph->daddr,
+                        th->check = tcp_v4_check(th, len, iph->saddr, iph->daddr,
 						 csum_partial((char *)th,
 							      sizeof(*th),
 				     			      skb->csum));
 
-			/* Check if TCP FIN or RST */
-			if (th->fin)
-			{
-				ms->flags |= IP_MASQ_F_SAW_FIN_IN;
-			}
-			if (th->rst)
-			{
-				ms->flags |= IP_MASQ_F_SAW_RST;
-			}
-
-			/* Now set the timeouts */
-			if (ms->flags & IP_MASQ_F_SAW_RST)
-			{
-				timeout = 1;
-			}
-			else if ((ms->flags & IP_MASQ_F_SAW_FIN) == IP_MASQ_F_SAW_FIN)
-			{
-				timeout = ip_masq_expire->tcp_fin_timeout;
-			}
-			else timeout = ip_masq_expire->tcp_timeout;
                 }
-		ip_masq_set_expire(ms, timeout);
                 ip_send_check(iph);
-#ifdef DEBUG_CONFIG_IP_MASQUERADE
-                printk("I-routed to %lX:%X\n",ntohl(iph->daddr),ntohs(portptr[1]));
-#endif
+
+                IP_MASQ_DEBUG(2, "I-routed to %08lX:%04X\n",ntohl(iph->daddr),ntohs(portptr[1]));
+
+		masq_set_state (ms, 0, iph, portptr);
+		ip_masq_put(ms);
+
                 return 1;
  	}
 
@@ -937,43 +1639,89 @@
  	return 0;
 }
 
+
+void ip_masq_control_add(struct ip_masq *ms, struct ip_masq* ctl_ms)
+{
+	if (ms->control) {
+		IP_MASQ_ERR( "request control ADD for already controlled: %d.%d.%d.%d:%d to %d.%d.%d.%d:%d\n",
+				NIPQUAD(ms->saddr),ntohs(ms->sport),
+				NIPQUAD(ms->daddr),ntohs(ms->dport));
+		ip_masq_control_del(ms);
+	}
+	IP_MASQ_DEBUG(1, "ADDing control for: ms.dst=%d.%d.%d.%d:%d ctl_ms.dst=%d.%d.%d.%d:%d\n",
+				NIPQUAD(ms->daddr),ntohs(ms->dport),
+				NIPQUAD(ctl_ms->daddr),ntohs(ctl_ms->dport));
+	ms->control = ctl_ms;
+	atomic_inc(&ctl_ms->n_control);
+}
+
+void ip_masq_control_del(struct ip_masq *ms)
+{
+	struct ip_masq *ctl_ms = ms->control;
+	if (!ctl_ms) {
+		IP_MASQ_ERR( "request control DEL for uncontrolled: %d.%d.%d.%d:%d to %d.%d.%d.%d:%d\n",
+				NIPQUAD(ms->saddr),ntohs(ms->sport),
+				NIPQUAD(ms->daddr),ntohs(ms->dport));
+			return;
+	}
+	IP_MASQ_DEBUG(1, "DELeting control for: ms.dst=%d.%d.%d.%d:%d ctl_ms.dst=%d.%d.%d.%d:%d\n",
+				NIPQUAD(ms->daddr),ntohs(ms->dport),
+				NIPQUAD(ctl_ms->daddr),ntohs(ctl_ms->dport));
+	ms->control = NULL;
+	if (atomic_read(&ctl_ms->n_control) == 0) {
+		IP_MASQ_ERR( "BUG control DEL with n=0 : %d.%d.%d.%d:%d to %d.%d.%d.%d:%d\n",
+				NIPQUAD(ms->saddr),ntohs(ms->sport),
+				NIPQUAD(ms->daddr),ntohs(ms->dport));
+			return;
+		
+	}
+	atomic_dec(&ctl_ms->n_control);
+}
+
+struct ip_masq * ip_masq_control_get(struct ip_masq *ms)
+{
+	return ms->control;
+}
+
 #ifdef CONFIG_PROC_FS
 /*
- *	/proc/net entry
+ *	/proc/net entries
+ *	From userspace
  */
-
 static int ip_msqhst_procinfo(char *buffer, char **start, off_t offset,
 			      int length, int unused)
 {
 	off_t pos=0, begin;
 	struct ip_masq *ms;
-	unsigned long flags;
 	char temp[129];
         int idx = 0;
 	int len=0;
 
+	ip_masq_lockz(&__ip_masq_lock, &masq_wait, 0);
+
 	if (offset < 128)
 	{
 		sprintf(temp,
-			"Prc FromIP   FPrt ToIP     TPrt Masq Init-seq  Delta PDelta Expires (free=%d,%d)",
-			ip_masq_free_ports[0], ip_masq_free_ports[1]);
+			"Prc FromIP   FPrt ToIP     TPrt Masq Init-seq  Delta PDelta Expires (free=%d,%d,%d)",
+			atomic_read(ip_masq_free_ports), 
+			atomic_read(ip_masq_free_ports+1), 
+			atomic_read(ip_masq_free_ports+2));
 		len = sprintf(buffer, "%-127s\n", temp);
 	}
 	pos = 128;
-	save_flags(flags);
-	cli();
 
         for(idx = 0; idx < IP_MASQ_TAB_SIZE; idx++)
         for(ms = ip_masq_m_tab[idx]; ms ; ms = ms->m_link)
 	{
-		int timer_active;
 		pos += 128;
 		if (pos <= offset)
 			continue;
 
-		timer_active = del_timer(&ms->timer);
-		if (!timer_active)
-			ms->timer.expires = jiffies;
+		/*
+		 *	We have locked the tables, no need to del/add timers
+		 *	nor cli()  8)
+		 */
+
 		sprintf(temp,"%s %08lX:%04X %08lX:%04X %04X %08X %6d %6d %7lu",
 			masq_proto_name(ms->protocol),
 			ntohl(ms->saddr), ntohs(ms->sport),
@@ -983,15 +1731,75 @@
 			ms->out_seq.delta,
 			ms->out_seq.previous_delta,
 			ms->timer.expires-jiffies);
-		if (timer_active)
-			add_timer(&ms->timer);
 		len += sprintf(buffer+len, "%-127s\n", temp);
 
 		if(len >= length)
 			goto done;
         }
 done:
-	restore_flags(flags);
+
+	ip_masq_unlockz(&__ip_masq_lock, &masq_wait, 0);
+
+	begin = len - (pos - offset);
+	*start = buffer + begin;
+	len -= begin;
+	if(len>length)
+		len = length;
+	return len;
+}
+
+static int ip_masq_procinfo(char *buffer, char **start, off_t offset,
+			      int length, int unused)
+{
+	off_t pos=0, begin;
+	struct ip_masq *ms;
+	char temp[129];
+        int idx = 0;
+	int len=0;
+
+	ip_masq_lockz(&__ip_masq_lock, &masq_wait, 0);
+
+	if (offset < 128)
+	{
+		sprintf(temp,
+			"Prot SrcIP    SPrt DstIP    DPrt MAddr    MPrt State        Ref Ctl Expires (free=%d,%d,%d)",
+			atomic_read(ip_masq_free_ports), 
+			atomic_read(ip_masq_free_ports+1), 
+			atomic_read(ip_masq_free_ports+2));
+		len = sprintf(buffer, "%-127s\n", temp);
+	}
+	pos = 128;
+
+        for(idx = 0; idx < IP_MASQ_TAB_SIZE; idx++)
+        for(ms = ip_masq_m_tab[idx]; ms ; ms = ms->m_link)
+	{
+		pos += 128;
+		if (pos <= offset)
+			continue;
+
+		/*
+		 *	We have locked the tables, no need to del/add timers
+		 *	nor cli()  8)
+		 */
+
+		sprintf(temp,"%-4s %08lX:%04X %08lX:%04X %08lX:%04X %-12s %3d %3d %7lu",
+			masq_proto_name(ms->protocol),
+			ntohl(ms->saddr), ntohs(ms->sport),
+			ntohl(ms->daddr), ntohs(ms->dport),
+			ntohl(ms->maddr), ntohs(ms->mport),
+			masq_state_name(ms->state),
+			atomic_read(&ms->refcnt),
+			atomic_read(&ms->n_control),
+			(ms->timer.expires-jiffies)/HZ);
+		len += sprintf(buffer+len, "%-127s\n", temp);
+
+		if(len >= length)
+			goto done;
+        }
+done:
+
+	ip_masq_unlockz(&__ip_masq_lock, &masq_wait, 0);
+
 	begin = len - (pos - offset);
 	*start = buffer + begin;
 	len -= begin;
@@ -1000,21 +1808,51 @@
 	return len;
 }
 
-static struct proc_dir_entry proc_net_ipmsqhst = {
-	PROC_NET_IPMSQHST, 13, "ip_masquerade",
-	S_IFREG | S_IRUGO, 1, 0, 0,
-	0, &proc_net_inode_operations,
-	ip_msqhst_procinfo
-};
 #endif
 
 /*
+ *	Control from ip_sockglue
+ *	From userspace
+ */
+int ip_masq_ctl(int optname, void *arg, int arglen)
+{
+	struct ip_fw_masqctl *mctl = arg;
+	int ret = EINVAL;
+
+	ip_masq_lockz(&__ip_masq_lock, &masq_wait, 0);
+
+	if (1) /*  (mctl->mctl_action == IP_MASQ_MOD_CTL)  */
+		ret = ip_masq_mod_ctl(optname, mctl, arglen);
+
+	ip_masq_unlockz(&__ip_masq_lock, &masq_wait, 0);
+
+	return ret;
+}
+
+/*
  *	Initialize ip masquerading
  */
 __initfunc(int ip_masq_init(void))
 {
-#ifdef CONFIG_PROC_FS
-	proc_net_register(&proc_net_ipmsqhst);
+#ifdef CONFIG_PROC_FS        
+	proc_net_register(&(struct proc_dir_entry) {
+		PROC_NET_IPMSQHST, 13, "ip_masquerade",
+		S_IFREG | S_IRUGO, 1, 0, 0,
+		0, &proc_net_inode_operations,
+		ip_msqhst_procinfo
+	});
+	proc_net_register(&(struct proc_dir_entry) {
+		0, 7, "ip_masq",
+		S_IFREG | S_IRUGO, 1, 0, 0,
+		0, &proc_net_inode_operations,
+		ip_masq_procinfo
+	});
+#endif	
+#ifdef CONFIG_IP_MASQUERADE_IPAUTOFW
+	ip_autofw_init();
+#endif
+#ifdef CONFIG_IP_MASQUERADE_IPPORTFW
+	ip_portfw_init();
 #endif
         ip_masq_app_init();
 
diff -u --recursive --new-file v2.1.72/linux/net/ipv4/ip_masq_app.c linux/net/ipv4/ip_masq_app.c
--- v2.1.72/linux/net/ipv4/ip_masq_app.c	Mon Dec  1 12:04:16 1997
+++ linux/net/ipv4/ip_masq_app.c	Wed Dec 10 09:45:16 1997
@@ -39,13 +39,6 @@
 #include <linux/proc_fs.h>
 #include <net/ip_masq.h>
 
-static const char *strProt[] = {"UDP","TCP"};
-
-static __inline__ const char * masq_proto_name(unsigned proto)
-{
-        return strProt[proto==IPPROTO_TCP];
-}
-
 #define IP_MASQ_APP_TAB_SIZE  16 /* must be power of 2 */
 
 #define IP_MASQ_APP_HASH(proto, port) ((port^proto) & (IP_MASQ_APP_TAB_SIZE-1))
@@ -74,7 +67,7 @@
         unsigned long flags;
         unsigned hash;
         if (!mapp) {
-                printk(KERN_ERR "register_ip_masq_app(): NULL arg\n");
+                IP_MASQ_ERR("register_ip_masq_app(): NULL arg\n");
                 return -EINVAL;
         }
         mapp->type = IP_MASQ_APP_TYPE(proto, port);
@@ -100,14 +93,14 @@
         unsigned hash;
         unsigned long flags;
         if (!mapp) {
-                printk(KERN_ERR "unregister_ip_masq_app(): NULL arg\n");
+                IP_MASQ_ERR("unregister_ip_masq_app(): NULL arg\n");
                 return -EINVAL;
         }
         /*
          * only allow unregistration if it has no attachments
          */
         if (mapp->n_attach)  {
-                printk(KERN_ERR "unregister_ip_masq_app(): has %d attachments. failed\n",
+                IP_MASQ_ERR("unregister_ip_masq_app(): has %d attachments. failed\n",
                        mapp->n_attach);
                 return -EINVAL;
         }
@@ -123,7 +116,7 @@
                 }
 
         restore_flags(flags);
-        printk(KERN_ERR "unregister_ip_masq_app(proto=%s,port=%u): not hashed!\n",
+        IP_MASQ_ERR("unregister_ip_masq_app(proto=%s,port=%u): not hashed!\n",
                masq_proto_name(IP_MASQ_APP_PROTO(mapp->type)), IP_MASQ_APP_PORT(mapp->type));
         return -EINVAL;
 }
@@ -165,7 +158,7 @@
         n_at = mapp->n_attach + delta;
         if (n_at < 0) {
                 restore_flags(flags);
-                printk(KERN_ERR "ip_masq_app: tried to set n_attach < 0 for (proto=%s,port==%d) ip_masq_app object.\n",
+                IP_MASQ_ERR("ip_masq_app: tried to set n_attach < 0 for (proto=%s,port==%d) ip_masq_app object.\n",
                        masq_proto_name(IP_MASQ_APP_PROTO(mapp->type)),
                        IP_MASQ_APP_PORT(mapp->type));
                 return -1;
@@ -183,14 +176,26 @@
 struct ip_masq_app * ip_masq_bind_app(struct ip_masq *ms)
 {
         struct ip_masq_app * mapp;
+
+	if (ms->protocol != IPPROTO_TCP && ms->protocol != IPPROTO_UDP)
+		return NULL;
+
         mapp = ip_masq_app_get(ms->protocol, ms->dport);
+
+#if 0000
+/* #ifdef CONFIG_IP_MASQUERADE_IPAUTOFW */
+	if (mapp == NULL)
+		mapp = ip_masq_app_get(ms->protocol, ms->sport);
+/* #endif */
+#endif
+
         if (mapp != NULL) {
                 /*
                  *	don't allow binding if already bound
                  */
 
                 if (ms->app != NULL) {
-                        printk(KERN_ERR "ip_masq_bind_app() called for already bound object.\n");
+                        IP_MASQ_ERR("ip_masq_bind_app() called for already bound object.\n");
                         return ms->app;
                 }
 
@@ -209,6 +214,10 @@
 {
         struct ip_masq_app * mapp;
         mapp = ms->app;
+
+	if (ms->protocol != IPPROTO_TCP && ms->protocol != IPPROTO_UDP)
+		return 0;
+
         if (mapp != NULL) {
                 if (mapp->masq_done_1) mapp->masq_done_1(mapp, ms);
                 ms->app = NULL;
@@ -236,14 +245,10 @@
 	if (ms_seq->delta || ms_seq->previous_delta) {
 		if(after(seq,ms_seq->init_seq) ) {
 			th->seq = htonl(seq + ms_seq->delta);
-#if DEBUG_CONFIG_IP_MASQ_APP
-			printk("masq_fix_seq() : added delta (%d) to seq\n",ms_seq->delta);
-#endif
+			IP_MASQ_DEBUG(1, "masq_fix_seq() : added delta (%d) to seq\n",ms_seq->delta);
 		} else {
 			th->seq = htonl(seq + ms_seq->previous_delta);
-#if DEBUG_CONFIG_IP_MASQ_APP
-	 		printk("masq_fix_seq() : added previous_delta (%d) to seq\n",ms_seq->previous_delta);
-#endif
+			IP_MASQ_DEBUG(1, "masq_fix_seq() : added previous_delta (%d) to seq\n",ms_seq->previous_delta);
 		}
 	}
 
@@ -269,14 +274,11 @@
         if (ms_seq->delta || ms_seq->previous_delta) {
                 if(after(ack_seq,ms_seq->init_seq)) {
                         th->ack_seq = htonl(ack_seq-ms_seq->delta);
-#if DEBUG_CONFIG_IP_MASQ_APP
-                        printk("masq_fix_ack_seq() : subtracted delta (%d) from ack_seq\n",ms_seq->delta);
-#endif
+                        IP_MASQ_DEBUG(1, "masq_fix_ack_seq() : subtracted delta (%d) from ack_seq\n",ms_seq->delta);
+
                 } else {
                         th->ack_seq = htonl(ack_seq-ms_seq->previous_delta);
-#if DEBUG_CONFIG_IP_MASQ_APP
-                        printk("masq_fix_ack_seq() : subtracted previous_delta (%d) from ack_seq\n",ms_seq->previous_delta);
-#endif
+                        IP_MASQ_DEBUG(1, "masq_fix_ack_seq() : subtracted previous_delta (%d) from ack_seq\n",ms_seq->previous_delta);
                 }
         }
 
@@ -369,7 +371,7 @@
  *	returns (new - old) skb->len diff.
  */
 
-int ip_masq_app_pkt_in(struct ip_masq *ms, struct sk_buff **skb_p)
+int ip_masq_app_pkt_in(struct ip_masq *ms, struct sk_buff **skb_p, __u32 maddr)
 {
         struct ip_masq_app * mapp;
         struct iphdr *iph;
@@ -414,7 +416,7 @@
         if ( mapp->pkt_in == NULL )
                 return 0;
 
-        diff = mapp->pkt_in(mapp, ms, skb_p);
+        diff = mapp->pkt_in(mapp, ms, skb_p, maddr);
 
         /*
          *	Update ip_masq seq stuff if len has changed.
@@ -529,7 +531,7 @@
 
                 n_skb = alloc_skb(MAX_HEADER + skb->len + diff, pri);
                 if (n_skb == NULL) {
-                        printk(KERN_ERR "skb_replace(): no room left (from %p)\n",
+                        IP_MASQ_ERR("skb_replace(): no room left (from %p)\n",
                                __builtin_return_address(0));
                         return skb;
 
@@ -589,9 +591,7 @@
         if (diff)
         {
                 struct iphdr *iph;
-#if DEBUG_CONFIG_IP_MASQ_APP
-                printk("masq_skb_replace(): pkt resized for %d bytes (len=%ld)\n", diff, skb->len);
-#endif
+                IP_MASQ_DEBUG(1, "masq_skb_replace(): pkt resized for %d bytes (len=%d)\n", diff, skb->len);
                 /*
                  * 	update ip header
                  */
diff -u --recursive --new-file v2.1.72/linux/net/ipv4/ip_masq_autofw.c linux/net/ipv4/ip_masq_autofw.c
--- v2.1.72/linux/net/ipv4/ip_masq_autofw.c	Wed Dec 31 16:00:00 1969
+++ linux/net/ipv4/ip_masq_autofw.c	Wed Dec 10 09:45:16 1997
@@ -0,0 +1,427 @@
+/*
+ *		IP_MASQ_AUTOFW auto forwarding module
+ *
+ *
+ * Version:	@(#)ip_masq_autofw.c  0.02      97/10/22
+ *
+ * Author:	Richard Lynch
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License
+ *	as published by the Free Software Foundation; either version
+ *	2 of the License, or (at your option) any later version.
+ *
+ *
+ * Fixes:
+ *	Juan Jose Ciarlante	: created this new file from ip_masq.c and ip_fw.c
+ *	Juan Jose Ciarlante	: modularized 
+ *	Juan Jose Ciarlante	: use GFP_KERNEL when creating entries
+ *	Juan Jose Ciarlante	: call del_timer() when freeing entries (!)
+ *  FIXME:
+ *	- implement refcnt
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <asm/system.h>
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+#include <linux/if.h>
+#include <linux/init.h>
+#include <linux/ip_fw.h>
+#include <net/ip_masq.h>
+#include <net/ip_masq_mod.h>
+#include <net/ip_autofw.h>
+
+/*
+ *	Debug level
+ */
+static int debug=0;
+
+MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_MASQ_APP_PORTS) "i");
+MODULE_PARM(debug, "i");
+
+/*
+ *	Auto-forwarding table
+ */
+
+static struct ip_autofw * ip_autofw_hosts = NULL;
+static struct ip_masq_mod * mmod_self = NULL;
+
+/*
+ *	Check if a masq entry should be created for a packet
+ */
+
+static __inline__ struct ip_autofw * ip_autofw_check_range (__u32 where, __u16 port, __u16 protocol, int reqact)
+{
+	struct ip_autofw *af;
+	af=ip_autofw_hosts;
+	port=ntohs(port);
+	while (af) {
+		if (af->type==IP_FWD_RANGE && 
+		     port>=af->low && 
+		     port<=af->high && 
+		     protocol==af->protocol && 
+
+		     /*
+		      *		It's ok to create masq entries after 
+		      *		the timeout if we're in insecure mode 
+		      */
+		     (af->flags & IP_AUTOFW_ACTIVE || !reqact || !(af->flags & IP_AUTOFW_SECURE)) &&  
+		     (!(af->flags & IP_AUTOFW_SECURE) || af->lastcontact==where || !reqact))
+			return(af);
+		af=af->next;
+	}
+	return(NULL);
+}
+
+static __inline__ struct ip_autofw * ip_autofw_check_port (__u16 port, __u16 protocol)
+{
+	struct ip_autofw *af;
+	af=ip_autofw_hosts;
+	port=ntohs(port);
+	while (af)
+	{
+		if (af->type==IP_FWD_PORT && port==af->visible && protocol==af->protocol)
+			return(af);
+		af=af->next;
+	}
+	return(NULL);
+}
+
+static __inline__ struct ip_autofw * ip_autofw_check_direct (__u16 port, __u16 protocol)
+{
+	struct ip_autofw *af;
+	af=ip_autofw_hosts;
+	port=ntohs(port);
+	while (af)
+	{
+		if (af->type==IP_FWD_DIRECT && af->low<=port && af->high>=port)
+			return(af);
+		af=af->next;
+	}
+	return(NULL);
+}
+
+static __inline__ void ip_autofw_update_out (__u32 who, __u32 where, __u16 port, __u16 protocol)
+{
+	struct ip_autofw *af;
+	af=ip_autofw_hosts;
+	port=ntohs(port);
+	while (af)
+	{
+		if (af->type==IP_FWD_RANGE && af->ctlport==port && af->ctlproto==protocol)
+		{
+			if (af->flags & IP_AUTOFW_USETIME)
+			{
+				if (af->timer.expires)
+					del_timer(&af->timer);
+				af->timer.expires=jiffies+IP_AUTOFW_EXPIRE;
+				add_timer(&af->timer);
+			}
+			af->flags|=IP_AUTOFW_ACTIVE;
+			af->lastcontact=where;
+			af->where=who;
+		}
+		af=af->next;
+	}
+}
+
+#if 0
+static __inline__ void ip_autofw_update_in (__u32 where, __u16 port, __u16 protocol)
+{
+	struct ip_autofw *af;
+	af=ip_autofw_check_range(where, port,protocol);
+	if (af)
+	{
+		del_timer(&af->timer);
+		af->timer.expires=jiffies+IP_AUTOFW_EXPIRE;
+		add_timer(&af->timer);
+	}
+}
+#endif
+
+
+static __inline__ void ip_autofw_expire(unsigned long data)
+{
+	struct ip_autofw * af;
+	af=(struct ip_autofw *) data;
+	af->flags &= ~IP_AUTOFW_ACTIVE;
+	af->timer.expires=0;
+	af->lastcontact=0;
+	if (af->flags & IP_AUTOFW_SECURE)
+		af->where=0;
+}
+
+
+
+static __inline__ int ip_autofw_add(struct ip_autofw * af)
+{
+	struct ip_autofw * newaf;
+	init_timer(&af->timer);
+	newaf = kmalloc( sizeof(struct ip_autofw), GFP_KERNEL );
+	if ( newaf == NULL ) 
+	{
+		printk("ip_autofw_add:  malloc said no\n");
+		return( ENOMEM );
+	}
+
+	MOD_INC_USE_COUNT;
+
+	memcpy(newaf, af, sizeof(struct ip_autofw));
+	newaf->timer.data = (unsigned long) newaf;
+	newaf->timer.function = ip_autofw_expire;
+	newaf->timer.expires = 0;
+	newaf->lastcontact=0;
+	newaf->next=ip_autofw_hosts;
+	ip_autofw_hosts=newaf;
+	ip_masq_mod_inc_nent(mmod_self);
+	return(0);
+}
+
+static __inline__ int ip_autofw_del(struct ip_autofw * af)
+{
+	struct ip_autofw ** af_p, *curr;
+
+	for (af_p=&ip_autofw_hosts, curr=*af_p; (curr=*af_p); af_p = &(*af_p)->next) {
+		if (af->type     == curr->type &&
+		    af->low      == curr->low &&
+		    af->high     == curr->high &&
+		    af->hidden   == curr->hidden &&
+		    af->visible  == curr->visible &&
+		    af->protocol == curr->protocol &&
+		    af->where    == curr->where &&
+		    af->ctlproto == curr->ctlproto &&
+		    af->ctlport  == curr->ctlport)
+		{
+			ip_masq_mod_dec_nent(mmod_self);
+			*af_p = curr->next;
+			if (af->flags&IP_AUTOFW_ACTIVE)
+				del_timer(&curr->timer);
+			kfree_s(curr,sizeof(struct ip_autofw));
+			MOD_DEC_USE_COUNT;
+			return 0;
+		}
+		curr=curr->next;
+	}
+	return EINVAL;
+}
+
+static __inline__ int ip_autofw_flush(void)
+{
+	struct ip_autofw * af;
+
+	while (ip_autofw_hosts)
+	{
+		af=ip_autofw_hosts;
+		ip_masq_mod_dec_nent(mmod_self);
+		ip_autofw_hosts=ip_autofw_hosts->next;
+		if (af->flags&IP_AUTOFW_ACTIVE)
+			del_timer(&af->timer);
+		kfree_s(af,sizeof(struct ip_autofw));
+		MOD_DEC_USE_COUNT;
+	}
+	return(0);
+}
+
+/*
+ *	Methods for registered object
+ */
+
+static int autofw_ctl(int optname, struct ip_fw_masqctl *mctl, int optlen)
+{
+	struct ip_autofw *af = (struct ip_autofw*) mctl->u.mod.data;
+
+	switch (optname) {
+		case IP_FW_MASQ_ADD:
+			if (optlen<sizeof(*af))
+				return EINVAL;
+			return ip_autofw_add(af);
+		case IP_FW_MASQ_DEL:
+			if (optlen<sizeof(*af))
+				return EINVAL;
+			return ip_autofw_del(af);
+		case IP_FW_MASQ_FLUSH:
+			return ip_autofw_flush();
+
+	}
+	return EINVAL;
+}
+
+
+static int autofw_out_update(struct iphdr *iph, __u16 *portp, struct ip_masq *ms)
+{
+	/* 
+	 *	Update any ipautofw entries ...
+	 */
+
+	ip_autofw_update_out(iph->saddr, iph->daddr, portp[1], iph->protocol);
+	return IP_MASQ_MOD_NOP;
+}
+
+static struct ip_masq * autofw_out_create(struct iphdr *iph, __u16 * portp, __u32 maddr)
+{
+	/*
+	 *	If the source port is supposed to match the masq port, then
+	 *  	make it so 
+	 */
+
+	if (ip_autofw_check_direct(portp[1],iph->protocol)) {
+		return ip_masq_new(iph->protocol,
+					maddr, portp[0],
+					iph->saddr, portp[0],
+					iph->daddr, portp[1],
+					0);
+	}
+	return NULL;
+}
+
+#if 0
+static int autofw_in_update(struct iphdr *iph, __u16 *portp, struct ip_masq *ms)
+{
+	ip_autofw_update_in(iph->saddr, portp[1], iph->protocol);
+	return IP_MASQ_MOD_NOP;
+}
+#endif
+
+static int autofw_in_rule(struct iphdr *iph, __u16 *portp)
+{
+	return (ip_autofw_check_range(iph->saddr, portp[1], iph->protocol, 0)
+		|| ip_autofw_check_direct(portp[1], iph->protocol)
+		|| ip_autofw_check_port(portp[1], iph->protocol));
+}
+
+static struct ip_masq * autofw_in_create(struct iphdr *iph, __u16 *portp, __u32 maddr)
+{
+	struct ip_autofw *af;
+
+        if ((af=ip_autofw_check_range(iph->saddr, portp[1], iph->protocol, 0))) {
+		IP_MASQ_DEBUG(1-debug, "autofw_check_range HIT\n");
+		return ip_masq_new(iph->protocol,
+					maddr, portp[1],
+					af->where, portp[1],
+					iph->saddr, portp[0],
+					0);
+        } 
+        if ((af=ip_autofw_check_port(portp[1], iph->protocol)) ) {
+		IP_MASQ_DEBUG(1-debug, "autofw_check_port HIT\n");
+		return ip_masq_new(iph->protocol,
+					maddr, htons(af->visible),
+					af->where, htons(af->hidden),
+					iph->saddr, portp[0],
+					0);
+        }
+	return NULL;
+}
+
+#ifdef CONFIG_PROC_FS
+static int autofw_procinfo(char *buffer, char **start, off_t offset,
+			      int length, int unused)
+{
+	off_t pos=0, begin=0;
+	struct ip_autofw * af;
+	int len=0;
+	
+	len=sprintf(buffer,"Type Prot Low  High Vis  Hid  Where    Last     CPto CPrt Timer Flags\n"); 
+        
+        for(af = ip_autofw_hosts; af ; af = af->next)
+	{
+		len+=sprintf(buffer+len,"%4X %4X %04X-%04X/%04X %04X %08lX %08lX %04X %04X %6lu %4X\n",
+					af->type,
+					af->protocol,
+					af->low,
+					af->high,
+					af->visible,
+					af->hidden,
+					ntohl(af->where),
+					ntohl(af->lastcontact),
+					af->ctlproto,
+					af->ctlport,
+					(af->timer.expires<jiffies ? 0 : af->timer.expires-jiffies), 
+					af->flags);
+
+		pos=begin+len;
+		if(pos<offset) 
+		{
+ 			len=0;
+			begin=pos;
+		}
+		if(pos>offset+length)
+			break;
+        }
+	*start=buffer+(offset-begin);
+	len-=(offset-begin);
+	if(len>length)
+		len=length;
+	return len;
+}
+
+static struct proc_dir_entry autofw_proc_entry = {
+		0, 0, NULL,
+		S_IFREG | S_IRUGO, 1, 0, 0,
+		0, &proc_net_inode_operations,
+		autofw_procinfo
+};
+
+#define proc_ent &autofw_proc_entry
+#else /* !CONFIG_PROC_FS */
+
+#define proc_ent NULL
+#endif
+
+
+#define	autofw_in_update NULL
+#define autofw_out_rule NULL
+#define autofw_mod_init NULL
+#define autofw_mod_done NULL
+
+static struct ip_masq_mod autofw_mod = {
+	NULL,			/* next */
+	NULL,			/* next_reg */
+	"autofw",		/* name */
+	ATOMIC_INIT(0),		/* nent */
+	ATOMIC_INIT(0),		/* refcnt */
+	proc_ent,
+	autofw_ctl,
+	autofw_mod_init,
+	autofw_mod_done,
+	autofw_in_rule,
+	autofw_in_update,
+	autofw_in_create,
+	autofw_out_rule,
+	autofw_out_update,
+	autofw_out_create,
+};
+
+__initfunc(int ip_autofw_init(void))
+{
+	return register_ip_masq_mod ((mmod_self=&autofw_mod));
+}
+
+int ip_autofw_done(void)
+{
+	return unregister_ip_masq_mod(&autofw_mod);
+}
+
+#ifdef MODULE
+EXPORT_NO_SYMBOLS;
+
+int init_module(void)
+{
+	if (ip_autofw_init() != 0)
+		return -EIO;
+	return 0;
+}
+
+void cleanup_module(void)
+{
+	if (ip_autofw_done() != 0)
+		printk(KERN_INFO "ip_autofw_done(): can't remove module");
+}
+
+#endif /* MODULE */
diff -u --recursive --new-file v2.1.72/linux/net/ipv4/ip_masq_cuseeme.c linux/net/ipv4/ip_masq_cuseeme.c
--- v2.1.72/linux/net/ipv4/ip_masq_cuseeme.c	Wed Dec 31 16:00:00 1969
+++ linux/net/ipv4/ip_masq_cuseeme.c	Wed Dec 10 09:45:16 1997
@@ -0,0 +1,261 @@
+/*
+ *		IP_MASQ_FTP CUSeeMe masquerading module
+ *
+ *
+ * Version:	@(#)$Id: ip_masq_cuseeme.c,v 1.2 1997/11/28 15:32:18 alan Exp $
+ *
+ * Author:	Richard Lynch
+ *		
+ *
+ * Fixes:
+ *	Richard Lynch     	:	Updated patch to conform to new module
+ *					specifications
+ *	Nigel Metheringham	:	Multiple port support
+ *	Michael Owings		:	Fixed broken init code
+ *					Added code to update inbound
+ *					packets with correct local addresses.
+ *					Fixes audio and "chat" problems
+ *					Thanx to the CU-SeeMe Consortium for
+ *					technical docs
+ *	Steven Clarke		:	Small changes for 2.1	
+ *
+ *
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License
+ *	as published by the Free Software Foundation; either version
+ *	2 of the License, or (at your option) any later version.
+ *	
+ * Multiple Port Support
+ *	The helper can be made to handle up to MAX_MASQ_APP_PORTS (normally 12)
+ *	with the port numbers being defined at module load time.  The module
+ *	uses the symbol "ports" to define a list of monitored ports, which can
+ *	be specified on the insmod command line as
+ *		ports=x1,x2,x3...
+ *	where x[n] are integer port numbers.  This option can be put into
+ *	/etc/conf.modules (or /etc/modules.conf depending on your config)
+ *	where modload will pick it up should you use modload to load your
+ *	modules.
+ *	
+ */
+
+#include <linux/module.h>
+#include <asm/system.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/skbuff.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/init.h>
+#include <net/protocol.h>
+#include <net/udp.h>
+
+/* #define IP_MASQ_NDEBUG */
+#include <net/ip_masq.h>
+
+#pragma pack(1)
+/* CU-SeeMe Data Header */
+typedef struct {
+	u_short 	dest_family;
+	u_short 	dest_port;
+	u_long  	dest_addr;
+	short 		family;
+	u_short 	port;
+	u_long 		addr;
+	u_long 		seq;
+	u_short 	msg;
+	u_short		data_type;
+	u_short		packet_len;
+} cu_header;
+
+/* Open Continue Header */
+typedef struct	{
+	cu_header	cu_head;
+	u_short 	client_count; /* Number of client info structs */
+	u_long		seq_no;
+	char		user_name[20];
+	char		stuff[4]; /* flags,  version stuff,  etc */
+}oc_header;
+
+/* client info structures */
+typedef struct {
+	u_long		address; /* Client address */
+	char	       	stuff[8]; /* Flags, pruning bitfield,  packet counts etc */
+} client_info;
+#pragma pack()
+
+/*
+ * List of ports (up to MAX_MASQ_APP_PORTS) to be handled by helper
+ * First port is set to the default port.
+ */
+static int ports[MAX_MASQ_APP_PORTS] = {7648}; /* I rely on the trailing items being set to zero */
+struct ip_masq_app *masq_incarnations[MAX_MASQ_APP_PORTS];
+
+/*
+ *     Debug level
+ */
+static int debug=0;
+
+MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_MASQ_APP_PORTS) "i");
+MODULE_PARM(debug, "i");
+
+static int
+masq_cuseeme_init_1 (struct ip_masq_app *mapp, struct ip_masq *ms)
+{
+        MOD_INC_USE_COUNT;
+        return 0;
+}
+
+static int
+masq_cuseeme_done_1 (struct ip_masq_app *mapp, struct ip_masq *ms)
+{
+        MOD_DEC_USE_COUNT;
+        return 0;
+}
+
+int
+masq_cuseeme_out (struct ip_masq_app *mapp, struct ip_masq *ms, struct sk_buff **skb_p, __u32 maddr)
+{
+	struct sk_buff *skb = *skb_p;
+	struct iphdr *iph = skb->nh.iph;
+	struct udphdr *uh = (struct udphdr *)&(((char *)iph)[iph->ihl*4]);
+	cu_header *cu_head;
+	char *data=(char *)&uh[1];
+
+	if (skb->len - ((unsigned char *) data - skb->h.raw) >= sizeof(cu_header))
+	{
+		cu_head         = (cu_header *) data;
+		/* cu_head->port   = ms->mport; */
+	        if( cu_head->addr )
+		cu_head->addr = (u_long) maddr;
+	        if(ntohs(cu_head->data_type) == 257)
+		        IP_MASQ_DEBUG(1-debug, "Sending talk packet!\n");
+	}
+	return 0;
+}
+
+int
+masq_cuseeme_in (struct ip_masq_app *mapp, struct ip_masq *ms, struct sk_buff **skb_p, __u32 maddr)
+{
+	struct sk_buff *skb = *skb_p;
+	struct iphdr *iph = skb->nh.iph;
+	struct udphdr *uh = (struct udphdr *)&(((char *)iph)[iph->ihl*4]);
+	cu_header *cu_head;
+	oc_header	*oc;
+	client_info	*ci;
+	char *data=(char *)&uh[1];
+	u_short len = skb->len - ((unsigned char *) data - skb->h.raw);
+	int		i, off;
+
+	if (len >= sizeof(cu_header))
+	{
+		cu_head         = (cu_header *) data;
+		if(cu_head->dest_addr) /* Correct destination address */
+			cu_head->dest_addr = (u_long) ms->saddr;
+		if(ntohs(cu_head->data_type)==101 && len > sizeof(oc_header))
+		{
+			oc = (oc_header * ) data;
+			/* Spin (grovel) thru client_info structs till we find our own */
+		        off=sizeof(oc_header);
+			for(i=0;
+			    (i < oc->client_count && off+sizeof(client_info) <= len);
+			    i++)		    
+			{
+			        ci=(client_info *)(data+off);
+				if(ci->address==(u_long) maddr)
+				{
+				        /* Update w/ our real ip address and exit */
+					ci->address = (u_long) ms->saddr;
+					break;
+				}
+			        else
+				   off+=sizeof(client_info);
+			}
+		}
+	}
+	return 0;
+}
+
+struct ip_masq_app ip_masq_cuseeme = {
+        NULL,			/* next */
+        "cuseeme",
+        0,                      /* type */
+        0,                      /* n_attach */
+        masq_cuseeme_init_1,	/* ip_masq_init_1 */
+        masq_cuseeme_done_1,	/* ip_masq_done_1 */
+        masq_cuseeme_out,	/* pkt_out */
+        masq_cuseeme_in    	/* pkt_in */
+};
+
+
+/*
+ * 	ip_masq_cuseeme initialization
+ */
+
+__initfunc(int ip_masq_cuseeme_init(void))
+{
+	int i, j;
+
+	for (i=0; (i<MAX_MASQ_APP_PORTS); i++) {
+		if (ports[i]) {
+			if ((masq_incarnations[i] = kmalloc(sizeof(struct ip_masq_app),
+							    GFP_KERNEL)) == NULL)
+				return -ENOMEM;
+			memcpy(masq_incarnations[i], &ip_masq_cuseeme, sizeof(struct ip_masq_app));
+			if ((j = register_ip_masq_app(masq_incarnations[i], 
+						      IPPROTO_UDP,
+						      ports[i]))) {
+				return j;
+			}
+#if DEBUG_CONFIG_IP_MASQ_CUSEEME
+			IP_MASQ_DEBUG(1-debug, "CuSeeMe: loaded support on port[%d] = %d\n",
+			       i, ports[i]);
+#endif
+		} else {
+			/* To be safe, force the incarnation table entry to NULL */
+			masq_incarnations[i] = NULL;
+		}
+	}
+	return 0;
+}
+
+/*
+ * 	ip_masq_cuseeme fin.
+ */
+
+int ip_masq_cuseeme_done(void)
+{
+	int i, j, k;
+
+	k=0;
+	for (i=0; (i<MAX_MASQ_APP_PORTS); i++) {
+		if (masq_incarnations[i]) {
+			if ((j = unregister_ip_masq_app(masq_incarnations[i]))) {
+				k = j;
+			} else {
+				kfree(masq_incarnations[i]);
+				masq_incarnations[i] = NULL;
+				IP_MASQ_DEBUG(1-debug, "CuSeeMe: unloaded support on port[%d] = %d\n", i, ports[i]);
+			}
+		}
+	}
+	return k;
+}
+
+#ifdef MODULE
+EXPORT_NO_SYMBOLS;
+
+int init_module(void)
+{
+        if (ip_masq_cuseeme_init() != 0)
+                return -EIO;
+        return 0;
+}
+
+void cleanup_module(void)
+{
+        if (ip_masq_cuseeme_done() != 0)
+                IP_MASQ_DEBUG(1-debug, "ip_masq_cuseeme: can't remove module");
+}
+
+#endif /* MODULE */
diff -u --recursive --new-file v2.1.72/linux/net/ipv4/ip_masq_ftp.c linux/net/ipv4/ip_masq_ftp.c
--- v2.1.72/linux/net/ipv4/ip_masq_ftp.c	Mon Dec  1 12:04:16 1997
+++ linux/net/ipv4/ip_masq_ftp.c	Wed Dec 10 09:45:16 1997
@@ -2,14 +2,20 @@
  *		IP_MASQ_FTP ftp masquerading module
  *
  *
- * Version:	@(#)ip_masq_ftp.c 0.01   02/05/96
+ * Version:	@(#)ip_masq_ftp.c 0.04   02/05/96
  *
  * Author:	Wouter Gadeyne
- *
+ *		
  *
  * Fixes:
  *	Wouter Gadeyne		:	Fixed masquerading support of ftp PORT commands
  * 	Juan Jose Ciarlante	:	Code moved and adapted from ip_fw.c
+ * 	Keith Owens		:	Add keep alive for ftp control channel
+ *	Nigel Metheringham	:	Added multiple port support
+ * 	Juan Jose Ciarlante	:	Use control_add() for ftp control chan
+ * 	Juan Jose Ciarlante	:	Litl bits for 2.1
+ *	Juan Jose Ciarlante	:	use ip_masq_listen() 
+ *	Juan Jose Ciarlante	: 	use private app_data for own flag(s)
  *
  *
  *
@@ -17,7 +23,18 @@
  *	modify it under the terms of the GNU General Public License
  *	as published by the Free Software Foundation; either version
  *	2 of the License, or (at your option) any later version.
- *
+ *	
+ * Multiple Port Support
+ *	The helper can be made to handle up to MAX_MASQ_APP_PORTS (normally 12)
+ *	with the port numbers being defined at module load time.  The module
+ *	uses the symbol "ports" to define a list of monitored ports, which can
+ *	be specified on the insmod command line as
+ *		ports=x1,x2,x3...
+ *	where x[n] are integer port numbers.  This option can be put into
+ *	/etc/conf.modules (or /etc/modules.conf depending on your config)
+ *	where modload will pick it up should you use modload to load your
+ *	modules.
+ *	
  */
 
 #include <linux/config.h>
@@ -31,9 +48,28 @@
 #include <linux/init.h>
 #include <net/protocol.h>
 #include <net/tcp.h>
+
+/* #define IP_MASQ_NDEBUG */
 #include <net/ip_masq.h>
 
-#define DEBUG_CONFIG_IP_MASQ_FTP 0
+
+/* 
+ * List of ports (up to MAX_MASQ_APP_PORTS) to be handled by helper
+ * First port is set to the default port.
+ */
+static int ports[MAX_MASQ_APP_PORTS] = {21}; /* I rely on the trailing items being set to zero */
+struct ip_masq_app *masq_incarnations[MAX_MASQ_APP_PORTS];
+
+/*
+ *	Debug level
+ */
+static int debug=0;
+
+MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_MASQ_APP_PORTS) "i");
+MODULE_PARM(debug, "i");
+
+/*	Dummy variable */
+static int masq_ftp_pasv;
 
 static int
 masq_ftp_init_1 (struct ip_masq_app *mapp, struct ip_masq *ms)
@@ -70,6 +106,8 @@
         data = (char *)&th[1];
 
         data_limit = skb->h.raw + skb->len - 18;
+        if (skb->len >= 6 && (memcmp(data, "PASV\r\n", 6) == 0 || memcmp(data, "pasv\r\n", 6) == 0))
+		ms->app_data = &masq_ftp_pasv;
 
 	while (data < data_limit)
 	{
@@ -100,39 +138,30 @@
 
 		from = (p1<<24) | (p2<<16) | (p3<<8) | p4;
 		port = (p5<<8) | p6;
-#if DEBUG_CONFIG_IP_MASQ_FTP
-		printk("PORT %X:%X detected\n",from,port);
-#endif
+
+		IP_MASQ_DEBUG(1-debug, "PORT %X:%X detected\n",from,port);
+
 		/*
 		 * Now update or create an masquerade entry for it
 		 */
-#if DEBUG_CONFIG_IP_MASQ_FTP
-		printk("protocol %d %lX:%X %X:%X\n", iph->protocol, htonl(from), htons(port), iph->daddr, 0);
 
-#endif
-		n_ms = ip_masq_out_get_2(iph->protocol,
+		IP_MASQ_DEBUG(1-debug, "protocol %d %lX:%X %X:%X\n", iph->protocol, htonl(from), htons(port), iph->daddr, 0);
+
+		n_ms = ip_masq_out_get(iph->protocol,
 					 htonl(from), htons(port),
 					 iph->daddr, 0);
-		if (n_ms) {
-			/* existing masquerade, clear timer */
-			ip_masq_set_expire(n_ms,0);
-		}
-		else {
-			n_ms = ip_masq_new(maddr, IPPROTO_TCP,
+		if (!n_ms) {
+			n_ms = ip_masq_new(IPPROTO_TCP,
+					   maddr, 0,
 					   htonl(from), htons(port),
 					   iph->daddr, 0,
 					   IP_MASQ_F_NO_DPORT);
 
 			if (n_ms==NULL)
 				return 0;
+			ip_masq_control_add(n_ms, ms);
 		}
 
-                /*
-                 * keep for a bit longer than tcp_fin, caller may not reissue
-                 * PORT before tcp_fin_timeout.
-                 */
-                ip_masq_set_expire(n_ms, ip_masq_expire->tcp_fin_timeout*3);
-
 		/*
 		 * Replace the old PORT with the new one
 		 */
@@ -142,30 +171,34 @@
 			from>>24&255,from>>16&255,from>>8&255,from&255,
 			port>>8&255,port&255);
 		buf_len = strlen(buf);
-#if DEBUG_CONFIG_IP_MASQ_FTP
-		printk("new PORT %X:%X\n",from,port);
-#endif
+
+		IP_MASQ_DEBUG(1-debug, "new PORT %X:%X\n",from,port);
 
 		/*
 		 * Calculate required delta-offset to keep TCP happy
 		 */
-
+		
 		diff = buf_len - (data-p);
-
+		
 		/*
 		 *	No shift.
 		 */
-
-		if (diff==0)
-		{
+		
+		if (diff==0) {
 			/*
 			 * simple case, just replace the old PORT cmd
  			 */
  			memcpy(p,buf,buf_len);
- 			return 0;
- 		}
+ 		} else {
+
+			*skb_p = ip_masq_skb_replace(skb, GFP_ATOMIC, p, data-p, buf, buf_len);
+		}
+                /*
+                 * 	Move tunnel to listen state
+                 */
+		ip_masq_listen(n_ms);
+		ip_masq_put(n_ms);
 
-                *skb_p = ip_masq_skb_replace(skb, GFP_ATOMIC, p, data-p, buf, buf_len);
                 return diff;
 
 	}
@@ -173,6 +206,108 @@
 
 }
 
+/*
+ * Look at incoming ftp packets to catch the response to a PASV command.  When
+ * we see one we build a masquerading entry for the client address, client port
+ * 0 (unknown at the moment), the server address and the server port.  Mark the
+ * current masquerade entry as a control channel and point the new entry at the
+ * control entry.  All this work just for ftp keepalive across masquerading.
+ *
+ * The incoming packet should be something like
+ * "227 Entering Passive Mode (xxx,xxx,xxx,xxx,ppp,ppp)".
+ * xxx,xxx,xxx,xxx is the server address, ppp,ppp is the server port number.
+ * ncftp 2.3.0 cheats by skipping the leading number then going 22 bytes into
+ * the data so we do the same.  If it's good enough for ncftp then it's good
+ * enough for me.
+ *
+ * In this case, the client is the source machine being masqueraded, the server
+ * is the destination for ftp requests.  It all depends on your point of view ...
+ */
+
+int
+masq_ftp_in (struct ip_masq_app *mapp, struct ip_masq *ms, struct sk_buff **skb_p, __u32 maddr)
+{
+	struct sk_buff *skb;
+	struct iphdr *iph;
+	struct tcphdr *th;
+	char *data, *data_limit;
+	unsigned char p1,p2,p3,p4,p5,p6;
+	__u32 to;
+	__u16 port;
+	struct ip_masq *n_ms;
+
+	if (ms->app_data != &masq_ftp_pasv)
+		return 0;	/* quick exit if no outstanding PASV */
+
+	skb = *skb_p;
+	iph = skb->nh.iph;
+	th = (struct tcphdr *)&(((char *)iph)[iph->ihl*4]);
+	data = (char *)&th[1];
+	data_limit = skb->h.raw + skb->len;
+
+	while (data < data_limit && *data != ' ')
+		++data;	
+	while (data < data_limit && *data == ' ')
+		++data;	
+	data += 22;
+	if (data >= data_limit || *data != '(')
+		return 0;
+	p1 = simple_strtoul(data+1, &data, 10);
+	if (data >= data_limit || *data != ',')
+		return 0;
+	p2 = simple_strtoul(data+1, &data, 10);
+	if (data >= data_limit || *data != ',')
+		return 0;
+	p3 = simple_strtoul(data+1, &data, 10);
+	if (data >= data_limit || *data != ',')
+		return 0;
+	p4 = simple_strtoul(data+1, &data, 10);
+	if (data >= data_limit || *data != ',')
+		return 0;
+	p5 = simple_strtoul(data+1, &data, 10);
+	if (data >= data_limit || *data != ',')
+		return 0;
+	p6 = simple_strtoul(data+1, &data, 10);
+	if (data >= data_limit || *data != ')')
+		return 0;
+
+	to = (p1<<24) | (p2<<16) | (p3<<8) | p4;
+	port = (p5<<8) | p6;
+
+	/*
+	 * Now update or create an masquerade entry for it
+	 */
+	IP_MASQ_DEBUG(1-debug, "PASV response %lX:%X %X:%X detected\n", ntohl(ms->saddr), 0, to, port);
+
+	n_ms = ip_masq_out_get(iph->protocol,
+				 ms->saddr, 0,
+				 htonl(to), htons(port));
+	if (!n_ms) {
+		n_ms = ip_masq_new(IPPROTO_TCP,
+					maddr, 0,
+					ms->saddr, 0,
+					htonl(to), htons(port),
+					IP_MASQ_F_NO_SPORT);
+
+		if (n_ms==NULL)
+			return 0;
+		ip_masq_control_add(n_ms, ms);
+	}
+
+#if 0	/* v0.12 state processing */
+
+	/*
+	 * keep for a bit longer than tcp_fin, client may not issue open
+	 * to server port before tcp_fin_timeout.
+	 */
+	n_ms->timeout = ip_masq_expire->tcp_fin_timeout*3;
+#endif
+	ms->app_data = NULL;
+	ip_masq_put(n_ms);
+
+	return 0;	/* no diff required for incoming packets, thank goodness */
+}
+
 struct ip_masq_app ip_masq_ftp = {
         NULL,			/* next */
 	"ftp",			/* name */
@@ -181,7 +316,7 @@
         masq_ftp_init_1,        /* ip_masq_init_1 */
         masq_ftp_done_1,        /* ip_masq_done_1 */
         masq_ftp_out,           /* pkt_out */
-        NULL                    /* pkt_in */
+        masq_ftp_in,            /* pkt_in */
 };
 
 /*
@@ -190,7 +325,27 @@
 
 __initfunc(int ip_masq_ftp_init(void))
 {
-        return register_ip_masq_app(&ip_masq_ftp, IPPROTO_TCP, 21);
+	int i, j;
+
+	for (i=0; (i<MAX_MASQ_APP_PORTS); i++) {
+		if (ports[i]) {
+			if ((masq_incarnations[i] = kmalloc(sizeof(struct ip_masq_app),
+							    GFP_KERNEL)) == NULL)
+				return -ENOMEM;
+			memcpy(masq_incarnations[i], &ip_masq_ftp, sizeof(struct ip_masq_app));
+			if ((j = register_ip_masq_app(masq_incarnations[i], 
+						      IPPROTO_TCP, 
+						      ports[i]))) {
+				return j;
+			}
+			IP_MASQ_DEBUG(1-debug, "Ftp: loaded support on port[%d] = %d\n",
+			       i, ports[i]);
+		} else {
+			/* To be safe, force the incarnation table entry to NULL */
+			masq_incarnations[i] = NULL;
+		}
+	}
+	return 0;
 }
 
 /*
@@ -199,7 +354,22 @@
 
 int ip_masq_ftp_done(void)
 {
-        return unregister_ip_masq_app(&ip_masq_ftp);
+	int i, j, k;
+
+	k=0;
+	for (i=0; (i<MAX_MASQ_APP_PORTS); i++) {
+		if (masq_incarnations[i]) {
+			if ((j = unregister_ip_masq_app(masq_incarnations[i]))) {
+				k = j;
+			} else {
+				kfree(masq_incarnations[i]);
+				masq_incarnations[i] = NULL;
+				IP_MASQ_DEBUG(1-debug, "Ftp: unloaded support on port[%d] = %d\n",
+				       i, ports[i]);
+			}
+		}
+	}
+	return k;
 }
 
 #ifdef MODULE
diff -u --recursive --new-file v2.1.72/linux/net/ipv4/ip_masq_irc.c linux/net/ipv4/ip_masq_irc.c
--- v2.1.72/linux/net/ipv4/ip_masq_irc.c	Mon Dec  1 12:04:16 1997
+++ linux/net/ipv4/ip_masq_irc.c	Wed Dec 10 09:45:16 1997
@@ -2,13 +2,22 @@
  *		IP_MASQ_IRC irc masquerading module
  *
  *
- * Version:	@(#)ip_masq_irc.c 0.01   03/20/96
+ * Version:	@(#)ip_masq_irc.c 0.03   97/11/30
  *
  * Author:	Juan Jose Ciarlante
- *
- *
+ *		
+ * Additions:
+ *  - recognize a few non-irc-II DCC requests (Oliver Wagner)
+ *     DCC MOVE (AmIRC/DCC.MOVE; SEND with resuming)
+ *     DCC SCHAT (AmIRC IDEA encrypted CHAT)
+ *     DCC TSEND (AmIRC/PIRCH SEND without ACKs)
  * Fixes:
- *	- set NO_DADDR flag in ip_masq_new().
+ *	Juan Jose Ciarlante	:  set NO_DADDR flag in ip_masq_new()
+ *	Nigel Metheringham	:  Added multiple port support 
+ *	Juan Jose Ciarlante	:  litl bits for 2.1
+ *	Oliver Wagner 		:  more IRC cmds processing
+ *	  <winmute@lucifer.gv.kotnet.org>
+ *	Juan Jose Ciarlante	:  put new ms entry to listen()
  *
  * FIXME:
  *	- detect also previous "PRIVMSG" string ?.
@@ -17,7 +26,18 @@
  *	modify it under the terms of the GNU General Public License
  *	as published by the Free Software Foundation; either version
  *	2 of the License, or (at your option) any later version.
- *
+ *	
+ * Multiple Port Support
+ *	The helper can be made to handle up to MAX_MASQ_APP_PORTS (normally 12)
+ *	with the port numbers being defined at module load time.  The module
+ *	uses the symbol "ports" to define a list of monitored ports, which can
+ *	be specified on the insmod command line as
+ *		ports=x1,x2,x3...
+ *	where x[n] are integer port numbers.  This option can be put into
+ *	/etc/conf.modules (or /etc/modules.conf depending on your config)
+ *	where modload will pick it up should you use modload to load your
+ *	modules.
+ *	
  */
 
 #include <linux/config.h>
@@ -34,7 +54,43 @@
 #include <net/tcp.h>
 #include <net/ip_masq.h>
 
-#define DEBUG_CONFIG_IP_MASQ_IRC 0
+
+/* 
+ * List of ports (up to MAX_MASQ_APP_PORTS) to be handled by helper
+ * First port is set to the default port.
+ */
+int ports[MAX_MASQ_APP_PORTS] = {6667}; /* I rely on the trailing items being set to zero */
+struct ip_masq_app *masq_incarnations[MAX_MASQ_APP_PORTS];
+/*
+ *	Debug level
+ */
+static int debug=0;
+
+MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_MASQ_APP_PORTS) "i");
+MODULE_PARM(debug, "i");
+
+
+/*
+ * List of supported DCC protocols
+ */
+
+#define NUM_DCCPROTO 5
+
+struct dccproto 
+{
+  char *match;
+  int matchlen;
+  int xtra_args;
+};
+
+struct dccproto dccprotos[NUM_DCCPROTO] = {
+ { "SEND ", 5, 1 },
+ { "CHAT ", 5, 0, },
+ { "MOVE ", 5, 1 },
+ { "TSEND ", 6, 1, },
+ { "SCHAT ", 6, 0, }
+};
+#define MAXMATCHLEN 6
 
 static int
 masq_irc_init_1 (struct ip_masq_app *mapp, struct ip_masq *ms)
@@ -72,145 +128,148 @@
         data = (char *)&th[1];
 
         /*
-         *	Hunt irc DCC string, the _shortest_:
-         *
-         *	strlen("DCC CHAT chat AAAAAAAA P\x01\n")=26
-         *	strlen("DCC SEND F AAAAAAAA P S\x01\n")=25
-         *		AAAAAAAAA: bound addr (1.0.0.0==16777216, min 8 digits)
-         *		P:         bound port (min 1 d )
-         *		F:         filename   (min 1 d )
-         *		S:         size       (min 1 d )
-         *		0x01, \n:  terminators
+	 *	Hunt irc DCC string, the _shortest_:
+	 *
+	 *	strlen("DCC CHAT chat AAAAAAAA P\x01\n")=26
+	 *	strlen("DCC SCHAT chat AAAAAAAA P\x01\n")=27
+	 *	strlen("DCC SEND F AAAAAAAA P S\x01\n")=25
+	 *	strlen("DCC MOVE F AAAAAAAA P S\x01\n")=25
+	 *	strlen("DCC TSEND F AAAAAAAA P S\x01\n")=26
+	 *	strlen("DCC MOVE F AAAAAAAA P S\x01\n")=25
+	 *		AAAAAAAAA: bound addr (1.0.0.0==16777216, min 8 digits)
+	 *		P:         bound port (min 1 d )
+	 *		F:         filename   (min 1 d )
+	 *		S:         size       (min 1 d ) 
+	 *		0x01, \n:  terminators
          */
 
         data_limit = skb->h.raw + skb->len;
-
-	while (data < (data_limit - 25) )
+        
+	while (data < (data_limit - ( 21 + MAXMATCHLEN ) ) )
 	{
+		int i;
 		if (memcmp(data,"DCC ",4))  {
 			data ++;
 			continue;
 		}
 
-                dcc_p = data;
+		dcc_p = data;
 		data += 4;     /* point to DCC cmd */
 
-                if (memcmp(data, "CHAT ", 5) == 0 ||
-                    memcmp(data, "SEND ", 5) == 0)
-                {
-                        /*
-                         *	extra arg (file_size) req. for "SEND"
-                         */
-
-                        if (*data == 'S') xtra_args++;
-                        data += 5;
-                }
-                else
-                        continue;
-
-                /*
-                 *	skip next string.
-                 */
-
-                while( *data++ != ' ')
-
-                        /*
-                         *	must still parse, at least, "AAAAAAAA P\x01\n",
-                         *      12 bytes left.
-                         */
-                        if (data > (data_limit-12)) return 0;
-
-
-                addr_beg_p = data;
-
-                /*
-                 *	client bound address in dec base
-                 */
-
- 		s_addr = simple_strtoul(data,&data,10);
-		if (*data++ !=' ')
-			continue;
-
-                /*
-                 *	client bound port in dec base
-                 */
-
-		s_port = simple_strtoul(data,&data,10);
-                addr_end_p = data;
-
-                /*
-                 *	should check args consistency?
-                 */
-
-                while(xtra_args) {
-                        if (*data != ' ')
-                                break;
-                        data++;
-                        simple_strtoul(data,&data,10);
-                        xtra_args--;
-                }
-
-                if (xtra_args != 0) continue;
-
-                /*
-                 *	terminators.
-                 */
-
-                if (data[0] != 0x01)
-                        continue;
-		if (data[1]!='\r' && data[1]!='\n')
-			continue;
-
-		/*
-		 *	Now create an masquerade entry for it
-                 * 	must set NO_DPORT and NO_DADDR because
-                 *	connection is requested by another client.
-		 */
-
-		n_ms = ip_masq_new(maddr, IPPROTO_TCP,
-                                   htonl(s_addr),htons(s_port),
-                                   0, 0,
-                                   IP_MASQ_F_NO_DPORT|IP_MASQ_F_NO_DADDR
-                                   );
-		if (n_ms==NULL)
-			return 0;
-
-                ip_masq_set_expire(n_ms, ip_masq_expire->tcp_fin_timeout);
-
-		/*
-		 * Replace the old "address port" with the new one
-		 */
-
-		buf_len = sprintf(buf,"%lu %u",
-                        ntohl(n_ms->maddr),ntohs(n_ms->mport));
-
-		/*
-		 * Calculate required delta-offset to keep TCP happy
-		 */
-
-		diff = buf_len - (addr_end_p-addr_beg_p);
-
-#if DEBUG_CONFIG_IP_MASQ_IRC
-                *addr_beg_p = '\0';
-		printk("masq_irc_out(): '%s' %X:%X detected (diff=%d)\n", dcc_p, s_addr,s_port, diff);
-#endif
-		/*
-		 *	No shift.
-		 */
-
-		if (diff==0)
+		for(i=0; i<NUM_DCCPROTO; i++)
 		{
 			/*
-			 * simple case, just copy.
- 			 */
- 			memcpy(addr_beg_p,buf,buf_len);
- 			return 0;
- 		}
-
-                *skb_p = ip_masq_skb_replace(skb, GFP_ATOMIC,
-                                             addr_beg_p, addr_end_p-addr_beg_p,
-                                             buf, buf_len);
-                return diff;
+			 * go through the table and hunt a match string
+			 */
+
+			if( memcmp(data, dccprotos[i].match, dccprotos[i].matchlen ) == 0 )
+			{
+				xtra_args = dccprotos[i].xtra_args;
+				data += dccprotos[i].matchlen;
+
+				/*
+				 *	skip next string.
+				 */
+
+				while( *data++ != ' ')
+
+					/*
+					 *	must still parse, at least, "AAAAAAAA P\x01\n",
+					 *      12 bytes left.
+					 */
+					if (data > (data_limit-12)) return 0;
+
+
+				addr_beg_p = data;
+
+				/*
+				 *	client bound address in dec base
+				 */
+
+				s_addr = simple_strtoul(data,&data,10);
+				if (*data++ !=' ')
+					continue;
+
+				/*
+				 *	client bound port in dec base
+				 */
+
+				s_port = simple_strtoul(data,&data,10);
+				addr_end_p = data;
+
+				/*
+				 *	should check args consistency?
+				 */
+
+				while(xtra_args) {
+					if (*data != ' ')
+						break;
+					data++;
+					simple_strtoul(data,&data,10);
+					xtra_args--;
+				}
+
+				if (xtra_args != 0) continue;
+
+				/*
+				 *	terminators.
+				 */
+
+				if (data[0] != 0x01)
+					continue;
+				if (data[1]!='\r' && data[1]!='\n')
+					continue;
+
+				/*
+				 *	Now create an masquerade entry for it
+				 * 	must set NO_DPORT and NO_DADDR because
+				 *	connection is requested by another client.
+				 */
+
+				n_ms = ip_masq_new(IPPROTO_TCP,
+						maddr, 0,
+						htonl(s_addr),htons(s_port),
+						0, 0,
+						IP_MASQ_F_NO_DPORT|IP_MASQ_F_NO_DADDR);
+				if (n_ms==NULL)
+					return 0;
+
+				/*
+				 * Replace the old "address port" with the new one
+				 */
+
+				buf_len = sprintf(buf,"%lu %u",
+						ntohl(n_ms->maddr),ntohs(n_ms->mport));
+
+				/*
+				 * Calculate required delta-offset to keep TCP happy
+				 */
+
+				diff = buf_len - (addr_end_p-addr_beg_p);
+
+				*addr_beg_p = '\0';
+				IP_MASQ_DEBUG(1-debug, "masq_irc_out(): '%s' %X:%X detected (diff=%d)\n", dcc_p, s_addr,s_port, diff);
+
+				/*
+				 *	No shift.
+				 */
+
+				if (diff==0) {
+					/*
+					 * simple case, just copy.
+					 */
+					memcpy(addr_beg_p,buf,buf_len);
+				} else {
+
+					*skb_p = ip_masq_skb_replace(skb, GFP_ATOMIC,
+							addr_beg_p, addr_end_p-addr_beg_p,
+							buf, buf_len);
+				}
+				ip_masq_listen(n_ms);
+				ip_masq_put(n_ms);
+				return diff;
+			}
+		}
 	}
 	return 0;
 
@@ -221,7 +280,7 @@
  *     	You need 1 object per port in case you need
  *	to offer also other used irc ports (6665,6666,etc),
  *	they will share methods but they need own space for
- *	data.
+ *	data. 
  */
 
 struct ip_masq_app ip_masq_irc = {
@@ -241,7 +300,28 @@
 
 __initfunc(int ip_masq_irc_init(void))
 {
-        return register_ip_masq_app(&ip_masq_irc, IPPROTO_TCP, 6667);
+	int i, j;
+
+	for (i=0; (i<MAX_MASQ_APP_PORTS); i++) {
+		if (ports[i]) {
+			if ((masq_incarnations[i] = kmalloc(sizeof(struct ip_masq_app),
+							    GFP_KERNEL)) == NULL)
+				return -ENOMEM;
+			memcpy(masq_incarnations[i], &ip_masq_irc, sizeof(struct ip_masq_app));
+			if ((j = register_ip_masq_app(masq_incarnations[i], 
+						      IPPROTO_TCP, 
+						      ports[i]))) {
+				return j;
+			}
+			IP_MASQ_DEBUG(1-debug,
+					"Irc: loaded support on port[%d] = %d\n",
+			       i, ports[i]);
+		} else {
+			/* To be safe, force the incarnation table entry to NULL */
+			masq_incarnations[i] = NULL;
+		}
+	}
+	return 0;
 }
 
 /*
@@ -250,8 +330,24 @@
 
 int ip_masq_irc_done(void)
 {
-        return unregister_ip_masq_app(&ip_masq_irc);
+	int i, j, k;
+
+	k=0;
+	for (i=0; (i<MAX_MASQ_APP_PORTS); i++) {
+		if (masq_incarnations[i]) {
+			if ((j = unregister_ip_masq_app(masq_incarnations[i]))) {
+				k = j;
+			} else {
+				kfree(masq_incarnations[i]);
+				masq_incarnations[i] = NULL;
+				IP_MASQ_DEBUG(1-debug, "Irc: unloaded support on port[%d] = %d\n",
+				       i, ports[i]);
+			}
+		}
+	}
+	return k;
 }
+
 
 #ifdef MODULE
 EXPORT_NO_SYMBOLS;
diff -u --recursive --new-file v2.1.72/linux/net/ipv4/ip_masq_mod.c linux/net/ipv4/ip_masq_mod.c
--- v2.1.72/linux/net/ipv4/ip_masq_mod.c	Wed Dec 31 16:00:00 1969
+++ linux/net/ipv4/ip_masq_mod.c	Wed Dec 10 09:45:16 1997
@@ -0,0 +1,316 @@
+/*
+ *		IP_MASQ_MOD masq modules support
+ *
+ *
+ * Version:	@(#)ip_masq_mod.c  0.02      97/10/30
+ *
+ * Author:	Juan Jose Ciarlante, <jjciarla@raiz.uncu.edu.ar>
+ *
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License
+ *	as published by the Free Software Foundation; either version
+ *	2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <net/ip_masq.h>
+#include <net/ip_masq_mod.h>
+#ifdef CONFIG_KERNELD
+#include <linux/kerneld.h>
+#endif
+
+EXPORT_SYMBOL(register_ip_masq_mod);
+EXPORT_SYMBOL(unregister_ip_masq_mod);
+EXPORT_SYMBOL(ip_masq_mod_lkp_link);
+EXPORT_SYMBOL(ip_masq_mod_lkp_unlink);
+
+/*
+ *	Base pointer for registered modules
+ */
+struct ip_masq_mod * ip_masq_mod_reg_base = NULL;
+
+/*
+ *	Base pointer for lookup (subset of above, a module could be
+ *	registered, but it could have no active rule); will avoid
+ *	unnecessary lookups.
+ */
+struct ip_masq_mod * ip_masq_mod_lkp_base = NULL;
+
+int ip_masq_mod_register_proc(struct ip_masq_mod *mmod)
+{
+#ifdef CONFIG_PROC_FS        
+	int ret;
+
+	struct proc_dir_entry *ent = mmod->mmod_proc_ent;
+
+	if (!ent) 
+		return 0;
+	if (!ent->name) {
+		ent->name = mmod->mmod_name;
+		ent->namelen = strlen (mmod->mmod_name);
+	}
+	ret = proc_net_register(ent);
+	if (ret) mmod->mmod_proc_ent = NULL;
+
+	return ret;
+#else
+	return 0;
+#endif
+}
+
+void ip_masq_mod_unregister_proc(struct ip_masq_mod *mmod)
+{
+#ifdef CONFIG_PROC_FS        
+	struct proc_dir_entry *ent = mmod->mmod_proc_ent;
+	if (!ent)
+		return;
+	proc_unregister(proc_net, ent->low_ino);
+#endif
+}
+
+/*
+ *	Link/unlink object for lookups
+ */
+
+int ip_masq_mod_lkp_unlink(struct ip_masq_mod *mmod)
+{
+	struct ip_masq_mod **mmod_p;
+
+	start_bh_atomic();
+
+	for (mmod_p = &ip_masq_mod_lkp_base; *mmod_p ; mmod_p = &(*mmod_p)->next)
+		if (mmod == (*mmod_p))  {
+			*mmod_p = mmod->next;
+			mmod->next = NULL;
+			end_bh_atomic();
+			return 0;
+		}
+
+	end_bh_atomic();
+	return -EINVAL;
+}
+
+int ip_masq_mod_lkp_link(struct ip_masq_mod *mmod)
+{
+	start_bh_atomic();
+
+	mmod->next = ip_masq_mod_lkp_base;
+	ip_masq_mod_lkp_base=mmod;
+
+	end_bh_atomic();
+	return 0;
+}
+
+int register_ip_masq_mod(struct ip_masq_mod *mmod)
+{
+	if (!mmod) {
+		IP_MASQ_ERR("register_ip_masq_mod(): NULL arg\n");
+		return -EINVAL;
+	}
+	if (!mmod->mmod_name) {
+		IP_MASQ_ERR("register_ip_masq_mod(): NULL mmod_name\n");
+		return -EINVAL;
+	}
+	ip_masq_mod_register_proc(mmod);
+
+	mmod->next_reg = ip_masq_mod_reg_base;
+	ip_masq_mod_reg_base=mmod;
+
+	return 0;
+}
+
+int unregister_ip_masq_mod(struct ip_masq_mod *mmod)
+{
+	struct ip_masq_mod **mmod_p;
+
+	if (!mmod) {
+		IP_MASQ_ERR( "unregister_ip_masq_mod(): NULL arg\n");
+		return -EINVAL;
+	}
+
+	/*
+	 * 	Only allow unregistration if it is not referenced
+	 */
+	if (atomic_read(&mmod->refcnt))  {
+		IP_MASQ_ERR( "unregister_ip_masq_mod(): is in use by %d guys. failed\n",
+				atomic_read(&mmod->refcnt));
+		return -EINVAL;
+	}
+
+	/*	
+	 *	Must be already unlinked from lookup list
+	 */
+	if (mmod->next) {
+		IP_MASQ_WARNING("MASQ: unregistering \"%s\" while in lookup list.fixed.",
+			mmod->mmod_name);
+		ip_masq_mod_lkp_unlink(mmod);
+	}
+
+	for (mmod_p = &ip_masq_mod_reg_base; *mmod_p ; mmod_p = &(*mmod_p)->next_reg)
+		if (mmod == (*mmod_p))  {
+			ip_masq_mod_unregister_proc(mmod);
+			*mmod_p = mmod->next_reg;
+			return 0;
+		}
+
+	IP_MASQ_ERR("unregister_ip_masq_mod(%s): not linked \n", mmod->mmod_name);
+	return -EINVAL;
+}
+
+int ip_masq_mod_in_rule(struct iphdr *iph, __u16 *portp)
+{
+	struct ip_masq_mod *mmod;
+	int ret;
+
+	for (mmod=ip_masq_mod_lkp_base;mmod;mmod=mmod->next) {
+		if (!mmod->mmod_in_rule) continue;
+		switch (ret=mmod->mmod_in_rule(iph, portp)) {
+			case IP_MASQ_MOD_NOP:
+				continue;
+			case IP_MASQ_MOD_ACCEPT:
+				return 1;
+			case IP_MASQ_MOD_REJECT:
+				return -1;
+		}
+	}
+	return 0;
+}
+
+int ip_masq_mod_out_rule(struct iphdr *iph, __u16 *portp)
+{
+	struct ip_masq_mod *mmod;
+	int ret;
+
+	for (mmod=ip_masq_mod_lkp_base;mmod;mmod=mmod->next) {
+		if (!mmod->mmod_out_rule) continue;
+		switch (ret=mmod->mmod_out_rule(iph, portp)) {
+			case IP_MASQ_MOD_NOP:
+				continue;
+			case IP_MASQ_MOD_ACCEPT:
+				return 1;
+			case IP_MASQ_MOD_REJECT:
+				return -1;
+		}
+	}
+	return 0;
+}
+
+struct ip_masq * ip_masq_mod_in_create(struct iphdr *iph, __u16 *portp, __u32 maddr)
+{
+	struct ip_masq_mod *mmod;
+	struct ip_masq *ms;
+
+	for (mmod=ip_masq_mod_lkp_base;mmod;mmod=mmod->next) {
+		if (!mmod->mmod_in_create) continue;
+		if ((ms=mmod->mmod_in_create(iph, portp, maddr))) {
+			return ms;
+		}
+	}
+	return NULL;
+}
+
+struct ip_masq * ip_masq_mod_out_create(struct iphdr *iph, __u16 *portp, __u32 maddr)
+{
+	struct ip_masq_mod *mmod;
+	struct ip_masq *ms;
+
+	for (mmod=ip_masq_mod_lkp_base;mmod;mmod=mmod->next) {
+		if (!mmod->mmod_out_create) continue;
+		if ((ms=mmod->mmod_out_create(iph, portp, maddr))) {
+			return ms;
+		}
+	}
+	return NULL;
+}
+
+int ip_masq_mod_in_update(struct iphdr *iph, __u16 *portp, struct ip_masq *ms)
+{
+	struct ip_masq_mod *mmod;
+	int ret;
+
+	for (mmod=ip_masq_mod_lkp_base;mmod;mmod=mmod->next) {
+		if (!mmod->mmod_in_update) continue;
+		switch (ret=mmod->mmod_in_update(iph, ms)) {
+			case IP_MASQ_MOD_NOP:
+				continue;
+			case IP_MASQ_MOD_ACCEPT:
+				return 1;
+			case IP_MASQ_MOD_REJECT:
+				return -1;
+		}
+	}
+	return 0;
+}
+
+int ip_masq_mod_out_update(struct iphdr *iph, __u16 *portp,  struct ip_masq *ms)
+{
+	struct ip_masq_mod *mmod;
+	int ret;
+
+	for (mmod=ip_masq_mod_lkp_base;mmod;mmod=mmod->next) {
+		if (!mmod->mmod_out_update) continue;
+		switch (ret=mmod->mmod_out_update(iph, portp, ms)) {
+			case IP_MASQ_MOD_NOP:
+				continue;
+			case IP_MASQ_MOD_ACCEPT:
+				return 1;
+			case IP_MASQ_MOD_REJECT:
+				return -1;
+		}
+	}
+	return 0;
+}
+
+struct ip_masq_mod * ip_masq_mod_getbyname(const char *mmod_name)
+{
+	struct ip_masq_mod * mmod;
+
+	IP_MASQ_DEBUG(1, "searching mmod_name \"%s\"\n", mmod_name);
+	
+	for (mmod=ip_masq_mod_reg_base; mmod ; mmod=mmod->next) {
+		if (mmod->mmod_ctl && *(mmod_name)
+				&& (strcmp(mmod_name, mmod->mmod_name)==0)) {
+			/* HIT */
+			return mmod;
+		}
+	}
+	return NULL;
+}
+
+/*
+ *	Module control entry
+ *	no need to lock (already locked in ip_masq.c)
+ */
+int ip_masq_mod_ctl(int optname, struct ip_fw_masqctl *mctl, int optlen)
+{
+	struct ip_masq_mod * mmod;
+#ifdef CONFIG_KERNELD
+	char kmod_name[IP_MASQ_MOD_NMAX+8];
+#endif
+	/* tappo */
+	mctl->u.mod.name[IP_MASQ_MOD_NMAX-1] = 0;
+
+	mmod = ip_masq_mod_getbyname(mctl->u.mod.name);
+	if (mmod)
+		return mmod->mmod_ctl(optname, mctl, optlen);
+#ifdef CONFIG_KERNELD
+	sprintf(kmod_name,"ip_masq_%s", mctl->u.mod.name);
+
+	IP_MASQ_DEBUG(1, "About to request \"%s\" module\n", kmod_name);
+
+	/* 
+	 *	Let sleep for a while ...
+	 */
+	request_module(kmod_name);
+	mmod = ip_masq_mod_getbyname(mctl->u.mod.name);
+	if (mmod)
+		return mmod->mmod_ctl(optname, mctl, optlen);
+#endif
+	return ESRCH;
+}
diff -u --recursive --new-file v2.1.72/linux/net/ipv4/ip_masq_portfw.c linux/net/ipv4/ip_masq_portfw.c
--- v2.1.72/linux/net/ipv4/ip_masq_portfw.c	Wed Dec 31 16:00:00 1969
+++ linux/net/ipv4/ip_masq_portfw.c	Wed Dec 10 09:45:16 1997
@@ -0,0 +1,461 @@
+/*
+ *		IP_MASQ_PORTFW masquerading module
+ *
+ *
+ * Version:	@(#)ip_masq_portfw.c  0.02      97/10/30
+ *
+ * Author:	Steven Clarke <steven.clarke@monmouth.demon.co.uk>
+ *
+ * Fixes:	
+ *	Juan Jose Ciarlante	: created this new file from ip_masq.c and ip_fw.c
+ *	Juan Jose Ciarlante	: modularized 
+ *	Juan Jose Ciarlante 	: use GFP_KERNEL
+ *
+ *	FIXME
+ *		- after creating /proc/net/ip_masq/ direct, put portfw underneath
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/list.h>
+#include <net/ip.h>
+#include <linux/ip_fw.h>
+#include <net/ip_masq.h>
+#include <net/ip_masq_mod.h>
+#include <net/ip_portfw.h>
+#include <linux/proc_fs.h>
+#include <linux/init.h>
+
+static struct ip_masq_mod *mmod_self = NULL;
+
+/*
+ *	Lock
+ */
+static atomic_t portfw_lock = ATOMIC_INIT(0);
+static struct wait_queue *portfw_wait;
+
+static struct list_head portfw_list[2];
+static __inline__ int portfw_idx(int protocol)
+{
+        return (protocol==IPPROTO_TCP);
+}
+
+/*
+ *
+ *	Delete forwarding entry(s):
+ *	called from _DEL, u-space.
+ *	. "relaxed" match, except for lport
+ *
+ */
+
+static __inline__ int ip_portfw_del(__u16 protocol, __u16 lport, __u32 laddr, __u16 rport, __u32 raddr)
+{
+        int prot = portfw_idx(protocol);
+        struct ip_portfw *n;
+	struct list_head *entry;
+	struct list_head *list = &portfw_list[prot];
+	int nent;
+
+	nent = atomic_read(&mmod_self->mmod_nent);
+
+	ip_masq_lockz(&portfw_lock, &portfw_wait, 1);
+
+	for (entry=list->next;entry != list;entry = entry->next)  {
+		n = list_entry(entry, struct ip_portfw, list);
+		if (n->lport == lport && 
+				(!laddr || n->laddr == laddr) &&
+				(!raddr || n->raddr == raddr) && 
+				(!rport || n->rport == rport)) {
+			list_del(entry);
+			ip_masq_mod_dec_nent(mmod_self);
+			kfree_s(n, sizeof(struct ip_portfw));
+			MOD_DEC_USE_COUNT;
+		}
+	}
+	ip_masq_unlockz(&portfw_lock, &portfw_wait, 1);
+	
+	return nent==atomic_read(&mmod_self->mmod_nent)? ESRCH : 0;
+}
+
+/*
+ *	Flush tables
+ *	called from _FLUSH, u-space.
+ */
+static __inline__ void ip_portfw_flush(void)
+{
+        int prot;
+	struct list_head *l;
+	struct list_head *e;
+	struct ip_portfw *n;
+
+	ip_masq_lockz(&portfw_lock, &portfw_wait, 1);
+
+	for (prot = 0; prot < 2;prot++) {
+		l = &portfw_list[prot];
+		while((e=l->next) != l) {
+			ip_masq_mod_dec_nent(mmod_self);
+			n = list_entry (e, struct ip_portfw, list);
+			list_del(e);
+			kfree_s(n, sizeof (*n));
+			MOD_DEC_USE_COUNT;
+		}
+	}
+
+	ip_masq_unlockz(&portfw_lock, &portfw_wait, 1);
+}
+
+/*
+ *	Lookup routine for lport,laddr match
+ *	called from ip_masq module (via registered obj)
+ */
+static __inline__ struct ip_portfw *ip_portfw_lookup(__u16 protocol, __u16 lport, __u32 laddr, __u32 *daddr_p, __u16 *dport_p)
+{
+	int prot = portfw_idx(protocol);
+	
+	struct ip_portfw *n = NULL;
+	struct list_head *l, *e;
+
+	ip_masq_lock(&portfw_lock, 0);
+
+	l = &portfw_list[prot];
+
+	for (e=l->next;e!=l;e=e->next) {
+		n = list_entry(e, struct ip_portfw, list);
+		if (lport == n->lport && laddr == n->laddr) {
+			/* Please be nice, don't pass only a NULL dport */
+			if (daddr_p) {
+				*daddr_p = n->raddr;
+				*dport_p = n->rport;
+			}
+			
+			goto out;
+		}
+	}
+	n = NULL;
+out:
+	ip_masq_unlock(&portfw_lock, 0);
+	return n;
+}
+
+/*
+ *	Edit routine for lport,[laddr], [raddr], [rport] match
+ *	By now, only called from u-space
+ */
+static __inline__ int ip_portfw_edit(__u16 protocol, __u16 lport, __u32 laddr, __u16 rport, __u32 raddr, int pref)
+{
+	int prot = portfw_idx(protocol);
+	
+	struct ip_portfw *n = NULL;
+	struct list_head *l, *e;
+	int count = 0;
+
+
+	ip_masq_lockz(&portfw_lock, &portfw_wait, 0);
+
+	l = &portfw_list[prot];
+
+	for (e=l->next;e!=l;e=e->next) {
+		n = list_entry(e, struct ip_portfw, list);
+		if (lport == n->lport && 
+				(!laddr || laddr == n->laddr) &&
+				(!rport || rport == n->rport) && 
+				(!raddr || raddr == n->raddr)) {
+			n->pref = pref;
+			atomic_set(&n->pref_cnt, pref);
+			count++;
+		}
+	}
+
+	ip_masq_unlockz(&portfw_lock, &portfw_wait, 0);
+
+	return count;
+}
+
+/*
+ *	Add/edit en entry
+ *	called from _ADD, u-space.
+ *	must return 0 or +errno
+ */
+static __inline__ int ip_portfw_add(__u16 protocol, __u16 lport, __u32 laddr, __u16 rport, __u32 raddr, int pref)
+{
+        struct ip_portfw  *npf;
+        int prot = portfw_idx(protocol);
+         
+	if (pref <= 0)
+		return EINVAL;
+
+	if (ip_portfw_edit(protocol, lport, laddr, rport, raddr, pref)) {
+		/*
+		 *	Edit ok ...
+		 */
+		return 0;
+	}
+
+	/* may block ... */
+	npf = (struct ip_portfw*) kmalloc(sizeof(struct ip_portfw), GFP_KERNEL);
+
+	if (!npf)
+		return ENOMEM;
+
+	MOD_INC_USE_COUNT;
+        memset(npf, 0, sizeof(*npf));
+
+        npf->laddr = laddr;
+        npf->lport = lport;
+        npf->rport = rport;
+        npf->raddr = raddr;
+	npf->pref  = pref;
+
+	atomic_set(&npf->pref_cnt, npf->pref);
+	INIT_LIST_HEAD(&npf->list);
+
+	ip_masq_lockz(&portfw_lock, &portfw_wait, 1);
+
+	/*
+	 *	Add at head
+	 */
+	list_add(&npf->list, &portfw_list[prot]);
+
+	ip_masq_unlockz(&portfw_lock, &portfw_wait, 1);
+
+	ip_masq_mod_inc_nent(mmod_self);
+        return 0;
+}
+
+
+
+static __inline__ int portfw_ctl(int cmd, struct ip_fw_masqctl *mctl, int optlen)
+{
+        struct ip_portfw_edits *mm = (struct ip_portfw_edits *) mctl->u.mod.data;
+	int ret = EINVAL;
+
+	/* 
+	 *	Don't trust the lusers - plenty of error checking! 
+	 */
+	if (optlen<sizeof(*mm)) 
+		return EINVAL;
+ 
+        if (cmd != IP_FW_MASQ_FLUSH) {
+		if (htons(mm->lport) < IP_PORTFW_PORT_MIN 
+				|| htons(mm->lport) > IP_PORTFW_PORT_MAX)
+			return EINVAL;
+
+                if (mm->protocol!=IPPROTO_TCP && mm->protocol!=IPPROTO_UDP)
+                        return EINVAL;
+        }
+
+
+	switch(cmd) {
+	case IP_FW_MASQ_ADD:
+		ret = ip_portfw_add(mm->protocol,
+				mm->lport, mm->laddr,
+				mm->rport, mm->raddr,
+				mm->pref);
+		break;
+
+	case IP_FW_MASQ_DEL:
+		ret = ip_portfw_del(mm->protocol, 
+				mm->lport, mm->laddr,
+				mm->rport, mm->raddr);
+		break;
+	case IP_FW_MASQ_FLUSH:
+		ip_portfw_flush();
+		ret = 0;
+		break;
+	}
+				
+
+	return ret;
+}
+
+
+
+
+#ifdef CONFIG_PROC_FS
+
+static int portfw_procinfo(char *buffer, char **start, off_t offset,
+                            int length, int unused)
+{
+        off_t pos=0, begin;
+        struct ip_portfw *pf;
+	struct list_head *l, *e;
+        char temp[65];
+        int ind;
+        int len=0;
+
+	ip_masq_lockz(&portfw_lock, &portfw_wait, 0);
+
+        if (offset < 64) 
+        {
+                sprintf(temp, "Prot LAddr    LPort > RAddr    RPort PrCnt  Pref");
+                len = sprintf(buffer, "%-63s\n", temp);
+        }
+        pos = 64;
+
+        for(ind = 0; ind < 2; ind++)
+        {
+		l = &portfw_list[ind];
+		for (e=l->next; e!=l; e=e->next)
+                {
+			pf = list_entry(e, struct ip_portfw, list);
+                        pos += 64;
+                        if (pos <= offset)
+                                continue;
+
+                        sprintf(temp,"%s  %08lX %5u > %08lX %5u %5d %5d",
+                                ind ? "TCP" : "UDP",
+				ntohl(pf->laddr), ntohs(pf->lport),
+				ntohl(pf->raddr), ntohs(pf->rport),
+				atomic_read(&pf->pref_cnt), pf->pref);
+                        len += sprintf(buffer+len, "%-63s\n", temp);
+
+                        if (len >= length)
+                                goto done;
+		}
+        }
+done:
+	ip_masq_unlockz(&portfw_lock, &portfw_wait, 0);
+
+        begin = len - (pos - offset);
+        *start = buffer + begin;
+        len -= begin;
+        if(len>length)
+                len = length;
+        return len;
+}
+
+static struct proc_dir_entry portfw_proc_entry = {
+/* 		0, 0, NULL", */
+		0, 9, "ip_portfw",   /* Just for compatibility, for now ... */
+		S_IFREG | S_IRUGO, 1, 0, 0,
+		0, &proc_net_inode_operations,
+		portfw_procinfo
+};
+
+#define proc_ent &portfw_proc_entry
+#else /* !CONFIG_PROC_FS */
+
+#define proc_ent NULL
+#endif
+
+static int portfw_in_rule(struct iphdr *iph, __u16 *portp)
+{
+
+	return (ip_portfw_lookup(iph->protocol, portp[1], iph->daddr, NULL, NULL)!=0);
+}
+
+static struct ip_masq * portfw_in_create(struct iphdr *iph, __u16 *portp, __u32 maddr)
+{
+	/* 
+	 *	If no entry exists in the masquerading table
+ 	 * 	and the port is involved
+	 *  	in port forwarding, create a new masq entry 
+	 */
+
+	__u32 raddr;
+	__u16 rport;
+	struct ip_masq *ms = NULL;
+	struct ip_portfw *pf;
+
+	/*
+	 *	Lock for reading only, by now...
+	 */
+	ip_masq_lock(&portfw_lock, 0);
+
+	if ((pf=ip_portfw_lookup(iph->protocol, 
+			portp[1], iph->daddr, 
+			&raddr, &rport))) {
+		ms = ip_masq_new(iph->protocol,
+				iph->daddr, portp[1],	
+				raddr, rport,
+				iph->saddr, portp[0],
+				0);
+		ip_masq_listen(ms);
+
+		if (!ms || atomic_read(&mmod_self->mmod_nent) <= 1 || 
+			ip_masq_nlocks(&portfw_lock) != 1)
+				/*
+				 *	Maybe later...
+				 */
+				goto out;
+
+		/*
+		 *	Entry created, lock==1.
+		 *	if pref_cnt == 0, move
+		 *	entry at _tail_.
+		 *	This is a simple load balance scheduling
+		 */
+	
+		if (atomic_dec_and_test(&pf->pref_cnt)) {
+			start_bh_atomic();
+
+			atomic_set(&pf->pref_cnt, pf->pref);
+			list_del(&pf->list);
+			list_add(&pf->list, 
+				portfw_list[portfw_idx(iph->protocol)].prev);
+
+			end_bh_atomic();
+		}
+	}
+out:
+	ip_masq_unlock(&portfw_lock, 0);
+	return ms;
+}
+
+#define portfw_in_update	NULL
+#define portfw_out_rule		NULL
+#define portfw_out_create	NULL
+#define portfw_out_update	NULL
+
+static struct ip_masq_mod portfw_mod = {
+	NULL,			/* next */
+	NULL,			/* next_reg */
+	"portfw",		/* name */
+	ATOMIC_INIT(0),		/* nent */
+	ATOMIC_INIT(0),		/* refcnt */
+	proc_ent,
+	portfw_ctl,
+	NULL,			/* masq_mod_init */
+	NULL,			/* masq_mod_done */
+	portfw_in_rule,
+	portfw_in_update,
+	portfw_in_create,
+	portfw_out_rule,
+	portfw_out_update,
+	portfw_out_create,
+};
+
+
+
+__initfunc(int ip_portfw_init(void))
+{
+	INIT_LIST_HEAD(&portfw_list[0]);
+	INIT_LIST_HEAD(&portfw_list[1]);
+	return register_ip_masq_mod ((mmod_self=&portfw_mod));
+}
+
+int ip_portfw_done(void)
+{
+	return unregister_ip_masq_mod(&portfw_mod);
+}
+
+#ifdef MODULE
+EXPORT_NO_SYMBOLS;
+
+int init_module(void)
+{
+	if (ip_portfw_init() != 0)
+		return -EIO;
+	return 0;
+}
+
+void cleanup_module(void)
+{
+	if (ip_portfw_done() != 0)
+		printk(KERN_INFO "ip_portfw_done(): can't remove module");
+}
+
+#endif /* MODULE */
diff -u --recursive --new-file v2.1.72/linux/net/ipv4/ip_masq_quake.c linux/net/ipv4/ip_masq_quake.c
--- v2.1.72/linux/net/ipv4/ip_masq_quake.c	Mon Dec  1 12:04:16 1997
+++ linux/net/ipv4/ip_masq_quake.c	Wed Dec 10 09:45:16 1997
@@ -11,6 +11,7 @@
  *      Harald Hoyer            :       Unofficial Quake Specs found at 
  *                                 http://www.gamers.org/dEngine/quake/spec/ 
  *      Harald Hoyer            :       Check for QUAKE-STRING
+ *	Juan Jose Ciarlante	:  litl bits for 2.1
  *
  *	This program is free software; you can redistribute it and/or
  *	modify it under the terms of the GNU General Public License
@@ -73,7 +74,7 @@
 }
 
 int
-masq_quake_in (struct ip_masq_app *mapp, struct ip_masq *ms, struct sk_buff **skb_p)
+masq_quake_in (struct ip_masq_app *mapp, struct ip_masq *ms, struct sk_buff **skb_p, __u32 maddr)
 {
 	struct sk_buff *skb;
 	struct iphdr *iph;
@@ -234,7 +235,8 @@
 
 	  memcpy(&udp_port, data, 2);
 	  
-	  n_ms = ip_masq_new(maddr, IPPROTO_UDP,
+	  n_ms = ip_masq_new(IPPROTO_UDP,
+			     maddr, 0,
 			     ms->saddr, htons(udp_port),
 			     ms->daddr, ms->dport,
 			     0);
@@ -248,6 +250,10 @@
 #endif
 	  udp_port = ntohs(n_ms->mport);
 	  memcpy(data, &udp_port, 2);
+
+	  ip_masq_listen(n_ms);
+	  ip_masq_control_add(n_ms, ms);
+	  ip_masq_put(n_ms);
 
 	  break;
 	}
diff -u --recursive --new-file v2.1.72/linux/net/ipv4/ip_masq_raudio.c linux/net/ipv4/ip_masq_raudio.c
--- v2.1.72/linux/net/ipv4/ip_masq_raudio.c	Mon Dec  1 12:04:16 1997
+++ linux/net/ipv4/ip_masq_raudio.c	Wed Dec 10 09:45:16 1997
@@ -2,11 +2,13 @@
  *		IP_MASQ_RAUDIO  - Real Audio masquerading module
  *
  *
- * Version:	@(#)$Id: ip_masq_raudio.c,v 1.7 1997/09/16 18:43:40 kuznet Exp $
+ * Version:	@(#)$Id: ip_masq_raudio.c,v 1.8 1997/11/28 15:32:32 alan Exp $
  *
  * Author:	Nigel Metheringham
+ *		Real Time Streaming code by Progressive Networks
  *		[strongly based on ftp module by Juan Jose Ciarlante & Wouter Gadeyne]
  *		[Real Audio information taken from Progressive Networks firewall docs]
+ *		[Kudos to Progressive Networks for making the protocol specs available]
  *
  *
  *
@@ -31,16 +33,40 @@
  *
  *	At present the "first packet" is defined as a packet starting with
  *	the protocol ID string - "PNA".
- *	When the link is up there appears to be enough control data
+ *	When the link is up there appears to be enough control data 
  *	crossing the control link to keep it open even if a long audio
  *	piece is playing.
  *
+ *	The Robust UDP support added in RealAudio 3.0 is supported, but due
+ *	to servers/clients not making great use of this has not been greatly
+ *	tested.  RealVideo (as used in the Real client version 4.0beta1) is
+ *	supported but again is not greatly tested (bandwidth requirements
+ *	appear to exceed that available at the sites supporting the protocol).
+ *
+ * Multiple Port Support
+ *	The helper can be made to handle up to MAX_MASQ_APP_PORTS (normally 12)
+ *	with the port numbers being defined at module load time.  The module
+ *	uses the symbol "ports" to define a list of monitored ports, which can
+ *	be specified on the insmod command line as
+ *		ports=x1,x2,x3...
+ *	where x[n] are integer port numbers.  This option can be put into
+ *	/etc/conf.modules (or /etc/modules.conf depending on your config)
+ *	where modload will pick it up should you use modload to load your
+ *	modules.
+ *
+ * Fixes:
+ * 	Juan Jose Ciarlante	:	Use control_add() for control chan
+ * 	10/15/97 - Modifications to allow masquerading of RTSP connections as
+ *     		well as PNA, which can potentially exist on the same port.
+ *		Joe Rumsey <ogre@real.com>
+ *	
  */
 
 #include <linux/config.h>
 #include <linux/module.h>
 #include <asm/system.h>
 #include <linux/types.h>
+#include <linux/ctype.h>
 #include <linux/kernel.h>
 #include <linux/skbuff.h>
 #include <linux/in.h>
@@ -50,30 +76,62 @@
 #include <net/tcp.h>
 #include <net/ip_masq.h>
 
+/*
 #ifndef DEBUG_CONFIG_IP_MASQ_RAUDIO
 #define DEBUG_CONFIG_IP_MASQ_RAUDIO 0
 #endif
+*/
+
+#define TOLOWER(c) (((c) >= 'A' && (c) <= 'Z') ? ((c) - 'A' + 'a') : (c))
+#define ISDIGIT(c) (((c) >= '0') && ((c) <= '9'))
 
 struct raudio_priv_data {
 	/* Associated data connection - setup but not used at present */
 	struct	ip_masq *data_conn;
+	/* UDP Error correction connection - setup but not used at present */
+	struct	ip_masq *error_conn;
 	/* Have we seen and performed setup */
 	short	seen_start;
+        short   is_rtsp;
 };
 
+int
+masq_rtsp_out (struct ip_masq_app *mapp, 
+		 struct ip_masq *ms, 
+		 struct sk_buff **skb_p, 
+		 __u32 maddr);
+
+/* 
+ * List of ports (up to MAX_MASQ_APP_PORTS) to be handled by helper
+ * First port is set to the default port.
+ */
+int ports[MAX_MASQ_APP_PORTS] = {554, 7070, 0}; /* I rely on the trailing items being set to zero */
+struct ip_masq_app *masq_incarnations[MAX_MASQ_APP_PORTS];
+
+/*
+ *	Debug level
+ */
+static int debug=0;
+
+MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_MASQ_APP_PORTS) "i");
+MODULE_PARM(debug, "i");
+
+
 static int
 masq_raudio_init_1 (struct ip_masq_app *mapp, struct ip_masq *ms)
 {
         MOD_INC_USE_COUNT;
 	if ((ms->app_data = kmalloc(sizeof(struct raudio_priv_data),
-				    GFP_ATOMIC)) == NULL)
+				    GFP_ATOMIC)) == NULL) 
 		printk(KERN_INFO "RealAudio: No memory for application data\n");
-	else
+	else 
 	{
-		struct raudio_priv_data *priv =
+		struct raudio_priv_data *priv = 
 			(struct raudio_priv_data *)ms->app_data;
 		priv->seen_start = 0;
 		priv->data_conn = NULL;
+		priv->error_conn = NULL;
+		priv->is_rtsp = 0;
 	}
         return 0;
 }
@@ -96,34 +154,43 @@
 	char *p, *data, *data_limit;
 	struct ip_masq *n_ms;
 	unsigned short version, msg_id, msg_len, udp_port;
-	struct raudio_priv_data *priv =
+	struct raudio_priv_data *priv = 
 		(struct raudio_priv_data *)ms->app_data;
 
 	/* Everything running correctly already */
 	if (priv && priv->seen_start)
 		return 0;
 
+	if(priv && priv->is_rtsp)
+	    return masq_rtsp_out(mapp, ms, skb_p, maddr);
+
         skb = *skb_p;
 	iph = skb->nh.iph;
         th = (struct tcphdr *)&(((char *)iph)[iph->ihl*4]);
         data = (char *)&th[1];
 
-        data_limit = skb->h.raw + skb->len - 18;
+        data_limit = skb->h.raw + skb->len;
+
+	if(memcmp(data, "OPTIONS", 7) == 0 ||
+	   memcmp(data, "DESCRIBE", 8) == 0)
+	{
+	    IP_MASQ_DEBUG(1-debug, "RealAudio: Detected RTSP connection\n");
+	    /* This is an RTSP client */
+	    if(priv)
+		priv->is_rtsp = 1;
+	    return masq_rtsp_out(mapp, ms, skb_p, maddr);
+	}
 
 	/* Check to see if this is the first packet with protocol ID */
 	if (memcmp(data, "PNA", 3)) {
-#if DEBUG_CONFIG_IP_MASQ_RAUDIO
-		printk("RealAudio: not initial protocol packet - ignored\n");
-#endif
+		IP_MASQ_DEBUG(1-debug, "RealAudio: not initial protocol packet - ignored\n");
 		return(0);
 	}
 	data += 3;
 	memcpy(&version, data, 2);
 
-#if DEBUG_CONFIG_IP_MASQ_RAUDIO
-	printk("RealAudio: initial seen - protocol version %d\n",
+	IP_MASQ_DEBUG(1-debug, "RealAudio: initial seen - protocol version %d\n",
 	       ntohs(version));
-#endif
 	if (priv)
 		priv->seen_start = 1;
 
@@ -135,15 +202,22 @@
 	}
 
 	data += 2;
-	while (data < data_limit) {
+	while (data+4 < data_limit) {
 		memcpy(&msg_id, data, 2);
 		data += 2;
 		memcpy(&msg_len, data, 2);
 		data += 2;
-#if DEBUG_CONFIG_IP_MASQ_RAUDIO
-		printk("RealAudio: msg %d - %d byte\n",
+		if (ntohs(msg_id) == 0) {
+			/* The zero tag indicates the end of options */
+			IP_MASQ_DEBUG(1-debug, "RealAudio: packet end tag seen\n");
+			return 0;
+		}
+		IP_MASQ_DEBUG(1-debug, "RealAudio: msg %d - %d byte\n",
 		       ntohs(msg_id), ntohs(msg_len));
-#endif
+		if (ntohs(msg_id) == 0) {
+			/* The zero tag indicates the end of options */
+			return 0;
+		}
 		p = data;
 		data += ntohs(msg_len);
 		if (data > data_limit)
@@ -151,39 +225,272 @@
 			printk(KERN_INFO "RealAudio: Packet too short for data\n");
 			return 0;
 		}
-		if (ntohs(msg_id) == 1) {
-			/* This is a message detailing the UDP port to be used */
+		if ((ntohs(msg_id) == 1) || (ntohs(msg_id) == 7)) {
+			/* 
+			 * MsgId == 1
+			 * Audio UDP data port on client
+			 *
+			 * MsgId == 7
+			 * Robust UDP error correction port number on client
+			 *
+			 * Since these messages are treated just the same, they
+			 * are bundled together here....
+			 */
 			memcpy(&udp_port, p, 2);
-			n_ms = ip_masq_new(maddr, IPPROTO_UDP,
-					   ms->saddr, udp_port,
-					   ms->daddr, 0,
-					   IP_MASQ_F_NO_DPORT);
+
+			/* 
+			 * Sometimes a server sends a message 7 with a zero UDP port
+			 * Rather than do anything with this, just ignore it!
+			 */
+			if (udp_port == 0)
+				continue;
+
+
+			n_ms = ip_masq_new(IPPROTO_UDP,
+						maddr, 0,
+						ms->saddr, udp_port,
+						ms->daddr, 0,
+						IP_MASQ_F_NO_DPORT);
 
 			if (n_ms==NULL)
 				return 0;
 
+			ip_masq_listen(n_ms);
+			ip_masq_control_add(n_ms, ms);
+
 			memcpy(p, &(n_ms->mport), 2);
-#if DEBUG_CONFIG_IP_MASQ_RAUDIO
-			printk("RealAudio: rewrote UDP port %d -> %d\n",
-			       ntohs(udp_port), ntohs(n_ms->mport));
-#endif
-			ip_masq_set_expire(n_ms, ip_masq_expire->udp_timeout);
+			IP_MASQ_DEBUG(1-debug, "RealAudio: rewrote UDP port %d -> %d in msg %d\n",
+			       ntohs(udp_port), ntohs(n_ms->mport), ntohs(msg_id));
 
 			/* Make ref in application data to data connection */
-			if (priv)
-				priv->data_conn = n_ms;
+			if (priv) {
+				if (ntohs(msg_id) == 1)
+					priv->data_conn = n_ms;
+				else
+					priv->error_conn = n_ms;
+			}
+			
+			ip_masq_put(n_ms);
+		}
+	}
+	return 0;
+}
 
-			/*
-			 * There is nothing else useful we can do
-			 * Maybe a development could do more, but for now
-			 * we exit gracefully!
-			 */
-			return 0;
+/*
+ * masq_rtsp_out
+ *
+ * 
+ */
+int
+masq_rtsp_out (struct ip_masq_app *mapp, 
+		 struct ip_masq *ms, 
+		 struct sk_buff **skb_p, 
+		 __u32 maddr)
+{
+        struct sk_buff *skb;
+	struct iphdr *iph;
+	struct tcphdr *th;
+	char *data, *data_limit;
+	struct ip_masq *n_ms, *n_ms2;
+	unsigned short udp_port;
+	struct raudio_priv_data *priv = 
+		(struct raudio_priv_data *)ms->app_data;
+	const char* srch = "transport:";
+	const char* srchpos = srch;
+	const char* srchend = srch + strlen(srch);
+	int state = 0;
+	char firstport[6];
+	int firstportpos = 0;
+	char secondport[6];
+	int secondportpos = 0;
+	char *portstart = NULL, *portend = NULL;
+	int diff;
 
-		} else if (ntohs(msg_id) == 0)
+	/* Everything running correctly already */
+	if (priv && priv->seen_start)
+		return 0;
+
+        skb = *skb_p;
+	iph = skb->nh.iph;
+        th = (struct tcphdr *)&(((char *)iph)[iph->ihl*4]);
+        data = (char *)&th[1];
+
+        data_limit = skb->h.raw + skb->len;
+
+	firstport[0] = 0;
+	secondport[0] = 0;
+
+	while(data < data_limit && state >= 0)
+	{
+	    switch(state)
+	    {
+		case 0:
+		case 1:
+		    if(TOLOWER(*data) == *srchpos)
+		    {
+			srchpos++;
+			if(srchpos == srchend)
+			{
+			    IP_MASQ_DEBUG(1-debug, "Found string %s in message\n",
+				   srch);
+			    state++;
+			    if(state == 1)
+			    {
+				srch = "client_port";
+				srchpos = srch;
+				srchend = srch + strlen(srch);
+			    }
+			}
+		    }
+		    else
+		    {
+			srchpos = srch;
+		    }
+		    break;
+		case 2:
+		    if(*data == '=')
+			state = 3;
+		    break;
+		case 3:
+		    if(ISDIGIT(*data))
+		    {
+			portstart = data;
+			firstportpos = 0;
+			firstport[firstportpos++] = *data;
+			state = 4;
+		    }
+		    break;
+		case 4:
+		    if(*data == '-')
+		    {
+			state = 5;
+		    }
+		    else if(*data == ';')
+		    {
+			portend = data - 1;
+			firstport[firstportpos] = 0;
+			state = -1;
+		    }
+		    else if(ISDIGIT(*data))
+		    {
+			firstport[firstportpos++] = *data;
+		    }
+		    else if(*data != ' ' && *data != '\t')
+		    {
+			/* This is a badly formed RTSP message, let's bail out */
+			IP_MASQ_DEBUG(1-debug, "Badly formed RTSP Message\n");
 			return 0;
+		    }
+		    break;
+		case 5:
+		    if(ISDIGIT(*data))
+		    {
+			secondportpos = 0;
+			secondport[secondportpos++] = *data;
+			state = 6;
+		    }
+		    else if(*data == ';')
+		    {
+			portend = data - 1;
+			secondport[secondportpos] = 0;
+			state = -1;
+		    }
+		    break;
+		case 6:
+		    if(*data == ';')
+		    {
+			portend = data - 1;
+			secondport[secondportpos] = 0;
+			state = -1;
+		    }
+		    else if(ISDIGIT(*data))
+		    {
+			secondport[secondportpos++] = *data;
+		    }
+		    else if(*data != ' ' && *data != '\t')
+		    {
+			/* This is a badly formed RTSP message, let's bail out */
+			IP_MASQ_DEBUG(1-debug, "Badly formed RTSP Message\n");
+			return 0;
+		    }
+		    break;
+	    }
+	    data++;
 	}
-	return 0;
+
+	if(state >= 0)
+	    return 0;
+
+	if(firstportpos > 0)
+	{
+	    char newbuf[12]; /* xxxxx-xxxxx\0 */
+	    char* tmpptr;
+
+	    udp_port = htons(simple_strtoul(firstport, &tmpptr, 10));
+	    n_ms = ip_masq_new(IPPROTO_UDP,
+			       maddr, 0,
+			       ms->saddr, udp_port,
+			       ms->daddr, 0,
+			       IP_MASQ_F_NO_DPORT);
+	    if (n_ms==NULL)
+		return 0;
+	    
+	    ip_masq_listen(n_ms);
+	    ip_masq_control_add(n_ms, ms);
+
+	    if(secondportpos > 0)
+	    {
+		udp_port = htons(simple_strtoul(secondport, &tmpptr, 10));
+		n_ms2 = ip_masq_new(IPPROTO_UDP,
+				maddr, 0,
+				ms->saddr, udp_port,
+				ms->daddr, 0,
+				IP_MASQ_F_NO_DPORT);
+		if (n_ms2==NULL) {
+		    ip_masq_put(n_ms);
+		    return 0;
+		}
+
+		ip_masq_listen(n_ms2);
+		ip_masq_control_add(n_ms2, ms);
+		sprintf(newbuf, "%d-%d", ntohs(n_ms->mport), 
+			ntohs(n_ms2->mport));
+	    }
+	    else
+	    {
+		sprintf(newbuf, "%d", ntohs(n_ms->mport));
+		n_ms2 = NULL;
+	    }
+	    *skb_p = ip_masq_skb_replace(skb, GFP_ATOMIC,
+					 portstart, portend - portstart + 1,
+					 newbuf, strlen(newbuf));
+	    IP_MASQ_DEBUG(1-debug, "RTSP: rewrote client_port to %s\n", newbuf);
+	    diff = strlen(newbuf) - (portend - portstart);
+	}
+	else
+	{
+	    return 0;
+	}
+	    
+	if(priv)
+	{
+	    priv->seen_start = 1;
+	    if(n_ms)
+		priv->data_conn = n_ms;
+	    if(n_ms2)
+		priv->error_conn = n_ms2;
+	}
+	/*
+	 *	Release tunnels
+	 */
+
+	if (n_ms)
+		ip_masq_put(n_ms);
+
+	if (n_ms2)
+		ip_masq_put(n_ms2);
+
+	return diff;
 }
 
 struct ip_masq_app ip_masq_raudio = {
@@ -203,7 +510,27 @@
 
 __initfunc(int ip_masq_raudio_init(void))
 {
-        return register_ip_masq_app(&ip_masq_raudio, IPPROTO_TCP, 7070);
+	int i, j;
+
+	for (i=0; (i<MAX_MASQ_APP_PORTS); i++) {
+		if (ports[i]) {
+			if ((masq_incarnations[i] = kmalloc(sizeof(struct ip_masq_app),
+							    GFP_KERNEL)) == NULL)
+				return -ENOMEM;
+			memcpy(masq_incarnations[i], &ip_masq_raudio, sizeof(struct ip_masq_app));
+			if ((j = register_ip_masq_app(masq_incarnations[i], 
+						      IPPROTO_TCP, 
+						      ports[i]))) {
+				return j;
+			}
+			IP_MASQ_DEBUG(1-debug, "RealAudio: loaded support on port[%d] = %d\n",
+			       i, ports[i]);
+		} else {
+			/* To be safe, force the incarnation table entry to NULL */
+			masq_incarnations[i] = NULL;
+		}
+	}
+	return 0;
 }
 
 /*
@@ -212,7 +539,22 @@
 
 int ip_masq_raudio_done(void)
 {
-        return unregister_ip_masq_app(&ip_masq_raudio);
+	int i, j, k;
+
+	k=0;
+	for (i=0; (i<MAX_MASQ_APP_PORTS); i++) {
+		if (masq_incarnations[i]) {
+			if ((j = unregister_ip_masq_app(masq_incarnations[i]))) {
+				k = j;
+			} else {
+				kfree(masq_incarnations[i]);
+				masq_incarnations[i] = NULL;
+				IP_MASQ_DEBUG(1-debug, "RealAudio: unloaded support on port[%d] = %d\n",
+				       i, ports[i]);
+			}
+		}
+	}
+	return k;
 }
 
 #ifdef MODULE
diff -u --recursive --new-file v2.1.72/linux/net/ipv4/ip_masq_vdolive.c linux/net/ipv4/ip_masq_vdolive.c
--- v2.1.72/linux/net/ipv4/ip_masq_vdolive.c	Wed Dec 31 16:00:00 1969
+++ linux/net/ipv4/ip_masq_vdolive.c	Wed Dec 10 09:45:16 1997
@@ -0,0 +1,291 @@
+/*
+ *		IP_MASQ_VDOLIVE  - VDO Live masquerading module
+ *
+ *
+ * Version:	@(#)$Id: ip_masq_vdolive.c,v 1.2 1997/11/28 15:32:35 alan Exp $
+ *
+ * Author:	Nigel Metheringham <Nigel.Metheringham@ThePLAnet.net>
+ *		PLAnet Online Ltd
+ *
+ * Fixes:	Minor changes for 2.1 by
+ *		Steven Clarke <Steven.Clarke@ThePlanet.Net>, Planet Online Ltd
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License
+ *	as published by the Free Software Foundation; either version
+ *	2 of the License, or (at your option) any later version.
+ *
+ * Thanks:
+ *	Thank you to VDOnet Corporation for allowing me access to
+ *	a protocol description without an NDA.  This means that
+ *	this module can be distributed as source - a great help!
+ *	
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <asm/system.h>
+#include <linux/skbuff.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/init.h>
+#include <net/protocol.h>
+#include <net/tcp.h>
+#include <net/ip_masq.h>
+
+struct vdolive_priv_data {
+	/* Ports used */
+	unsigned short	origport;
+	unsigned short	masqport;
+	/* State of decode */
+	unsigned short	state;
+};
+
+/* 
+ * List of ports (up to MAX_MASQ_APP_PORTS) to be handled by helper
+ * First port is set to the default port.
+ */
+static int ports[MAX_MASQ_APP_PORTS] = {7000}; /* I rely on the trailing items being set to zero */
+struct ip_masq_app *masq_incarnations[MAX_MASQ_APP_PORTS];
+
+/*
+ *     Debug level
+ */
+static int debug=0;
+
+MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_MASQ_APP_PORTS) "i");
+MODULE_PARM(debug, "i");
+
+static int
+masq_vdolive_init_1 (struct ip_masq_app *mapp, struct ip_masq *ms)
+{
+	MOD_INC_USE_COUNT;
+	if ((ms->app_data = kmalloc(sizeof(struct vdolive_priv_data),
+				    GFP_ATOMIC)) == NULL) 
+		IP_MASQ_DEBUG(1-debug, "VDOlive: No memory for application data\n");
+	else 
+	{
+		struct vdolive_priv_data *priv = 
+			(struct vdolive_priv_data *)ms->app_data;
+		priv->origport = 0;
+		priv->masqport = 0;
+		priv->state = 0;
+	}
+        return 0;
+}
+
+static int
+masq_vdolive_done_1 (struct ip_masq_app *mapp, struct ip_masq *ms)
+{
+        MOD_DEC_USE_COUNT;
+	if (ms->app_data)
+		kfree_s(ms->app_data, sizeof(struct vdolive_priv_data));
+        return 0;
+}
+
+int
+masq_vdolive_out (struct ip_masq_app *mapp, struct ip_masq *ms, struct sk_buff **skb_p, __u32 maddr)
+{
+        struct sk_buff *skb;
+	struct iphdr *iph;
+	struct tcphdr *th;
+	char *data, *data_limit;
+	unsigned int tagval;	/* This should be a 32 bit quantity */
+	struct ip_masq *n_ms;
+	struct vdolive_priv_data *priv = 
+		(struct vdolive_priv_data *)ms->app_data;
+
+	/* This doesn't work at all if no priv data was allocated on startup */
+	if (!priv)
+		return 0;
+
+	/* Everything running correctly already */
+	if (priv->state == 3)
+		return 0;
+
+        skb = *skb_p;
+	iph = skb->nh.iph;
+        th = (struct tcphdr *)&(((char *)iph)[iph->ihl*4]);
+        data = (char *)&th[1];
+
+        data_limit = skb->h.raw + skb->len;
+
+	if (data+8 > data_limit) {
+		IP_MASQ_DEBUG(1-debug, "VDOlive: packet too short for ID %p %p\n", data, data_limit);
+		return 0;
+	}
+	memcpy(&tagval, data+4, 4);
+	IP_MASQ_DEBUG(1-debug, "VDOlive: packet seen, tag %ld, in initial state %d\n", ntohl(tagval), priv->state);
+
+	/* Check for leading packet ID */
+	if ((ntohl(tagval) != 6) && (ntohl(tagval) != 1)) {
+		IP_MASQ_DEBUG(1-debug, "VDOlive: unrecognised tag %ld, in initial state %d\n", ntohl(tagval), priv->state);
+		return 0;
+	}
+		
+
+	/* Check packet is long enough for data - ignore if not */
+	if ((ntohl(tagval) == 6) && (data+36 > data_limit)) {
+		IP_MASQ_DEBUG(1-debug, "VDOlive: initial packet too short %p %p\n", data, data_limit);
+		return 0;
+	} else if ((ntohl(tagval) == 1) && (data+20 > data_limit)) {
+		IP_MASQ_DEBUG(1-debug,"VDOlive: secondary packet too short %p %p\n", data, data_limit);
+		return 0;
+	}
+
+	/* Adjust data pointers */
+	/*
+	 * I could check the complete protocol version tag 
+	 * in here however I am just going to look for the
+	 * "VDO Live" tag in the hope that this part will
+	 * remain constant even if the version changes
+	 */
+	if (ntohl(tagval) == 6) {
+		data += 24;
+		IP_MASQ_DEBUG(1-debug, "VDOlive: initial packet found\n");
+	} else {
+		data += 8;
+		IP_MASQ_DEBUG(1-debug, "VDOlive: secondary packet found\n");
+	}
+
+	if (memcmp(data, "VDO Live", 8) != 0) {
+		IP_MASQ_DEBUG(1-debug,"VDOlive: did not find tag\n");
+		return 0;
+	}
+	/* 
+	 * The port number is the next word after the tag.
+	 * VDOlive encodes all of these values
+	 * in 32 bit words, so in this case I am
+	 * skipping the first 2 bytes of the next
+	 * word to get to the relevant 16 bits
+	 */
+	data += 10;
+
+	/*
+	 * If we have not seen the port already,
+	 * set the masquerading tunnel up
+	 */
+	if (!priv->origport) {
+		memcpy(&priv->origport, data, 2);
+		IP_MASQ_DEBUG(1-debug, "VDOlive: found port %d\n", ntohs(priv->origport));
+
+		/* Open up a tunnel */
+		n_ms = ip_masq_new(IPPROTO_UDP,
+				   maddr, 0,
+				   ms->saddr, priv->origport,
+				   ms->daddr, 0,
+				   IP_MASQ_F_NO_DPORT);
+					
+		if (n_ms==NULL) {
+		        ip_masq_put(n_ms);
+			IP_MASQ_DEBUG(1-debug, "VDOlive: unable to build UDP tunnel for %x:%x\n", ms->saddr, priv->origport);
+			/* Leave state as unset */
+			priv->origport = 0;
+			return 0;
+		}
+		ip_masq_listen(n_ms);
+
+		ip_masq_put(ms);
+		priv->masqport = n_ms->mport;
+	} else if (memcmp(data, &(priv->origport), 2)) {
+		IP_MASQ_DEBUG(1-debug, "VDOlive: ports do not match\n");
+		/* Write the port in anyhow!!! */
+	}
+
+	/*
+	 * Write masq port into packet
+	 */
+	memcpy(data, &(priv->masqport), 2);
+	IP_MASQ_DEBUG(1-debug, "VDOlive: rewrote port %d to %d, server %08X\n", ntohs(priv->origport), ntohs(priv->masqport), ms->saddr);
+
+	/*
+	 * Set state bit to make which bit has been done
+	 */
+
+	priv->state |= (ntohl(tagval) == 6) ? 1 : 2;
+
+	return 0;
+}
+
+
+struct ip_masq_app ip_masq_vdolive = {
+        NULL,			/* next */
+	"VDOlive",	       	/* name */
+        0,                      /* type */
+        0,                      /* n_attach */
+        masq_vdolive_init_1,	/* ip_masq_init_1 */
+        masq_vdolive_done_1,	/* ip_masq_done_1 */
+        masq_vdolive_out,	/* pkt_out */
+        NULL                    /* pkt_in */
+};
+
+/*
+ * 	ip_masq_vdolive initialization
+ */
+
+__initfunc(int ip_masq_vdolive_init(void))
+{
+	int i, j;
+
+	for (i=0; (i<MAX_MASQ_APP_PORTS); i++) {
+		if (ports[i]) {
+			if ((masq_incarnations[i] = kmalloc(sizeof(struct ip_masq_app),
+							    GFP_KERNEL)) == NULL)
+				return -ENOMEM;
+			memcpy(masq_incarnations[i], &ip_masq_vdolive, sizeof(struct ip_masq_app));
+			if ((j = register_ip_masq_app(masq_incarnations[i], 
+						      IPPROTO_TCP, 
+						      ports[i]))) {
+				return j;
+			}
+			IP_MASQ_DEBUG(1-debug, "RealAudio: loaded support on port[%d] = %d\n", i, ports[i]);
+		} else {
+			/* To be safe, force the incarnation table entry to NULL */
+			masq_incarnations[i] = NULL;
+		}
+	}
+	return 0;
+}
+
+/*
+ * 	ip_masq_vdolive fin.
+ */
+
+int ip_masq_vdolive_done(void)
+{
+	int i, j, k;
+
+	k=0;
+	for (i=0; (i<MAX_MASQ_APP_PORTS); i++) {
+		if (masq_incarnations[i]) {
+			if ((j = unregister_ip_masq_app(masq_incarnations[i]))) {
+				k = j;
+			} else {
+				kfree(masq_incarnations[i]);
+				masq_incarnations[i] = NULL;
+				IP_MASQ_DEBUG(1-debug,"VDOlive: unloaded support on port[%d] = %d\n", i, ports[i]);
+			}
+		}
+	}
+	return k;
+}
+
+
+#ifdef MODULE
+EXPORT_NO_SYMBOLS;
+
+int init_module(void)
+{
+        if (ip_masq_vdolive_init() != 0)
+                return -EIO;
+        return 0;
+}
+
+void cleanup_module(void)
+{
+        if (ip_masq_vdolive_done() != 0)
+                IP_MASQ_DEBUG(1-debug, "ip_masq_vdolive: can't remove module");
+}
+
+#endif /* MODULE */
diff -u --recursive --new-file v2.1.72/linux/net/ipv4/ip_output.c linux/net/ipv4/ip_output.c
--- v2.1.72/linux/net/ipv4/ip_output.c	Mon Dec  1 12:04:16 1997
+++ linux/net/ipv4/ip_output.c	Wed Dec 10 09:45:16 1997
@@ -5,7 +5,7 @@
  *
  *		The Internet Protocol (IP) output module.
  *
- * Version:	$Id: ip_output.c,v 1.40 1997/10/12 17:01:48 kuznet Exp $
+ * Version:	$Id: ip_output.c,v 1.41 1997/11/28 15:32:37 alan Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -69,6 +69,12 @@
 #include <linux/mroute.h>
 #include <linux/netlink.h>
 #include <linux/ipsec.h>
+
+/*
+ *      Shall we try to damage output packets if routing dev changes?
+ */
+
+int sysctl_ip_dynaddr = 0;
 
 static void __inline__ ip_ll_header_reserve(struct sk_buff *skb)
 {
diff -u --recursive --new-file v2.1.72/linux/net/ipv4/ip_sockglue.c linux/net/ipv4/ip_sockglue.c
--- v2.1.72/linux/net/ipv4/ip_sockglue.c	Mon Dec  1 12:04:16 1997
+++ linux/net/ipv4/ip_sockglue.c	Wed Dec 10 09:45:16 1997
@@ -5,7 +5,7 @@
  *
  *		The IP to API glue.
  *		
- * Version:	$Id: ip_sockglue.c,v 1.28 1997/11/17 17:36:08 kuznet Exp $
+ * Version:	$Id: ip_sockglue.c,v 1.29 1997/11/28 15:32:39 alan Exp $
  *
  * Authors:	see ip.c
  *
@@ -229,7 +229,10 @@
 	int val=0,err;
 #if defined(CONFIG_IP_FIREWALL) || defined(CONFIG_IP_ACCT)
 	struct ip_fw tmp_fw;
-#endif	
+#endif
+#ifdef CONFIG_IP_MASQUERADE
+	char masq_ctl[IP_FW_MASQCTL_MAX];
+#endif
 
 	if(optlen>=sizeof(int)) {
 		if(get_user(val, (int *) optval))
@@ -462,6 +465,20 @@
 			if(copy_from_user(&tmp_fw,optval,optlen))
 				return -EFAULT;
 			err=ip_fw_ctl(optname, &tmp_fw,optlen);
+			return -err;	/* -0 is 0 after all */
+			
+#endif
+#ifdef CONFIG_IP_MASQUERADE
+		case IP_FW_MASQ_ADD:
+		case IP_FW_MASQ_DEL:
+		case IP_FW_MASQ_FLUSH:
+			if(!suser())
+				return -EPERM;
+			if(optlen>sizeof(masq_ctl) || optlen<1)
+				return -EINVAL;
+			if(copy_from_user(masq_ctl,optval,optlen))
+				return -EFAULT;
+			err=ip_masq_ctl(optname, masq_ctl,optlen);
 			return -err;	/* -0 is 0 after all */
 			
 #endif
diff -u --recursive --new-file v2.1.72/linux/net/ipv4/route.c linux/net/ipv4/route.c
--- v2.1.72/linux/net/ipv4/route.c	Mon Dec  1 12:04:16 1997
+++ linux/net/ipv4/route.c	Wed Dec 10 09:45:16 1997
@@ -5,7 +5,7 @@
  *
  *		ROUTE - implementation of the IP router.
  *
- * Version:	$Id: route.c,v 1.33 1997/10/24 17:16:08 kuznet Exp $
+ * Version:	$Id: route.c,v 1.34 1997/12/04 03:42:22 freitag Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -1000,6 +1000,8 @@
 	rth->u.dst.pmtu	= res.fi->fib_mtu ? : out_dev->dev->mtu;
 	rth->u.dst.window=res.fi->fib_window ? : 0;
 	rth->u.dst.rtt	= res.fi->fib_rtt ? : TCP_TIMEOUT_INIT;
+	rth->u.dst.rate_last = rth->u.dst.rate_tokens = 0; 
+
 	if (FIB_RES_GW(res) && FIB_RES_NH(res).nh_scope == RT_SCOPE_LINK)
 		rth->rt_gateway	= FIB_RES_GW(res);
 
@@ -1370,6 +1372,7 @@
 		rth->u.dst.window=0;
 		rth->u.dst.rtt	= TCP_TIMEOUT_INIT;
 	}
+	rth->u.dst.rate_last = rth->u.dst.rate_tokens = 0; 
 	rth->rt_flags = flags;
         rth->rt_type = res.type;
 	hash = rt_hash_code(daddr, saddr^(oif<<5), tos);
diff -u --recursive --new-file v2.1.72/linux/net/ipv4/sysctl_net_ipv4.c linux/net/ipv4/sysctl_net_ipv4.c
--- v2.1.72/linux/net/ipv4/sysctl_net_ipv4.c	Mon Dec  1 12:04:16 1997
+++ linux/net/ipv4/sysctl_net_ipv4.c	Wed Dec 10 09:45:16 1997
@@ -1,7 +1,7 @@
 /*
  * sysctl_net_ipv4.c: sysctl interface to net IPV4 subsystem.
  *
- * $Id: sysctl_net_ipv4.c,v 1.21 1997/10/17 01:21:18 davem Exp $
+ * $Id: sysctl_net_ipv4.c,v 1.22 1997/11/28 15:32:42 alan Exp $
  *
  * Begun April 1, 1996, Mike Shaver.
  * Added /proc/sys/net/ipv4 directory entry (empty =) ). [MS]
@@ -47,6 +47,12 @@
 extern int sysctl_ipfrag_high_thresh; 
 extern int sysctl_ipfrag_time;
 
+/* From ip_output.c */
+extern int sysctl_ip_dynaddr;
+
+/* From ip_masq.c */
+extern int sysctl_ip_masq_debug;
+
 extern int sysctl_tcp_cong_avoidance;
 extern int sysctl_tcp_hoe_retransmits;
 extern int sysctl_tcp_sack;
@@ -198,6 +204,12 @@
 	 &sysctl_ipfrag_high_thresh, sizeof(int), 0644, NULL, &proc_dointvec},
 	{NET_IPV4_IPFRAG_LOW_THRESH, "ipfrag_low_thresh",
 	 &sysctl_ipfrag_low_thresh, sizeof(int), 0644, NULL, &proc_dointvec},
+	{NET_IPV4_IP_DYNADDR, "ip_dynaddr",
+	 &sysctl_ip_dynaddr, sizeof(int), 0644, NULL, &proc_dointvec},
+#ifdef CONFIG_IP_MASQUERADE
+	{NET_IPV4_IP_MASQ_DEBUG, "ip_masq_debug",
+	 &sysctl_ip_masq_debug, sizeof(int), 0644, NULL, &proc_dointvec},
+#endif
 	{NET_IPV4_IPFRAG_TIME, "ipfrag_time",
 	 &sysctl_ipfrag_time, sizeof(int), 0644, NULL, &proc_dointvec_jiffies},
 	{NET_IPV4_TCP_MAX_KA_PROBES, "tcp_max_ka_probes",
diff -u --recursive --new-file v2.1.72/linux/net/ipv4/tcp_ipv4.c linux/net/ipv4/tcp_ipv4.c
--- v2.1.72/linux/net/ipv4/tcp_ipv4.c	Wed Dec 10 11:12:46 1997
+++ linux/net/ipv4/tcp_ipv4.c	Wed Dec 10 09:47:56 1997
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp_ipv4.c,v 1.74 1997/10/30 23:52:27 davem Exp $
+ * Version:	$Id: tcp_ipv4.c,v 1.76 1997/12/07 04:44:19 freitag Exp $
  *
  *		IPv4 specific functions
  *
@@ -40,6 +40,7 @@
  *					Added tail drop and some other bugfixes.
  *					Added new listen sematics (ifdefed by
  *					NEW_LISTEN for now)
+ *	Juan Jose Ciarlante:		ip_dynaddr bits
  */
 
 #include <linux/config.h>
@@ -47,6 +48,7 @@
 #include <linux/fcntl.h>
 #include <linux/random.h>
 #include <linux/ipsec.h>
+#include <linux/inet.h>
 
 #include <net/icmp.h>
 #include <net/tcp.h>
@@ -59,6 +61,7 @@
 extern int sysctl_tcp_timestamps;
 extern int sysctl_tcp_window_scaling;
 extern int sysctl_tcp_syncookies;
+extern int sysctl_ip_dynaddr;
 
 /* Check TCP sequence numbers in ICMP packets. */
 #define ICMP_PARANOIA 1 
@@ -846,31 +849,6 @@
 		return; 
 	}
 
-	/* pointless, because we have no way to retry when sk is locked.
-	   But the socket should be really locked here for better interaction
-	   with the socket layer. This needs to be solved for SMP
-	   (I would prefer an "ICMP backlog").
-
-	   tcp_v4_err is called only from bh, so that lock_sock is pointless,
-	   even in commented form :-) --ANK
-	   
-	   Note "for SMP" ;) -AK
-
-	   Couple of notes about backlogging:
-	   - error_queue could be used for it.
-	   - could, but MUST NOT :-), because:
-	     a) it is not clear,
-	        who will process deferred messages.
-	     b) ICMP is not reliable by design, so that you can safely
-	        drop ICMP messages. Besides that, if ICMP really arrived
-		it is very unlikely, that socket is locked. 	--ANK
-
-            I don't think it's unlikely that sk is locked. With the 
-	    open_request stuff there is much more stress on the main
-	    LISTEN socket. I just want to make sure that all ICMP unreachables
-	    destroy unneeded open_requests as reliable as possible (for
-	    syn flood protection) -AK
-	*/
 	tp = &sk->tp_pinfo.af_tcp;
 #ifdef ICMP_PARANOIA
 	seq = ntohl(th->seq);
@@ -1617,10 +1595,31 @@
 	struct iphdr *iph;
 	struct tcphdr *th;
 	int size;
+        int want_rewrite = sysctl_ip_dynaddr && sk->state == TCP_SYN_SENT;
 
 	/* Check route */
 
 	rt = (struct rtable*)skb->dst;
+
+	/* Force route checking if want_rewrite */
+	if (want_rewrite) {
+		int tmp;
+		__u32 old_saddr = rt->rt_src;
+
+		/* Query new route */
+		tmp = ip_route_connect(&rt, rt->rt_dst, 0, 
+					RT_TOS(sk->ip_tos)|(sk->localroute||0),
+					sk->bound_dev_if);
+
+		/* Only useful if different source addrs */
+		if (tmp == 0 || rt->rt_src != old_saddr ) {
+			dst_release(skb->dst);
+			skb->dst = &rt->u.dst;
+		} else {
+			want_rewrite = 0;
+			dst_release(&rt->u.dst);
+		}
+	} else 
 	if (rt->u.dst.obsolete) {
 		int err;
 		err = ip_route_output(&rt, rt->rt_dst, rt->rt_src, rt->key.tos, rt->key.oif);
@@ -1639,6 +1638,50 @@
 	iph = skb->nh.iph;
 	th = skb->h.th;
 	size = skb->tail - skb->h.raw;
+
+        if (want_rewrite) {
+        	__u32 new_saddr = rt->rt_src;
+                
+                /*
+                 *	Ouch!, this should not happen.
+                 */
+                if (!sk->saddr || !sk->rcv_saddr) {
+                	printk(KERN_WARNING "tcp_v4_rebuild_header(): not valid sock addrs: saddr=%08lX rcv_saddr=%08lX\n",
+			       ntohl(sk->saddr), 
+			       ntohl(sk->rcv_saddr));
+                        return 0;
+                }
+
+		/*
+		 *	Maybe whe are in a skb chain loop and socket address has
+		 *	yet been 'damaged'.
+		 */
+
+		if (new_saddr != sk->saddr) {
+			if (sysctl_ip_dynaddr > 1) {
+				printk(KERN_INFO "tcp_v4_rebuild_header(): shifting sk->saddr from %d.%d.%d.%d to %d.%d.%d.%d\n",
+					NIPQUAD(sk->saddr), 
+					NIPQUAD(new_saddr));
+			}
+
+			sk->saddr = new_saddr;
+			sk->rcv_saddr = new_saddr;
+			/* sk->prot->rehash(sk); */
+			tcp_v4_rehash(sk);
+		} 
+
+		if (new_saddr != iph->saddr) {
+			if (sysctl_ip_dynaddr > 1) {
+				printk(KERN_INFO "tcp_v4_rebuild_header(): shifting iph->saddr from %d.%d.%d.%d to %d.%d.%d.%d\n",
+					NIPQUAD(iph->saddr), 
+					NIPQUAD(new_saddr));
+			}
+
+			iph->saddr = new_saddr;
+			ip_send_check(iph);
+		} 
+        
+        }
 
 	return 0;
 }
diff -u --recursive --new-file v2.1.72/linux/net/ipv4/tcp_timer.c linux/net/ipv4/tcp_timer.c
--- v2.1.72/linux/net/ipv4/tcp_timer.c	Mon Dec  1 12:04:17 1997
+++ linux/net/ipv4/tcp_timer.c	Wed Dec 10 09:45:16 1997
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp_timer.c,v 1.31 1997/11/05 08:14:01 freitag Exp $
+ * Version:	$Id: tcp_timer.c,v 1.32 1997/12/08 07:03:29 freitag Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -44,6 +44,8 @@
 	{ATOMIC_INIT(0), TCP_KEEPALIVE_PERIOD, 0, tcp_keepalive}   /* KEEPALIVE	*/
 };
 
+const char timer_bug_msg[] = KERN_DEBUG "tcpbug: unknown timer value\n";
+
 /*
  * Using different timers for retransmit, delayed acks and probes
  * We may wish use just one timer maintaining a list of expire jiffies 
@@ -112,45 +114,6 @@
 	};
 }
 
-void tcp_clear_xmit_timer(struct sock *sk, int what)
-{
-	struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
-
-	switch (what) {
-	case TIME_RETRANS:
-		del_timer(&tp->retransmit_timer);
-		break;
-	case TIME_DACK:
-		del_timer(&tp->delack_timer);
-		break;
-	case TIME_PROBE0:
-		del_timer(&tp->probe_timer);
-		break;	
-	default:
-		printk(KERN_DEBUG "bug: unknown timer value\n");
-	};
-}
-
-int tcp_timer_is_set(struct sock *sk, int what)
-{
-	struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
-
-	switch (what) {
-	case TIME_RETRANS:
-		return tp->retransmit_timer.next != NULL;
-		break;
-	case TIME_DACK:
-		return tp->delack_timer.next != NULL;
-		break;
-	case TIME_PROBE0:
-		return tp->probe_timer.next != NULL;
-		break;	
-	default:
-		printk(KERN_DEBUG "bug: unknown timer value\n");
-	};
-	return 0;
-}
-
 void tcp_clear_xmit_timers(struct sock *sk)
 {	
 	struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
@@ -160,6 +123,25 @@
 	del_timer(&tp->probe_timer);
 }
 
+static int tcp_write_err(struct sock *sk, int force)
+{
+	sk->err = sk->err_soft ? sk->err_soft : ETIMEDOUT;
+	sk->error_report(sk);
+	
+	tcp_clear_xmit_timers(sk);
+	
+	/* Time wait the socket. */
+	if (!force && (1<<sk->state) & (TCPF_FIN_WAIT1|TCPF_FIN_WAIT2|TCPF_CLOSING)) {
+		tcp_set_state(sk,TCP_TIME_WAIT);
+		tcp_reset_msl_timer (sk, TIME_CLOSE, TCP_TIMEWAIT_LEN);
+	} else {
+		/* Clean up time. */
+		tcp_set_state(sk, TCP_CLOSE);
+		return 0;
+	}
+	return 1;
+}
+
 /*
  *	A write timeout has occurred. Process the after effects. BROKEN (badly)
  */
@@ -172,10 +154,7 @@
 	 *	Look for a 'soft' timeout.
 	 */
 	if ((sk->state == TCP_ESTABLISHED &&
-
-	     /* Eric, what the heck is this doing?!?! */
-	     tp->retransmits && !(tp->retransmits & 7)) ||
-
+	     tp->retransmits && (tp->retransmits % TCP_QUICK_TRIES) == 0) ||
 	    (sk->state != TCP_ESTABLISHED && tp->retransmits > sysctl_tcp_retries1)) {
 		/*	Attempt to recover if arp has changed (unlikely!) or
 		 *	a route has shifted (not supported prior to 1.3).
@@ -185,42 +164,15 @@
 	
 	/* Have we tried to SYN too many times (repent repent 8)) */
 	if(tp->retransmits > sysctl_tcp_syn_retries && sk->state==TCP_SYN_SENT) {
-		if(sk->err_soft)
-			sk->err=sk->err_soft;
-		else
-			sk->err=ETIMEDOUT;
-#ifdef TCP_DEBUG
-		printk(KERN_DEBUG "syn timeout\n");
-#endif
-
-		sk->error_report(sk);
-		tcp_clear_xmit_timers(sk);
-		tcp_statistics.TcpAttemptFails++;	/* Is this right ??? - FIXME - */
-		tcp_set_state(sk,TCP_CLOSE);
+		tcp_write_err(sk, 1);
 		/* Don't FIN, we got nothing back */
 		return 0;
 	}
 
 	/* Has it gone just too far? */
-	if (tp->retransmits > sysctl_tcp_retries2) {
-		if(sk->err_soft)
-			sk->err = sk->err_soft;
-		else
-			sk->err = ETIMEDOUT;
-		sk->error_report(sk);
-
-		tcp_clear_xmit_timers(sk);
-
-		/* Time wait the socket. */
-		if ((1<<sk->state) & (TCPF_FIN_WAIT1|TCPF_FIN_WAIT2|TCPF_CLOSING)) {
-			tcp_set_state(sk,TCP_TIME_WAIT);
-			tcp_reset_msl_timer (sk, TIME_CLOSE, TCP_TIMEWAIT_LEN);
-		} else {
-			/* Clean up time. */
-			tcp_set_state(sk, TCP_CLOSE);
-			return 0;
-		}
-	}
+	if (tp->retransmits > sysctl_tcp_retries2) 
+		return tcp_write_err(sk, 0);
+
 	return 1;
 }
 
@@ -251,7 +203,8 @@
 	}
 
 	/*
-	 *	*WARNING* RFC 1122 forbids this
+	 *	*WARNING* RFC 1122 forbids this 
+	 * 	It doesn't AFAIK, because we kill the retransmit timer -AK
 	 *	FIXME: We ought not to do it, Solaris 2.5 actually has fixing
 	 *	this behaviour in Solaris down as a bug fix. [AC]
 	 */
diff -u --recursive --new-file v2.1.72/linux/net/ipv4/udp.c linux/net/ipv4/udp.c
--- v2.1.72/linux/net/ipv4/udp.c	Mon Dec  1 12:04:17 1997
+++ linux/net/ipv4/udp.c	Wed Dec 10 09:45:16 1997
@@ -5,7 +5,7 @@
  *
  *		The User Datagram Protocol (UDP).
  *
- * Version:	$Id: udp.c,v 1.44 1997/10/15 19:56:35 freitag Exp $
+ * Version:	$Id: udp.c,v 1.45 1997/12/04 03:55:17 freitag Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -53,6 +53,8 @@
  *					Last socket cache retained as it
  *					does have a high hit rate.
  *		Olaf Kirch	:	Don't linearise iovec on sendmsg.
+ *		Andi Kleen	:	Some cleanups, cache destination entry
+ *					for connect. 
  *
  *
  *		This program is free software; you can redistribute it and/or
@@ -69,7 +71,7 @@
      MUST pass IP options from IP -> application (OK)
      MUST allow application to specify IP options (OK)
    4.1.3.3 (ICMP Messages)
-     MUST pass ICMP error messages to application (OK)
+     MUST pass ICMP error messages to application (OK -- except when SO_BSDCOMPAT is set)
    4.1.3.4 (UDP Checksums)
      MUST provide facility for checksumming (OK)
      MAY allow application to control checksumming (OK)
@@ -78,12 +80,10 @@
    4.1.3.5 (UDP Multihoming)
      MUST allow application to specify source address (OK)
      SHOULD be able to communicate the chosen src addr up to application
-       when application doesn't choose (NOT YET - doesn't seem to be in the BSD API)
-       [Does opening a SOCK_PACKET and snooping your output count 8)]
+       when application doesn't choose (DOES - use recvmsg cmsgs)
    4.1.3.6 (Invalid Addresses)
      MUST discard invalid source addresses (OK -- done in the new routing code)
-     MUST only send datagrams with one of our addresses (NOT YET - ought to be OK )
-   950728 -- MS
+     MUST only send datagrams with one of our addresses (OK)
 */
 
 #include <asm/system.h>
@@ -459,8 +459,6 @@
   	return s;
 }
 
-#define min(a,b)	((a)<(b)?(a):(b))
-
 /*
  * This routine is called by the ICMP module when it gets some
  * sort of error condition.  If err < 0 then the socket should
@@ -497,33 +495,27 @@
 			kfree_skb(skb2, FREE_READ);
 	}
   	
-	if (type == ICMP_SOURCE_QUENCH) {
-#if 0 /* FIXME:	If you check the rest of the code, this is a NOP!
-       * 	Someone figure out what we were trying to be doing
-       * 	here.  Besides, cong_window is a TCP thing and thus
-       * 	I moved it out of normal sock and into tcp_opt.
-       */
-		/* Slow down! */
-		if (sk->cong_window > 1) 
-			sk->cong_window = sk->cong_window/2;
-#endif
+	switch (type) {
+	case ICMP_SOURCE_QUENCH:
 		return;
-	}
-
-	if (type == ICMP_PARAMETERPROB)
-	{
+	case ICMP_PARAMETERPROB:
 		sk->err = EPROTO;
 		sk->error_report(sk);
 		return;
-	}
-
-	if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED)
-	{
-		if (sk->ip_pmtudisc != IP_PMTUDISC_DONT) {
-			sk->err = EMSGSIZE;
-			sk->error_report(sk);
+	case ICMP_DEST_UNREACH:
+		if (code == ICMP_FRAG_NEEDED) { /* Path MTU discovery */
+			if (sk->ip_pmtudisc != IP_PMTUDISC_DONT) {
+				/* 
+				 * There should be really a way to pass the
+				 * discovered MTU value back to the user (the
+				 * ICMP layer did all the work for us)
+				 */
+				sk->err = EMSGSIZE;
+				sk->error_report(sk);
+			}
+			return;
 		}
-		return;
+		break;
 	}
 			
 	/*
@@ -622,8 +614,8 @@
 	int ulen = len + sizeof(struct udphdr);
 	struct ipcm_cookie ipc;
 	struct udpfakehdr ufh;
-	struct rtable *rt;
-	int free = 0;
+	struct rtable *rt = NULL;
+	int free = 0, localroute = 0;
 	u32 daddr;
 	u8  tos;
 	int err;
@@ -635,12 +627,13 @@
 	 *	Check the flags.
 	 */
 
-	if (msg->msg_flags&MSG_OOB)		/* Mirror BSD error message compatibility */
+	if (msg->msg_flags&MSG_OOB)	/* Mirror BSD error message compatibility */
 		return -EOPNOTSUPP;
 
 	if (msg->msg_flags&~(MSG_DONTROUTE|MSG_DONTWAIT))
 	  	return -EINVAL;
 
+
 	/*
 	 *	Get and verify the address. 
 	 */
@@ -660,11 +653,13 @@
 		ufh.uh.dest = usin->sin_port;
 		if (ufh.uh.dest == 0)
 			return -EINVAL;
+		/* XXX: is a one-behind cache for the dst_entry worth it? */
 	} else {
 		if (sk->state != TCP_ESTABLISHED)
 			return -EINVAL;
 		ufh.daddr = sk->daddr;
 		ufh.uh.dest = sk->dummy_th.dest;
+		rt = (struct rtable *)sk->dst_cache;
   	}
 
 	ipc.addr = sk->saddr;
@@ -688,9 +683,13 @@
 			return -EINVAL;
 		daddr = ipc.opt->faddr;
 	}
-	tos = RT_TOS(sk->ip_tos) | (sk->localroute || (msg->msg_flags&MSG_DONTROUTE) ||
-				    (ipc.opt && ipc.opt->is_strictroute));
-
+	tos = RT_TOS(sk->ip_tos);
+	if (sk->localroute || (msg->msg_flags&MSG_DONTROUTE) || 
+	    (ipc.opt && ipc.opt->is_strictroute)) {
+		tos |= 1;
+		rt = NULL; /* sorry */
+	}
+		
 	if (MULTICAST(daddr)) {
 		if (!ipc.oif)
 			ipc.oif = sk->ip_mc_index;
@@ -698,17 +697,15 @@
 			ufh.saddr = sk->ip_mc_addr;
 	}
 
-	err = ip_route_output(&rt, daddr, ufh.saddr, tos, ipc.oif);
-
-	if (err) {
-		if (free) kfree(ipc.opt);
-		return err;
-	}
+	if (rt == NULL) {
+		err = ip_route_output(&rt, daddr, ufh.saddr, tos, ipc.oif);
+		if (err) 
+			goto out;
+		localroute = 1;
 
-	if (rt->rt_flags&RTCF_BROADCAST && !sk->broadcast) {
-		if (free) kfree(ipc.opt);
-		ip_rt_put(rt);
-		return -EACCES;
+		err = -EACCES;
+		if (rt->rt_flags&RTCF_BROADCAST && !sk->broadcast) 
+			goto out;
 	}
 
 	ufh.saddr = rt->rt_src;
@@ -727,15 +724,13 @@
 	/* violation above. -- MS */
 
 	lock_sock(sk);
-	if (sk->no_check)
-		err = ip_build_xmit(sk, udp_getfrag_nosum, &ufh, ulen, 
-				    &ipc, rt, msg->msg_flags);
-	else
-		err = ip_build_xmit(sk, udp_getfrag, &ufh, ulen, 
-				    &ipc, rt, msg->msg_flags);
-	ip_rt_put(rt);
+	err = ip_build_xmit(sk,sk->no_check ? udp_getfrag_nosum : udp_getfrag,
+			    &ufh, ulen, &ipc, rt, msg->msg_flags);
 	release_sock(sk);
 
+out:
+	if (localroute)
+		ip_rt_put(rt);
 	if (free)
 		kfree(ipc.opt);
 	if (!err) {
@@ -776,7 +771,7 @@
 				 * of this packet since that is all
 				 * that will be read.
 				 */
-				amount = skb->len-sizeof(struct udphdr);
+				amount = skb->tail - skb->h.raw;
 			}
 			return put_user(amount, (int *)arg);
 		}
@@ -905,6 +900,9 @@
 	if (usin->sin_family && usin->sin_family != AF_INET) 
 	  	return(-EAFNOSUPPORT);
 
+	dst_release(sk->dst_cache);
+	sk->dst_cache = NULL;
+
 	err = ip_route_connect(&rt, usin->sin_addr.s_addr, sk->saddr,
 			       sk->ip_tos|sk->localroute, sk->bound_dev_if);
 	if (err)
@@ -920,9 +918,11 @@
 	sk->daddr = rt->rt_dst;
 	sk->dummy_th.dest = usin->sin_port;
 	sk->state = TCP_ESTABLISHED;
+
 	if(uh_cache_sk == sk)
 		uh_cache_sk = NULL;
-	ip_rt_put(rt);
+
+	sk->dst_cache = &rt->u.dst;
 	return(0);
 }
 
@@ -1073,13 +1073,6 @@
 		kfree_skb(skb, FREE_WRITE);
 		return(0);
 	}
-
-	/* RFC1122 warning: According to 4.1.3.6, we MUST discard any */
-	/* datagram which has an invalid source address, either here or */
-	/* in IP. */
-	/* Right now, IP isn't doing it, and neither is UDP. It's on the */
-	/* FIXME list for IP, though, so I wouldn't worry about it. */
-	/* (That's the Right Place to do it, IMHO.) -- MS */
 
 	if (uh->check &&
 	    (((skb->ip_summed==CHECKSUM_HW)&&udp_check(uh,len,saddr,daddr,skb->csum)) ||
diff -u --recursive --new-file v2.1.72/linux/net/ipv6/addrconf.c linux/net/ipv6/addrconf.c
--- v2.1.72/linux/net/ipv6/addrconf.c	Mon Dec  1 12:04:17 1997
+++ linux/net/ipv6/addrconf.c	Wed Dec 10 09:45:16 1997
@@ -5,7 +5,7 @@
  *	Authors:
  *	Pedro Roque		<roque@di.fc.ul.pt>	
  *
- *	$Id: addrconf.c,v 1.28 1997/11/05 20:20:43 kuznet Exp $
+ *	$Id: addrconf.c,v 1.30 1997/12/09 17:12:47 freitag Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -18,6 +18,8 @@
  *
  *	Janos Farkas			:	delete timer on ifdown
  *	<chexum@bankinf.banki.hu>
+ *	Andi Kleen			:	kill doube kfree on module
+ *						unload.
  */
 
 #include <linux/config.h>
@@ -1045,7 +1047,6 @@
 	return NOTIFY_OK;
 }
 
-
 static int addrconf_ifdown(struct device *dev)
 {
 	struct inet6_dev *idev, **bidev;
@@ -1067,6 +1068,8 @@
 
 	if (idev == NULL) {
 		end_bh_atomic();
+
+		printk(KERN_DEBUG "addrconf_ifdown: invalid device %p\n",dev);
 		return -ENODEV;
 	}
 
@@ -1403,13 +1406,10 @@
 	 */
 
 	for (i=0; i < IN6_ADDR_HSIZE; i++) {
-		for (idev = inet6_dev_lst[i]; idev; ) {
-			struct inet6_dev *back;
-
+		struct inet6_dev *next;
+		for (idev = inet6_dev_lst[i]; idev; idev = next) {
+			next = idev->next;
 			addrconf_ifdown(idev->dev);	
-			back = idev;
-			idev = idev->next;
-			kfree(back);
 		}
 	}
 
diff -u --recursive --new-file v2.1.72/linux/net/sunrpc/svc.c linux/net/sunrpc/svc.c
--- v2.1.72/linux/net/sunrpc/svc.c	Mon Dec  1 12:04:18 1997
+++ linux/net/sunrpc/svc.c	Tue Dec 16 12:28:18 1997
@@ -21,6 +21,7 @@
 #include <linux/sunrpc/clnt.h>
 
 #define RPCDBG_FACILITY	RPCDBG_SVCDSP
+#define RPC_PARANOIA 1
 
 /*
  * Create an RPC service
@@ -162,8 +163,9 @@
 }
 
 /*
- * Register an RPC service with the local portmapper. To
- * unregister a service, call this routine with proto and port == 0.
+ * Register an RPC service with the local portmapper.
+ * To unregister a service, call this routine with 
+ * proto and port == 0.
  */
 int
 svc_register(struct svc_serv *serv, int proto, unsigned short port)
@@ -196,7 +198,7 @@
 			continue;
 		error = rpc_register(progp->pg_prog, i, proto, port, &dummy);
 		if (error < 0)
-			return error;
+			break;
 		if (port && !dummy) {
 			error = -EACCES;
 			break;
@@ -246,14 +248,8 @@
 		serv->sv_stats->rpcbadfmt++;
 		goto dropit;			/* drop request */
 	}
-	if (vers != 2) {		/* RPC version number */
-		serv->sv_stats->rpcbadfmt++;
-		resp->buf[-1] = xdr_one;	/* REJECT */
-		svc_putlong(resp, xdr_zero);	/* RPC_MISMATCH */
-		svc_putlong(resp, xdr_two);	/* Only RPCv2 supported */
-		svc_putlong(resp, xdr_two);
-		goto error;
-	}
+	if (vers != 2)		/* RPC version number */
+		goto err_bad_rpc;
 
 	rqstp->rq_prog = prog = ntohl(*bufp++);	/* program number */
 	rqstp->rq_vers = vers = ntohl(*bufp++);	/* version number */
@@ -269,50 +265,23 @@
 	 */
 	svc_authenticate(rqstp, &rpc_stat, &auth_stat);
 
-	if (rpc_stat != rpc_success) {
-		serv->sv_stats->rpcbadfmt++;
-		svc_putlong(resp, rpc_garbage_args);
-		goto error;
-	}
+	if (rpc_stat != rpc_success)
+		goto err_garbage;
 
-	if (auth_stat != rpc_auth_ok) {
-		dprintk("svc: authentication failed (%ld)\n", ntohl(auth_stat));
-		serv->sv_stats->rpcbadauth++;
-		resp->buf[-1] = xdr_one;	/* REJECT */
-		svc_putlong(resp, xdr_one);	/* AUTH_ERROR */
-		svc_putlong(resp, auth_stat);	/* status */
-		goto error;
-		return svc_send(rqstp);
-	}
+	if (auth_stat != rpc_auth_ok)
+		goto err_bad_auth;
 
 	progp = serv->sv_program;
-	if (prog != progp->pg_prog) {
-		dprintk("svc: unknown program %d (me %d)\n", prog, progp->pg_prog);
-		serv->sv_stats->rpcbadfmt++;
-		svc_putlong(resp, rpc_prog_unavail);
-		goto error;
-		return svc_send(rqstp);
-	}
+	if (prog != progp->pg_prog)
+		goto err_bad_prog;
 
 	versp = progp->pg_vers[vers];
-	if (!versp || vers >= progp->pg_nvers) {
-		dprintk("svc: unknown version (%d)\n", vers);
-		serv->sv_stats->rpcbadfmt++;
-		svc_putlong(resp, rpc_prog_mismatch);
-		svc_putlong(resp, htonl(progp->pg_lovers));
-		svc_putlong(resp, htonl(progp->pg_hivers));
-		goto error;
-		return svc_send(rqstp);
-	}
+	if (!versp || vers >= progp->pg_nvers)
+		goto err_bad_vers;
 
 	procp = versp->vs_proc + proc;
-	if (proc >= versp->vs_nproc || !procp->pc_func) {
-		dprintk("svc: unknown procedure (%d)\n", proc);
-		serv->sv_stats->rpcbadfmt++;
-		svc_putlong(resp, rpc_proc_unavail);
-		goto error;
-		return svc_send(rqstp);
-	}
+	if (proc >= versp->vs_nproc || !procp->pc_func)
+		goto err_unknown;
 	rqstp->rq_server   = serv;
 	rqstp->rq_procinfo = procp;
 
@@ -334,16 +303,10 @@
 	if (!versp->vs_dispatch) {
 		/* Decode arguments */
 		xdr = procp->pc_decode;
-		if (xdr && !xdr(rqstp, rqstp->rq_argbuf.buf, rqstp->rq_argp)) {
-			dprintk("svc: failed to decode args\n");
-			serv->sv_stats->rpcbadfmt++;
-			svc_putlong(resp, rpc_garbage_args);
-			goto error;
-		}
+		if (xdr && !xdr(rqstp, rqstp->rq_argbuf.buf, rqstp->rq_argp))
+			goto err_garbage;
 
-		*statp = procp->pc_func(rqstp,
-					rqstp->rq_argp,
-					rqstp->rq_resp);
+		*statp = procp->pc_func(rqstp, rqstp->rq_argp, rqstp->rq_resp);
 
 		/* Encode reply */
 		if (*statp == rpc_success && (xdr = procp->pc_encode)
@@ -373,6 +336,55 @@
 	dprintk("svc: svc_process dropit\n");
 	svc_drop(rqstp);
 	return 0;
+
+err_bad_rpc:
+	serv->sv_stats->rpcbadfmt++;
+	resp->buf[-1] = xdr_one;	/* REJECT */
+	svc_putlong(resp, xdr_zero);	/* RPC_MISMATCH */
+	svc_putlong(resp, xdr_two);	/* Only RPCv2 supported */
+	svc_putlong(resp, xdr_two);
+	goto error;
+
+err_bad_auth:
+	dprintk("svc: authentication failed (%ld)\n", ntohl(auth_stat));
+	serv->sv_stats->rpcbadauth++;
+	resp->buf[-1] = xdr_one;	/* REJECT */
+	svc_putlong(resp, xdr_one);	/* AUTH_ERROR */
+	svc_putlong(resp, auth_stat);	/* status */
+	goto error;
+
+err_bad_prog:
+#ifdef RPC_PARANOIA
+	printk("svc: unknown program %d (me %d)\n", prog, progp->pg_prog);
+#endif
+	serv->sv_stats->rpcbadfmt++;
+	svc_putlong(resp, rpc_prog_unavail);
+	goto error;
+
+err_bad_vers:
+#ifdef RPC_PARANOIA
+	printk("svc: unknown version (%d)\n", vers);
+#endif
+	serv->sv_stats->rpcbadfmt++;
+	svc_putlong(resp, rpc_prog_mismatch);
+	svc_putlong(resp, htonl(progp->pg_lovers));
+	svc_putlong(resp, htonl(progp->pg_hivers));
+	goto error;
+
+err_unknown:
+#ifdef RPC_PARANOIA
+	printk("svc: unknown procedure (%d)\n", proc);
+#endif
+	serv->sv_stats->rpcbadfmt++;
+	svc_putlong(resp, rpc_proc_unavail);
+	goto error;
+
+err_garbage:
+#ifdef RPC_PARANOIA
+	printk("svc: failed to decode args\n");
+#endif
+	serv->sv_stats->rpcbadfmt++;
+	svc_putlong(resp, rpc_garbage_args);
 
 error:
 	return svc_send(rqstp);
