diff -u --recursive --new-file v1.3.93/linux/CREDITS linux/CREDITS
--- v1.3.93/linux/CREDITS	Fri Apr 19 10:07:57 1996
+++ linux/CREDITS	Mon Apr 22 07:14:01 1996
@@ -1365,3 +1365,10 @@
 S: 3078 Sulphur Spring Court
 S: San Jose, California 95148
 S: USA
+
+N: Dmitry S. Gorodchanin
+E: begemot@bgm.rosprint.net
+D: RISCom/8 driver, misc kernel fixes.
+S: 6/1 M.Koneva bl, apt #125 
+S: Poltava 314023
+S: Ukraine
diff -u --recursive --new-file v1.3.93/linux/Documentation/Configure.help linux/Documentation/Configure.help
--- v1.3.93/linux/Documentation/Configure.help	Sun Apr 21 19:21:58 1996
+++ linux/Documentation/Configure.help	Mon Apr 22 07:14:01 1996
@@ -2803,6 +2803,15 @@
   order to become a BBS. If you have a card like that, say Y here and
   read the file Documentation/digiboard.txt.
 
+SDL RISCom/8 card support
+CONFIG_RISCOM8
+  This is a driver for the SDL Communications RISCom/8 multiport card,
+  that give you many serial ports. You would need something like this
+  to connect more than two modems to your linux box, for instance in
+  order to become a BBS. If you have a card like that, say Y here and
+  read the file Documentation/riscom8.txt. Also it's possible to say
+  M here and compile this driver as kernel loadable module.
+
 Cyclades async mux support
 CONFIG_CYCLADES
   This is a driver for a card that gives you many serial ports. You
diff -u --recursive --new-file v1.3.93/linux/Documentation/riscom8.txt linux/Documentation/riscom8.txt
--- v1.3.93/linux/Documentation/riscom8.txt	Thu Jan  1 02:00:00 1970
+++ linux/Documentation/riscom8.txt	Mon Apr 22 07:14:01 1996
@@ -0,0 +1,56 @@
+	This is the README for RISCom/8 multi-port serial driver
+	(C) 1994-1996 D.Gorodchanin (begemot@bgm.rosrpint.net)
+	See file LICENSE for terms and conditions.
+
+NOTE: English is not my native language. 
+      I'm sorry for any mistakes in this text.
+
+Misc. notes for RISCom/8 serial driver, in no particule order :)
+
+1) This driver can support up to 4 boards at time.
+   Use string "riscom8=0xXXX,0xXXX,0xXXX,0xXXX" at LILO prompt, for
+   setting I/O base addresses for boards. If you compile driver
+   as module use insmod options "iobase=0xXXX iobase1=0xXXX iobase2=..."
+
+2) The driver partially supports famous 'setserial' program, you can use almost
+   any it option, exclude port & irq settings.
+
+3) There are some misc. defines at the beginning of riscom8.c, please read the 
+   comments and try to change some of them in case of problems.
+	
+4) I consider the current state of the driver as BETA.
+   If you REALLY think you found the bug, send me e-mail, I hope I'll
+   fix it. For any other problems please ask support@sdlcomm.com.
+
+5) SDL Communications WWW page is http://www.sdlcomm.com.
+
+6) You can use the script at the end of this file to create RISCom/8 devices.
+
+7) Minors number for 1-st board are 0-7, for second 8-15, etc.
+
+22 Apr 1996.
+
+-------------------------------cut here-------------------------------------
+#!/bin/bash
+NORMAL_DEVICE=/dev/ttyL
+CALLOUT_DEVICE=/dev/cuL
+NORMAL_MAJOR=48
+CALLOUT_MAJOR=49
+
+echo "Creating devices... "
+for i in 0 1 2 3; do
+	echo "Board No $[$i+1]"
+	for j in 0 1 2 3 4 5 6 7; do
+		k=$[ 8 * $i + $j]
+		rm -f $NORMAL_DEVICE$k 
+		mknod $NORMAL_DEVICE$k c $NORMAL_MAJOR $k
+		chmod a+rw $NORMAL_DEVICE$k
+		echo -n $NORMAL_DEVICE$k" "
+		rm -f $CALLOUT_DEVICE$k 
+		mknod $CALLOUT_DEVICE$k c $CALLOUT_MAJOR $k
+		chmod a+rw $CALLOUT_DEVICE$k
+		echo $CALLOUT_DEVICE$k
+	done
+done
+echo "done."
+-------------------------------cut here-------------------------------------
diff -u --recursive --new-file v1.3.93/linux/MAGIC linux/MAGIC
--- v1.3.93/linux/MAGIC	Fri Mar 22 12:58:41 1996
+++ linux/MAGIC	Mon Apr 22 07:14:01 1996
@@ -61,6 +61,7 @@
 SERIAL_MAGIC        0x5301  struct async_struct  include/linux/serial.h
 SLIP_MAGIC          0x5302  struct slip          drivers/net/slip.h
 SCC_MAGIC           0x8530  struct scc_channel   include/linux/scc.h
+RISCOM8_MAGIC       0x0907  struct riscom_port	 drivers/char/riscom8.h
 
 
 
diff -u --recursive --new-file v1.3.93/linux/MAINTAINERS linux/MAINTAINERS
--- v1.3.93/linux/MAINTAINERS	Sun Apr 21 19:21:59 1996
+++ linux/MAINTAINERS	Mon Apr 22 11:44:26 1996
@@ -159,7 +159,7 @@
 
 FTAPE/QIC-117:
 P:	Kai Harrekilde-Petersen
-M:	khp@@dolphinics.no
+M:	khp@dolphinics.no
 L:	linux-tape@vger.rutgers.edu
 S:	Maintained
 
@@ -260,6 +260,13 @@
 M:	clameter@fuller.edu
 L:	digiboard@list.fuller.edu
 S:	Maintained
+
+RISCOM8 DRIVER:
+P:	Dmitry Gorodchanin
+M:	begemot@bgm.rosprint.net
+L:	linux-kernel@vger.rutgers.edu
+S:	Maintained
+
 
 MOUSE AND MISC DEVICES [GENERAL]
 P:	Alessandro Rubini
diff -u --recursive --new-file v1.3.93/linux/Makefile linux/Makefile
--- v1.3.93/linux/Makefile	Sun Apr 21 19:21:59 1996
+++ linux/Makefile	Mon Apr 22 11:03:24 1996
@@ -1,6 +1,6 @@
 VERSION = 1
 PATCHLEVEL = 3
-SUBLEVEL = 93
+SUBLEVEL = 94
 
 ARCH = i386
 
diff -u --recursive --new-file v1.3.93/linux/arch/alpha/defconfig linux/arch/alpha/defconfig
--- v1.3.93/linux/arch/alpha/defconfig	Sun Apr 21 12:39:00 1996
+++ linux/arch/alpha/defconfig	Mon Apr 22 13:44:45 1996
@@ -96,7 +96,6 @@
 #
 # CONFIG_SCSI_MULTI_LUN is not set
 CONFIG_SCSI_CONSTANTS=y
-# CONFIG_SCSI_AUTO_BIOSP is not set
 
 #
 # SCSI low-level drivers
@@ -151,6 +150,7 @@
 # CONFIG_APRICOT is not set
 CONFIG_DE4X5=y
 # CONFIG_DEC_ELCP is not set
+# CONFIG_DGRS is not set
 # CONFIG_ZNET is not set
 # CONFIG_NET_POCKET is not set
 # CONFIG_TR is not set
@@ -180,6 +180,7 @@
 CONFIG_ISO9660_FS=y
 # CONFIG_HPFS_FS is not set
 # CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
 
 #
 # Character devices
@@ -188,6 +189,7 @@
 # CONFIG_DIGI is not set
 # CONFIG_CYCLADES is not set
 # CONFIG_STALDRV is not set
+# CONFIG_RISCOM8 is not set
 # CONFIG_PRINTER is not set
 # CONFIG_BUSMOUSE is not set
 CONFIG_PSMOUSE=y
diff -u --recursive --new-file v1.3.93/linux/arch/i386/defconfig linux/arch/i386/defconfig
--- v1.3.93/linux/arch/i386/defconfig	Mon Apr 15 12:20:17 1996
+++ linux/arch/i386/defconfig	Mon Apr 22 12:12:57 1996
@@ -138,6 +138,7 @@
 CONFIG_ISO9660_FS=y
 # CONFIG_HPFS_FS is not set
 # CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
 
 #
 # Character devices
@@ -146,6 +147,7 @@
 # CONFIG_DIGI is not set
 # CONFIG_CYCLADES is not set
 # CONFIG_STALDRV is not set
+# CONFIG_RISCOM8 is not set
 # CONFIG_PRINTER is not set
 # CONFIG_BUSMOUSE is not set
 # CONFIG_PSMOUSE is not set
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/Makefile linux/arch/m68k/Makefile
--- v1.3.93/linux/arch/m68k/Makefile	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/Makefile	Sat Mar 23 16:41:07 1996
@@ -0,0 +1,106 @@
+#
+# m68k/Makefile
+#
+# This file is included by the global makefile so that you can add your own
+# architecture-specific flags and dependencies. Remember to do have actions
+# for "archclean" and "archdep" for cleaning up and making dependencies for
+# this architecture
+#
+# 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 by Hamish Macdonald
+#
+
+# override top level makefile
+ifdef CONFIG_KERNEL_ELF
+AS	= as -m68020
+LD	= ld -m m68kelf
+CC	:= $(CC)
+# set up for cross compiling
+COMPILE_ARCH = $(shell uname -m)
+ifneq ($(COMPILE_ARCH),$(ARCH))
+	CROSSDIR=/usr/$(ARCH)-linux
+	CC := $(CROSSDIR)/$(CC)
+	AS := $(CROSSDIR)/$(AS)
+	LD := $(CROSSDIR)/$(LD)
+	AR := $(CROSSDIR)/$(AR)
+	NM := $(CROSSDIR)/$(NM)
+	STRIP := $(CROSSDIR)/$(STRIP)
+endif
+else
+AS	= /usr/m68k-linuxaout/bin/as -m68020 
+CC	:= $(CC) -pipe -b m68k-linuxaout
+LD	= ld -m m68klinux
+endif
+
+#
+# Set these to indicate how to link it..
+#
+# -zmagic:   
+#
+# LINKFLAGS    = -Ttext 0x100000
+#
+# -qmagic (we need to remove the 32 byte header for bootup purposes)
+#
+
+ifdef CONFIG_KERNEL_ELF
+LINKFLAGS = -Ttext 0x1000
+else
+LINKFLAGS = -qmagic -Ttext 0xFE0
+endif
+CFLAGS := $(CFLAGS) -pipe
+
+HEAD := arch/m68k/kernel/head.o
+
+SUBDIRS += arch/m68k/kernel arch/m68k/mm arch/m68k/console arch/m68k/lib
+#SUBDIRS += arch/m68k/kernel arch/m68k/mm arch/m68k/lib
+ARCHIVES := arch/m68k/kernel/kernel.o arch/m68k/mm/mm.o $(ARCHIVES)
+LIBS += arch/m68k/lib/lib.a
+
+ifdef CONFIG_AMIGA
+ARCHIVES := $(ARCHIVES) arch/m68k/amiga/amiga.o
+SUBDIRS := $(SUBDIRS) arch/m68k/amiga
+endif
+
+ifdef CONFIG_ATARI
+ARCHIVES := $(ARCHIVES) arch/m68k/atari/atari.o
+SUBDIRS := $(SUBDIRS) arch/m68k/atari
+endif
+
+ifdef CONFIG_MAC
+ARCHIVES := $(ARCHIVES) arch/m68k/mac/mac.o
+SUBDIRS := $(SUBDIRS) arch/m68k/mac
+endif
+
+# add in console.a after {amiga,atari}.o that need it
+ARCHIVES := $(ARCHIVES) arch/m68k/console/console.a
+
+ifdef CONFIG_FPSP_040
+ARCHIVES := $(ARCHIVES) arch/m68k/fpsp040/fpsp.o
+SUBDIRS := $(SUBDIRS) arch/m68k/fpsp040
+endif
+
+ifdef CONFIG_IFPSP_060
+ARCHIVES := $(ARCHIVES) arch/m68k/ifpsp060/ifpsp.o
+SUBDIRS := $(SUBDIRS) arch/m68k/ifpsp060
+endif
+
+MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot
+
+lilo:	vmlinux
+	if [ -f $(INSTALL_PATH)/vmlinux ]; then mv -f $(INSTALL_PATH)/vmlinux $(INSTALL_PATH)/vmlinux.old; fi
+	if [ -f $(INSTALL_PATH)/System.map ]; then mv -f $(INSTALL_PATH)/System.map $(INSTALL_PATH)/System.old; fi
+	cat vmlinux > $(INSTALL_PATH)/vmlinux
+	cp System.map $(INSTALL_PATH)/System.map
+	if [ -x /sbin/lilo ]; then /sbin/lilo; else /etc/lilo/install; fi
+
+bootstrap:
+	@$(MAKEBOOT) bootstrap
+
+archclean:
+	@$(MAKEBOOT) clean
+
+archdep:
+	$(MAKEBOOT) dep
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/Makefile_elf linux/arch/m68k/Makefile_elf
--- v1.3.93/linux/arch/m68k/Makefile_elf	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/Makefile_elf	Wed Dec 27 22:51:18 1995
@@ -0,0 +1,91 @@
+#
+# m68k/Makefile
+#
+# This file is included by the global makefile so that you can add your own
+# architecture-specific flags and dependencies. Remember to do have actions
+# for "archclean" and "archdep" for cleaning up and making dependencies for
+# this architecture
+#
+# 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 by Hamish Macdonald
+#
+
+# override top level makefile
+AS	= as -m68020 
+#CC	:= $(CC) -b m68kelf
+LD	= ld -m m68kelf
+
+
+#
+# Set these to indicate how to link it..
+#
+# -zmagic:   
+#
+# LINKFLAGS    = -Ttext 0x100000
+#
+# -qmagic (we need to remove the 32 byte header for bootup purposes)
+#
+
+LINKFLAGS = -qmagic -Ttext 0xFE0
+
+HEAD := arch/m68k/kernel/head.o
+
+SUBDIRS := $(SUBDIRS) arch/m68k/kernel arch/m68k/mm arch/m68k/lib
+ARCHIVES := arch/m68k/kernel/kernel.o arch/m68k/mm/mm.o $(ARCHIVES)
+LIBS := $(TOPDIR)/arch/m68k/lib/lib.a $(LIBS) $(TOPDIR)/arch/m68k/lib/lib.a
+
+ifdef CONFIG_AMIGA
+ARCHIVES := $(ARCHIVES) arch/m68k/amiga/amiga.o
+SUBDIRS := $(SUBDIRS) arch/m68k/amiga
+endif
+
+ifdef CONFIG_ATARI
+ARCHIVES := $(ARCHIVES) arch/m68k/atari/atari.o
+SUBDIRS := $(SUBDIRS) arch/m68k/atari
+endif
+
+ifdef CONFIG_MAC
+ARCHIVES := $(ARCHIVES) arch/m68k/mac/mac.o
+SUBDIRS := $(SUBDIRS) arch/m68k/mac
+endif
+
+ifdef CONFIG_FPSP_040
+ARCHIVES := $(ARCHIVES) arch/m68k/fpsp040/fpsp.o
+SUBDIRS := $(SUBDIRS) arch/m68k/fpsp040
+endif
+
+arch/m68k/kernel: dummy
+	$(MAKE) linuxsubdirs SUBDIRS=arch/m68k/kernel
+
+arch/m68k/mm: dummy
+	$(MAKE) linuxsubdirs SUBDIRS=arch/m68k/mm
+
+arch/m68k/lib: dummy
+	$(MAKE) linuxsubdirs SUBDIRS=arch/m68k/lib
+
+arch/m68k/amiga: dummy
+	$(MAKE) linuxsubdirs SUBDIRS=arch/m68k/amiga
+
+arch/m68k/atari: dummy
+	$(MAKE) linuxsubdirs SUBDIRS=arch/m68k/atari
+
+MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot
+
+lilo:	vmlinux
+	if [ -f $(INSTALL_PATH)/vmlinux ]; then mv -f $(INSTALL_PATH)/vmlinux $(INSTALL_PATH)/vmlinux.old; fi
+	if [ -f $(INSTALL_PATH)/System.map ]; then mv -f $(INSTALL_PATH)/System.map $(INSTALL_PATH)/System.old; fi
+	cat vmlinux > $(INSTALL_PATH)/vmlinux
+	cp System.map $(INSTALL_PATH)/System.map
+	if [ -x /sbin/lilo ]; then /sbin/lilo; else /etc/lilo/install; fi
+
+bootstrap:
+	@$(MAKEBOOT) bootstrap
+
+archclean:
+	@$(MAKEBOOT) clean
+
+archdep:
+	$(MAKEBOOT) dep
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/amiga/Makefile linux/arch/m68k/amiga/Makefile
--- v1.3.93/linux/arch/m68k/amiga/Makefile	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/amiga/Makefile	Tue Apr  2 00:27:34 1996
@@ -0,0 +1,15 @@
+#
+# Makefile for Linux arch/m68k/amiga 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).
+#
+# Note 2! The CFLAGS definitions are now in the main makefile...
+
+O_TARGET := amiga.o
+O_OBJS	 := config.o amikeyb.o amiints.o amipart.o \
+	   chipram.o amisound.o amifb.o zorro.o
+OX_OBJS = ksyms.o
+
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/amiga/amifb.c linux/arch/m68k/amiga/amifb.c
--- v1.3.93/linux/arch/m68k/amiga/amifb.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/amiga/amifb.c	Mon Apr  1 22:05:42 1996
@@ -0,0 +1,5086 @@
+/*
+ * linux/arch/m68k/amiga/amifb.c -- Low level implementation of the Amiga frame
+ *                                  buffer device
+ *
+ *    Copyright (C) 1995 Geert Uytterhoeven
+ *
+ *
+ * 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:
+ *
+ *   -  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 README.legal 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 <asm/segment.h>
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/amigahw.h>
+#include <asm/amigaints.h>
+#include <asm/bootinfo.h>
+#include <linux/fb.h>
+
+
+#undef  CONFIG_AMIFB_OCS
+#undef  CONFIG_AMIFB_ECS
+#define CONFIG_AMIFB_AGA   /* Only AGA support at the moment */
+
+#define USE_MONO_AMIFB_IF_NON_AGA
+
+
+/* -------------------- BEGIN: TODO ----------------------------------------- **
+
+
+   - scan the sources for `TODO'
+
+   - timings and monspecs can be set via the kernel command line (cfr. Atari)
+
+   - OCS and ECS
+
+   - hardware cursor
+
+   - Interlaced screen -> Interlaced sprite/hardware cursor
+
+
+** -------------------- END: TODO ------------------------------------------- */
+
+
+/*******************************************************************************
+
+
+   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:   Start 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:   Start 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 depencies 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 (*).
+      - 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.
+
+   (*) This is for fmode = 3. Lower fmodes allow for more freedom w.r.t. the
+       timings, but they limit the maximum display depth, and cause more stress
+       on the custom chip bus.
+
+
+   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
+   --------------
+
+   aga_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
+   -----------------------
+
+   Since broadcast video timings are `fixed' and only depend on the video
+   system (PAL/NTSC), hsync_len and vsync_len are not used and must be set to
+   zero. All xres/yres and margin values are defined within the `visible
+   rectangle' of the display.
+
+   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 = 576 for an interlaced, 288
+        for a non-interlaced and 144 for a doublescanned display.
+      - make sure (left_margin+xres+right_margin)*pixclock is a reasonable
+        approximation to 52.48 µs.
+
+   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.
+   But since Amigas have RGB output, this issue isn't of any importance here.
+
+
+                                                            -- 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 emulation disable */
+
+
+   /*
+    *    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       (0x0080) /* 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
+    */
+
+#define TAG_SHRES       (1)      /* SHRES, clk_shift = TAG_SHRES-1 */
+#define TAG_HIRES       (2)      /* HIRES, clk_shift = TAG_HIRES-1 */
+#define TAG_LORES       (3)      /* LORES, clk_shift = TAG_LORES-1 */
+
+
+   /*
+    *    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 */
+
+
+   /*
+    *    Broadcast Video Timings
+    *
+    *    Horizontal values are in 35 ns (SHRES) units
+    *    Vertical values are in non-interlaced scanlines
+    */
+
+#define PAL_WINDOW_H    (1472)   /* PAL Window Limits */
+#define PAL_WINDOW_V    (288)
+#define PAL_DIWSTRT_H   (360)
+#define PAL_DIWSTRT_V   (24)
+
+#define NTSC_WINDOW_H   (1472)   /* NTSC Window Limits */
+#define NTSC_WINDOW_V   (242)
+#define NTSC_DIWSTRT_H  (360)
+#define NTSC_DIWSTRT_V  (20)
+
+#define PAL_HTOTAL      (1816)   /* Total line length */
+#define NTSC_HTOTAL     (1816)   /* Needed for YWRAP */
+
+
+   /*
+    *    Monitor Specifications
+    *
+    *    These are typical for a `generic' Amiga monitor (e.g. A1960)
+    */
+
+static long vfmin = 50, vfmax = 90, hfmin = 15000, hfmax = 38000;
+
+static u_short pwrsave = 0;      /* VESA suspend mode (not for PAL/NTSC) */
+
+
+   /*
+    *    Various macros
+    */
+
+#define up8(x)          (((x)+7) & ~7)
+#define down8(x)        ((x) & ~7)
+#define div8(x)         ((x)>>3)
+#define mod8(x)         ((x) & 7)
+
+#define up16(x)         (((x)+15) & ~15)
+#define down16(x)       ((x) & ~15)
+#define div16(x)        ((x)>>4)
+#define mod16(x)        ((x) & 15)
+
+#define up32(x)         (((x)+31) & ~31)
+#define down32(x)       ((x) & ~31)
+#define div32(x)        ((x)>>5)
+#define mod32(x)        ((x) & 31)
+
+#define up64(x)         (((x)+63) & ~63)
+#define down64(x)       ((x) & ~63)
+#define div64(x)        ((x)>>6)
+#define mod64(x)        ((x) & 63)
+
+#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)))
+
+
+   /*
+    *    Chip RAM we reserve for the Frame Buffer
+    *
+    *    This defines the Maximum Virtual Screen Size
+    */
+
+#define VIDEOMEMSIZE_AGA_2M   (1280*1024)    /* AGA (2MB) : max 1280*1024*256 */
+#define VIDEOMEMSIZE_AGA_1M   (1024*768)     /* AGA (1MB) : max 1024*768*256 */
+#define VIDEOMEMSIZE_ECS_2M   (1280*1024/2)  /* ECS (2MB) : max 1280*1024*16 */
+#define VIDEOMEMSIZE_ECS_1M   (1024*768/2)   /* ECS (1MB) : max 1024*768*16 */
+#define VIDEOMEMSIZE_OCS      (800*600/2)    /* OCS      : max 800*600*16 */
+
+
+static u_long videomemory;
+static u_long videomemorysize;
+
+#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) & 0xff)<<24 | ((x) & 0xfe)<<16 | 0x0001fffe)
+#define CEND                  (0xfffffffe)
+
+
+typedef union {
+   u_long l;
+   u_short w[2];
+} copins;
+
+
+   /*
+    *    Frame Header Copper List
+    */
+
+struct clist_hdr {
+   copins bplcon0;
+   copins diwstrt;
+   copins diwstop;
+   copins diwhigh;
+   copins sprfix[8];
+   copins sprstrtup[16];
+   copins wait;
+   copins jump;
+   copins wait_forever;
+};
+
+
+   /*
+    *    Long Frame/Short Frame Copper List
+    */
+
+struct clist_dyn {
+   copins diwstrt;
+   copins diwstop;
+   copins diwhigh;
+   copins bplcon0;
+   copins sprpt[2];              /* Sprite 0 */
+   copins rest[64];
+};
+
+
+static struct clist_hdr *clist_hdr;
+static struct clist_dyn *clist_lof;
+static struct clist_dyn *clist_shf;    /* Only used for Interlace */
+
+
+   /*
+    *    Hardware Cursor
+    */
+
+#define CRSR_RATE       (20)     /* Number of frames/flash toggle */
+
+static u_long *lofsprite, *shfsprite, *dummysprite;
+static u_short cursormode = FB_CURSOR_FLASH;
+
+
+   /*
+    *    Current Video Mode
+    */
+
+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 */
+   int vmode;                    /* vmode */
+   u_short diwstrt_h;            /* vmode */
+   u_short diwstrt_v;            /* vmode */
+   u_long next_line;             /* modulo for next line */
+   u_long next_plane;            /* modulo for next plane */
+   short crsr_x;                 /* movecursor */
+   short crsr_y;                 /* movecursor */
+
+   /* OCS Hardware Registers */
+
+   u_long bplpt0;                /* vmode, pan (Note: physical address) */
+   u_short bplcon0;              /* vmode */
+   u_short bplcon1;              /* vmode, pan */
+   u_short bpl1mod;              /* vmode, pan */
+   u_short bpl2mod;              /* vmode, pan */
+   u_short diwstrt;              /* vmode */
+   u_short diwstop;              /* vmode */
+   u_short ddfstrt;              /* vmode, pan */
+   u_short ddfstop;              /* vmode, pan */
+
+#if defined(CONFIG_AMIFB_ECS) || defined(CONFIG_AMIFB_AGA)
+   /* Additional ECS Hardware Registers */
+
+   u_short diwhigh;              /* vmode */
+   u_short bplcon3;              /* vmode */
+   u_short beamcon0;             /* vmode */
+   u_short htotal;               /* vmode */
+   u_short hsstrt;               /* vmode */
+   u_short hsstop;               /* vmode */
+   u_short vtotal;               /* vmode */
+   u_short vsstrt;               /* vmode */
+   u_short vsstop;               /* vmode */
+   u_short hcenter;              /* vmode */
+#endif /* defined(CONFIG_AMIFB_ECS) || defined(CONFIG_AMIFB_AGA) */
+
+#if defined(CONFIG_AMIFB_AGA)
+   /* Additional AGA Hardware Registers */
+
+   u_short fmode;                /* vmode */
+#endif /* defined(CONFIG_AMIFB_AGA) */
+};
+
+static struct amiga_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 */
+
+
+   /*
+    *    The minimum period for audio depends on htotal (for OCS/ECS/AGA)
+    */
+
+volatile u_short amiga_audio_min_period = 124;   /* Default for pre-OCS */
+
+
+   /*
+    *    Since we can't read the palette on OCS/ECS, and since reading one
+    *    single color palette entry requires 5 expensive custom chip bus
+    *    accesses on AGA, we keep a copy of the current palette.
+    */
+
+#ifdef CONFIG_AMIFB_AGA
+static struct { u_char red, green, blue, pad; } palette[256];
+#else /* CONFIG_AMIFB_AGA */
+static struct { u_char red, green, blue, pad; } palette[32];
+#endif /* CONFIG_AMIFB_AGA */
+
+
+   /*
+    *    Latches and Flags for display changes during VBlank
+    */
+
+static volatile u_short do_vmode = 0;           /* Change the Video Mode */
+static volatile short do_blank = 0;             /* (Un)Blank the Screen (±1) */
+static volatile u_short do_movecursor = 0;      /* Move the Cursor */
+static volatile u_short full_vmode_change = 1;  /* Full Change or Only Pan */
+static volatile u_short is_blanked = 0;         /* Screen is Blanked */
+
+
+   /*
+    *    Switch for Chipset Independency
+    */
+
+static struct fb_hwswitch {
+
+   /* Initialization */
+   int (*init)(void);
+
+   /* Display Control */
+   int (*encode_fix)(struct fb_fix_screeninfo *fix, struct amiga_fb_par *par);
+   int (*decode_var)(struct fb_var_screeninfo *var, struct amiga_fb_par *par);
+   int (*encode_var)(struct fb_var_screeninfo *var, struct amiga_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);
+   int (*pan_display)(struct fb_var_screeninfo *var, struct amiga_fb_par *par);
+
+   /* Routines Called by VBlank Interrupt to minimize flicker */
+   void (*do_vmode)(void);
+   void (*do_blank)(int blank);
+   void (*do_movecursor)(void);
+   void (*do_flashcursor)(void);
+} *fbhw;
+
+
+   /*
+    *    Frame Buffer Name
+    *
+    *    The rest of the name is filled in by amiga_fb_init
+    */
+
+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"
+};
+
+
+   /*
+    *    Predefined Video Mode Definitions
+    *
+    *    Since the actual pixclock values depend on the E-Clock, we use the
+    *    TAG_* values and fill in the real values during initialization.
+    *    Thus we assume no one has pixel clocks of 333, 500 or 1000 GHz :-)
+    */
+
+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, 78, 18, 24, 18, 0, 0,
+      FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED
+   }, {
+      /* 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, 78, 18, 48, 36, 0, 0,
+      FB_SYNC_BROADCAST, FB_VMODE_INTERLACED
+   }, {
+      /* 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, 78, 18, 20, 12, 0, 0,
+      FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED
+   }, {
+      /* 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, 78, 18, 40, 24, 0, 0,
+      FB_SYNC_BROADCAST, FB_VMODE_INTERLACED
+   }, {
+      /* 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, 164, 92, 9, 9, 80, 8,
+      0, FB_VMODE_NONINTERLACED
+   }, {
+      /* 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, 164, 92, 18, 18, 80, 16,
+      0, FB_VMODE_INTERLACED
+   }, {
+      /* 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
+   }, {
+      /* 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
+   }, {
+      /* 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
+   }, {
+      /* 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
+   }, {
+      /* 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
+   }, {
+      /* 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
+   }, {
+      /* 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
+   }, {
+      /* 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
+   }, {
+      /* 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
+   }, {
+      /* 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
+   }, {
+      /* 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
+   }, {
+      /* 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
+   }, {
+      /* 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
+   }, {
+      /* 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
+   },
+
+   /*
+    *    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
+   }, {
+      /* 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
+   },
+
+   /*
+    *    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_mode = 0;
+
+
+   /*
+    *    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 /* CONFIG_FB_CYBER */
+
+
+   /*
+    *    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 */
+
+
+   /*
+    *    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_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_pan_display(struct fb_var_screeninfo *var, 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, int con);
+static int amiga_fb_set_var_cursorinfo(struct fb_var_cursorinfo *var, 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 amifb_switch(int con);
+static int amifb_updatevar(int con);
+static void amifb_blank(int blank);
+
+
+   /*
+    *    Support for OCS
+    */
+
+#ifdef CONFIG_AMIFB_OCS
+#error "OCS support: not yet implemented"
+#endif /* CONFIG_AMIFB_OCS */
+
+
+   /*
+    *    Support for ECS
+    */
+
+#ifdef CONFIG_AMIFB_ECS
+#error "ECS support: not yet implemented"
+#endif /* CONFIG_AMIFB_ECS */
+
+
+   /*
+    *    Support for AGA
+    */
+
+#ifdef CONFIG_AMIFB_AGA
+static int aga_init(void);
+static int aga_encode_fix(struct fb_fix_screeninfo *fix,
+                          struct amiga_fb_par *par);
+static int aga_decode_var(struct fb_var_screeninfo *var,
+                          struct amiga_fb_par *par);
+static int aga_encode_var(struct fb_var_screeninfo *var,
+                          struct amiga_fb_par *par);
+static int aga_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
+                         u_int *transp);
+static int aga_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+                         u_int transp);
+static int aga_pan_display(struct fb_var_screeninfo *var,
+                           struct amiga_fb_par *par);
+static void aga_do_vmode(void);
+static void aga_do_blank(int blank);
+static void aga_do_movecursor(void);
+static void aga_do_flashcursor(void);
+
+static int aga_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix, int con);
+static int aga_get_var_cursorinfo(struct fb_var_cursorinfo *var, int con);
+static int aga_set_var_cursorinfo(struct fb_var_cursorinfo *var, int con);
+static int aga_get_cursorstate(struct fb_cursorstate *state, int con);
+static int aga_set_cursorstate(struct fb_cursorstate *state, int con);
+
+static __inline__ void aga_build_clist_hdr(struct clist_hdr *cop);
+static __inline__ void aga_update_clist_hdr(struct clist_hdr *cop,
+                                            struct amiga_fb_par *par);
+static void aga_build_clist_dyn(struct clist_dyn *cop,
+                                struct clist_dyn *othercop, u_short shf,
+                                struct amiga_fb_par *par);
+#endif /* CONFIG_AMIFB_AGA */
+
+
+   /*
+    *    Internal routines
+    */
+
+static u_long chipalloc(u_long size);
+static void amiga_fb_get_par(struct amiga_fb_par *par);
+static void amiga_fb_set_par(struct amiga_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 amiga_fb_set_disp(int con);
+static void amifb_interrupt(int irq, struct pt_regs *fp, void *dummy);
+static char * strtoke(char * s,const char * ct);
+static int get_video_mode(const char *name);
+static void check_default_mode(void);
+
+
+#ifdef USE_MONO_AMIFB_IF_NON_AGA
+
+/******************************************************************************
+*
+* This is the old monochrome frame buffer device. It's invoked if we're running
+* on a non-AGA machine, until the color support for OCS/ECS is finished.
+*
+******************************************************************************/
+
+/*
+ * atari/atafb.c -- Low level implementation of Atari frame buffer device
+ * amiga/amifb.c -- Low level implementation of Amiga frame buffer device
+ *
+ *  Copyright (C) 1994 Martin Schaller & Roman Hodek & Geert Uytterhoeven
+ *  
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file README.legal in the main directory of this archive
+ * for more details.
+ *
+ * History:
+ *   - 03 Jan 95: Original version my Martin Schaller: The TT driver and
+ *                all the device independant 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.
+ *   - 26 Jan 95: Geert: Amiga version
+ *   - 19 Feb 95: Hamish: added Jes Sorensen's ECS patches to the Amiga
+ *		  frame buffer device.  This provdes ECS support and the
+ *		  following screen-modes: multiscan, multiscan-lace,
+ * 		  super72, super72-lace, dblntsc, dblpal & euro72.
+ *		  He suggests that we remove the old AGA screenmodes,
+ *		  as they are non-standard, and some of them doesn't work
+ *		  under ECS.
+ */
+
+static struct mono_mono_amiga_fb_par {
+	u_long smem_start;
+	u_long smem_len;
+	struct geometry *geometry;
+	ushort scr_max_height;			/* screen dimensions */
+	ushort scr_max_width;
+	ushort scr_height;
+	ushort scr_width;
+	ushort scr_depth;
+	int bytes_per_row;			/* offset to one line below */
+	ulong fgcol;
+	ulong bgcol;
+	ulong crsrcol;
+	ushort scroll_latch;			/* Vblank support for hardware scroll */
+	ushort y_wrap;
+	ushort cursor_latch;			/* Hardware cursor */
+	ushort *cursor, *dummy;
+	ushort cursor_flash;
+	ushort cursor_visible;
+	ushort diwstrt_v, diwstrt_h;		/* display window control */
+	ushort diwstop_v, diwstop_h;
+	ushort bplcon0;				/* display mode */
+	ushort htotal;
+	u_char *bitplane[8];			/* pointers to display bitplanes */
+	ulong plane_size;
+	ushort *coplist1hdr;			/* List 1 static  component */
+	ushort *coplist1dyn;			/* List 1 dynamic component */
+	ushort *coplist2hdr;			/* List 2 static  component */
+	ushort *coplist2dyn;			/* List 2 dynamic component */
+} mono_current_par;
+
+
+static ushort mono_cursor_data[] =
+{
+    0x2c81,0x2d00,
+    0xf000,0x0000,
+    0x0000,0x0000
+};
+
+
+/*
+ *  Color definitions
+ */
+
+#define FG_COLOR		(0x000000)	/* black */
+#define BG_COLOR		(0xaaaaaa)	/* lt. grey */
+#define CRSR_COLOR		(0xff0000)	/* bright red */
+
+#define FG_COLOR_INV		BG_COLOR
+#define BG_COLOR_INV		FG_COLOR
+#define CRSR_COLOR_INV		(0x6677aa)	/* a blue-ish color */
+
+/*
+ *  Split 24-bit RGB colors in 12-bit MSB (for OCS/ECS/AGA) and LSB (for AGA)
+ */
+
+#define COLOR_MSB(rgb)	(((rgb>>12)&0xf00)|((rgb>>8)&0x0f0)|((rgb>>4)&0x00f))
+#define COLOR_LSB(rgb)	(((rgb>>8) &0xf00)|((rgb>>4)&0x0f0)|((rgb)   &0x00f))
+
+/* Cursor definitions */
+
+#define CRSR_FLASH		1	/* Cursor flashing on(1)/off(0) */
+#define CRSR_BLOCK		1	/* Block(1) or line(0) cursor */
+
+
+/* controlling screen blanking (read in VBL handler) */
+static int mono_do_blank;
+static int mono_do_unblank;
+static unsigned short mono_save_bplcon3;
+
+/*
+ * mono_ecs_color_zero is used to keep custom.color[0] for the special ECS color-
+ * table, as custom.color[0] is cleared at vblank interrupts.
+ * -Jes (jds@kom.auc.dk)
+ */
+
+static ushort mono_ecs_color_zero;
+
+static struct {
+	int right_count;
+	int done;
+} mono_vblank;
+
+
+static __inline__ void mono_init_vblank(void)
+{
+	mono_vblank.right_count = 0;
+	mono_vblank.done = 0;
+}
+
+/* Geometry structure contains all useful information about given mode.
+ *
+ * Strictly speaking `scr_max_height' and `scr_max_width' is redundant
+ * information with DIWSTRT value provided. Might be useful if modes
+ * can be hotwired by user in future. It fits for the moment.
+ *
+ * At the moment, the code only distinguishes between OCS and AGA. ECS
+ * lies somewhere in between - someone more familiar with it could make
+ * appropriate modifications so that some advanced display modes are
+ * available, without confusing the poor chipset. OCS modes use only the
+ * bplcon0, diwstrt, diwstop, ddfstrt, ddfstop registers (a few others could
+ * be used as well). -wjr
+ *
+ * The code now supports ECS aswell, except for FMODE all control registers
+ * are the same under ECS. A special color-table has to be generated though.
+ * -Jes
+ */
+struct geometry {
+    char *modename;	/* Name this thing */
+    char isOCS;		/* Is it OCS or ECS/AGA */
+    ushort bplcon0;	/* Values for bit plane control register 0 */
+    ushort scr_width;
+    ushort scr_height;
+    ushort scr_depth;
+    ushort scr_max_width;     /* Historical, might be useful still */
+    ushort scr_max_height;
+    ushort diwstrt_h;	/* Where the display window starts */
+    ushort diwstrt_v;
+    ushort alignment;	/* Pixels per scanline must be a multiple of this */
+    /* OCS doesn't need anything past here */
+    ushort bplcon2;
+    ushort bplcon3;
+    /* The rest of these control variable sync */
+    ushort htotal;	/* Total hclocks */
+    ushort hsstrt;	/* HSYNC start and stop */
+    ushort hsstop;
+    ushort hbstrt;	/* HBLANK start and stop */
+    ushort hbstop;
+    ushort vtotal;	/* Total vlines */
+    ushort vsstrt;	/* VSYNC, VBLANK ditto */
+    ushort vsstop;
+    ushort vbstrt;
+    ushort vbstop;
+    ushort hcenter;	/* Center of line, for interlaced modes */
+    ushort beamcon0;	/* Beam control */
+    ushort fmode;	/* Memory fetch mode */
+};
+
+#define MAX_COP_LIST_ENTS 64
+#define COP_MEM_REQ       (MAX_COP_LIST_ENTS*4*2)
+#define SPR_MEM_REQ       (24)
+
+
+static struct geometry mono_modes[] = {
+	/* NTSC modes: !!! can't guarantee anything about overscan modes !!! */
+	{
+		"ntsc-lace", 1,
+		BPC0_HIRES | BPC0_LACE,
+		640, 400, 1,
+		704, 480,
+		0x71, 0x18,		/* diwstrt h,v */
+		16			/* WORD aligned */
+	}, {
+		"ntsc", 1,
+		BPC0_HIRES,
+		640, 200, 1,
+		704, 240,
+		0x71, 0x18,
+		16			/* WORD aligned */
+	}, {
+		"ntsc-lace-over", 1,
+		BPC0_HIRES | BPC0_LACE,
+		704, 480, 1,
+		704, 480,
+		0x71, 0x18,
+		16			/* WORD aligned */
+	}, {
+		"ntsc-over", 1,
+		BPC0_HIRES,
+		704, 240, 1,
+		704, 240,
+		0x71, 0x18,
+		16			/* WORD aligned */
+	},
+	/* PAL modes. Warning:
+	 * 
+	 * PAL overscan causes problems on my machine because maximum diwstop_h
+	 * value seems to be ~0x1c2, rather than 0x1e0+ inferred by RKM 1.1
+	 * and 0x1d5 inferred by original `amicon.c' source. Is this a hardware
+	 * limitation of OCS/pal or 1084?. Or am I doing something stupid here?
+	 *
+	 * Included a couple of overscan modes that DO work on my machine,
+	 * although not particularly useful.
+	 */
+	{
+		"pal-lace", 1,
+		BPC0_HIRES | BPC0_LACE,
+		640, 512, 1,
+		704, 592,
+		0x71, 0x18,
+		16			/* WORD aligned */
+	}, {
+		"pal", 1,
+		BPC0_HIRES,
+		640, 256, 1,
+		704, 296,
+		0x71, 0x18,
+		16			/* WORD aligned */
+	}, {
+		"pal-lace-over", 1,
+		BPC0_HIRES | BPC0_LACE,
+		704, 592, 1,
+		704, 582,
+		0x5b, 0x18,
+		16			/* WORD aligned */
+	}, {
+		"pal-over", 1,
+		BPC0_HIRES,
+		704, 296, 1,
+		704, 296,
+		0x5b, 0x18,
+		16			/* WORD aligned */
+
+	},
+	/* ECS modes, these are real ECS modes */
+	{
+		"multiscan", 0,
+		BPC0_SHRES | BPC0_ECSENA,	/* bplcon0 */
+		640, 480, 1,
+		640, 480,
+		0x0041, 0x002c,			/* diwstrt h,v */
+		64,	        		/* 64-bit aligned */
+		BPC2_KILLEHB,			/* bplcon2 */
+		BPC3_PF2OF1 | BPC3_PF2OF0 | BPC3_SPRES1 | BPC3_SPRES0 |
+			BPC3_BRDRBLNK | BPC3_EXTBLKEN,	/* bplcon3 */
+
+		0x0072,				/* htotal */
+		0x000a,				/* hsstrt */
+		0x0013,				/* hsstop */
+		0x0002,				/* hbstrt */
+		0x001c,				/* hbstop */
+		0x020c,				/* vtotal */
+		0x0008,				/* vsstrt */
+		0x0011,				/* vsstop */
+		0x0000,				/* vbstrt */
+		0x001c,				/* vbstop */
+		0x0043,				/* hcenter */
+		BMC0_VARVBEN | BMC0_LOLDIS | BMC0_VARVSYEN |
+			BMC0_VARHSYEN | BMC0_VARBEAMEN | BMC0_BLANKEN,
+						/* beamcon0 */
+		FMODE_BPAGEM | FMODE_BPL32	/* fmode */
+	},
+	{
+		"multiscan-lace", 0,
+		BPC0_SHRES | BPC0_LACE | BPC0_ECSENA,	/* bplcon0 */
+		640, 960, 1,
+		640, 960,
+		0x0041, 0x002c,			/* diwstrt h,v */
+		64,	        		/* 64-bit aligned */
+		BPC2_KILLEHB,			/* bplcon2 */
+		BPC3_PF2OF1 | BPC3_PF2OF0 | BPC3_SPRES1 | BPC3_SPRES0 |
+			BPC3_BRDRBLNK | BPC3_EXTBLKEN,	/* bplcon3 */
+
+		0x0072,				/* htotal */
+		0x000a,				/* hsstrt */
+		0x0013,				/* hsstop */
+		0x0002,				/* hbstrt */
+		0x001c,				/* hbstop */
+		0x020c,				/* vtotal */
+		0x0008,				/* vsstrt */
+		0x0011,				/* vsstop */
+		0x0000,				/* vbstrt */
+		0x001c,				/* vbstop */
+		0x0043,				/* hcenter */
+		BMC0_VARVBEN | BMC0_LOLDIS | BMC0_VARVSYEN |
+			BMC0_VARHSYEN | BMC0_VARBEAMEN | BMC0_BLANKEN,
+						/* beamcon0 */
+		FMODE_BPAGEM | FMODE_BPL32	/* fmode */
+	},
+	/* Super 72 - 800x300 72Hz noninterlaced mode. */
+	{
+		"super72", 0,
+		BPC0_SHRES | BPC0_ECSENA,	/* bplcon0 */
+		800, 304, 1,			/* need rows%8 == 0 */
+		800, 304,			/* (cols too) */
+		0x0051, 0x0021,			/* diwstrt h,v */
+		64,				/* 64-bit aligned */
+		BPC2_KILLEHB,			/* bplcon2 */
+		BPC3_PF2OF1 | BPC3_PF2OF0 | BPC3_SPRES1 | BPC3_SPRES0 |
+			BPC3_BRDRBLNK | BPC3_EXTBLKEN,	/* bplcon3 */
+		0x0091,				/* htotal */
+		0x000a,				/* hsstrt */
+		0x0013,				/* hsstop */
+		0x0001,				/* hbstrt */
+		0x001e,				/* hbstop */
+		0x0156,				/* vtotal */
+		0x0009,				/* vsstrt */
+		0x0012,				/* vsstop */
+		0x0000,				/* vbstrt */
+		0x001c,				/* vbstop */
+		0x0052,				/* hcenter */
+		BMC0_VARVBEN | BMC0_LOLDIS | BMC0_VARVSYEN |
+			BMC0_VARHSYEN | BMC0_VARBEAMEN | BMC0_BLANKEN,
+						/* beamcon0 */
+		FMODE_BPAGEM | FMODE_BPL32	/* fmode */
+	},
+	/* Super 72 lace - 800x600 72Hz interlaced mode. */
+	{
+		"super72-lace", 0,
+		BPC0_SHRES | BPC0_LACE | BPC0_ECSENA,	/* bplcon0 */
+		800, 600, 1,			/* need rows%8 == 0 */
+		800, 600,			/* (cols too) */
+		0x0051, 0x0021,			/* diwstrt h,v */
+		64,     			/* 64-bit aligned */
+		BPC2_KILLEHB,			/* bplcon2 */
+		BPC3_PF2OF1 | BPC3_PF2OF0 | BPC3_SPRES1 | BPC3_SPRES0 |
+			BPC3_BRDRBLNK | BPC3_EXTBLKEN,
+						/* bplcon3 */
+		0x0091,				/* htotal */
+		0x000a,				/* hsstrt */
+		0x0013,				/* hsstop */
+		0x0001,				/* hbstrt */
+		0x001e,				/* hbstop */
+		0x0150,				/* vtotal */
+		0x0009,				/* vsstrt */
+		0x0012,				/* vsstop */
+		0x0000,				/* vbstrt */
+		0x001c,				/* vbstop */
+		0x0052,				/* hcenter */
+		BMC0_VARVBEN | BMC0_LOLDIS | BMC0_VARVSYEN |
+			BMC0_VARHSYEN | BMC0_VARBEAMEN | BMC0_BLANKEN,
+						/* beamcon0 */
+		FMODE_BPAGEM | FMODE_BPL32	/* fmode */
+	},
+	/* DblNtsc - 640x400 59Hz noninterlaced mode. */
+	{
+		"dblntsc", 0,
+		BPC0_SHRES | BPC0_ECSENA,	/* bplcon0 */
+		640, 400, 1,			/* need rows%8 == 0 */
+		640, 400,			/* (cols too) */
+		0x0049, 0x0021,			/* diwstrt h,v */
+		64,				/* 64-bit aligned */
+		BPC2_KILLEHB,			/* bplcon2 */
+		BPC3_PF2OF1 | BPC3_PF2OF0 | BPC3_SPRES1 | BPC3_SPRES0 |
+			BPC3_BRDRBLNK | BPC3_EXTBLKEN,
+						/* bplcon3 */
+		0x0079,				/* htotal */
+		0x0007,				/* hsstrt */
+		0x0013,				/* hsstop */
+		0x0001,				/* hbstrt */
+		0x001e,				/* hbstop */
+		0x01ec,				/* vtotal */
+		0x0008,				/* vsstrt */
+		0x0010,				/* vsstop */
+		0x0000,				/* vbstrt */
+		0x0019,				/* vbstop */
+		0x0046,				/* hcenter */
+		BMC0_VARVBEN | BMC0_LOLDIS | BMC0_VARVSYEN |
+			BMC0_VARHSYEN | BMC0_VARBEAMEN | BMC0_BLANKEN,
+						/* beamcon0 */
+		FMODE_BPAGEM | FMODE_BPL32	/* fmode */
+	},
+	/* DblPal - 640x512 52Hz noninterlaced mode. */
+	{
+		"dblpal", 0,
+		BPC0_SHRES | BPC0_ECSENA,	/* bplcon0 */
+		640, 512, 1,			/* need rows%8 == 0 */
+		640, 512,			/* (cols too) */
+		0x0049, 0x0021,			/* diwstrt h,v */
+		64,				/* 64-bit aligned */
+		BPC2_KILLEHB,			/* bplcon2 */
+		BPC3_PF2OF1 | BPC3_PF2OF0 | BPC3_SPRES1 | BPC3_SPRES0 |
+			BPC3_BRDRBLNK | BPC3_EXTBLKEN,
+						/* bplcon3 */
+		0x0079,				/* htotal */
+		0x0007,				/* hsstrt */
+		0x0013,				/* hsstop */
+		0x0001,				/* hbstrt */
+		0x001e,				/* hbstop */
+		0x0234,				/* vtotal */
+		0x0008,				/* vsstrt */
+		0x0010,				/* vsstop */
+		0x0000,				/* vbstrt */
+		0x0019,				/* vbstop */
+		0x0046,				/* hcenter */
+		BMC0_VARVBEN | BMC0_LOLDIS | BMC0_VARVSYEN |
+			BMC0_VARHSYEN | BMC0_VARBEAMEN | BMC0_BLANKEN,
+						/* beamcon0 */
+		FMODE_BPAGEM | FMODE_BPL32	/* fmode */
+	},
+	/* Euro72 - productivity - 640x400 71Hz noninterlaced mode. */
+	{
+		"euro72", 0,
+		BPC0_SHRES | BPC0_ECSENA,	/* bplcon0 */
+		640, 400, 1,			/* need rows%8 == 0 */
+		640, 400,			/* (cols too) */
+		0x0041, 0x0021,			/* diwstrt h,v */
+		64,				/* 64-bit aligned */
+		BPC2_KILLEHB,			/* bplcon2 */
+		BPC3_PF2OF1 | BPC3_PF2OF0 | BPC3_SPRES1 | BPC3_SPRES0 |
+			BPC3_BRDRBLNK | BPC3_EXTBLKEN,
+						/* bplcon3 */
+		0x0071,				/* htotal */
+		0x0009,				/* hsstrt */
+		0x0013,				/* hsstop */
+		0x0001,				/* hbstrt */
+		0x001e,				/* hbstop */
+		0x01be,				/* vtotal */
+		0x0008,				/* vsstrt */
+		0x0016,				/* vsstop */
+		0x0000,				/* vbstrt */
+		0x001f,				/* vbstop */
+		0x0041,				/* hcenter */
+		BMC0_VARVBEN | BMC0_LOLDIS | BMC0_VARVSYEN |
+			BMC0_VARHSYEN | BMC0_VARBEAMEN | BMC0_BLANKEN,
+						/* beamcon0 */
+		FMODE_BPAGEM | FMODE_BPL32	/* fmode */
+	},
+	/* AGA modes */
+	{
+	/*
+	 * A 640x480, 60Hz noninterlaced AGA mode. It would be nice to be
+	 * able to have some of these values computed dynamically, but that
+	 * requires more knowledge of AGA than I have. At the moment,
+	 * the values make it centered on my 1960 monitor. -wjr
+	 *
+	 * For random reasons to do with the way arguments are parsed,
+	 * these names can't start with a digit.
+	 *
+	 * Don't count on being able to reduce scr_width and scr_height
+	 * and ending up with a smaller but well-formed screen - this
+	 * doesn't seem to work well at the moment.
+	 */
+		"aga640x480", 0,
+		BPC0_SHRES | BPC0_ECSENA,			/* bplcon0 */
+		640, 480, 1,
+		640, 480,
+		0x0041, 0x002b,						/* diwstrt h,v */
+		64,										/* 64-bit aligned */
+		BPC2_KILLEHB,							/* bplcon2 */
+		BPC3_PF2OF1 | BPC3_PF2OF0 | BPC3_SPRES1 | BPC3_SPRES0 |
+		BPC3_BRDRBLNK | BPC3_EXTBLKEN,	/* bplcon3 */
+		0x0071,									/* htotal */
+		0x000c,									/* hsstrt */
+		0x001c,									/* hsstop */
+		0x0008,									/* hbstrt */
+		0x001e,									/* hbstop */
+		0x020c,									/* vtotal */
+		0x0001,									/* vsstrt */
+		0x0003,									/* vsstop */
+		0x0000,									/* vbstrt */
+		0x000f,									/* vbstop */
+		0x0046,									/* hcenter */
+		BMC0_HARDDIS | BMC0_VARVBEN | BMC0_LOLDIS | BMC0_VARVSYEN |
+			BMC0_VARHSYEN | BMC0_VARBEAMEN | BMC0_BLANKEN,	/* beamcon0 */
+		FMODE_BPAGEM | FMODE_BPL32			/* fmode */
+	}, {
+		/* An 800x600 72Hz interlaced mode. */
+		"aga800x600", 0,
+		BPC0_SHRES | BPC0_LACE | BPC0_ECSENA,	/* bplcon0 */
+		896, 624, 1,							/* need rows%8 == 0 */
+		896, 624,								/* (cols too) */
+		0x0041, 0x001e,						/* diwstrt h,v */
+		64,						/* 64-bit aligned */
+		BPC2_KILLEHB,							/* bplcon2 */
+		BPC3_PF2OF1 | BPC3_PF2OF0 | BPC3_SPRES1 | BPC3_SPRES0 |
+		BPC3_BRDRBLNK | BPC3_EXTBLKEN,	/* bplcon3 */
+		0x0091,									/* htotal */
+		0x000e,									/* hsstrt */
+		0x001d,									/* hsstop */
+		0x000a,									/* hbstrt */
+		0x001e,									/* hbstop */
+		0x0156,									/* vtotal */
+		0x0001,									/* vsstrt */
+		0x0003,									/* vsstop */
+		0x0000,									/* vbstrt */
+		0x000f,									/* vbstop */
+		0x0050,									/* hcenter */
+		BMC0_HARDDIS | BMC0_VARVBEN | BMC0_LOLDIS | BMC0_VARVSYEN |
+		BMC0_VARHSYEN | BMC0_VARBEAMEN | BMC0_BLANKEN,	/* beamcon0 */
+		FMODE_BPAGEM | FMODE_BPL32			/* fmode */
+	},
+	/*
+	 * Additional AGA modes by Geert Uytterhoeven
+	 */
+	{
+		/*
+		 * A 720x400, 70 Hz noninterlaced AGA mode (29.27 kHz)
+		 */
+		"aga720x400", 0,
+		BPC0_SHRES | BPC0_ECSENA,			/* bplcon0 */
+		720, 400, 1,
+		720, 400,
+		0x0041, 0x0013,						/* diwstrt h,v */
+		64,										/* 64-bit aligned */
+		BPC2_KILLEHB,							/* bplcon2 */
+		BPC3_PF2OF1 | BPC3_PF2OF0 | BPC3_SPRES1 | BPC3_SPRES0 |
+		BPC3_BRDRBLNK | BPC3_EXTBLKEN,	/* bplcon3 */
+		0x0079,									/* htotal */
+		0x000e,									/* hsstrt */
+		0x0018,									/* hsstop */
+		0x0001,									/* hbstrt */
+		0x0021,									/* hbstop */
+		0x01a2,									/* vtotal */
+		0x0003,									/* vsstrt */
+		0x0005,									/* vsstop */
+		0x0000,									/* vbstrt */
+		0x0012,									/* vbstop */
+		0x0046,									/* hcenter */
+		BMC0_VARVBEN | BMC0_LOLDIS | BMC0_VARVSYEN | BMC0_VARHSYEN |
+		BMC0_VARBEAMEN | BMC0_PAL | BMC0_VARCSYEN | BMC0_CSYTRUE |
+		BMC0_VSYTRUE,							/* beamcon0 */
+		FMODE_BPAGEM | FMODE_BPL32			/* fmode */
+	}, {
+		/*
+		 * A 640x400, 76 Hz noninterlaced AGA mode (31.89 kHz)
+		 */
+		"aga640x400", 0,
+		BPC0_SHRES | BPC0_ECSENA,			/* bplcon0 */
+		640, 400, 1,
+		640, 400,
+		0x0041, 0x0015,						/* diwstrt h,v */
+		64,										/* 64-bit aligned */
+		BPC2_KILLEHB,							/* bplcon2 */
+		BPC3_PF2OF1 | BPC3_PF2OF0 | BPC3_SPRES1 | BPC3_SPRES0 |
+		BPC3_BRDRBLNK | BPC3_EXTBLKEN,	/* bplcon3 */
+		0x006f,									/* htotal */
+		0x000d,									/* hsstrt */
+		0x0018,									/* hsstop */
+		0x0001,									/* hbstrt */
+		0x0021,									/* hbstop */
+		0x01a4,									/* vtotal */
+		0x0003,									/* vsstrt */
+		0x0005,									/* vsstop */
+		0x0000,									/* vbstrt */
+		0x0014,									/* vbstop */
+		0x0046,									/* hcenter */
+		BMC0_VARVBEN | BMC0_LOLDIS | BMC0_VARVSYEN | BMC0_VARHSYEN |
+		BMC0_VARBEAMEN | BMC0_PAL | BMC0_VARCSYEN | BMC0_CSYTRUE |
+		BMC0_VSYTRUE,							/* beamcon0 */
+		FMODE_BPAGEM | FMODE_BPL32			/* fmode */
+	}, {
+		/*
+		 * A 640x480, 64 Hz noninterlaced AGA mode (31.89 kHz)
+		 */
+		"aga640x480a", 0,
+		BPC0_SHRES | BPC0_ECSENA,			/* bplcon0 */
+		640, 480, 1,
+		640, 480,
+		0x0041, 0x0015,						/* diwstrt h,v */
+		64,										/* 64-bit aligned */
+		BPC2_KILLEHB,							/* bplcon2 */
+		BPC3_PF2OF1 | BPC3_PF2OF0 | BPC3_SPRES1 | BPC3_SPRES0 |
+		BPC3_BRDRBLNK | BPC3_EXTBLKEN,	/* bplcon3 */
+		0x006f,									/* htotal */
+		0x000e,									/* hsstrt */
+		0x0018,									/* hsstop */
+		0x0001,									/* hbstrt */
+		0x0021,									/* hbstop */
+		0x01f4,									/* vtotal */
+		0x0003,									/* vsstrt */
+		0x0005,									/* vsstop */
+		0x0000,									/* vbstrt */
+		0x0014,									/* vbstop */
+		0x0046,									/* hcenter */
+		BMC0_VARVBEN | BMC0_LOLDIS | BMC0_VARVSYEN | BMC0_VARHSYEN |
+		BMC0_VARBEAMEN | BMC0_PAL | BMC0_VARCSYEN | BMC0_CSYTRUE |
+		BMC0_VSYTRUE,							/* beamcon0 */
+		FMODE_BPAGEM | FMODE_BPL32			/* fmode */
+	}
+};
+
+#define	NMODES	(sizeof(mono_modes) / sizeof(struct geometry))
+
+static struct fb_var_screeninfo mono_mono_amiga_fb_predefined[] = {
+	{ /* 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 }
+};
+
+static int mono_num_mono_amiga_fb_predefined= sizeof(mono_mono_amiga_fb_predefined)/sizeof(struct fb_var_screeninfo);
+
+
+
+/* Some default modes */
+#define OCS_PAL_LOWEND_DEFMODE	5	/* PAL non-laced for 500/2000 */
+#define OCS_PAL_3000_DEFMODE		4	/* PAL laced for 3000 */
+#define OCS_NTSC_LOWEND_DEFMODE	1	/* NTSC non-laced for 500/2000 */
+#define OCS_NTSC_3000_DEFMODE		0	/* NTSC laced for 3000 */
+#define AGA_DEFMODE					8	/* 640x480 non-laced for AGA */
+
+static int mono_amifb_inverse = 0;
+static int mono_amifb_mode = -1;
+
+static void mono_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"))
+			mono_amifb_inverse = 1;
+      else if (!strncmp(this_opt, "font:", 5))
+               strcpy(fb_info.fontname, this_opt+5);
+		else
+			for (i = 0; i < NMODES; i++)
+				if (!strcmp(this_opt, mono_modes[i].modename)) {
+					mono_amifb_mode = i;
+					break;
+				}
+}
+
+/* Notes about copper scrolling:
+ *
+ * 1. The VBLANK routine dynamically rewrites a LIVE copper list that is
+ *    currently being executed. Don't mess with it unless you know the
+ *    complications. Fairly sure that double buffered lists doesn't
+ *    make our life any easier.
+ *
+ * 2. The vblank code starts executing at logical line 0. Display must be
+ *    set up and ready to run by line DIWSTRT_V, typically 0x2c, minimum
+ *    value is 0x18 for maximum overscan.
+ *
+ *    Tests on my A500/030 for dynamically generating a 37 element copper
+ *    list during the VBLANK period under AmigaDos required between
+ *    0x10 and 0x14 scanlines. This should be pathological case, and
+ *    should do better under Linux/68k. It is however IMPERATIVE that I am
+ *    first in the VBLANK isr chain. Try to keep 'buildclist' as fast as
+ *    possible. Don't think that it justifies assembler thou'
+ *
+ * 3. PAL 640x256 display (no overscan) has copper-wait y positions in range
+ *    0x02c -> 0x12c. NTSC overscan uses values > 256 too. However counter
+ *    is 8 bit, will wrap. RKM 1.1 suggests use of a WAIT(0x00,0xff),
+ *    WAIT(x,y-0x100) pair to handle this case. This is WRONG - must use
+ *    WAIT(0xe2,0xff) to ensure that wrap occures by next copper
+ *    instruction. Argghh!
+ *
+ * 4. RKM 1.1 suggests Copper-wait x positions are in range [0,0xe2].
+ *    Horizontal blanking occurs in range 0x0f -> 0x35. Black screen
+ *    shown in range 0x04 -> 0x47.
+ *
+ *    Experiments suggest that using WAIT(0x00,y), we can replace up to
+ *    7 bitplane pointers before display fetch start. Using a 
+ *    WAIT(0xe0,y-1) instead, we can replace 8 pointers that should be
+ *    all that we need for a full AGA display. Should work because of
+ *    fetch latency with bitmapped display.
+ *
+ *    I think that this works. Someone please tell me if something breaks.
+ *
+ * Is diwstop_h the right value to use for "close to the end of line"?
+ * It seems to work for me, at least for the modes I've defined. -wjr
+ *
+ * I changed the Wait(diwstop_h, 0xff) for 256-line chunk skipping to
+ * Wait(diwstop_h-2, 0xff) to make it work with the additional
+ * `get-all-you-can-get-out-of-it' AGA modes. Maybe we should derive the
+ * wait position from the HTOTAL value? - G.U.
+ *
+ * The Wait(diwstop_h-2, 0xff) didn't work in Super72 under ECS, instead
+ * I changed it to Wait(htotal-4, 0xff). Dunno whether it works under AGA,
+ * and don't ask my why it works. I'm trying to get some facts on this issue
+ * from Commodore.
+ * -Jes
+ */
+
+static __inline__ ushort *mono_build_clist_hdr(register struct display *p,
+														ushort *cop,
+														ushort *othercop)	/* Interlace: List for next frame */
+{
+	int i;
+	ushort diwstrt_v = mono_current_par.diwstrt_v;
+	ushort diwstop_h = mono_current_par.diwstop_h;
+
+	if (othercop) {
+		*cop++ = CUSTOM_OFS(cop1lc);
+		*cop++ = (long)othercop >> 16;
+		*cop++ = CUSTOM_OFS(cop1lc) + 2;
+		*cop++ = (long)othercop;
+	}
+
+	/* Point Sprite 0 at cursor sprite: */
+	*cop++ = CUSTOM_OFS(sprpt[0]);
+	*cop++ = (ushort)((long)mono_current_par.cursor >> 16);
+	*cop++ = CUSTOM_OFS(sprpt[0]) + 2;
+	*cop++ = (ushort)((long)mono_current_par.cursor & 0x0000ffff);
+
+	/* Point Sprites 1-7 at dummy sprite: */
+	for (i=1; i<8; i++) {
+		*cop++ = CUSTOM_OFS(sprpt[i]);
+		*cop++ = (ushort)((long)mono_current_par.dummy >> 16);
+		*cop++ = CUSTOM_OFS(sprpt[i]) + 2;
+		*cop++ = (ushort)((long)mono_current_par.dummy & 0x0000ffff);
+	}
+
+	/* Halt copper until we have rebuilt the display list */
+
+	*cop++ = ((diwstrt_v - 2) << 8) | (diwstop_h >> 1) | 0x1;
+	*cop++ = 0xfffe;
+
+	return(cop);
+}
+
+static __inline__ ushort *mono_build_clist_dyn(register struct display *p,
+														ushort *cop,
+														int shf)				/* Interlace: Short frame */
+{
+	ushort diwstrt_v = mono_current_par.diwstrt_v;
+	ushort diwstop_h = mono_current_par.diwstop_h;
+	ushort y_wrap = mono_current_par.y_wrap;
+	ulong offset = y_wrap * mono_current_par.bytes_per_row;
+	long scrmem;
+	int i;
+
+	/* Set up initial bitplane ptrs */
+
+	for (i = 0 ; i < mono_current_par.scr_depth ; i++) {
+		scrmem    = ((long)mono_current_par.bitplane[i]) + offset;
+
+		if (shf)
+			scrmem += mono_current_par.bytes_per_row;
+
+		*cop++ = CUSTOM_OFS(bplpt[i]);
+		*cop++ = (long)scrmem >> 16;
+		*cop++ = CUSTOM_OFS(bplpt[i]) + 2;
+		*cop++ = (long)scrmem;
+	}
+
+	/* If wrapped frame needed - wait for line then switch bitplXs */
+
+	if (y_wrap) {
+		ushort line;
+        
+		if (mono_current_par.bplcon0 & BPC0_LACE)
+			line = diwstrt_v + (mono_current_par.scr_height - y_wrap)/2;
+		else
+			line = diwstrt_v + mono_current_par.scr_height - y_wrap;
+
+		/* Handle skipping over 256-line chunks */
+		while (line > 256) {
+			/* Hardware limitation - 8 bit counter    */
+			/* Wait(diwstop_h-2, 0xff) */
+			if (mono_current_par.bplcon0 & BPC0_SHRES)
+				/*
+				 * htotal-4 is used in SHRES-mode, as diwstop_h-2 doesn't work under ECS.
+				 * Does this work under AGA?
+				 * -Jes
+				 */
+				*cop++ = 0xff00 | ((mono_current_par.htotal-4) | 1);
+			else 
+				*cop++ = 0xff00 | ((diwstop_h-2) >> 1) | 0x1;
+
+			*cop++ = 0xfffe;
+			/* Wait(0, 0) - make sure we're in the new segment */
+			*cop++ = 0x0001;
+			*cop++ = 0xfffe;
+			line -= 256;
+
+			/*
+			 * Under ECS we have to keep color[0], as it is part of a special color-table.
+			 */
+
+			if (boot_info.bi_amiga.chipset == CS_ECS && mono_current_par.bplcon0 & BPC0_ECSENA) {
+				*cop++ = 0x0180;
+				*cop++ = mono_ecs_color_zero;
+			}
+		}
+	
+		/* Wait(diwstop_h, line - 1) */
+		*cop++ = ((line - 1)   << 8) | (diwstop_h >> 1) | 0x1;
+		*cop++ = 0xfffe;
+
+		for (i = 0 ; i < mono_current_par.scr_depth ; i++) {
+			scrmem = (long)mono_current_par.bitplane[i];
+			if (shf)
+				scrmem += mono_current_par.bytes_per_row;
+
+				*cop++ = CUSTOM_OFS(bplpt[i]); 
+				*cop++ = (long)scrmem >> 16;
+				*cop++ = CUSTOM_OFS(bplpt[i]) + 2;
+				*cop++ = (long)scrmem;
+		}
+	}
+    
+	/* End of Copper list */
+	*cop++ = 0xffff;
+	*cop++ = 0xfffe;
+
+	return(cop);
+}
+
+
+static __inline__ void mono_build_cursor(register struct display *p)
+{
+	int vs, hs, ve;
+	ushort diwstrt_v = mono_current_par.diwstrt_v;
+	ushort diwstrt_h = mono_current_par.diwstrt_h;
+
+	if (mono_current_par.bplcon0 & BPC0_LACE) {
+		vs = diwstrt_v + (p->cursor_y * p->fontheight)/2; 
+		ve = vs + p->fontheight/2;
+	} else {
+		vs = diwstrt_v + (p->cursor_y * p->fontheight); 
+		ve = vs + p->fontheight;
+	}
+
+	if (mono_current_par.bplcon0 & BPC0_ECSENA)
+		/*
+		 * It's an AGA mode. We'll assume that the sprite was set
+		 * into 35ns resolution by the appropriate SPRES bits in bplcon3.
+		 */
+		hs = diwstrt_h  * 4 + (p->cursor_x * p->fontwidth) - 4;
+	else
+		hs = diwstrt_h + (p->cursor_x * p->fontwidth) / 2 - 1;
+
+	if (mono_current_par.bplcon0 & BPC0_ECSENA) {
+		/* There are some high-order bits on the sprite position */
+		*((ulong *) mono_current_par.cursor) =
+		((((vs & 0xff) << 24) | ((vs & 0x100) >> 6) |
+		((vs & 0x200) >> 3)) |
+		(((hs & 0x7f8) << 13) | ((hs & 0x4) >> 2) |
+		((hs & 0x3) << 3)) |
+		(((ve & 0xff) << 8) | ((ve & 0x100) >> 7) |
+		((ve & 0x200) >> 4)));
+	} else {
+		*((ulong *) mono_current_par.cursor) =
+		((vs << 24) | ((vs & 0x00000100) >> 6) |
+		((hs & 0x000001fe) << 15) | (hs & 0x00000001) | 
+		((ve & 0x000000ff) << 8) | ((ve & 0x00000100) >> 7));
+	}
+}
+
+static void mono_build_ecs_colors(ushort color1, ushort color2, ushort color3, 
+                      ushort color4, ushort *table)
+{
+/*
+ * This function calculates the special ECS color-tables needed when running
+ * new screen-modes available under ECS. See the hardware reference manual
+ * 3rd edition for details.
+ * -Jes
+ */
+ushort  t;
+
+        t = (color1 & 0x0ccc);
+        table[0] = t;
+        table[4] = t;
+        table[8] = t;
+        table[12] = t;
+        t = t >> 2;
+        table[0] = (table[0] | t);
+        table[1] = t;
+        table[2] = t;
+        table[3] = t;
+
+        t = (color2 & 0x0ccc);
+        table[1] = (table[1] | t);
+        table[5] = t;
+        table[9] = t;
+        table[13] = t;
+        t = t >> 2;
+        table[4] = (table[4] | t);
+        table[5] = (table[5] | t);
+        table[6] = t;
+        table[7] = t;
+
+        t = (color3 & 0x0ccc);
+        table[2] = (table[2] | t);
+        table[6] = (table[6] | t);
+        table[10] = t;
+        table[14] = t;
+        t = t >> 2;
+        table[8] = (table[8] | t);
+        table[9] = (table[9] | t);
+        table[10] = (table[10] | t);
+        table[11] = t;
+
+        t = (color4 & 0x0ccc);
+        table[3] = (table[3] | t);
+        table[7] = (table[7] | t);
+        table[11] = (table[11] | t);
+        table[15] = t;
+        t = t >> 2;
+        table[12] = (table[12] | t);
+        table[13] = (table[13] | t);
+        table[14] = (table[14] | t);
+        table[15] = (table[15] | t);
+
+}
+
+/* mono_display_init():
+ *
+ *    Fills out (struct display *) given a geometry structure
+ */
+
+static void mono_display_init(struct display *p,
+                         struct geometry *geom, ushort inverse)
+{
+	ushort ecs_table[16];
+	int    i;
+	char   *chipptr;
+	ushort diwstrt_v, diwstop_v;
+	ushort diwstrt_h, diwstop_h;
+	ushort diw_min_h, diw_min_v;
+	ushort bplmod, diwstrt, diwstop, diwhigh, ddfstrt, ddfstop;
+	ushort cursorheight, cursormask = 0;
+	u_long size;
+
+	/* Decide colour scheme */
+
+	if (inverse) {
+		mono_current_par.fgcol   = FG_COLOR_INV;
+		mono_current_par.bgcol   = BG_COLOR_INV;
+		mono_current_par.crsrcol = CRSR_COLOR_INV;
+	} else {
+		mono_current_par.fgcol   = FG_COLOR;
+		mono_current_par.bgcol   = BG_COLOR;
+		mono_current_par.crsrcol = CRSR_COLOR;
+	}
+
+	/* Define screen geometry */
+   
+	mono_current_par.scr_max_height = geom->scr_max_height;
+	mono_current_par.scr_max_width  = geom->scr_max_width; 
+	mono_current_par.scr_height     = geom->scr_height;
+	mono_current_par.scr_width      = geom->scr_width;
+	mono_current_par.scr_depth      = geom->scr_depth;
+	mono_current_par.bplcon0        = geom->bplcon0 | BPC0_COLOR;
+	mono_current_par.htotal         = geom->htotal;
+
+	/* htotal was added, as I use it to calc the pal-line. -Jes */
+
+	if (mono_current_par.scr_depth < 8)
+		mono_current_par.bplcon0 |= (mono_current_par.scr_depth << 12);
+	else {
+		/* must be exactly 8 */
+		mono_current_par.bplcon0 |= BPC0_BPU3;
+	}
+
+	diw_min_v         = geom->diwstrt_v;
+	diw_min_h         = geom->diwstrt_h;
+
+	/* We can derive everything else from this, at least for OCS */
+	/*
+	 * For AGA: we don't use the finer position control available for
+	 * diw* yet (could be set by 35ns increments).
+	 */
+
+	/* Calculate line and plane size while respecting the alignment restrictions */
+	mono_current_par.bytes_per_row  = ((mono_current_par.scr_width+geom->alignment-1)&~(geom->alignment-1)) >> 3;
+	mono_current_par.plane_size     = mono_current_par.bytes_per_row * mono_current_par.scr_height;
+
+
+	/*
+	 *		Quick hack for frame buffer mmap():
+	 *
+	 *		plane_size must be a multiple of the page size
+	 */
+
+	mono_current_par.plane_size = PAGE_ALIGN(mono_current_par.plane_size);
+
+
+	mono_current_par.y_wrap   = 0;                  mono_current_par.scroll_latch = 1;
+	p->cursor_x = 0; p->cursor_y = 0; mono_current_par.cursor_latch = 1;
+
+	if (mono_current_par.bplcon0 & BPC0_LACE) {
+		bplmod = mono_current_par.bytes_per_row;
+		diwstrt_v = diw_min_v + (mono_current_par.scr_max_height - mono_current_par.scr_height)/4;
+		diwstop_v = (diwstrt_v + mono_current_par.scr_height/2);
+	} else {
+		bplmod = 0;
+		diwstrt_v = diw_min_v + (mono_current_par.scr_max_height - mono_current_par.scr_height)/2;
+		diwstop_v = (diwstrt_v + mono_current_par.scr_height);
+	}
+
+	if (mono_current_par.bplcon0 & BPC0_HIRES) {
+		diwstrt_h =  diw_min_h + (mono_current_par.scr_max_width - mono_current_par.scr_width)/4;
+		diwstop_h = (diwstrt_h + mono_current_par.scr_width/2);
+		/* ??? Where did 0x1d5 come from in original code ??? */
+	} else if (mono_current_par.bplcon0 & BPC0_SHRES) {
+		diwstrt_h =  diw_min_h + (mono_current_par.scr_max_width - mono_current_par.scr_width)/8;
+		diwstop_h = (diwstrt_h + mono_current_par.scr_width/4);
+	} else {
+		diwstrt_h =  diw_min_h + (mono_current_par.scr_max_width - mono_current_par.scr_width)/2;
+		diwstop_h = (diwstrt_h + mono_current_par.scr_width);
+	}
+
+	if (mono_current_par.bplcon0 & BPC0_HIRES) {
+		ddfstrt = (diwstrt_h >> 1) - 4;
+		ddfstop = ddfstrt + (4 * (mono_current_par.bytes_per_row>>1)) - 8;
+	} else if (mono_current_par.bplcon0 & BPC0_SHRES && boot_info.bi_amiga.chipset == CS_AGA) {
+		/* There may be some interaction with FMODE here... -8 is magic. */
+
+		/*
+		 * This should be fixed, so it supports all different
+		 * FMODE's.  FMODE varies the speed with 1,2 & 4 the
+		 * standard ECS speed.  Someone else has to do it, as
+		 * I don't have an AGA machine with MMU available
+		 * here.
+		 *
+		 * This particular speed looks like FMODE = 3 to me.
+		 * ddfstop should be changed so it depends on FMODE under AGA.
+		 * -Jes
+		 */
+		ddfstrt = (diwstrt_h >> 1) - 8;
+		ddfstop = ddfstrt + (2 * (mono_current_par.bytes_per_row>>1)) - 8;
+	} else if (mono_current_par.bplcon0 & BPC0_SHRES && boot_info.bi_amiga.chipset == CS_ECS){
+		/* 
+		 * Normal speed for ECS, should be the same for FMODE = 0
+		 * -Jes
+		 */
+		ddfstrt = (diwstrt_h >> 1) - 2;
+		ddfstop = ddfstrt + (2 * (mono_current_par.bytes_per_row>>1)) - 8;
+	} else {
+		ddfstrt = (diwstrt_h >> 1) - 8;
+		ddfstop = ddfstrt + (8 * (mono_current_par.bytes_per_row>>1)) - 8;
+	}
+
+	if (mono_current_par.bplcon0 & BPC0_LACE)
+		cursorheight = p->fontheight/2;
+	else
+		cursorheight = p->fontheight;
+
+	/*
+	 *		Quick hack for frame buffer mmap():
+	 *
+	 *		chipptr must be at a page boundary
+	 */
+
+	size = mono_current_par.scr_depth*mono_current_par.plane_size+COP_MEM_REQ+SPR_MEM_REQ+4*(cursorheight-1);
+	size += PAGE_SIZE-1;
+	chipptr = amiga_chip_alloc(size);
+	chipptr = (char *)PAGE_ALIGN((u_long)chipptr);
+
+   
+	/* locate the bitplanes */
+	/* These MUST be 64 bit aligned for full AGA compatibility!! */
+
+	mono_current_par.smem_start = (u_long)chipptr;
+	mono_current_par.smem_len = mono_current_par.plane_size*mono_current_par.scr_depth;
+	mono_current_par.geometry = geom;
+
+	for (i = 0 ; i < mono_current_par.scr_depth ; i++, chipptr += mono_current_par.plane_size) {
+		mono_current_par.bitplane[i] = (u_char *) chipptr;
+		memset ((void *)chipptr, 0, mono_current_par.plane_size);  /* and clear */
+	}
+
+	/* locate the copper lists */
+	mono_current_par.coplist1hdr = (ushort *) chipptr;  chipptr += MAX_COP_LIST_ENTS * 4;
+	mono_current_par.coplist2hdr = (ushort *) chipptr;  chipptr += MAX_COP_LIST_ENTS * 4;
+
+	/* locate the sprite data */
+	mono_current_par.cursor      = (ushort *) chipptr;  chipptr += 8+4*cursorheight;
+	mono_current_par.dummy       = (ushort *) chipptr;  chipptr += 12;
+
+	/* create the sprite data for the cursor image */
+	memset((void *)mono_current_par.cursor, 0, 8+4*cursorheight);
+	/*
+	 * Only AGA supplies hires sprites.
+	 */
+	if (mono_current_par.bplcon0 & BPC0_ECSENA && boot_info.bi_amiga.chipset == CS_AGA)
+		/* AGA cursor is SHIRES, ECS sprites differ */
+		for (i = 0; (i < p->fontwidth) && (i < 16); i++)
+			cursormask |= 1<<(15-i);
+	else
+		/* For OCS & ECS sprites are pure LORES 8-< */
+		for (i = 0; (i < p->fontwidth/2) && (i < 8); i++)
+			cursormask |= 1<<(15-i);
+
+	mono_current_par.cursor[0] = mono_cursor_data[0];
+	mono_current_par.cursor[1] = mono_cursor_data[1];
+
+#if (CRSR_BLOCK == 1)
+	for (i = 0; i < cursorheight; i++)
+#else
+	for (i = cursorheight-2; i < cursorheight; i++)
+#endif
+		mono_current_par.cursor[2+2*i] = cursormask;
+
+	/* set dummy sprite data to a blank sprite */
+	memset((void *)mono_current_par.dummy, 0, 12);
+  
+	/* set cursor flashing */
+	mono_current_par.cursor_flash = CRSR_FLASH;
+
+	/* Make the cursor invisible */
+	mono_current_par.cursor_visible = 0;
+ 
+	/* Initialise the chipregs */
+	mono_current_par.diwstrt_v = diwstrt_v;
+	mono_current_par.diwstrt_h = diwstrt_h;
+	mono_current_par.diwstop_v = diwstop_v;
+	mono_current_par.diwstop_h = diwstop_h;
+	diwstrt = ((diwstrt_v << 8) | diwstrt_h);
+	diwstop = ((diwstop_v & 0xff) << 8) | (diwstop_h & 0xff);
+
+	custom.bplcon0   = mono_current_par.bplcon0;	/* set the display mode */
+	custom.bplcon1   = 0;		/* Needed for horizontal scrolling */
+	custom.bplcon2   = 0;
+	custom.bpl1mod   = bplmod;
+	custom.bpl2mod   = bplmod;
+	custom.diwstrt   = diwstrt;
+	custom.diwstop   = diwstop;
+	custom.ddfstrt   = ddfstrt;
+	custom.ddfstop   = ddfstop;
+
+	custom.color[0]  = COLOR_MSB(mono_current_par.bgcol);
+	custom.color[1]  = COLOR_MSB(mono_current_par.fgcol);
+	custom.color[17] = COLOR_MSB(mono_current_par.crsrcol); /* Sprite 0 color */
+
+	if (boot_info.bi_amiga.chipset == CS_AGA) {
+		/* Fill in the LSB of the 24 bit color palette */
+		/* Must happen after MSB */
+		custom.bplcon3   = geom->bplcon3 | BPC3_LOCT;
+		custom.color[0]  = COLOR_LSB(mono_current_par.bgcol);
+		custom.color[1]  = COLOR_LSB(mono_current_par.fgcol);
+		custom.color[17] = COLOR_LSB(mono_current_par.crsrcol);
+		custom.bplcon3   = geom->bplcon3;
+	}
+
+	if (boot_info.bi_amiga.chipset == CS_ECS && mono_current_par.bplcon0 & BPC0_ECSENA) {
+		/*
+		 * Calculation of the special ECS color-tables for
+		 * planes and sprites is done in the function
+		 * build_ecs_table
+		 */
+
+		/*
+		 * Calcs a special ECS colortable for the bitplane,
+		 * and copies it to the custom registers
+		 */
+		mono_build_ecs_colors(COLOR_MSB(mono_current_par.bgcol), COLOR_MSB(mono_current_par.fgcol),
+				 0, 0, ecs_table); 
+
+#if 0
+		for (i = 0; i < 8; i++){
+			custom.color[i]   = ecs_table[i*2];
+			custom.color[i+8] = ecs_table[i*2+1];
+		}
+#else
+		for (i = 0; i < 16; i++){
+			custom.color[i]   = ecs_table[i];
+		}
+#endif
+
+		mono_ecs_color_zero = ecs_table[0];
+
+		/*
+		 * Calcs a special ECS colortable for the cursor
+		 * sprite, and copies it to the appropriate custom
+		 * registers
+		 */
+		mono_build_ecs_colors(0, COLOR_MSB(mono_current_par.crsrcol), 0, 0, ecs_table);
+
+		for (i = 0; i < 16; i++){
+			custom.color[i+16] = ecs_table[i];
+		}
+	}
+
+	if (!(geom->isOCS)) {
+		/* Need to set up a bunch more regs */
+		/* Assumes that diwstrt is in the (0,0) sector, but stop might not be */
+		diwhigh = (diwstop_v & 0x700) | ((diwstop_h & 0x100) << 5);
+
+		custom.bplcon2   = geom->bplcon2;
+		custom.bplcon3   = geom->bplcon3;
+		/* save bplcon3 for blanking */
+		mono_save_bplcon3 = geom->bplcon3;
+
+		custom.diwhigh   = diwhigh;	/* must happen AFTER diwstrt, stop */
+
+		custom.htotal	= geom->htotal;
+		custom.hsstrt	= geom->hsstrt;
+		custom.hsstop	= geom->hsstop;
+		custom.hbstrt	= geom->hbstrt;
+		custom.hbstop	= geom->hbstop;
+		custom.vtotal	= geom->vtotal;
+		custom.vsstrt	= geom->vsstrt;
+		custom.vsstop	= geom->vsstop;
+		custom.vbstrt	= geom->vbstrt;
+		custom.vbstop	= geom->vbstop;
+		custom.hcenter	= geom->hcenter;
+		custom.beamcon0	= geom->beamcon0;
+		if (boot_info.bi_amiga.chipset == CS_AGA) {
+			custom.fmode	= geom->fmode;
+		}
+		/* 
+		 * fmode does NOT! exist under ECS, weird things might happen
+		 */
+
+		/* We could load 8-bit colors here, if we wanted */
+
+		/*
+		 *    The minimum period for audio depends on htotal (for OCS/ECS/AGA)
+		 */
+		if (boot_info.bi_amiga.chipset != CS_STONEAGE)
+			amiga_audio_min_period = (geom->htotal>>1)+1;
+	}
+
+
+	/* Build initial copper lists. sprites must be set up, and mono_current_par.diwstrt. */
+
+	if (mono_current_par.bplcon0 & BPC0_LACE) {
+		mono_current_par.coplist1dyn = mono_build_clist_hdr(p,mono_current_par.coplist1hdr, mono_current_par.coplist2hdr),
+		mono_build_clist_dyn(p, mono_current_par.coplist1dyn, 0);
+
+		mono_current_par.coplist2dyn = mono_build_clist_hdr(p,mono_current_par.coplist2hdr, mono_current_par.coplist1hdr),
+		mono_build_clist_dyn(p, mono_current_par.coplist2dyn, 1);
+	} else {
+		mono_current_par.coplist1dyn = mono_build_clist_hdr(p,mono_current_par.coplist1hdr, NULL),
+		mono_build_clist_dyn(p, mono_current_par.coplist1dyn, 0);
+	}
+
+
+	/* Get ready to run first copper list */
+	custom.cop1lc = mono_current_par.coplist1hdr;
+	custom.copjmp1 = 0;
+
+	/* turn on DMA for bitplane and sprites */
+	custom.dmacon = DMAF_SETCLR | DMAF_RASTER | DMAF_COPPER | DMAF_SPRITE;
+
+	if (mono_current_par.bplcon0 & BPC0_LACE) {
+		/* Make sure we get the fields in the right order */
+
+		/* wait for LOF frame bit to go low */
+		while (custom.vposr & 0x8000)
+			;
+
+		/* wait for LOF frame bit to go high */
+		while (!(custom.vposr & 0x8000))
+			;
+
+		/* start again at the beginning of copper list 1 */
+		custom.cop1lc = mono_current_par.coplist1hdr;
+		custom.copjmp1 = 0;
+	}
+}
+
+
+static void mono_amifb_interrupt(int irq, struct pt_regs *fp, void *data)
+{
+	register struct display *p = disp;
+
+	static ushort cursorcount = 0;
+	static ushort cursorstate = 0;
+
+	/* I *think* that you should only change display lists on long frame.
+	 * At least it goes awfully perculiar on my A500 without the following
+	 * test. Not really in a position to test this hypothesis, so sorry
+	 * for the slow scrolling, all you flicker-fixed souls
+	 */
+
+	if (!(mono_current_par.bplcon0 & BPC0_LACE) || (custom.vposr & 0x8000)) {
+		if (mono_current_par.scroll_latch || mono_current_par.cursor_latch)
+			mono_build_cursor(p);
+
+		if (mono_current_par.scroll_latch)
+			if (mono_current_par.bplcon0 & BPC0_LACE) {
+				mono_build_clist_dyn(p, mono_current_par.coplist1dyn, 0);
+				mono_build_clist_dyn(p, mono_current_par.coplist2dyn, 1);
+			} else
+				mono_build_clist_dyn(p, mono_current_par.coplist1dyn, 0);
+			mono_current_par.scroll_latch = 0;
+			mono_current_par.cursor_latch = 0;
+	}
+
+	if (!(custom.potgor & (1<<10)))
+		mono_vblank.right_count++;
+
+	if (mono_current_par.cursor_visible) {
+		if (mono_current_par.cursor_flash) {
+			if (cursorcount)
+				cursorcount--;
+			else {
+				cursorcount = CRSR_RATE;
+				if ((cursorstate = !cursorstate))
+					custom.dmacon = DMAF_SETCLR | DMAF_SPRITE;
+				else
+					custom.dmacon = DMAF_SPRITE;
+			}
+		}
+	} else
+		custom.dmacon = DMAF_SPRITE;
+
+	if (mono_do_blank) {
+		custom.dmacon = DMAF_RASTER | DMAF_SPRITE;
+		custom.color[0] = 0;
+		if (boot_info.bi_amiga.chipset == CS_AGA) {
+			/* Fill in the LSB of the 24 bit color palette */
+			/* Must happen after MSB */
+			custom.bplcon3 = mono_save_bplcon3 | BPC3_LOCT;
+			custom.color[0]= 0;
+			custom.bplcon3 = mono_save_bplcon3;
+		}
+		mono_do_blank = 0;
+	}
+
+	if (mono_do_unblank) {
+		if (mono_current_par.cursor_visible)
+			custom.dmacon = DMAF_SETCLR | DMAF_RASTER | DMAF_SPRITE;
+		else
+			custom.dmacon = DMAF_SETCLR | DMAF_RASTER;
+		custom.color[0] = COLOR_MSB(mono_current_par.bgcol);
+		if (boot_info.bi_amiga.chipset == CS_AGA) {
+			/* Fill in the LSB of the 24 bit color palette */
+			/* Must happen after MSB */
+			custom.bplcon3 = mono_save_bplcon3 | BPC3_LOCT;
+			custom.color[0] = COLOR_LSB(mono_current_par.bgcol);
+			custom.bplcon3 = mono_save_bplcon3;
+		}
+		/* color[0] is set to mono_ecs_color_zero under ECS */
+		if (boot_info.bi_amiga.chipset == CS_ECS && mono_current_par.bplcon0 & BPC0_ECSENA) {
+			custom.color[0]  = mono_ecs_color_zero;
+		}
+		mono_do_unblank = 0;
+	}
+
+	mono_vblank.done = 1;
+}
+
+
+static int mono_amiga_fb_get_fix(struct fb_fix_screeninfo *fix, int con)
+{
+	int i;
+
+	strcpy(fix->id, mono_current_par.geometry->modename);
+	fix->smem_start = mono_current_par.smem_start;
+	fix->smem_len = mono_current_par.smem_len;
+
+	/*
+	 *		Only monochrome bitmap at the moment
+	 */
+
+	fix->type = FB_TYPE_PACKED_PIXELS;
+
+	fix->type_aux = 0;
+	if (mono_amifb_inverse)
+		fix->visual = FB_VISUAL_MONO10;
+	else
+		fix->visual = FB_VISUAL_MONO01;
+
+	fix->xpanstep = 0;
+	fix->ypanstep = 0;
+	fix->ywrapstep = 1;
+
+	for (i = 0; i < arraysize(fix->reserved); i++)
+		fix->reserved[i] = 0;
+	return(0);
+}
+
+
+static int mono_amiga_fb_get_var(struct fb_var_screeninfo *var, int con)
+{
+	int i;
+
+	var->xres = mono_current_par.geometry->scr_width;
+	var->yres = mono_current_par.geometry->scr_height;
+	var->xres_virtual = var->xres;
+	var->yres_virtual = var->yres;
+	var->xoffset = 0;
+	var->yoffset = 0;
+
+	var->bits_per_pixel = mono_current_par.geometry->scr_depth;
+	var->grayscale = 0;
+
+	if (boot_info.bi_amiga.chipset == CS_AGA) {
+		var->red.offset = 0;
+		var->red.length = 8;
+		var->red.msb_right = 0;
+		var->green = var->red;
+		var->blue = var->red;
+	} else {
+		var->red.offset = 0;
+		var->red.length = 4;
+		var->red.msb_right = 0;
+		var->green = var->red;
+		var->blue = var->red;
+	}
+
+	var->nonstd = 0;
+	var->activate = 0;
+
+	var->width = -1;
+	var->height = -1;
+
+	var->accel = FB_ACCEL_NONE;
+
+	var->pixclock = 35242;
+	var->left_margin = (mono_current_par.geometry->hbstop-mono_current_par.geometry->hsstrt)*8;
+	var->right_margin = (mono_current_par.geometry->hsstrt-mono_current_par.geometry->hbstrt)*8;
+	var->upper_margin = (mono_current_par.geometry->vbstop-mono_current_par.geometry->vsstrt)*8;
+	var->lower_margin = (mono_current_par.geometry->vsstrt-mono_current_par.geometry->vbstrt)*8;
+	var->hsync_len = (mono_current_par.geometry->hsstop-mono_current_par.geometry->hsstrt)*8;
+	var->vsync_len = (mono_current_par.geometry->vsstop-mono_current_par.geometry->vsstrt)*8;
+	var->sync = 0;
+	if (mono_current_par.geometry->bplcon0 & BPC0_LACE)
+		var->vmode = FB_VMODE_INTERLACED;
+	else if ((boot_info.bi_amiga.chipset == CS_AGA) && (mono_current_par.geometry->fmode & FMODE_BSCAN2))
+		var->vmode = FB_VMODE_DOUBLE;
+	else
+		var->vmode = FB_VMODE_NONINTERLACED;
+
+	for (i = 0; i < arraysize(var->reserved); i++)
+		var->reserved[i] = 0;
+
+	return(0);
+}
+
+
+static void mono_amiga_fb_set_disp(int con)
+{
+	struct fb_fix_screeninfo fix;
+
+	mono_amiga_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 = mono_amifb_inverse;
+}
+
+
+static int mono_amiga_fb_set_var(struct fb_var_screeninfo *var, int con)
+{
+	/*
+	 *		Not yet implemented
+	 */
+	return 0;				/* The X server needs this */
+	return(-EINVAL);
+}
+
+
+static short mono_red_normal[] = {
+	((BG_COLOR & 0xff0000)>>8) | ((BG_COLOR & 0xff0000)>>16),
+	((FG_COLOR & 0xff0000)>>8) | ((FG_COLOR & 0xff0000)>>16)
+};
+static short mono_green_normal[] = {
+	((BG_COLOR & 0x00ff00)) | ((BG_COLOR & 0x00ff00)>>8),
+	((FG_COLOR & 0x00ff00)) | ((FG_COLOR & 0x00ff00)>>8)
+};
+static short mono_blue_normal[] = {
+	((BG_COLOR & 0x0000ff)<<8) | ((BG_COLOR & 0x0000ff)),
+	((FG_COLOR & 0x0000ff)<<8) | ((FG_COLOR & 0x0000ff))
+};
+
+static short mono_red_inverse[] = {
+	((BG_COLOR_INV & 0xff0000)>>8) | ((BG_COLOR_INV & 0xff0000)>>16),
+	((FG_COLOR_INV & 0xff0000)>>8) | ((FG_COLOR_INV & 0xff0000)>>16)
+};
+static short mono_green_inverse[] = {
+	((BG_COLOR_INV & 0x00ff00)) | ((BG_COLOR_INV & 0x00ff00)>>8),
+	((FG_COLOR_INV & 0x00ff00)) | ((FG_COLOR_INV & 0x00ff00)>>8)
+};
+static short mono_blue_inverse[] = {
+	((BG_COLOR_INV & 0x0000ff)<<8) | ((BG_COLOR_INV & 0x0000ff)),
+	((FG_COLOR_INV & 0x0000ff)<<8) | ((FG_COLOR & 0x0000ff))
+};
+
+static struct fb_cmap mono_default_cmap_normal = { 0, 2, mono_red_normal, mono_green_normal, mono_blue_normal, NULL };
+static struct fb_cmap mono_default_cmap_inverse = { 0, 2, mono_red_inverse, mono_green_inverse, mono_blue_inverse, NULL };
+
+static int mono_amiga_fb_get_cmap(struct fb_cmap *cmap, int kspc, int con)
+{
+	int i, start;
+	unsigned short *red, *green, *blue, *transp;
+	unsigned int hred, hgreen, hblue, htransp;
+	struct fb_cmap *def_cmap;
+
+	red = cmap->red;
+	green = cmap->green;
+	blue = cmap->blue;
+	transp = cmap->transp;
+	start = cmap->start;
+	if (start < 0)
+		return(-EINVAL);
+
+	if (mono_amifb_inverse)
+		def_cmap = &mono_default_cmap_inverse;
+	else
+		def_cmap = &mono_default_cmap_normal;
+
+	for (i = 0; i < cmap->len; i++) {
+		if (i < def_cmap->len) {
+			hred = def_cmap->red[i];
+			hgreen = def_cmap->green[i];
+			hblue = def_cmap->blue[i];
+			if (def_cmap->transp)
+				htransp = def_cmap->transp[i];
+			else
+				htransp = 0;
+		} else
+			hred = hgreen = hblue = htransp = 0;
+		if (kspc) {
+			*red = hred;
+			*green = hgreen;
+			*blue = hblue;
+			if (transp)
+				*transp = htransp;
+		} else {
+			put_fs_word(hred, red);
+			put_fs_word(hgreen, green);
+			put_fs_word(hblue, blue);
+			if (transp)
+				put_fs_word(htransp, transp);
+		}
+		red++;
+		green++;
+		blue++;
+		if (transp)
+			transp++;
+	}
+	return(0);
+}
+
+
+static int mono_amiga_fb_set_cmap(struct fb_cmap *cmap, int kspc, int con)
+{
+	/*
+	 *		Not yet implemented
+	 */
+	return(-EINVAL);
+}
+
+
+static int mono_amiga_fb_pan_display(struct fb_var_screeninfo *var, int con)
+{
+	/*
+	 *		Not yet implemented
+	 */
+	return(-EINVAL);
+}
+
+
+static int mono_amiga_fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+								  unsigned long arg, int con)
+{
+	return(-EINVAL);
+}
+
+static struct fb_ops mono_amiga_fb_ops = {
+	mono_amiga_fb_get_fix, mono_amiga_fb_get_var, mono_amiga_fb_set_var, mono_amiga_fb_get_cmap,
+	mono_amiga_fb_set_cmap, mono_amiga_fb_pan_display, mono_amiga_fb_ioctl	
+};
+
+
+static int mono_amifb_switch (int con)
+{
+	mono_current_par.y_wrap = disp[con].var.yoffset;
+	mono_current_par.cursor_latch = 1;
+	mono_current_par.scroll_latch = 1;
+	return(0);
+}
+
+
+static int mono_amifb_updatevar(int con)
+{
+	mono_current_par.y_wrap = disp[con].var.yoffset;
+	mono_current_par.cursor_latch = 1;
+	mono_current_par.scroll_latch = 1;
+	return(0);
+}
+
+
+static void mono_amifb_blank(int blank)
+{
+	if (blank)
+		mono_do_blank = 1;
+	else
+		mono_do_unblank = 1;
+}
+
+
+static struct fb_info *mono_amiga_fb_init(long *mem_start)
+{
+	int mode = mono_amifb_mode;
+	ulong model;
+	int inverse_video = mono_amifb_inverse;
+	int err;
+
+	err=register_framebuffer("Amiga Builtin", &node, &mono_amiga_fb_ops,  mono_num_mono_amiga_fb_predefined,
+									 mono_mono_amiga_fb_predefined);
+
+	model = boot_info.bi_un.bi_ami.model;
+	if (mode == -1)
+		if (boot_info.bi_amiga.chipset == CS_AGA)
+			mode = AGA_DEFMODE;
+		else if (model == AMI_3000)
+			mode = boot_info.bi_un.bi_ami.vblank == 50 ? OCS_PAL_3000_DEFMODE : OCS_NTSC_3000_DEFMODE;
+		else
+			mode = boot_info.bi_un.bi_ami.vblank == 50 ? OCS_PAL_LOWEND_DEFMODE : OCS_NTSC_LOWEND_DEFMODE;
+
+	mono_init_vblank();
+	mono_display_init(disp, &mono_modes[mode], inverse_video);
+	if (!add_isr(IRQ_AMIGA_VERTB, mono_amifb_interrupt, 0, NULL, "frame buffer"))
+		panic("Couldn't add vblank interrupt");
+
+	mono_amiga_fb_get_var(&disp[0].var, 0);
+	if (mono_amifb_inverse)
+		disp[0].cmap = mono_default_cmap_inverse;
+	else
+		disp[0].cmap = mono_default_cmap_normal;
+	mono_amiga_fb_set_disp(-1);
+
+	strcpy(fb_info.modename, "Amiga Builtin ");
+	fb_info.disp = disp;
+	fb_info.switch_con = &mono_amifb_switch;
+	fb_info.updatevar = &mono_amifb_updatevar;
+	fb_info.blank = &mono_amifb_blank;	
+	strcat(fb_info.modename, mono_modes[mode].modename);
+
+	return(&fb_info);
+}
+#endif /* USE_MONO_AMIFB_IF_NON_AGA */
+
+
+/* -------------------- OCS specific routines ------------------------------- */
+
+
+#ifdef CONFIG_AMIFB_OCS
+   /*
+    *    Initialization
+    *
+    *    Allocate the required chip memory.
+    *    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 ocs_init(void)
+{
+   u_long p;
+
+   /*
+    *    Disable Display DMA
+    */
+
+   custom.dmacon = DMAF_ALL | DMAF_MASTER;
+
+   /*
+    *    Set the Default Video Mode
+    */
+
+   if (!amifb_mode)
+      amifb_mode = get_video_mode(boot_info.bi_un.bi_ami.vblank == 50 ?
+                                  DEFMODE_PAL : DEFMODE_NTSC);
+
+   /*
+    *    Allocate Chip RAM Structures
+    */
+
+   videomemorysize = VIDEOMEMSIZE_OCS;
+
+
+   ...
+   ...
+   ...
+
+
+   /*
+    *    Enable Display DMA
+    */
+
+   custom.dmacon = DMAF_SETCLR | DMAF_MASTER | DMAF_RASTER | DMAF_COPPER |
+                   DMAF_SPRITE;
+
+   return(0);
+}
+#endif /* CONFIG_AMIFB_OCS */
+
+
+/* -------------------- ECS specific routines ------------------------------- */
+
+
+#ifdef CONFIG_AMIFB_ECS
+   /*
+    *    Initialization
+    *
+    *    Allocate the required chip memory.
+    *    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 ecs_init(void)
+{
+   u_long p;
+
+   /*
+    *    Disable Display DMA
+    */
+
+   custom.dmacon = DMAF_ALL | DMAF_MASTER;
+
+   /*
+    *    Set the Default Video Mode
+    */
+
+   if (!amifb_mode)
+      if (AMIGAHW_PRESENT(AMBER_FF))
+         amifb_mode = get_video_mode(boot_info.bi_un.bi_ami.vblank == 50 ?
+                                     DEFMODE_AMBER_PAL : DEFMODE_AMBER_NTSC);
+      else
+         amifb_mode = get_video_mode(boot_info.bi_un.bi_ami.vblank == 50 ?
+                                     DEFMODE_PAL : DEFMODE_NTSC);
+
+   /*
+    *    Allocate Chip RAM Structures
+    */
+
+   if (boot_info.bi_amiga.chip_size > 1048576)
+      videomemorysize = VIDEOMEMSIZE_ECS_2M;
+   else
+      videomemorysize = VIDEOMEMSIZE_ECS_1M;
+
+
+   ...
+   ...
+   ...
+
+
+   /*
+    *    Enable Display DMA
+    */
+
+   custom.dmacon = DMAF_SETCLR | DMAF_MASTER | DMAF_RASTER | DMAF_COPPER |
+                   DMAF_SPRITE;
+
+   return(0);
+}
+#endif /* CONFIG_AMIFB_ECS */
+
+
+/* -------------------- AGA specific routines ------------------------------- */
+
+
+#ifdef CONFIG_AMIFB_AGA
+   /*
+    *    Macros for the conversion from real world values to hardware register
+    *    values (and vice versa).
+    *
+    *    This helps us to keep our attention on the real stuff...
+    *
+    *    Hardware limits:
+    *
+    *       parameter     min      max     step
+    *       ---------     ---     ----     ----
+    *       diwstrt_h       0     2047        1
+    *       diwstrt_v       0     2047        1
+    *       diwstop_h       0     2047        1
+    *       diwstop_v       0     2047        1
+    *
+    *       ddfstrt         0     2032       16
+    *       ddfstop         0     2032       16
+    *
+    *       htotal          8     2048        8
+    *       hsstrt          0     2040        8
+    *       hsstop          0     2040        8
+    *       vtotal          1     2048        1
+    *       vsstrt          0     2047        1
+    *       vsstop          0     2047        1
+    *       hcenter         0     2040        8
+    *
+    *       hbstrt          0     2047        1
+    *       hbstop          0     2047        1
+    *       vbstrt          0     2047        1
+    *       vbstop          0     2047        1
+    *
+    *    Horizontal values are in 35 ns (SHRES) pixels
+    *    Vertical values are in scanlines
+    */
+
+/* bplcon1 (smooth scrolling) */
+
+#define hscroll2hw(hscroll) \
+   (((hscroll)<<12 & 0x3000) | ((hscroll)<<8 & 0xc300) | \
+    ((hscroll)<<4 & 0x0c00) | ((hscroll)<<2 & 0x00f0) | ((hscroll)>>2 & 0x000f))
+
+#define hw2hscroll(hscroll) \
+   (((hscroll)>>8 & 0x00c3) | ((hscroll)<<2 & 0x003c))
+
+/* diwstrt/diwstop/diwhigh (visible display window) */
+
+#define diwstrt2hw(diwstrt_h, diwstrt_v) \
+   (((diwstrt_v)<<8 & 0xff00) | ((diwstrt_h)>>2 & 0x00ff))
+#define diwstop2hw(distop_h, diwstop_v) \
+   (((diwstop_v)<<8 & 0xff00) | ((diwstop_h)>>2 & 0x00ff))
+#define diw2hw_high(diwstrt_h, diwstrt_v, distop_h, diwstop_v) \
+   (((diwstop_h)<<3 & 0x2000) | ((diwstop_h)<<11 & 0x1800) | \
+    ((diwstop_v) & 0x0700) | ((diwstrt_h)>>5 & 0x0020) | \
+    ((diwstrt_h)<<3 & 0x0018) | ((diwstrt_v)>>8 & 0x0007))
+
+#define hw2diwstrt_h(diwstrt, diwhigh) \
+   (((diwhigh)<<5 & 0x0400) | ((diwstrt)<<2 & 0x03fc) | ((diwhigh)>>3 & 0x0003))
+#define hw2diwstrt_v(diwstrt, diwhigh) \
+   (((diwhigh)<<8 & 0x0700) | ((diwstrt)>>8 & 0x00ff))
+#define hw2diwstop_h(diwstop, diwhigh) \
+   (((diwhigh)>>3 & 0x0400) | ((diwstop)<<2 & 0x03fc) | \
+    ((diwhigh)>>11 & 0x0003))
+#define hw2diwstop_v(diwstop, diwhigh) \
+   (((diwhigh) & 0x0700) | ((diwstop)>>8 & 0x00ff))
+
+/* ddfstrt/ddfstop (display DMA) */
+
+#define ddfstrt2hw(ddfstrt)   (div8(ddfstrt) & 0x00fe)
+#define ddfstop2hw(ddfstop)   (div8(ddfstop) & 0x00fe)
+
+#define hw2ddfstrt(ddfstrt)   ((ddfstrt)<<3)
+#define hw2ddfstop(ddfstop)   ((ddfstop)<<3)
+
+/* hsstrt/hsstop/htotal/vsstrt/vsstop/vtotal (sync timings) */
+
+#define hsstrt2hw(hsstrt)     (div8(hsstrt))
+#define hsstop2hw(hsstop)     (div8(hsstop))
+#define htotal2hw(htotal)     (div8(htotal)-1)
+#define vsstrt2hw(vsstrt)     (vsstrt)
+#define vsstop2hw(vsstop)     (vsstop)
+#define vtotal2hw(vtotal)     ((vtotal)-1)
+
+#define hw2hsstrt(hsstrt)     ((hsstrt)<<3)
+#define hw2hsstop(hsstop)     ((hsstop)<<3)
+#define hw2htotal(htotal)     (((htotal)+1)<<3)
+#define hw2vsstrt(vsstrt)     (vsstrt)
+#define hw2vsstop(vsstop)     (vsstop)
+#define hw2vtotal(vtotal)     ((vtotal)+1)
+
+/* 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)     (vbstrt)
+#define vbstop2hw(vbstop)     (vbstop)
+
+#define hw2hbstrt(hbstrt)     (((hbstrt)<<3 & 0x07f8) | ((hbstrt)>>8 & 0x0007))
+#define hw2hbstop(hbstop)     (((hbstop)<<3 & 0x07f8) | ((hbstop)>>8 & 0x0007))
+#define hw2vbstrt(vbstrt)     (vbstrt)
+#define hw2vbstop(vbstop)     (vbstop)
+
+/* color */
+
+#define rgb2hw_high(red, green, blue) \
+   (((red)<<4 & 0xf00) | ((green) & 0x0f0) | ((blue)>>4 & 0x00f))
+#define rgb2hw_low(red, green, blue) \
+   (((red)<<8 & 0xf00) | ((green)<<4 & 0x0f0) | ((blue) & 0x00f))
+
+#define hw2red(high, low)     (((high)>>4 & 0xf0) | ((low)>>8 & 0x0f))
+#define hw2green(high, low)   (((high) & 0xf0) | ((low)>>4 & 0x0f))
+#define hw2blue(high, low)    (((high)<<4 & 0xf0) | ((low) & 0x0f))
+
+/* sprpos/sprctl (sprite positioning) */
+
+#define spr2hw_pos(start_v, start_h) \
+   (((start_v)<<8&0xff00) | ((start_h)>>3&0x00ff))
+#define spr2hw_ctl(start_v, start_h, stop_v) \
+   (((stop_v)<<8&0xff00) | ((start_v)>>3&0x0040) | ((stop_v)>>4&0x0020) | \
+    ((start_h)<<3&0x0018) | ((start_v)>>6&0x0004) | ((stop_v)>>7&0x0002) | \
+    ((start_h)>>2&0x0001))
+
+
+   /*
+    *    Hardware Cursor
+    */
+
+struct aga_cursorsprite {
+   u_short sprpos;
+   u_short pad1[3];
+   u_short sprctl;
+   u_short pad2[3];
+   union {
+      struct {
+         u_long data[64*4];
+         u_long trailer[4];
+      } nonlaced;
+      struct {
+         u_long data[32*4];
+         u_long trailer[4];
+      } laced;
+   } u;
+};
+
+struct aga_dummysprite {
+   u_short sprpos;
+   u_short pad1[3];
+   u_short sprctl;
+   u_short pad2[3];
+   u_long data[4];
+   u_long trailer[4];
+};
+
+
+   /*
+    *    Pixel modes for Bitplanes and Sprites
+    */
+
+static u_short bplpixmode[3] = {
+   BPC0_SHRES,                   /*  35 ns / 28 MHz */
+   BPC0_HIRES,                   /*  70 ns / 14 MHz */
+   0                             /* 140 ns /  7 MHz */
+};
+
+static u_short sprpixmode[3] = {
+   BPC3_SPRES1 | BPC3_SPRES0,    /*  35 ns / 28 MHz */
+   BPC3_SPRES1,                  /*  70 ns / 14 MHz */
+   BPC3_SPRES0                   /* 140 ns /  7 MHz */
+};
+
+
+   /*
+    *    Initialization
+    *
+    *    Allocate the required chip memory.
+    *    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 aga_init(void)
+{
+   u_long p;
+
+   /*
+    *    Disable Display DMA
+    */
+
+   custom.dmacon = DMAF_ALL | DMAF_MASTER;
+
+   /*
+    *    Set the Default Video Mode
+    */
+
+   if (!amifb_mode)
+      amifb_mode = get_video_mode(DEFMODE_AGA);
+
+   /*
+    *    Allocate Chip RAM Structures
+    */
+
+   if (boot_info.bi_amiga.chip_size > 1048576)
+      videomemorysize = VIDEOMEMSIZE_AGA_2M;
+   else
+      videomemorysize = VIDEOMEMSIZE_AGA_1M;
+
+   p = chipalloc(videomemorysize+                     /* Bitplanes */
+                 sizeof(struct clist_hdr)+            /* Copper Lists */
+                 2*sizeof(struct clist_dyn)+
+                 2*sizeof(struct aga_cursorsprite)+   /* Sprites */
+                 sizeof(struct aga_dummysprite));
+
+   assignchunk(videomemory, u_long, p, videomemorysize);
+   assignchunk(clist_hdr, struct clist_hdr *, p, sizeof(struct clist_hdr));
+   assignchunk(clist_lof, struct clist_dyn *, p, sizeof(struct clist_dyn));
+   assignchunk(clist_shf, struct clist_dyn *, p, sizeof(struct clist_dyn));
+   assignchunk(lofsprite, u_long *, p, sizeof(struct aga_cursorsprite));
+   assignchunk(shfsprite, u_long *, p, sizeof(struct aga_cursorsprite));
+   assignchunk(dummysprite, u_long *, p, sizeof(struct aga_dummysprite));
+
+   /*
+    *    Make sure the Copper has something to do
+    */
+
+   aga_build_clist_hdr(clist_hdr);
+
+   custom.cop1lc = (u_short *)ZTWO_PADDR(clist_hdr);
+   custom.cop2lc = (u_short *)ZTWO_PADDR(&clist_hdr->wait_forever);
+   custom.copjmp1 = 0;
+
+   /*
+    *    Enable Display DMA
+    */
+
+   custom.dmacon = DMAF_SETCLR | DMAF_MASTER | DMAF_RASTER | DMAF_COPPER |
+                   DMAF_SPRITE;
+
+   /*
+    *    These hardware register values will never be changed later
+    */
+
+   custom.bplcon2 = BPC2_KILLEHB | BPC2_PF2P2 | BPC2_PF1P2;
+   custom.bplcon4 = BPC4_ESPRM4 | BPC4_OSPRM4;
+
+   return(0);
+}
+
+
+   /*
+    *    This function should fill in the `fix' structure based on the
+    *    values in the `par' structure.
+    */
+
+static int aga_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->visual = FB_VISUAL_PSEUDOCOLOR;
+
+   if (par->diwstrt_h >= 323)
+      fix->xpanstep = 1;
+   else
+      fix->xpanstep = 64;
+   fix->ypanstep = 1;
+
+   if (hw2ddfstrt(par->ddfstrt) >= (par->bpp-1)*64)
+      fix->ywrapstep = 1;
+   else
+      fix->ywrapstep = 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 aga_decode_var(struct fb_var_screeninfo *var,
+                          struct amiga_fb_par *par)
+{
+   u_short clk_shift, line_shift_incd;
+   u_long upper, lower, hslen, vslen;
+   int xres_n, yres_n, xoffset_n;                              /* normalized */
+   u_long left_n, right_n, upper_n, lower_n, hslen_n, vslen_n; /* normalized */
+   u_long diwstrt_h, diwstrt_v, diwstop_h, diwstop_v;
+   u_long hsstrt, vsstrt, hsstop, vsstop, htotal, vtotal;
+   u_long ddfmin, ddfmax, ddfstrt, ddfstop, hscroll;
+   double hrate, vrate;
+   u_short loopcnt = 0;
+
+   /*
+    *    Find a matching Pixel Clock
+    */
+
+   for (clk_shift = 0; clk_shift < 3; clk_shift++)
+      if (var->pixclock <= pixclock[clk_shift])
+         break;
+   if (clk_shift >= 3)
+      return(-EINVAL);
+   par->clk_shift = clk_shift;
+
+   /*
+    *    Round up the Geometry Values (if necessary)
+    */
+
+   par->xres = max(var->xres, 64);
+   par->yres = max(var->yres, 64);
+   par->vxres = up64(max(var->xres_virtual, par->xres));
+   par->vyres = max(var->yres_virtual, par->yres);
+
+   par->bpp = var->bits_per_pixel;
+   if (par->bpp > 8)
+      return(-EINVAL);
+
+   if (!var->nonstd) {
+      if (par->bpp < 1)
+         par->bpp = 1;
+   } else if (var->nonstd == FB_NONSTD_HAM)
+      par->bpp = par->bpp <= 6 ? 6 : 8;
+   else
+      return(-EINVAL);
+
+   upper = var->upper_margin;
+   lower = var->lower_margin;
+   hslen = var->hsync_len;
+   vslen = var->vsync_len;
+
+   par->vmode = var->vmode;
+   switch (par->vmode & FB_VMODE_MASK) {
+      case FB_VMODE_NONINTERLACED:
+         line_shift_incd = 1;
+         break;
+      case FB_VMODE_INTERLACED:
+         line_shift_incd = 0;
+         if (par->yres & 1)
+            par->yres++;               /* even */
+         if (upper & 1)
+            upper++;                   /* even */
+         if (!(lower & 1))
+            lower++;                   /* odd */
+         if (vslen & 1)
+            vslen++;                   /* even */
+         break;
+      case FB_VMODE_DOUBLE:
+         line_shift_incd = 2;
+         break;
+      default:
+         return(-EINVAL);
+         break;
+   }
+
+   par->xoffset = var->xoffset;
+   par->yoffset = var->yoffset;
+   if (par->vmode & FB_VMODE_YWRAP) {
+      if (par->xoffset || par->yoffset < 0 || par->yoffset >= par->yres)
+         return(-EINVAL);
+   } else {
+      if (par->xoffset < 0 || par->xoffset+par->xres > par->vxres ||
+          par->yoffset < 0 || par->yoffset+par->yres > par->vyres)
+         return(-EINVAL);
+   }
+
+   if (var->sync & FB_SYNC_BROADCAST) {
+      if (hslen || vslen)
+         return(-EINVAL);
+   } else {
+      hslen = hslen < 1 ? 1 : hslen;
+      vslen = vslen < 1 ? 1 : vslen;
+   }
+
+   /*
+    *    Check the Memory Requirements
+    */
+
+   if (par->vxres*par->vyres*par->bpp > videomemorysize<<3)
+      return(-EINVAL);
+
+   /*
+    *    Normalize all values:
+    *
+    *      - horizontal: in 35 ns (SHRES) pixels
+    *      - vertical: in non-interlaced scanlines
+    */
+
+   xres_n = par->xres<<clk_shift;
+   xoffset_n = par->xoffset<<clk_shift;
+   yres_n = par->yres<<line_shift_incd>>1;
+
+   left_n = var->left_margin<<clk_shift;
+   right_n = var->right_margin<<clk_shift;
+   hslen_n = hslen<<clk_shift;
+   upper_n = upper<<line_shift_incd>>1;
+   lower_n = lower<<line_shift_incd>>1;
+   vslen_n = vslen<<line_shift_incd>>1;
+
+   /*
+    *    Vertical and Horizontal Timings
+    */
+
+   par->bplcon3 = sprpixmode[clk_shift];
+aga_calculate_timings:
+   if (var->sync & FB_SYNC_BROADCAST) {
+      if (upper_n+yres_n+lower_n == PAL_WINDOW_V) {
+         /* PAL video mode */
+         diwstrt_v = PAL_DIWSTRT_V+upper_n;
+         diwstop_v = diwstrt_v+yres_n;
+         diwstrt_h = PAL_DIWSTRT_H+left_n;
+         diwstop_h = diwstrt_h+xres_n+1;
+         par->htotal = htotal2hw(PAL_HTOTAL);
+         hrate = 15625;
+         vrate = 50;
+         par->beamcon0 = BMC0_PAL;
+      } else if (upper_n+yres_n+lower_n == NTSC_WINDOW_V) {
+         /* NTSC video mode */
+         diwstrt_v = NTSC_DIWSTRT_V+upper_n;
+         diwstop_v = diwstrt_v+yres_n;
+         diwstrt_h = NTSC_DIWSTRT_H+left_n;
+         diwstop_h = diwstrt_h+xres_n+1;
+         par->htotal = htotal2hw(NTSC_HTOTAL);
+         hrate = 15750;
+         vrate = 60;
+         par->beamcon0 = 0;
+      } else
+         return(-EINVAL);
+   } else {
+      /* Programmable video mode */
+      vsstrt = lower_n;
+      vsstop = vsstrt+vslen_n;
+      diwstrt_v = vsstop+upper_n;
+      diwstop_v = diwstrt_v+yres_n;
+      vtotal = diwstop_v;
+      hslen_n = up8(hslen_n);
+      htotal = up8(left_n+xres_n+right_n+hslen_n);
+      if (vtotal > 2048 || htotal > 2048)
+         return(-EINVAL);
+      right_n = htotal-left_n-xres_n-hslen_n;
+      hsstrt = down8(right_n+4);
+      hsstop = hsstrt+hslen_n;
+      diwstop_h = htotal+hsstrt-right_n+1;
+      diwstrt_h = diwstop_h-xres_n-1;
+      hrate = (double)amiga_masterclock/htotal;
+      vrate = hrate/vtotal;
+      par->bplcon3 |= BPC3_BRDRBLNK | 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;
+      par->htotal = htotal2hw(htotal);
+      par->hsstrt = hsstrt2hw(hsstrt);
+      par->hsstop = hsstop2hw(hsstop);
+      par->vtotal = vtotal2hw(vtotal);
+      par->vsstrt = vsstrt2hw(vsstrt);
+      par->vsstop = vsstop2hw(vsstop);
+      par->hcenter = par->hsstrt+(par->htotal>>1);
+   }
+   par->diwstrt_v = diwstrt_v;
+   par->diwstrt_h = diwstrt_h;
+   par->crsr_x = 0;
+   par->crsr_y = 0;
+
+   /*
+    *    DMA Timings
+    */
+
+   ddfmin = down64(xoffset_n);
+   ddfmax = up64(xoffset_n+xres_n);
+   hscroll = diwstrt_h-68-mod64(xoffset_n);
+   ddfstrt = down64(hscroll);
+   if (ddfstrt < 128) {
+      right_n += (128-hscroll);
+      /* Prevent an infinite loop */
+      if (loopcnt++)
+         return(-EINVAL);
+      goto aga_calculate_timings;
+   }
+   hscroll -= ddfstrt;
+   ddfstop = ddfstrt+ddfmax-ddfmin-(64<<clk_shift);
+
+   /*
+    *    Bitplane calculations
+    */
+
+   if (amifb_ilbm) {
+      par->next_plane = div8(par->vxres);
+      par->next_line = par->bpp*par->next_plane;
+   } else {
+      par->next_line = div8(par->vxres);
+      par->next_plane = par->vyres*par->next_line;
+   }
+   par->bplpt0 = ZTWO_PADDR((u_long)videomemory+div8(ddfmin>>clk_shift)+
+                            par->yoffset*par->next_line);
+   par->bpl1mod = par->next_line-div8((ddfmax-ddfmin)>>clk_shift);
+   par->bpl2mod = par->bpl1mod;
+
+   /*
+    *    Hardware Register Values
+    */
+
+   par->bplcon0 = BPC0_COLOR | BPC0_ECSENA | bplpixmode[clk_shift];
+   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;
+   par->bplcon1 = hscroll2hw(hscroll);
+   par->diwstrt = diwstrt2hw(diwstrt_h, diwstrt_v);
+   par->diwstop = diwstop2hw(diwstop_h, diwstop_v);
+   par->diwhigh = diw2hw_high(diwstrt_h, diwstrt_v, distop_h, diwstop_v);
+   par->ddfstrt = ddfstrt2hw(ddfstrt);
+   par->ddfstop = ddfstop2hw(ddfstop);
+   par->fmode = FMODE_SPAGEM | FMODE_SPR32 | FMODE_BPAGEM | FMODE_BPL32;
+
+   switch (par->vmode & FB_VMODE_MASK) {
+      case FB_VMODE_INTERLACED:
+         par->bpl1mod += par->next_line;
+         par->bpl2mod += par->next_line;
+         par->bplcon0 |= BPC0_LACE;
+         break;
+      case FB_VMODE_DOUBLE:
+         par->bpl1mod -= par->next_line;
+         par->fmode |= FMODE_SSCAN2 | FMODE_BSCAN2;
+         break;
+   }
+
+   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 aga_encode_var(struct fb_var_screeninfo *var,
+                          struct amiga_fb_par *par)
+{
+   u_short clk_shift, line_shift_incd;
+   u_long left, right, upper, lower, hslen, vslen;
+   u_short diwstop_h, diwstop_v;
+   u_short hsstrt, vsstrt, hsstop, vsstop, htotal;
+   int i;
+
+   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;
+
+   var->red.offset = 0;
+   var->red.length = 8;
+   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 = FB_ACCEL_NONE;
+
+   clk_shift = par->clk_shift;
+   var->pixclock = pixclock[clk_shift];
+
+   diwstop_h = hw2diwstop_h(par->diwstop, par->diwhigh);
+   if (par->beamcon0 & BMC0_VARBEAMEN) {
+      hsstrt = hw2hsstrt(par->hsstrt);
+      vsstrt = hw2vsstrt(par->vsstrt);
+      hsstop = hw2hsstop(par->hsstop);
+      vsstop = hw2vsstop(par->vsstop);
+      htotal = hw2htotal(par->htotal);
+      left = par->diwstrt_h-hsstop;
+      right = htotal+hsstrt-diwstop_h+1;
+      hslen = hsstop-hsstrt;
+      upper = par->diwstrt_v-vsstop;
+      lower = vsstrt;
+      vslen = vsstop-vsstrt;
+      var->sync = 0;
+   } else {
+      diwstop_v = hw2diwstop_v(par->diwstop, par->diwhigh);
+      if (par->beamcon0 & BMC0_PAL) {
+         left = par->diwstrt_h-PAL_DIWSTRT_H;
+         right = PAL_DIWSTRT_H+PAL_WINDOW_H-diwstop_h+1;
+         upper = par->diwstrt_v-PAL_DIWSTRT_V;
+         lower = PAL_DIWSTRT_V+PAL_WINDOW_V-diwstop_v;
+      } else {
+         left = par->diwstrt_h-NTSC_DIWSTRT_H;
+         right = NTSC_DIWSTRT_H+NTSC_WINDOW_H-diwstop_h;
+         upper = par->diwstrt_v-NTSC_DIWSTRT_V;
+         lower = NTSC_DIWSTRT_V+NTSC_WINDOW_V-diwstop_v;
+      }
+      hslen = 0;
+      vslen = 0;
+      var->sync = FB_SYNC_BROADCAST;
+   }
+
+   if (par->bplcon0 & BPC0_ERSY)
+      var->sync |= FB_SYNC_EXT;
+   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;
+
+   switch (par->vmode & FB_VMODE_MASK) {
+      case FB_VMODE_NONINTERLACED:
+         line_shift_incd = 1;
+         break;
+      case FB_VMODE_INTERLACED:
+         line_shift_incd = 0;
+         break;
+      case FB_VMODE_DOUBLE:
+         line_shift_incd = 2;
+         break;
+   }
+
+   var->left_margin = left>>clk_shift;
+   var->right_margin = right>>clk_shift;
+   var->upper_margin = upper<<1>>line_shift_incd;
+   var->lower_margin = lower<<1>>line_shift_incd;
+   var->hsync_len = hslen>>clk_shift;
+   var->vsync_len = vslen<<1>>line_shift_incd;
+   var->vmode = par->vmode;
+   for (i = 0; i < arraysize(var->reserved); i++)
+      var->reserved[i] = 0;
+
+   return(0);
+}
+
+
+   /*
+    *    Read a single color register and split it into
+    *    colors/transparent. Return != 0 for invalid regno.
+    */
+
+static int aga_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
+                         u_int *transp)
+{
+   if (regno > 255)
+      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 aga_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+                         u_int transp)
+{
+   u_short bplcon3 = current_par.bplcon3;
+
+   if (regno > 255)
+      return(1);
+
+   /*
+    *    Update the corresponding Hardware Color Register, unless it's Color
+    *    Register 0 and the screen is blanked.
+    *
+    *    The cli()/sti() pair is here to protect bplcon3 from being changed by
+    *    the VBlank interrupt routine.
+    */
+
+   cli();
+   if (regno || !is_blanked) {
+      custom.bplcon3 = bplcon3 | (regno<<8 & 0xe000);
+      custom.color[regno&31] = rgb2hw_high(red, green, blue);
+      custom.bplcon3 = bplcon3 | (regno<<8 & 0xe000) | BPC3_LOCT;
+      custom.color[regno&31] = rgb2hw_low(red, green, blue);
+      custom.bplcon3 = bplcon3;
+   }
+   sti();
+
+   palette[regno].red = red;
+   palette[regno].green = green;
+   palette[regno].blue = blue;
+
+   return(0);
+}
+
+
+   /*
+    *    Pan or Wrap the Display
+    *
+    *    This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
+    *    in `var'.
+    */
+
+static int aga_pan_display(struct fb_var_screeninfo *var,
+                           struct amiga_fb_par *par)
+{
+   int xoffset, yoffset, vmode, xres_n, xoffset_n;
+   u_short clk_shift, line_shift_incd;
+   u_long ddfmin, ddfmax, ddfstrt, ddfstop, hscroll;
+
+   xoffset = var->xoffset;
+   yoffset = var->yoffset;
+   if (var->vmode & FB_VMODE_YWRAP) {
+      if (hw2ddfstrt(par->ddfstrt) < (par->bpp-1)*64 || xoffset ||
+          yoffset < 0 || yoffset >= par->yres)
+         return(-EINVAL);
+      vmode = par->vmode | FB_VMODE_YWRAP;
+   } else {
+      if (par->diwstrt_h < 323)
+         xoffset = up64(xoffset);
+      if (xoffset < 0 || xoffset+par->xres > par->vxres ||
+          yoffset < 0 || yoffset+par->yres > par->vyres)
+         return(-EINVAL);
+      vmode = par->vmode & ~FB_VMODE_YWRAP;
+   }
+
+   clk_shift = par->clk_shift;
+   switch (vmode & FB_VMODE_MASK) {
+      case FB_VMODE_NONINTERLACED:
+         line_shift_incd = 1;
+         break;
+      case FB_VMODE_INTERLACED:
+         line_shift_incd = 0;
+         break;
+      case FB_VMODE_DOUBLE:
+         line_shift_incd = 2;
+         break;
+   }
+   xres_n = par->xres<<clk_shift;
+   xoffset_n = xoffset<<clk_shift;
+
+   /*
+    *    DMA timings
+    */
+
+   ddfmin = down64(xoffset_n);
+   ddfmax = up64(xoffset_n+xres_n);
+   hscroll = par->diwstrt_h-68-mod64(xoffset_n);
+   ddfstrt = down64(hscroll);
+   if (ddfstrt < 128)
+      return(-EINVAL);
+   hscroll -= ddfstrt;
+   ddfstop = ddfstrt+ddfmax-ddfmin-(64<<clk_shift);
+   par->bplcon1 = hscroll2hw(hscroll);
+   par->ddfstrt = ddfstrt2hw(ddfstrt);
+   par->ddfstop = ddfstop2hw(ddfstop);
+
+   /*
+    *    Bitplane calculations
+    */
+
+   par->bplpt0 = ZTWO_PADDR((u_long)videomemory+div8(ddfmin>>clk_shift)+
+                            yoffset*par->next_line);
+   par->bpl1mod = par->next_line-div8((ddfmax-ddfmin)>>clk_shift);
+   par->bpl2mod = par->bpl1mod;
+   switch (vmode & FB_VMODE_MASK) {
+      case FB_VMODE_INTERLACED:
+         par->bpl1mod += par->next_line;
+         par->bpl2mod += par->next_line;
+         break;
+      case FB_VMODE_DOUBLE:
+         par->bpl1mod -= par->next_line;
+         break;
+   }
+
+   par->xoffset = var->xoffset = xoffset;
+   par->yoffset = var->yoffset = yoffset;
+   par->vmode = var->vmode = vmode;
+   return(0);
+}
+
+
+   /*
+    *    Change the video mode (called by VBlank interrupt)
+    */
+
+void aga_do_vmode(void)
+{
+   struct amiga_fb_par *par = &current_par;
+
+   /*
+    *    Rebuild the dynamic part of the Copper List and activate the right
+    *    Copper List as soon as possible
+    *
+    *    Make sure we're in a Long Frame if the video mode is interlaced.
+    *    This is always the case if we already were in an interlaced mode,
+    *    since then the VBlank only calls us during a Long Frame.
+    *    But this _is_ necessary if we're switching from a non-interlaced
+    *    to an interlaced mode.
+    */
+
+   if ((par->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
+      custom.vposw = 0x8000;
+      aga_build_clist_dyn(clist_lof, clist_shf, 0, par);
+      custom.cop2lc = (u_short *)ZTWO_PADDR(clist_lof);
+      aga_build_clist_dyn(clist_shf, clist_lof, 1, par);
+   } else {
+      aga_build_clist_dyn(clist_lof, NULL, 0, par);
+      custom.cop2lc = (u_short *)ZTWO_PADDR(clist_lof);
+   }
+
+   /*
+    *    Update the hardware registers
+    */
+
+   if (full_vmode_change) {
+      custom.fmode = par->fmode;
+      custom.beamcon0 = par->beamcon0;
+      if (par->beamcon0 & BMC0_VARBEAMEN) {
+         custom.htotal = par->htotal;
+         custom.vtotal = par->vtotal;
+         custom.hsstrt = par->hsstrt;
+         custom.hsstop = par->hsstop;
+         custom.hbstrt = par->hsstrt;
+         custom.hbstop = par->hsstop;
+         custom.vsstrt = par->vsstrt;
+         custom.vsstop = par->vsstop;
+         custom.vbstrt = par->vsstrt;
+         custom.vbstop = par->vsstop;
+         custom.hcenter = par->hcenter;
+      }
+      custom.bplcon3 = par->bplcon3;
+      full_vmode_change = 0;
+   }
+   custom.ddfstrt = par->ddfstrt;
+   custom.ddfstop = par->ddfstop;
+   custom.bpl1mod = par->bpl1mod;
+   custom.bpl2mod = par->bpl2mod;
+   custom.bplcon1 = par->bplcon1;
+
+   /*
+    *    Update the Frame Header Copper List
+    */
+
+   aga_update_clist_hdr(clist_hdr, par);
+
+   /*
+    *    The minimum period for audio depends on htotal (for OCS/ECS/AGA)
+    */
+
+   if ((boot_info.bi_amiga.chipset != CS_STONEAGE) && full_vmode_change)
+      amiga_audio_min_period = (par->htotal>>1)+1;
+}
+
+
+   /*
+    *    (Un)Blank the screen (called by VBlank interrupt)
+    */
+
+void aga_do_blank(int blank)
+{
+   struct amiga_fb_par *par = &current_par;
+   u_short bplcon3 = par->bplcon3;
+   u_char red, green, blue;
+
+   if (blank) {
+      custom.dmacon = DMAF_RASTER | DMAF_SPRITE;
+      red = green = blue = 0;
+      if (pwrsave && par->beamcon0 & BMC0_VARBEAMEN) {
+         /* VESA suspend mode, switch off HSYNC */
+         custom.hsstrt = par->htotal+2;
+         custom.hsstop = par->htotal+2;
+      }
+   } else {
+      custom.dmacon = DMAF_SETCLR | DMAF_RASTER;
+      red = palette[0].red;
+      green = palette[0].green;
+      blue = palette[0].blue;
+      if (pwrsave && par->beamcon0 & BMC0_VARBEAMEN) {
+         custom.hsstrt = par->hsstrt;
+         custom.hsstop = par->hsstop;
+      }
+   }
+   custom.bplcon3 = bplcon3;
+   custom.color[0] = rgb2hw_high(red, green, blue);
+   custom.bplcon3 = bplcon3 | BPC3_LOCT;
+   custom.color[0] = rgb2hw_low(red, green, blue);
+   custom.bplcon3 = bplcon3;
+
+   is_blanked = blank;
+}
+
+
+   /*
+    *    Move the cursor (called by VBlank interrupt)
+    */
+
+void aga_do_movecursor(void)
+{
+   struct amiga_fb_par *par = &current_par;
+   struct aga_cursorsprite *sprite = (struct aga_cursorsprite *)lofsprite;
+   long hs, vs, ve;
+   u_short s1, s2, is_double = 0;
+
+   if (par->crsr_x <= -64 || par->crsr_x >= par->xres || par->crsr_y <= -64 ||
+       par->crsr_y >= par->yres)
+      hs = vs = ve = 0;
+   else {
+      hs = par->diwstrt_h-4+(par->crsr_x<<par->clk_shift);
+      vs = par->crsr_y;
+      ve = min(vs+64, par->yres);
+      switch (par->vmode & FB_VMODE_MASK) {
+         case FB_VMODE_INTERLACED:
+            vs >>= 1;
+            ve >>= 1;
+            break;
+         case FB_VMODE_DOUBLE:
+            vs <<= 1;
+            ve <<= 1;
+            is_double = 1;
+            break;
+      }
+      vs += par->diwstrt_v;
+      ve += par->diwstrt_v;
+   }
+   s1 = spr2hw_pos(vs, hs);
+   if (is_double)
+      s1 |= 0x80;
+   s2 = spr2hw_ctl(vs, hs, ve);
+   sprite->sprpos = s1;
+   sprite->sprctl = s2;
+
+   /*
+    *    TODO: Special cases:
+    *    
+    *      - Interlaced: fill position in in both lofsprite & shfsprite
+    *                    swap lofsprite & shfsprite on odd lines
+    *    
+    *      - Doublescan: OK?
+    *    
+    *      - ve <= bottom of display: OK?
+    */
+}
+
+
+   /*
+    *    Flash the cursor (called by VBlank interrupt)
+    */
+
+void aga_do_flashcursor(void)
+{
+#if 1
+   static int cursorcount = 0;
+   static int cursorstate = 0;
+
+   switch (cursormode) {
+      case FB_CURSOR_OFF:
+         custom.dmacon = DMAF_SPRITE;
+         break;
+      case FB_CURSOR_ON:
+         custom.dmacon = DMAF_SETCLR | DMAF_SPRITE;
+         break;
+      case FB_CURSOR_FLASH:
+         if (cursorcount)
+            cursorcount--;
+         else {
+            cursorcount = CRSR_RATE;
+            if ((cursorstate = !cursorstate))
+               custom.dmacon = DMAF_SETCLR | DMAF_SPRITE;
+            else
+               custom.dmacon = DMAF_SPRITE;
+         }
+         break;
+   }
+#endif
+}
+
+
+#if 1
+static int aga_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix, int con)
+{
+#if 0
+   if (ddfstrt >= 192) {
+#endif
+      fix->crsr_width = 64;
+      fix->crsr_height = 64;
+      fix->crsr_xsize = 64;
+      fix->crsr_ysize = 64;
+      fix->crsr_color1 = 17;
+      fix->crsr_color2 = 18;
+#if 0
+   } else {
+      fix->crsr_width = 0;
+      fix->crsr_height = 0;
+      fix->crsr_xsize = 0;
+      fix->crsr_ysize = 0;
+      fix->crsr_color1 = 0;
+      fix->crsr_color2 = 0;
+   }
+#endif
+   return(0);
+}
+
+
+static int aga_get_var_cursorinfo(struct fb_var_cursorinfo *var, int con)
+{
+   struct aga_cursorsprite *sprite = (struct aga_cursorsprite *)lofsprite;
+
+   /* TODO: interlaced sprites */
+   memcpy(var->data, sprite->u.nonlaced.data, sizeof(var->data));
+   return(0);
+}
+
+
+static int aga_set_var_cursorinfo(struct fb_var_cursorinfo *var, int con)
+{
+   struct aga_cursorsprite *sprite = (struct aga_cursorsprite *)lofsprite;
+
+   /* TODO: interlaced sprites */
+   memcpy(sprite->u.nonlaced.data, var->data, sizeof(var->data));
+   return(0);
+}
+
+
+static int aga_get_cursorstate(struct fb_cursorstate *state, int con)
+{
+   state->xoffset = current_par.crsr_x;
+   state->yoffset = current_par.crsr_y;
+   state->mode = cursormode;
+   return(0);
+}
+
+
+static int aga_set_cursorstate(struct fb_cursorstate *state, int con)
+{
+   current_par.crsr_x = state->xoffset;
+   current_par.crsr_y = state->yoffset;
+   cursormode = state->mode;
+   do_movecursor = 1;
+   return(0);
+}
+#endif
+
+
+   /*
+    *    Build the Frame Header Copper List
+    */
+
+static __inline__ void aga_build_clist_hdr(struct clist_hdr *cop)
+{
+   int i, j;
+   u_long p;
+
+   cop->bplcon0.l = CMOVE(BPC0_COLOR | BPC0_SHRES | BPC0_ECSENA, bplcon0);
+   cop->diwstrt.l = CMOVE(0x0181, diwstrt);
+   cop->diwstop.l = CMOVE(0x0281, diwstop);
+   cop->diwhigh.l = CMOVE(0x0000, diwhigh);
+   for (i = 0; i < 8; i++)
+      cop->sprfix[i].l = CMOVE(0, spr[i].pos);
+   for (i = 0, j = 0; i < 8; i++) {
+      p = ZTWO_PADDR(dummysprite);
+      cop->sprstrtup[j++].l = CMOVE(highw(p), sprpt[i]);
+      cop->sprstrtup[j++].l = CMOVE2(loww(p), sprpt[i]);
+   }
+   cop->wait.l = CWAIT(0, 12);         /* Initial value */
+   cop->jump.l = CMOVE(0, copjmp2);
+   cop->wait_forever.l = CEND;
+}
+
+
+   /*
+    *    Update the Frame Header Copper List
+    */
+
+static __inline__ void aga_update_clist_hdr(struct clist_hdr *cop,
+                                            struct amiga_fb_par *par)
+{
+   cop->bplcon0.l = CMOVE(~(BPC0_BPU3 | BPC0_BPU2 | BPC0_BPU1 | BPC0_BPU0) &
+                          par->bplcon0, bplcon0);
+   cop->wait.l = CWAIT(0, par->diwstrt_v-2);
+}
+
+
+   /*
+    *    Build the Long Frame/Short Frame Copper List
+    */
+
+static void aga_build_clist_dyn(struct clist_dyn *cop,
+                                struct clist_dyn *othercop, u_short shf,
+                                struct amiga_fb_par *par)
+{
+   u_long y_wrap, bplpt0, p, line;
+   int i, j = 0;
+
+   cop->diwstrt.l = CMOVE(par->diwstrt, diwstrt);
+   cop->diwstop.l = CMOVE(par->diwstop, diwstop);
+   cop->diwhigh.l = CMOVE(par->diwhigh, diwhigh);
+   cop->bplcon0.l = CMOVE(par->bplcon0, bplcon0);
+
+   /* Point Sprite 0 at cursor sprite */
+
+   /* TODO: This should depend on the vertical sprite position too */
+   if (shf) {
+      p = ZTWO_PADDR(shfsprite);
+      cop->sprpt[0].l = CMOVE(highw(p), sprpt[0]);
+      cop->sprpt[1].l = CMOVE2(loww(p), sprpt[0]);
+   } else {
+      p = ZTWO_PADDR(lofsprite);
+      cop->sprpt[0].l = CMOVE(highw(p), sprpt[0]);
+      cop->sprpt[1].l = CMOVE2(loww(p), sprpt[0]);
+   }
+
+   bplpt0 = par->bplpt0;
+   if (shf)
+      bplpt0 += par->next_line;
+   y_wrap = par->vmode & FB_VMODE_YWRAP ? par->yoffset : 0;
+
+   /* Set up initial bitplane ptrs */
+
+   for (i = 0, p = bplpt0; i < par->bpp; i++, p += par->next_plane) {
+      cop->rest[j++].l = CMOVE(highw(p), bplpt[i]);
+      cop->rest[j++].l = CMOVE2(loww(p), bplpt[i]);
+   }
+
+   if (y_wrap) {
+      bplpt0 -= y_wrap*par->next_line;
+      line = par->yres-y_wrap;
+      switch (par->vmode & FB_VMODE_MASK) {
+         case FB_VMODE_INTERLACED:
+            line >>= 1;
+            break;
+         case FB_VMODE_DOUBLE:
+            line <<= 1;
+            break;
+      }
+      line += par->diwstrt_v;
+
+      /* Handle skipping over 256-line chunks */
+
+      while (line > 256) {
+         /* Hardware limitation - 8 bit counter */
+         cop->rest[j++].l = CWAIT(par->htotal-4, 255);
+         /* Wait(0, 0) - make sure we're in the new segment */
+         cop->rest[j++].l = CWAIT(0, 0);
+         line -= 256;
+      }
+      cop->rest[j++].l = CWAIT(par->htotal-11, line-1);
+
+      for (i = 0, p = bplpt0; i < par->bpp; i++, p += par->next_plane) {
+         cop->rest[j++].l = CMOVE(highw(p), bplpt[i]);
+         cop->rest[j++].l = CMOVE2(loww(p), bplpt[i]);
+      }
+   }
+
+   if (othercop) {
+      p = ZTWO_PADDR(othercop);
+      cop->rest[j++].l = CMOVE(highw(p), cop2lc);
+      cop->rest[j++].l = CMOVE2(loww(p), cop2lc);
+   }
+
+   /* End of Copper list */
+   cop->rest[j++].l = CEND;
+
+   if (j > arraysize(cop->rest))
+      printk("aga_build_clist_dyn: copper list overflow (%d entries)\n", j);
+}
+#endif /* CONFIG_AMIFB_AGA */
+
+
+/* -------------------- Interfaces to hardware functions -------------------- */
+
+
+#ifdef CONFIG_AMIFB_OCS
+static struct fb_hwswitch ocs_switch = {
+   ocs_init, ocs_encode_fix, ocs_decode_var, ocs_encode_var, ocs_getcolreg,
+   ocs_setcolreg, ocs_pan_display, ocs_do_vmode, ocs_do_blank,
+   ocs_do_movecursor, ocs_do_flashcursor
+};
+#endif /* CONFIG_AMIFB_OCS */
+
+#ifdef CONFIG_AMIFB_ECS
+static struct fb_hwswitch ecs_switch = {
+   ecs_init, ecs_encode_fix, ecs_decode_var, ecs_encode_var, ecs_getcolreg,
+   ecs_setcolreg, ecs_pan_display, ecs_do_vmode, ecs_do_blank,
+   ecs_do_movecursor, ecs_do_flashcursor
+};
+#endif /* CONFIG_AMIFB_ECS */
+
+#ifdef CONFIG_AMIFB_AGA
+static struct fb_hwswitch aga_switch = {
+   aga_init, aga_encode_fix, aga_decode_var, aga_encode_var, aga_getcolreg,
+   aga_setcolreg, aga_pan_display, aga_do_vmode, aga_do_blank,
+   aga_do_movecursor, aga_do_flashcursor
+};
+#endif /* CONFIG_AMIFB_AGA */
+
+
+/* -------------------- Generic routines ------------------------------------ */
+
+
+   /*
+    *    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);
+}
+
+
+   /*
+    *    Fill the hardware's `par' structure.
+    */
+
+static void amiga_fb_get_par(struct amiga_fb_par *par)
+{
+   if (current_par_valid)
+      *par = current_par;
+   else
+      fbhw->decode_var(&amiga_fb_predefined[amifb_mode], par);
+}
+
+
+static void amiga_fb_set_par(struct amiga_fb_par *par)
+{
+   do_vmode = 0;
+   current_par = *par;
+   full_vmode_change = 1;
+   do_vmode = 1;
+   current_par_valid = 1;
+}
+
+
+static int do_fb_set_var(struct fb_var_screeninfo *var, int isactive)
+{
+   int err, activate;
+   struct amiga_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)
+      amiga_fb_set_par(&par);
+   fbhw->encode_var(var, &par);
+   var->activate = activate;
+   return(0);
+}
+
+
+   /*
+    *    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 };
+
+
+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 (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_fs_word(hred, red);
+         put_fs_word(hgreen, green);
+         put_fs_word(hblue, blue);
+         if (transp)
+            put_fs_word(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 {
+         hred = get_fs_word(red);
+         hgreen = get_fs_word(green);
+         hblue = get_fs_word(blue);
+         htransp = transp ? get_fs_word(transp) : 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:
+         memcpy_fromfs(to, from, len);
+         return;
+      case 2:
+         memcpy_tofs(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 amiga_fb_get_fix(struct fb_fix_screeninfo *fix, int con)
+{
+   struct amiga_fb_par par;
+   int error = 0;
+
+   if (con == -1)
+      amiga_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 amiga_fb_get_var(struct fb_var_screeninfo *var, int con)
+{
+   struct amiga_fb_par par;
+   int error = 0;
+
+   if (con == -1) {
+      amiga_fb_get_par(&par);
+      error = fbhw->encode_var(var, &par);
+   } else
+      *var = disp[con].var;
+   return(error);
+}
+
+
+static void amiga_fb_set_disp(int con)
+{
+   struct fb_fix_screeninfo fix;
+
+   amiga_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 = amifb_inverse;
+}
+
+
+   /*
+    *    Set the User Defined Part of the Display
+    */
+
+static int amiga_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) {
+         amiga_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 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);
+}
+
+
+   /*
+    *    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)
+{
+   int err;
+   u_short oldlatch;
+
+   if (var->vmode & FB_VMODE_YWRAP) {
+      if (var->xoffset || var->yoffset >= disp[con].var.yres)
+         return(-EINVAL);
+   } else {
+      if (var->xoffset+disp[con].var.xres > disp[con].var.xres_virtual ||
+          var->yoffset+disp[con].var.yres > disp[con].var.yres_virtual)
+    return(-EINVAL);
+   }
+   if (con == currcon) {
+      cli();
+      oldlatch = do_vmode;
+      do_vmode = 0;
+      sti();
+      if ((err = fbhw->pan_display(var, &current_par))) {
+         if (oldlatch)
+            do_vmode = 1;
+         return(err);
+      }
+      do_vmode = 1;
+   }
+   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);
+}
+
+
+   /*
+    *    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;
+   struct fb_fix_cursorinfo crsrfix;
+   struct fb_var_cursorinfo crsrvar;
+   struct fb_cursorstate crsrstate;
+
+   switch (cmd) {
+#ifdef CONFIG_AMIFB_AGA
+      case FBIOGET_FCURSORINFO:
+         i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(crsrfix));
+         if (i)
+            return(i);
+         i = amiga_fb_get_fix_cursorinfo(&crsrfix, con);
+         memcpy_tofs((void *)arg, &crsrfix, sizeof(crsrfix));
+         return(i);
+      case FBIOGET_VCURSORINFO:
+         i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(crsrvar));
+         if (i)
+            return(i);
+         i = amiga_fb_get_var_cursorinfo(&crsrvar, con);
+         memcpy_tofs((void *)arg, &crsrvar, sizeof(crsrvar));
+         return(i);
+      case FBIOPUT_VCURSORINFO:
+         i = verify_area(VERIFY_READ, (void *)arg, sizeof(crsrvar));
+         if (i)
+            return(i);
+         memcpy_fromfs(&crsrvar, (void *)arg, sizeof(crsrvar));
+         i = amiga_fb_set_var_cursorinfo(&crsrvar, con);
+         return(i);
+      case FBIOGET_CURSORSTATE:
+         i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(crsrstate));
+         if (i)
+            return(i);
+         i = amiga_fb_get_cursorstate(&crsrstate, con);
+         memcpy_tofs((void *)arg, &crsrstate, sizeof(crsrstate));
+         return(i);
+      case FBIOPUT_CURSORSTATE:
+         i = verify_area(VERIFY_READ, (void *)arg, sizeof(crsrstate));
+         if (i)
+            return(i);
+         memcpy_fromfs(&crsrstate, (void *)arg, sizeof(crsrstate));
+         i = amiga_fb_set_cursorstate(&crsrstate, con);
+         return(i);
+#endif /* CONFIG_AMIFB_AGA */
+#if 1
+      case FBCMD_GET_CURRENTPAR:
+         if ((i = verify_area(VERIFY_WRITE, (void *)arg,
+                              sizeof(struct amiga_fb_par))))
+            return(i);
+         memcpy_tofs((void *)arg, (void *)&current_par,
+                     sizeof(struct amiga_fb_par));
+         return(0);
+         break;
+      case FBCMD_SET_CURRENTPAR:
+         if ((i = verify_area(VERIFY_READ, (void *)arg,
+                              sizeof(struct amiga_fb_par))))
+            return(i);
+         memcpy_fromfs((void *)&current_par, (void *)arg,
+                       sizeof(struct amiga_fb_par));
+         return(0);
+         break;
+#endif
+   }
+   return(-EINVAL);
+}
+
+
+#ifdef CONFIG_AMIFB_AGA
+   /*
+    *    Hardware Cursor
+    */
+
+static int amiga_fb_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix, int con)
+{
+   if (boot_info.bi_amiga.chipset == CS_AGA)
+      return(aga_get_fix_cursorinfo(fix, con));
+   return(-EINVAL);
+}
+
+
+static int amiga_fb_get_var_cursorinfo(struct fb_var_cursorinfo *var, int con)
+{
+   if (boot_info.bi_amiga.chipset == CS_AGA)
+      return(aga_get_var_cursorinfo(var, con));
+   return(-EINVAL);
+}
+
+
+static int amiga_fb_set_var_cursorinfo(struct fb_var_cursorinfo *var, int con)
+{
+   if (boot_info.bi_amiga.chipset == CS_AGA)
+      return(aga_set_var_cursorinfo(var, con));
+   return(-EINVAL);
+}
+
+
+static int amiga_fb_get_cursorstate(struct fb_cursorstate *state, int con)
+{
+   if (boot_info.bi_amiga.chipset == CS_AGA)
+      return(aga_get_cursorstate(state, con));
+   return(-EINVAL);
+}
+
+
+static int amiga_fb_set_cursorstate(struct fb_cursorstate *state, int con)
+{
+   if (boot_info.bi_amiga.chipset == CS_AGA)
+      return(aga_set_cursorstate(state, con));
+   return(-EINVAL);
+}
+#endif /* CONFIG_AMIFB_AGA */
+
+
+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 /* CONFIG_FB_CYBER */
+
+#ifdef USE_MONO_AMIFB_IF_NON_AGA
+   if (boot_info.bi_amiga.chipset != CS_AGA) {
+      mono_video_setup(options, ints);
+      return;
+   }
+#endif /* USE_MONO_AMIFB_IF_NON_AGA */
+
+   mcap_spec[0] = '\0';
+   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")) {
+         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 (!strcmp(this_opt, "pwrsave"))
+         pwrsave = 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
+         amifb_mode = get_video_mode(this_opt);
+
+   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:
+      ;
+   }
+}
+
+
+   /*
+    *    Initialization
+    */
+
+struct fb_info *amiga_fb_init(long *mem_start)
+{
+   int err, tag, i;
+   struct fb_var_screeninfo *var;
+
+   /*
+    *    Check for a Graphics Board
+    */
+
+#ifdef CONFIG_FB_CYBER
+   if (amifb_Cyber)
+      return(Cyber_fb_init(mem_start));
+#endif /* CONFIG_FB_CYBER */
+
+   /*
+    *    Use the Builtin Chipset
+    */
+
+   if (!AMIGAHW_PRESENT(AMI_VIDEO))
+      return(NULL);
+
+#ifdef USE_MONO_AMIFB_IF_NON_AGA
+   if (boot_info.bi_amiga.chipset != CS_AGA)
+      return(mono_amiga_fb_init(mem_start));
+#endif /* USE_MONO_AMIFB_IF_NON_AGA */
+
+   switch (boot_info.bi_amiga.chipset) {
+#ifdef CONFIG_AMIFB_OCS
+      case CS_OCS:
+         strcat(amiga_fb_name, "OCS");
+default_chipset:
+         fbhw = &ocs_switch;
+         maxdepth[TAG_SHRES-1] = 0;       /* OCS means no SHRES */
+         maxdepth[TAG_HIRES-1] = 4;
+         maxdepth[TAG_LORES-1] = 6;
+         break;
+#endif /* CONFIG_AMIFB_OCS */
+
+#ifdef CONFIG_AMIFB_ECS
+      case CS_ECS:
+         strcat(amiga_fb_name, "ECS");
+         fbhw = &ecs_switch;
+         maxdepth[TAG_SHRES-1] = 2;
+         maxdepth[TAG_HIRES-1] = 4;
+         maxdepth[TAG_LORES-1] = 6;
+         break;
+#endif /* CONFIG_AMIFB_ECS */
+
+#ifdef CONFIG_AMIFB_AGA
+      case CS_AGA:
+         strcat(amiga_fb_name, "AGA");
+         fbhw = &aga_switch;
+         maxdepth[TAG_SHRES-1] = 8;
+         maxdepth[TAG_HIRES-1] = 8;
+         maxdepth[TAG_LORES-1] = 8;
+         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-1] = 25E9/amiga_eclock;   /* SHRES:  35 ns / 28 MHz */
+   pixclock[TAG_HIRES-1] = 50E9/amiga_eclock;   /* HIRES:  70 ns / 14 MHz */
+   pixclock[TAG_LORES-1] = 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-1];
+         if (amiga_fb_predefined[i].bits_per_pixel > maxdepth[tag-1])
+            amiga_fb_predefined[i].bits_per_pixel = maxdepth[tag-1];
+      }
+   }
+
+   err = register_framebuffer(amiga_fb_name, &node, &amiga_fb_ops,
+                              NUM_TOTAL_MODES, amiga_fb_predefined);
+   if (err < 0)
+      panic("Cannot register frame buffer");
+
+   fbhw->init();
+   check_default_mode();
+
+   if (!add_isr(IRQ_AMIGA_VERTB, amifb_interrupt, 0, NULL, "frame buffer"))
+      panic("Couldn't add vblank interrupt");
+
+   strcpy(fb_info.modename, amiga_fb_name);
+   fb_info.disp = disp;
+   fb_info.switch_con = &amifb_switch;
+   fb_info.updatevar = &amifb_updatevar;
+   fb_info.blank = &amifb_blank;
+
+   var = &amiga_fb_predefined[amifb_mode];
+   do_fb_set_var(var, 1);
+   strcat(fb_info.modename, " ");
+   strcat(fb_info.modename, amiga_fb_modenames[amifb_mode]);
+
+   amiga_fb_get_var(&disp[0].var, -1);
+   amiga_fb_set_disp(-1);
+   do_install_cmap(0);
+   return(&fb_info);
+}
+
+
+static int amifb_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 amifb_updatevar(int con)
+{
+   do_vmode = 0;
+   current_par.yoffset = disp[con].var.yoffset;
+   current_par.vmode = disp[con].var.vmode;
+   current_par.bplpt0 = ZTWO_PADDR((u_long)videomemory+
+                                   current_par.yoffset*current_par.next_line);
+   do_vmode = 1;
+   return(0);
+}
+
+
+   /*
+    *    Blank the display.
+    */
+
+static void amifb_blank(int blank)
+{
+   do_blank = blank ? 1 : -1;
+}
+
+
+   /*
+    *    VBlank Display Interrupt
+    */
+
+static void amifb_interrupt(int irq, struct pt_regs *fp, void *dummy)
+{
+   static int is_laced = 0;
+
+#if 0
+   /*
+    *    This test should be here, in case current_par isn't initialized yet
+    *
+    *    Fortunately only do_flashcursor() will be called in that case, and
+    *    currently that function doesn't use current_par. But this may change
+    *    in future...
+    */
+   if (!current_par_valid)
+      return;
+#endif
+
+   /*
+    *    If interlaced, only change the display on a long frame
+    */
+
+   if (!is_laced || custom.vposr & 0x8000) {
+      if (do_vmode) {
+         fbhw->do_vmode();
+         do_vmode = 0;
+         is_laced = (current_par.vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED;
+      }
+      if (do_movecursor) {
+         fbhw->do_movecursor();
+         do_movecursor = 0;
+      }
+   }
+   if (do_blank) {
+      fbhw->do_blank(do_blank > 0 ? 1 : 0);
+      do_blank = 0;
+   }
+   if (!is_blanked)
+      fbhw->do_flashcursor();
+}
+
+
+   /*
+    *    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);
+}
+
+
+   /*
+    *    Get a Video Modes
+    */
+
+static int get_video_mode(const char *name)
+{
+   int i;
+
+   for (i = 1; i < NUM_PREDEF_MODES; i++)
+      if (!strcmp(name, amiga_fb_modenames[i]))
+         return(i);
+   return(0);
+}
+
+
+   /*
+    *    Check the Default Video Mode
+    */
+
+static void check_default_mode(void)
+{
+   struct fb_var_screeninfo var;
+
+   /* First check the user supplied or system default video mode */
+   if (amifb_mode) {
+      var = amiga_fb_predefined[amifb_mode];
+      var.activate = FB_ACTIVATE_TEST;
+      if (!do_fb_set_var(&var, 1))
+         goto found_video_mode;
+   }
+
+   /* Try some other modes... */
+   printk("Can't use default video mode. Probing video modes...\n");
+   for (amifb_mode = 1; amifb_mode < NUM_PREDEF_MODES; amifb_mode++) {
+      var = amiga_fb_predefined[amifb_mode];
+      var.activate = FB_ACTIVATE_TEST;
+      if (!do_fb_set_var(&var, 1))
+         goto found_video_mode;
+   }
+   panic("Can't find any usable video mode");
+
+found_video_mode:
+   amiga_fb_predefined[0] = var;
+}
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/amiga/amiints.c linux/arch/m68k/amiga/amiints.c
--- v1.3.93/linux/arch/m68k/amiga/amiints.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/amiga/amiints.c	Wed Mar 20 20:02:50 1996
@@ -0,0 +1,376 @@
+/*
+ * amiints.c -- Amiga Linux interrupt handling code
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file README.legal in the main directory of this archive
+ * for more details.
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/traps.h>
+#include <asm/amigahw.h>
+#include <asm/amigaints.h>
+
+/* isr node variables for amiga interrupt sources */
+static isr_node_t *ami_lists[NUM_AMIGA_SOURCES];
+
+static const ushort ami_intena_vals[NUM_AMIGA_SOURCES] = {
+    IF_VERTB, IF_COPER, IF_AUD0, IF_AUD1, IF_AUD2, IF_AUD3, IF_BLIT,
+    IF_DSKSYN, IF_DSKBLK, IF_RBF, IF_TBE, IF_PORTS, IF_PORTS, IF_PORTS,
+    IF_PORTS, IF_PORTS, IF_EXTER, IF_EXTER, IF_EXTER, IF_EXTER, IF_EXTER,
+    IF_SOFT, IF_PORTS, IF_EXTER
+    };
+
+struct ciadata
+{
+    volatile struct CIA *ciaptr;
+    unsigned long	baseirq;
+} ciadata[2];
+
+/*
+ * index into ami_lists for IRQs.  CIA IRQs are special, because
+ * the same cia interrupt handler is used for both CIAs.
+ */
+#define IRQ_IDX(source) (source & ~IRQ_MACHSPEC)
+#define CIA_IRQ_IDX(source) (IRQ_IDX(datap->baseirq) \
+			     +(source-IRQ_AMIGA_CIAA_TA))
+
+/*
+ * void amiga_init_INTS (void)
+ *
+ * Parameters:	None
+ *
+ * Returns:	Nothing
+ *
+ * This function should be called during kernel startup to initialize
+ * the amiga IRQ handling routines.
+ */
+
+static void
+    ami_int1(int irq, struct pt_regs *fp, void *data),
+    ami_int2(int irq, struct pt_regs *fp, void *data),
+    ami_int3(int irq, struct pt_regs *fp, void *data),
+    ami_int4(int irq, struct pt_regs *fp, void *data),
+    ami_int5(int irq, struct pt_regs *fp, void *data),
+    ami_int6(int irq, struct pt_regs *fp, void *data),
+    ami_int7(int irq, struct pt_regs *fp, void *data),
+    ami_intcia(int irq, struct pt_regs *fp, void *data);
+
+void amiga_init_INTS (void)
+{
+    int i;
+
+    /* initialize handlers */
+    for (i = 0; i < NUM_AMIGA_SOURCES; i++)
+	ami_lists[i] = NULL;
+
+    add_isr (IRQ1, ami_int1, 0, NULL, "int1 handler");
+    add_isr (IRQ2, ami_int2, 0, NULL, "int2 handler");
+    add_isr (IRQ3, ami_int3, 0, NULL, "int3 handler");
+    add_isr (IRQ4, ami_int4, 0, NULL, "int4 handler");
+    add_isr (IRQ5, ami_int5, 0, NULL, "int5 handler");
+    add_isr (IRQ6, ami_int6, 0, NULL, "int6 handler");
+    add_isr (IRQ7, ami_int7, 0, NULL, "int7 handler");
+
+    /* hook in the CIA interrupts */
+    ciadata[0].ciaptr = &ciaa;
+    ciadata[0].baseirq = IRQ_AMIGA_CIAA_TA;
+    add_isr (IRQ_AMIGA_PORTS, ami_intcia, 0, NULL, "Amiga CIAA");
+    ciadata[1].ciaptr = &ciab;
+    ciadata[1].baseirq = IRQ_AMIGA_CIAB_TA;
+    add_isr (IRQ_AMIGA_EXTER, ami_intcia, 0, NULL, "Amiga CIAB");
+
+    /* turn off all interrupts and enable the master interrupt bit */
+    custom.intena = 0x7fff;
+    custom.intreq = 0x7fff;
+    custom.intena = 0xc000;
+
+    /* turn off all CIA interrupts */
+    ciaa.icr = 0x7f;
+    ciab.icr = 0x7f;
+
+    /* clear any pending CIA interrupts */
+    i = ciaa.icr;
+    i = ciab.icr;
+}
+
+
+/*
+ * The builtin Amiga hardware interrupt handlers.
+ */
+
+static void ami_int1 (int irq, struct pt_regs *fp, void *data)
+{
+    ushort ints = custom.intreqr & custom.intenar;
+
+    /* if serial transmit buffer empty, interrupt */
+    if (ints & IF_TBE) {
+	if (ami_lists[IRQ_IDX(IRQ_AMIGA_TBE)]) {
+	    call_isr_list (IRQ_AMIGA_TBE,
+			   ami_lists[IRQ_IDX(IRQ_AMIGA_TBE)], fp);
+	    /* 
+	     * don't acknowledge.... 
+	     * allow serial code to turn off interrupts, but
+	     * leave it pending so that when interrupts are
+	     * turned on, transmission will resume
+	     */
+	} else
+	    /* acknowledge the interrupt */
+	    custom.intreq = IF_TBE;
+    }
+
+    /* if floppy disk transfer complete, interrupt */
+    if (ints & IF_DSKBLK) {
+	call_isr_list (IRQ_AMIGA_DSKBLK,
+		       ami_lists[IRQ_IDX(IRQ_AMIGA_DSKBLK)], fp);
+
+	/* acknowledge */
+	custom.intreq = IF_DSKBLK;
+    }
+
+    /* if software interrupt set, interrupt */
+    if (ints & IF_SOFT) {
+	call_isr_list (IRQ_AMIGA_SOFT,
+		       ami_lists[IRQ_IDX(IRQ_AMIGA_SOFT)], fp);
+
+	/* acknowledge */
+	custom.intreq = IF_SOFT;
+    }
+}
+
+static void ami_int2 (int irq, struct pt_regs *fp, void *data)
+{
+    ushort ints = custom.intreqr & custom.intenar;
+
+    if (ints & IF_PORTS) {
+	/* call routines which have hooked into the PORTS interrupt */
+	call_isr_list (IRQ_AMIGA_PORTS,
+		       ami_lists[IRQ_IDX(IRQ_AMIGA_PORTS)], fp);
+
+	/* acknowledge */
+	custom.intreq = IF_PORTS;
+    }
+}
+
+static void ami_int3 (int irq, struct pt_regs *fp, void *data)
+{
+    ushort ints = custom.intreqr & custom.intenar;
+
+    /* if a copper interrupt */
+    if (ints & IF_COPER) {
+	call_isr_list (IRQ_AMIGA_COPPER,
+		       ami_lists[IRQ_IDX(IRQ_AMIGA_COPPER)], fp);
+
+	/* acknowledge */
+	custom.intreq = IF_COPER;
+    }
+
+    /* if a vertical blank interrupt */
+    if (ints & IF_VERTB) {
+	call_isr_list (IRQ_AMIGA_VERTB,
+		       ami_lists[IRQ_IDX(IRQ_AMIGA_VERTB)], fp);
+
+	/* acknowledge */
+	custom.intreq = IF_VERTB;
+    }
+
+    /* if a blitter interrupt */
+    if (ints & IF_BLIT) {
+	call_isr_list (IRQ_AMIGA_BLIT,
+		       ami_lists[IRQ_IDX(IRQ_AMIGA_BLIT)], fp);
+
+	/* acknowledge */
+	custom.intreq = IF_BLIT;
+    }
+}
+
+static void ami_int4 (int irq, struct pt_regs *fp, void *data)
+{
+    ushort ints = custom.intreqr & custom.intenar;
+
+    /* if audio 0 interrupt */
+    if (ints & IF_AUD0) {
+	call_isr_list (IRQ_AMIGA_AUD0,
+		       ami_lists[IRQ_IDX(IRQ_AMIGA_AUD0)], fp);
+
+	/* acknowledge */
+	custom.intreq = IF_AUD0;
+    }
+
+    /* if audio 1 interrupt */
+    if (ints & IF_AUD1) {
+	call_isr_list (IRQ_AMIGA_AUD1,
+		       ami_lists[IRQ_IDX(IRQ_AMIGA_AUD1)], fp);
+
+	/* acknowledge */
+	custom.intreq = IF_AUD1;
+    }
+
+    /* if audio 2 interrupt */
+    if (ints & IF_AUD2) {
+	call_isr_list (IRQ_AMIGA_AUD2,
+		       ami_lists[IRQ_IDX(IRQ_AMIGA_AUD2)], fp);
+
+	/* acknowledge */
+	custom.intreq = IF_AUD2;
+    }
+
+    /* if audio 3 interrupt */
+    if (ints & IF_AUD3) {
+	call_isr_list (IRQ_AMIGA_AUD3,
+		       ami_lists[IRQ_IDX(IRQ_AMIGA_AUD3)], fp);
+
+	/* acknowledge */
+	custom.intreq = IF_AUD3;
+    }
+}
+
+static void ami_int5 (int irq, struct pt_regs *fp, void *data)
+{
+    ushort ints = custom.intreqr & custom.intenar;
+
+    /* if serial receive buffer full interrupt */
+    if (ints & IF_RBF) {
+	if (ami_lists[IRQ_IDX(IRQ_AMIGA_RBF)]) {
+	    call_isr_list (IRQ_AMIGA_RBF,
+			   ami_lists[IRQ_IDX(IRQ_AMIGA_RBF)], fp);
+	    /* don't acknowledge ; leave that for the handler */
+        } else
+	    /* acknowledge the interrupt */
+	    custom.intreq = IF_RBF;
+    }
+
+    /* if a disk sync interrupt */
+    if (ints & IF_DSKSYN) {
+	call_isr_list (IRQ_AMIGA_DSKSYN,
+		       ami_lists[IRQ_IDX(IRQ_AMIGA_DSKSYN)], fp);
+
+	/* acknowledge */
+	custom.intreq = IF_DSKSYN;
+    }
+}
+
+static void ami_int6 (int irq, struct pt_regs *fp, void *data)
+{
+    ushort ints = custom.intreqr & custom.intenar;
+
+    if (ints & IF_EXTER) {
+	/* call routines which have hooked into the EXTER interrupt */
+	call_isr_list (IRQ_AMIGA_EXTER,
+		       ami_lists[IRQ_IDX(IRQ_AMIGA_EXTER)], fp);
+
+	/* acknowledge */
+	custom.intreq = IF_EXTER;
+    }
+}
+
+static void ami_int7 (int irq, struct pt_regs *fp, void *data)
+{
+    panic ("level 7 interrupt received\n");
+}
+
+static void ami_intcia (int irq, struct pt_regs *fp, void *data)
+{
+    /* check CIA interrupts */
+    struct ciadata *datap;
+    u_char cia_ints;
+
+    /* setup data correctly */
+    if (irq == IRQ_AMIGA_PORTS)
+	    datap = &ciadata[0];
+    else
+	    datap = &ciadata[1];
+
+    cia_ints = datap->ciaptr->icr;
+
+    /* if timer A interrupt */
+    if (cia_ints & CIA_ICR_TA)
+	call_isr_list (IRQ_AMIGA_CIAA_TA,
+		       ami_lists[CIA_IRQ_IDX(IRQ_AMIGA_CIAA_TA)], fp);
+
+    /* if timer B interrupt */
+    if (cia_ints & CIA_ICR_TB)
+	call_isr_list (IRQ_AMIGA_CIAA_TB,
+		       ami_lists[CIA_IRQ_IDX(IRQ_AMIGA_CIAA_TB)], fp);
+
+    /* if the alarm interrupt */
+    if (cia_ints & CIA_ICR_ALRM)
+	call_isr_list (IRQ_AMIGA_CIAA_ALRM,
+		       ami_lists[CIA_IRQ_IDX(IRQ_AMIGA_CIAA_ALRM)], fp);
+
+    /* if serial port interrupt (keyboard) */
+    if (cia_ints & CIA_ICR_SP)
+	call_isr_list (IRQ_AMIGA_CIAA_SP,
+		       ami_lists[CIA_IRQ_IDX(IRQ_AMIGA_CIAA_SP)], fp);
+
+    /* if flag interrupt (parallel port) */
+    if (cia_ints & CIA_ICR_FLG)
+	call_isr_list (IRQ_AMIGA_CIAA_FLG,
+		       ami_lists[CIA_IRQ_IDX(IRQ_AMIGA_CIAA_FLG)], fp);
+}
+
+/*
+ * amiga_add_isr : add an interrupt service routine for a particular
+ *		   machine specific interrupt source.
+ *		   If the addition was successful, it returns 1, otherwise
+ *		   it returns 0.  It will fail if another routine is already
+ *		   bound into the specified source.
+ *   Note that the "pri" argument is currently unused.
+ */
+
+int amiga_add_isr (unsigned long source, isrfunc isr, int pri, void
+		   *data, char *name)
+{
+    unsigned long amiga_source = source & ~IRQ_MACHSPEC;
+    isr_node_t *p;
+
+    if (amiga_source > NUM_AMIGA_SOURCES) {
+	printk ("amiga_add_isr: Unknown interrupt source %ld\n", source);
+	return 0;
+    }
+
+    p = new_isr_node();
+    p->isr = isr;
+    p->pri = pri;
+    p->data = data;
+    p->name = name;
+    p->next = NULL;
+    insert_isr (&ami_lists[amiga_source], p);
+
+    /* enable the interrupt */
+    custom.intena = IF_SETCLR | ami_intena_vals[amiga_source];
+
+    /* if a CIAA interrupt, enable the appropriate CIA ICR bit */
+    if (source >= IRQ_AMIGA_CIAA_TA && source <= IRQ_AMIGA_CIAA_FLG)
+	ciaa.icr = 0x80 | (1 << (source - IRQ_AMIGA_CIAA_TA));
+
+    /* if a CIAB interrupt, enable the appropriate CIA ICR bit */
+    if (source >= IRQ_AMIGA_CIAB_TA && source <= IRQ_AMIGA_CIAB_FLG)
+	ciab.icr = 0x80 | (1 << (source - IRQ_AMIGA_CIAB_TA));
+
+    return 1;
+}
+
+int amiga_get_irq_list( char *buf, int len )
+{	int			i;
+    isr_node_t	*p;
+
+	for( i = 0; i < NUM_AMIGA_SOURCES; ++i ) {
+		if (!ami_lists[i])
+			continue;
+		len += sprintf( buf+len, "ami  %2d: ???????? ", i );
+		for( p = ami_lists[i]; p; p = p->next ) {
+			len += sprintf( buf+len, "%s\n", p->name );
+			if (p->next)
+				len += sprintf( buf+len, "                  " );
+		}
+	}
+	
+	return( len );
+}
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/amiga/amikeyb.c linux/arch/m68k/amiga/amikeyb.c
--- v1.3.93/linux/arch/m68k/amiga/amikeyb.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/amiga/amikeyb.c	Sat Mar 30 20:29:34 1996
@@ -0,0 +1,300 @@
+/*
+ * linux/amiga/amikeyb.c
+ *
+ * Amiga Keyboard driver for 680x0 Linux
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file README.legal 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 <asm/bootinfo.h>
+#include <asm/amigatypes.h>
+#include <asm/amigaints.h>
+#include <asm/amigahw.h>
+#include <asm/irq.h>
+
+extern int do_poke_blanked_console;
+extern void process_keycode (int);
+
+#define AMIKEY_CAPS	(0x62)
+#define BREAK_MASK	(0x80)
+
+static u_short amiplain_map[NR_KEYS] = {
+	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, 0xf208, 0xf209, 0xf30d, 0xf30c, 0xf30a, 0xf10a,
+	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, 0xf203, 0xf30d, 0xf30c, 0xf30a, 0xf10a,
+	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, 0xf202, 0xf30d, 0xf30c, 0xf30a, 0xf516,
+	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, 0xf204, 0xf30d, 0xf30c, 0xf30a, 0xf10a,
+	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, 0xf200, 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, 0xf50a,
+	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, 0xf200, 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};
+
+extern struct pt_regs *pt_regs;
+
+static void amikeyb_rep (unsigned long ignore)
+{
+	unsigned long flags;
+	save_flags(flags);
+	cli();
+
+	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);
+	process_keycode (rep_scancode);
+
+	restore_flags(flags);
+}
+
+static void keyboard_interrupt (int irq, struct pt_regs *fp, void *dummy)
+{
+    unsigned char scancode, break_flag;
+
+    /* save frame for register dump */
+    pt_regs = (struct pt_regs *)fp;
+
+    /* get and invert scancode (keyboard is active low) */
+    scancode = ~ciaa.sdr;
+
+    /* switch SP pin to output for handshake */
+    ciaa.cra |= 0x40;
+    /* wait until 85 us have expired */
+    udelay(85);
+    /* switch CIA serial port to input mode */
+    ciaa.cra &= ~0x40;
+
+    /* rotate scan code to get up/down bit in proper position */
+    __asm__ __volatile__ ("rorb #1,%0" : "=g" (scancode) : "0" (scancode));
+
+    /*
+     * do machine independent keyboard processing of "normalized" scancode
+     * A "normalized" scancode is one that an IBM PC might generate
+     * Check make/break first
+     */
+    break_flag = scancode & BREAK_MASK;
+    scancode &= (unsigned char )~BREAK_MASK;
+
+    if (scancode == AMIKEY_CAPS) {
+	    /* if the key is CAPS, fake a press/release. */
+	    process_keycode (AMIKEY_CAPS);
+	    process_keycode (BREAK_MASK | AMIKEY_CAPS);
+    } else {
+	    /* handle repeat */
+	    if (break_flag) {
+		    del_timer(&amikeyb_rep_timer);
+		    rep_scancode = 0;
+	    } else {
+		    del_timer(&amikeyb_rep_timer);
+		    rep_scancode = break_flag | scancode;
+		    amikeyb_rep_timer.expires = jiffies + key_repeat_delay;
+		    amikeyb_rep_timer.prev = amikeyb_rep_timer.next = NULL;
+		    add_timer(&amikeyb_rep_timer);
+	    }
+	    process_keycode (break_flag | scancode);
+    }
+
+    do_poke_blanked_console = 1;
+    mark_bh(CONSOLE_BH);
+    add_keyboard_randomness(scancode);
+
+    return;
+}
+
+int amiga_keyb_init (void)
+{
+    if (!AMIGAHW_PRESENT(AMI_KEYBOARD))
+        return -EIO;
+
+    /* setup key map */
+    key_maps[0]  = amiplain_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;
+    memcpy (plain_map, amiplain_map, sizeof(plain_map));
+
+    /*
+     * Initialize serial data direction.
+     */
+    ciaa.cra &= ~0x41;	     /* serial data in, turn off TA */
+
+    /*
+     * arrange for processing of keyboard interrupt
+     */
+    add_isr (IRQ_AMIGA_CIAA_SP, keyboard_interrupt, 0, NULL, "keyboard");
+
+    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 v1.3.93/linux/arch/m68k/amiga/amipart.c linux/arch/m68k/amiga/amipart.c
--- v1.3.93/linux/arch/m68k/amiga/amipart.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/amiga/amipart.c	Wed Mar 20 20:03:41 1996
@@ -0,0 +1,119 @@
+/*
+ * linux/amiga/amipart.c
+ *
+ * Amiga partition checking driver for 680x0 Linux
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file README.legal in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/fs.h>
+#include <linux/genhd.h>
+#include <linux/kernel.h>
+
+#include <asm/amigardb.h>
+#include <asm/machdep.h>
+
+extern int current_minor;
+
+static ulong checksum (ulong *ptr, int len)
+{
+	ulong sum;
+	int cnt;
+
+	for (sum = 0, cnt = 0; cnt < len; cnt++)
+		sum += ptr[cnt];
+
+	return sum;
+}
+
+/* XXX */
+/* int current_minor = 0; */
+
+void amiga_check_partition(struct gendisk *hd, kdev_t dev)
+{
+	int i, minor = current_minor, m_lim = current_minor + hd->max_p;
+	struct buffer_head *bh;
+	struct RigidDiskBlock *rdb;
+	struct PartitionBlock *pb;
+	ulong bnum, partsect;
+
+	for (bnum = 0; bnum < RDB_LOCATION_LIMIT/2; bnum++) {
+		if (!(bh = bread(dev,bnum,1024))) {
+			printk (" unable to read block %ld\n", bnum);
+			return;
+		}
+#ifdef DEBUG
+		printk ("block read, press mousebutton to continue\n");
+		waitbut();
+#endif
+		rdb = (struct RigidDiskBlock *)bh->b_data;
+		if (rdb->rdb_ID == IDNAME_RIGIDDISK)
+			break;
+		rdb = (struct RigidDiskBlock *)&bh->b_data[512];
+		if (rdb->rdb_ID == IDNAME_RIGIDDISK)
+			break;
+		brelse (bh);
+	}
+	if (bnum == RDB_LOCATION_LIMIT/2) {
+		/* no RDB on the disk! */
+		printk (" unable to find RigidDiskBlock\n");
+		return;
+	}
+
+	/* checksum the RigidDiskBlock */
+	if (checksum ((ulong *)rdb, rdb->rdb_SummedLongs) != 0) {
+		printk (" RDB checksum bad\n");
+		return;
+	}
+
+	printk("  %s%c:", hd->major_name, 'a'+(minor >> hd->minor_shift));
+
+	partsect = rdb->rdb_PartitionList;
+	brelse (bh);
+
+	for (i = 1; minor < m_lim && partsect != 0xffffffff; minor++, i++)
+	{
+		ulong *env;
+
+		if (!(bh = bread(dev,partsect/2,1024))) {
+			printk (" block %ld read failed\n", partsect);
+			return;
+		}
+#ifdef DEBUG
+		printk ("block read, press mousebutton to continue\n");
+		waitbut();
+#endif
+		pb = (struct PartitionBlock *)bh->b_data;
+		if (partsect & 1)
+			pb = (struct PartitionBlock *)&bh->b_data[512];
+		if (pb->pb_ID != IDNAME_PARTITION) {
+			printk (" block %ld Not a partition block (%#lx)\n",
+				partsect, pb->pb_ID);
+			brelse (bh);
+			return;
+		}
+		if (checksum ((ulong *)pb, pb->pb_SummedLongs) != 0) {
+			printk (" block %ld checksum bad\n", partsect);
+			brelse (bh);
+			return;
+		}
+
+		env = pb->pb_Environment;
+
+		hd->part[minor].start_sect = env[DE_LOWCYL]
+			* env[DE_NUMHEADS] * env[DE_BLKSPERTRACK];
+		hd->part[minor].nr_sects = (env[DE_UPPERCYL]
+					    - env[DE_LOWCYL] + 1)
+			* env[DE_NUMHEADS] * env[DE_BLKSPERTRACK];
+
+		printk(" %s%c%d", hd->major_name,
+		       'a'+(minor >> hd->minor_shift), i);
+
+		partsect = pb->pb_Next;
+		brelse (bh);
+	}
+
+	printk ("\n");
+}
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/amiga/amisound.c linux/arch/m68k/amiga/amisound.c
--- v1.3.93/linux/arch/m68k/amiga/amisound.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/amiga/amisound.c	Thu Apr 18 02:26:30 1996
@@ -0,0 +1,110 @@
+/*
+ * linux/amiga/amisound.c
+ *
+ * amiga sound driver for 680x0 Linux
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file README.legal in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/sched.h>
+#include <linux/timer.h>
+
+#include <asm/system.h>
+#include <asm/amigahw.h>
+#include <asm/bootinfo.h>
+
+static u_short *snd_data = NULL;
+static const signed char sine_data[] = {
+	0,  39,  75,  103,  121,  127,  121,  103,  75,  39,
+	0, -39, -75, -103, -121, -127, -121, -103, -75, -39
+};
+#define DATA_SIZE	(sizeof(sine_data)/sizeof(sine_data[0]))
+
+/* Imported from arch/m68k/amiga/amifb.c */
+extern volatile u_short amiga_audio_min_period;
+
+#define MAX_PERIOD	(65535)
+
+
+    /*
+     *	Current period (set by dmasound.c)
+     */
+
+u_short amiga_audio_period = MAX_PERIOD;
+
+static u_long clock_constant;
+
+static void init_sound(void)
+{
+	snd_data = amiga_chip_alloc(sizeof(sine_data));
+	if (!snd_data) {
+		printk (KERN_CRIT "amiga init_sound: failed to allocate chipmem\n");
+		return;
+	}
+	memcpy (snd_data, sine_data, sizeof(sine_data));
+
+	/* setup divisor */
+	clock_constant = (amiga_colorclock+DATA_SIZE/2)/DATA_SIZE;
+}
+
+static void nosound( unsigned long ignored );
+static struct timer_list sound_timer = { NULL, NULL, 0, 0, nosound };
+
+void amiga_mksound( unsigned int hz, unsigned int ticks )
+{
+	static int inited = 0;
+	unsigned long flags;
+
+	if (!inited) {
+		init_sound();
+		inited = 1;
+	}
+
+	if (!snd_data)
+		return;
+
+	save_flags(flags);
+	cli();
+	del_timer( &sound_timer );
+
+	if (hz > 20 && hz < 32767) {
+		u_long period = (clock_constant / hz);
+
+		if (period < amiga_audio_min_period)
+			period = amiga_audio_min_period;
+		if (period > MAX_PERIOD)
+			period = MAX_PERIOD;
+
+		/* setup pointer to data, period, length and volume */
+		custom.aud[0].audlc = snd_data;
+		custom.aud[0].audlen = sizeof(sine_data)/2;
+		custom.aud[0].audper = (u_short)period;
+		custom.aud[0].audvol = 64; /* maxvol */
+	
+		if (ticks) {
+			sound_timer.expires = jiffies + ticks;
+			add_timer( &sound_timer );
+		}
+
+		/* turn on DMA for audio channel 0 */
+		custom.dmacon = DMAF_SETCLR | DMAF_AUD0;
+
+		restore_flags(flags);
+		return;
+	} else {
+		nosound( 0 );
+		restore_flags(flags);
+		return;
+	}
+}
+
+
+static void nosound( unsigned long ignored )
+{
+	/* turn off DMA for audio channel 0 */
+	custom.dmacon = DMAF_AUD0;
+	/* restore period to previous value after beeping */
+	custom.aud[0].audper = amiga_audio_period;
+}	
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/amiga/chipram.c linux/arch/m68k/amiga/chipram.c
--- v1.3.93/linux/arch/m68k/amiga/chipram.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/amiga/chipram.c	Thu Mar  7 18:19:55 1996
@@ -0,0 +1,158 @@
+/*
+**  linux/amiga/chipram.c
+**
+**      Modified 03-May-94 by Geert Uytterhoeven
+**                           (Geert.Uytterhoeven@cs.kuleuven.ac.be)
+**          - 64-bit aligned allocations for full AGA compatibility
+*/
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <asm/bootinfo.h>
+#include <asm/amigahw.h>
+
+struct chip_desc {
+	unsigned first   :  1;
+	unsigned last    :  1;
+	unsigned alloced :  1;
+	unsigned length  : 24;
+	long pad;					/* We suppose this makes this struct 64 bits long!! */
+};
+
+#define DP(ptr) ((struct chip_desc *)(ptr))
+
+static unsigned long chipsize;
+
+void amiga_chip_init (void)
+{
+  struct chip_desc *dp;
+
+  if (!AMIGAHW_PRESENT(CHIP_RAM))
+    return;
+
+  chipsize = boot_info.bi_amiga.chip_size;
+
+  /* initialize start boundary */
+
+  custom.color[0] = 0xfff;
+
+  dp = DP(chipaddr);
+  dp->first = 1;
+
+  custom.color[0] = 0x0f00;
+
+  dp->alloced = 0;
+  dp->length = chipsize - 2*sizeof(*dp);
+
+  /* initialize end boundary */
+  dp = DP(chipaddr + chipsize) - 1;
+  dp->last = 1;
+  
+  custom.color[0] = 0x00f0;
+
+  dp->alloced = 0;
+  dp->length = chipsize - 2*sizeof(*dp);
+
+  custom.color[0] = 0x000f;
+
+#ifdef DEBUG
+  printk ("chipram end boundary is %p, length is %d\n", dp,
+	  dp->length);
+#endif
+}
+
+void *amiga_chip_alloc (long size)
+{
+	/* last chunk */
+	struct chip_desc *dp;
+	void *ptr;
+
+	/* round off */
+	size = (size + 7) & ~7;
+
+#ifdef DEBUG
+	printk ("chip_alloc: allocate %ld bytes\n", size);
+#endif
+
+	/*
+	 * get pointer to descriptor for last chunk by 
+	 * going backwards from end chunk
+	 */
+	dp = DP(chipaddr + chipsize) - 1;
+	dp = DP((unsigned long)dp - dp->length) - 1;
+	
+	while ((dp->alloced || dp->length < size)
+	       && !dp->first)
+		dp = DP ((unsigned long)dp - dp[-1].length) - 2;
+
+	if (dp->alloced || dp->length < size) {
+		printk ("no chipmem available for %ld allocation\n", size);
+		return NULL;
+	}
+
+	if (dp->length < (size + 2*sizeof(*dp))) {
+		/* length too small to split; allocate the whole thing */
+		dp->alloced = 1;
+		ptr = (void *)(dp+1);
+		dp = DP((unsigned long)ptr + dp->length);
+		dp->alloced = 1;
+#ifdef DEBUG
+		printk ("chip_alloc: no split\n");
+#endif
+	} else {
+		/* split the extent; use the end part */
+		long newsize = dp->length - (2*sizeof(*dp) + size);
+
+#ifdef DEBUG
+		printk ("chip_alloc: splitting %d to %ld\n", dp->length,
+			newsize);
+#endif
+		dp->length = newsize;
+		dp = DP((unsigned long)(dp+1) + newsize);
+		dp->first = dp->last = 0;
+		dp->alloced = 0;
+		dp->length = newsize;
+		dp++;
+		dp->first = dp->last = 0;
+		dp->alloced = 1;
+		dp->length = size;
+		ptr = (void *)(dp+1);
+		dp = DP((unsigned long)ptr + size);
+		dp->alloced = 1;
+		dp->length = size;
+	}
+
+#ifdef DEBUG
+	printk ("chip_alloc: returning %p\n", ptr);
+#endif
+
+	if ((unsigned long)ptr & 7)
+		panic("chip_alloc: alignment violation\n");
+
+	return ptr;
+}
+
+void amiga_chip_free (void *ptr)
+{
+	struct chip_desc *sdp = DP(ptr) - 1, *dp2;
+	struct chip_desc *edp = DP((unsigned long)ptr + sdp->length);
+
+	/* deallocate the chunk */
+	sdp->alloced = edp->alloced = 0;
+
+	/* check if we should merge with the previous chunk */
+	if (!sdp->first && !sdp[-1].alloced) {
+		dp2 = DP((unsigned long)sdp - sdp[-1].length) - 2;
+		dp2->length += sdp->length + 2*sizeof(*sdp);
+		edp->length = dp2->length;
+		sdp = dp2;
+	}
+
+	/* check if we should merge with the following chunk */
+	if (!edp->last && !edp[1].alloced) {
+		dp2 = DP((unsigned long)edp + edp[1].length) + 2;
+		dp2->length += edp->length + 2*sizeof(*sdp);
+		sdp->length = dp2->length;
+		edp = dp2;
+	}
+}
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/amiga/config.c linux/arch/m68k/amiga/config.c
--- v1.3.93/linux/arch/m68k/amiga/config.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/amiga/config.c	Fri Apr 19 02:41:15 1996
@@ -0,0 +1,881 @@
+/*
+ *  linux/amiga/config.c
+ *
+ *  Copyright (C) 1993 Hamish Macdonald
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file README.legal in the main directory of this archive
+ * for more details.
+ */
+
+/*
+ * Miscellaneous Amiga stuff
+ */
+
+#include <stdarg.h>
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/kd.h>
+#include <linux/tty.h>
+#include <linux/console.h>
+#include <linux/linkage.h>
+
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/bootinfo.h>
+#include <asm/amigahw.h>
+#include <asm/amigaints.h>
+#include <asm/irq.h>
+#include <asm/machdep.h>
+
+u_long amiga_masterclock;
+u_long amiga_colorclock;
+
+extern char m68k_debug_device[];
+
+extern void amiga_sched_init(isrfunc handler);
+extern int amiga_keyb_init(void);
+extern int amiga_kbdrate (struct kbd_repeat *);
+extern void amiga_init_INTS (void);
+extern int amiga_add_isr (unsigned long, isrfunc, int, void *, char *);
+extern int amiga_remove_isr (unsigned long, isrfunc);
+extern int amiga_get_irq_list (char *, int);
+extern void amiga_enable_irq(unsigned int);
+extern void amiga_disable_irq(unsigned int);
+extern unsigned long amiga_gettimeoffset (void);
+extern void a3000_gettod (int *, int *, int *, int *, int *, int *);
+extern void a2000_gettod (int *, int *, int *, int *, int *, int *);
+extern int amiga_hwclk (int, struct hwclk_time *);
+extern int amiga_set_clock_mmss (unsigned long);
+extern void amiga_check_partition (struct gendisk *hd, unsigned int dev);
+extern void amiga_mksound( unsigned int count, unsigned int ticks );
+#ifdef CONFIG_BLK_DEV_FD
+extern int amiga_floppy_init (void);
+extern void amiga_floppy_setup(char *, int *);
+#endif
+extern void amiga_reset (void);
+extern void amiga_waitbut(void);
+extern struct consw fb_con;
+extern struct fb_info *amiga_fb_init(long *);
+extern void zorro_init(void);
+static void ami_savekmsg_init(void);
+static void ami_mem_print(const char *b);
+extern void amiga_debug_init(void);
+extern void amiga_video_setup(char *, int *);
+
+extern void (*kd_mksound)(unsigned int, unsigned int);
+
+void config_amiga(void)
+{
+  char *type = NULL;
+
+  switch(boot_info.bi_amiga.model) {
+  case AMI_500:
+    type = "A500";
+    break;
+  case AMI_500PLUS:
+    type = "A500+";
+    break;
+  case AMI_600:
+    type = "A600";
+    break;
+  case AMI_1000:
+    type = "A1000";
+    break;
+  case AMI_1200:
+    type = "A1200";
+    break;
+  case AMI_2000:
+    type = "A2000";
+    break;
+  case AMI_2500:
+    type = "A2500";
+    break;
+  case AMI_3000:
+    type = "A3000";
+    break;
+  case AMI_3000T:
+    type = "A3000T";
+    break;
+  case AMI_3000PLUS:
+    type = "A3000+";
+    break;
+  case AMI_4000:
+    type = "A4000";
+    break;
+  case AMI_4000T:
+    type = "A4000T";
+    break;
+  case AMI_CDTV:
+    type = "CDTV";
+    break;
+  case AMI_CD32:
+    type = "CD32";
+    break;
+  case AMI_DRACO:
+    type = "Draco";
+    break;
+  }
+  printk("Amiga hardware found: ");
+  if (type)
+    printk("[%s] ", type);
+  switch(boot_info.bi_amiga.model) {
+  case AMI_UNKNOWN:
+    goto Generic;
+
+  case AMI_500:
+  case AMI_500PLUS:
+  case AMI_1000:
+    AMIGAHW_SET(A2000_CLK);             /* Is this correct? */
+    printk("A2000_CLK ");
+    goto Generic;
+
+  case AMI_600:
+  case AMI_1200:
+    AMIGAHW_SET(A1200_IDE);
+    printk("A1200_IDE ");
+    AMIGAHW_SET(A2000_CLK);             /* Is this correct? */
+    printk("A2000_CLK ");
+    goto Generic;
+
+  case AMI_2000:
+  case AMI_2500:
+    AMIGAHW_SET(A2000_CLK);
+    printk("A2000_CLK ");
+    goto Generic;
+
+  case AMI_3000:
+  case AMI_3000T:
+    AMIGAHW_SET(AMBER_FF);
+    printk("AMBER_FF ");
+    AMIGAHW_SET(MAGIC_REKICK);
+    printk("MAGIC_REKICK ");
+    /* fall through */
+  case AMI_3000PLUS:
+    AMIGAHW_SET(A3000_SCSI);
+    printk("A3000_SCSI ");
+    AMIGAHW_SET(A3000_CLK);
+    printk("A3000_CLK ");
+    goto Generic;
+
+  case AMI_4000T:
+    AMIGAHW_SET(A4000_SCSI);
+    printk("A4000_SCSI ");
+    /* fall through */
+  case AMI_4000:
+    AMIGAHW_SET(A4000_IDE);
+    printk("A4000_IDE ");
+    AMIGAHW_SET(A3000_CLK);
+    printk("A3000_CLK ");
+    goto Generic;
+
+  case AMI_CDTV:
+  case AMI_CD32:
+    AMIGAHW_SET(CD_ROM);
+    printk("CD_ROM ");
+    AMIGAHW_SET(A2000_CLK);             /* Is this correct? */
+    printk("A2000_CLK ");
+    goto Generic;
+
+  Generic:
+    AMIGAHW_SET(AMI_VIDEO);
+    AMIGAHW_SET(AMI_BLITTER);
+    AMIGAHW_SET(AMI_AUDIO);
+    AMIGAHW_SET(AMI_FLOPPY);
+    AMIGAHW_SET(AMI_KEYBOARD);
+    AMIGAHW_SET(AMI_MOUSE);
+    AMIGAHW_SET(AMI_SERIAL);
+    AMIGAHW_SET(AMI_PARALLEL);
+    AMIGAHW_SET(CHIP_RAM);
+    AMIGAHW_SET(PAULA);
+    printk("VIDEO BLITTER AUDIO FLOPPY KEYBOARD MOUSE SERIAL PARALLEL "
+	   "CHIP_RAM PAULA ");
+
+    switch(boot_info.bi_amiga.chipset) {
+    case CS_OCS:
+    case CS_ECS:
+    case CS_AGA:
+      switch (custom.deniseid & 0xf) {
+      case 0x0c:
+	AMIGAHW_SET(DENISE_HR);
+	printk("DENISE_HR");
+	break;
+      case 0x08:
+	AMIGAHW_SET(LISA);
+	printk("LISA ");
+	break;
+      }
+      break;
+    default:
+      AMIGAHW_SET(DENISE);
+      printk("DENISE ");
+      break;
+    }
+    switch ((custom.vposr>>8) & 0x7f) {
+    case 0x00:
+      AMIGAHW_SET(AGNUS_PAL);
+      printk("AGNUS_PAL ");
+      break;
+    case 0x10:
+      AMIGAHW_SET(AGNUS_NTSC);
+      printk("AGNUS_NTSC ");
+      break;
+    case 0x20:
+    case 0x21:
+      AMIGAHW_SET(AGNUS_HR_PAL);
+      printk("AGNUS_HR_PAL ");
+      break;
+    case 0x30:
+    case 0x31:
+      AMIGAHW_SET(AGNUS_HR_NTSC);
+      printk("AGNUS_HR_NTSC ");
+      break;
+    case 0x22:
+    case 0x23:
+      AMIGAHW_SET(ALICE_PAL);
+      printk("ALICE_PAL ");
+      break;
+    case 0x32:
+    case 0x33:
+      AMIGAHW_SET(ALICE_NTSC);
+      printk("ALICE_NTSC ");
+      break;
+    }
+    AMIGAHW_SET(ZORRO);
+    printk("ZORRO ");
+    break;
+
+  case AMI_DRACO:
+    panic("No support for Draco yet");
+ 
+  default:
+    panic("Unknown Amiga Model");
+  }
+  printk("\n");
+ 
+  mach_sched_init      = amiga_sched_init;
+  mach_keyb_init       = amiga_keyb_init;
+  mach_kbdrate         = amiga_kbdrate;
+  mach_init_INTS       = amiga_init_INTS;
+  mach_add_isr         = amiga_add_isr;
+#if 0 /* ++1.3++ */
+  mach_remove_isr      = amiga_remove_isr;
+  mach_enable_irq      = amiga_enable_irq;
+  mach_disable_irq     = amiga_disable_irq;
+#endif
+  mach_get_irq_list    = amiga_get_irq_list;
+  mach_gettimeoffset   = amiga_gettimeoffset;
+  if (AMIGAHW_PRESENT(A3000_CLK)){
+    mach_gettod  = a3000_gettod;
+    mach_max_dma_address = 0xffffffff; /*
+					* default MAX_DMA 0xffffffff
+					* on Z3 machines - we should
+					* consider adding something
+					* like a dma_mask in kmalloc
+					* later on, so people using Z2
+					* boards in Z3 machines won't
+					* get into trouble - Jes
+					*/
+  }
+  else{ /* if (AMIGAHW_PRESENT(A2000_CLK)) */
+    mach_gettod  = a2000_gettod;
+    mach_max_dma_address = 0x00ffffff; /*
+					* default MAX_DMA 0x00ffffff
+					* on Z2 machines.
+					*/
+  }
+  mach_hwclk           = amiga_hwclk;
+  mach_set_clock_mmss  = amiga_set_clock_mmss;
+  mach_check_partition = amiga_check_partition;
+  mach_mksound         = amiga_mksound;
+#ifdef CONFIG_BLK_DEV_FD
+  mach_floppy_init     = amiga_floppy_init;
+  mach_floppy_setup    = amiga_floppy_setup;
+#endif
+  mach_reset           = amiga_reset;
+  waitbut              = amiga_waitbut;
+  conswitchp           = &fb_con;
+  mach_fb_init         = amiga_fb_init;
+  mach_debug_init      = amiga_debug_init;
+  mach_video_setup     = amiga_video_setup;
+  kd_mksound           = amiga_mksound;
+
+  /* Fill in the clock values (based on the 700 kHz E-Clock) */
+  amiga_masterclock = 40*amiga_eclock;	/* 28 MHz */
+  amiga_colorclock = 5*amiga_eclock;		/* 3.5 MHz */
+
+  /* clear all DMA bits */
+  custom.dmacon = DMAF_ALL;
+  /* ensure that the DMA master bit is set */
+  custom.dmacon = DMAF_SETCLR | DMAF_MASTER;
+
+  /* initialize chipram allocator */
+  amiga_chip_init ();
+
+  /* initialize only once here, not every time the debug level is raised */
+  if (!strcmp( m68k_debug_device, "mem" ))
+    ami_savekmsg_init();
+
+  /*
+   * if it is an A3000, set the magic bit that forces
+   * a hard rekick
+   */
+  if (AMIGAHW_PRESENT(MAGIC_REKICK))
+    *(u_char *)ZTWO_VADDR(0xde0002) |= 0x80;
+
+  zorro_init();
+#ifdef CONFIG_ZORRO
+  /*
+   * Identify all known AutoConfig Expansion Devices
+   */
+  zorro_identify();
+#endif /* CONFIG_ZORRO */
+}
+
+extern long time_finetune;	/* from kernel/sched.c */
+
+static unsigned short jiffy_ticks;
+
+#if 1 /* ++1.3++ */
+static void timer_wrapper( int irq, struct pt_regs *fp, void *otimerf )
+ {
+   unsigned short flags, old_flags;
+
+   ciab.icr = 0x01;
+
+   save_flags(flags);
+   old_flags = (flags & ~0x0700) | (fp->sr & 0x0700);
+   
+   restore_flags(old_flags);
+
+   (*(isrfunc)otimerf)( irq, fp, NULL );
+
+   restore_flags(flags);
+   ciab.icr = 0x81;
+}
+#endif
+
+void amiga_sched_init (isrfunc timer_routine)
+{
+
+#if 0 /* XXX */ /* I think finetune was removed by the 1.3.29 patch */
+    double finetune;
+#endif
+
+    jiffy_ticks = (amiga_eclock+50)/100;
+#if 0 /* XXX */
+    finetune = (jiffy_ticks-amiga_eclock/HZ)/amiga_eclock*1000000*(1<<24);
+    time_finetune = finetune+0.5;
+#endif
+
+    ciab.cra &= 0xC0;	 /* turn off timer A, continous mode, from Eclk */
+    ciab.talo = jiffy_ticks % 256;
+    ciab.tahi = jiffy_ticks / 256;
+    /* CIA interrupts when counter underflows, so adjust ticks by 1 */
+    jiffy_ticks -= 1;
+
+    /* install interrupt service routine for CIAB Timer A */
+    /*
+     * Please don't change this to use ciaa, as it interfers with the
+     * SCSI code. We'll have to take a look at this later
+     */
+#if 0
+    add_isr (IRQ_AMIGA_CIAB_TA, timer_routine, 0, NULL, "timer");
+#else
+    add_isr (IRQ_AMIGA_CIAB_TA, timer_wrapper, 0, timer_routine, "timer");
+#endif
+    /* start timer */
+    ciab.cra |= 0x01;
+}
+
+#define TICK_SIZE 10000
+
+/* This is always executed with interrupts disabled.  */
+unsigned long amiga_gettimeoffset (void)
+{
+    unsigned short hi, lo, hi2;
+    unsigned long ticks, offset = 0;
+
+    /* read CIA A timer A current value */
+    hi	= ciab.tahi;
+    lo	= ciab.talo;
+    hi2 = ciab.tahi;
+
+    if (hi != hi2) {
+	lo = ciab.talo;
+	hi = hi2;
+    }
+
+    ticks = hi << 8 | lo;
+
+#if 0 /* XXX */
+/* reading the ICR clears all interrupts.  bad idea! */
+      if (ticks > jiffy_ticks - jiffy_ticks / 100)
+	/* check for pending interrupt */
+	if (ciab.icr & CIA_ICR_TA)
+	  offset = 10000;
+#endif
+
+    ticks = (jiffy_ticks-1) - ticks;
+    ticks = (10000 * ticks) / jiffy_ticks;
+
+    return ticks + offset;
+}
+
+void a3000_gettod (int *yearp, int *monp, int *dayp,
+		   int *hourp, int *minp, int *secp)
+{
+	volatile struct tod3000 *tod = TOD_3000;
+
+	tod->cntrl1 = TOD3000_CNTRL1_HOLD;
+
+	*secp  = tod->second1 * 10 + tod->second2;
+	*minp  = tod->minute1 * 10 + tod->minute2;
+	*hourp = tod->hour1   * 10 + tod->hour2;
+	*dayp  = tod->day1    * 10 + tod->day2;
+	*monp  = tod->month1  * 10 + tod->month2;
+	*yearp = tod->year1   * 10 + tod->year2;
+
+	tod->cntrl1 = TOD3000_CNTRL1_FREE;
+}
+
+void a2000_gettod (int *yearp, int *monp, int *dayp,
+		   int *hourp, int *minp, int *secp)
+{
+	volatile struct tod2000 *tod = TOD_2000;
+
+	tod->cntrl1 = TOD2000_CNTRL1_HOLD;
+
+	while (tod->cntrl1 & TOD2000_CNTRL1_BUSY)
+		;
+
+	*secp  = tod->second1     * 10 + tod->second2;
+	*minp  = tod->minute1     * 10 + tod->minute2;
+	*hourp = (tod->hour1 & 3) * 10 + tod->hour2;
+	*dayp  = tod->day1        * 10 + tod->day2;
+	*monp  = tod->month1      * 10 + tod->month2;
+	*yearp = tod->year1       * 10 + tod->year2;
+
+	if (!(tod->cntrl3 & TOD2000_CNTRL3_24HMODE))
+		if ((!tod->hour1 & TOD2000_HOUR1_PM) && *hourp == 12)
+			*hourp = 0;
+		else if ((tod->hour1 & TOD2000_HOUR1_PM) && *hourp != 12)
+			*hourp += 12;
+
+	tod->cntrl1 &= ~TOD2000_CNTRL1_HOLD;
+}
+
+int amiga_hwclk(int op, struct hwclk_time *t)
+{
+	if (AMIGAHW_PRESENT(A3000_CLK)) {
+		volatile struct tod3000 *tod = TOD_3000;
+
+		tod->cntrl1 = TOD3000_CNTRL1_HOLD;
+
+		if (!op) { /* read */
+			t->sec  = tod->second1 * 10 + tod->second2;
+			t->min  = tod->minute1 * 10 + tod->minute2;
+			t->hour = tod->hour1   * 10 + tod->hour2;
+			t->day  = tod->day1    * 10 + tod->day2;
+			t->wday = tod->weekday;
+			t->mon  = tod->month1  * 10 + tod->month2 - 1;
+			t->year = tod->year1   * 10 + tod->year2;
+		} else {
+			tod->second1 = t->sec / 10;
+			tod->second2 = t->sec % 10;
+			tod->minute1 = t->min / 10;
+			tod->minute2 = t->min % 10;
+			tod->hour1   = t->hour / 10;
+			tod->hour2   = t->hour % 10;
+			tod->day1    = t->day / 10;
+			tod->day2    = t->day % 10;
+			if (t->wday != -1)
+				tod->weekday = t->wday;
+			tod->month1  = (t->mon + 1) / 10;
+			tod->month2  = (t->mon + 1) % 10;
+			tod->year1   = t->year / 10;
+			tod->year2   = t->year % 10;
+		}
+
+		tod->cntrl1 = TOD3000_CNTRL1_FREE;
+	} else /* if (AMIGAHW_PRESENT(A2000_CLK)) */ {
+		volatile struct tod2000 *tod = TOD_2000;
+
+		tod->cntrl1 = TOD2000_CNTRL1_HOLD;
+	    
+		while (tod->cntrl1 & TOD2000_CNTRL1_BUSY)
+			;
+
+		if (!op) { /* read */
+			t->sec  = tod->second1     * 10 + tod->second2;
+			t->min  = tod->minute1     * 10 + tod->minute2;
+			t->hour = (tod->hour1 & 3) * 10 + tod->hour2;
+			t->day  = tod->day1        * 10 + tod->day2;
+			t->wday = tod->weekday;
+			t->mon  = tod->month1      * 10 + tod->month2 - 1;
+			t->year = tod->year1       * 10 + tod->year2;
+
+			if (!(tod->cntrl3 & TOD2000_CNTRL3_24HMODE))
+				if ((!tod->hour1 & TOD2000_HOUR1_PM) && t->hour == 12)
+					t->hour = 0;
+				else if ((tod->hour1 & TOD2000_HOUR1_PM) && t->hour != 12)
+					t->hour += 12;
+		} else {
+			tod->second1 = t->sec / 10;
+			tod->second2 = t->sec % 10;
+			tod->minute1 = t->min / 10;
+			tod->minute2 = t->min % 10;
+			if (tod->cntrl3 & TOD2000_CNTRL3_24HMODE)
+				tod->hour1 = t->hour / 10;
+			else if (t->hour >= 12)
+				tod->hour1 = TOD2000_HOUR1_PM +
+					(t->hour - 12) / 10;
+			else
+				tod->hour1 = t->hour / 10;
+			tod->hour2   = t->hour % 10;
+			tod->day1    = t->day / 10;
+			tod->day2    = t->day % 10;
+			if (t->wday != -1)
+				tod->weekday = t->wday;
+			tod->month1  = (t->mon + 1) / 10;
+			tod->month2  = (t->mon + 1) % 10;
+			tod->year1   = t->year / 10;
+			tod->year2   = t->year % 10;
+		}
+
+		tod->cntrl1 &= ~TOD2000_CNTRL1_HOLD;
+	}
+
+	return 0;
+}
+
+int amiga_set_clock_mmss (unsigned long nowtime)
+{
+	short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60;
+
+	if (AMIGAHW_PRESENT(A3000_CLK)) {
+		volatile struct tod3000 *tod = TOD_3000;
+
+		tod->cntrl1 = TOD3000_CNTRL1_HOLD;
+
+		tod->second1 = real_seconds / 10;
+		tod->second2 = real_seconds % 10;
+		tod->minute1 = real_minutes / 10;
+		tod->minute2 = real_minutes % 10;
+		
+		tod->cntrl1 = TOD3000_CNTRL1_FREE;
+	} else /* if (AMIGAHW_PRESENT(A2000_CLK)) */ {
+		volatile struct tod2000 *tod = TOD_2000;
+
+		tod->cntrl1 = TOD2000_CNTRL1_HOLD;
+	    
+		while (tod->cntrl1 & TOD2000_CNTRL1_BUSY)
+			;
+
+		tod->second1 = real_seconds / 10;
+		tod->second2 = real_seconds % 10;
+		tod->minute1 = real_minutes / 10;
+		tod->minute2 = real_minutes % 10;
+
+		tod->cntrl1 &= ~TOD2000_CNTRL1_HOLD;
+	}
+
+	return 0;
+}
+
+void amiga_waitbut (void)
+{
+    int i;
+
+    while (1) {
+	while (ciaa.pra & 0x40);
+
+	/* debounce */
+	for (i = 0; i < 1000; i++);
+
+	if (!(ciaa.pra & 0x40))
+	    break;
+    }
+
+    /* wait for button up */
+    while (1) {
+	while (!(ciaa.pra & 0x40));
+
+	/* debounce */
+	for (i = 0; i < 1000; i++);
+
+	if (ciaa.pra & 0x40)
+	    break;
+    }
+}
+
+void ami_serial_print (const char *str)
+{
+    while (*str) {
+        if (*str == '\n') {
+            custom.serdat = (unsigned char)'\r' | 0x100;
+            while (!(custom.serdatr & 0x2000))
+                ;
+        }
+        custom.serdat = (unsigned char)*str++ | 0x100;
+        while (!(custom.serdatr & 0x2000))
+            ;
+    }
+}
+
+void amiga_debug_init (void)
+{
+    extern void (*debug_print_proc)(const char *);
+
+    if (!strcmp( m68k_debug_device, "ser" )) {
+        /* no initialization required (?) */
+        debug_print_proc = ami_serial_print;
+    } else if (!strcmp( m68k_debug_device, "mem" )) {
+        /* already initialized by config_amiga() (needed only once) */
+        debug_print_proc = ami_mem_print;
+    }
+}
+
+void dbprintf(const char *fmt , ...)
+{
+	static char buf[1024];
+	va_list args;
+	extern void console_print (const char *str);
+	extern int vsprintf(char * buf, const char * fmt, va_list args);
+
+	va_start(args, fmt);
+	vsprintf(buf, fmt, args);
+	va_end(args);
+
+	console_print (buf);
+}
+
+NORET_TYPE void amiga_reset( void )
+    ATTRIB_NORET;
+
+void amiga_reset (void)
+{
+  unsigned long jmp_addr040 = VTOP(&&jmp_addr_label040);
+  unsigned long jmp_addr = VTOP(&&jmp_addr_label);
+
+  cli();
+  if (m68k_is040or060)
+    /* Setup transparent translation registers for mapping
+     * of 16 MB kernel segment before disabling translation
+     */
+    __asm__ __volatile__
+      ("movel    %0,%/d0\n\t"
+       "andl     #0xff000000,%/d0\n\t"
+       "orw      #0xe020,%/d0\n\t"   /* map 16 MB, enable, cacheable */
+       ".long    0x4e7b0004\n\t"   /* movec d0,itt0 */
+       ".long    0x4e7b0006\n\t"   /* movec d0,dtt0 */
+       "jmp      %0@\n\t"
+       : /* no outputs */
+       : "a" (jmp_addr040));
+  else
+    /* for 680[23]0, just disable translation and jump to the physical
+     * address of the label
+     */
+    __asm__ __volatile__
+      ("pmove  %/tc,%@\n\t"
+       "bclr   #7,%@\n\t"
+       "pmove  %@,%/tc\n\t"
+       "jmp    %0@\n\t"
+       : /* no outputs */
+       : "a" (jmp_addr));
+ jmp_addr_label040:
+  /* disable translation on '040 now */
+  __asm__ __volatile__    
+    ("moveq #0,%/d0\n\t"
+     ".long 0x4e7b0003\n\t"         /* movec d0,tc; disable MMU */
+     : /* no outputs */
+     : /* no inputs */
+     : "d0");
+
+ jmp_addr_label:
+  /* pickup reset address from AmigaOS ROM, reset devices and jump
+   * to reset address
+   */
+  __asm__ __volatile__
+    ("movew #0x2700,%/sr\n\t"
+     "leal  0x01000000,%/a0\n\t"
+     "subl  %/a0@(-0x14),%/a0\n\t"
+     "movel %/a0@(4),%/a0\n\t"
+     "subql #2,%/a0\n\t"
+     "bra   1f\n\t"
+     /* align on a longword boundary */
+     __ALIGN_STR "\n"
+     "1:\n\t"
+     "reset\n\t"
+     "jmp   %/a0@" : /* Just that gcc scans it for % escapes */ );
+  
+  for (;;);
+
+}
+
+extern void *amiga_chip_alloc(long size);
+
+
+#define SAVEKMSG_MAXMEM		128*1024
+
+
+#define SAVEKMSG_MAGIC1		0x53415645	/* 'SAVE' */
+#define SAVEKMSG_MAGIC2		0x4B4D5347	/* 'KMSG' */
+
+struct savekmsg {
+    u_long magic1;		/* SAVEKMSG_MAGIC1 */
+    u_long magic2;		/* SAVEKMSG_MAGIC2 */
+    u_long magicptr;		/* address of magic1 */
+    u_long size;
+    char data[0];
+};
+
+static struct savekmsg *savekmsg = NULL;
+
+
+static void ami_savekmsg_init(void)
+{
+    savekmsg = (struct savekmsg *)amiga_chip_alloc(SAVEKMSG_MAXMEM);
+    savekmsg->magic1 = SAVEKMSG_MAGIC1;
+    savekmsg->magic2 = SAVEKMSG_MAGIC2;
+    savekmsg->magicptr = VTOP(savekmsg);
+    savekmsg->size = 0;
+}
+
+
+static void ami_mem_print(const char *b)
+{
+    int len;
+
+    for (len = 0; b[len]; len++);
+    if (savekmsg->size+len <= SAVEKMSG_MAXMEM) {
+        memcpy(savekmsg->data+savekmsg->size, b, len);
+        savekmsg->size += len;
+    }
+}
+
+
+void amiga_get_model(char *model)
+{
+    strcpy(model, "Amiga ");
+    switch (boot_info.bi_amiga.model) {
+	case AMI_500:
+	    strcat(model, "500");
+	    break;
+	case AMI_500PLUS:
+	    strcat(model, "500+");
+	    break;
+	case AMI_600:
+	    strcat(model, "600");
+	    break;
+	case AMI_1000:
+	    strcat(model, "1000");
+	    break;
+	case AMI_1200:
+	    strcat(model, "1200");
+	    break;
+	case AMI_2000:
+	    strcat(model, "2000");
+	    break;
+	case AMI_2500:
+	    strcat(model, "2500");
+	    break;
+	case AMI_3000:
+	    strcat(model, "3000");
+	    break;
+	case AMI_3000T:
+	    strcat(model, "3000T");
+	    break;
+	case AMI_3000PLUS:
+	    strcat(model, "3000+");
+	    break;
+	case AMI_4000:
+	    strcat(model, "4000");
+	    break;
+	case AMI_4000T:
+	    strcat(model, "4000T");
+	    break;
+	case AMI_CDTV:
+	    strcat(model, "CDTV");
+	    break;
+	case AMI_CD32:
+	    strcat(model, "CD32");
+	    break;
+	case AMI_DRACO:
+	    strcpy(model, "DRACO");
+	    break;
+    }
+}
+
+
+int amiga_get_hardware_list(char *buffer)
+{
+    int len = 0;
+
+    if (AMIGAHW_PRESENT(CHIP_RAM))
+	len += sprintf(buffer+len, "Chip RAM:\t%ldK\n",
+		       boot_info.bi_amiga.chip_size>>10);
+    len += sprintf(buffer+len, "PS Freq:\t%dHz\nEClock Freq:\t%ldHz\n",
+		   boot_info.bi_amiga.psfreq, amiga_eclock);
+    if (AMIGAHW_PRESENT(AMI_VIDEO)) {
+	char *type;
+	switch(boot_info.bi_amiga.chipset) {
+	    case CS_OCS:
+		type = "OCS";
+		break;
+	    case CS_ECS:
+		type = "ECS";
+		break;
+	    case CS_AGA:
+		type = "AGA";
+		break;
+	    default:
+		type = "Old or Unknown";
+		break;
+	}
+	len += sprintf(buffer+len, "Graphics:\t%s\n", type);
+    }
+
+#define AMIGAHW_ANNOUNCE(name, str)				\
+    if (AMIGAHW_PRESENT(name))				\
+	len += sprintf (buffer+len, "\t%s\n", str)
+
+    len += sprintf (buffer + len, "Detected hardware:\n");
+
+    AMIGAHW_ANNOUNCE(AMI_VIDEO, "Amiga Video");
+    AMIGAHW_ANNOUNCE(AMI_BLITTER, "Blitter");
+    AMIGAHW_ANNOUNCE(AMBER_FF, "Amber Flicker Fixer");
+    AMIGAHW_ANNOUNCE(AMI_AUDIO, "Amiga Audio");
+    AMIGAHW_ANNOUNCE(AMI_FLOPPY, "Floppy Controller");
+    AMIGAHW_ANNOUNCE(A3000_SCSI, "SCSI Controller WD33C93 (A3000 style)");
+    AMIGAHW_ANNOUNCE(A4000_SCSI, "SCSI Controller NCR53C710 (A4000T style)");
+    AMIGAHW_ANNOUNCE(A1200_IDE, "IDE Interface (A1200 style)");
+    AMIGAHW_ANNOUNCE(A4000_IDE, "IDE Interface (A4000 style)");
+    AMIGAHW_ANNOUNCE(CD_ROM, "Internal CD ROM drive");
+    AMIGAHW_ANNOUNCE(AMI_KEYBOARD, "Keyboard");
+    AMIGAHW_ANNOUNCE(AMI_MOUSE, "Mouse Port");
+    AMIGAHW_ANNOUNCE(AMI_SERIAL, "Serial Port");
+    AMIGAHW_ANNOUNCE(AMI_PARALLEL, "Parallel Port");
+    AMIGAHW_ANNOUNCE(A2000_CLK, "Hardware Clock (A2000 style)");
+    AMIGAHW_ANNOUNCE(A3000_CLK, "Hardware Clock (A3000 style)");
+    AMIGAHW_ANNOUNCE(CHIP_RAM, "Chip RAM");
+    AMIGAHW_ANNOUNCE(PAULA, "Paula 8364");
+    AMIGAHW_ANNOUNCE(DENISE, "Denise 8362");
+    AMIGAHW_ANNOUNCE(DENISE_HR, "Denise 8373");
+    AMIGAHW_ANNOUNCE(LISA, "Lisa 8375");
+    AMIGAHW_ANNOUNCE(AGNUS_PAL, "Normal/Fat PAL Agnus 8367/8371");
+    AMIGAHW_ANNOUNCE(AGNUS_NTSC, "Normal/Fat NTSC Agnus 8361/8370");
+    AMIGAHW_ANNOUNCE(AGNUS_HR_PAL, "Fat Hires PAL Agnus 8372");
+    AMIGAHW_ANNOUNCE(AGNUS_HR_NTSC, "Fat Hires NTSC Agnus 8372");
+    AMIGAHW_ANNOUNCE(ALICE_PAL, "PAL Alice 8374");
+    AMIGAHW_ANNOUNCE(ALICE_NTSC, "NTSC Alice 8374");
+    AMIGAHW_ANNOUNCE(MAGIC_REKICK, "Magic Hard Rekick");
+    if (AMIGAHW_PRESENT(ZORRO))
+	len += sprintf(buffer+len, "\tZorro AutoConfig: %d Expansion Device%s\n",
+		       boot_info.bi_amiga.num_autocon,
+		       boot_info.bi_amiga.num_autocon == 1 ? "" : "s");
+
+    return(len);
+}
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/amiga/ksyms.c linux/arch/m68k/amiga/ksyms.c
--- v1.3.93/linux/arch/m68k/amiga/ksyms.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/amiga/ksyms.c	Thu Apr 11 02:26:52 1996
@@ -0,0 +1,20 @@
+#include <linux/module.h>
+
+static struct symbol_table mach_amiga_symbol_table = {
+#include <linux/symtab_begin.h>
+
+  /*
+   * Add things here when you find the need for it.
+   */
+
+  /* examble
+  X(something_you_need),
+  */
+
+#include <linux/symtab_end.h>
+};
+
+void mach_amiga_syms_export(void)
+{
+	register_symtab(&mach_amiga_symbol_table);
+}
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/amiga/zorro.c linux/arch/m68k/amiga/zorro.c
--- v1.3.93/linux/arch/m68k/amiga/zorro.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/amiga/zorro.c	Wed Mar 20 20:04:17 1996
@@ -0,0 +1,668 @@
+/*
+ *    linux/arch/m68k/amiga/zorro.c
+ *
+ *    Copyright (C) 1995 Geert Uytterhoeven
+ *
+ *    This file is subject to the terms and conditions of the GNU General Public
+ *    License.  See the file README.legal in the main directory of this archive
+ *    for more details.
+ */
+
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <asm/bitops.h>
+#include <asm/amigahw.h>
+#include <asm/bootinfo.h>
+#include <asm/zorro.h>
+
+
+#ifdef CONFIG_ZORRO
+
+   /*
+    *    Zorro Expansion Device Manufacturers and Products
+    */
+
+struct Manufacturer {
+   char *Name;
+   u_short ID;
+   u_short NumProd;
+   struct Product *Products;
+};
+
+struct Product {
+   char *Name;
+   u_char ID;
+};
+
+struct GVP_Product {
+   char *Name;
+   enum GVP_ident ID;
+};
+
+
+   /*
+    *    Macro's to make life easier
+    */
+
+#define BEGIN_PROD(id) static struct Product Prod_##id[] = {
+#define PROD(name, id) \
+   { name, PROD_##id },
+
+#define BEGIN_GVP_PROD static struct GVP_Product Ext_Prod_GVP[] = {
+#define GVP_PROD(name, id) \
+   { name, GVP_##id },
+
+#define BEGIN_MANUF static struct Manufacturer Manufacturers[] = {
+#define MANUF(name, id) \
+   { name, MANUF_##id, sizeof(Prod_##id)/sizeof(struct Product), Prod_##id },
+
+#define END };
+
+
+   /*
+    *    Known Zorro Expansion Devices
+    *
+    *    Warning: Make sure the Manufacturer and Product names are not too
+    *             long (max. 80 characters per board identification line)
+    */
+
+BEGIN_PROD(MEMPHIS)
+   PROD("Stormbringer", STORMBRINGER)
+END
+
+BEGIN_PROD(COMMODORE2)
+   PROD("A2088 Bridgeboard", A2088)
+   PROD("A2386-SX Bridgeboard", A2386SX)
+END
+
+BEGIN_PROD(COMMODORE)
+   PROD("A2090/A2090A HD Controller", A2090A)
+   PROD("A590 SCSI Controller", A590)
+   PROD("A2091 SCSI Controller", A2091)
+   PROD("A2090B 2090 Autoboot Card", A2090B)
+   PROD("A2060 Arcnet Card", ARCNET)
+   PROD("A2052/58.RAM | 590/2091.RAM", CBMRAM)
+   PROD("A560 Memory Module", A560RAM)
+   PROD("A2232 Serial Prototype", A2232PROTO)
+   PROD("A2232 Serial Production", A2232)
+   PROD("A2620 68020/RAM Card", A2620)
+   PROD("A2630 68030/RAM Card", A2630)
+   PROD("A4091 SCSI Controller", A4091)
+   PROD("Romulator Card", ROMULATOR)
+   PROD("A3000 Test Fixture", A3000TESTFIX)
+   PROD("A2065 Ethernet Card", A2065)
+END
+
+BEGIN_PROD(CARDCO)
+   PROD("Cardco A2410 Hires Graphics card", CC_A2410)
+END
+
+BEGIN_PROD(MICROBOTICS)
+   PROD("VXL-30 Turbo Board", VXL_30)
+END
+
+BEGIN_PROD(ASDG)
+   PROD("Lan Rover Ethernet", LAN_ROVER)
+   PROD("Dual Serial Card", ASDG_DUAL_SERIAL)
+END
+
+BEGIN_PROD(UNIV_OF_LOWELL)
+   PROD("A2410 Hires Graphics Card", A2410)
+END
+
+BEGIN_PROD(AMERISTAR)
+   PROD("A2065 Ethernet Card", AMERISTAR2065)
+   PROD("A560 Arcnet Card", A560)
+   PROD("A4066 Ethernet Card", A4066)
+END
+
+BEGIN_PROD(SUPRA)
+   PROD("Wordsync SCSI Controller", WORDSYNC)
+   PROD("Wordsync II SCSI Controller", WORDSYNC_II)
+   PROD("2400 Modem", SUPRA_2400MODEM)
+END
+
+BEGIN_PROD(CSA)
+   PROD("Magnum 40 SCSI Controller", MAGNUM)
+   PROD("12 Gauge SCSI Controller", 12GAUGE)
+END
+
+BEGIN_PROD(POWER_COMPUTING)
+   PROD("Viper II Turbo Board (DKB 1240)", DKB_1240)
+END
+
+BEGIN_PROD(GVP)
+   PROD("Generic GVP product", GVP)
+   PROD("Series II SCSI Controller", GVPIISCSI)
+   PROD("Series II SCSI Controller", GVPIISCSI_2)
+   PROD("Series II RAM", GVPIIRAM)
+   PROD("GFORCE 040 with SCSI Controller", GFORCE_040_SCSI)
+   PROD("IV-24 Graphics Board", GVPIV_24)
+/*
+   PROD("I/O Extender", GVPIO_EXT)
+*/
+END
+
+BEGIN_GVP_PROD
+   GVP_PROD("GFORCE 040", GFORCE_040)
+   GVP_PROD("GFORCE 040 with SCSI controller", GFORCE_040_SCSI)
+   GVP_PROD("A1291 SCSI controller", A1291_SCSI)
+   GVP_PROD("COMBO 030 R4", COMBO_R4)
+   GVP_PROD("COMBO 030 R4 with SCSI controller", COMBO_R4_SCSI)
+   GVP_PROD("Phone Pak", PHONEPAK)
+   GVP_PROD("IO-Extender", IOEXT)
+   GVP_PROD("GFORCE 030", GFORCE_030)
+   GVP_PROD("GFORCE 030 with SCSI controller", GFORCE_030_SCSI)
+   GVP_PROD("A530", A530)
+   GVP_PROD("A530 with SCSI", A530_SCSI)
+   GVP_PROD("COMBO 030 R3", COMBO_R3)
+   GVP_PROD("COMBO 030 R3 with SCSI controller", COMBO_R3_SCSI)
+   GVP_PROD("SERIES-II SCSI controller", SERIESII)
+END
+
+BEGIN_PROD(PPI)
+   PROD("Mercury Turbo Board", MERCURY)
+   PROD("PP&S A3000 68040 Turbo Board", PPS_A3000_040)
+   PROD("PP&S A2000 68040 Turbo Board", PPS_A2000_040)
+   PROD("Zeus SCSI Controller", ZEUS)
+   PROD("PP&S A500 68040 Turbo Board", PPS_A500_040)
+END
+
+BEGIN_PROD(BSC)
+   PROD("ALF 3 SCSI Controller", ALF_3_SCSI)
+END
+
+BEGIN_PROD(C_LTD)
+   PROD("Kronos SCSI Controller", KRONOS_SCSI)
+END
+
+BEGIN_PROD(JOCHHEIM)
+   PROD("Jochheim RAM", JOCHHEIM_RAM)
+END
+
+BEGIN_PROD(CHECKPOINT)
+   PROD("Serial Solution", SERIAL_SOLUTION)
+END
+
+BEGIN_PROD(GOLEM)
+   PROD("Golem SCSI-II Controller", GOLEM_SCSI_II)
+END
+
+BEGIN_PROD(HARDITAL_SYNTHES)
+   PROD("SCSI Controller", HARDITAL_SCSI)
+END
+
+BEGIN_PROD(BSC2)
+   PROD("Oktagon 2008 SCSI Controller", OKTAGON_SCSI)
+   PROD("Tandem", TANDEM)
+   PROD("Oktagon 2008 RAM", OKTAGON_RAM)
+   PROD("Alfa Data MultiFace I", MULTIFACE_I)
+   PROD("Alfa Data MultiFace II", MULTIFACE_II)
+   PROD("Alfa Data MultiFace III", MULTIFACE_III)
+   PROD("ISDN Master", ISDN_MASTER)
+END
+
+BEGIN_PROD(ADV_SYS_SOFT)
+   PROD("Nexus SCSI Controller", NEXUS_SCSI)
+   PROD("Nexus RAM", NEXUS_RAM)
+END
+
+BEGIN_PROD(IVS)
+   PROD("Trumpcard 500 SCSI Controller", TRUMPCARD_500)
+   PROD("Trumpcard SCSI Controller", TRUMPCARD)
+   PROD("Vector SCSI Controller", VECTOR)
+END
+
+BEGIN_PROD(XPERT_PRODEV)
+   PROD("Merlin Graphics Board (RAM)", MERLIN_RAM)
+   PROD("Merlin Graphics Board (REG)", MERLIN_REG)
+END
+
+BEGIN_PROD(HYDRA_SYSTEMS)
+   PROD("Amiganet Board", AMIGANET)
+END
+
+BEGIN_PROD(DIG_MICRONICS)
+   PROD("DMI Resolver Graphics Board", DMI_RESOLVER)
+END
+
+BEGIN_PROD(HELFRICH1)
+   PROD("Rainbow3 Graphics Board", RAINBOW3)
+END
+
+BEGIN_PROD(SW_RESULT_ENTS)
+   PROD("GG2+ Bus Converter", GG2PLUS)
+END
+
+BEGIN_PROD(VILLAGE_TRONIC)
+   PROD("Ariadne Ethernet Card", ARIADNE)
+   PROD("Picasso II Graphics Board (RAM)", PICASSO_II_RAM)
+   PROD("Picasso II Graphics Board (REG)", PICASSO_II_REG)
+END
+
+BEGIN_PROD(UTILITIES_ULTD)
+   PROD("Emplant Deluxe SCSI Controller", EMPLANT_DELUXE)
+   PROD("Emplant Deluxe SCSI Controller", EMPLANT_DELUXE2)
+END
+
+BEGIN_PROD(MTEC)
+   PROD("68030 Turbo Board", MTEC_68030)
+   PROD("T1230/28 Turbo Board", MTEC_T1230)
+END
+
+BEGIN_PROD(GVP2)
+   PROD("Spectrum Graphics Board (RAM)", SPECTRUM_RAM)
+   PROD("Spectrum Graphics Board (REG)", SPECTRUM_REG)
+END
+
+BEGIN_PROD(HELFRICH2)
+   PROD("Piccolo Graphics Board (RAM)", PICCOLO_RAM)
+   PROD("Piccolo Graphics Board (REG)", PICCOLO_REG)
+   PROD("PeggyPlus MPEG Decoder Board", PEGGY_PLUS)
+   PROD("SD64 Graphics Board (RAM)", SD64_RAM)
+   PROD("SD64 Graphics Board (REG)", SD64_REG)
+END
+
+BEGIN_PROD(MACROSYSTEMS)
+   PROD("Warp Engine SCSI Controller", WARP_ENGINE)
+END
+
+BEGIN_PROD(HARMS_PROF)
+   PROD("3500 Turbo board", 3500_TURBO)
+END
+
+BEGIN_PROD(VORTEX)
+   PROD("Golden Gate 80386 Board", GOLDEN_GATE_386)
+   PROD("Golden Gate RAM", GOLDEN_GATE_RAM)
+   PROD("Golden Gate 80486 Board", GOLDEN_GATE_486)
+END
+
+BEGIN_PROD(DATAFLYER)
+   PROD("4000SX SCSI Controller", DATAFLYER_4000SX)
+END
+
+BEGIN_PROD(PHASE5)
+   PROD("FastLane RAM", FASTLANE_RAM)
+   PROD("FastLane/Blizzard 1230-II SCSI Controller", FASTLANE_SCSI)
+   PROD("Blizzard 1230-III Turbo Board", BLIZZARD_1230_III)
+   PROD("Blizzard 1230-IV Turbo Board", BLIZZARD_1230_IV)
+   PROD("CyberVision64 Graphics Board", CYBERVISION)
+END
+
+BEGIN_PROD(APOLLO)
+   PROD("AT-Apollo", AT_APOLLO)
+   PROD("Turbo Board", APOLLO_TURBO)
+END
+
+BEGIN_PROD(UWE_GERLACH)
+   PROD("RAM/ROM", UG_RAM_ROM)
+END
+
+BEGIN_PROD(MACROSYSTEMS2)
+   PROD("Maestro", MAESTRO)
+   PROD("VLab", VLAB)
+   PROD("Maestro Pro", MAESTRO_PRO)
+   PROD("Retina Z2 Graphics Board", RETINA_Z2)
+   PROD("MultiEvolution", MULTI_EVOLUTION)
+   PROD("Retina Z3 Graphics Board", RETINA_Z3)
+END
+
+BEGIN_MANUF
+   MANUF("Memphis", MEMPHIS)
+   MANUF("Commodore", COMMODORE2)
+   MANUF("Commodore", COMMODORE)
+   MANUF("Cardco", CARDCO)
+   MANUF("MicroBotics", MICROBOTICS)
+   MANUF("ASDG", ASDG)
+   MANUF("University of Lowell", UNIV_OF_LOWELL)
+   MANUF("Ameristar", AMERISTAR)
+   MANUF("Supra", SUPRA)
+   MANUF("CSA", CSA)
+   MANUF("Power Computing", POWER_COMPUTING)
+   MANUF("Great Valley Products", GVP)
+   MANUF("Progressive Peripherals", PPI)
+   MANUF("BSC", BSC)
+   MANUF("C Ltd.", C_LTD)
+   MANUF("Jochheim", JOCHHEIM)
+   MANUF("Checkpoint Technologies", CHECKPOINT)
+   MANUF("Golem", GOLEM)
+   MANUF("Hardital Synthesis", HARDITAL_SYNTHES)
+   MANUF("BSC", BSC2)
+   MANUF("Advanced Systems & Software", ADV_SYS_SOFT)
+   MANUF("IVS", IVS)
+   MANUF("XPert/ProDev", XPERT_PRODEV)
+   MANUF("Hydra Systems", HYDRA_SYSTEMS)
+   MANUF("Digital Micronics", DIG_MICRONICS)
+   MANUF("Helfrich", HELFRICH1)
+   MANUF("Software Result Enterprises", SW_RESULT_ENTS)
+   MANUF("Village Tronic", VILLAGE_TRONIC)
+   MANUF("Utilities Unlimited", UTILITIES_ULTD)
+   MANUF("MTEC", MTEC)
+   MANUF("Great Valley Products", GVP2)
+   MANUF("Helfrich", HELFRICH2)
+   MANUF("MacroSystems", MACROSYSTEMS)
+   MANUF("Harms Professional", HARMS_PROF)
+   MANUF("Vortex", VORTEX)
+   MANUF("DataFlyer", DATAFLYER)
+   MANUF("Phase5", PHASE5)
+   MANUF("Apollo", APOLLO)
+   MANUF("Uwe Gerlach", UWE_GERLACH)
+   MANUF("MacroSystems", MACROSYSTEMS2)
+END
+
+#define NUM_MANUF (sizeof(Manufacturers)/sizeof(struct Manufacturer))
+#define NUM_GVP_PROD (sizeof(Ext_Prod_GVP)/sizeof(struct GVP_Product))
+
+#endif /* CONFIG_ZORRO */
+
+
+   /*
+    *    Configured Expansion Devices
+    */
+
+static u_long BoardPartFlags[NUM_AUTO] = { 0, };
+
+   
+   /*
+    *    Find the key for the next unconfigured expansion device of a specific
+    *    type.
+    *
+    *    Part is a device specific number (0 <= part <= 31) to allow for the
+    *    independent configuration of independent parts of an expansion board.
+    *    Thanks to Jes Soerensen for this idea!
+    *
+    *    Index is used to specify the first board in the autocon list
+    *    to be tested. It was inserted in order to solve the problem
+    *    with the GVP boards that uses the same product code, but
+    *    it should help if there are other companies uses the same
+    *    method as GVP. Drivers for boards which are not using this
+    *    method does not need to think of this - just set index = 0.
+    *    
+    *    Example:
+    *
+    *       while ((key = zorro_find(MY_MANUF, MY_PROD, MY_PART, 0))) {
+    *          cd = zorro_get_board(key);
+    *          initialise_this_board;
+    *          zorro_config_board(key, MY_PART);
+    *       }
+    */
+
+int zorro_find(int manuf, int prod, int part, int index)
+{
+   int key;
+   struct ConfigDev *cd;
+  
+   if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(ZORRO))
+      return(0);
+
+   if ((part < 0) || (part > 31)) {
+      printk("zorro_find: bad part %d\n", part);
+      return(0);
+   }
+
+   for (key = index + 1; key <= boot_info.bi_amiga.num_autocon; key++) {
+      cd = &boot_info.bi_amiga.autocon[key-1];
+      if ((cd->cd_Rom.er_Manufacturer == manuf) &&
+          (cd->cd_Rom.er_Product == prod) &&
+          !(BoardPartFlags[key-1] & (1<<part)))
+         break;
+   }
+   return(key <= boot_info.bi_amiga.num_autocon ? key : 0);
+}
+
+
+   /*
+    *    Get the board for a specified key
+    */
+
+struct ConfigDev *zorro_get_board(int key)
+{
+   struct ConfigDev *cd = NULL;
+
+   if ((key < 1) || (key > boot_info.bi_amiga.num_autocon))
+      printk("zorro_get_board: bad key %d\n", key);
+   else
+      cd = &boot_info.bi_amiga.autocon[key-1];
+
+   return(cd);
+}
+
+
+   /*
+    *    Mark a part of a board as configured
+    */
+
+void zorro_config_board(int key, int part)
+{
+   if ((key < 1) || (key > boot_info.bi_amiga.num_autocon))
+      printk("zorro_config_board: bad key %d\n", key);
+   else if ((part < 0) || (part > 31))
+      printk("zorro_config_board: bad part %d\n", part);
+   else
+      BoardPartFlags[key-1] |= 1<<part;
+}
+
+
+   /*
+    *    Mark a part of a board as unconfigured
+    *
+    *    This function is mainly intended for the unloading of LKMs
+    */
+
+void zorro_unconfig_board(int key, int part)
+{
+   if ((key < 1) || (key > boot_info.bi_amiga.num_autocon))
+      printk("zorro_unconfig_board: bad key %d\n", key);
+   else if ((part < 0) || (part > 31))
+      printk("zorro_unconfig_board: bad part %d\n", part);
+   else
+      BoardPartFlags[key-1] &= ~(1<<part);
+}
+
+
+#ifdef CONFIG_ZORRO
+
+   /*
+    *    Identify an AutoConfig Expansion Device
+    *
+    *    If the board was configured by a Linux/m68k driver, an asterisk will
+    *    be printed before the board address (except for unknown and `Hacker
+    *    Test' boards).
+    */
+
+static int identify(int devnum, char *buf)
+{
+   struct ConfigDev *cd;
+   int manuf, prod;
+   u_long addr, size;
+   char *manufname, *prodname, *is_mem;
+   char zorro, mag, configured;
+   int identified = 0;
+   int i, j, k, len = 0;
+   enum GVP_ident epc;
+
+   cd = &boot_info.bi_amiga.autocon[devnum];
+   manuf = cd->cd_Rom.er_Manufacturer;
+   prod = cd->cd_Rom.er_Product;
+   addr = (u_long)cd->cd_BoardAddr;
+   size = cd->cd_BoardSize;
+   configured = BoardPartFlags[devnum] ? '*' : ' ';
+   manufname = prodname = "<UNKNOWN>";
+
+   for (i = 0; i < NUM_MANUF; i++)
+      if (Manufacturers[i].ID == manuf) {
+         manufname = Manufacturers[i].Name;
+         for (j = 0; j < Manufacturers[i].NumProd; j++)
+            if (Manufacturers[i].Products[j].ID == prod)
+               if ((manuf != MANUF_GVP) || (prod != PROD_GVP)) {
+                  prodname = Manufacturers[i].Products[j].Name;
+                  identified = 1;
+                  break;
+               } else {
+                  epc = *(enum GVP_ident *)ZTWO_VADDR(addr+0x8000) &
+                        GVP_EPCMASK;
+                  for (k = 0; k < NUM_GVP_PROD; k++)
+                     if (Ext_Prod_GVP[k].ID == epc) {
+                        prodname = Ext_Prod_GVP[k].Name;
+                        identified = 1;
+                        break;
+                     }
+               }
+         break;
+      }
+
+   switch (cd->cd_Rom.er_Type & ERT_TYPEMASK) {
+      case ERT_ZORROII:
+         zorro = '2';
+         break;
+      case ERT_ZORROIII:
+         zorro = '3';
+         break;
+      default:
+         zorro = '?';
+         break;
+   }
+   if (size & 0xfffff) {
+      size >>= 10;
+      mag = 'K';
+   } else {
+      size >>= 20;
+      mag = 'M';
+   }
+   if (cd->cd_Rom.er_Type & ERTF_MEMLIST)
+      is_mem = " MEM";
+   else
+      is_mem = "";
+
+   if (identified)
+      len = sprintf(buf, " %c0x%08lx: %s %s (Z%c, %ld%c%s)\n", configured, addr,
+                    manufname, prodname, zorro, size, mag, is_mem);
+   else if (manuf == MANUF_HACKER)
+      len = sprintf(buf, "  0x%08lx: Hacker Test Board 0x%02x (Z%c, %ld%c%s)\n",
+                    addr, prod, zorro, size, mag, is_mem);
+   else {
+      len = sprintf(buf, "  0x%08lx: [%04x:%02x] made by %s (Z%c, %ld%c%s)\n",
+                    addr, manuf, prod, manufname, zorro, size, mag, is_mem);
+      len += sprintf(buf+len, "  Please report this unknown device to "
+                     "Geert.Uytterhoeven@cs.kuleuven.ac.be\n");
+   }
+   return(len);
+}
+
+
+   /*
+    *    Identify all known AutoConfig Expansion Devices
+    */
+
+void zorro_identify(void)
+{
+   int i;
+   char tmp[160];
+
+   if (!AMIGAHW_PRESENT(ZORRO))
+      return;
+
+   printk("Probing AutoConfig expansion device(s):\n");
+   for (i = 0; i < boot_info.bi_amiga.num_autocon; i++) {
+      identify(i, tmp);
+      printk(tmp);
+   }
+   if (!boot_info.bi_amiga.num_autocon)
+      printk("No AutoConfig expansion devices present.\n");
+}
+
+
+   /*
+    *    Get the list of all AutoConfig Expansion Devices
+    */
+
+int zorro_get_list(char *buffer)
+{
+   int i, j, len = 0;
+   char tmp[160];
+
+   if (MACH_IS_AMIGA && AMIGAHW_PRESENT(ZORRO)) {
+      len = sprintf(buffer, "AutoConfig expansion devices:\n");
+      for (i = 0; i < boot_info.bi_amiga.num_autocon; i++) {
+         j = identify(i, tmp);
+         if (len+j >= 4075) {
+            len += sprintf(buffer+len, "4K limit reached!\n");
+            break;
+         }
+         strcpy(buffer+len, tmp);
+         len += j;
+      }
+   }
+   return(len);
+}
+
+#endif /* CONFIG_ZORRO */
+
+
+   /*
+    *    Bitmask indicating portions of available Zorro II RAM that are unused
+    *    by the system. Every bit represents a 64K chunk, for a maximum of 8MB
+    *    (128 chunks, physical 0x00200000-0x009fffff).
+    *
+    *    If you want to use (= allocate) portions of this RAM, you should clear
+    *    the corresponding bits.
+    *
+    *    Possible uses:
+    *       - z2ram device
+    *       - SCSI DMA bounce buffers
+    */
+
+u_long zorro_unused_z2ram[4] = { 0, 0, 0, 0 };
+
+
+static void mark_region(u_long addr, u_long size, int flag)
+{
+   u_long start, end, chunk;
+
+   if (flag) {
+      start = (addr+Z2RAM_CHUNKMASK) & ~Z2RAM_CHUNKMASK;
+      end = (addr+size) & ~Z2RAM_CHUNKMASK;
+   } else {
+      start = addr & ~Z2RAM_CHUNKMASK;
+      end = (addr+size+Z2RAM_CHUNKMASK) & ~Z2RAM_CHUNKMASK;
+   }
+   if (end <= Z2RAM_START || start >= Z2RAM_END)
+      return;
+   start = start < Z2RAM_START ? 0x00000000 : start-Z2RAM_START;
+   end = end > Z2RAM_END ? Z2RAM_SIZE : end-Z2RAM_START;
+   while (start < end) {
+      chunk = start>>Z2RAM_CHUNKSHIFT;
+      if (flag)
+         set_bit( chunk, zorro_unused_z2ram );
+      else
+         clear_bit( chunk, zorro_unused_z2ram );
+      start += Z2RAM_CHUNKSIZE;
+   }
+}
+
+
+   /*
+    *    Initialization
+    */
+
+void zorro_init(void)
+{
+   int i;
+   struct ConfigDev *cd;
+
+   if (!AMIGAHW_PRESENT(ZORRO))
+      return;
+
+   /* Mark all available Zorro II memory */
+   for (i = 0; i < boot_info.bi_amiga.num_autocon; i++) {
+      cd = &boot_info.bi_amiga.autocon[i];
+      if (cd->cd_Rom.er_Type & ERTF_MEMLIST)
+         mark_region((u_long)cd->cd_BoardAddr, cd->cd_BoardSize, 1);
+   }
+   /* Unmark all used Zorro II memory */
+   for (i = 0; i < boot_info.num_memory; i++)
+      mark_region(boot_info.memory[i].addr, boot_info.memory[i].size, 0);
+}
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/atari/Makefile linux/arch/m68k/atari/Makefile
--- v1.3.93/linux/arch/m68k/atari/Makefile	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/atari/Makefile	Mon Apr  1 22:04:02 1996
@@ -0,0 +1,17 @@
+#
+# Makefile for Linux arch/m68k/atari 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).
+#
+# Note 2! The CFLAGS definitions are now in the main makefile...
+
+EXTRA_CFLAGS := -Wa,-m68030
+
+O_TARGET := atari.o
+O_OBJS	 := config.o atakeyb.o ataints.o \
+            atapart.o stdma.o atasound.o joystick.o stram.o atafb.o
+OX_OBJS = ksyms.o
+
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/atari/atafb.c linux/arch/m68k/atari/atafb.c
--- v1.3.93/linux/arch/m68k/atari/atafb.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/atari/atafb.c	Sat Mar 30 21:06:53 1996
@@ -0,0 +1,3175 @@
+/*
+ * 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 README.legal 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/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/malloc.h>
+#include <linux/delay.h>
+
+#include <asm/segment.h>
+#include <asm/pgtable.h>
+#include <asm/irq.h>
+
+#include <asm/atarihw.h>
+#include <asm/atariints.h>
+#include <asm/bootinfo.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;
+
+#ifdef ATAFB_FALCON
+static int pwrsave = 0;	/* use VESA suspend mode instead of blanking only? */
+#endif
+
+static struct atari_fb_par {
+	unsigned long screen_base;
+	int vyres;
+	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 informations */
+			short mono;
+			short ste_mode;
+			short bpp;
+		} falcon;
+		/* Nothing needed for external mode */
+	} hw;
+} current_par;
+
+/* Don't calculate an own resoltion, 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!
+*/
+
+struct { unsigned char red,green,blue,pad; } MV300_color[256];
+#endif /* ATAFB_EXT */
+
+
+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 NULL then blanking
+ *   is done by setting the CLUT to black. Return != 0 if un-/blanking
+ *   failed due to e.g. video mode which doesn't support it.
+ */
+
+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};
+
+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 */
+};
+
+struct fb_var_screeninfo atari_fb_predefined[] = {
+ 	{ /* 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, 200, 0, 0, 4, 0,   		/* xres-grayscale */
+	  {0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {0, 0, 0}, 	/* red green blue tran*/
+	  0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
+	{ /* st mid */
+	  640, 200, 640, 200, 0, 0, 2, 0,		/* xres-grayscale */
+	  {0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {0, 0, 0}, 	/* red green blue tran*/
+	  0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
+	{ /* st high */
+	  640, 400, 640, 400, 0, 0, 1, 0,		/* xres-grayscale */
+	  {0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {0, 0, 0}, 	/* red green blue tran*/
+	  0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
+	{ /* tt low */
+	  320, 480, 320, 480, 0, 0, 8, 0,		/* xres-grayscale */
+	  {0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {0, 0, 0}, 	/* red green blue tran*/
+	  0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
+	{ /* tt mid */
+	  640, 480, 640, 480, 0, 0, 4, 0,		/* xres-grayscale */
+	  {0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {0, 0, 0}, 	/* red green blue tran*/
+	  0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
+	{ /* tt high */
+	  1280, 960, 1280, 960, 0, 0, 1, 0,		/* xres-grayscale */
+	  {0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {0, 0, 0}, 	/* red green blue tran*/
+	  0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
+	{ /* vga2 */
+	  640, 480, 640, 480, 0, 0, 1, 0,   		/* xres-grayscale */
+	  {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, 	/* red green blue tran*/
+	  0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
+	{ /* vga4 */
+	  640, 480, 640, 480, 0, 0, 2, 0,		/* xres-grayscale */
+	  {0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {0, 0, 0}, 	/* red green blue tran*/
+	  0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
+	{ /* vga16 */
+	  640, 480, 640, 480, 0, 0, 4, 0,		/* xres-grayscale */
+	  {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, 	/* red green blue tran*/
+	  0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
+	{ /* vga256 */
+	  640, 480, 640, 480, 0, 0, 8, 0,		/* xres-grayscale */
+	  {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, 	/* red green blue tran*/
+	  0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
+	{ /* falh2 */
+	  896, 608, 896, 608, 0, 0, 1, 0,		/* xres-grayscale */
+	  {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, 	/* red green blue tran*/
+	  0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
+	{ /* falh16 */
+	  896, 608, 896, 608, 0, 0, 4, 0,		/* xres-grayscale */
+	  {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, 	/* red green blue tran*/
+	  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 }
+};
+
+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;
+	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;
+
+	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 (var->sync & FB_SYNC_EXT)
+		par->hw.tt.sync=0;
+	else
+		par->hw.tt.sync=1;
+	linelen=xres*bpp/8;
+	if ((var->yoffset + yres)*linelen > screen_len && screen_len)
+		return -EINVAL;
+	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)
+		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) */
+	short right, hsync, left;	/* standard timing in clock cycles, not pixel */
+		/* hsync initialized in falcon_detect() */
+	short sync_mask;	/* or-mask for hw.falcon.sync to set this clock */
+	short control_mask; /* dito, for hw.falcon.vid_control */
+}
+f25  = {25175000, 39722, 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 short 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, 4700000, 4000000, 4700000};
+
+
+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;
+	if (par->hw.falcon.mono) {
+		fix->type = FB_TYPE_PACKED_PIXELS;
+		fix->type_aux = 0;
+	}
+	else if (par->hw.falcon.f_shift & 0x100) {
+		fix->type = FB_TYPE_PACKED_PIXELS;
+		fix->type_aux = 0;
+		fix->visual = FB_VISUAL_TRUECOLOR;  /* is this ok or should this be DIRECTCOLOR? */
+	}
+	if (par->hw.falcon.mono)
+		/* no smooth scrolling possible with longword aligned video mem */
+		fix->xpanstep = 32;
+	else
+		fix->xpanstep = 1;
+	fix->ypanstep = 1;
+	fix->ywrapstep = 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 use_default_timing = 0;
+	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_VGA || DontCalcRes) {
+		/* Skip all calculations, VGA multisync only yet */
+		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 < 640x480 */
+	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;
+	else if (yres <= 480)
+		yres = 480;
+
+	/* 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.
+	 *
+	 * 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;
+	/* <=0 : yres_virtual determined by screensize */
+	if (yres_virtual < yres && yres_virtual > 0)
+		yres_virtual = yres;
+
+	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 == 320) ? 2 : 1;
+
+	/* Default values are used for vert./hor. timing if no pixelclock given. */
+	if (var->pixclock == 0)
+		use_default_timing = 1;
+
+#if 0 /* currently unused */
+	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 if (mon_type == F_MON_SC || mon_type == F_MON_TV) {
+		plen = 2 * xstretch;
+		pclock = &f32;
+		hsync_len = 150 / plen;
+		if (yres > 240)
+			interlace = 1;
+		/* TODO set margins */
+	}
+	else
+#endif
+	{	/* F_MON_VGA */
+		if (bpp == 16)
+			xstretch = 2; /* hicolor only double pixel width */
+		if (use_default_timing) {
+			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 {
+#if 0 /* TODO enable this (untested yet) */
+			/* Round down pixelclock */
+			int i; unsigned long pcl=0;
+			for (i=1; i<=4; i*=2) {
+				if (f25.t*i<=var->pixclock && pcl<f25.t*i) {
+					pcl=f25.t*i; pclock=&f25;
+				}
+				if (f32.t*i<=var->pixclock && pcl<f32.t*i) {
+					pcl=f32.t*i; pclock=&f32;
+				}
+				if (fext.t && fext.t*i<=var->pixclock && pcl<fext.t*i) {
+					pcl=fext.t*i; pclock=&fext;
+				}
+			}
+			if (!pcl)
+				return -EINVAL;
+			plen = pcl / pclock->t;
+
+#else
+			if (var->pixclock == f25.t || var->pixclock == 2*f25.t)
+				pclock = &f25;
+			else if (var->pixclock == f32.t || var->pixclock == 2*f32.t)
+				pclock = &f32;
+			else if ((var->pixclock == fext.t || var->pixclock == 2*fext.t) && fext.t) {
+				pclock = &fext;
+			}
+			else
+				return -EINVAL;
+			plen = var->pixclock / pclock->t;
+#endif
+
+			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) {
+				/* # lines in half frame */
+				upper_margin = (upper_margin + 1) / 2;
+				lower_margin = (lower_margin + 1) / 2;
+				vsync_len = (vsync_len + 1) / 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 && 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 ((var->yoffset + yres)*linelen > screen_len && screen_len)
+		return -EINVAL;
+	if (var->yres_virtual * linelen > screen_len && screen_len)
+		return -EINVAL;
+	if (var->yres * linelen > screen_len && screen_len)
+		return -EINVAL;
+	par->vyres = 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->vyres)
+			var->yres_virtual = par->vyres;
+		else
+			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
+		/* cant 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;
+	}
+
+	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, struct pt_regs *fp, void *dummy )
+{
+	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;
+
+		/*f030_sreg[2] = 0;*/
+
+		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;
+
+	if (disp[currcon].var.bits_per_pixel == 1)
+		var->xoffset = up(var->xoffset, 32);
+	par->hw.falcon.xoffset = var->xoffset & 15;
+	par->hw.falcon.line_offset = disp[currcon].var.bits_per_pixel *
+	       	  (disp[currcon].var.xres_virtual - disp[currcon].var.xres) / 16;
+	if (par->hw.falcon.xoffset)
+		par->hw.falcon.line_offset -= disp[currcon].var.bits_per_pixel;
+	xoffset = var->xoffset - par->hw.falcon.xoffset;
+
+	par->screen_base
+		= screen_base + (var->yoffset * disp[currcon].var.xres_virtual +
+				xoffset) * disp[currcon].var.bits_per_pixel / 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 affects usleep()).
+ */
+	if (mon_type == F_MON_SM)	/* this doesn't work on SM124 */
+		return 1;
+	if (blank_mode) {
+		/* disable graphics output (this speeds up the CPU) ... */
+		videl.vdb = current_par.VFT + 1;
+		/* ... and blank all lines */
+		videl.hbe = current_par.HHT + 2;
+		/* VESA suspend mode, switch off HSYNC */
+		if (pwrsave && mon_type == F_MON_VGA)
+			videl.hss = current_par.HHT + 2;
+	}
+	else {
+		videl.vdb = current_par.VDB;
+		videl.hbe = current_par.HBE;
+		videl.hss = current_par.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:
+		vfmin = 50;
+		vfmax = 60;
+		hfmin = 15624;
+		hfmax = 15626;
+		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);
+
+	/* Detectet 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;
+	}
+	fix->xpanstep = 0;
+	if (ATARIHW_PRESENT(EXTD_SHIFTER))
+		fix->ypanstep = 1;
+	else
+		fix->ypanstep = 0;
+	fix->ywrapstep = 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;
+
+	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 (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 ((var->yoffset + yres)*linelen > screen_len && screen_len)
+		return -EINVAL;
+	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)
+		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;
+	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 (var->xoffset)
+		return -EINVAL;
+	par->screen_base
+		= screen_base + (var->yoffset * disp[currcon].var.xres_virtual
+						 * 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
+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
+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
+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
+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 Independant 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};
+
+struct fb_cmap default_16_colors = { 0, 16, red16, green16, blue16, NULL };
+struct fb_cmap default_4_colors = { 0, 4, red4, green4, blue4, NULL };
+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_fs_word(hred, red);
+			put_fs_word(hgreen, green);
+			put_fs_word(hblue, blue);
+			if (transp) put_fs_word(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 {
+			hred=get_fs_word(red);
+			hgreen=get_fs_word(green);
+			hblue=get_fs_word(blue);
+			htransp=(transp)?get_fs_word(transp):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:
+		memcpy_fromfs(to,from,len);
+		return;
+	case 2:
+		memcpy_tofs(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;
+	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,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;
+		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
+		    || 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)
+{
+	int i;
+
+	switch (cmd) {
+#ifdef FBCMD_GET_CURRENTPAR
+	case FBCMD_GET_CURRENTPAR:
+		if ((i = verify_area(VERIFY_WRITE, (void *)arg,
+							 sizeof(struct atari_fb_par))))
+			return i;
+		memcpy_tofs((void *)arg, (void *)&current_par,
+					sizeof(struct atari_fb_par));
+		return 0;
+#endif
+#ifdef FBCMD_SET_CURRENTPAR
+	case FBCMD_SET_CURRENTPAR:
+		if ((i = verify_area(VERIFY_READ, (void *)arg,
+							 sizeof(struct atari_fb_par))))
+			return i;
+		memcpy_fromfs((void *)&current_par, (void *)arg,
+					sizeof(struct atari_fb_par));
+		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;
+}
+
+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);
+}
+
+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;
+			add_isr(IRQ_AUTO_4, falcon_vbl_switcher, IRQ_TYPE_PRIO, NULL,
+					"framebuffer/modeswitch");
+			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 (m68k_is040or060) {
+			/* 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;
+	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 (!strcmp(this_opt, "pwrsave"))
+		pwrsave = 1;
+	else if (!strncmp(this_opt, "eclock:", 7)) {
+		fext.f = simple_strtoul(this_opt+7, NULL, 10);
+		/* external pixelclock in kHz --> ps */
+		fext.t = (2000000000UL/fext.f+1)/2;
+		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 extendet 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 v1.3.93/linux/arch/m68k/atari/atafb.h linux/arch/m68k/atari/atafb.h
--- v1.3.93/linux/arch/m68k/atari/atafb.h	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/atari/atafb.h	Wed Dec 27 22:43:49 1995
@@ -0,0 +1,48 @@
+#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 v1.3.93/linux/arch/m68k/atari/ataints.c linux/arch/m68k/atari/ataints.c
--- v1.3.93/linux/arch/m68k/atari/ataints.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/atari/ataints.c	Sat Apr 13 14:31:00 1996
@@ -0,0 +1,634 @@
+/*
+ * arch/m68k/atari/ataints.c -- Atari Linux interrupt handling code
+ *
+ * 5/2/94 Roman Hodek:
+ *  Added support for TT interrupts; setup for TT SCU (may someone has
+ *  twiddled there and we won't get the right interrupts :-()
+ *
+ *  Major change: The device-independant code in m68k/ints.c didn't know
+ *  about non-autovec ints yet. It hardcoded the number of possible ints to
+ *  7 (IRQ1...IRQ7). But the Atari has lots of non-autovec ints! I made the
+ *  number of possible ints a constant defined in interrupt.h, which is
+ *  47 for the Atari. So we can call add_isr() for all Atari interrupts just
+ *  the normal way. Additionally, all vectors >= 48 are initialized to call
+ *  trap() instead of inthandler(). This must be changed here, too.
+ *
+ * 1995-07-16 Lars Brinkhoff <f93labr@dd.chalmers.se>:
+ *  Corrected a bug in atari_add_isr() which rejected all SCC
+ *  interrupt sources if there were no TT MFP!
+ *
+ * 12/13/95: New interface functions atari_level_triggered_int() and
+ *  atari_register_vme_int() as support for level triggered VME interrupts.
+ *
+ * 02/12/96: (Roman)
+ *  Total rewrite of Atari interrupt handling, for new scheme see comments
+ *  below.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file README.legal in the main directory of this archive
+ * for more details.
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/ptrace.h>
+#include <linux/kernel_stat.h>
+
+#include <asm/system.h>
+#include <asm/traps.h>
+
+#include <asm/atarihw.h>
+#include <asm/atariints.h>
+#include <asm/atari_stdma.h>
+#include <asm/bootinfo.h>
+#include <asm/irq.h>
+
+
+/*
+ * Atari interrupt handling scheme:
+ * --------------------------------
+ * 
+ * All interrupt source have an internal number (defined in
+ * <asm/atariints.h>): Autovector interrupts are 1..7, then follow ST-MFP,
+ * TT-MFP, SCC, and finally VME interrupts. Vector numbers for the latter can
+ * be allocated by atari_register_vme_int(). Currently, all int source numbers
+ * have the IRQ_MACHSPEC bit set, to keep the general int handling functions
+ * in kernel/ints.c from them.
+ *
+ * Each interrupt can be of three types:
+ * 
+ *  - SLOW: The handler runs with all interrupts enabled, except the one it
+ *    was called by (to avoid reentering). This should be the usual method.
+ *    But it is currently possible only for MFP ints, since only the MFP
+ *    offers an easy way to mask interrupts.
+ *
+ *  - FAST: The handler runs with all interrupts disabled. This should be used
+ *    only for really fast handlers, that just do actions immediately
+ *    necessary, and let the rest do a bottom half or task queue.
+ *
+ *  - PRIORITIZED: The handler can be interrupted by higher-level ints
+ *    (greater IPL, no MFP priorities!). This is the method of choice for ints
+ *    which should be slow, but are not from a MFP.
+ *
+ * The feature of more than one handler for one int source is still there, but
+ * only applicable if all handers are of the same type. To not slow down
+ * processing of ints with only one handler by the chaining feature, the list
+ * calling function atari_call_isr_list() is only plugged in at the time the
+ * second handler is registered.
+ *
+ * Implementation notes: For fast-as-possible int handling, there are separate
+ * entry points for each type (slow/fast/prio). The assembler handler calls
+ * the isr directly in the usual case, no C wrapper is involved. In case of
+ * multiple handlers, atari_call_isr_list() is registered as handler and calls
+ * in turn the real isr's. To ease access from assembler level to the isr
+ * function pointer and accompanying data, these two are stored in a separate
+ * array, irq_handler[]. The rest of data (type, name) are put into a second
+ * array, irq_param, that is accessed from C only. For each slow interrupt (32
+ * in all) there are separate handler functions, which makes it possible to
+ * hard-code the MFP register address and value, are necessary to mask the
+ * int. If there'd be only one generic function, lots of calculations would be
+ * needed to determine MFP register and int mask from the vector number :-(
+ *
+ * Furthermore, slow ints may not lower the IPL below its previous value
+ * (before the int happened). This is needed so that an int of class PRIO, on
+ * that this int may be stacked, cannot be reentered. This feature is
+ * implemented as follows: If the stack frame format is 1 (throwaway), the int
+ * is not stacked, and the IPL is anded with 0xfbff, resulting in a new level
+ * 2, which still blocks the HSYNC, but no interrupts of interest. If the
+ * frame format is 0, the int is nested, and the old IPL value can be found in
+ * the sr copy in the frame.
+ */
+
+
+#define	NUM_INT_SOURCES	(8 + NUM_ATARI_SOURCES)
+
+typedef void (*asm_irq_handler)(void);
+
+struct irqhandler {
+	isrfunc	isr;
+	void	*data;
+};
+
+struct irqparam {
+	int type;
+	char *name;
+};
+
+/*
+ * Array with isr's and their parameter data. This array is accessed from low
+ * level assembler code, so an element size of 8 allows usage of index scaling
+ * addressing mode.
+ */
+static struct irqhandler irq_handler[NUM_INT_SOURCES];
+
+/*
+ * This array hold the rest of parameters of int handlers: type
+ * (slow,fast,prio) and the name of the handler. These values are only
+ * accessed from C
+ */
+static struct irqparam irq_param[NUM_INT_SOURCES];
+
+/*
+ * Counter for next free interrupt vector number
+ * (new vectors starting from 0x70 can be allocated by
+ * atari_register_vme_int())
+ */
+static int next_free_vme_vec = VME_SOURCE_BASE;
+
+/* check for valid int number (complex, sigh...) */
+#define	IS_VALID_INTNO(n)											\
+	((n) > 0 &&														\
+	 /* autovec and ST-MFP ok anyway */								\
+	 (((n) < TTMFP_SOURCE_BASE) ||									\
+	  /* TT-MFP ok if present */									\
+	  ((n) >= TTMFP_SOURCE_BASE && (n) < SCC_SOURCE_BASE &&			\
+	   ATARIHW_PRESENT(TT_MFP)) ||									\
+	  /* SCC ok if present and number even */						\
+	  ((n) >= SCC_SOURCE_BASE && (n) < VME_SOURCE_BASE &&			\
+	   !((n) & 1) && ATARIHW_PRESENT(SCC)) ||						\
+	  /* greater numbers ok if less than #registered VME vectors */	\
+	  ((n) >= VME_SOURCE_BASE && (n) < next_free_vme_vec)))
+
+
+/*
+ * Here start the assembler entry points for interrupts
+ */
+
+#define IRQ_NAME(nr) atari_slow_irq_##nr##_handler(void)
+
+#define	MFP_MK_BASE	"0xfa13"
+
+/* This must agree with head.S.  */
+#define ORIG_DO "0x20"
+#define FORMATVEC "0x2E"
+#define SR "0x28"
+#define SAVE_ALL				\
+	"clrl	%%sp@-;"    /* stk_adj */	\
+	"clrl	%%sp@-;"			\
+	"subql	#1,%%sp@;"  /* orig d0 = -1 */	\
+	"movel	%%d0,%%sp@-;" /* d0 */		\
+	"moveml	%%d1-%%d5/%%a0-%%a1,%%sp@-"
+
+#define	BUILD_SLOW_IRQ(n)						   \
+asmlinkage void IRQ_NAME(n);						   \
+/* Dummy function to allow asm with operands.  */			   \
+void atari_slow_irq_##n##_dummy (void) {				   \
+__asm__ (ALIGN_STR "\n"							   \
+SYMBOL_NAME_STR(atari_slow_irq_) #n "_handler:\t"			   \
+	SAVE_ALL "\n"							   \
+"	addql	#1,"SYMBOL_NAME_STR(intr_count)"\n"			   \
+"	andb	#~(1<<(" #n "&7)),"	/* mask this interrupt */	   \
+	"("MFP_MK_BASE"+(((" #n "&8)^8)>>2)+((" #n "&16)<<3)):w\n"	   \
+"	movew	%%sp@("SR"),%%d0\n"	/* get old IPL from stack frame */ \
+"	movew	%%sr,%%d1\n"						   \
+"	andw	#0x0700,%%d0\n"						   \
+"	andw	#0xf8ff,%%d1\n"						   \
+"	orw 	%%d0,%%d1\n"						   \
+"	movew	%%d1,%%sr\n"		/* set IPL = previous value */	   \
+"	addql	#1,%a0\n"						   \
+"	lea	"SYMBOL_NAME_STR(irq_handler)"+("#n"+8)*8,%%a0\n"	   \
+"	movel	%%a0@(4),%%sp@-\n"	/* push handler data */		   \
+"	pea 	%%sp@(4)\n"		/* push addr of frame */	   \
+"	pea 	(" #n "+8):w\n"		/* push int number */		   \
+"	movel	%%a0@,%%a0\n"						   \
+"	jbsr	%%a0@\n"		/* call the handler */		   \
+"	addql	#8,%%sp\n"						   \
+"	addql	#4,%%sp\n"						   \
+"	orw	#0x0600,%%sr\n"						   \
+"	andw	#0xfeff,%%sr\n"		/* set IPL = 6 again */		   \
+"	orb 	#(1<<(" #n "&7)),"	/* now unmask the int again */	   \
+	    "("MFP_MK_BASE"+(((" #n "&8)^8)>>2)+((" #n "&16)<<3)):w\n"	   \
+"	jbra	"SYMBOL_NAME_STR(ret_from_interrupt)"\n"		   \
+	 : : "i" (&kstat.interrupts[n+8])				   \
+);									   \
+}
+
+BUILD_SLOW_IRQ(0);
+BUILD_SLOW_IRQ(1);
+BUILD_SLOW_IRQ(2);
+BUILD_SLOW_IRQ(3);
+BUILD_SLOW_IRQ(4);
+BUILD_SLOW_IRQ(5);
+BUILD_SLOW_IRQ(6);
+BUILD_SLOW_IRQ(7);
+BUILD_SLOW_IRQ(8);
+BUILD_SLOW_IRQ(9);
+BUILD_SLOW_IRQ(10);
+BUILD_SLOW_IRQ(11);
+BUILD_SLOW_IRQ(12);
+BUILD_SLOW_IRQ(13);
+BUILD_SLOW_IRQ(14);
+BUILD_SLOW_IRQ(15);
+BUILD_SLOW_IRQ(16);
+BUILD_SLOW_IRQ(17);
+BUILD_SLOW_IRQ(18);
+BUILD_SLOW_IRQ(19);
+BUILD_SLOW_IRQ(20);
+BUILD_SLOW_IRQ(21);
+BUILD_SLOW_IRQ(22);
+BUILD_SLOW_IRQ(23);
+BUILD_SLOW_IRQ(24);
+BUILD_SLOW_IRQ(25);
+BUILD_SLOW_IRQ(26);
+BUILD_SLOW_IRQ(27);
+BUILD_SLOW_IRQ(28);
+BUILD_SLOW_IRQ(29);
+BUILD_SLOW_IRQ(30);
+BUILD_SLOW_IRQ(31);
+
+asm_irq_handler slow_handlers[32] = {
+	atari_slow_irq_0_handler,
+	atari_slow_irq_1_handler,
+	atari_slow_irq_2_handler,
+	atari_slow_irq_3_handler,
+	atari_slow_irq_4_handler,
+	atari_slow_irq_5_handler,
+	atari_slow_irq_6_handler,
+	atari_slow_irq_7_handler,
+	atari_slow_irq_8_handler,
+	atari_slow_irq_9_handler,
+	atari_slow_irq_10_handler,
+	atari_slow_irq_11_handler,
+	atari_slow_irq_12_handler,
+	atari_slow_irq_13_handler,
+	atari_slow_irq_14_handler,
+	atari_slow_irq_15_handler,
+	atari_slow_irq_16_handler,
+	atari_slow_irq_17_handler,
+	atari_slow_irq_18_handler,
+	atari_slow_irq_19_handler,
+	atari_slow_irq_20_handler,
+	atari_slow_irq_21_handler,
+	atari_slow_irq_22_handler,
+	atari_slow_irq_23_handler,
+	atari_slow_irq_24_handler,
+	atari_slow_irq_25_handler,
+	atari_slow_irq_26_handler,
+	atari_slow_irq_27_handler,
+	atari_slow_irq_28_handler,
+	atari_slow_irq_29_handler,
+	atari_slow_irq_30_handler,
+	atari_slow_irq_31_handler
+};
+
+asmlinkage void atari_fast_irq_handler( void );
+asmlinkage void atari_prio_irq_handler( void );
+
+/* Dummy function to allow asm with operands.  */
+void atari_fast_prio_irq_dummy (void) {
+__asm__ (ALIGN_STR "\n"
+SYMBOL_NAME_STR(atari_fast_irq_handler) ":
+	orw 	#0x700,%%sr		/* disable all interrupts */
+"SYMBOL_NAME_STR(atari_prio_irq_handler) ":\t"
+	SAVE_ALL "
+	addql	#1,"SYMBOL_NAME_STR(intr_count)"
+	movew	%%sp@(" FORMATVEC "),%%d0	/* get vector number from stack frame */
+	andil	#0xfff,%%d0		/* mask off format nibble */
+	lsrl	#2,%%d0			/* convert vector to source */
+	subl	#(0x40-8),%%d0
+	jpl 	1f
+	addl	#(0x40-8-0x18),%%d0
+1:	lea	%a0,%%a0
+	addql	#1,%%a0@(%%d0:l:4)
+	lea	"SYMBOL_NAME_STR(irq_handler)",%%a0
+	lea	%%a0@(%%d0:l:8),%%a0
+	movel	%%a0@(4),%%sp@-		/* push handler data */
+	pea 	%%sp@(4)		/* push frame address */
+	movel	%%d0,%%sp@-		/* push int number */
+	movel	%%a0@,%%a0
+	jsr	%%a0@			/* and call the handler */
+	addql	#8,%%sp
+	addql	#4,%%sp
+	jbra	"SYMBOL_NAME_STR(ret_from_interrupt)
+	 : : "i" (&kstat.interrupts)
+);
+}
+
+/* GK:
+ * HBL IRQ handler for Falcon. Nobody needs it :-)
+ * ++andreas: raise ipl to disable further HBLANK interrupts.
+ */
+asmlinkage void falcon_hblhandler(void);
+asm(".text\n"
+ALIGN_STR "\n"
+SYMBOL_NAME_STR(falcon_hblhandler) ":
+	movel	%d0,%sp@-
+	movew	%sp@(4),%d0
+	andw	#0xf8ff,%d0
+	orw	#0x0200,%d0	/* set saved ipl to 2 */
+	movew	%d0,%sp@(4)
+	movel	%sp@+,%d0
+	rte");
+
+/* Defined in entry.S; only increments 'num_suprious' */
+asmlinkage void bad_interrupt(void);
+
+extern void atari_microwire_cmd( int cmd );
+
+/*
+ * void atari_init_INTS (void)
+ *
+ * Parameters:	None
+ *
+ * Returns:	Nothing
+ *
+ * This function should be called during kernel startup to initialize
+ * the atari IRQ handling routines.
+ */
+
+void atari_init_INTS(void)
+{
+	int i;
+
+	/* initialize the vector table */
+	for (i = 0; i < NUM_INT_SOURCES; ++i) {
+		vectors[IRQ_SOURCE_TO_VECTOR(i)] = bad_interrupt;
+	}
+
+	/* Initialize the MFP(s) */
+
+#ifdef ATARI_USE_SOFTWARE_EOI
+	mfp.vec_adr  = 0x48;	/* Software EOI-Mode */
+#else
+	mfp.vec_adr  = 0x40;	/* Automatic EOI-Mode */
+#endif
+	mfp.int_en_a =		    /* turn off MFP-Ints */
+	mfp.int_en_b = 0x00;
+	mfp.int_mk_a =			/* no Masking */
+	mfp.int_mk_b = 0xff;
+
+	if (ATARIHW_PRESENT(TT_MFP)) {
+#ifdef ATARI_USE_SOFTWARE_EOI
+		tt_mfp.vec_adr  = 0x58;		/* Software EOI-Mode */
+#else
+		tt_mfp.vec_adr  = 0x50;		/* Automatic EOI-Mode */
+#endif
+		tt_mfp.int_en_a =			/* turn off MFP-Ints */
+		tt_mfp.int_en_b = 0x00;
+		tt_mfp.int_mk_a =			/* no Masking */
+		tt_mfp.int_mk_b = 0xff;
+	}
+
+	if (ATARIHW_PRESENT(SCC)) {
+		scc.cha_a_ctrl = 9;
+		MFPDELAY();
+		scc.cha_a_ctrl = (char) 0xc0; /* hardware reset */
+	}
+
+	if (ATARIHW_PRESENT(SCU)) {
+		/* init the SCU if present */
+		tt_scu.sys_mask = 0x10;		/* enable VBL (for the cursor) and
+									 * disable HSYNC interrupts (who
+									 * needs them?)  MFP and SCC are
+									 * enabled in VME mask
+									 */
+		tt_scu.vme_mask = 0x60;		/* enable MFP and SCC ints */
+	}
+	else {
+		/* If no SCU, the HSYNC interrupt needs to be disabled this
+		 * way. (Else _inthandler in kernel/sys_call.S gets overruns)
+		 */
+		vectors[VEC_INT2] = falcon_hblhandler;
+	}
+
+	if (ATARIHW_PRESENT(PCM_8BIT) && ATARIHW_PRESENT(MICROWIRE)) {
+		/* Initialize the LM1992 Sound Controller to enable
+		   the PSG sound.  This is misplaced here, it should
+		   be in a atasound_init(), that doesn't exist yet. */
+		atari_microwire_cmd(MW_LM1992_PSG_HIGH);
+	}
+	
+	stdma_init();
+
+	/* Initialize the PSG: all sounds off, both ports output */
+	sound_ym.rd_data_reg_sel = 7;
+	sound_ym.wd_data = 0xff;
+}
+
+
+static void atari_call_isr_list( int irq, struct pt_regs *fp, void *_p )
+{
+  isr_node_t *p;
+	
+  for( p = (isr_node_t *)_p; p; p = p->next )
+    p->isr( irq, fp, p->data );
+}
+
+
+/*
+ * atari_add_isr : add an interrupt service routine for a particular
+ *		   machine specific interrupt source.
+ *		   If the addition was successful, it returns 1, otherwise
+ *		   it returns 0.  It will fail if the interrupt is already
+ *                 occupied of another handler with different type
+ */
+
+int atari_add_isr(unsigned long source, isrfunc isr, int type, void
+		  *data, char *name)
+{
+	int vector;
+	
+	source &= ~IRQ_MACHSPEC;
+	if (type < IRQ_TYPE_SLOW || type > IRQ_TYPE_PRIO) {
+		printk ("atari_add_isr: Bad irq type %d requested from %s\n",
+				type, name );
+		return( 0 );
+	}
+	if (!IS_VALID_INTNO(source)) {
+		printk ("atari_add_isr: Unknown irq %ld requested from %s\n",
+				source, name );
+		return( 0 );
+	}
+	vector = IRQ_SOURCE_TO_VECTOR(source);
+
+	/*
+	 * Check type/source combination: slow ints are (currently)
+	 * only possible for MFP-interrupts.
+	 */
+	if (type == IRQ_TYPE_SLOW &&
+		(source < STMFP_SOURCE_BASE || source >= SCC_SOURCE_BASE)) {
+		printk ("atari_add_isr: Slow irq requested for non-MFP source %ld from %s\n",
+				source, name );
+		return( 0 );
+	}
+		
+	if (vectors[vector] == bad_interrupt) {
+		/* int has no handler yet */
+		irq_handler[source].isr = isr;
+		irq_handler[source].data = data;
+		irq_param[source].type = type;
+		irq_param[source].name = name;
+		vectors[vector] =
+			(type == IRQ_TYPE_SLOW) ? slow_handlers[source-STMFP_SOURCE_BASE] :
+			(type == IRQ_TYPE_FAST) ? atari_fast_irq_handler :
+									  atari_prio_irq_handler;
+		/* If MFP int, also enable and umask it */
+		atari_turnon_irq(source);
+		atari_enable_irq(source);
+
+		return 1;
+	}
+	else if (irq_param[source].type == type) {
+		/* old handler is of same type -> handlers can be chained */
+		isr_node_t *p;
+		unsigned long flags;
+
+		save_flags(flags);
+		cli();
+
+		if (irq_handler[source].isr != atari_call_isr_list) {
+			/* Only one handler yet, make a node for this first one */
+			p = new_isr_node();
+			if (p == NULL) return 0;
+			p->isr = irq_handler[source].isr;
+			p->data = irq_handler[source].data;
+			p->name = irq_param[source].name;
+			p->next = NULL;
+
+			irq_handler[source].isr = atari_call_isr_list;
+			irq_handler[source].data = p;
+			irq_param[source].name = "chained";
+		}
+
+		p = new_isr_node();
+		if (p == NULL) return 0;
+		p->isr = isr;
+		p->data = data;
+		p->name = name;
+		/* new handlers are put in front of the queue */
+		p->next = irq_handler[source].data;
+		irq_handler[source].data = p;
+
+		restore_flags(flags);
+		return 1;
+	}
+	else {
+		printk ("atari_add_isr: Irq %ld allocated by other type int (call from %s)\n",
+				source, name );
+		return( 0 );
+	}
+}
+
+
+int atari_remove_isr(unsigned long source, isrfunc isr)
+{
+	unsigned long flags;
+	int vector;
+	isr_node_t **p, *q;
+
+	source &= ~IRQ_MACHSPEC;
+
+	if (!IS_VALID_INTNO(source)) {
+		printk("atari_remove_isr: Unknown irq %ld\n", source);
+		return 0;
+	}
+
+	vector = IRQ_SOURCE_TO_VECTOR(source);
+	if (vectors[vector] == bad_interrupt)
+		goto not_found;
+
+	save_flags(flags);
+	cli();
+
+	if (irq_handler[source].isr != atari_call_isr_list) {
+		/* It's the only handler for the interrupt */
+		if (irq_handler[source].isr != isr) {
+			restore_flags(flags);
+			goto not_found;
+		}
+		irq_handler[source].isr = NULL;
+		irq_handler[source].data = NULL;
+		irq_param[source].name = NULL;
+		vectors[vector] = bad_interrupt;
+		/* If MFP int, also disable it */
+		atari_disable_irq(source);
+		atari_turnoff_irq(source);
+
+		restore_flags(flags);
+		return 1;
+	}
+
+	/* The interrupt is chained, find the isr on the list */
+	for( p = (isr_node_t **)&irq_handler[source].data; *p; p = &(*p)->next ) {
+		if ((*p)->isr == isr) break;
+	}
+	if (!*p) {
+		restore_flags(flags);
+		goto not_found;
+	}
+
+	(*p)->isr = NULL; /* Mark it as free for reallocation */
+	*p = (*p)->next;
+
+	/* If there's now only one handler, unchain the interrupt, i.e. plug in
+	 * the handler directly again and omit atari_call_isr_list */
+	q = (isr_node_t *)irq_handler[source].data;
+	if (q && !q->next) {
+		irq_handler[source].isr = q->isr;
+		irq_handler[source].data = q->data;
+		irq_param[source].name = q->name;
+		q->isr = NULL; /* Mark it as free for reallocation */
+	}
+
+	restore_flags(flags);
+	return 1;
+
+  not_found:
+	printk("atari_remove_isr: isr %p not found on list!\n", isr);
+	return 0;
+}
+
+
+/*
+ * atari_register_vme_int() returns the number of a free interrupt vector for
+ * hardware with a programmable int vector (probably a VME board).
+ */
+
+unsigned long atari_register_vme_int(void)
+{
+	unsigned long source;
+	
+	if (next_free_vme_vec == NUM_ATARI_SOURCES)
+		return 0;
+
+	source = next_free_vme_vec | IRQ_MACHSPEC;
+	next_free_vme_vec++;
+	return source;
+}
+
+
+int atari_get_irq_list(char *buf, int len)
+{
+	int i;
+
+	for (i = 0; i < NUM_INT_SOURCES; ++i) {
+		if (vectors[IRQ_SOURCE_TO_VECTOR(i)] == bad_interrupt)
+			continue;
+		if (i < STMFP_SOURCE_BASE)
+			len += sprintf(buf+len, "auto %2d: %8d ",
+				       i, kstat.interrupts[i]);
+		else
+			len += sprintf(buf+len, "vec $%02x: %8d ",
+				       IRQ_SOURCE_TO_VECTOR(i),
+				       kstat.interrupts[i]);
+
+		if (irq_handler[i].isr != atari_call_isr_list) {
+			len += sprintf(buf+len, "%s\n", irq_param[i].name);
+		}
+		else {
+			isr_node_t *p;
+			for( p = (isr_node_t *)irq_handler[i].data; p; p = p->next ) {
+				len += sprintf(buf+len, "%s\n", p->name);
+				if (p->next)
+					len += sprintf( buf+len, "                  " );
+			}
+		}
+	}
+	if (num_spurious)
+		len += sprintf(buf+len, "spurio.: %8ld\n", num_spurious);
+	
+	return len;
+}
+
+
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/atari/atakeyb.c linux/arch/m68k/atari/atakeyb.c
--- v1.3.93/linux/arch/m68k/atari/atakeyb.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/atari/atakeyb.c	Mon Apr  1 22:00:10 1996
@@ -0,0 +1,847 @@
+/*
+ * linux/atari/atakeyb.c
+ *
+ * Atari Keyboard driver for 680x0 Linux
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file README.legal in the main directory of this archive
+ * for more details.
+ */
+
+/*
+ * Atari support by Robert de Vries
+ * enhanced by Bjoern Brauel and Roman Hodek
+ */
+
+#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 <asm/atariints.h>
+#include <asm/atarihw.h>
+#include <asm/atarikb.h>
+#include <asm/atari_mouse.h>
+#include <asm/atari_joystick.h>
+#include <asm/irq.h>
+
+extern int do_poke_blanked_console;
+extern void process_keycode (int);
+extern int ovsc_switchmode;
+unsigned char mach_keyboard_type;
+static void atakeyb_rep( unsigned long ignore );
+extern unsigned int keymap_count;
+
+/* Hook for MIDI serial driver */
+void (*atari_MIDI_interrupt_hook) (void);
+/* Hook for mouse driver */
+void (*atari_mouse_interrupt_hook) (char *);
+
+#define ATAKEY_CAPS	(58)
+#define BREAK_MASK	(0x80)
+
+/*
+ * ++roman: The following changes were applied manually:
+ *
+ *  - The Alt (= Meta) key works in combination with Shift and
+ *    Control, e.g. Alt+Shift+a sends Meta-A (0xc1), Alt+Control+A sends
+ *    Meta-Ctrl-A (0x81) ...
+ *
+ *  - The parentheses on the keypad send '(' and ')' with all
+ *    modifiers (as would do e.g. keypad '+'), but they cannot be used as
+ *    application keys (i.e. sending Esc O c).
+ *
+ *  - HELP and UNDO are mapped to be F21 and F24, resp, that send the
+ *    codes "\E[M" and "\E[P". (This is better than the old mapping to
+ *    F11 and F12, because these codes are on Shift+F1/2 anyway.) This
+ *    way, applications that allow their own keyboard mappings
+ *    (e.g. tcsh, X Windows) can be configured to use them in the way
+ *    the label suggests (providing help or undoing).
+ *
+ *  - Console switching is done with Alt+Fx (consoles 1..10) and
+ *    Shift+Alt+Fx (consoles 11..20).
+ *
+ *  - The misc. special function implemented in the kernel are mapped
+ *    to the following key combinations:
+ *
+ *      ClrHome          -> Home/Find
+ *      Shift + ClrHome  -> End/Select
+ *      Shift + Up       -> Page Up
+ *      Shift + Down     -> Page Down
+ *      Alt + Help       -> show system status
+ *      Shift + Help     -> show memory info
+ *      Ctrl + Help      -> show registers
+ *      Ctrl + Alt + Del -> Reboot
+ *      Alt + Undo       -> switch to last console
+ *      Shift + Undo     -> send interrupt
+ *      Alt + Insert     -> stop/start output (same as ^S/^Q)
+ *      Alt + Up         -> Scroll back console (if implemented)
+ *      Alt + Down       -> Scroll forward console (if implemented)
+ *      Alt + CapsLock   -> NumLock
+ *
+ */
+
+static u_short ataplain_map[NR_KEYS] = {
+	0xf200, 0xf01b, 0xf031, 0xf032, 0xf033, 0xf034, 0xf035, 0xf036,
+	0xf037, 0xf038, 0xf039, 0xf030, 0xf02d, 0xf03d, 0xf008, 0xf009,
+	0xfb71, 0xfb77, 0xfb65, 0xfb72, 0xfb74, 0xfb79, 0xfb75, 0xfb69,
+	0xfb6f, 0xfb70, 0xf05b, 0xf05d, 0xf201, 0xf702, 0xfb61, 0xfb73,
+	0xfb64, 0xfb66, 0xfb67, 0xfb68, 0xfb6a, 0xfb6b, 0xfb6c, 0xf03b,
+	0xf027, 0xf060, 0xf700, 0xf05c, 0xfb7a, 0xfb78, 0xfb63, 0xfb76,
+	0xfb62, 0xfb6e, 0xfb6d, 0xf02c, 0xf02e, 0xf02f, 0xf700, 0xf200,
+	0xf703, 0xf020, 0xf207, 0xf100, 0xf101, 0xf102, 0xf103, 0xf104,
+	0xf105, 0xf106, 0xf107, 0xf108, 0xf109, 0xf200, 0xf200, 0xf114,
+	0xf603, 0xf200, 0xf30b, 0xf601, 0xf200, 0xf602, 0xf30a, 0xf200,
+	0xf600, 0xf200, 0xf115, 0xf07f, 0xf200, 0xf200, 0xf200, 0xf200,
+	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+	0xf200, 0xf121, 0xf11b, 0xf028, 0xf029, 0xf30d, 0xf30c, 0xf307,
+	0xf308, 0xf309, 0xf304, 0xf305, 0xf306, 0xf301, 0xf302, 0xf303,
+	0xf300, 0xf310, 0xf30e, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200
+};
+
+static u_short atashift_map[NR_KEYS] = {
+	0xf200, 0xf01b, 0xf021, 0xf040, 0xf023, 0xf024, 0xf025, 0xf05e,
+	0xf026, 0xf02a, 0xf028, 0xf029, 0xf05f, 0xf02b, 0xf008, 0xf009,
+	0xfb51, 0xfb57, 0xfb45, 0xfb52, 0xfb54, 0xfb59, 0xfb55, 0xfb49,
+	0xfb4f, 0xfb50, 0xf07b, 0xf07d, 0xf201, 0xf702, 0xfb41, 0xfb53,
+	0xfb44, 0xfb46, 0xfb47, 0xfb48, 0xfb4a, 0xfb4b, 0xfb4c, 0xf03a,
+	0xf022, 0xf07e, 0xf700, 0xf07c, 0xfb5a, 0xfb58, 0xfb43, 0xfb56,
+	0xfb42, 0xfb4e, 0xfb4d, 0xf03c, 0xf03e, 0xf03f, 0xf700, 0xf200,
+	0xf703, 0xf020, 0xf207, 0xf10a, 0xf10b, 0xf10c, 0xf10d, 0xf10e,
+	0xf10f, 0xf110, 0xf111, 0xf112, 0xf113, 0xf200, 0xf200, 0xf117,
+	0xf118, 0xf200, 0xf30b, 0xf601, 0xf200, 0xf602, 0xf30a, 0xf200,
+	0xf119, 0xf200, 0xf115, 0xf07f, 0xf200, 0xf200, 0xf200, 0xf200,
+	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+	0xf200, 0xf205, 0xf203, 0xf028, 0xf029, 0xf30d, 0xf30c, 0xf307,
+	0xf308, 0xf309, 0xf304, 0xf305, 0xf306, 0xf301, 0xf302, 0xf303,
+	0xf300, 0xf310, 0xf30e, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200
+};
+
+static u_short atactrl_map[NR_KEYS] = {
+	0xf200, 0xf200, 0xf200, 0xf000, 0xf01b, 0xf01c, 0xf01d, 0xf01e,
+	0xf01f, 0xf07f, 0xf200, 0xf200, 0xf07f, 0xf200, 0xf008, 0xf200,
+	0xf011, 0xf017, 0xf005, 0xf012, 0xf014, 0xf019, 0xf015, 0xf009,
+	0xf00f, 0xf010, 0xf01b, 0xf01d, 0xf201, 0xf702, 0xf001, 0xf013,
+	0xf004, 0xf006, 0xf007, 0xf008, 0xf00a, 0xf00b, 0xf00c, 0xf200,
+	0xf007, 0xf000, 0xf700, 0xf01c, 0xf01a, 0xf018, 0xf003, 0xf016,
+	0xf002, 0xf00e, 0xf00d, 0xf200, 0xf200, 0xf07f, 0xf700, 0xf200,
+	0xf703, 0xf000, 0xf207, 0xf100, 0xf101, 0xf102, 0xf103, 0xf104,
+	0xf105, 0xf106, 0xf107, 0xf108, 0xf109, 0xf200, 0xf200, 0xf114,
+	0xf603, 0xf200, 0xf30b, 0xf601, 0xf200, 0xf602, 0xf30a, 0xf200,
+	0xf600, 0xf200, 0xf115, 0xf07f, 0xf200, 0xf200, 0xf200, 0xf200,
+	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+	0xf200, 0xf121, 0xf202, 0xf028, 0xf029, 0xf30d, 0xf30c, 0xf307,
+	0xf308, 0xf309, 0xf304, 0xf305, 0xf306, 0xf301, 0xf302, 0xf303,
+	0xf300, 0xf310, 0xf30e, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200
+};
+
+static u_short atashift_ctrl_map[NR_KEYS] = {
+	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf008, 0xf200,
+	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+	0xf200, 0xf200, 0xf200, 0xf200, 0xf201, 0xf702, 0xf200, 0xf200,
+	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+	0xf200, 0xf200, 0xf700, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf700, 0xf200,
+	0xf703, 0xf200, 0xf207, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf117,
+	0xf603, 0xf200, 0xf30b, 0xf601, 0xf200, 0xf602, 0xf30a, 0xf200,
+	0xf600, 0xf200, 0xf115, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+	0xf200, 0xf200, 0xf200, 0xf028, 0xf029, 0xf30d, 0xf30c, 0xf307,
+	0xf308, 0xf309, 0xf304, 0xf305, 0xf306, 0xf301, 0xf302, 0xf303,
+	0xf300, 0xf310, 0xf30e, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200
+};
+
+static u_short ataalt_map[NR_KEYS] = {
+	0xf200, 0xf81b, 0xf831, 0xf832, 0xf833, 0xf834, 0xf835, 0xf836,
+	0xf837, 0xf838, 0xf839, 0xf830, 0xf82d, 0xf83d, 0xf808, 0xf809,
+	0xf871, 0xf877, 0xf865, 0xf872, 0xf874, 0xf879, 0xf875, 0xf869,
+	0xf86f, 0xf870, 0xf85b, 0xf85d, 0xf80d, 0xf702, 0xf861, 0xf873,
+	0xf864, 0xf866, 0xf867, 0xf868, 0xf86a, 0xf86b, 0xf86c, 0xf83b,
+	0xf827, 0xf860, 0xf700, 0xf85c, 0xf87a, 0xf878, 0xf863, 0xf876,
+	0xf862, 0xf86e, 0xf86d, 0xf82c, 0xf82e, 0xf82f, 0xf700, 0xf200,
+	0xf703, 0xf820, 0xf208, 0xf500, 0xf501, 0xf502, 0xf503, 0xf504,
+	0xf505, 0xf506, 0xf507, 0xf508, 0xf509, 0xf200, 0xf200, 0xf114,
+	0xf20b, 0xf200, 0xf30b, 0xf601, 0xf200, 0xf602, 0xf30a, 0xf200,
+	0xf20a, 0xf200, 0xf209, 0xf87f, 0xf200, 0xf200, 0xf200, 0xf200,
+	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+	0xf200, 0xf206, 0xf204, 0xf028, 0xf029, 0xf30d, 0xf30c, 0xf907,
+	0xf908, 0xf909, 0xf904, 0xf905, 0xf906, 0xf901, 0xf902, 0xf903,
+	0xf900, 0xf310, 0xf30e, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200
+};
+
+static u_short atashift_alt_map[NR_KEYS] = {
+	0xf200, 0xf81b, 0xf821, 0xf840, 0xf823, 0xf824, 0xf825, 0xf85e,
+	0xf826, 0xf82a, 0xf828, 0xf829, 0xf85f, 0xf82b, 0xf808, 0xf809,
+	0xf851, 0xf857, 0xf845, 0xf852, 0xf854, 0xf859, 0xf855, 0xf849,
+	0xf84f, 0xf850, 0xf87b, 0xf87d, 0xf201, 0xf702, 0xf841, 0xf853,
+	0xf844, 0xf846, 0xf847, 0xf848, 0xf84a, 0xf84b, 0xf84c, 0xf83a,
+	0xf822, 0xf87e, 0xf700, 0xf87c, 0xf85a, 0xf858, 0xf843, 0xf856,
+	0xf842, 0xf84e, 0xf84d, 0xf83c, 0xf83e, 0xf83f, 0xf700, 0xf200,
+	0xf703, 0xf820, 0xf207, 0xf50a, 0xf50b, 0xf50c, 0xf50d, 0xf50e,
+	0xf50f, 0xf510, 0xf511, 0xf512, 0xf513, 0xf200, 0xf200, 0xf117,
+	0xf118, 0xf200, 0xf30b, 0xf601, 0xf200, 0xf602, 0xf30a, 0xf200,
+	0xf119, 0xf200, 0xf115, 0xf87f, 0xf200, 0xf200, 0xf200, 0xf200,
+	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+	0xf200, 0xf200, 0xf200, 0xf028, 0xf029, 0xf30d, 0xf30c, 0xf307,
+	0xf308, 0xf309, 0xf304, 0xf305, 0xf306, 0xf301, 0xf302, 0xf303,
+	0xf300, 0xf310, 0xf30e, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200
+};
+
+static u_short atactrl_alt_map[NR_KEYS] = {
+	0xf200, 0xf200, 0xf200, 0xf800, 0xf81b, 0xf81c, 0xf81d, 0xf81e,
+	0xf81f, 0xf87f, 0xf200, 0xf200, 0xf87f, 0xf200, 0xf808, 0xf200,
+	0xf811, 0xf817, 0xf805, 0xf812, 0xf814, 0xf819, 0xf815, 0xf809,
+	0xf80f, 0xf810, 0xf81b, 0xf81d, 0xf201, 0xf702, 0xf801, 0xf813,
+	0xf804, 0xf806, 0xf807, 0xf808, 0xf80a, 0xf80b, 0xf80c, 0xf200,
+	0xf807, 0xf800, 0xf700, 0xf81c, 0xf81a, 0xf818, 0xf803, 0xf816,
+	0xf802, 0xf80e, 0xf80d, 0xf200, 0xf200, 0xf87f, 0xf700, 0xf200,
+	0xf703, 0xf800, 0xf207, 0xf100, 0xf101, 0xf102, 0xf103, 0xf104,
+	0xf105, 0xf106, 0xf107, 0xf108, 0xf109, 0xf200, 0xf200, 0xf114,
+	0xf603, 0xf200, 0xf30b, 0xf601, 0xf200, 0xf602, 0xf30a, 0xf200,
+	0xf600, 0xf200, 0xf115, 0xf07f, 0xf200, 0xf200, 0xf200, 0xf200,
+	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+	0xf200, 0xf121, 0xf202, 0xf028, 0xf029, 0xf30d, 0xf30c, 0xf307,
+	0xf308, 0xf309, 0xf304, 0xf305, 0xf306, 0xf301, 0xf302, 0xf303,
+	0xf300, 0xf310, 0xf30e, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200
+};
+
+static u_short atashift_ctrl_alt_map[NR_KEYS] = {
+	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf808, 0xf200,
+	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+	0xf200, 0xf200, 0xf200, 0xf200, 0xf201, 0xf702, 0xf200, 0xf200,
+	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+	0xf200, 0xf200, 0xf700, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf700, 0xf200,
+	0xf703, 0xf200, 0xf207, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf117,
+	0xf603, 0xf200, 0xf30b, 0xf601, 0xf200, 0xf602, 0xf30a, 0xf200,
+	0xf600, 0xf200, 0xf115, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+	0xf200, 0xf200, 0xf200, 0xf028, 0xf029, 0xf30d, 0xf30c, 0xf307,
+	0xf308, 0xf309, 0xf304, 0xf305, 0xf306, 0xf301, 0xf302, 0xf303,
+	0xf300, 0xf310, 0xf30e, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200
+};
+
+typedef enum kb_state_t
+{
+    KEYBOARD, AMOUSE, RMOUSE, JOYSTICK, CLOCK, RESYNC
+} KB_STATE_T;
+
+#define	IS_SYNC_CODE(sc)	((sc) >= 0x04 && (sc) <= 0xfb)
+
+typedef struct keyboard_state
+{
+    unsigned char  buf[6];
+    int 	   len;
+    KB_STATE_T	   state;
+} KEYBOARD_STATE;
+
+KEYBOARD_STATE kb_state;
+
+#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 struct timer_list atakeyb_rep_timer = { NULL, NULL, 0, 0, atakeyb_rep };
+
+extern struct pt_regs *pt_regs;
+
+static void atakeyb_rep( unsigned long ignore )
+
+{
+	pt_regs = NULL;
+
+	/* Disable keyboard it for the time we call process_keycode(), else a race
+	 * in the keyboard tty queue may happen */
+	atari_disable_irq( IRQ_MFP_ACIA );
+	del_timer( &atakeyb_rep_timer );
+
+	/* A keyboard int may have come in before we disabled the irq, so
+	 * double-check whether rep_scancode is still != 0 */
+	if (rep_scancode) {
+		atakeyb_rep_timer.expires = jiffies + key_repeat_rate;
+		atakeyb_rep_timer.prev = atakeyb_rep_timer.next = NULL;
+		add_timer( &atakeyb_rep_timer );
+
+		process_keycode (rep_scancode);
+	}
+
+	atari_enable_irq( IRQ_MFP_ACIA );
+}
+
+
+/* ++roman: If a keyboard overrun happened, we can't tell in general how much
+ * bytes have been lost and in which state of the packet structure we are now.
+ * This usually causes keyboards bytes to be interpreted as mouse movements
+ * and vice versa, which is very annoying. It seems better to throw away some
+ * bytes (that are usually mouse bytes) than to misinterpret them. Therefor I
+ * introduced the RESYNC state for IKBD data. In this state, the bytes up to
+ * one that really looks like a key event (0x04..0xf2) or the start of a mouse
+ * packet (0xf8..0xfb) are thrown away, but at most 2 bytes. This at least
+ * speeds up the resynchronization of the event structure, even if maybe a
+ * mouse movement is lost. However, nothing is perfect. For bytes 0x01..0x03,
+ * it's really hard to decide whether they're mouse or keyboard bytes. Since
+ * overruns usually occur when moving the Atari mouse rapidly, they're seen as
+ * mouse bytes here. If this is wrong, only a make code of the keyboard gets
+ * lost, which isn't too bad. Loosing a break code would be desasterous,
+ * because then the keyboard repeat strikes...
+ */
+
+static void keyboard_interrupt(int irq, struct pt_regs *fp, void *dummy)
+{
+  u_char acia_stat;
+  int scancode;
+  int break_flag;
+
+  /* save frame for register dump */
+  pt_regs = (struct pt_regs *)fp;
+
+ repeat:
+  if (acia.mid_ctrl & ACIA_IRQ)
+	if (atari_MIDI_interrupt_hook)
+		atari_MIDI_interrupt_hook();
+  acia_stat = acia.key_ctrl;
+  /* check out if the interrupt came from this ACIA */
+  if (!((acia_stat | acia.mid_ctrl) & ACIA_IRQ))
+	return;
+
+    if (acia_stat & ACIA_OVRN)
+    {
+	/* a very fast typist or a slow system, give a warning */
+	/* ...happens often if interrupts were disabled for too long */
+	printk( "Keyboard overrun\n" );
+	scancode = acia.key_data;
+	/* Turn off autorepeating in case a break code has been lost */
+	del_timer( &atakeyb_rep_timer );
+	rep_scancode = 0;
+	if (IS_SYNC_CODE(scancode)) {
+	    /* This code seem already to be the start of a new packet or a
+	     * single keycode */
+	    kb_state.state = KEYBOARD;
+	    goto interpret_scancode;
+	}
+	else {
+	    /* Go to RESYNC state and skip this byte */
+	    kb_state.state = RESYNC;
+	    kb_state.len = 1; /* skip max. 1 another byte */
+	    goto repeat;
+	}
+    }
+
+    if (acia_stat & ACIA_RDRF)	/* received a character */
+    {
+	scancode = acia.key_data;	/* get it or reset the ACIA, I'll get it! */
+      interpret_scancode:
+	switch (kb_state.state)
+	{
+	  case KEYBOARD:
+	    switch (scancode)
+	    {
+	      case 0xF7:
+		kb_state.state = AMOUSE;
+		kb_state.len = 0;
+		break;
+
+	      case 0xF8:
+	      case 0xF9:
+     	      case 0xFA:
+	      case 0xFB:
+		kb_state.state = RMOUSE;
+	    	kb_state.len = 1;
+		kb_state.buf[0] = scancode;
+		break;
+
+	      case 0xFC:
+		kb_state.state = CLOCK;
+		kb_state.len = 0;
+		break;
+
+	      case 0xFE:
+	      case 0xFF:
+		kb_state.state = JOYSTICK;
+		kb_state.len = 1;
+		kb_state.buf[0] = scancode;
+		break;
+
+	      default:
+		break_flag = scancode & BREAK_MASK;
+		scancode &= ~BREAK_MASK;
+
+		if (break_flag) {
+		    del_timer( &atakeyb_rep_timer );
+		    rep_scancode = 0;
+		}
+		else {
+		    del_timer( &atakeyb_rep_timer );
+		    rep_scancode = scancode;
+		    atakeyb_rep_timer.expires = jiffies + key_repeat_delay;
+		    atakeyb_rep_timer.prev = atakeyb_rep_timer.next = NULL;
+		    add_timer( &atakeyb_rep_timer );
+		}
+
+		process_keycode( break_flag | scancode );
+		do_poke_blanked_console = 1;
+		mark_bh(CONSOLE_BH);
+		add_keyboard_randomness(scancode);
+
+		break;
+	    }
+	    break;
+
+	  case AMOUSE:
+	    kb_state.buf[kb_state.len++] = scancode;
+	    if (kb_state.len == 5)
+	    {
+		kb_state.state = KEYBOARD;
+		/* not yet used */
+		/* wake up someone waiting for this */
+	    }
+	    break;	
+
+	  case RMOUSE:
+	    kb_state.buf[kb_state.len++] = scancode;
+	    if (kb_state.len == 3)
+	    {
+		kb_state.state = KEYBOARD;
+		if (atari_mouse_interrupt_hook)
+			atari_mouse_interrupt_hook(kb_state.buf);
+	    }
+	    break;
+
+	  case JOYSTICK:
+	    kb_state.buf[1] = scancode;
+	    kb_state.state = KEYBOARD;
+	    atari_joystick_interrupt(kb_state.buf);
+	    break;
+
+	  case CLOCK:
+	    kb_state.buf[kb_state.len++] = scancode;
+	    if (kb_state.len == 6)
+	    {
+		kb_state.state = KEYBOARD;
+		/* wake up someone waiting for this.
+		   But will this ever be used, as Linux keeps its own time.
+		   Perhaps for synchronization purposes? */
+		/* wake_up_interruptible(&clock_wait); */
+	    }
+	    break;
+
+	  case RESYNC:
+	    if (kb_state.len <= 0 || IS_SYNC_CODE(scancode)) {
+		kb_state.state = KEYBOARD;
+		goto interpret_scancode;
+	    }
+	    kb_state.len--;
+	    break;
+	}
+    }
+
+#ifdef KEYB_WRITE_INTERRUPT
+    if (acia_stat & ACIA_TDRE)	/* transmit of character is finished */
+    {
+	if (kb_state.buf)
+	{
+	    acia.key_data = *kb_state.buf++;
+	    kb_state.len--;
+	    if (kb_state.len == 0)
+	    {
+		kb_state.buf = NULL;
+		if (!kb_state.kernel_mode)
+			/* unblock something */;
+	    }
+	}
+    }
+#endif
+
+#if 0
+    if (acia_stat & ACIA_CTS)
+	/* cannot happen */;
+#endif
+
+    if (acia_stat & (ACIA_FE | ACIA_PE))
+    {
+	printk("Error in keyboard communication\n");
+    }
+
+    /* process_keycode() can take a lot of time, so check again if
+	 * some character arrived
+	 */
+    goto repeat;
+}
+
+#ifdef KEYB_WRITE_INTERRUPT
+void ikbd_write(const char *str, int len)
+{
+    u_char acia_stat;
+
+    if (kb_stat.buf)
+	/* wait */;
+    acia_stat = acia.key_ctrl;
+    if (acia_stat & ACIA_TDRE)
+    {
+	if (len != 1)
+	{
+	    kb_stat.buf = str + 1;
+	    kb_stat.len = len - 1;
+	}
+	acia.key_data = *str;
+	/* poll */
+    }
+}
+#else
+/*
+ * I write to the keyboard without using interrupts, I poll instead.
+ * This takes for the maximum length string allowed (7) at 7812.5 baud
+ * 8 data 1 start 1 stop bit: 9.0 ms
+ * If this takes too long for normal operation, interrupt driven writing
+ * is the solution. (I made a feeble attempt in that direction but I
+ * kept it simple for now.)
+ */
+void ikbd_write(const char *str, int len)
+{
+    u_char acia_stat;
+
+    if ((len < 1) || (len > 7))
+	panic("ikbd: maximum string length exceeded");
+    while (len)
+    {
+	acia_stat = acia.key_ctrl;
+	if (acia_stat & ACIA_TDRE)
+	{
+	    acia.key_data = *str++;
+	    len--;
+	}
+    }
+}
+#endif
+
+/* Reset (without touching the clock) */
+void ikbd_reset(void)
+{
+    static const char cmd[2] = { 0x80, 0x01 };
+    
+    ikbd_write(cmd, 2);
+
+    /* if allswell code 0xF1 is returned, else the break codes of
+       all keys making contact */
+}
+
+/* Set mouse button action */
+void ikbd_mouse_button_action(int mode)
+{
+    char cmd[2] = { 0x07, mode };
+
+    ikbd_write(cmd, 2);
+}
+
+/* Set relative mouse position reporting */
+void ikbd_mouse_rel_pos(void)
+{
+    static const char cmd[1] = { 0x08 };
+
+    ikbd_write(cmd, 1);
+}
+
+/* Set absolute mouse position reporting */
+void ikbd_mouse_abs_pos(int xmax, int ymax)
+{
+    char cmd[5] = { 0x09, xmax>>8, xmax&0xFF, ymax>>8, ymax&0xFF };
+
+    ikbd_write(cmd, 5);
+}
+
+/* Set mouse keycode mode */
+void ikbd_mouse_kbd_mode(int dx, int dy)
+{
+    char cmd[3] = { 0x0A, dx, dy };
+
+    ikbd_write(cmd, 3);
+}
+
+/* Set mouse threshold */
+void ikbd_mouse_thresh(int x, int y)
+{
+    char cmd[3] = { 0x0B, x, y };
+
+    ikbd_write(cmd, 3);
+}
+
+/* Set mouse scale */
+void ikbd_mouse_scale(int x, int y)
+{
+    char cmd[3] = { 0x0C, x, y };
+
+    ikbd_write(cmd, 3);
+}
+
+/* Interrogate mouse position */
+void ikbd_mouse_pos_get(int *x, int *y)
+{
+    static const char cmd[1] = { 0x0D };
+
+    ikbd_write(cmd, 1);
+
+    /* wait for returning bytes */
+}
+
+/* Load mouse position */
+void ikbd_mouse_pos_set(int x, int y)
+{
+    char cmd[6] = { 0x0E, 0x00, x>>8, x&0xFF, y>>8, y&0xFF };
+
+    ikbd_write(cmd, 6);
+}
+
+/* Set Y=0 at bottom */
+void ikbd_mouse_y0_bot(void)
+{
+    static const char cmd[1] = { 0x0F };
+
+    ikbd_write(cmd, 1);
+}
+
+/* Set Y=0 at top */
+void ikbd_mouse_y0_top(void)
+{
+    static const char cmd[1] = { 0x10 };
+
+    ikbd_write(cmd, 1);
+}
+
+/* Resume */
+void ikbd_resume(void)
+{
+    static const char cmd[1] = { 0x11 };
+
+    ikbd_write(cmd, 1);
+}
+
+/* Disable mouse */
+void ikbd_mouse_disable(void)
+{
+    static const char cmd[1] = { 0x12 };
+
+    ikbd_write(cmd, 1);
+}
+
+/* Pause output */
+void ikbd_pause(void)
+{
+    static const char cmd[1] = { 0x13 };
+
+    ikbd_write(cmd, 1);
+}
+
+/* Set joystick event reporting */
+void ikbd_joystick_event_on(void)
+{
+    static const char cmd[1] = { 0x14 };
+
+    ikbd_write(cmd, 1);
+}
+
+/* Set joystick interrogation mode */
+void ikbd_joystick_event_off(void)
+{
+    static const char cmd[1] = { 0x15 };
+
+    ikbd_write(cmd, 1);
+}
+
+/* Joystick interrogation */
+void ikbd_joystick_get_state(void)
+{
+    static const char cmd[1] = { 0x16 };
+
+    ikbd_write(cmd, 1);
+}
+
+#if 0
+/* This disables all other ikbd activities !!!! */
+/* Set joystick monitoring */
+void ikbd_joystick_monitor(int rate)
+{
+    static const char cmd[2] = { 0x17, rate };
+
+    ikbd_write(cmd, 2);
+
+    kb_state.state = JOYSTICK_MONITOR;
+}
+#endif
+
+/* some joystick routines not in yet (0x18-0x19) */
+
+/* Disable joysticks */
+void ikbd_joystick_disable(void)
+{
+    static const char cmd[1] = { 0x1A };
+
+    ikbd_write(cmd, 1);
+}
+
+/* Time-of-day clock set */
+void ikbd_clock_set(int year, int month, int day, int hour, int minute, int second)
+{
+    char cmd[7] = { 0x1B, year, month, day, hour, minute, second };
+
+    ikbd_write(cmd, 7);
+}
+
+/* Interrogate time-of-day clock */
+void ikbd_clock_get(int *year, int *month, int *day, int *hour, int *minute, int second)
+{
+    static const char cmd[1] = { 0x1C };
+
+    ikbd_write(cmd, 1);
+}
+
+/* Memory load */
+void ikbd_mem_write(int address, int size, char *data)
+{
+    panic("Attempt to write data into keyboard memory");
+}
+
+/* Memory read */
+void ikbd_mem_read(int address, char data[6])
+{
+    char cmd[3] = { 0x21, address>>8, address&0xFF };
+
+    ikbd_write(cmd, 3);
+
+    /* receive data and put it in data */
+}
+
+/* Controller execute */
+void ikbd_exec(int address)
+{
+    char cmd[3] = { 0x22, address>>8, address&0xFF };
+
+    ikbd_write(cmd, 3);
+}
+
+/* Status inquiries (0x87-0x9A) not yet implemented */
+
+/* Set the state of the caps lock led. */
+void atari_kbd_leds (unsigned int leds)
+{
+    char cmd[6] = {32, 0, 4, 1, 254 + ((leds & 4) != 0), 0};
+    ikbd_write(cmd, 6);
+}
+
+/*
+ * The original code sometimes left the interrupt line of 
+ * the ACIAs low forever. I hope, it is fixed now.
+ *
+ * Martin Rogge, 20 Aug 1995
+ */
+ 
+int atari_keyb_init(void)
+{
+    /* setup key map */
+    key_maps[0]  = ataplain_map;
+    key_maps[1]  = atashift_map;
+    key_maps[2]  = 0; /* ataaltgr_map */
+    key_maps[4]  = atactrl_map;
+    key_maps[5]  = atashift_ctrl_map;
+    key_maps[8]  = ataalt_map;
+    key_maps[9]  = atashift_alt_map;
+    key_maps[12] = atactrl_alt_map;
+    key_maps[13] = atashift_ctrl_alt_map;
+    memcpy (plain_map, ataplain_map, sizeof(plain_map));
+    keymap_count = 8;
+
+    /* say that we don't have an AltGr key */
+    mach_keyboard_type = KB_84;
+
+    kb_state.state = KEYBOARD;
+    kb_state.len = 0;
+
+    add_isr(IRQ_MFP_ACIA, keyboard_interrupt, IRQ_TYPE_SLOW, NULL,
+	    "keyboard/mouse/MIDI");
+
+    atari_turnoff_irq(IRQ_MFP_ACIA);
+    do {
+	acia.key_ctrl = ACIA_RESET;		/* reset ACIA */
+	(void)acia.key_ctrl;
+	(void)acia.key_data;
+
+	acia.mid_ctrl = ACIA_RESET;		/* reset other ACIA */
+	(void)acia.mid_ctrl;
+	(void)acia.mid_data;
+
+	/* divide 500kHz by 64 gives 7812.5 baud */
+	/* 8 data no parity 1 start 1 stop bit */
+	/* receive interrupt enabled */
+#ifdef KEYB_WRITE_INTERRUPT
+	/* RTS low, transmit interrupt enabled */
+	if (ovsc_switchmode == 1)
+	    acia.key_ctrl = (ACIA_DIV64|ACIA_D8N1S|ACIA_RHTIE|ACIA_RIE);
+	    /* switch on OverScan via keyboard ACIA */
+	else
+	    acia.key_ctrl = (ACIA_DIV64|ACIA_D8N1S|ACIA_RLTIE|ACIA_RIE);
+#else
+	/* RTS low, transmit interrupt disabled */
+	if (ovsc_switchmode == 1)
+	    acia.key_ctrl = (ACIA_DIV64|ACIA_D8N1S|ACIA_RHTID|ACIA_RIE);
+	else
+	    acia.key_ctrl = (ACIA_DIV64|ACIA_D8N1S|ACIA_RLTID|ACIA_RIE);
+#endif
+	   
+	acia.mid_ctrl = ACIA_DIV16 | ACIA_D8N1S;
+    }
+    /* make sure the interrupt line is up */
+    while ((mfp.par_dt_reg & 0x10) == 0);
+
+    /* enable ACIA Interrupts */ 
+    mfp.active_edge &= ~0x10;
+    atari_turnon_irq(IRQ_MFP_ACIA);
+
+    ikbd_reset();
+    ikbd_mouse_disable();
+    ikbd_joystick_disable();
+
+    atari_joystick_init();
+  
+    return 0;
+}
+
+
+int atari_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 v1.3.93/linux/arch/m68k/atari/atapart.c linux/arch/m68k/atari/atapart.c
--- v1.3.93/linux/arch/m68k/atari/atapart.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/atari/atapart.c	Sat Mar 30 14:11:04 1996
@@ -0,0 +1,158 @@
+/*
+ * linux/atari/atapart.c
+ *
+ * Atari partition checking driver for 680x0 Linux
+ * Written by Andreas Schwab (schwab@ls5.informatik.uni-dortmund.de)
+ *
+ * 5/3/94 Roman Hodek:
+ *   Added some sanity checks
+ *   Linux device names start from 1 not 0, so I changed the initial value
+ *   for i to 1.
+ *
+ * 10/09/94 Guenther Kelleter:
+ *   Added support for ICD/Supra partition info.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file README.legal in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/fs.h>
+#include <linux/genhd.h>
+#include <linux/kernel.h>
+
+#include <asm/atari_rootsec.h>
+
+/* ++guenther: this should be settable by the user ("make config")?.
+ */
+#define ICD_PARTS
+
+extern int current_minor;
+
+void
+atari_check_partition (struct gendisk *hd, unsigned int dev)
+{
+  int i, minor = current_minor, m_lim = current_minor + hd->max_p;
+  struct buffer_head *bh;
+  struct rootsector *rs;
+  struct partition_info *pi;
+  ulong extensect;
+#ifdef ICD_PARTS
+  int part_fmt = 0; /* 0:unknown, 1:AHDI, 2:ICD/Supra */
+#endif
+
+  bh = bread (dev, 0, 1024);
+  if (!bh)
+    {
+      printk (" unable to read block 0\n");
+      return;
+    }
+
+  rs = (struct rootsector *) bh->b_data;
+  printk ("  %s%c:", hd->major_name, 'a' + (minor >> hd->minor_shift));
+
+  pi = &rs->part[0];
+  for (i = 1; pi < &rs->part[4] && minor < m_lim; i++, minor++, pi++)
+    {
+      if (pi->flg & 1)
+  /* active partition */
+  {
+    if (memcmp (pi->id, "XGM", 3) == 0)
+      /* extension partition */
+      {
+        struct rootsector *xrs;
+        struct buffer_head *xbh;
+        ulong partsect;
+
+#ifdef ICD_PARTS
+        part_fmt = 1;
+#endif
+        partsect = extensect = pi->st;
+        while (1)
+      {
+        xbh = bread (dev, partsect / 2, 1024);
+        if (!xbh)
+          {
+            printk (" block %ld read failed\n", partsect);
+            return;
+          }
+        if (partsect & 1)
+          xrs = (struct rootsector *) &xbh->b_data[512];
+        else
+          xrs = (struct rootsector *) &xbh->b_data[0];
+
+		/* ++roman: sanity check: bit 0 of flg field must be set */
+		if (!(xrs->part[0].flg & 1)) {
+			printk( "\nFirst sub-partition in extended partition is not valid!\n" );
+			break;
+		}
+		
+        hd->part[minor].start_sect = partsect + xrs->part[0].st;
+        hd->part[minor].nr_sects = xrs->part[0].siz;
+        printk (" %s%c%d", hd->major_name,
+            'a' + (minor >> hd->minor_shift), i);
+
+		if (!(xrs->part[1].flg & 1)) {
+			/* end of linked partition list */
+			brelse( xbh );
+			break;
+		}
+		if (memcmp( xrs->part[1].id, "XGM", 3 ) != 0) {
+			printk( "\nID of extended partion is not XGM!\n" );
+			brelse( xbh );
+			break;
+		}
+		
+		partsect = xrs->part[1].st + extensect;
+        brelse (xbh);
+        i++;
+        minor++;
+        if (minor >= m_lim) {
+			printk( "\nMaximum number of partitions reached!\n" );
+			break;
+		}
+      }
+      }
+    else
+      {
+        /* we don't care about other id's */
+        hd->part[minor].start_sect = pi->st;
+        hd->part[minor].nr_sects = pi->siz;
+        printk (" %s%c%d", hd->major_name,
+            'a' + (minor >> hd->minor_shift), i);
+
+      }
+  }
+    }
+#ifdef ICD_PARTS
+  if ( part_fmt!=1 ) /* no extended partitions -> test ICD-format */
+  {
+    pi = &rs->icdpart[0];
+    /* sanity check: no ICD format if first partion invalid */
+    if (memcmp (pi->id, "GEM", 3) == 0 ||
+        memcmp (pi->id, "BGM", 3) == 0 ||
+        memcmp (pi->id, "RAW", 3) == 0 )
+    {
+      for (i = 1; pi < &rs->icdpart[8] && minor < m_lim; i++, minor++, pi++)
+      {
+        /* accept only GEM,BGM,RAW partitions */
+        if (pi->flg & 1 && 
+            (memcmp (pi->id, "GEM", 3) == 0 ||
+             memcmp (pi->id, "BGM", 3) == 0 ||
+             memcmp (pi->id, "RAW", 3) == 0) )
+        {
+          part_fmt = 2;
+          hd->part[minor].start_sect = pi->st;
+          hd->part[minor].nr_sects = pi->siz;
+          printk (" %s%c%d", hd->major_name,
+              'a' + (minor >> hd->minor_shift), i);
+        }
+      }
+    }
+  }
+#endif
+  brelse (bh);
+
+  printk ("\n");
+}
+
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/atari/atari.mup linux/arch/m68k/atari/atari.mup
--- v1.3.93/linux/arch/m68k/atari/atari.mup	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/atari/atari.mup	Wed Dec 27 22:44:02 1995
@@ -0,0 +1,16 @@
+gcc -D__KERNEL__ -O2 -m68030 -c atacon.c -o atacon.o
+gcc -D__KERNEL__ -O2 -m68030 -c atasound.c -o atasound.o
+gcc -D__KERNEL__ -O2 -m68030 -c ataints.c -o ataints.o
+gcc -D__KERNEL__ -O2 -m68030 -c atapart.c -o atapart.o
+gcc -D__KERNEL__ -O2 -m68030 -c atakeyb.c -o atakeyb.o
+gcc -D__KERNEL__ -O2 -m68030 -c joystick.c -o joystick.o
+gcc -D__KERNEL__ -O2 -m68030 -c mouse.c -o mouse.o
+gcc -D__KERNEL__ -O2 -m68030 -c config.c -o config.o
+gcc -D__KERNEL__ -O2 -m68030 -c font_8x16.c -o font_8x16.o
+gcc -D__KERNEL__ -O2 -m68030 -c font_8x8.c -o font_8x8.o
+gcc -D__KERNEL__ -O2 -m68030 -c stdma.c -o stdma.o
+
+
+lnx-ld -r -o atari.o atacon.o atasound.o ataints.o atapart.o atakeyb.o config.o font_8x8.o font_8x1.o joystick.o mouse.o stdma.o
+
+cp atari.o ..\makedir
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/atari/atasound.c linux/arch/m68k/atari/atasound.c
--- v1.3.93/linux/arch/m68k/atari/atasound.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/atari/atasound.c	Thu Apr 18 02:04:17 1996
@@ -0,0 +1,150 @@
+/*
+linux/arch/m68k/atari/atasound.c
+
+++Geert: Moved almost all stuff to linux/drivers/sound/
+
+The author of atari_nosound, atari_mksound and atari_microwire_cmd is
+unknown.
+(++roman: That's me... :-)
+
+This file is subject to the terms and conditions of the GNU General Public
+License.  See the file README.legal in the main directory of this archive
+for more details.
+
+*/
+
+
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/major.h>
+#include <linux/config.h>
+#include <linux/fcntl.h>
+#include <linux/errno.h>
+#include <linux/mm.h>
+
+#include <asm/atarihw.h>
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/pgtable.h>
+#include <asm/atariints.h>
+#include <asm/bootinfo.h>
+
+
+/*
+ * stuff from the old atasound.c
+ */
+
+
+static void atari_nosound (unsigned long ignored)
+{
+	unsigned char	tmp;
+	unsigned long flags;
+	
+	/* turn off generator A in mixer control */
+	save_flags(flags);
+	cli();
+	sound_ym.rd_data_reg_sel = 7;
+	tmp = sound_ym.rd_data_reg_sel;
+	sound_ym.wd_data = tmp | 0x39;
+	restore_flags(flags);
+}	
+		
+
+void atari_microwire_cmd (int cmd)
+{
+	tt_microwire.mask = 0x7ff;
+	tt_microwire.data = MW_LM1992_ADDR | cmd;
+
+	/* Busy wait for data being completely sent :-( */
+	while( tt_microwire.mask != 0x7ff)
+		;
+}
+
+
+#define	PC_FREQ		1192180
+#define	PSG_FREQ	125000
+
+
+void atari_mksound (unsigned int count, unsigned int ticks)
+{
+	static struct timer_list sound_timer = { NULL, NULL, 0, 0,
+						     atari_nosound };
+	/*
+	 * Generates sound of some count for some number of clock ticks
+	 * [count = 1193180 / frequency]
+	 */
+	unsigned long flags;
+	unsigned char tmp;
+
+	save_flags(flags);
+	cli();
+
+	if (count == 750 && ticks == HZ/8) {
+		/* Special case: These values are used by console.c to
+		 * generate the console bell. They are catched here and the
+		 * sound actually generated is somehow special: it uses the
+		 * generator B and an envelope. No timer is needed therefore
+		 * and the bell doesn't disturb an other ongoing sound.
+		 */
+
+		/* set envelope duration to 492 ms */
+		sound_ym.rd_data_reg_sel = 11;
+		sound_ym.wd_data = 0;
+		sound_ym.rd_data_reg_sel = 12;
+		sound_ym.wd_data = 15;
+		/* envelope form: max -> min single */
+		sound_ym.rd_data_reg_sel = 13;
+		sound_ym.wd_data = 9;
+		/* set generator B frequency to 2400 Hz */
+		sound_ym.rd_data_reg_sel = 2;
+		sound_ym.wd_data = 52;
+		sound_ym.rd_data_reg_sel = 3;
+		sound_ym.wd_data = 0;
+		/* set volume of generator B to envelope control */
+		sound_ym.rd_data_reg_sel = 9;
+		sound_ym.wd_data = 0x10;
+		/* enable generator B in the mixer control */
+		sound_ym.rd_data_reg_sel = 7;
+		tmp = sound_ym.rd_data_reg_sel;
+		sound_ym.wd_data = (tmp & ~0x02) | 0x38;
+
+		restore_flags(flags);
+		return;
+	}
+
+	del_timer( &sound_timer );
+
+	if (!count) {
+		atari_nosound( 0 );
+	}
+	else {
+
+		/* convert from PC counter value (base frequency 1.193 MHz)
+		 * to PSG period value (base frequency 125 kHz).
+		 */
+		int period = (PSG_FREQ * count + PC_FREQ/2) / PC_FREQ;
+
+		if (period > 0xfff) period = 0xfff;
+
+		/* set generator A frequency to 0 */
+		sound_ym.rd_data_reg_sel = 0;
+		sound_ym.wd_data = period & 0xff;
+		sound_ym.rd_data_reg_sel = 1;
+		sound_ym.wd_data = (period >> 8) & 0xf;
+		/* turn on generator A in mixer control (but not noise
+		 * generator!) */
+		sound_ym.rd_data_reg_sel = 7;
+		tmp = sound_ym.rd_data_reg_sel;
+		sound_ym.wd_data = (tmp & ~0x01) | 0x38;
+		/* set generator A level to maximum, no envelope */
+		sound_ym.rd_data_reg_sel = 8;
+		sound_ym.wd_data = 15;
+		
+		if (ticks) {
+			sound_timer.expires = jiffies + ticks;
+			add_timer( &sound_timer );
+		}
+	}
+
+	restore_flags(flags);
+}
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/atari/atasound.h linux/arch/m68k/atari/atasound.h
--- v1.3.93/linux/arch/m68k/atari/atasound.h	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/atari/atasound.h	Mon Mar  4 22:36:02 1996
@@ -0,0 +1,33 @@
+/*
+ * Minor numbers for the sound driver.
+ *
+ * Unfortunately Creative called the codec chip of SB as a DSP. For this
+ * reason the /dev/dsp is reserved for digitized audio use. There is a
+ * device for true DSP processors but it will be called something else.
+ * In v3.0 it's /dev/sndproc but this could be a temporary solution.
+ */
+
+#define SND_NDEVS	256	/* Number of supported devices */
+#define SND_DEV_CTL	0	/* Control port /dev/mixer */
+#define SND_DEV_SEQ	1	/* Sequencer output /dev/sequencer (FM
+				   synthesizer and MIDI output) */
+#define SND_DEV_MIDIN	2	/* Raw midi access */
+#define SND_DEV_DSP	3	/* Digitized voice /dev/dsp */
+#define SND_DEV_AUDIO	4	/* Sparc compatible /dev/audio */
+#define SND_DEV_DSP16	5	/* Like /dev/dsp but 16 bits/sample */
+#define SND_DEV_STATUS	6	/* /dev/sndstat */
+/* #7 not in use now. Was in 2.4. Free for use after v3.0. */
+#define SND_DEV_SEQ2	8	/* /dev/sequencer, level 2 interface */
+#define SND_DEV_SNDPROC 9	/* /dev/sndproc for programmable devices */
+#define SND_DEV_PSS	SND_DEV_SNDPROC
+
+#define DSP_DEFAULT_SPEED	8000
+
+#define ON		1
+#define OFF		0
+
+#define MAX_AUDIO_DEV	5
+#define MAX_MIXER_DEV	2
+#define MAX_SYNTH_DEV	3
+#define MAX_MIDI_DEV	6
+#define MAX_TIMER_DEV	3
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/atari/config.c linux/arch/m68k/atari/config.c
--- v1.3.93/linux/arch/m68k/atari/config.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/atari/config.c	Fri Apr 19 02:41:15 1996
@@ -0,0 +1,1155 @@
+/*
+ *  linux/atari/config.c
+ *
+ *  Copyright (C) 1994 Bj”rn Brauel
+ *
+ *  5/2/94 Roman Hodek:
+ *    Added setting of time_adj to get a better clock.
+ *
+ *  5/14/94 Roman Hodek:
+ *    gettod() for TT 
+ *
+ *  5/15/94 Roman Hodek:
+ *    hard_reset_now() for Atari (and others?)
+ *
+ *  94/12/30 Andreas Schwab:
+ *    atari_sched_init fixed to get precise clock.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file README.legal in the main directory of this archive
+ * for more details.
+ */
+
+/*
+ * Miscellaneous atari stuff
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <asm/bootinfo.h>
+#include <linux/mc146818rtc.h>
+#include <linux/kd.h>
+#include <linux/tty.h>
+#include <linux/console.h>
+
+#include <asm/atarihw.h>
+#include <asm/atarihdreg.h>
+#include <asm/atariints.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/pgtable.h>
+#include <asm/machdep.h>
+
+extern void atari_sched_init(isrfunc);
+extern int atari_keyb_init(void);
+extern int atari_kbdrate (struct kbd_repeat *);
+extern void atari_kbd_leds (unsigned int);
+extern void atari_init_INTS (void);
+extern int atari_add_isr (unsigned long, isrfunc, int, void *, char *);
+extern int atari_remove_isr (unsigned long, isrfunc);
+extern void atari_enable_irq (unsigned);
+extern void atari_disable_irq (unsigned);
+extern int atari_get_irq_list (char *buf, int len);
+extern unsigned long atari_gettimeoffset (void);
+extern void atari_mste_gettod (int *, int *, int *, int *, int *, int *);
+extern void atari_gettod (int *, int *, int *, int *, int *, int *);
+extern int atari_mste_hwclk (int, struct hwclk_time *);
+extern int atari_hwclk (int, struct hwclk_time *);
+extern int atari_mste_set_clock_mmss (unsigned long);
+extern int atari_set_clock_mmss (unsigned long);
+extern void atari_check_partition (struct gendisk *hd, unsigned int dev);
+extern void atari_mksound( unsigned int count, unsigned int ticks );
+extern void atari_reset( void );
+#ifdef CONFIG_BLK_DEV_FD
+extern int atari_floppy_init (void);
+extern void atari_floppy_setup(char *, int *);
+#endif
+extern void atari_waitbut (void);
+extern struct consw fb_con;
+extern struct fb_info *atari_fb_init(long *);
+extern void atari_debug_init (void);
+extern void atari_video_setup(char *, int *);
+
+extern void (*kd_mksound)(unsigned int, unsigned int);
+
+/* This function tests for the presence of an address, specially a
+ * hardware register address. It is called very early in the kernel
+ * initialization process, when the VBR register isn't set up yet. On
+ * an Atari, it still points to address 0, which is unmapped. So a bus
+ * error would cause another bus error while fetching the exception
+ * vector, and the CPU would do nothing at all. So we needed to set up
+ * a temporary VBR and a vector table for the duration of the test.
+ */
+
+static int hwreg_present( volatile void *regp )
+{
+    int	ret = 0;
+    long	save_sp, save_vbr;
+    long	tmp_vectors[3];
+
+    __asm__ __volatile__
+	(	"movec	%/vbr,%2\n\t"
+		"movel	#Lberr1,%4@(8)\n\t"
+                "movec	%4,%/vbr\n\t"
+		"movel	%/sp,%1\n\t"
+		"moveq	#0,%0\n\t"
+		"tstb	%3@\n\t"  
+		"nop\n\t"
+		"moveq	#1,%0\n"
+                "Lberr1:\n\t"
+		"movel	%1,%/sp\n\t"
+		"movec	%2,%/vbr"
+		: "=&d" (ret), "=&r" (save_sp), "=&r" (save_vbr)
+		: "a" (regp), "a" (tmp_vectors)
+                );
+
+    return( ret );
+}
+  
+#if 0
+static int hwreg_present_bywrite( volatile void *regp,
+				 unsigned char val )
+
+{
+    int		ret;
+    long	save_sp, save_vbr;
+    static long tmp_vectors[3] = { 0, 0, (long)&&after_test };
+	
+    __asm__ __volatile__
+	(	"movec	%/vbr,%2\n\t"	/* save vbr value            */
+                "movec	%4,%/vbr\n\t"	/* set up temporary vectors  */
+		"movel	%/sp,%1\n\t"	/* save sp                   */
+		"moveq	#0,%0\n\t"	/* assume not present        */
+		"moveb	%5,%3@\n\t"	/* write the hardware reg    */
+		"cmpb	%3@,%5\n\t"	/* compare it                */
+		"seq	%0"		/* comes here only if reg    */
+                                        /* is present                */
+		: "=d&" (ret), "=r&" (save_sp), "=r&" (save_vbr)
+		: "a" (regp), "r" (tmp_vectors), "d" (val)
+                );
+  after_test:
+    __asm__ __volatile__
+      (	"movel	%0,%/sp\n\t"		/* restore sp                */
+        "movec	%1,%/vbr"			/* restore vbr               */
+        : : "r" (save_sp), "r" (save_vbr) : "sp"
+	);
+
+    return( ret );
+}
+#endif
+
+/* Basically the same, but writes a value into a word register, protected
+ * by a bus error handler */
+
+static int hwreg_write( volatile void *regp, unsigned short val )
+{
+	int		ret;
+	long	save_sp, save_vbr;
+	long	tmp_vectors[3];
+
+	__asm__ __volatile__
+	(	"movec	%/vbr,%2\n\t"
+		"movel	#Lberr2,%4@(8)\n\t"
+		"movec	%4,%/vbr\n\t"
+		"movel	%/sp,%1\n\t"
+		"moveq	#0,%0\n\t"
+		"movew	%5,%3@\n\t"  
+		"nop	\n\t"	/* If this nop isn't present, 'ret' may already be
+				 * loaded with 1 at the time the bus error
+				 * happens! */
+		"moveq	#1,%0\n"
+	"Lberr2:\n\t"
+		"movel	%1,%/sp\n\t"
+		"movec	%2,%/vbr"
+		: "=&d" (ret), "=&r" (save_sp), "=&r" (save_vbr)
+		: "a" (regp), "a" (tmp_vectors), "g" (val)
+	);
+
+	return( ret );
+}
+
+/* ++roman: This is a more elaborate test for an SCC chip, since the plain
+ * Medusa board generates DTACK at the SCC's standard addresses, but a SCC
+ * board in the Medusa is possible. Also, the addresses where the ST_ESCC
+ * resides generate DTACK without the chip, too.
+ * The method is to write values into the interrupt vector register, that
+ * should be readable without trouble (from channel A!).
+ */
+
+static int scc_test( volatile char *ctla )
+{
+	if (!hwreg_present( ctla ))
+		return( 0 );
+	MFPDELAY();
+
+	*ctla = 2; MFPDELAY();
+	*ctla = 0x40; MFPDELAY();
+	
+	*ctla = 2; MFPDELAY();
+	if (*ctla != 0x40) return( 0 );
+	MFPDELAY();
+
+	*ctla = 2; MFPDELAY();
+	*ctla = 0x60; MFPDELAY();
+	
+	*ctla = 2; MFPDELAY();
+	if (*ctla != 0x60) return( 0 );
+
+	return( 1 );
+}
+
+void config_atari(void)
+{
+    mach_sched_init      = atari_sched_init;
+    mach_keyb_init       = atari_keyb_init;
+    mach_kbdrate         = atari_kbdrate;
+    mach_kbd_leds        = atari_kbd_leds;
+    mach_init_INTS       = atari_init_INTS;
+    mach_add_isr         = atari_add_isr;
+    mach_remove_isr      = atari_remove_isr;
+    mach_enable_irq      = atari_enable_irq;
+    mach_disable_irq     = atari_disable_irq;
+    mach_get_irq_list	 = atari_get_irq_list;
+    mach_gettimeoffset   = atari_gettimeoffset;
+    mach_check_partition = atari_check_partition;
+    mach_mksound         = atari_mksound;
+    mach_reset           = atari_reset;
+#ifdef CONFIG_BLK_DEV_FD
+    mach_floppy_init	 = atari_floppy_init;
+    mach_floppy_setup	 = atari_floppy_setup;
+#endif
+    conswitchp	         = &fb_con;
+    waitbut		 = atari_waitbut;
+    mach_fb_init         = atari_fb_init;
+    mach_max_dma_address = 0xffffff;
+    mach_debug_init	 = atari_debug_init;
+    mach_video_setup	 = atari_video_setup;
+    kd_mksound		 = atari_mksound;
+
+    /* ++bjoern: 
+     * Determine hardware present
+     */
+
+    printk( "Atari hardware found: " );
+    if (is_medusa) {
+        /* There's no Atari video hardware on the Medusa, but all the
+         * addresses below generate a DTACK so no bus error occurs! */
+    }
+    else if (hwreg_present( f030_xreg )) {
+	ATARIHW_SET(VIDEL_SHIFTER);
+        printk( "VIDEL " );
+        /* This is a temporary hack: If there is Falcon video
+         * hardware, we assume that the ST-DMA serves SCSI instead of
+         * ACSI. In the future, there should be a better method for
+         * this...
+         */
+	ATARIHW_SET(ST_SCSI);
+        printk( "STDMA-SCSI " );
+    }
+    else if (hwreg_present( tt_palette )) {
+	ATARIHW_SET(TT_SHIFTER);
+        printk( "TT_SHIFTER " );
+    }
+    else if (hwreg_present( &shifter.bas_hi )) {
+        if (hwreg_present( &shifter.bas_lo ) &&
+	    (shifter.bas_lo = 0x0aau, shifter.bas_lo == 0x0aau)) {
+	    ATARIHW_SET(EXTD_SHIFTER);
+            printk( "EXTD_SHIFTER " );
+        }
+        else {
+	    ATARIHW_SET(STND_SHIFTER);
+            printk( "STND_SHIFTER " );
+        }
+    }
+    if (hwreg_present( &mfp.par_dt_reg )) {
+	ATARIHW_SET(ST_MFP);
+        printk( "ST_MFP " );
+    }
+    if (hwreg_present( &tt_mfp.par_dt_reg )) {
+	ATARIHW_SET(TT_MFP);
+        printk( "TT_MFP " );
+    }
+    if (hwreg_present( &tt_scsi_dma.dma_addr_hi )) {
+	ATARIHW_SET(SCSI_DMA);
+        printk( "TT_SCSI_DMA " );
+    }
+    if (hwreg_present( &st_dma.dma_hi )) {
+	ATARIHW_SET(STND_DMA);
+        printk( "STND_DMA " );
+    }
+    if (is_medusa || /* The ST-DMA address registers aren't readable
+                      * on all Medusas, so the test below may fail */
+        (hwreg_present( &st_dma.dma_vhi ) &&
+         (st_dma.dma_vhi = 0x55) && (st_dma.dma_hi = 0xaa) &&
+         st_dma.dma_vhi == 0x55 && st_dma.dma_hi == 0xaa &&
+         (st_dma.dma_vhi = 0xaa) && (st_dma.dma_hi = 0x55) &&
+         st_dma.dma_vhi == 0xaa && st_dma.dma_hi == 0x55)) {
+	ATARIHW_SET(EXTD_DMA);
+        printk( "EXTD_DMA " );
+    }
+    if (hwreg_present( &tt_scsi.scsi_data )) {
+	ATARIHW_SET(TT_SCSI);
+        printk( "TT_SCSI " );
+    }
+    if (hwreg_present( &sound_ym.rd_data_reg_sel )) {
+	ATARIHW_SET(YM_2149);
+        printk( "YM2149 " );
+    }
+    if (!is_medusa && hwreg_present( &tt_dmasnd.ctrl )) {
+	ATARIHW_SET(PCM_8BIT);
+        printk( "PCM " );
+    }
+    if (hwreg_present( (void *)(0xffff8940) )) {
+	ATARIHW_SET(CODEC);
+        printk( "CODEC " );
+    }
+    if (hwreg_present( &tt_scc_dma.dma_ctrl ) &&
+#if 0
+	/* This test sucks! Who knows some better? */
+	(tt_scc_dma.dma_ctrl = 0x01, (tt_scc_dma.dma_ctrl & 1) == 1) &&
+	(tt_scc_dma.dma_ctrl = 0x00, (tt_scc_dma.dma_ctrl & 1) == 0)
+#else
+	!is_medusa
+#endif
+	) {
+	ATARIHW_SET(SCC_DMA);
+        printk( "SCC_DMA " );
+    }
+    if (scc_test( &scc.cha_a_ctrl )) {
+	ATARIHW_SET(SCC);
+        printk( "SCC " );
+    }
+    if (scc_test( &st_escc.cha_b_ctrl )) {
+	ATARIHW_SET( ST_ESCC );
+	printk( "ST_ESCC " );
+    }
+    if (hwreg_present( &tt_scu.sys_mask )) {
+	ATARIHW_SET(SCU);
+	/* Assume a VME bus if there's a SCU */
+	ATARIHW_SET( VME );
+        printk( "VME SCU " );
+    }
+    if (hwreg_present( (void *)(0xffff9210) )) {
+	ATARIHW_SET(ANALOG_JOY);
+        printk( "ANALOG_JOY " );
+    }
+    if (hwreg_present( blitter.halftone )) {
+	ATARIHW_SET(BLITTER);
+        printk( "BLITTER " );
+    }
+    if (hwreg_present( (void *)(ATA_HD_BASE+ATA_HD_CMD) )) {
+	ATARIHW_SET(IDE);
+        printk( "IDE " );
+    }
+#if 1 /* This maybe wrong */
+    if (!is_medusa &&
+	hwreg_present( &tt_microwire.data ) &&
+	hwreg_present( &tt_microwire.mask ) &&
+	(tt_microwire.mask = 0x7ff,
+	 tt_microwire.data = MW_LM1992_PSG_HIGH | MW_LM1992_ADDR,
+	 tt_microwire.data != 0)) {
+	ATARIHW_SET(MICROWIRE);
+	while (tt_microwire.mask != 0x7ff) ;
+        printk( "MICROWIRE " );
+    }
+#endif
+    if (hwreg_present( &tt_rtc.regsel )) {
+	ATARIHW_SET(TT_CLK);
+        printk( "TT_CLK " );
+        mach_gettod = atari_gettod;
+        mach_hwclk = atari_hwclk;
+        mach_set_clock_mmss = atari_set_clock_mmss;
+    }
+    if (hwreg_present( &mste_rtc.sec_ones)) {
+	ATARIHW_SET(MSTE_CLK);
+        printk( "MSTE_CLK ");
+        mach_gettod = atari_mste_gettod;
+        mach_hwclk = atari_mste_hwclk;
+        mach_set_clock_mmss = atari_mste_set_clock_mmss;
+    }
+    if (!is_medusa &&
+	hwreg_present( &dma_wd.fdc_speed ) &&
+	hwreg_write( &dma_wd.fdc_speed, 0 )) {
+	    ATARIHW_SET(FDCSPEED);
+	    printk( "FDC_SPEED ");
+    }
+    if (!ATARIHW_PRESENT(ST_SCSI)) {
+	ATARIHW_SET(ACSI);
+        printk( "ACSI " );
+    }
+    printk("\n");
+
+    if (m68k_is040or060)
+        /* Now it seems to be safe to turn of the tt0 transparent
+         * translation (the one that must not be turned off in
+         * head.S...)
+         */
+        __asm__ volatile ("moveq #0,%/d0;"
+                          ".long 0x4e7b0004;"	/* movec d0,itt0 */
+                          ".long 0x4e7b0006;"	/* movec d0,dtt0 */
+						  : /* no outputs */
+						  : /* no inputs */
+						  : "d0");
+	
+    /* allocator for memory that must reside in st-ram */
+    atari_stram_init ();
+
+    /* Set up a mapping for the VMEbus address region:
+     *
+     * VME is either at phys. 0xfexxxxxx (TT) or 0xa00000..0xdfffff
+     * (MegaSTE) In both cases, the whole 16 MB chunk is mapped at
+     * 0xfe000000 virt., because this can be done with a single
+     * transparent translation. On the 68040, lots of often unused
+     * page tables would be needed otherwise. On a MegaSTE or similar,
+     * the highest byte is stripped off by hardware due to the 24 bit
+     * design of the bus.
+     */
+
+    if (!m68k_is040or060) {
+        unsigned long	tt1_val;
+        tt1_val = 0xfe008543;	/* Translate 0xfexxxxxx, enable, cache
+                                 * inhibit, read and write, FDC mask = 3,
+                                 * FDC val = 4 -> Supervisor only */
+        __asm__ __volatile__ ( "pmove	%0@,%/tt1" : : "a" (&tt1_val) );
+    }
+    else {
+        __asm__ __volatile__
+            ( "movel %0,%/d0\n\t"
+              ".long 0x4e7b0005\n\t"	/* movec d0,itt1 */
+              ".long 0x4e7b0007"	/* movec d0,dtt1 */
+              :
+              : "g" (0xfe00a040)	/* Translate 0xfexxxxxx, enable,
+                                         * supervisor only, non-cacheable/
+                                         * serialized, writable */
+              : "d0" );
+
+    }
+}
+
+void atari_sched_init (isrfunc timer_routine)
+{
+    /* set Timer C data Register */
+    mfp.tim_dt_c = INT_TICKS;
+    /* start timer C, div = 1:100 */
+    mfp.tim_ct_cd = (mfp.tim_ct_cd & 15) | 0x60; 
+    /* install interrupt service routine for MFP Timer C */
+    add_isr (IRQ_MFP_TIMC, timer_routine, IRQ_TYPE_SLOW, NULL, "timer");
+}
+
+/* ++andreas: gettimeoffset fixed to check for pending interrupt */
+
+#define TICK_SIZE 10000
+  
+/* This is always executed with interrupts disabled.  */
+unsigned long atari_gettimeoffset (void)
+{
+  unsigned long ticks, offset = 0;
+
+  /* read MFP timer C current value */
+  ticks = mfp.tim_dt_c;
+  /* The probability of underflow is less than 2% */
+  if (ticks > INT_TICKS - INT_TICKS / 50)
+    /* Check for pending timer interrupt */
+    if (mfp.int_pn_b & (1 << 5))
+      offset = TICK_SIZE;
+
+  ticks = INT_TICKS - ticks;
+  ticks = ticks * 10000L / INT_TICKS;
+
+  return ticks + offset;
+}
+
+
+static void
+mste_read(struct MSTE_RTC *val)
+{
+#define COPY(v) val->v=(mste_rtc.v & 0xf)
+	do {
+		COPY(sec_ones) ; COPY(sec_tens) ; COPY(min_ones) ; 
+		COPY(min_tens) ; COPY(hr_ones) ; COPY(hr_tens) ; 
+		COPY(weekday) ; COPY(day_ones) ; COPY(day_tens) ; 
+		COPY(mon_ones) ; COPY(mon_tens) ; COPY(year_ones) ;
+		COPY(year_tens) ;
+	/* prevent from reading the clock while it changed */
+	} while (val->sec_ones != (mste_rtc.sec_ones & 0xf));
+#undef COPY
+}
+
+static void
+mste_write(struct MSTE_RTC *val)
+{
+#define COPY(v) mste_rtc.v=val->v
+	do {
+		COPY(sec_ones) ; COPY(sec_tens) ; COPY(min_ones) ; 
+		COPY(min_tens) ; COPY(hr_ones) ; COPY(hr_tens) ; 
+		COPY(weekday) ; COPY(day_ones) ; COPY(day_tens) ; 
+		COPY(mon_ones) ; COPY(mon_tens) ; COPY(year_ones) ;
+		COPY(year_tens) ;
+	/* prevent from writing the clock while it changed */
+	} while (val->sec_ones != (mste_rtc.sec_ones & 0xf));
+#undef COPY
+}
+
+#define	RTC_READ(reg)				\
+    ({	unsigned char	__val;			\
+		outb(reg,&tt_rtc.regsel);	\
+		__val = tt_rtc.data;		\
+		__val;				\
+	})
+
+#define	RTC_WRITE(reg,val)			\
+    do {					\
+		outb(reg,&tt_rtc.regsel);	\
+		tt_rtc.data = (val);		\
+	} while(0)
+
+
+void atari_mste_gettod (int *yearp, int *monp, int *dayp,
+			int *hourp, int *minp, int *secp)
+{
+    int hr24=0;
+    struct MSTE_RTC val;
+
+    mste_rtc.mode=(mste_rtc.mode | 1);
+    hr24=mste_rtc.mon_tens & 1;
+    mste_rtc.mode=(mste_rtc.mode & ~1);
+
+    mste_read(&val);
+    *secp = val.sec_ones + val.sec_tens * 10;
+    *minp = val.min_ones + val.min_tens * 10;
+    if (hr24)
+        *hourp = val.hr_ones + val.hr_tens * 10;
+    else {
+        *hourp = val.hr_ones + (val.hr_tens & 1) * 10;
+        if (val.hr_tens & 2)
+            *hourp += 12;
+    }
+    *dayp = val.day_ones + val.day_tens * 10;
+    *monp = val.mon_ones + val.mon_tens * 10;
+    *yearp = val.year_ones + val.year_tens * 10 + 80;	
+}
+
+  
+void atari_gettod (int *yearp, int *monp, int *dayp,
+		   int *hourp, int *minp, int *secp)
+{
+    unsigned char	ctrl;
+    unsigned short tos_version;
+		
+    while (!(RTC_READ(RTC_FREQ_SELECT) & RTC_UIP)) ;
+    while (RTC_READ(RTC_FREQ_SELECT) & RTC_UIP) ;
+
+    *secp  = RTC_READ(RTC_SECONDS);
+    *minp  = RTC_READ(RTC_MINUTES);
+    *hourp = RTC_READ(RTC_HOURS);
+    *dayp  = RTC_READ(RTC_DAY_OF_MONTH);
+    *monp  = RTC_READ(RTC_MONTH);
+    *yearp = RTC_READ(RTC_YEAR);
+
+    ctrl = RTC_READ(RTC_CONTROL); 
+
+    if (!(ctrl & RTC_DM_BINARY)) {
+        BCD_TO_BIN(*secp);
+        BCD_TO_BIN(*minp);
+        BCD_TO_BIN(*hourp);
+        BCD_TO_BIN(*dayp);
+        BCD_TO_BIN(*monp);
+        BCD_TO_BIN(*yearp);
+    }
+    if (!(ctrl & RTC_24H)) {
+        if (*hourp & 0x80) {
+            *hourp &= ~0x80;
+            *hourp += 12;
+        }
+    }
+    /* Adjust values (let the setup valid) */
+
+    /* Fetch tos version at Physical 2 */
+    /* We my not be able to access this address if the kernel is
+       loaded to st ram, since the first page is unmapped.  On the
+       Medusa this is always the case and there is nothing we can do
+       about this, so we just assume the smaller offset.  For the TT
+       we use the fact that in head.S we have set up a mapping
+       0xFFxxxxxx -> 0x00xxxxxx, so that the first 16MB is accessible
+       in the last 16MB of the address space. */
+    tos_version = is_medusa ? 0xfff : *(unsigned short *)0xFF000002;
+    *yearp += (tos_version < 0x306) ? 70 : 68;
+}
+
+#define HWCLK_POLL_INTERVAL	5
+
+int atari_mste_hwclk( int op, struct hwclk_time *t )
+{
+    int hour, year;
+    int hr24=0;
+    struct MSTE_RTC val;
+    
+    mste_rtc.mode=(mste_rtc.mode | 1);
+    hr24=mste_rtc.mon_tens & 1;
+    mste_rtc.mode=(mste_rtc.mode & ~1);
+
+    if (op) {
+        /* write: prepare values */
+        
+        val.sec_ones = t->sec % 10;
+        val.sec_tens = t->sec / 10;
+        val.min_ones = t->min % 10;
+        val.min_tens = t->min / 10;
+        hour = t->hour;
+        val.hr_ones = hour % 10;
+        val.hr_tens = hour / 10;
+        if (!hr24  && hour > 11) {
+            hour -= 12;
+            val.hr_ones = hour % 10;
+            val.hr_tens = (hour / 10) | 2;
+        }
+        val.day_ones = t->day % 10;
+        val.day_tens = t->day / 10;
+        val.mon_ones = (t->mon+1) % 10;
+        val.mon_tens = (t->mon+1) / 10;
+        year = t->year - 80;
+        val.year_ones = year % 10;
+        val.year_tens = year / 10;
+        val.weekday = t->wday;
+        mste_write(&val);
+        mste_rtc.mode=(mste_rtc.mode | 1);
+        val.year_ones = (year % 4);	/* leap year register */
+        mste_rtc.mode=(mste_rtc.mode & ~1);
+    }
+    else {
+        mste_read(&val);
+        t->sec = val.sec_ones + val.sec_tens * 10;
+        t->min = val.min_ones + val.min_tens * 10;
+        if (hr24)
+            t->hour = val.hr_ones + val.hr_tens * 10;
+        else {
+            t->hour = val.hr_ones + (val.hr_tens & 1) * 10;
+            if (val.hr_tens & 2)
+                t->hour += 12;
+        }
+	t->day = val.day_ones + val.day_tens * 10;
+        t->mon = val.mon_ones + val.mon_tens * 10 - 1;
+        t->year = val.year_ones + val.year_tens * 10 + 80;
+        t->wday = val.weekday;
+    }
+    return 0;
+}
+
+int atari_hwclk( int op, struct hwclk_time *t )
+{
+    int sec=0, min=0, hour=0, day=0, mon=0, year=0, wday=0; 
+    unsigned long 	flags;
+    unsigned short	tos_version;
+    unsigned char	ctrl;
+
+    /* Tos version at Physical 2.  See above for explanation why we
+       cannot use PTOV(2).  */
+    tos_version = is_medusa ? 0xfff : *(unsigned short *)0xff000002;
+
+    ctrl = RTC_READ(RTC_CONTROL); /* control registers are
+                                   * independant from the UIP */
+
+    if (op) {
+        /* write: prepare values */
+        
+        sec  = t->sec;
+        min  = t->min;
+        hour = t->hour;
+        day  = t->day;
+        mon  = t->mon + 1;
+        year = t->year - ((tos_version < 0x306) ? 70 : 68);
+        wday = t->wday + (t->wday >= 0);
+        
+        if (!(ctrl & RTC_24H) && hour > 11) {
+            hour -= 12;
+            hour |= 0x80;
+        }
+        
+        if (!(ctrl & RTC_DM_BINARY)) {
+            BIN_TO_BCD(sec);
+            BIN_TO_BCD(min);
+            BIN_TO_BCD(hour);
+            BIN_TO_BCD(day);
+            BIN_TO_BCD(mon);
+            BIN_TO_BCD(year);
+            if (wday >= 0) BIN_TO_BCD(wday);
+        }
+    }
+    
+    /* Reading/writing the clock registers is a bit critical due to
+     * the regular update cycle of the RTC. While an update is in
+     * progress, registers 0..9 shouldn't be touched.
+     * The problem is solved like that: If an update is currently in
+     * progress (the UIP bit is set), the process sleeps for a while
+     * (50ms). This really should be enough, since the update cycle
+     * normally needs 2 ms.
+     * If the UIP bit reads as 0, we have at least 244 usecs until the
+     * update starts. This should be enough... But to be sure,
+     * additionally the RTC_SET bit is set to prevent an update cycle.
+     */
+
+    while( RTC_READ(RTC_FREQ_SELECT) & RTC_UIP ) {
+        current->state = TASK_INTERRUPTIBLE;
+        current->timeout = jiffies + HWCLK_POLL_INTERVAL;
+        schedule();
+    }
+
+    save_flags(flags);
+    cli();
+    RTC_WRITE( RTC_CONTROL, ctrl | RTC_SET );
+    if (!op) {
+        sec  = RTC_READ( RTC_SECONDS );
+        min  = RTC_READ( RTC_MINUTES );
+        hour = RTC_READ( RTC_HOURS );
+        day  = RTC_READ( RTC_DAY_OF_MONTH );
+        mon  = RTC_READ( RTC_MONTH );
+        year = RTC_READ( RTC_YEAR );
+        wday = RTC_READ( RTC_DAY_OF_WEEK );
+    }
+    else {
+        RTC_WRITE( RTC_SECONDS, sec );
+        RTC_WRITE( RTC_MINUTES, min );
+        RTC_WRITE( RTC_HOURS, hour );
+        RTC_WRITE( RTC_DAY_OF_MONTH, day );
+        RTC_WRITE( RTC_MONTH, mon );
+        RTC_WRITE( RTC_YEAR, year );
+        if (wday >= 0) RTC_WRITE( RTC_DAY_OF_WEEK, wday );
+    }
+    RTC_WRITE( RTC_CONTROL, ctrl & ~RTC_SET );
+    restore_flags(flags);
+
+    if (!op) {
+        /* read: adjust values */
+        
+        if (!(ctrl & RTC_DM_BINARY)) {
+            BCD_TO_BIN(sec);
+            BCD_TO_BIN(min);
+            BCD_TO_BIN(hour);
+            BCD_TO_BIN(day);
+            BCD_TO_BIN(mon);
+            BCD_TO_BIN(year);
+            BCD_TO_BIN(wday);
+        }
+
+        if (!(ctrl & RTC_24H)) {
+            if (hour & 0x80) {
+                hour &= ~0x80;
+                hour += 12;
+            }
+        }
+
+        t->sec  = sec;
+        t->min  = min;
+        t->hour = hour;
+        t->day  = day;
+        t->mon  = mon - 1;
+        t->year = year + ((tos_version < 0x306) ? 70 : 68);
+        t->wday = wday - 1;
+    }
+
+    return( 0 );
+}
+
+
+int atari_mste_set_clock_mmss (unsigned long nowtime)
+{
+    short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60;
+    struct MSTE_RTC val;
+    unsigned char rtc_minutes;
+
+    mste_read(&val);  
+    rtc_minutes= val.min_ones + val.min_tens * 10;
+    if ((rtc_minutes < real_minutes
+         ? real_minutes - rtc_minutes
+         : rtc_minutes - real_minutes) < 30)
+    {
+        val.sec_ones = real_seconds % 10;
+        val.sec_tens = real_seconds / 10;
+        val.min_ones = real_minutes % 10;
+        val.min_tens = real_minutes / 10;
+        mste_write(&val);
+    }
+    else
+        return -1;
+    return 0;
+}
+
+int atari_set_clock_mmss (unsigned long nowtime)
+{
+    int retval = 0;
+    short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60;
+    unsigned char save_control, save_freq_select, rtc_minutes;
+
+    save_control = RTC_READ (RTC_CONTROL); /* tell the clock it's being set */
+    RTC_WRITE (RTC_CONTROL, save_control | RTC_SET);
+
+    save_freq_select = RTC_READ (RTC_FREQ_SELECT); /* stop and reset prescaler */
+    RTC_WRITE (RTC_FREQ_SELECT, save_freq_select | RTC_DIV_RESET2);
+
+    rtc_minutes = RTC_READ (RTC_MINUTES);
+    if (!(save_control & RTC_DM_BINARY))
+        BCD_TO_BIN (rtc_minutes);
+
+    /* Since we're only adjusting minutes and seconds, don't interfere
+       with hour overflow.  This avoids messing with unknown time zones
+       but requires your RTC not to be off by more than 30 minutes.  */
+    if ((rtc_minutes < real_minutes
+         ? real_minutes - rtc_minutes
+         : rtc_minutes - real_minutes) < 30)
+        {
+            if (!(save_control & RTC_DM_BINARY))
+                {
+                    BIN_TO_BCD (real_seconds);
+                    BIN_TO_BCD (real_minutes);
+                }
+            RTC_WRITE (RTC_SECONDS, real_seconds);
+            RTC_WRITE (RTC_MINUTES, real_minutes);
+        }
+    else
+        retval = -1;
+
+    RTC_WRITE (RTC_FREQ_SELECT, save_freq_select);
+    RTC_WRITE (RTC_CONTROL, save_control);
+    return retval;
+}
+
+
+void atari_waitbut (void)
+{
+    /* sorry, no-op */
+}
+
+
+static inline void ata_mfp_out (char c)
+{
+    while (!(mfp.trn_stat & 0x80)) /* wait for tx buf empty */
+	barrier ();
+    mfp.usart_dta = c;
+}
+
+void ata_mfp_print (const char *str)
+{
+    for( ; *str; ++str ) {
+	if (*str == '\n')
+	    ata_mfp_out( '\r' );
+	ata_mfp_out( *str );
+    }
+}
+
+static inline void ata_scc_out (char c)
+{
+    do {
+	MFPDELAY();
+    } while (!(scc.cha_b_ctrl & 0x04)); /* wait for tx buf empty */
+    MFPDELAY();
+    scc.cha_b_data = c;
+}
+
+void ata_scc_print (const char *str)
+{
+    for( ; *str; ++str ) {
+	if (*str == '\n')
+	    ata_scc_out( '\r' );
+	ata_scc_out( *str );
+    }
+}
+
+static int ata_par_out (char c)
+{
+    extern unsigned long loops_per_sec;
+    unsigned char tmp;
+    /* This a some-seconds timeout in case no printer is connected */
+    unsigned long i = loops_per_sec > 1 ? loops_per_sec : 10000000;
+
+    while( (mfp.par_dt_reg & 1) && --i ) /* wait for BUSY == L */
+	;
+    if (!i) return( 0 );
+    
+    sound_ym.rd_data_reg_sel = 15;  /* select port B */
+    sound_ym.wd_data = c;           /* put char onto port */
+    sound_ym.rd_data_reg_sel = 14;  /* select port A */
+    tmp = sound_ym.rd_data_reg_sel;
+    sound_ym.wd_data = tmp & ~0x20; /* set strobe L */
+    MFPDELAY();                     /* wait a bit */
+    sound_ym.wd_data = tmp | 0x20;  /* set strobe H */
+    return( 1 );
+}
+
+void ata_par_print (const char *str)
+{
+    static int printer_present = 1;
+
+    if (!printer_present)
+	return;
+
+    for( ; *str; ++str ) {
+	if (*str == '\n')
+	    if (!ata_par_out( '\r' )) {
+		printer_present = 0;
+		return;
+	    }
+	if (!ata_par_out( *str )) {
+	    printer_present = 0;
+	    return;
+	}
+    }
+}
+
+
+void atari_debug_init( void )
+{
+    extern void (*debug_print_proc)(const char *);
+    extern char m68k_debug_device[];
+    
+    if (!strcmp( m68k_debug_device, "ser" )) {
+	/* defaults to ser2 for a Falcon and ser1 otherwise */
+	strcpy( m68k_debug_device, 
+		((boot_info.bi_atari.mch_cookie >> 16) == ATARI_MCH_FALCON) ?
+		"ser2" : "ser1" );
+
+    }
+
+    if (!strcmp( m68k_debug_device, "ser1" )) {
+	/* ST-MFP Modem1 serial port */
+	mfp.trn_stat  &= ~0x01; /* disable TX */
+	mfp.usart_ctr  = 0x88;  /* clk 1:16, 8N1 */
+	mfp.tim_ct_cd &= 0x70;  /* stop timer D */
+	mfp.tim_dt_d   = 2;     /* 9600 bps */
+	mfp.tim_ct_cd |= 0x01;  /* start timer D, 1:4 */
+	mfp.trn_stat  |= 0x01;  /* enable TX */
+	debug_print_proc = ata_mfp_print;
+    }
+    else if (!strcmp( m68k_debug_device, "ser2" )) {
+	/* SCC Modem2 serial port */
+	static unsigned char *p, scc_table[] = {
+	    9, 12,		/* Reset */
+	    4, 0x44,		/* x16, 1 stopbit, no parity */
+	    3, 0xc0,		/* receiver: 8 bpc */
+	    5, 0xe2,		/* transmitter: 8 bpc, assert dtr/rts */
+	    9, 0,		/* no interrupts */
+	    10, 0,		/* NRZ */
+	    11, 0x50,		/* use baud rate generator */
+	    12, 24, 13, 0,	/* 9600 baud */
+	    14, 2, 14, 3,	/* use master clock for BRG, enable */
+	    3, 0xc1,		/* enable receiver */
+	    5, 0xea,		/* enable transmitter */
+	    0
+	};
+	    
+	(void)scc.cha_b_ctrl; /* reset reg pointer */
+	for( p = scc_table; *p != 0; ) {
+	    scc.cha_b_ctrl = *p++;
+	    MFPDELAY();
+	    scc.cha_b_ctrl = *p++;
+	    MFPDELAY();
+	}
+	debug_print_proc = ata_scc_print;
+    }
+    else if (!strcmp( m68k_debug_device, "par" )) {
+	/* parallel printer */
+	atari_turnoff_irq( IRQ_MFP_BUSY ); /* avoid ints */
+	sound_ym.rd_data_reg_sel = 7;  /* select mixer control */
+	sound_ym.wd_data = 0xff;       /* sound off, ports are output */
+	sound_ym.rd_data_reg_sel = 15; /* select port B */
+	sound_ym.wd_data = 0;          /* no char */
+	sound_ym.rd_data_reg_sel = 14; /* select port A */
+	sound_ym.wd_data = sound_ym.rd_data_reg_sel | 0x20; /* strobe H */
+	debug_print_proc = ata_par_print;
+    }
+    else
+	debug_print_proc = NULL;
+}
+
+
+void ata_serial_print (const char *str)
+{
+  int c;
+
+  while (c = *str++, c != 0)
+    {
+      if (c == '\n')
+	{
+	  while (!(mfp.trn_stat & (1 << 7)))
+	    barrier ();
+	  mfp.usart_dta = '\r';
+	}
+      while (!(mfp.trn_stat & (1 << 7)))
+	barrier ();
+      mfp.usart_dta = c;
+    }
+}
+
+/* ++roman:
+ *
+ * This function does a reset on machines that lack the ability to
+ * assert the processor's _RESET signal somehow via hardware. It is
+ * based on the fact that you can find the initial SP and PC values
+ * after a reset at physical addresses 0 and 4. This works pretty well
+ * for Atari machines, since the lowest 8 bytes of physical memory are
+ * really ROM (mapped by hardware). For other 680x0 machines: don't
+ * know if it works...
+ *
+ * To get the values at addresses 0 and 4, the MMU better is turned
+ * off first. After that, we have to jump into physical address space
+ * (the PC before the pmove statement points to the virtual address of
+ * the code). Getting that physical address is not hard, but the code
+ * becomes a bit complex since I've tried to ensure that the jump
+ * statement after the pmove is in the cache already (otherwise the
+ * processor can't fetch it!). For that, the code first jumps to the
+ * jump statement with the (virtual) address of the pmove section in
+ * an address register . The jump statement is surely in the cache
+ * now. After that, that physical address of the reset code is loaded
+ * into the same address register, pmove is done and the same jump
+ * statements goes to the reset code. Since there are not many
+ * statements between the two jumps, I hope it stays in the cache.
+ *
+ * The C code makes heavy use of the GCC features that you can get the
+ * address of a C label. No hope to compile this with another compiler
+ * than GCC!
+ */
+  
+/* ++andreas: no need for complicated code, just depend on prefetch */
+
+void atari_reset (void)
+{
+    long tc_val = 0;
+    long reset_addr;
+
+    /* On the Medusa, phys. 0x4 may contain garbage because it's no
+       ROM.  See above for explanation why we cannot use PTOV(4). */
+    reset_addr = is_medusa ? 0xe00030 : *(unsigned long *) 0xff000004;
+
+    acia.key_ctrl = ACIA_RESET;             /* reset ACIA for switch off OverScan, if it's active */
+
+    /* processor independent: turn off interrupts and reset the VBR;
+     * the caches must be left enabled, else prefetching the final jump
+     * instruction doesn't work. */
+    cli();
+    __asm__ __volatile__
+	("moveq	#0,%/d0\n\t"
+	 "movec	%/d0,%/vbr"
+	 : : : "d0" );
+    
+    if (m68k_is040or060) {
+        unsigned long jmp_addr040 = VTOP(&&jmp_addr_label040);
+	if (m68k_is040or060 == 6) {
+	    /* 68060: clear PCR to turn off superscalar operation */
+	    __asm__ __volatile__
+		("moveq	#0,%/d0\n\t"
+		 ".long	0x4e7b0808"	/* movec d0,pcr */
+		 : : : "d0" );
+	}
+	    
+        __asm__ __volatile__
+            ("movel    %0,%/d0\n\t"
+             "andl     #0xff000000,%/d0\n\t"
+             "orw      #0xe020,%/d0\n\t"   /* map 16 MB, enable, cacheable */
+             ".long    0x4e7b0004\n\t"   /* movec d0,itt0 */
+             ".long    0x4e7b0006\n\t"   /* movec d0,dtt0 */
+             "jmp   %0@\n\t"
+             : /* no outputs */
+             : "a" (jmp_addr040)
+             : "d0" );
+      jmp_addr_label040:
+        __asm__ __volatile__
+          ("moveq #0,%/d0\n\t"
+	   ".word 0xf4d8\n\t"		/* cinva i/d */
+	   ".word 0xf518\n\t"		/* pflusha */
+           ".long 0x4e7b0003\n\t"	/* movec d0,tc */
+           "jmp %0@"
+           : /* no outputs */
+           : "a" (reset_addr)
+           : "d0");
+    }
+    else
+        __asm__ __volatile__
+            ("pmove %0@,%/tc\n\t"
+             "jmp %1@"
+             : /* no outputs */
+             : "a" (&tc_val), "a" (reset_addr));
+}
+
+
+void atari_get_model(char *model)
+{
+    strcpy(model, "Atari ");
+    switch (boot_info.bi_atari.mch_cookie >> 16) {
+	case ATARI_MCH_ST:
+	    if (ATARIHW_PRESENT(MSTE_CLK))
+		strcat (model, "Mega ST");
+	    else
+		strcat (model, "ST");
+	    break;
+	case ATARI_MCH_STE:
+	    if ((boot_info.bi_atari.mch_cookie & 0xffff) == 0x10)
+		strcat (model, "Mega STE");
+	    else
+		strcat (model, "STE");
+	    break;
+	case ATARI_MCH_TT:
+	    if (is_medusa)
+		/* Medusa has TT _MCH cookie */
+		strcat (model, "Medusa");
+	    else
+		strcat (model, "TT");
+	    break;
+	case ATARI_MCH_FALCON:
+	    strcat (model, "Falcon");
+	    break;
+	default:
+	    sprintf (model + strlen (model), "(unknown mach cookie 0x%lx)",
+		     boot_info.bi_atari.mch_cookie);
+	    break;
+    }
+}
+
+
+int atari_get_hardware_list(char *buffer)
+{
+    int len = 0;
+
+    for (i = 0; i < boot_info.num_memory; i++)
+	len += sprintf (buffer+len, "\t%3ld MB at 0x%08lx (%s)\n",
+			boot_info.memory[i].size >> 20,
+			boot_info.memory[i].addr,
+			(boot_info.memory[i].addr & 0xff000000 ?
+			 "alternate RAM" : "ST-RAM"));
+
+#define ATARIHW_ANNOUNCE(name,str)				\
+    if (ATARIHW_PRESENT(name))			\
+	len += sprintf (buffer + len, "\t%s\n", str)
+
+    len += sprintf (buffer + len, "Detected hardware:\n");
+    ATARIHW_ANNOUNCE(STND_SHIFTER, "ST Shifter");
+    ATARIHW_ANNOUNCE(EXTD_SHIFTER, "STe Shifter");
+    ATARIHW_ANNOUNCE(TT_SHIFTER, "TT Shifter");
+    ATARIHW_ANNOUNCE(VIDEL_SHIFTER, "Falcon Shifter");
+    ATARIHW_ANNOUNCE(YM_2149, "Programmable Sound Generator");
+    ATARIHW_ANNOUNCE(PCM_8BIT, "PCM 8 Bit Sound");
+    ATARIHW_ANNOUNCE(CODEC, "CODEC Sound");
+    ATARIHW_ANNOUNCE(TT_SCSI, "SCSI Controller NCR5380 (TT style)");
+    ATARIHW_ANNOUNCE(ST_SCSI, "SCSI Controller NCR5380 (Falcon style)");
+    ATARIHW_ANNOUNCE(ACSI, "ACSI Interface");
+    ATARIHW_ANNOUNCE(IDE, "IDE Interface");
+    ATARIHW_ANNOUNCE(FDCSPEED, "8/16 Mhz Switch for FDC");
+    ATARIHW_ANNOUNCE(ST_MFP, "Multi Function Peripheral MFP 68901");
+    ATARIHW_ANNOUNCE(TT_MFP, "Second Multi Function Peripheral MFP 68901");
+    ATARIHW_ANNOUNCE(SCC, "Serial Communications Controller SCC 8530");
+    ATARIHW_ANNOUNCE(ST_ESCC, "Extended Serial Communications Controller SCC 85230");
+    ATARIHW_ANNOUNCE(ANALOG_JOY, "Paddle Interface");
+    ATARIHW_ANNOUNCE(MICROWIRE, "MICROWIRE(tm) Interface");
+    ATARIHW_ANNOUNCE(STND_DMA, "DMA Controller (24 bit)");
+    ATARIHW_ANNOUNCE(EXTD_DMA, "DMA Controller (32 bit)");
+    ATARIHW_ANNOUNCE(SCSI_DMA, "DMA Controller for NCR5380");
+    ATARIHW_ANNOUNCE(SCC_DMA, "DMA Controller for SCC");
+    ATARIHW_ANNOUNCE(TT_CLK, "Clock Chip MC146818A");
+    ATARIHW_ANNOUNCE(MSTE_CLK, "Clock Chip RP5C15");
+    ATARIHW_ANNOUNCE(SCU, "System Control Unit");
+    ATARIHW_ANNOUNCE(BLITTER, "Blitter");
+    ATARIHW_ANNOUNCE(VME, "VME Bus");
+
+    return(len);
+}
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/atari/joystick.c linux/arch/m68k/atari/joystick.c
--- v1.3.93/linux/arch/m68k/atari/joystick.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/atari/joystick.c	Sat Mar 30 14:11:04 1996
@@ -0,0 +1,141 @@
+/*
+ * Atari Joystick Driver for Linux
+ * by Robert de Vries (robert@and.nl) 19Jul93
+ *
+ * 16 Nov 1994 Andreas Schwab
+ * Support for three button mouse (shamelessly stolen from MiNT)
+ * third button wired to one of the joystick directions on joystick 1
+ */
+
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/major.h>
+
+#include <asm/atarikb.h>
+#include <asm/atari_joystick.h>
+#include <asm/atari_mouse.h>
+#include <asm/segment.h>
+
+#define MAJOR_NR    JOYSTICK_MAJOR
+
+#define	ANALOG_JOY(n)	(!(n & 0x80))
+#define	DIGITAL_JOY(n)	(n & 0x80)
+#define	DEVICE_NR(n)	(MINOR(n) & 0x7f)
+
+
+static struct joystick_status joystick[2];
+int atari_mouse_buttons; /* for three-button mouse */
+
+void atari_joystick_interrupt(char *buf)
+{
+    int j;
+/*    ikbd_joystick_disable(); */
+
+    j = buf[0] & 0x1;
+    joystick[j].dir   = buf[1] & 0xF;
+    joystick[j].fire  = (buf[1] & 0x80) >> 7;
+    joystick[j].ready = 1;
+    wake_up_interruptible(&joystick[j].wait);
+
+    /* For three-button mouse emulation fake a mouse packet */
+    if (atari_mouse_interrupt_hook &&
+	j == 1 && (buf[1] & 1) != ((atari_mouse_buttons & 2) >> 1))
+      {
+	char faked_packet[3];
+
+	atari_mouse_buttons = (atari_mouse_buttons & 5) | ((buf[1] & 1) << 1);
+	faked_packet[0] = (atari_mouse_buttons & 1) | 
+			  (atari_mouse_buttons & 4 ? 2 : 0);
+	faked_packet[1] = 0;
+	faked_packet[2] = 0;
+	atari_mouse_interrupt_hook (faked_packet);
+      }
+
+/*    ikbd_joystick_event_on(); */
+}
+
+static void release_joystick(struct inode *inode, struct file *file)
+{
+    int minor = DEVICE_NR(inode->i_rdev);
+
+    joystick[minor].active = 0;
+    joystick[minor].ready = 0;
+
+    if ((joystick[0].active == 0) && (joystick[1].active == 0))
+	ikbd_joystick_disable();
+}
+
+static int open_joystick(struct inode *inode, struct file *file)
+{
+    int minor = DEVICE_NR(inode->i_rdev);
+
+    if (!DIGITAL_JOY(inode->i_rdev) || minor > 1)
+	return -ENODEV;
+    if (joystick[minor].active)
+	return -EBUSY;
+    joystick[minor].active = 1;
+    joystick[minor].ready = 0;
+    ikbd_joystick_event_on();
+    return 0;
+}
+
+static int write_joystick(struct inode *inode, struct file *file,
+			  const char *buffer, int count)
+{
+    return -EINVAL;
+}
+
+static int read_joystick(struct inode *inode, struct file *file,
+			 char *buffer, int count)
+{
+    int minor = DEVICE_NR(inode->i_rdev);
+    int i;
+
+    if (count < 2)
+	return -EINVAL;
+    if (!joystick[minor].ready)
+	return -EAGAIN;
+    put_user(joystick[minor].fire, buffer++);
+    put_user(joystick[minor].dir, buffer++);
+    for (i = 0; i < count; i++)
+	put_user(0, buffer++);
+    joystick[minor].ready = 0;
+
+    return i;
+}
+
+static int joystick_select(struct inode *inode, struct file *file, int sel_type, select_table *wait)
+{
+    int minor = DEVICE_NR(inode->i_rdev);
+
+    if (sel_type != SEL_IN)
+	return 0;
+    if (joystick[minor].ready)
+	return 1;
+    select_wait(&joystick[minor].wait, wait);
+    return 0;
+}
+
+struct file_operations atari_joystick_fops = {
+	NULL,		/* joystick_seek */
+	read_joystick,
+	write_joystick,
+	NULL,		/* joystick_readdir */
+	joystick_select,
+	NULL,		/* joystick_ioctl */
+	NULL,		/* joystick_mmap */
+	open_joystick,
+	release_joystick
+};
+
+int atari_joystick_init(void)
+{
+    joystick[0].active = joystick[1].active = 0;
+    joystick[0].ready = joystick[1].ready = 0;
+    joystick[0].wait = joystick[1].wait = NULL;
+
+    if (register_chrdev(MAJOR_NR, "joystick", &atari_joystick_fops))
+	printk("unable to get major %d for joystick devices\n", MAJOR_NR);
+
+    return 0;
+}
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/atari/ksyms.c linux/arch/m68k/atari/ksyms.c
--- v1.3.93/linux/arch/m68k/atari/ksyms.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/atari/ksyms.c	Sat Apr 13 14:31:00 1996
@@ -0,0 +1,53 @@
+#include <linux/config.h>
+#include <linux/module.h>
+#include <asm/ptrace.h>
+#include <asm/traps.h>
+#include <asm/atarihw.h>
+#include <asm/atariints.h>
+#include <asm/atarikb.h>
+#include <asm/atari_joystick.h>
+#include <asm/atari_stdma.h>
+#if 0
+#include <asm/atari_acsi.h>
+#endif
+
+static struct symbol_table mach_atari_symbol_table = {
+#include <linux/symtab_begin.h>
+
+	X(is_medusa),
+	X(atari_register_vme_int),
+	X(stdma_lock),
+	X(stdma_release),
+	X(stdma_others_waiting),
+	X(stdma_islocked),
+
+	X(atari_mouse_buttons),
+	X(atari_mouse_interrupt_hook),
+	X(atari_MIDI_interrupt_hook),
+	X(ikbd_write),
+	X(ikbd_mouse_y0_top),
+	X(ikbd_mouse_thresh),
+	X(ikbd_mouse_rel_pos),
+	X(ikbd_mouse_disable),
+
+#if 0
+#ifdef CONFIG_ATARI_ACSI
+	X(acsi_wait_for_IRQ),
+	X(acsi_wait_for_noIRQ),
+	X(acsicmd_nodma),
+	X(acsi_getstatus),
+#ifdef CONFIG_ATARI_SLM
+	X(acsi_extstatus),
+	X(acsi_end_extstatus),
+	X(acsi_extcmd),
+#endif
+#endif
+#endif /* 0 */
+
+#include <linux/symtab_end.h>
+};
+
+void mach_atari_syms_export(void)
+{
+	register_symtab(&mach_atari_symbol_table);
+}
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/atari/stdma.c linux/arch/m68k/atari/stdma.c
--- v1.3.93/linux/arch/m68k/atari/stdma.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/atari/stdma.c	Fri Apr 19 02:35:24 1996
@@ -0,0 +1,194 @@
+
+/*
+ *  linux/atari/stmda.c
+ *
+ *  Copyright (C) 1994 Roman Hodek
+ *
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file README.legal in the main directory of this archive
+ * for more details.
+ */
+
+
+/* This file contains some function for controlling the access to the  */
+/* ST-DMA chip that may be shared between devices. Currently we have:  */
+/*   TT:     Floppy and ACSI bus                                       */
+/*   Falcon: Floppy and SCSI                                           */
+/*                                                                     */
+/* The controlling functions set up a wait queue for access to the     */
+/* ST-DMA chip. Callers to stdma_lock() that cannot granted access are */
+/* put onto a queue and waked up later if the owner calls              */
+/* stdma_release(). Additionally, the caller gives his interrupt       */
+/* service routine to stdma_lock().                                    */
+/*                                                                     */
+/* On the Falcon, the IDE bus uses just the ACSI/Floppy interrupt, but */
+/* not the ST-DMA chip itself. So falhd.c needs not to lock the        */
+/* chip. The interrupt is routed to falhd.c if IDE is configured, the  */
+/* model is a Falcon and the interrupt was caused by the HD controller */
+/* (can be determined by looking at its status register).              */
+
+
+#include <linux/types.h>
+#include <linux/genhd.h>
+#include <linux/sched.h>
+#include <asm/bootinfo.h>
+#include <asm/atari_stdma.h>
+#include <asm/atariints.h>
+#include <asm/atarihw.h>
+#include <asm/atarihdreg.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+
+static int stdma_locked = 0;			/* the semaphore */
+static isrfunc	stdma_isr = NULL;		/* int func to be called */
+static void	*stdma_isr_data = NULL;		/* data passed to isr */
+static struct wait_queue *stdma_wait = NULL;	/* wait queue for ST-DMA */
+
+
+
+
+/***************************** Prototypes *****************************/
+
+static void stdma_int (int irq, struct pt_regs *fp, void *dummy);
+
+/************************* End of Prototypes **************************/
+
+
+
+/*
+ * Function: void stdma_lock( isrfunc isr, void *data )
+ *
+ * Purpose: Trys to get a lock on the ST-DMA chip that is used by more
+ *   then one device driver. Waits on stdma_wait until lock is free.
+ *   stdma_lock() may not be called from an interrupt! You have to
+ *   get the lock in your main routine and release it when your
+ *   request is finished.
+ *
+ * Inputs: A interupt function that is called until the lock is
+ *   released.
+ *
+ * Returns: nothing
+ *
+ */
+
+void stdma_lock(isrfunc isr, void *data)
+{
+	unsigned long	oldflags;
+
+	save_flags(oldflags);
+	cli();		/* protect lock */
+
+	while(stdma_locked)
+		/* Since the DMA is used for file system purposes, we
+		 have to sleep uninterruptible (there may be locked
+		 buffers) */
+		sleep_on(&stdma_wait);
+
+	stdma_locked   = 1;
+	stdma_isr      = isr;
+	stdma_isr_data = data;
+	restore_flags(oldflags);
+}
+
+
+/*
+ * Function: void stdma_release( void )
+ *
+ * Purpose: Releases the lock on the ST-DMA chip. 
+ *
+ * Inputs: none
+ *
+ * Returns: nothing
+ *
+ */
+
+void stdma_release(void)
+{
+	unsigned long	oldflags;
+
+	save_flags(oldflags);
+	cli();
+	
+	stdma_locked   = 0;
+	stdma_isr      = NULL;
+	stdma_isr_data = NULL;
+	wake_up(&stdma_wait);
+
+	restore_flags(oldflags);
+}
+
+
+/*
+ * Function: int stdma_others_waiting( void )
+ *
+ * Purpose: Check if someone waits for the ST-DMA lock.
+ *
+ * Inputs: none
+ *
+ * Returns: 0 if noone is waiting, != 0 otherwise
+ *
+ */
+
+int stdma_others_waiting(void)
+{
+	return stdma_wait != NULL;
+}
+
+
+/*
+ * Function: int stdma_islocked( void )
+ *
+ * Purpose: Check if the ST-DMA is currently locked.
+ * Note: Returned status is only valid if ints are disabled while calling and
+ *       as long as they remain disabled.
+ *       If called with ints enabled, status can change only from locked to
+ *       unlocked, because ints may not lock the ST-DMA.
+ *
+ * Inputs: none
+ *
+ * Returns: != 0 if locked, 0 otherwise
+ *
+ */
+
+int stdma_islocked(void)
+{
+	return stdma_locked;
+}
+
+
+/*
+ * Function: void stdma_init( void )
+ *
+ * Purpose: Initialize the ST-DMA chip access controlling.
+ *   It sets up the interrupt and its service routine. The int is registered
+ *   as slow int, client devices have to live with that (no problem
+ *   currently).
+ *
+ * Inputs: none
+ *
+ * Return: nothing
+ *
+ */
+
+void stdma_init(void)
+{
+	stdma_isr = NULL;
+	add_isr(IRQ_MFP_FDC, stdma_int, IRQ_TYPE_SLOW, NULL,
+		"ST-DMA: floppy/ACSI/IDE/Falcon-SCSI");
+}
+
+
+/*
+ * Function: void stdma_int()
+ *
+ * Purpose: The interupt routine for the ST-DMA. It calls the isr
+ *   registered by stdma_lock().
+ *
+ */
+
+static void stdma_int(int irq, struct pt_regs *fp, void *dummy)
+{
+  if (stdma_isr)
+      (*stdma_isr)(irq, fp, stdma_isr_data);
+}
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/atari/stram.c linux/arch/m68k/atari/stram.c
--- v1.3.93/linux/arch/m68k/atari/stram.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/atari/stram.c	Wed Dec 27 22:44:28 1995
@@ -0,0 +1,243 @@
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <asm/bootinfo.h>
+#include <asm/atarihw.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+
+#if 0
+
+struct stram_desc
+  {
+    unsigned first:1;
+    unsigned last:1;
+    unsigned alloced:1;
+    unsigned length:24;
+  };
+
+#define DP(ptr) ((struct stram_desc *) (ptr))
+
+static unsigned long stramsize;
+static unsigned long stramaddr;
+
+void
+atari_stram_init (void)
+{
+  struct stram_desc *dp;
+  stramaddr = boot_info.bi_atari.stram_start;
+  stramsize = boot_info.bi_atari.stram_size;
+
+  /* initialize start boundary */
+  dp = DP (stramaddr);
+  dp->first = 1;
+  dp->alloced = 0;
+  dp->length = stramsize - 2 * sizeof (*dp);
+
+  /* initialize end boundary */
+  dp = DP (stramaddr + stramsize) - 1;
+  dp->last = 1;
+  dp->alloced = 0;
+  dp->length = stramsize - 2 * sizeof (*dp);
+
+#ifdef DEBUG
+  printk ("stram end boundary is %p, length is %d\n", dp,
+	  dp->length);
+#endif
+}
+
+void *
+atari_stram_alloc (long size)
+{
+  /* last chunk */
+  struct stram_desc *dp;
+  void *ptr;
+
+  /* round off */
+  size = (size + 3) & ~3;
+
+#ifdef DEBUG
+  printk ("stram_alloc: allocate %ld bytes\n", size);
+#endif
+
+  /*
+   * get pointer to descriptor for last chunk by 
+   * going backwards from end chunk
+   */
+  dp = DP (stramaddr + stramsize) - 1;
+  dp = DP ((unsigned long) dp - dp->length) - 1;
+
+  while ((dp->alloced || dp->length < size) && !dp->first)
+    dp = DP ((unsigned long) dp - dp[-1].length) - 2;
+
+  if (dp->alloced || dp->length < size)
+    {
+      printk ("no stram available for %ld allocation\n", size);
+      return NULL;
+    }
+
+  if (dp->length < size + 2 * sizeof (*dp))
+    {
+      /* length too small to split; allocate the whole thing */
+      dp->alloced = 1;
+      ptr = (void *) (dp + 1);
+      dp = DP ((unsigned long) ptr + dp->length);
+      dp->alloced = 1;
+#ifdef DEBUG
+      printk ("stram_alloc: no split\n");
+#endif
+    }
+  else
+    {
+      /* split the extent; use the end part */
+      long newsize = dp->length - (2 * sizeof (*dp) + size);
+
+#ifdef DEBUG
+      printk ("stram_alloc: splitting %d to %ld\n", dp->length,
+	      newsize);
+#endif
+      dp->length = newsize;
+      dp = DP ((unsigned long) (dp + 1) + newsize);
+      dp->first = dp->last = 0;
+      dp->alloced = 0;
+      dp->length = newsize;
+      dp++;
+      dp->first = dp->last = 0;
+      dp->alloced = 1;
+      dp->length = size;
+      ptr = (void *) (dp + 1);
+      dp = DP ((unsigned long) ptr + size);
+      dp->alloced = 1;
+      dp->length = size;
+    }
+
+#ifdef DEBUG
+  printk ("stram_alloc: returning %p\n", ptr);
+#endif
+  return ptr;
+}
+
+void 
+atari_stram_free (void *ptr)
+{
+  struct stram_desc *sdp = DP (ptr) - 1, *dp2;
+  struct stram_desc *edp = DP ((unsigned long) ptr + sdp->length);
+
+  /* deallocate the chunk */
+  sdp->alloced = edp->alloced = 0;
+
+  /* check if we should merge with the previous chunk */
+  if (!sdp->first && !sdp[-1].alloced)
+    {
+      dp2 = DP ((unsigned long) sdp - sdp[-1].length) - 2;
+      dp2->length += sdp->length + 2 * sizeof (*sdp);
+      edp->length = dp2->length;
+      sdp = dp2;
+    }
+
+  /* check if we should merge with the following chunk */
+  if (!edp->last && !edp[1].alloced)
+    {
+      dp2 = DP ((unsigned long) edp + edp[1].length) + 2;
+      dp2->length += edp->length + 2 * sizeof (*sdp);
+      sdp->length = dp2->length;
+      edp = dp2;
+    }
+}
+
+#else
+
+#include <linux/mm.h>
+
+/* ++roman:
+ * 
+ * New version of ST-Ram buffer allocation. Instead of using the
+ * 1 MB - 4 KB that remain when the the ST-Ram chunk starts at $1000
+ * (1 MB granularity!), such buffers are reserved like this:
+ *
+ *  - If the kernel resides in ST-Ram anyway, we can take the buffer
+ *    from behind the current kernel data space the normal way
+ *    (incrementing start_mem).
+ *    
+ *  - If the kernel is in TT-Ram, stram_init() initializes start and
+ *    end of the available region. Buffers are allocated from there
+ *    and mem_init() later marks the such used pages as reserved.
+ *    Since each TT-Ram chunk is at least 4 MB in size, I hope there
+ *    won't be an overrun of the ST-Ram region by normal kernel data
+ *    space.
+ *    
+ * For that, ST-Ram may only be allocated while kernel initialization
+ * is going on, or exactly: before mem_init() is called. There is also
+ * no provision now for freeing ST-Ram buffers. It seems that isn't
+ * really needed.
+ *
+ * ToDo:
+ * Check the high level scsi code what is done when the
+ * UNCHECKED_ISA_DMA flag is set. It guess, it is just a test for adr
+ * < 16 Mega. There should be call to atari_stram_alloc() instead.
+ *
+ * Also ToDo:
+ * Go through head.S and delete parts no longer needed (transparent
+ * mapping of ST-Ram etc.)
+ * 
+ */
+   
+
+unsigned long rsvd_stram_beg, rsvd_stram_end;
+    /* Start and end of the reserved ST-Ram region */
+static unsigned long stram_end;
+    /* Overall end of ST-Ram */
+
+
+void atari_stram_init( void )
+
+{	int		i;
+
+	for( i = 0; i < boot_info.num_memory; ++i ) {
+		if (boot_info.memory[i].addr == 0) {
+			rsvd_stram_beg = PTOV( 0x800 ); /* skip super-only first 2 KB! */
+			rsvd_stram_end = rsvd_stram_beg;
+			stram_end = rsvd_stram_beg - 0x800 + boot_info.memory[i].size;
+			return;
+		}
+	}
+	/* Should never come here! (There is always ST-Ram!) */
+}
+
+
+void *atari_stram_alloc( long size, unsigned long *start_mem )
+
+{
+	static int				kernel_in_stram = -1;
+	
+	void	*adr = 0;
+	
+	if (kernel_in_stram < 0)
+		kernel_in_stram = (PTOV( 0 ) == 0);
+
+	if (kernel_in_stram) {
+		/* Get memory from kernel data space */
+		adr = (void *) *start_mem;
+		*start_mem += size;
+	}
+	else {
+		/* Get memory from rsvd_stram_beg */
+		if (rsvd_stram_end + size < stram_end) {
+			adr = (void *) rsvd_stram_end;
+			rsvd_stram_end += size;
+		}
+	}
+	
+	return( adr );
+}
+
+void atari_stram_free( void *ptr )
+
+{
+	/* Sorry, this is a dummy. It isn't needed anyway. */
+}
+
+#endif
+
+
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/boot/Makefile linux/arch/m68k/boot/Makefile
--- v1.3.93/linux/arch/m68k/boot/Makefile	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/boot/Makefile	Wed Dec 27 22:44:28 1995
@@ -0,0 +1,37 @@
+#
+# linux/arch/m68k/boot/Makefile
+#
+# 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.
+
+ifdef CONFIG_AMIGA
+AMIGA_BOOTOBJS := amiga/bootstrap.o
+endif
+
+ifdef CONFIG_ATARI
+ATARI_BOOTOBJS := atari/bootstrap.o
+HOSTCC += -b m68k-mint
+endif
+
+ifdef CONFIG_ATARI
+atari_bootstrap: $(ATARI_BOOTOBJS)
+	$(HOSTCC) $(HOSTFLAGS) -o $@ $(ATARI_BOOTOBJS)
+	rm -f ../../../bootstrap
+	ln $@ ../../../bootstrap
+endif
+
+ifdef CONFIG_AMIGA
+amiga_bootstrap: $(AMIGA_BOOTOBJS)
+	$(HOSTCC) $(HOSTFLAGS) -o $@ $(AMIGA_BOOTOBJS)
+	rm -f ../../../bootstrap
+	ln $@ ../../../bootstrap
+endif
+
+$(AMIGA_BOOTOBJS) $(ATARI_BOOTOBJS): %.o: %.c
+	$(HOSTCC) $(HOSTFLAGS) -c $< -o $@
+
+clean:
+	rm -f *.o
+
+dep:
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/boot/amiga/bootstrap.c linux/arch/m68k/boot/amiga/bootstrap.c
--- v1.3.93/linux/arch/m68k/boot/amiga/bootstrap.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/boot/amiga/bootstrap.c	Wed Dec 27 22:44:29 1995
@@ -0,0 +1,782 @@
+/*
+** bootstrap.c -- This program loads the Linux/68k kernel into an Amiga
+**                and and launches it.
+**
+** Copyright 1993,1994 by Hamish Macdonald, Greg Harp
+**
+** Modified 11-May-94 by Geert Uytterhoeven
+**                      (Geert.Uytterhoeven@cs.kuleuven.ac.be)
+**     - A3640 MapROM check
+** Modified 31-May-94 by Geert Uytterhoeven
+**     - Memory thrash problem solved
+** Modified 07-March-95 by Geert Uytterhoeven
+**     - Memory block sizes are rounded to a multiple of 256K instead of 1M
+**       This _requires_ >0.9pl5 to work!
+**       (unless all block sizes are multiples of 1M :-)
+**
+** This file is subject to the terms and conditions of the GNU General Public
+** License.  See the file README.legal in the main directory of this archive
+** for more details.
+**
+*/
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/file.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+/* Amiga bootstrap include file */
+#include "bootstrap.h"
+
+/* required Linux/68k include files */
+#include <linux/a.out.h>
+#include <asm/bootinfo.h>
+
+/* temporary stack size */
+#define TEMP_STACKSIZE	256
+
+/* Exec Base */
+extern struct ExecBase *SysBase;
+
+extern char *optarg;
+
+struct exec kexec;
+char *memptr;
+u_long start_mem;
+u_long mem_size;
+u_long rd_size;
+
+struct ExpansionBase *ExpansionBase;
+struct GfxBase *GfxBase;
+
+struct bootinfo bi;
+u_long bi_size = sizeof bi;
+
+caddr_t CustomBase = (caddr_t)CUSTOM_PHYSADDR;
+
+void usage(void)
+{
+	fprintf (stderr, "Usage:\n"
+		 "\tbootstrap [-d] [-k kernel_executable] [-r ramdisk_file]"
+		 " [option...]\n");
+	exit (EXIT_FAILURE);
+}
+
+/*
+ * This assembler code is copied to chip ram, and
+ * then executed.
+ * It copies the kernel (and ramdisk) to their
+ * final resting place.
+ */
+#ifndef __GNUC__
+#error GNU CC is required to compile the bootstrap program
+#endif
+asm("
+.text
+.globl _copyall, _copyallend
+_copyall:
+				| /* put variables in registers because they may */
+	lea	_kexec,a3	| /* be overwritten by kernel/ramdisk copy!! - G.U. */
+	movel	_memptr,a4
+	movel	_start_mem,a5
+	movel	_mem_size,d0
+	movel	_rd_size,d1
+	movel	_bi_size,d5
+	movel	a3@(4),d2	| kexec.a_text
+	movel	a3@(8),d3	| kexec.a_data
+	movel	a3@(12),d4	| kexec.a_bss
+
+				| /* copy kernel text and data */
+	movel	a4,a0		| src = (u_long *)memptr;
+	movel	a0,a2		| limit = (u_long *)(memptr + kexec.a_text + kexec.a_data);
+	addl	d2,a2
+	addl	d3,a2
+	movel	a5,a1		| dest = (u_long *)start_mem;
+1:	cmpl	a0,a2
+	beqs	2f		| while (src < limit)
+	moveb	a0@+,a1@+	|	*dest++ = *src++;
+	bras	1b
+2:
+
+				| /* clear kernel bss */
+	movel	a1,a0		| dest = (u_long *)(start_mem + kexec.a_text + kexec.a_data);
+	movel	a1,a2		| limit = dest + kexec.a_bss / sizeof(u_long);
+	addl	d4,a2
+1:	cmpl	a0,a2
+	beqs	2f		| while (dest < limit)
+	clrb	a0@+		|	*dest++ = 0;
+	bras	1b
+2:
+
+				| /* copy bootinfo to end of bss */
+	movel	a4,a1		| src = (u long *)memptr + kexec.a_text + kexec.a_data);
+	addl	d2,a1
+	addl	d3,a1		| dest = end of bss (already in a0)
+	movel   d5,d7		| count = sizeof bi
+	subql	#1,d7
+1:	moveb	a1@+,a0@+	| while (--count > -1)
+	dbra	d7,1b		|	*dest++ = *src++
+	
+
+				| /* copy the ramdisk to the top of memory (from back to front) */
+	movel	a5,a1		| dest = (u_long *)(start_mem + mem_size);
+	addl	d0,a1
+	movel	a4,a2		| limit = (u_long *)(memptr + kexec.a_text + kexec.a_data + sizeof bi);
+	addl	d2,a2
+	addl	d3,a2
+        addl    d5,a2
+	movel	a2,a0		| src = (u_long *)((u_long)limit + rd_size);
+	addl	d1,a0
+1:	cmpl	a0,a2
+	beqs	2f		| while (src > limit)
+	moveb	a0@-,a1@-	| 	*--dest = *--src;
+	bras	1b
+2:
+				| /* jump to start of kernel */
+	movel	a5,a0		| jump_to (START_MEM);
+	jsr	a0@
+_copyallend:
+");
+
+asm("
+.text
+.globl _maprommed
+_maprommed:
+	oriw	#0x0700,sr
+	moveml	#0x3f20,sp@-
+/* Save cache settings */
+	.long 	0x4e7a1002	/* movec cacr,d1 */
+/* Save MMU settings */
+	.long 	0x4e7a2003	/* movec tc,d2 */
+	.long 	0x4e7a3004	/* movec itt0,d3 */
+	.long 	0x4e7a4005	/* movec itt1,d4 */
+	.long 	0x4e7a5006	/* movec dtt0,d5 */
+	.long 	0x4e7a6007	/* movec dtt1,d6 */
+	moveq	#0,d0
+	movel	d0,a2
+/* Disable caches */
+	.long 	0x4e7b0002	/* movec d0,cacr */
+/* Disable MMU */
+	.long 	0x4e7b0003	/* movec d0,tc */
+	.long 	0x4e7b0004	/* movec d0,itt0 */
+	.long 	0x4e7b0005	/* movec d0,itt1 */
+	.long 	0x4e7b0006	/* movec d0,dtt0 */
+	.long 	0x4e7b0007	/* movec d0,dtt1 */
+	lea	0x07f80000,a0
+	lea	0x00f80000,a1
+	movel	a0@,d7
+	cmpl	a1@,d7
+	jnes	1f
+	movel	d7,d0
+	notl	d0
+	movel	d0,a0@
+	nop
+	cmpl	a1@,d0
+	jnes	1f
+/* MapROMmed A3640 present */
+	moveq	#-1,d0
+	movel	d0,a2
+1:	movel	d7,a0@
+/* Restore MMU settings */
+	.long 	0x4e7b2003	/* movec d2,tc */
+	.long 	0x4e7b3004	/* movec d3,itt0 */
+	.long 	0x4e7b4005	/* movec d4,itt1 */
+	.long 	0x4e7b5006	/* movec d5,dtt0 */
+	.long 	0x4e7b6007	/* movec d6,dtt1 */
+/* Restore cache settings */
+	.long 	0x4e7b1002	/* movec d1,cacr */
+	movel	a2,d0
+	moveml	sp@+,#0x04fc
+	rte
+");
+
+extern unsigned long maprommed();
+
+
+extern char copyall, copyallend;
+
+int main(int argc, char *argv[])
+{
+	int ch, debugflag = 0, kfd, rfd = -1, i;
+	long fast_total = 0;	     /* total Fast RAM in system */
+	struct MemHeader *mnp;
+	struct ConfigDev *cdp = NULL;
+	char *kernel_name = "vmlinux";
+	char *ramdisk_name = NULL;
+	char *memfile = NULL;
+	u_long memreq;
+	void (*startfunc)(void);
+	long startcodesize;
+	u_long *stack, text_offset;
+	unsigned char *rb3_reg = NULL, *piccolo_reg = NULL, *sd64_reg = NULL;
+
+	/* print the greet message */
+	puts("Linux/68k Amiga Bootstrap version 1.11");
+	puts("Copyright 1993,1994 by Hamish Macdonald and Greg Harp\n");
+
+	/* machine is Amiga */
+	bi.machtype = MACH_AMIGA;
+
+	/* check arguments */
+	while ((ch = getopt(argc, argv, "dk:r:m:")) != EOF)
+		switch (ch) {
+		    case 'd':
+			debugflag = 1;
+			break;
+		    case 'k':
+			kernel_name = optarg;
+			break;
+		    case 'r':
+			ramdisk_name = optarg;
+			break;
+		    case 'm':
+			memfile = optarg;
+			break;
+		    case '?':
+		    default:
+			usage();
+		}
+	argc -= optind;
+	argv += optind;
+
+	SysBase = *(struct ExecBase **)4;
+
+	/* Memory & AutoConfig based on 'unix_boot.c' by C= */
+
+	/* open Expansion Library */
+	ExpansionBase = (struct ExpansionBase *)OpenLibrary("expansion.library", 36);
+	if (!ExpansionBase) {
+		puts("Unable to open expansion.library V36 or greater!  Aborting...");
+		exit(EXIT_FAILURE);
+	}
+
+	/* find all of the autoconfig boards in the system */
+	cdp = (struct ConfigDev *)FindConfigDev(cdp, -1, -1);
+	for (i=0; (i < NUM_AUTO) && cdp; i++) {
+		/* copy the contents of each structure into our boot info */
+		memcpy(&bi.bi_amiga.autocon[i], cdp, sizeof(struct ConfigDev));
+
+		/* count this device */
+		bi.bi_amiga.num_autocon++;
+
+		/* get next device */
+		cdp = (struct ConfigDev *)FindConfigDev(cdp, -1, -1);
+	}
+
+	/* find out the memory in the system */
+	for (mnp = (struct MemHeader *)SysBase->MemList.l_head;
+	     (bi.num_memory < NUM_MEMINFO) && mnp->mh_Node.ln_Succ;
+	     mnp = (struct MemHeader *)mnp->mh_Node.ln_Succ)
+	{
+		struct MemHeader mh;
+
+		/* copy the information */
+		mh = *mnp;
+
+		/* if we suspect that Kickstart is shadowed in an A3000,
+		   modify the entry to show 512K more at the top of RAM
+		   Check first for a MapROMmed A3640 board: overwriting the
+		   Kickstart image causes an infinite lock-up on reboot! */
+
+		if (mh.mh_Upper == (void *)0x07f80000)
+			if ((SysBase->AttnFlags & AFF_68040) && Supervisor(maprommed))
+				printf("A3640 MapROM detected.\n");
+			else {
+				mh.mh_Upper = (void *)0x08000000;
+				printf("A3000 shadowed Kickstart detected.\n");
+			}
+
+		/* if we suspect that Kickstart is zkicked,
+		   modify the entry to show 512K more at the botton of RAM */
+		if (mh.mh_Lower == (void *)0x00280020) {
+		    mh.mh_Lower =  (void *)0x00200000;
+		    printf("ZKick detected.\n");
+		}
+
+		/*
+		 * If this machine has "LOCAL" memory between 0x07000000
+		 * and 0x080000000, then we'll call it an A3000.
+		 */
+		if (mh.mh_Lower >= (void *)0x07000000 &&
+		    mh.mh_Lower <  (void *)0x08000000 &&
+		    (mh.mh_Attributes & MEMF_LOCAL))
+			bi.bi_amiga.model = AMI_3000;
+
+		/* mask the memory limit values */
+		mh.mh_Upper = (void *)((u_long)mh.mh_Upper & 0xfffff000);
+		mh.mh_Lower = (void *)((u_long)mh.mh_Lower & 0xfffff000);
+
+		/* if fast memory */
+		if (mh.mh_Attributes & MEMF_FAST) {
+			unsigned long size;
+
+			/* record the start */
+			bi.memory[bi.num_memory].addr = (u_long)mh.mh_Lower;
+
+			/* set the size value to the size of this block */
+			size = (u_long)mh.mh_Upper - (u_long)mh.mh_Lower;
+
+			/* mask off to a 256K increment */
+			size &= 0xfffc0000;
+
+			fast_total += size;
+
+			if (size > 0)
+				/* count this block */
+				bi.memory[bi.num_memory++].size  = size;
+
+		} else if (mh.mh_Attributes & MEMF_CHIP) {
+			/* if CHIP memory, record the size */
+			bi.bi_amiga.chip_size =
+				(u_long)mh.mh_Upper; /* - (u_long)mh.mh_Lower; */
+		}
+	}
+
+	CloseLibrary((struct Library *)ExpansionBase);
+
+	/*
+	 * if we have a memory file, read the memory information from it
+	 */
+	if (memfile) {
+	    FILE *fp;
+	    int i;
+
+	    if ((fp = fopen (memfile, "r")) == NULL) {
+		perror ("open memory file");
+		fprintf (stderr, "Cannot open memory file %s\n", memfile);
+		exit (EXIT_FAILURE);
+	    }
+
+	    if (fscanf (fp, "%lu", &bi.bi_amiga.chip_size) != 1) {
+		fprintf (stderr, "memory file does not contain chip memory size\n");
+		fclose (fp);
+		exit (EXIT_FAILURE);
+	    }
+		
+	    for (i = 0; i < NUM_MEMINFO; i++) {
+		if (fscanf (fp, "%lx %lu", &bi.memory[i].addr,
+			    &bi.memory[i].size) != 2)
+		    break;
+	    }
+
+	    fclose (fp);
+
+	    if (i != bi.num_memory && i > 0)
+		bi.num_memory = i;
+	}
+
+	/* get info from ExecBase */
+	bi.bi_amiga.vblank = SysBase->VBlankFrequency;
+	bi.bi_amiga.psfreq = SysBase->PowerSupplyFrequency;
+	bi.bi_amiga.eclock = SysBase->EClockFrequency;
+
+	/* open graphics library */
+	GfxBase = (struct GfxBase *)OpenLibrary ("graphics.library", 0);
+
+	/* determine chipset */
+	bi.bi_amiga.chipset = CS_STONEAGE;
+	if(GfxBase)
+	{
+	    if(GfxBase->ChipRevBits0 & GFXG_AGA)
+	    {
+		bi.bi_amiga.chipset = CS_AGA;
+		/*
+		 *  we considered this machine to be an A3000 because of its
+		 *  local memory just beneath $8000000; now if it has AGA, it
+		 *  must be an A4000
+		 *  except the case no RAM is installed on the motherboard but
+		 *  on an additional card like FastLane Z3 or on the processor
+		 *  board itself. Gotta check this out.
+		 */
+		bi.bi_amiga.model =
+		    (bi.bi_amiga.model == AMI_3000) ? AMI_4000 : AMI_1200;
+	    }
+	    else if(GfxBase->ChipRevBits0 & GFXG_ECS)
+		bi.bi_amiga.chipset = CS_ECS;
+	    else if(GfxBase->ChipRevBits0 & GFXG_OCS)
+		bi.bi_amiga.chipset = CS_OCS;
+	}
+
+	/* Display amiga model */
+	switch (bi.bi_amiga.model) {
+	    case AMI_UNKNOWN:
+		break;
+	    case AMI_500:
+		printf ("Amiga 500 ");
+		break;
+	    case AMI_2000:
+		printf ("Amiga 2000 ");
+		break;
+	    case AMI_3000:
+		printf ("Amiga 3000 ");
+		break;
+	    case AMI_4000:
+		printf ("Amiga 4000 ");
+		break;
+	    case AMI_1200:		/* this implies an upgraded model   */
+		printf ("Amiga 1200 "); /* equipped with at least 68030 !!! */
+		break;
+	}
+
+	/* display and set the CPU <type */
+	printf("CPU: ");
+	if (SysBase->AttnFlags & AFF_68040) {
+		printf("68040");
+		bi.cputype = CPU_68040;
+		if (SysBase->AttnFlags & AFF_FPU40) {
+			printf(" with internal FPU");
+			bi.cputype |= FPU_68040;
+		} else
+			printf(" without FPU");
+	} else {
+		if (SysBase->AttnFlags & AFF_68030) {
+			printf("68030");
+			bi.cputype = CPU_68030;
+		} else if (SysBase->AttnFlags & AFF_68020) {
+			printf("68020 (Do you have an MMU?)");
+			bi.cputype = CPU_68020;
+		} else {
+			puts("Insufficient for Linux.  Aborting...");
+			printf("SysBase->AttnFlags = %#x\n", SysBase->AttnFlags);
+			exit (EXIT_FAILURE);
+		}
+		if (SysBase->AttnFlags & AFF_68882) {
+			printf(" with 68882 FPU");
+			bi.cputype |= FPU_68882;
+		} else if (SysBase->AttnFlags & AFF_68881) {
+			printf(" with 68881 FPU");
+			bi.cputype |= FPU_68881;
+		} else
+			printf(" without FPU");
+	}
+
+	switch(bi.bi_amiga.chipset)
+	{
+	    case CS_STONEAGE:
+		printf(", old or unknown chipset");
+		break;
+	    case CS_OCS:
+		printf(", OCS");
+		break;
+	    case CS_ECS:
+		printf(", ECS");
+		break;
+	    case CS_AGA:
+		printf(", AGA chipset");
+		break;
+	}
+
+	putchar ('\n');
+	putchar ('\n');
+
+	/*
+	 * Copy command line options into the kernel command line.
+	 */
+	i = 0;
+	while (argc--) {
+		if ((i+strlen(*argv)+1) < CL_SIZE) {
+			i += strlen(*argv) + 1;
+			if (bi.command_line[0])
+				strcat (bi.command_line, " ");
+			strcat (bi.command_line, *argv++);
+		}
+	}
+	printf ("Command line is '%s'\n", bi.command_line);
+
+	/* display the clock statistics */
+	printf("Vertical Blank Frequency: %dHz\nPower Supply Frequency: %dHz\n",
+	       bi.bi_amiga.vblank, bi.bi_amiga.psfreq);
+	printf("EClock Frequency: %7.5fKHz\n\n",
+	       (float)bi.bi_amiga.eclock / 1000);
+
+	/* display autoconfig devices */
+	if (bi.bi_amiga.num_autocon) {
+		printf("Found %d AutoConfig Device%s", bi.bi_amiga.num_autocon,
+		       (bi.bi_amiga.num_autocon > 1)?"s\n":"\n");
+		for (i=0; i<bi.bi_amiga.num_autocon; i++)
+		{
+			printf("Device %d: addr = %08lx\n", i,
+			       (u_long)bi.bi_amiga.autocon[i].cd_BoardAddr);
+			/* check for a Rainbow 3 and prepare to reset it if there is one */
+			if ( (bi.bi_amiga.autocon[i].cd_Rom.er_Manufacturer == MANUF_HELFRICH1) &&
+				 (bi.bi_amiga.autocon[i].cd_Rom.er_Product == PROD_RAINBOW3) )
+			{
+				printf("(Found a Rainbow 3 board - will reset it at kernel boot time)\n");
+				rb3_reg = (unsigned char *)(bi.bi_amiga.autocon[i].cd_BoardAddr + 0x01002000);
+			}
+
+			/* check for a Piccolo and prepare to reset it if there is one */
+			if ( (bi.bi_amiga.autocon[i].cd_Rom.er_Manufacturer == MANUF_HELFRICH2) &&
+				 (bi.bi_amiga.autocon[i].cd_Rom.er_Product == PROD_PICCOLO_REG) )
+			{
+				printf("(Found a Piccolo board - will reset it at kernel boot time)\n");
+				piccolo_reg = (unsigned char *)(bi.bi_amiga.autocon[i].cd_BoardAddr + 0x8000);
+			}
+
+			/* check for a SD64 and prepare to reset it if there is one */
+			if ( (bi.bi_amiga.autocon[i].cd_Rom.er_Manufacturer == MANUF_HELFRICH2) &&
+				 (bi.bi_amiga.autocon[i].cd_Rom.er_Product == PROD_SD64_REG) )
+			{
+				printf("(Found a SD64 board - will reset it at kernel boot time)\n");
+				sd64_reg = (unsigned char *)(bi.bi_amiga.autocon[i].cd_BoardAddr + 0x8000);
+			}
+
+			/* what this code lacks - what if there are several boards of  */
+			/* the same brand ? In that case I should reset them one after */
+			/* the other, which is currently not done - a rare case...FN   */
+			/* ok, MY amiga currently hosts all three of the above boards ;-) */
+		}
+	} else
+		puts("No AutoConfig Devices Found");
+
+	/* display memory */
+	if (bi.num_memory) {
+		printf("\n%d Block%sof Memory Found\n", bi.num_memory,
+		       (bi.num_memory > 1)?"s ":" ");
+		for (i=0; i<bi.num_memory; i++) {
+			printf("Block %d: %08lx to %08lx (%ldKB)\n",
+			       i, bi.memory[i].addr,
+			       bi.memory[i].addr + bi.memory[i].size,
+			       bi.memory[i].size >> 10);
+		}
+	} else {
+		puts("No memory found?!  Aborting...");
+		exit(10);
+	}
+
+	/* display chip memory size */
+	printf ("%ldK of CHIP memory\n", bi.bi_amiga.chip_size >> 10);
+
+	start_mem = bi.memory[0].addr;
+	mem_size = bi.memory[0].size;
+
+	/* tell us where the kernel will go */
+	printf("\nThe kernel will be located at %08lx\n", start_mem);
+
+	/* verify that there is enough Chip RAM */
+	if (bi.bi_amiga.chip_size < 512*1024) {
+		puts("\nNot enough Chip RAM in this system.  Aborting...");
+		exit(10);
+	}
+
+	/* verify that there is enough Fast RAM */
+	if (fast_total < 2*1024*1024) {
+		puts("\nNot enough Fast RAM in this system.  Aborting...");
+		exit(10);
+	}
+
+	/* open kernel executable and read exec header */
+	if ((kfd = open (kernel_name, O_RDONLY)) == -1) {
+		fprintf (stderr, "Unable to open kernel file %s\n", kernel_name);
+		exit (EXIT_FAILURE);
+	}
+
+	if (read (kfd, (void *)&kexec, sizeof(kexec)) != sizeof(kexec)) {
+		fprintf (stderr, "Unable to read exec header from %s\n",
+			 kernel_name);
+		exit (EXIT_FAILURE);
+	}
+
+	switch (N_MAGIC(kexec)) {
+	  case ZMAGIC:
+	    text_offset = N_TXTOFF(kexec);
+	    break;
+	  case QMAGIC:
+	    text_offset = sizeof(kexec);
+	    /* the text size includes the exec header; remove this */
+	    kexec.a_text -= sizeof(kexec);
+	    break;
+	  default:
+	    fprintf (stderr, "Wrong magic number %lo in kernel header\n",
+		     N_MAGIC(kexec));
+	    exit (EXIT_FAILURE);
+	}
+
+	/* Load the kernel at one page after start of mem */
+	start_mem += PAGE_SIZE;
+	mem_size -= PAGE_SIZE;
+	/* Align bss size to multiple of four */
+	kexec.a_bss = (kexec.a_bss + 3) & ~3;
+
+	if (ramdisk_name) {
+		if ((rfd = open (ramdisk_name, O_RDONLY)) == -1) {
+			fprintf (stderr, "Unable to open ramdisk file %s\n",
+				 ramdisk_name);
+			exit (EXIT_FAILURE);
+		}
+		/* record ramdisk size */
+		bi.ramdisk_size = (lseek (rfd, 0, L_XTND) + 1023) >> 10;
+	} else
+		bi.ramdisk_size = 0;
+
+	rd_size = bi.ramdisk_size << 10;
+	bi.ramdisk_addr = (u_long)start_mem + mem_size - rd_size;
+
+	memreq = kexec.a_text + kexec.a_data + sizeof(bi) + rd_size;
+	if (!(memptr = (char *)AllocMem (memreq, MEMF_FAST | MEMF_CLEAR))) {
+		fprintf (stderr, "Unable to allocate memory\n");
+		exit (EXIT_FAILURE);
+	}
+
+	if (lseek (kfd, text_offset, L_SET) == -1) {
+		fprintf (stderr, "Failed to seek to text\n");
+		FreeMem ((void *)memptr, memreq);
+		exit (EXIT_FAILURE);
+	}
+	if (read (kfd, memptr, kexec.a_text) != kexec.a_text) {
+		fprintf (stderr, "Failed to read text\n");
+		FreeMem ((void *)memptr, memreq);
+		exit (EXIT_FAILURE);
+	}
+
+	/* data follows immediately after text */
+	if (read (kfd, memptr + kexec.a_text, kexec.a_data) != kexec.a_data) {
+		fprintf (stderr, "Failed to read data\n");
+		FreeMem ((void *)memptr, memreq);
+		exit (EXIT_FAILURE);
+	}
+	close (kfd);
+
+	/* copy the boot_info struct to the end of the kernel image */
+	memcpy ((void *)(memptr + kexec.a_text + kexec.a_data), &bi,
+		sizeof(bi));
+
+	if (rfd != -1) {
+		if (lseek (rfd, 0, L_SET) == -1) {
+			fprintf (stderr, "Failed to seek to beginning of ramdisk file\n");
+			FreeMem ((void *)memptr, memreq);
+			exit (EXIT_FAILURE);
+		}
+		if (read (rfd, memptr + kexec.a_text + kexec.a_data 
+			  + sizeof(bi), rd_size) != rd_size) {
+			fprintf (stderr, "Failed to read ramdisk file\n");
+			FreeMem ((void *)memptr, memreq);
+			exit (EXIT_FAILURE);
+		}
+		close (rfd);
+	}
+
+	/* allocate temporary chip ram stack */
+	stack = (u_long *)AllocMem( TEMP_STACKSIZE, MEMF_CHIP|MEMF_CLEAR);
+	if (!stack) {
+		fprintf (stderr, "Unable to allocate memory for stack\n");
+		FreeMem ((void *)memptr, memreq);
+		exit (EXIT_FAILURE);
+	}
+
+	/* allocate chip ram for copy of startup code */
+	startcodesize = &copyallend - &copyall;
+	startfunc = (void (*)(void))AllocMem( startcodesize, MEMF_CHIP);
+	if (!startfunc) {
+		fprintf (stderr, "Unable to allocate memory for code\n");
+		FreeMem ((void *)memptr, memreq);
+		FreeMem ((void *)stack, TEMP_STACKSIZE);
+		exit (EXIT_FAILURE);
+	}
+
+	/* copy startup code to CHIP RAM */
+	memcpy (startfunc, &copyall, startcodesize);
+
+	if (debugflag) {
+		if (bi.ramdisk_size)
+			printf ("RAM disk at %#lx, size is %ldK\n",
+				(u_long)memptr + kexec.a_text + kexec.a_data,
+				bi.ramdisk_size);
+
+		printf ("\nKernel text at %#lx, code size %x\n",
+			start_mem, kexec.a_text);
+		printf ("Kernel data at %#lx, data size %x\n",
+			start_mem + kexec.a_text, kexec.a_data );
+		printf ("Kernel bss  at %#lx, bss  size %x\n",
+			start_mem + kexec.a_text + kexec.a_data,
+			kexec.a_bss );
+		printf ("boot info at %#lx\n", start_mem + kexec.a_text
+			+ kexec.a_data + kexec.a_bss);
+
+		printf ("\nKernel entry is %#x\n", kexec.a_entry );
+
+		printf ("ramdisk dest top is %#lx\n", start_mem + mem_size);
+		printf ("ramdisk lower limit is %#lx\n",
+			(u_long)(memptr + kexec.a_text + kexec.a_data));
+		printf ("ramdisk src top is %#lx\n",
+			(u_long)(memptr + kexec.a_text + kexec.a_data)
+			+ rd_size);
+
+		printf ("Type a key to continue the Linux boot...");
+		fflush (stdout);
+		getchar();
+	}
+
+	/* wait for things to settle down */
+	sleep(2);
+
+	/* FN: If a Rainbow III board is present, reset it to disable */
+	/* its (possibly activated) vertical blank interrupts as the */
+	/* kernel is not yet prepared to handle them (level 6). */
+	if (rb3_reg != NULL)
+	{
+		/* set RESET bit in special function register */
+		*rb3_reg = 0x01;
+		/* actually, only a few cycles delay are required... */
+		sleep(1);
+		/* clear reset bit */
+		*rb3_reg = 0x00;
+	}
+
+	/* the same stuff as above, for the Piccolo board. */
+	/* this also has the side effect of resetting the board's */
+	/* output selection logic to use the Amiga's display in single */
+	/* monitor systems - which is currently what we want. */
+	if (piccolo_reg != NULL)
+	{
+		/* set RESET bit in special function register */
+		*piccolo_reg = 0x01;
+		/* actually, only a few cycles delay are required... */
+		sleep(1);
+		/* clear reset bit */
+		*piccolo_reg = 0x51;
+	}
+
+	/* the same stuff as above, for the SD64 board. */
+	/* just as on the Piccolo, this also resets the monitor switch */
+	if (sd64_reg != NULL)
+	{
+		/* set RESET bit in special function register */
+		*sd64_reg = 0x1f;
+		/* actually, only a few cycles delay are required... */
+		sleep(1);
+	/* clear reset bit AND switch monitor bit (0x20) */
+	*sd64_reg = 0x4f;
+	}
+
+	if (GfxBase) {
+		/* set graphics mode to a nice normal one */
+		LoadView (NULL);
+		CloseLibrary ((struct Library *)GfxBase);
+	}
+
+	Disable();
+
+	/* Turn off all DMA */
+	custom.dmacon = DMAF_ALL | DMAF_MASTER;
+
+	/* turn off caches */
+	CacheControl (0L, ~0L);
+
+	/* Go into supervisor state */
+	SuperState ();
+
+	/* setup stack */
+	change_stack ((char *) stack + TEMP_STACKSIZE);
+
+	/* turn off any mmu translation */
+	disable_mmu ();
+
+	/* execute the copy-and-go code (from CHIP RAM) */
+	startfunc();
+
+	/* NOTREACHED */
+}
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/boot/amiga/bootstrap.h linux/arch/m68k/boot/amiga/bootstrap.h
--- v1.3.93/linux/arch/m68k/boot/amiga/bootstrap.h	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/boot/amiga/bootstrap.h	Wed Dec 27 22:44:39 1995
@@ -0,0 +1,329 @@
+/*
+** bootstrap.h -- This file is a part of the Amiga bootloader.
+**
+** Copyright 1993, 1994 by Hamish Macdonald
+**
+** Some minor additions by Michael Rausch 1-11-94
+** Modified 11-May-94 by Geert Uytterhoeven
+**                      (Geert.Uytterhoeven@cs.kuleuven.ac.be)
+**     - inline Supervisor() call
+**
+** This file is subject to the terms and conditions of the GNU General Public
+** License.  See the file README.legal in the main directory of this archive
+** for more details.
+**
+*/
+
+#ifndef BOOTSTRAP_H
+#define BOOTSTRAP_H
+
+#include <asm/amigatypes.h>
+#include <asm/amigahw.h>
+
+struct List {
+    struct Node *l_head;
+    struct Node *l_tail;
+    struct Node *l_tailpred;
+    u_char  l_type;
+    u_char  l_pad;
+};
+
+struct MemChunk {
+    struct  MemChunk *mc_Next;	/* pointer to next chunk */
+    u_long   mc_Bytes;		/* chunk byte size	*/
+};
+
+#define MEMF_CHIP  (1<<1)
+#define MEMF_FAST  (1<<2)
+#define MEMF_LOCAL (1<<8)
+#define MEMF_CLEAR (1<<16)
+
+struct MemHeader {
+    struct  Node mh_Node;
+    u_short   mh_Attributes;	/* characteristics of this region */
+    struct  MemChunk *mh_First; /* first free region		*/
+    void    *mh_Lower;		/* lower memory bound		*/
+    void    *mh_Upper;		/* upper memory bound+1 */
+    u_long   mh_Free;		/* total number of free bytes	*/
+};
+
+struct ExecBase {
+    u_char	fill1[296];
+    u_short	AttnFlags;
+    u_char	fill2[24];
+    struct List MemList;
+    u_char	fill3[194];
+    u_char	VBlankFrequency;
+    u_char	PowerSupplyFrequency;
+    u_char	fill4[36];
+    u_long	EClockFrequency;
+};
+
+#ifndef AFF_68020
+#define AFB_68020 1
+#define AFF_68020 (1<<AFB_68020)
+#endif
+
+#ifndef AFF_68030
+#define AFB_68030 2
+#define AFF_68030 (1<<AFB_68030)
+#endif
+
+#ifndef AFF_68040
+#define AFB_68040 3
+#define AFF_68040 (1<<AFB_68040)
+#endif
+
+#ifndef AFF_68881
+#define AFB_68881 4
+#define AFF_68881 (1<<AFB_68881)
+#endif
+
+#ifndef AFF_68882
+#define AFB_68882 5
+#define AFF_68882 (1<<AFB_68882)
+#endif
+
+#ifndef AFF_FPU40
+#define AFB_FPU40 6
+#define AFF_FPU40 (1<<AFB_FPU40)
+#endif
+
+/*
+ *  GfxBase is now used to determine if AGA or ECS is present
+ */
+
+struct GfxBase {
+	u_char	unused1[0xec];
+	u_char	ChipRevBits0;
+	u_char	unused2[5];
+	u_short	monitor_id;
+};
+
+#ifndef	GFXB_HR_AGNUS
+#define	GFXB_HR_AGNUS	0
+#define	GFXF_HR_AGNUS	(1<<GFXB_HR_AGNUS)
+#endif
+
+#ifndef	GFXB_HR_DENISE
+#define GFXB_HR_DENISE	1
+#define GFXF_HR_DENISE	(1<<GFXB_HR_DENISE)
+#endif
+
+#ifndef	GFXB_AA_ALICE
+#define GFXB_AA_ALICE	2
+#define GFXF_AA_ALICE	(1<<GFXB_AA_ALICE)
+#endif
+
+#ifndef	GFXB_AA_LISA
+#define GFXB_AA_LISA	3
+#define GFXF_AA_LISA	(1<<GFXB_AA_LISA)
+#endif
+
+/*
+ *  HiRes(=Big) Agnus present; i.e. 
+ *  1MB chipmem, big blits (none of interest so far) and programmable sync
+ */
+#define GFXG_OCS	(GFXF_HR_AGNUS)
+/*
+ *  HiRes Agnus/Denise present; we are running on ECS
+ */
+#define GFXG_ECS	(GFXF_HR_AGNUS|GFXF_HR_DENISE)
+/*
+ *  Alice and Lisa present; we are running on AGA
+ */
+#define GFXG_AGA	(GFXF_AA_ALICE|GFXF_AA_LISA)
+
+struct Library;
+
+extern struct ExecBase *SysBase;
+
+static __inline void *
+AllocMem (unsigned long byteSize,unsigned long requirements)
+{
+  register void  *_res	__asm("d0");
+  register struct ExecBase *a6 __asm("a6") = SysBase;
+  register unsigned long d0 __asm("d0") = byteSize;
+  register unsigned long d1 __asm("d1") = requirements;
+  __asm __volatile ("jsr a6@(-0xc6)"
+  : "=r" (_res)
+  : "r" (a6), "r" (d0), "r" (d1)
+  : "a0","a1","d0","d1", "memory");
+  return _res;
+}
+static __inline void
+CloseLibrary (struct Library *library)
+{
+  register struct ExecBase *a6 __asm("a6") = SysBase;
+  register struct Library *a1 __asm("a1") = library;
+  __asm __volatile ("jsr a6@(-0x19e)"
+  : /* no output */
+  : "r" (a6), "r" (a1)
+  : "a0","a1","d0","d1", "memory");
+}
+static __inline void
+Disable (void)
+{
+  extern struct ExecBase *SysBase;
+  register struct ExecBase *a6 __asm("a6") = SysBase;
+  __asm __volatile ("jsr a6@(-0x78)"
+  : /* no output */
+  : "r" (a6)
+  : "a0","a1","d0","d1", "memory");
+}
+static __inline void
+Enable (void)
+{
+  register struct ExecBase *a6 __asm("a6") = SysBase;
+  __asm __volatile ("jsr a6@(-0x7e)"
+  : /* no output */
+  : "r" (a6)
+  : "a0","a1","d0","d1", "memory");
+}
+static __inline void
+FreeMem (void * memoryBlock,unsigned long byteSize)
+{
+  register struct ExecBase *a6 __asm("a6") = SysBase;
+  register void *a1 __asm("a1") = memoryBlock;
+  register unsigned long d0 __asm("d0") = byteSize;
+  __asm __volatile ("jsr a6@(-0xd2)"
+  : /* no output */
+  : "r" (a6), "r" (a1), "r" (d0)
+  : "a0","a1","d0","d1", "memory");
+}
+static __inline struct Library *
+OpenLibrary (char *libName,unsigned long version)
+{
+  register struct Library * _res  __asm("d0");
+  register struct ExecBase *a6 __asm("a6") = SysBase;
+  register u_char *a1 __asm("a1") = libName;
+  register unsigned long d0 __asm("d0") = version;
+  __asm __volatile ("jsr a6@(-0x228)"
+  : "=r" (_res)
+  : "r" (a6), "r" (a1), "r" (d0)
+  : "a0","a1","d0","d1", "memory");
+  return _res;
+}
+static __inline void *
+SuperState (void)
+{
+  register void  *_res	__asm("d0");
+  register struct ExecBase *a6 __asm("a6") = SysBase;
+  __asm __volatile ("jsr a6@(-0x96)"
+  : "=r" (_res)
+  : "r" (a6)
+  : "a0","a1","d0","d1", "memory");
+  return _res;
+}
+static __inline void 
+CacheClearU (void)
+{
+  register struct ExecBase *a6 __asm("a6") = SysBase;
+  __asm __volatile ("jsr a6@(-0x27c)"
+  : /* no output */
+  : "r" (a6)
+  : "a0","a1","d0","d1", "memory");
+}
+static __inline unsigned long 
+CacheControl (unsigned long cacheBits,unsigned long cacheMask)
+{
+  register unsigned long  _res  __asm("d0");
+  register struct ExecBase *a6 __asm("a6") = SysBase;
+  register unsigned long d0 __asm("d0") = cacheBits;
+  register unsigned long d1 __asm("d1") = cacheMask;
+  __asm __volatile ("jsr a6@(-0x288)"
+  : "=r" (_res)
+  : "r" (a6), "r" (d0), "r" (d1)
+  : "a0","a1","d0","d1", "memory");
+  return _res;
+}
+static __inline unsigned long
+Supervisor (unsigned long (*userfunc)())
+{
+  register unsigned long _res __asm("d0");
+  register struct ExecBase *a6 __asm("a6") = SysBase;
+  register unsigned long (*a0)() __asm("a0") = userfunc;
+	/* gcc doesn't seem to like asm parameters in a5 */
+  __asm __volatile ("movel a5,sp@-;movel a0,a5;jsr a6@(-0x1e);movel sp@+,a5"
+  : "=r" (_res)
+  : "r" (a6), "r" (a0)
+  : "a0","a1","d0","d1","memory");
+  return _res;
+}
+
+
+struct ExpansionBase;
+extern struct ExpansionBase *ExpansionBase;
+
+static __inline struct ConfigDev *
+FindConfigDev (struct ConfigDev *oldConfigDev,long manufacturer,long product)
+{
+  register struct ConfigDev * _res  __asm("d0");
+  register struct ExpansionBase* a6 __asm("a6") = ExpansionBase;
+  register struct ConfigDev *a0 __asm("a0") = oldConfigDev;
+  register long d0 __asm("d0") = manufacturer;
+  register long d1 __asm("d1") = product;
+  __asm __volatile ("jsr a6@(-0x48)"
+  : "=r" (_res)
+  : "r" (a6), "r" (a0), "r" (d0), "r" (d1)
+  : "a0","a1","d0","d1", "memory");
+  return _res;
+}
+
+struct GfxBase;
+extern struct GfxBase *GfxBase;
+struct View;
+static __inline void 
+LoadView (struct View *view)
+{
+  register struct GfxBase* a6 __asm("a6") = GfxBase;
+  register struct View *a1 __asm("a1") = view;
+  __asm __volatile ("jsr a6@(-0xde)"
+  : /* no output */
+  : "r" (a6), "r" (a1)
+  : "a0","a1","d0","d1", "memory");
+}
+
+static __inline void change_stack (char *stackp)
+{
+    __asm__ volatile ("movel %0,sp\n\t" :: "g" (stackp) : "sp");
+}
+
+static __inline void disable_cache (void)
+{
+    __asm__ volatile ("movec %0,cacr" :: "d" (0));
+}
+
+static __inline void disable_mmu (void)
+{
+    if (SysBase->AttnFlags & AFF_68040)
+	    __asm__ volatile ("moveq #0,d0;"
+			      ".long 0x4e7b0003;"	/* movec d0,tc */
+			      ".long 0x4e7b0004;"	/* movec d0,itt0 */
+			      ".long 0x4e7b0005;"	/* movec d0,itt1 */
+			      ".long 0x4e7b0006;"	/* movec d0,dtt0 */
+			      ".long 0x4e7b0007"	/* movec d0,dtt1 */
+			      : /* no outputs */
+			      : /* no inputs */
+			      : "d0");
+    else {
+	    __asm__ volatile ("subl  #4,sp;"
+			      "pmove tc,sp@;"
+			      "bclr  #7,sp@;"
+			      "pmove sp@,tc;"
+			      "addl  #4,sp");
+	    if (SysBase->AttnFlags & AFF_68030)
+		    __asm__ volatile ("clrl  sp@-;"
+				      ".long 0xf0170800;" /* pmove sp@,tt0 */
+				      ".long 0xf0170c00;" /* pmove sp@,tt1 */
+				      "addql #4,sp");
+    }
+}
+
+static __inline void jump_to (unsigned long addr)
+{
+    __asm__ volatile ("jmp %0@" :: "a" (addr));
+    /* NOTREACHED */
+}
+
+#endif /* BOOTSTRAP_H */
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/boot/atari/Makefile linux/arch/m68k/boot/atari/Makefile
--- v1.3.93/linux/arch/m68k/boot/atari/Makefile	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/boot/atari/Makefile	Wed Dec 27 22:44:40 1995
@@ -0,0 +1,12 @@
+
+CC		:= d:/gnu/bin/gcc.ttp
+CFLAGS	:= -Wall -O2 -fno-defer-pop -mint -s
+LD		:= d:/gnu/bin/gcc.ttp
+LDFLAGS	:= -mint -D__GNUC__
+
+bootstra.ttp: bootstra.o
+	$(LD) $(LDFLAGS) -o $@ $^
+	prgflags 7 7 $@
+	cp $@ d:/linux
+
+bootstra.o: bootstra.c bootinfo.h
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/boot/atari/bootstrap.c linux/arch/m68k/boot/atari/bootstrap.c
--- v1.3.93/linux/arch/m68k/boot/atari/bootstrap.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/boot/atari/bootstrap.c	Mon Mar  4 22:36:11 1996
@@ -0,0 +1,999 @@
+/*
+** bootstrap.c -- Load and launch the Atari Linux kernel
+**
+** Copyright 1993 by Arjan Knor
+**
+** This file is subject to the terms and conditions of the GNU General Public
+** License.  See the file README.legal in the main directory of this archive
+** for more details.
+**
+** History:
+**  10 Dec 1995 BOOTP/TFTP support (Roman)
+**	03 Oct 1995 Allow kernel to be loaded to TT ram again (Andreas)
+**	11 Jul 1995 Add support for ELF format kernel (Andreas)
+**	16 Jun 1995 Adapted to Linux 1.2: kernel always loaded into ST ram
+**		    (Andreas)
+**      14 Nov 1994 YANML (Yet Another New Memory Layout :-) kernel
+**		    start address is KSTART_ADDR + PAGE_SIZE, this
+**		    does not need the ugly klugde with
+**		    -fwritable-strings (++andreas)
+**      09 Sep 1994 Adapted to the new memory layout: All the boot_info entry
+**                  mentions all ST-Ram and the mover is located somewhere
+**                  in the middle of memory (roman)
+**                  Added the default arguments file known from the other
+**                  bootstrap version
+**      19 Feb 1994 Changed everything so that it works? (rdv)
+**      14 Mar 1994 New mini-copy routine used (rdv)
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stddef.h>
+#include <string.h>
+#include <ctype.h>
+#include "sysvars.h"
+#include <osbind.h>
+#include <sys/types.h>
+#include <sys/file.h>
+
+/* linux specific include files */
+#include <linux/a.out.h>
+#include <linux/elf.h>
+#include <asm/page.h>
+
+#define _LINUX_TYPES_H		/* Hack to prevent including <linux/types.h> */
+#include <asm/bootinfo.h>
+
+/* Atari bootstrap include file */
+#include "bootstrap.h"
+
+#define MIN_RAMSIZE     (3)	/* 3 MB */
+#define TEMP_STACKSIZE 256
+
+extern char *optarg;
+extern int optind;
+static void get_default_args( int *argc, char ***argv );
+/* This is missing in <unistd.h> */
+extern int sync (void);
+
+struct bootinfo bi;
+u_long *cookiejar;
+u_long userstk;
+
+/* getcookie -- function to get the value of the given cookie. */
+static int getcookie(char *cookie, u_long *value)
+{
+    int i = 0;
+
+    while(cookiejar[i] != 0L) {
+	if(cookiejar[i] == *(u_long *)cookie) {
+	    *value = cookiejar[i + 1];
+	    return 1;
+	}
+	i += 2;
+    }
+    return -1;
+}
+
+static void usage(void)
+{
+    fprintf(stderr, "Usage:\n"
+	    "\tbootstrap [-dst] [-k kernel_executable] [-r ramdisk_file]"
+	    " [option...]\n");
+    exit(EXIT_FAILURE);
+}
+
+/*
+ * Copy the kernel and the ramdisk to their final resting places.
+ *
+ * I assume that the kernel data and the ramdisk reside somewhere
+ * in the middle of the memory.
+ *
+ * This program itself should be somewhere in the first 4096 bytes of memory
+ * where the kernel never will be. In this way it can never be overwritten
+ * by itself.
+ *
+ * At this point the registers have:
+ * a0: the start of the final kernel
+ * a1: the start of the current kernel
+ * a2: the end of the final ramdisk
+ * a3: the end of the current ramdisk
+ * d0: the kernel size
+ * d1: the ramdisk size 
+ */
+asm ("
+.text
+.globl _copyall, _copyallend
+_copyall:
+
+	movel	a0,a4	    	/* save the start of the kernel for booting */
+
+1:	movel	a1@+,a0@+   	/* copy the kernel starting at the beginning */
+	subql	#4,d0
+	jcc	1b
+
+	tstl	d1
+	beq		3f
+
+2:	movel	a3@-,a2@-   	/* copy the ramdisk starting at the end */
+	subql	#4,d1
+	jcc	2b
+
+3:	jmp	a4@ 	    	/* jump to the start of the kernel */
+_copyallend:
+");
+
+extern char copyall, copyallend;
+
+
+/* Test for a Medusa: This is the only machine on which address 0 is
+ * writeable!
+ * ...err! On the Afterburner040 (for the Falcon) it's the same... So we do
+ * another test with 0x00ff82fe, that gives a bus error on the Falcon, but is
+ * in the range where the Medusa always asserts DTACK.
+ */
+
+int test_medusa( void )
+
+{	int		rv = 0;
+
+	__asm__ __volatile__
+		( "movel	0x8,a0\n\t"
+		  "movel	sp,a1\n\t"
+		  "moveb	0x0,d1\n\t"
+		  "movel	#Lberr,0x8\n\t"
+		  "moveq	#0,%0\n\t"
+		  "clrb		0x0\n\t"
+		  "nop		\n\t"
+		  "moveb	d1,0x0\n\t"
+		  "nop		\n\t"
+		  "tstb		0x00ff82fe\n\t"
+		  "nop		\n\t"
+		  "moveq	#1,%0\n"
+		"Lberr:\t"
+		  "movel	a1,sp\n\t"
+		  "movel	a0,0x8"
+		  : "=d" (rv)
+		  : /* no inputs */
+		  : "d1", "a0", "a1", "memory" );
+
+	return( rv );
+}
+
+
+void get_medusa_bank_sizes( u_long *bank1, u_long *bank2 )
+
+{	static u_long	save_addr;
+	u_long			test_base, saved_contents[16];
+#define	TESTADDR(i)	(*((u_long *)((char *)test_base + i*8*MB)))
+#define	TESTPAT		0x12345678
+	unsigned short	oldflags;
+	int				i;
+
+	/* This ensures at least that none of the test addresses conflicts
+	 * with the test code itself */
+	test_base = ((unsigned long)&save_addr & 0x007fffff) | 0x20000000;
+	*bank1 = *bank2 = 0;
+	
+	/* Interrupts must be disabled because arbitrary addresses may be
+	 * temporarily overwritten, even code of an interrupt handler */
+	__asm__ __volatile__ ( "movew sr,%0; oriw #0x700,sr" : "=g" (oldflags) : );
+	disable_cache();
+	
+	/* save contents of the test addresses */
+	for( i = 0; i < 16; ++i )
+		saved_contents[i] = TESTADDR(i);
+	
+	/* write 0s into all test addresses */
+	for( i = 0; i < 16; ++i )
+		TESTADDR(i) = 0;
+
+	/* test for bank 1 */
+#if 0
+	/* This is Freddi's original test, but it didn't work. */
+	TESTADDR(0) = TESTADDR(1) = TESTPAT;
+	if (TESTADDR(1) == TESTPAT) {
+		if (TESTADDR(2) == TESTPAT)
+			*bank1 = 8*MB;
+		else if (TESTADDR(3) == TESTPAT)
+			*bank1 = 16*MB;
+		else
+			*bank1 = 32*MB;
+	}
+	else {
+		if (TESTADDR(2) == TESTPAT)
+			*bank1 = 0;
+		else
+			*bank1 = 16*MB;
+	}
+#else
+	TESTADDR(0) = TESTPAT;
+	if (TESTADDR(1) == TESTPAT)
+		*bank1 = 8*MB;
+	else if (TESTADDR(2) == TESTPAT)
+		*bank1 = 16*MB;
+	else if (TESTADDR(4) == TESTPAT)
+		*bank1 = 32*MB;
+	else
+		*bank1 = 64*MB;
+#endif
+
+	/* test for bank2 */
+	if (TESTADDR(8) != 0)
+		*bank2 = 0;
+	else {
+		TESTADDR(8) = TESTPAT;
+		if (TESTADDR(9) != 0) {
+			if (TESTADDR(10) == TESTPAT)
+				*bank2 = 8*MB;
+			else
+				*bank2 = 32*MB;
+		}
+		else {
+			TESTADDR(9) = TESTPAT;
+			if (TESTADDR(10) == TESTPAT)
+				*bank2 = 16*MB;
+			else
+				*bank2 = 64*MB;
+		}
+	}
+	
+	/* restore contents of the test addresses and restore interrupt mask */
+	for( i = 0; i < 16; ++i )
+		TESTADDR(i) = saved_contents[i];
+	__asm__ __volatile__ ( "movew %0,sr" : : "g" (oldflags) );
+}
+
+#undef TESTADDR
+#undef TESTPAT
+
+#ifdef USE_BOOTP
+# include "bootp.h"
+#else
+# define kread	read
+# define klseek	lseek
+# define kclose	close
+#endif
+
+
+/* ++andreas: this must be inline due to Super */
+static inline void boot_exit (int) __attribute__ ((noreturn));
+static inline void boot_exit(int status)
+{
+    /* first go back to user mode */
+    (void)Super(userstk);
+	getchar();
+    exit(status);
+}
+
+int main(int argc, char *argv[])
+{
+    int debugflag = 0, ch, kfd, rfd = -1, i, ignore_ttram = 0;
+    int load_to_stram = 0;
+    char *ramdisk_name, *kernel_name, *memptr;
+    u_long ST_ramsize, TT_ramsize, memreq;
+    u_long cpu_type, fpu_type, mch_type, mint;
+    struct exec kexec;
+    int elf_kernel = 0;
+    Elf32_Ehdr kexec_elf;
+    Elf32_Phdr *kernel_phdrs = NULL;
+    u_long start_mem, mem_size, rd_size, text_offset = 0, kernel_size;
+#ifdef USE_BOOTP
+    int prefer_bootp = 1, kname_set = 0;
+#endif
+
+    ramdisk_name = NULL;
+    kernel_name = "vmlinux";
+
+    /* print the startup message */
+    puts("\fLinux/68k Atari Bootstrap version 1.6"
+#ifdef USE_BOOTP
+	 " (with BOOTP)"
+#endif
+	 );
+    puts("Copyright 1993,1994 by Arjan Knor, Robert de Vries, Roman Hodek, Andreas Schwab\n");
+
+	/* ++roman: If no arguments on the command line, read them from
+	 * file */
+	if (argc == 1)
+		get_default_args( &argc, &argv );
+
+    /* machine is Atari */
+    bi.machtype = MACH_ATARI;
+
+    /* check arguments */
+#ifdef USE_BOOTP
+    while ((ch = getopt(argc, argv, "bdtsk:r:")) != EOF)
+#else
+    while ((ch = getopt(argc, argv, "dtsk:r:")) != EOF)
+#endif
+	switch (ch) {
+	  case 'd':
+	    debugflag = 1;
+	    break;
+	  case 't':
+	    ignore_ttram = 1;
+	    break;
+	  case 's':
+	    load_to_stram = 1;
+	    break;
+	  case 'k':
+	    kernel_name = optarg;
+#ifdef USE_BOOTP
+	    kname_set = 1;
+#endif
+	    break;
+	  case 'r':
+	    ramdisk_name = optarg;
+	    break;
+#ifdef USE_BOOTP
+	  case 'b':
+	    prefer_bootp = 1;
+	    break;
+#endif
+	  case '?':
+	  default:
+	    usage();
+	}
+
+    argc -= optind;
+    argv += optind;
+  
+    /* We have to access some system variables to get
+     * the information we need, so we must switch to
+     * supervisor mode first.
+     */
+    userstk = Super(0L);
+
+    /* get the info we need from the cookie-jar */
+    cookiejar = *_p_cookies;
+    if(cookiejar == 0L) {
+	/* if we find no cookies, it's probably an ST */
+	fprintf(stderr, "Error: No cookiejar found. Is this an ST?\n");
+	boot_exit(EXIT_FAILURE);
+    }
+
+    /* Exit if MiNT/MultiTOS is running.  */
+    if(getcookie("MiNT", &mint) != -1)
+    {
+	puts("Warning: MiNT is running\n");
+#if 0
+	puts("Linux cannot be started when MiNT is running. Aborting...\n");
+	boot_exit(EXIT_FAILURE);
+#endif
+    }
+
+    /* get _CPU, _FPU and _MCH */
+    getcookie("_CPU", &cpu_type);
+    getcookie("_FPU", &fpu_type);
+    getcookie("_MCH", &mch_type);
+
+    /* check if we are on a 68030/40 with FPU */
+    if ((cpu_type != 30 && cpu_type != 40 && cpu_type != 60) ||
+		(fpu_type >> 16) < 2)
+    {
+	puts("Machine type currently not supported. Aborting...");
+	boot_exit(EXIT_FAILURE);
+    }
+
+    switch(cpu_type) {
+      case  0:
+      case 10: break;
+      case 20: bi.cputype = CPU_68020; break;
+      case 30: bi.cputype = CPU_68030; break;
+      case 40: bi.cputype = CPU_68040; break;
+      case 60: bi.cputype = CPU_68060; break;
+      default:
+	fprintf(stderr, "Error: Unknown CPU type. Aborting...\n");
+	boot_exit(EXIT_FAILURE);
+	break;
+    }
+
+    printf("CPU: %ld; ", cpu_type + 68000);
+    printf("FPU: ");
+
+    /* check for FPU; in case of a '040 or '060, don't look at _FPU itself,
+     * some software may set it to wrong values (68882 or the like) */
+	if (cpu_type == 40) {
+		bi.cputype |= FPU_68040;
+		puts( "68040\n" );
+	}
+	else if (cpu_type == 60) {
+		bi.cputype |= FPU_68060;
+		puts( "68060\n" );
+	}
+	else {
+		switch ((fpu_type >> 16) & 6) {
+		  case 0:
+			puts("not present\n");
+			break;
+		  case 2:
+			/* try to determine real type */
+			if (fpu_idle_frame_size () != 0x18)
+				goto m68882;
+			/* fall through */
+		  case 4:
+			bi.cputype |= FPU_68881;
+			puts("68881\n");
+			break;
+		  case 6:
+		  m68882:
+			bi.cputype |= FPU_68882;
+			puts("68882\n");
+			break;
+		  default:
+			puts("Unknown FPU type. Assuming no FPU.");
+			break;
+		}
+	}
+
+    memset(&bi.bi_atari.hw_present, 0, sizeof(bi.bi_atari.hw_present));
+
+    /* Get the amounts of ST- and TT-RAM. */
+    /* The size must be a multiple of 1MB. */
+    i = 0;
+	
+    if (!test_medusa()) {
+	struct {
+		unsigned short version;   /* version - currently 1 */
+		unsigned long fr_start; /* start addr FastRAM */
+		unsigned long fr_len;   /* length FastRAM */
+	} *magn_cookie;
+	struct {
+		unsigned long version;
+		unsigned long fr_start; /* start addr */
+		unsigned long fr_len;   /* length */
+	} *fx_cookie;
+
+        TT_ramsize = 0;
+        if (!ignore_ttram) {
+	    /* "Original" or properly emulated TT-Ram */
+	    if (*ramtop) {
+		/* the 'ramtop' variable at 0x05a4 is not
+		 * officially documented. We use it anyway
+		 * because it is the only way to get the TTram size.
+		 * (It is zero if there is no TTram.)
+		 */
+		bi.memory[i].addr = TT_RAM_BASE;
+		bi.memory[i].size = (*ramtop - TT_RAM_BASE) & ~(MB - 1);
+		TT_ramsize = bi.memory[i].size / MB;
+		i++;
+		printf("TT-RAM: %ld Mb; ", TT_ramsize);
+	    }
+
+	    /* test for MAGNUM alternate RAM
+	     * added 26.9.1995 M. Schwingen, rincewind@discworld.oche.de
+	     */
+	    if (getcookie("MAGN", (u_long *)&magn_cookie) != -1) {
+		bi.memory[i].addr = magn_cookie->fr_start;
+		bi.memory[i].size = magn_cookie->fr_len & ~(MB - 1);
+		TT_ramsize += bi.memory[i].size / MB;
+		printf("MAGNUM alternate RAM: %ld Mb; ", bi.memory[i].size/MB);
+		i++;
+	    }
+
+	    /* BlowUps FX */
+	    if (getcookie("BPFX", (u_long *)&fx_cookie) != -1 && fx_cookie) {
+		/* if fx is set (cookie call above),
+		 * we assume that BlowUps FX-card
+		 * is installed. (Nat!)
+		 */
+		bi.memory[i].addr = fx_cookie->fr_start;
+		bi.memory[i].size = fx_cookie->fr_len & ~(MB - 1);
+		printf("FX alternate RAM: %ld Mb; ", bi.memory[i].size/MB);
+		i++;
+	    }
+	}
+
+        bi.memory[i].addr = 0;
+        bi.memory[i].size = *phystop & ~(MB - 1);
+        ST_ramsize = bi.memory[i].size / MB;
+        i++;
+        printf("ST-RAM: %ld Mb\n", ST_ramsize );
+
+        bi.num_memory = i;
+
+	if (load_to_stram && i > 1) {
+	    /* Put ST-RAM first in the list of mem blocks */
+	    struct mem_info temp = bi.memory[i - 1];
+	    bi.memory[i - 1] = bi.memory[0];
+	    bi.memory[0] = temp;
+	}
+    }
+    else {
+        u_long	bank1, bank2, medusa_st_ram;
+
+        get_medusa_bank_sizes( &bank1, &bank2 );
+	medusa_st_ram = *phystop & ~(MB - 1);
+        bank1 -= medusa_st_ram;
+        TT_ramsize = 0;
+
+        bi.memory[i].addr = 0;
+        bi.memory[i].size = medusa_st_ram;
+        ST_ramsize = bi.memory[i].size / MB;
+        i++;
+        printf("Medusa pseudo ST-RAM from bank 1: %ld Mb; ", ST_ramsize );
+
+        if (!ignore_ttram && bank1 > 0) {
+            bi.memory[i].addr = 0x20000000 + medusa_st_ram;
+            bi.memory[i].size = bank1;
+            TT_ramsize += bank1;
+            i++;
+            printf("TT-RAM bank 1: %ld Mb; ", bank1/MB );
+        }
+			
+        if (!ignore_ttram && bank2 > 0) {
+            bi.memory[i].addr = 0x24000000;
+            bi.memory[i].size = bank2;
+            TT_ramsize += bank2;
+            i++;
+            printf("TT-RAM bank 2: %ld Mb; ", bank2/MB );
+        }
+			
+        bi.num_memory = i;
+        printf("\n");
+    }
+
+    /* verify that there is enough RAM; ST- and TT-RAM combined */
+    if (ST_ramsize + TT_ramsize < MIN_RAMSIZE) {
+	puts("Not enough RAM. Aborting...");
+	boot_exit(10);
+    }
+
+#if 0	
+    /* Get language/keyboard info */
+    /* TODO: do we need this ? */
+    /* Could be used to auto-select keyboard map later on. (rdv) */
+    if (getcookie("_AKP",&language) == -1)
+    {
+	/* Get the language info from the OS-header */
+	os_header = *_sysbase;
+	os_header = os_header->os_beg;
+	lang = (os_header->os_conf) >> 1;
+	printf("Language: ");
+	switch(lang) {
+	  case HOL: puts("Dutch"); break; /* Own country first :-) */
+	  case USA: puts("American"); break;
+	  case SWG: puts("Switzerland (German)"); break;
+	  case FRG: puts("German"); break;
+	  case FRA: puts("French"); break;
+	  case SWF: puts("Switzerland (French)"); break;
+	  case UK:  puts("English"); break;
+	  case SPA: puts("Spanish"); break;
+	  case ITA: puts("Italian"); break;
+	  case SWE: puts("Swedish"); break;
+	  case TUR: puts("Turkey"); break;
+	  case FIN: puts("Finnish"); break;
+	  case NOR: puts("Norwegian"); break;
+	  case DEN: puts("Danish"); break;
+	  case SAU: puts("Saudi-Arabian"); break;
+	  default:  puts("Unknown"); break;
+	}
+    }
+    else
+    {
+	printf("Language: ");
+	switch(language & 0x0F)
+	{
+	  case 1: printf("German "); break;
+	  case 2: printf("French "); break;
+	  case 4: printf("Spanish "); break;
+	  case 5: printf("Italian "); break;
+	  case 7: printf("Swiss French "); break;
+	  case 8: printf("Swiss German "); break;
+	  default: printf("English ");
+	}
+	printf("Keyboard type :");
+	switch(language >> 8)
+	{
+	  case 1: printf("German "); break;
+	  case 2: printf("French "); break;
+	  case 4: printf("Spanish "); break;
+	  case 5: printf("Italian "); break;
+	  case 7: printf("Swiss French "); break;
+	  case 8: printf("Swiss German "); break;
+	  default: printf("English ");
+	}
+	printf("\n");
+    }
+#endif
+	
+    /* Pass contents of the _MCH cookie to the kernel */
+    bi.bi_atari.mch_cookie = mch_type;
+    
+    /*
+     * Copy command line options into the kernel command line.
+     */
+    i = 0;
+    while (argc--) {
+	if ((i+strlen(*argv)+1) < CL_SIZE) {
+	    i += strlen(*argv) + 1;
+	    if (bi.command_line[0])
+		strcat (bi.command_line, " ");
+	    strcat (bi.command_line, *argv++);
+	}
+    }
+    printf ("Command line is '%s'\n", bi.command_line);
+
+    start_mem = bi.memory[0].addr;
+    mem_size = bi.memory[0].size;
+
+    /* tell us where the kernel will go */
+    printf("\nThe kernel will be located at 0x%08lx\n", start_mem);
+
+#ifdef TEST
+    /*
+    ** Temporary exit point for testing
+    */
+    boot_exit(-1);
+#endif /* TEST */
+
+#ifdef USE_BOOTP
+    kfd = -1;
+    if (prefer_bootp) {
+	/* First try to get a remote kernel, then use a local kernel (if
+	 * present) */
+	if (get_remote_kernel( kname_set ? kernel_name : NULL ) < 0) {
+	    printf( "\nremote boot failed; trying local kernel\n" );
+	    if ((kfd = open (kernel_name, O_RDONLY)) == -1) {
+		fprintf (stderr, "Unable to open kernel file %s\n",
+			 kernel_name);
+		boot_exit (EXIT_FAILURE);
+	    }
+	}
+    }
+    else {
+	/* Try BOOTP if local kernel cannot be opened */
+	if ((kfd = open (kernel_name, O_RDONLY)) == -1) {
+	    printf( "\nlocal kernel failed; trying remote boot\n" );
+	    if (get_remote_kernel( kname_set ? kernel_name : NULL ) < 0) {
+		fprintf (stderr, "Unable to remote boot and "
+			 "to open kernel file %s\n", kernel_name);
+		boot_exit (EXIT_FAILURE);
+	    }
+	}
+    }
+#else
+    /* open kernel executable and read exec header */
+    if ((kfd = open (kernel_name, O_RDONLY)) == -1) {
+	fprintf (stderr, "Unable to open kernel file %s\n", kernel_name);
+	boot_exit (EXIT_FAILURE);
+    }
+#endif
+
+    if (kread (kfd, (void *)&kexec, sizeof(kexec)) != sizeof(kexec))
+    {
+	fprintf (stderr, "Unable to read exec header from %s\n", kernel_name);
+	boot_exit (EXIT_FAILURE);
+    }
+
+    switch (N_MAGIC(kexec)) {
+    case ZMAGIC:
+	text_offset = N_TXTOFF(kexec);
+	break;
+    case QMAGIC:
+	text_offset = sizeof(kexec);
+	/* the text size includes the exec header; remove this */
+	kexec.a_text -= sizeof(kexec);
+	break;
+    default:
+	/* Try to parse it as an ELF header */
+	klseek (kfd, 0, SEEK_SET);
+	if (kread (kfd, (void *)&kexec_elf, sizeof (kexec_elf)) == sizeof (kexec_elf)
+	    && memcmp (&kexec_elf.e_ident[EI_MAG0], ELFMAG, SELFMAG) == 0)
+	  {
+	    elf_kernel = 1;
+	    /* A few plausability checks */
+	    if (kexec_elf.e_type != ET_EXEC || kexec_elf.e_machine != EM_68K
+		|| kexec_elf.e_version != EV_CURRENT)
+	      {
+		fprintf (stderr, "Invalid ELF header contents in kernel\n");
+		boot_exit (EXIT_FAILURE);
+	      }
+	    /* Load the program headers */
+	    kernel_phdrs = (Elf32_Phdr *) Malloc (kexec_elf.e_phnum * sizeof (Elf32_Phdr));
+	    if (kernel_phdrs == NULL)
+	      {
+		fprintf (stderr, "Unable to allocate memory for program headers\n");
+		boot_exit (EXIT_FAILURE);
+	      }
+	    klseek (kfd, kexec_elf.e_phoff, SEEK_SET);
+	    if (kread (kfd, (void *) kernel_phdrs,
+		      kexec_elf.e_phnum * sizeof (*kernel_phdrs))
+		!= kexec_elf.e_phnum * sizeof (*kernel_phdrs))
+	      {
+		fprintf (stderr, "Unable to read programm headers from %s\n",
+			 kernel_name);
+		boot_exit (EXIT_FAILURE);
+	      }
+	    break;
+	  }
+	fprintf (stderr, "Wrong magic number %lo in kernel header\n",
+		 N_MAGIC(kexec));
+	boot_exit (EXIT_FAILURE);
+    }
+
+    /* Load the kernel one page after start of mem */
+    start_mem += PAGE_SIZE;
+    mem_size -= PAGE_SIZE;
+    /* Align bss size to multiple of four */
+    if (!elf_kernel)
+      kexec.a_bss = (kexec.a_bss + 3) & ~3;
+
+    /* init ramdisk */
+    if(ramdisk_name) {
+	if((rfd = open(ramdisk_name, O_RDONLY)) == -1) {
+	    fprintf(stderr, "Unable to open ramdisk file %s\n",
+		    ramdisk_name);
+	    boot_exit(EXIT_FAILURE);
+	}
+	bi.ramdisk_size = (lseek(rfd, 0, SEEK_END) + 1023) / 1024;
+    }
+    else
+	bi.ramdisk_size = 0;
+
+    rd_size = bi.ramdisk_size << 10;
+    if (mem_size - rd_size < MB && bi.num_memory > 1)
+      /* If running low on ST ram load ramdisk into alternate ram.  */
+      bi.ramdisk_addr = (u_long) bi.memory[1].addr + bi.memory[1].size - rd_size;
+    else
+      /* Else hopefully there is enough ST ram. */
+      bi.ramdisk_addr = (u_long)start_mem + mem_size - rd_size;
+
+    /* calculate the total required amount of memory */
+    if (elf_kernel)
+      {
+	u_long min_addr = 0xffffffff, max_addr = 0;
+	for (i = 0; i < kexec_elf.e_phnum; i++)
+	  {
+	    if (min_addr > kernel_phdrs[i].p_vaddr)
+	      min_addr = kernel_phdrs[i].p_vaddr;
+	    if (max_addr < kernel_phdrs[i].p_vaddr + kernel_phdrs[i].p_memsz)
+	      max_addr = kernel_phdrs[i].p_vaddr + kernel_phdrs[i].p_memsz;
+	  }
+	/* This is needed for newer linkers that include the header in
+	   the first segment.  */
+	if (min_addr == 0)
+	  {
+	    min_addr = PAGE_SIZE;
+	    kernel_phdrs[0].p_vaddr += PAGE_SIZE;
+	    kernel_phdrs[0].p_offset += PAGE_SIZE;
+	    kernel_phdrs[0].p_filesz -= PAGE_SIZE;
+	    kernel_phdrs[0].p_memsz -= PAGE_SIZE;
+	  }
+	kernel_size = max_addr - min_addr;
+      }
+    else
+      kernel_size = kexec.a_text + kexec.a_data + kexec.a_bss;
+    memreq = kernel_size + sizeof (bi) + rd_size;
+	
+    /* allocate RAM for the kernel */
+    if (!(memptr = (char *)Malloc (memreq)))
+    {
+	fprintf (stderr, "Unable to allocate memory for kernel and ramdisk\n");
+	boot_exit (EXIT_FAILURE);
+    }
+    else
+	fprintf(stderr, "kernel at address %lx\n", (u_long) memptr);
+
+    (void)memset(memptr, 0, memreq);
+
+    /* read the text and data segments from the kernel image */
+    if (elf_kernel)
+      {
+	for (i = 0; i < kexec_elf.e_phnum; i++)
+	  {
+	    if (klseek (kfd, kernel_phdrs[i].p_offset, SEEK_SET) == -1)
+	      {
+		fprintf (stderr, "Failed to seek to segment %d\n", i);
+		boot_exit (EXIT_FAILURE);
+	      }
+	    if (kread (kfd, memptr + kernel_phdrs[i].p_vaddr - PAGE_SIZE,
+		      kernel_phdrs[i].p_filesz)
+		!= kernel_phdrs[i].p_filesz)
+	      {
+		fprintf (stderr, "Failed to read segment %d\n", i);
+		boot_exit (EXIT_FAILURE);
+	      }
+	  }
+      }
+    else
+      {
+	if (klseek (kfd, text_offset, SEEK_SET) == -1)
+	{
+	    fprintf (stderr, "Failed to seek to text\n");
+	    Mfree ((void *)memptr);
+	    boot_exit (EXIT_FAILURE);
+	}
+
+	if (kread (kfd, memptr, kexec.a_text) != kexec.a_text)
+	{
+	    fprintf (stderr, "Failed to read text\n");
+	    Mfree ((void *)memptr);
+	    boot_exit (EXIT_FAILURE);
+	}
+
+	/* data follows immediately after text */
+	if (kread (kfd, memptr + kexec.a_text, kexec.a_data) != kexec.a_data)
+	{
+	    fprintf (stderr, "Failed to read data\n");
+	    Mfree ((void *)memptr);
+	    boot_exit (EXIT_FAILURE);
+	}
+      }
+    kclose (kfd);
+
+    /* copy the boot_info struct to the end of the kernel image */
+    memcpy ((void *)(memptr + kernel_size),
+	    &bi, sizeof(bi));
+
+    /* read the ramdisk image */
+    if (rfd != -1)
+    {
+	if (lseek (rfd, 0, SEEK_SET) == -1)
+	{
+	    fprintf (stderr, "Failed to seek to beginning of ramdisk file\n");
+	    Mfree ((void *)memptr);
+	    boot_exit (EXIT_FAILURE);
+	}
+	if (read (rfd, memptr + kernel_size + sizeof (bi),
+		  rd_size) != rd_size)
+	{
+	    fprintf (stderr, "Failed to read ramdisk file\n");
+	    Mfree ((void *)memptr);
+	    boot_exit (EXIT_FAILURE);
+	}
+	close (rfd);
+    }
+
+    /* for those who want to debug */
+    if (debugflag)
+    {
+	if (bi.ramdisk_size)
+	    printf ("RAM disk at %#lx, size is %ldK\n",
+		    (u_long)memptr + kernel_size,
+		    bi.ramdisk_size);
+
+	if (elf_kernel)
+	  {
+	    for (i = 0; i < kexec_elf.e_phnum; i++)
+	      {
+		printf ("Kernel segment %d at %#lx, size %ld\n", i,
+			start_mem + kernel_phdrs[i].p_vaddr - PAGE_SIZE,
+			kernel_phdrs[i].p_memsz);
+	      }
+	  }
+	else
+	  {
+	    printf ("\nKernel text at %#lx, code size %d\n",
+		    start_mem, kexec.a_text);
+	    printf ("Kernel data at %#lx, data size %d\n",
+		    start_mem + kexec.a_text, kexec.a_data );
+	    printf ("Kernel bss  at %#lx, bss  size %d\n",
+		    start_mem + kexec.a_text + kexec.a_data, kexec.a_bss );
+	  }
+	printf ("\nboot_info is at %#lx\n",
+		start_mem + kernel_size);
+	printf ("\nKernel entry is %#lx\n",
+		elf_kernel ? kexec_elf.e_entry : kexec.a_entry);
+	printf ("ramdisk dest top is %#lx\n", bi.ramdisk_addr + rd_size);
+	printf ("ramdisk lower limit is %#lx\n",
+		(u_long)(memptr + kernel_size));
+	printf ("ramdisk src top is %#lx\n",
+		(u_long)(memptr + kernel_size) +
+		rd_size);
+
+	printf ("Type a key to continue the Linux boot...");
+	fflush (stdout);
+	getchar();
+    }
+
+    printf("Booting Linux...\n");
+
+    sync ();
+
+    /* turn off interrupts... */
+    disable_interrupts();
+
+    /* turn off caches... */
+    disable_cache();
+
+    /* ..and any MMU translation */
+    disable_mmu();
+
+    /* ++guenther: allow reset if launched with MiNT */
+    *(long*)0x426 = 0;
+
+    /* copy mover code to a safe place if needed */
+    memcpy ((void *) 0x400, &copyall, &copyallend - &copyall);
+
+    /* setup stack */
+    change_stack ((void *) PAGE_SIZE);
+
+    /*
+     * On the Atari you can have two situations:
+     * 1. One piece of contiguous RAM (Falcon)
+     * 2. Two pieces of contiguous RAM (TT)
+     * In case 2 you can load your program into ST-ram and load your data in
+     * any old RAM you have left.
+     * In case 1 you could overwrite your own program when copying the
+     * kernel and ramdisk to their final positions.
+     * To solve this the mover code is copied to a safe place first.
+     * Then this program jumps to the mover code. After the mover code
+     * has finished it jumps to the start of the kernel in its new position.
+     * I thought the memory just after the interrupt vector table was a safe
+     * place because it is used by TOS to store some system variables.
+     * This range goes from 0x400 to approx. 0x5B0.
+     * This is more than enough for the miniscule mover routine (16 bytes).
+     */
+
+    jump_to_mover((char *) start_mem, memptr,
+		  (char *) bi.ramdisk_addr + rd_size, memptr + memreq,
+		  kernel_size + sizeof (bi),
+		  rd_size,
+		  (void *) 0x400);
+
+    for (;;);
+    /* NOTREACHED */
+}
+
+
+
+#define	MAXARGS		30
+
+static void get_default_args( int *argc, char ***argv )
+
+{	FILE		*f;
+	static char	*nargv[MAXARGS];
+	char		arg[256], *p;
+	int			c, quote, state;
+
+	if (!(f = fopen( "bootargs", "r" )))
+		return;
+	
+	*argc = 1;
+	if (***argv)
+	  nargv[0] = **argv;
+	else
+	  nargv[0] = "bootstrap";
+	*argv = nargv;
+
+	quote = state = 0;
+	p = arg;
+	while( (c = fgetc(f)) != EOF ) {		
+
+		if (state == 0) {
+			/* outside args, skip whitespace */
+			if (!isspace(c)) {
+				state = 1;
+				p = arg;
+			}
+		}
+		
+		if (state) {
+			/* inside an arg: copy it into 'arg', obeying quoting */
+			if (!quote && (c == '\'' || c == '"'))
+				quote = c;
+			else if (quote && c == quote)
+				quote = 0;
+			else if (!quote && isspace(c)) {
+				/* end of this arg */
+				*p = 0;
+				nargv[(*argc)++] = strdup(arg);
+				state = 0;
+			}
+			else
+				*p++ = c;
+		}
+	}
+	if (state) {
+		/* last arg finished by EOF! */
+		*p = 0;
+		nargv[(*argc)++] = strdup(arg);
+	}
+	fclose( f );
+	
+	nargv[*argc] = 0;
+}    
+
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/boot/atari/bootstrap.h linux/arch/m68k/boot/atari/bootstrap.h
--- v1.3.93/linux/arch/m68k/boot/atari/bootstrap.h	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/boot/atari/bootstrap.h	Mon Mar  4 22:36:11 1996
@@ -0,0 +1,147 @@
+/*
+** bootstrap.h -- This file is a part of the Atari bootloader.
+**
+** Copyright 1993 by Arjan Knor
+**
+** Modified by Andreas Schwab
+** - clear transparent translation registers
+**
+** This file is subject to the terms and conditions of the GNU General Public
+** License.  See the file README.legal in the main directory of this archive
+** for more details.
+**
+*/
+
+#ifndef BOOTSTRAP_H
+#define BOOTSTRAP_H
+
+/* _MCH cookie values */
+#define MACH_ST  0
+#define MACH_STE 1
+#define MACH_TT  2
+#define MACH_FALCON 3
+
+/* some constants for memory handling */
+#define ST_RAM 0
+#define TT_RAM 1
+#define TT_RAM_BASE  (u_long)(0x01000000)
+#define MB           (1024 * 1024)
+#define START_MEM    (bi.memory[0].addr)
+#define MEM_SIZE     (bi.memory[0].size)
+
+/* the various CPU- and FPU-types */
+#define AFF_68000 (1)
+#define AFF_68020 (2)
+#define AFF_68030 (4)
+#define AFF_68040 (8)
+#define AFF_68881 (16)
+#define AFF_68882 (32)
+
+/* the possible OS-languages */
+#define USA 0
+#define FRG 1
+#define FRA 2
+#define UK  3
+#define SPA 4
+#define ITA 5
+#define SWE 6
+#define SWF 7
+#define SWG 8
+#define TUR 9
+#define FIN 10
+#define NOR 11
+#define DEN 12
+#define SAU 13
+#define HOL 14
+
+/* some inline functions */
+
+static __inline int fpu_idle_frame_size (void)
+{
+  char fpu_frame[216];
+  __asm__ __volatile__ ("fnop"::);
+  __asm__ __volatile__ ("fsave %0@" : : "a" (fpu_frame));
+  return fpu_frame[1];
+}
+
+static __inline void change_stack (u_long *stackp)
+{
+    __asm__ volatile ("movel %0,sp\n\t" :: "g" (stackp) : "sp");
+}
+
+static __inline void disable_interrupts (void)
+{
+  __asm__ volatile ("orw #0x700,sr":);
+}
+
+extern struct bootinfo bi;
+static __inline void disable_cache (void)
+{
+    __asm__ volatile ("movec %0,cacr" :: "d" (0));
+    if (bi.cputype & CPU_68060) {
+	/* '060: clear branch cache after disabling it;
+	 * disable superscalar operation (and enable FPU) */
+	__asm__ volatile ("movec %0,cacr" :: "d" (0x00400000));
+	__asm__ volatile ("moveq #0,d0;"
+			  ".long 0x4e7b0808"	/* movec d0,pcr */
+			  : /* no outputs */
+			  : /* no inputs */
+			  : "d0");
+    }
+}
+
+static __inline void disable_mmu (void)
+{
+	if (bi.cputype & (CPU_68040|CPU_68060)) {
+	    __asm__ volatile ("moveq #0,d0;"
+						  ".long 0x4e7b0003;"	/* movec d0,tc */
+						  ".long 0x4e7b0004;"	/* movec d0,itt0 */
+						  ".long 0x4e7b0005;"	/* movec d0,itt1 */
+						  ".long 0x4e7b0006;"	/* movec d0,dtt0 */
+						  ".long 0x4e7b0007"	/* movec d0,dtt1 */
+						  : /* no outputs */
+						  : /* no inputs */
+						  : "d0");
+	}
+	else {
+		__asm__ volatile ("subl  #4,sp\n\t"
+						  "pmove tc,sp@\n\t"
+						  "bclr  #7,sp@\n\t"
+						  "pmove sp@,tc\n\t"
+						  "addl  #4,sp");
+		if (bi.cputype & CPU_68030) {
+			__asm__ volatile ("clrl sp@-\n\t"
+							  ".long 0xf0170800\n\t" /* pmove sp@,tt0 */
+							  ".long 0xf0170c00\n\t" /* pmove sp@,tt1 */
+							  "addl  #4,sp\n");
+		}
+	}
+}
+
+static __inline void jump_to_mover (void *, void *, void *, void *, int, int,
+				    void *) __attribute__ ((noreturn));
+static __inline void jump_to_mover (void *kernel_start, void *mem_start,
+				    void *ramdisk_end, void *mem_end,
+				    int kernel_size, int ramdisk_size,
+				    void *mover_addr)
+{
+    asm volatile ("movel %0,a0\n\t"
+		  "movel %1,a1\n\t"
+		  "movel %2,a2\n\t"
+		  "movel %3,a3\n\t"
+		  "movel %4,d0\n\t"
+		  "movel %5,d1\n\t"
+		  "jmp   %6@\n"
+		  : /* no outputs */
+		  : "g" (kernel_start), "g" (mem_start),
+		    "g" (ramdisk_end), "g" (mem_end),
+		    "g" (kernel_size), "g" (ramdisk_size),
+		    "a" (mover_addr)
+		  : "a0", "a1", "a2", "a3", "d0", "d1");
+
+	/* Avoid warning that function may return */
+	for (;;) ;
+}
+
+#endif /* BOOTSTRAP_H */
+
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/boot/atari/sysvars.h linux/arch/m68k/boot/atari/sysvars.h
--- v1.3.93/linux/arch/m68k/boot/atari/sysvars.h	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/boot/atari/sysvars.h	Wed Dec 27 22:44:47 1995
@@ -0,0 +1,22 @@
+typedef struct _osheader
+{
+  unsigned short os_entry;
+  unsigned short os_version;
+  void *reseth;
+  struct _osheader *os_beg;
+  void *os_end;
+  long os_rsv1;
+  void *os_magic;
+  long os_date;
+  unsigned short os_conf;
+  unsigned short os_dosdate;
+  char **p_root;
+  unsigned char **pkbshift;
+  void **p_run;
+  char *p_rsv2;
+} OSHEADER;
+
+#define phystop    ((unsigned long *)0x42e)
+#define _sysbase   ((OSHEADER **)0x4f2)
+#define _p_cookies ((unsigned long **)0x5a0)
+#define ramtop     ((unsigned long *)0x5a4)
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/config.in linux/arch/m68k/config.in
--- v1.3.93/linux/arch/m68k/config.in	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/config.in	Thu Apr 18 02:01:36 1996
@@ -0,0 +1,171 @@
+#
+# For a description of the syntax of this configuration file,
+# see the Configure script.
+#
+mainmenu_name "Linux/68k Kernel Configuration"
+
+mainmenu_option next_comment
+comment 'Loadable module support'
+bool 'Enable loadable module support' CONFIG_MODULES
+if [ "$CONFIG_MODULES" = "y" ]; then
+  bool 'Set version information on all symbols for modules' CONFIG_MODVERSIONS
+  bool 'Kernel daemon support (e.g. autoload of modules)' CONFIG_KERNELD
+fi
+endmenu
+
+mainmenu_option next_comment
+comment 'General setup'
+
+bool 'Amiga support' CONFIG_AMIGA
+bool 'Atari support' CONFIG_ATARI
+bool 'Macintosh support' CONFIG_MAC
+bool '68040 floating point software package' CONFIG_FPSP_040
+bool '68060 integer/floating point software package' CONFIG_IFPSP_060
+bool 'Networking support' CONFIG_NET
+bool 'System V IPC' CONFIG_SYSVIPC
+tristate 'Kernel support for a.out binaries' CONFIG_BINFMT_AOUT
+tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
+if [ "$CONFIG_BINFMT_ELF" = "y" ]; then
+  bool 'Compile kernel as ELF - if your GCC is ELF-GCC' CONFIG_KERNEL_ELF
+fi
+if [ "$CONFIG_AMIGA" = "y" ]; then
+  bool 'Amiga AutoConfig Identification' CONFIG_ZORRO
+fi
+endmenu
+
+#
+# Block device driver configuration
+#
+mainmenu_option next_comment
+comment 'Floppy, IDE, and other block devices'
+
+tristate 'Normal floppy disk support' CONFIG_BLK_DEV_FD
+bool 'IDE harddisk support' CONFIG_BLK_DEV_IDE
+if [ "$CONFIG_AMIGA" = "y" ]; then
+bool 'Amiga Cybervision support' CONFIG_FB_CYBER
+bool 'Amiga Zorro II ramdisk support' CONFIG_AMIGA_Z2RAM
+fi
+if [ "$CONFIG_ATARI" = "y" ]; then
+bool 'Atari ACSI support' CONFIG_ATARI_ACSI
+fi
+
+tristate 'RAM disk support' CONFIG_BLK_DEV_RAM
+if [ "$CONFIG_BLK_DEV_RAM" = "y" ]; then
+  bool '   Initial RAM disk (initrd) support' CONFIG_BLK_DEV_INITRD
+fi
+
+tristate 'Loopback device support' CONFIG_BLK_DEV_LOOP
+endmenu
+
+if [ "$CONFIG_NET" = "y" ]; then
+  source net/Config.in
+fi
+
+mainmenu_option next_comment
+comment 'SCSI support'
+
+tristate 'SCSI support' CONFIG_SCSI
+
+if [ "$CONFIG_SCSI" != "n" ]; then
+
+comment 'SCSI support type (disk, tape, CDrom)'
+
+dep_tristate 'SCSI disk support' CONFIG_BLK_DEV_SD $CONFIG_SCSI
+dep_tristate 'SCSI tape support' CONFIG_CHR_DEV_ST $CONFIG_SCSI
+dep_tristate 'SCSI CDROM support' CONFIG_BLK_DEV_SR $CONFIG_SCSI
+dep_tristate 'SCSI generic support' CONFIG_CHR_DEV_SG $CONFIG_SCSI
+
+comment 'Some SCSI devices (e.g. CD jukebox) support multiple LUNs'
+
+bool 'Probe all LUNs on each SCSI device' CONFIG_SCSI_MULTI_LUN
+
+bool 'Verbose SCSI error reporting (kernel size +=12K)' CONFIG_SCSI_CONSTANTS
+
+mainmenu_option next_comment
+comment 'SCSI low-level drivers'
+
+if [ "$CONFIG_AMIGA" = "y" ]; then
+bool 'A3000 WD33C93A support' CONFIG_A3000_SCSI
+bool 'A2091 WD33C93A support' CONFIG_A2091_SCSI
+bool 'GVP Series II WD33C93A support' CONFIG_GVP11_SCSI
+fi
+if [ "$CONFIG_ATARI" = "y" ]; then
+dep_tristate 'Atari native SCSI support' CONFIG_ATARI_SCSI $CONFIG_SCSI
+fi
+#dep_tristate 'SCSI debugging host adapter' CONFIG_SCSI_DEBUG $CONFIG_SCSI
+endmenu
+
+fi
+endmenu
+
+if [ "$CONFIG_NET" = "y" ]; then
+
+mainmenu_option next_comment
+comment 'Network device support'
+
+bool 'Network device support' CONFIG_NETDEVICES
+if [ "$CONFIG_NETDEVICES" = "y" ]; then
+#
+# Network device configuration
+#
+tristate 'Dummy net driver support' CONFIG_DUMMY
+tristate 'SLIP (serial line) support' CONFIG_SLIP
+if [ "$CONFIG_SLIP" != "n" ]; then
+  bool ' CSLIP compressed headers' CONFIG_SLIP_COMPRESSED
+fi
+tristate 'PPP (point-to-point) support' CONFIG_PPP
+if [ ! "$CONFIG_PPP" = "n" ]; then
+  comment 'CCP compressors for PPP are only built as modules.'
+fi
+tristate 'EQL (serial line load balancing) support' CONFIG_EQUALIZER
+if [ "$CONFIG_AMIGA" = "y" ]; then
+  bool 'Ariadne support' CONFIG_ARIADNE
+  bool 'A2065 support' CONFIG_A2065
+  bool 'Hydra support' CONFIG_HYDRA
+fi
+if [ "$CONFIG_ATARI" = "y" ]; then
+  bool 'Atari Lance support' CONFIG_ATARILANCE
+fi
+fi
+endmenu
+
+fi
+
+source fs/Config.in
+
+mainmenu_option next_comment
+comment 'Character devices'
+
+bool 'Parallel printer support' CONFIG_PRINTER
+if [ "$CONFIG_AMIGA" = "y" ]; then
+  tristate 'Amiga mouse support' CONFIG_AMIGAMOUSE
+fi
+if [ "$CONFIG_ATARI" = "y" ]; then
+  tristate 'Atari mouse support' CONFIG_ATARIMOUSE
+fi
+bool 'Watchdog Timer Support'	CONFIG_WATCHDOG
+if [ "$CONFIG_WATCHDOG" != "n" ]; then
+  bool '   Disable watchdog shutdown on close' CONFIG_WATCHDOG_NOWAYOUT
+  bool '   Software Watchdog' CONFIG_SOFT_WATCHDOG
+fi
+bool 'Support for user misc device modules' CONFIG_UMISC
+endmenu
+
+mainmenu_option next_comment
+comment 'Sound support'
+
+bool 'Sound support' CONFIG_SOUND y
+if [ "$CONFIG_SOUND" != "n" ]; then
+  bool 'Amiga or Atari DMA sound support' CONFIG_DMASOUND y
+fi
+endmenu
+
+mainmenu_option next_comment
+comment 'Kernel hacking'
+
+#bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC
+bool 'Kernel profiling support' CONFIG_PROFILE
+if [ "$CONFIG_PROFILE" = "y" ]; then
+  int ' Profile shift count' CONFIG_PROFILE_SHIFT 2
+fi
+endmenu
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/console/Makefile linux/arch/m68k/console/Makefile
--- v1.3.93/linux/arch/m68k/console/Makefile	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/console/Makefile	Sat Mar 23 16:36:12 1996
@@ -0,0 +1,15 @@
+#
+# 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).
+#
+
+EXTRA_CFLAGS := -Wa,-m68030
+
+L_TARGET = console.a
+L_OBJS = fbcon.o fonts.o font_8x16.o font_8x8.o
+M_OBJS =
+
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/console/fbcon.c linux/arch/m68k/console/fbcon.c
--- v1.3.93/linux/arch/m68k/console/fbcon.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/console/fbcon.c	Sun Mar 17 18:10:37 1996
@@ -0,0 +1,3618 @@
+/*
+ * 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 README.legal 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/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 <asm/bootinfo.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 /* CONFIG_FB_CYBER */
+#include <linux/fb.h>
+#include <asm/font.h>
+#include <asm/machdep.h>
+
+#include <asm/system.h>
+
+#include "../../../drivers/char/vt_kern.h"   /* vt_cons and vc_resize_con() */
+
+
+/* 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
+
+
+/* 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 /* CONFIG_FB_CYBER */
+
+#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_8PACKED) || \
+    defined(CONFIG_FBCON_16PACKED) || defined(CONFIG_FBCON_24PACKED) || \
+    defined(CONFIG_FBCON_32PACKED)
+#define CONFIG_FBCON_PACKED
+#else
+#undef CONFIG_FBCON_PACKED
+#endif
+
+
+struct fb_info *fb_info;
+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, 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 y, int x);
+static int fbcon_putcs(struct vc_data *conp, const char *s, int count, int y,
+                       int x);
+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);
+
+
+   /*
+    *    Internal routines
+    */
+
+static void fbcon_setup(int con, int setcol, int cls);
+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 y);
+static void fbcon_vbl_handler(int irq, struct pt_regs *fp, void *dummy);
+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 y,
+                      int x);
+static void putcs_mono(struct vc_data *conp, struct display *p, const char *s,
+                       int count, int y, int x);
+static void rev_char_mono(struct display *p, int x, int y);
+#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 y,
+                      int x);
+static void putcs_ilbm(struct vc_data *conp, struct display *p, const char *s,
+                       int count, int y, int x);
+static void rev_char_ilbm(struct display *p, int x, int y);
+#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 y,
+                      int x);
+static void putcs_plan(struct vc_data *conp, struct display *p, const char *s,
+                       int count, int y, int x);
+static void rev_char_plan(struct display *p, int x, int y);
+#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 y,
+                         int x);
+static void putcs_2_plane(struct vc_data *conp, struct display *p,
+                          const char *s, int count, int y, int x);
+static void rev_char_2_plane(struct display *display, int x, int y);
+#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 y,
+                         int x);
+static void putcs_4_plane(struct vc_data *conp, struct display *p,
+                          const char *s, int count, int y, int x);
+static void rev_char_4_plane(struct display *p, int x, int y);
+#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 y,
+                         int x);
+static void putcs_8_plane(struct vc_data *conp, struct display *p,
+                          const char *s, int count, int y, int x);
+static void rev_char_8_plane(struct display *display, int x, int y);
+#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 y,
+                          int x);
+static void putcs_8_packed(struct vc_data *conp, struct display *p,
+                           const char *s, int count, int y, int x);
+static void rev_char_8_packed(struct display *p, int x, int y);
+#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 y, int x);
+static void putcs_16_packed(struct vc_data *conp, struct display *p,
+                            const char *s, int count, int y, int x);
+static void rev_char_16_packed(struct display *p, int x, int y);
+#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 y,
+                       int x);
+static void putcs_cyber(struct vc_data *conp, struct display *p, const char *s,
+                        int count, int y, int x);
+static void rev_char_cyber(struct display *p, int x, int y);
+
+extern void Cyber_WaitQueue(u_short fifo);
+extern void Cyber_WaitBlit(void);
+extern void Cyber_BitBLT(u_short curx, u_short cury, u_short destx,
+                         u_short desty, u_short width, u_short height,
+                         u_short mode);
+extern void Cyber_RectFill(u_short x, u_short y, u_short width, u_short height,
+                           u_short mode, u_short color);
+extern void Cyber_MoveCursor(u_short x, u_short y);
+#endif /* CONFIG_FBCON_CYBER */
+
+
+   /*
+    *    `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 y, int x);
+    void (*putcs)(struct vc_data *conp, struct display *p, const char *s,
+                  int count, int y, int x);
+    void (*rev_char)(struct display *p, int x, int y);
+};
+
+
+#ifdef CONFIG_FBCON_MONO
+struct display_switch dispsw_mono = {
+   bmove_mono, clear_mono, putc_mono, putcs_mono, rev_char_mono
+};
+#endif /* CONFIG_FBCON_MONO */
+
+#ifdef CONFIG_FBCON_ILBM
+struct display_switch dispsw_ilbm = {
+   bmove_ilbm, clear_ilbm, putc_ilbm, putcs_ilbm, rev_char_ilbm
+};
+#endif /* CONFIG_FBCON_ILBM */
+
+#ifdef CONFIG_FBCON_PLANES
+struct display_switch dispsw_plan = {
+   bmove_plan, clear_plan, putc_plan, putcs_plan, rev_char_plan
+};
+#endif /* CONFIG_FBCON_PLANES */
+
+#ifdef CONFIG_FBCON_2PLANE
+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
+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
+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
+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
+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
+struct display_switch dispsw_cyber = {
+   bmove_cyber, clear_cyber, putc_cyber, putcs_cyber, rev_char_cyber
+};
+#endif /* CONFIG_FBCON_CYBER */
+
+
+static u_long fbcon_startup(u_long kmem_start, 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 = add_isr(IRQ_AMIGA_VERTB, fbcon_vbl_handler, 0, NULL,
+                       "console/cursor");
+   }
+#endif /* CONFIG_AMIGA */
+#ifdef CONFIG_ATARI
+   if (MACH_IS_ATARI) {
+      cursor_blink_rate = ATARI_CURSOR_BLINK_RATE;
+      irqres = add_isr(IRQ_AUTO_4, fbcon_vbl_handler, IRQ_TYPE_PRIO, NULL,
+		       "console/cursor");
+   }
+#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, 0);
+}
+
+
+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, 1);
+   return(0);
+}
+
+
+static void fbcon_setup(int con, int setcol, int cls)
+{
+   struct display *p = &disp[con];
+   struct vc_data *conp = p->conp;
+
+   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)
+      panic("fbcon_setup: No support for fontwidth != 8");
+
+   if (divides(p->ywrapstep, p->fontheight))
+      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;
+
+   conp->vc_cols = p->var.xres/p->fontwidth;
+   conp->vc_rows = p->var.yres/p->fontheight;
+   conp->vc_can_do_color = p->var.bits_per_pixel != 1;
+
+#ifdef CONFIG_FBCON_MONO
+   if (p->var.bits_per_pixel == 1) {
+      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) {
+      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) {
+      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 /* CONFIG_FBCON_CYBER */
+#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);
+      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 (cls)
+      vc_resize_con(conp->vc_rows, conp->vc_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 thats 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
+ * asynchronisity.
+ *
+ * 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 clearity, 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 y)
+{
+   int rows = p->conp->vc_rows;
+
+   y += p->yscroll;
+   return(y < rows || p->scrollmode != SCROLL_YWRAP ? y : y-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 = conp->vc_rows-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 y, int x)
+{
+   int unit = conp->vc_num;
+   struct display *p = &disp[unit];
+
+   if (!p->can_soft_blank && console_blanked)
+      return(0);
+
+   if ((p->cursor_x == x) && (p->cursor_y == y))
+       CURSOR_UNDRAWN();
+
+   p->dispsw->putc(conp, p, c, real_y(p, y), x);
+
+   return(0);
+}
+
+
+static int fbcon_putcs(struct vc_data *conp, const char *s, int count, int y,
+                       int x)
+{
+   int unit = conp->vc_num;
+   struct display *p = &disp[unit];
+
+   if (!p->can_soft_blank && console_blanked)
+      return(0);
+
+   if ((p->cursor_y == y) && (x <= p->cursor_x) && (p->cursor_x < x+count))
+      CURSOR_UNDRAWN();
+
+   p->dispsw->putcs(conp, p, s, count, real_y(p, y), x);
+
+   return(0);
+}
+
+
+static int fbcon_cursor(struct vc_data *conp, int mode)
+{
+   int unit = conp->vc_num;
+   struct display *p = &disp[unit];
+
+   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, struct pt_regs *fp, void *dummy)
+{
+   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 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 (t == 0 && b == conp->vc_rows &&
+             vt_cons[unit]->vc_mode == KD_TEXT) {
+            if (count > conp->vc_rows)             /* Maximum realistic size */
+               count = conp->vc_rows;
+            switch (p->scrollmode) {
+               case SCROLL_YWRAP:
+                  p->yscroll += count;
+                  if (p->yscroll >= conp->vc_rows) /* Deal with wrap */
+                     p->yscroll -= conp->vc_rows;
+                  p->var.xoffset = 0;
+                  p->var.yoffset = p->yscroll*p->fontheight;
+                  p->var.vmode |= FB_VMODE_YWRAP;
+                  fb_info->updatevar(unit);
+                  break;
+
+               case SCROLL_YPAN:
+                  p->yscroll += count;
+                  if (p->yscroll*p->fontheight+p->var.yres >
+                      p->var.yres_virtual) {
+                     p->dispsw->bmove(p, p->yscroll, 0, 0, 0, b-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);
+                  break;
+
+               case SCROLL_YMOVE:
+                  p->dispsw->bmove(p, count, 0, 0, 0, b-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 (t == 0 && b == conp->vc_rows &&
+             vt_cons[unit]->vc_mode == KD_TEXT) {
+            if (count > conp->vc_rows)             /* Maximum realistic size */
+               count = conp->vc_rows;
+            switch (p->scrollmode) {
+               case SCROLL_YWRAP:
+                  p->yscroll -= count;
+                  if (p->yscroll < 0)              /* Deal with wrap */
+                     p->yscroll += conp->vc_rows;
+                  p->var.xoffset = 0;
+                  p->var.yoffset = p->yscroll*p->fontheight;
+                  p->var.vmode |= FB_VMODE_YWRAP;
+                  fb_info->updatevar(unit);
+                  break;
+
+               case SCROLL_YPAN:
+                  p->yscroll -= count;
+                  if (p->yscroll < 0) {
+                     p->yscroll = (p->var.yres_virtual-p->var.yres)/
+                                  p->fontheight;
+                     p->dispsw->bmove(p, 0, 0, p->yscroll+count, 0, b-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);
+                  break;
+
+               case SCROLL_YMOVE:
+                  p->dispsw->bmove(p, 0, 0, count, 0, b-count, conp->vc_cols);
+                  break;
+            }
+         } else
+            fbcon_bmove(conp, t, 0, t+count, 0, b-t-count, conp->vc_cols);
+
+         /* Fixed bmove() should end Arno's frustration with copying?
+          * Confusius says:
+          *    Man who copies in wrong direction, end up with trashed data
+          */
+         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, conp->vc_rows-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);
+}
+
+
+/* ====================================================================== */
+
+/*
+ *    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 && sy == 0 && width == p->next_line) {
+      src = p->screen_base;
+      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 y,
+                      int x)
+{
+   u_char *dest, *cdat;
+   u_int rows, bold, reverse, underline;
+   u_char d;
+
+   c &= 0xff;
+
+   dest = p->screen_base+y*p->fontheight*p->next_line+x;
+   cdat = p->fontdata+c*p->fontheight;
+   bold = attr_bold(p,conp);
+   reverse = attr_reverse(p,conp);
+   underline = attr_underline(p,conp);
+
+   for (rows = p->fontheight; rows--; dest += p->next_line) {
+      d = *cdat++;
+      if (underline && !rows)
+         d = 0xff;
+      else if (bold)
+         d |= d>>1;
+      if (reverse)
+         d = ~d;
+      *dest = d;
+   }
+}
+
+
+static void putcs_mono(struct vc_data *conp, struct display *p, const char *s,
+                       int count, int y, int x)
+{
+   u_char *dest, *dest0, *cdat;
+   u_int rows, bold, reverse, underline;
+   u_char c, d;
+
+   dest0 = p->screen_base+y*p->fontheight*p->next_line+x;
+   bold = attr_bold(p,conp);
+   reverse = attr_reverse(p,conp);
+   underline = 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 (underline && !rows)
+            d = 0xff;
+         else if (bold)
+            d |= d>>1;
+         if (reverse)
+            d = ~d;
+         *dest = d;
+      }
+   }
+}
+
+
+static void rev_char_mono(struct display *p, int x, int y)
+{
+   u_char *dest;
+   u_int rows;
+
+   dest = p->screen_base+y*p->fontheight*p->next_line+x;
+   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 && sy == 0 && width == p->next_plane)
+      mymemmove(p->screen_base+dy*p->fontheight*p->next_line, p->screen_base,
+                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 y,
+                      int x)
+{
+   u_char *dest, *cdat;
+   u_int rows, i;
+   u_char d;
+   int fg0, bg0, fg, bg;
+
+   c &= 0xff;
+
+   dest = p->screen_base+y*p->fontheight*p->next_line+x;
+   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 splitted 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 y, int x)
+{
+   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+y*p->fontheight*p->next_line+x;
+   fg0 = attr_fgcol(p,conp);
+   bg0 = attr_bgcol(p,conp);
+
+   while (count--)
+      if (x&3 || count < 3) {   /* Slow version */
+         c1 = *s++;
+         dest = dest0++;
+         x++;
+
+         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;
+         x += 4;
+         count -= 3;
+      }
+}
+
+
+static void rev_char_ilbm(struct display *p, int x, int y)
+{
+   u_char *dest, *dest0;
+   u_int rows, i;
+   int mask;
+
+   dest0 = p->screen_base+y*p->fontheight*p->next_line+x;
+   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 && sy == 0 && width == p->next_line) {
+      src = p->screen_base;
+      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 y,
+                      int x)
+{
+   u_char *dest, *dest0, *cdat, *cdat0;
+   u_int rows, i;
+   u_char d;
+   int fg, bg;
+
+   c &= 0xff;
+
+   dest0 = p->screen_base+y*p->fontheight*p->next_line+x;
+   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 splitted 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 y, int x)
+{
+   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+y*p->fontheight*p->next_line+x;
+   fg0 = attr_fgcol(p,conp);
+   bg0 = attr_bgcol(p,conp);
+
+   while (count--)
+      if (x&3 || count < 3) {   /* Slow version */
+         c1 = *s++;
+         dest1 = dest0++;
+         x++;
+
+         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;
+         x += 4;
+         count -= 3;
+      }
+}
+
+
+static void rev_char_plan(struct display *p, int x, int y)
+{
+   u_char *dest, *dest0;
+   u_int rows, i;
+   int mask;
+
+   dest0 = p->screen_base+y*p->fontheight*p->next_line+x;
+   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 adjancent
+	 * 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 y,
+                         int x)
+{
+   u_char   *dest;
+    u_char   *cdat;
+    int rows;
+    int bytes = p->next_line;
+	ulong			  eorx, fgx, bgx, fdx;
+
+	c &= 0xff;
+
+    dest  = p->screen_base + y * p->fontheight * bytes + (x>>1)*4 + (x & 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 y, int x)
+{
+	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 + y * p->fontheight * bytes + (x>>1)*4 + (x & 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 x, int y)
+{
+   u_char *dest;
+   int j;
+   int bytes;
+
+   dest = p->screen_base + y * p->fontheight * p->next_line + (x>>1)*4 + (x & 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 adjancent
+	 * 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 y,
+                         int x)
+{
+	u_char   *dest;
+    u_char   *cdat;
+    int rows;
+    int bytes = p->next_line;
+	ulong			  eorx, fgx, bgx, fdx;
+
+	c &= 0xff;
+
+    dest  = p->screen_base + y * p->fontheight * bytes + (x>>1)*8 + (x & 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 y, int x)
+{
+	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 + y * p->fontheight * bytes + (x>>1)*8 + (x & 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 x, int y)
+{
+   u_char *dest;
+   int j;
+   int bytes;
+
+   dest = p->screen_base + y * p->fontheight * p->next_line + (x>>1)*8 + (x & 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 y,
+                         int x)
+{
+	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 + y * p->fontheight * bytes + (x>>1)*16 + (x & 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 y, int x)
+{
+	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 + y * p->fontheight * bytes + (x>>1)*16 + (x & 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 x, int y)
+{
+   u_char *dest;
+   int j;
+   int bytes;
+
+   dest = p->screen_base + y * p->fontheight * p->next_line + (x>>1)*16 + (x & 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 y,
+                          int x)
+{
+	u_char *dest,*cdat;
+	int bytes=p->next_line,rows;
+	ulong eorx,fgx,bgx;
+
+	c &= 0xff;
+
+	dest = p->screen_base + y * p->fontheight * bytes + x * 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 y, int x)
+{
+	u_char *cdat, c, *dest, *dest0;
+	int rows,bytes=p->next_line;
+	u_long eorx, fgx, bgx;
+
+	dest0 = p->screen_base + y * p->fontheight * bytes + x * 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 x, int y)
+{
+	u_char *dest;
+	int bytes=p->next_line, rows;
+
+	dest = p->screen_base + y * p->fontheight * bytes + x * 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 y, int x)
+{
+	u_char *dest,*cdat;
+	int bytes=p->next_line,rows;
+	ulong eorx,fgx,bgx;
+
+	c &= 0xff;
+
+	dest = p->screen_base + y * p->fontheight * bytes + x * 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 y, int x)
+{
+	u_char *cdat, c, *dest, *dest0;
+	int rows,bytes=p->next_line;
+	u_long eorx, fgx, bgx;
+
+	dest0 = p->screen_base + y * p->fontheight * bytes + x * 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 x, int y)
+{
+	u_char *dest;
+	int bytes=p->next_line, rows;
+
+	dest = p->screen_base + y * p->fontheight * bytes + x * 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)
+{
+   u_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 y,
+                       int x)
+{
+	u_char *dest, *cdat;
+	u_long tmp;
+	u_int rows, reverse, underline; 
+	u_char d;
+   u_char fg, bg;
+
+   c &= 0xff;
+
+	dest = p->screen_base+y*p->fontheight*p->next_line+8*x;
+	cdat = p->fontdata+(c*p->fontheight);
+   fg = disp->fgcol;
+   bg = disp->bgcol;
+	reverse = conp->vc_reverse;
+	underline = conp->vc_underline;
+
+   Cyber_WaitBlit();
+	for (rows = p->fontheight; rows--; dest += p->next_line) {
+  		d = *cdat++;
+
+		if (underline && !rows)
+			d = 0xff;
+		if (reverse)
+			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 y, int x)
+{
+	u_char *dest, *dest0, *cdat;
+   u_long tmp;
+	u_int rows, reverse, underline;
+	u_char c, d;
+   u_char fg, bg;
+
+	dest0 = p->screen_base+y*p->fontheight*p->next_line+8*x;
+   fg = disp->fgcol;
+   bg = disp->bgcol;
+	reverse = conp->vc_reverse;
+	underline = 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 (underline && !rows)
+				d = 0xff;
+			if (reverse)
+				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 x, int y)
+{
+	u_char *dest;
+	u_int rows;
+   u_char fg, bg;
+
+   fg = disp->fgcol;
+   bg = disp->bgcol;
+
+	dest = p->screen_base+y*p->fontheight*p->next_line+8*x;
+   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 */
+
+
+/* ====================================================================== */
+
+   /*
+    *    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
+};
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/console/font_8x16.c linux/arch/m68k/console/font_8x16.c
--- v1.3.93/linux/arch/m68k/console/font_8x16.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/console/font_8x16.c	Mon Mar  4 22:38:11 1996
@@ -0,0 +1,4625 @@
+/**********************************************/
+/*                                            */
+/*       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 v1.3.93/linux/arch/m68k/console/font_8x8.c linux/arch/m68k/console/font_8x8.c
--- v1.3.93/linux/arch/m68k/console/font_8x8.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/console/font_8x8.c	Mon Mar  4 22:38:11 1996
@@ -0,0 +1,2577 @@
+/**********************************************/
+/*                                            */
+/*       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 v1.3.93/linux/arch/m68k/console/fonts.c linux/arch/m68k/console/fonts.c
--- v1.3.93/linux/arch/m68k/console/fonts.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/console/fonts.c	Mon Mar  4 22:38:11 1996
@@ -0,0 +1,100 @@
+
+/*
+ * 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 README.legal in the main directory of this archive
+ * for more details.
+ */
+
+
+#include <linux/types.h>
+#include <linux/string.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[];
+
+
+   /*
+    *    Font Descriptor Array
+    */
+
+struct softfontdesc {
+   char *name;
+   int *width;
+   int *height;
+   u_char *data;
+};
+
+static struct softfontdesc softfonts[] = {
+   { fontname_8x8, &fontwidth_8x8, &fontheight_8x8, fontdata_8x8 },
+   { fontname_8x16, &fontwidth_8x16, &fontheight_8x16, fontdata_8x16 }
+};
+
+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[])
+{
+   if (yres < 400) {
+      if (name)
+   	   *name = fontname_8x8;
+   	if (width)
+   	   *width = fontwidth_8x8;
+   	if (height)
+   	   *height = fontheight_8x8;
+   	if (data)
+         *data = fontdata_8x8;
+	} else {
+      if (name)
+   	   *name = fontname_8x16;
+   	if (width)
+   	   *width = fontwidth_8x16;
+   	if (height)
+   	   *height = fontheight_8x16;
+   	if (data)
+         *data = fontdata_8x16;
+	}
+}
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/console/txtcon.c linux/arch/m68k/console/txtcon.c
--- v1.3.93/linux/arch/m68k/console/txtcon.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/console/txtcon.c	Mon Mar  4 22:38:11 1996
@@ -0,0 +1,127 @@
+/*
+ * 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 README.legal 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, 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 u_long txtcon_startup(u_long kmem_start, 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);
+}
+
+
+/* ====================================================================== */
+
+   /*
+    *    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
+};
+
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/defconfig linux/arch/m68k/defconfig
--- v1.3.93/linux/arch/m68k/defconfig	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/defconfig	Thu Apr 18 02:01:36 1996
@@ -0,0 +1,145 @@
+#
+# Automatically generated make config: don't edit
+#
+
+#
+# Loadable module support
+#
+# CONFIG_MODULES is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_KERNELD is not set
+
+#
+# General setup
+#
+CONFIG_AMIGA=y
+# CONFIG_ATARI is not set
+# CONFIG_MAC is not set
+CONFIG_FPSP_040=y
+# CONFIG_IFPSP_060 is not set
+# CONFIG_NET is not set
+CONFIG_SYSVIPC=y
+CONFIG_BINFMT_AOUT=y
+CONFIG_BINFMT_ELF=y
+CONFIG_KERNEL_ELF=y
+# CONFIG_ZORRO is not set
+
+#
+# Block device driver configuration
+#
+CONFIG_BLK_DEV_FD=y
+CONFIG_BLK_DEV_RAM=y
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_IDE is not set
+# CONFIG_FB_CYBER is not set
+# CONFIG_AMIGA_Z2RAM is not set
+# CONFIG_ATARI_ACSI is not set
+
+#
+# Networking options
+#
+# CONFIG_FIREWALL is not set
+# CONFIG_NET_ALIAS is not set
+CONFIG_INET=y
+# CONFIG_IP_FORWARD is not set
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_FIREWALL is not set
+# CONFIG_IP_ACCT is not set
+
+#
+# (it is safe to leave these untouched)
+#
+# CONFIG_INET_PCTCP is not set
+# CONFIG_INET_RARP is not set
+# CONFIG_NO_PATH_MTU_DISCOVERY is not set
+# CONFIG_TCP_NAGLE_OFF is not set
+CONFIG_IP_NOSR=y
+# CONFIG_SKB_LARGE is not set
+
+#
+#  
+#
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_AX25 is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_NETLINK is not set
+
+#
+# SCSI support
+#
+CONFIG_SCSI=y
+
+#
+# SCSI support type (disk, tape, CDrom)
+#
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_ST=y
+CONFIG_BLK_DEV_SR=y
+# CONFIG_CHR_DEV_SG is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+
+#
+# SCSI low-level drivers
+#
+CONFIG_A3000_SCSI=y
+# CONFIG_A2091_SCSI is not set
+# CONFIG_GVP11_SCSI is not set
+# CONFIG_ATARI_SCSI is not set
+
+#
+# Network device support
+#
+# CONFIG_NETDEVICES is not set
+# CONFIG_DUMMY is not set
+# CONFIG_SLIP is not set
+# CONFIG_PPP is not set
+# CONFIG_ARIADNE is not set
+# CONFIG_A2065 is not set
+# CONFIG_HYDRA is not set
+# CONFIG_ATARILANCE is not set
+
+#
+# Filesystems
+#
+# CONFIG_QUOTA is not set
+CONFIG_MINIX_FS=y
+# CONFIG_EXT_FS is not set
+CONFIG_EXT2_FS=y
+# CONFIG_XIA_FS is not set
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+# CONFIG_VFAT_FS is not set
+# CONFIG_UMSDOS_FS is not set
+CONFIG_PROC_FS=y
+CONFIG_NFS_FS=y
+# CONFIG_ROOT_NFS is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_ISO9660_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_AFFS_FS is not set
+
+#
+# Character devices
+#
+# CONFIG_PRINTER is not set
+CONFIG_AMIGAMOUSE=y
+# CONFIG_ATARIMOUSE is not set
+# CONFIG_UMISC is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+# CONFIG_DMASOUND is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PROFILE is not set
+CONFIG_SCSI_CONSTANTS=y
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/fpsp040/Makefile linux/arch/m68k/fpsp040/Makefile
--- v1.3.93/linux/arch/m68k/fpsp040/Makefile	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/fpsp040/Makefile	Thu Dec 28 01:15:11 1995
@@ -0,0 +1,31 @@
+#
+# Makefile for Linux arch/m68k/fpsp040 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).
+#
+# Note 2! The CFLAGS definitions are now in the main makefile...
+
+.S.o:
+	$(CC) -D__ASSEMBLY__ -traditional -c -o $*.o $<
+#	$(AS) -o $*.o $<
+
+OS_TARGET := fpsp.o
+
+OS_OBJS   := bindec.o binstr.o decbin.o do_func.o gen_except.o get_op.o \
+	    kernel_ex.o res_func.o round.o sacos.o sasin.o satan.o satanh.o \
+	    scosh.o setox.o sgetem.o sint.o slog2.o slogn.o \
+	    smovecr.o srem_mod.o scale.o \
+	    ssin.o ssinh.o stan.o stanh.o sto_res.o stwotox.o tbldo.o util.o \
+	    x_bsun.o x_fline.o x_operr.o x_ovfl.o x_snan.o x_store.o \
+	    x_unfl.o x_unimp.o x_unsupp.o bugfix.o skeleton.o
+
+all:	$(OS_TARGET)
+
+include $(TOPDIR)/Rules.make
+
+$(OS_OBJS): fpsp.h
+
+$(OS_TARGET): $(OS_OBJS) fpsp.h
+	$(LD) -x -r -o $(OS_TARGET) $(OS_OBJS)
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/fpsp040/bindec.S linux/arch/m68k/fpsp040/bindec.S
--- v1.3.93/linux/arch/m68k/fpsp040/bindec.S	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/fpsp040/bindec.S	Sat Feb 24 22:58:42 1996
@@ -0,0 +1,920 @@
+|
+|	bindec.sa 3.4 1/3/91
+|
+|	bindec
+|
+|	Description:
+|		Converts an input in extended precision format
+|		to bcd format.
+|
+|	Input:
+|		a0 points to the input extended precision value
+|		value in memory; d0 contains the k-factor sign-extended
+|		to 32-bits.  The input may be either normalized,
+|		unnormalized, or denormalized.
+|
+|	Output:	result in the FP_SCR1 space on the stack.
+|
+|	Saves and Modifies: D2-D7,A2,FP2
+|
+|	Algorithm:
+|
+|	A1.	Set RM and size ext;  Set SIGMA = sign of input.  
+|		The k-factor is saved for use in d7. Clear the
+|		BINDEC_FLG for separating normalized/denormalized
+|		input.  If input is unnormalized or denormalized,
+|		normalize it.
+|
+|	A2.	Set X = abs(input).
+|
+|	A3.	Compute ILOG.
+|		ILOG is the log base 10 of the input value.  It is
+|		approximated by adding e + 0.f when the original 
+|		value is viewed as 2^^e * 1.f in extended precision.  
+|		This value is stored in d6.
+|
+|	A4.	Clr INEX bit.
+|		The operation in A3 above may have set INEX2.  
+|
+|	A5.	Set ICTR = 0;
+|		ICTR is a flag used in A13.  It must be set before the 
+|		loop entry A6.
+|
+|	A6.	Calculate LEN.
+|		LEN is the number of digits to be displayed.  The
+|		k-factor can dictate either the total number of digits,
+|		if it is a positive number, or the number of digits
+|		after the decimal point which are to be included as
+|		significant.  See the 68882 manual for examples.
+|		If LEN is computed to be greater than 17, set OPERR in
+|		USER_FPSR.  LEN is stored in d4.
+|
+|	A7.	Calculate SCALE.
+|		SCALE is equal to 10^ISCALE, where ISCALE is the number
+|		of decimal places needed to insure LEN integer digits
+|		in the output before conversion to bcd. LAMBDA is the
+|		sign of ISCALE, used in A9. Fp1 contains
+|		10^^(abs(ISCALE)) using a rounding mode which is a
+|		function of the original rounding mode and the signs
+|		of ISCALE and X.  A table is given in the code.
+|
+|	A8.	Clr INEX; Force RZ.
+|		The operation in A3 above may have set INEX2.  
+|		RZ mode is forced for the scaling operation to insure
+|		only one rounding error.  The grs bits are collected in 
+|		the INEX flag for use in A10.
+|
+|	A9.	Scale X -> Y.
+|		The mantissa is scaled to the desired number of
+|		significant digits.  The excess digits are collected
+|		in INEX2.
+|
+|	A10.	Or in INEX.
+|		If INEX is set, round error occured.  This is
+|		compensated for by 'or-ing' in the INEX2 flag to
+|		the lsb of Y.
+|
+|	A11.	Restore original FPCR; set size ext.
+|		Perform FINT operation in the user's rounding mode.
+|		Keep the size to extended.
+|
+|	A12.	Calculate YINT = FINT(Y) according to user's rounding
+|		mode.  The FPSP routine sintd0 is used.  The output
+|		is in fp0.
+|
+|	A13.	Check for LEN digits.
+|		If the int operation results in more than LEN digits,
+|		or less than LEN -1 digits, adjust ILOG and repeat from
+|		A6.  This test occurs only on the first pass.  If the
+|		result is exactly 10^LEN, decrement ILOG and divide
+|		the mantissa by 10.
+|
+|	A14.	Convert the mantissa to bcd.
+|		The binstr routine is used to convert the LEN digit 
+|		mantissa to bcd in memory.  The input to binstr is
+|		to be a fraction; i.e. (mantissa)/10^LEN and adjusted
+|		such that the decimal point is to the left of bit 63.
+|		The bcd digits are stored in the correct position in 
+|		the final string area in memory.
+|
+|	A15.	Convert the exponent to bcd.
+|		As in A14 above, the exp is converted to bcd and the
+|		digits are stored in the final string.
+|		Test the length of the final exponent string.  If the
+|		length is 4, set operr.
+|
+|	A16.	Write sign bits to final string.
+|
+|	Implementation Notes:
+|
+|	The registers are used as follows:
+|
+|		d0: scratch; LEN input to binstr
+|		d1: scratch
+|		d2: upper 32-bits of mantissa for binstr
+|		d3: scratch;lower 32-bits of mantissa for binstr
+|		d4: LEN
+|      		d5: LAMBDA/ICTR
+|		d6: ILOG
+|		d7: k-factor
+|		a0: ptr for original operand/final result
+|		a1: scratch pointer
+|		a2: pointer to FP_X; abs(original value) in ext
+|		fp0: scratch
+|		fp1: scratch
+|		fp2: scratch
+|		F_SCR1:
+|		F_SCR2:
+|		L_SCR1:
+|		L_SCR2:
+
+|		Copyright (C) Motorola, Inc. 1990
+|			All Rights Reserved
+|
+|	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA 
+|	The copyright notice above does not evidence any  
+|	actual or intended publication of such source code.
+
+|BINDEC    idnt    2,1 | Motorola 040 Floating Point Software Package
+
+	.include "fpsp.h"
+
+	|section	8
+
+| Constants in extended precision
+LOG2: 	.long	0x3FFD0000,0x9A209A84,0xFBCFF798,0x00000000
+LOG2UP1:	.long	0x3FFD0000,0x9A209A84,0xFBCFF799,0x00000000
+
+| Constants in single precision
+FONE: 	.long	0x3F800000,0x00000000,0x00000000,0x00000000
+FTWO:	.long	0x40000000,0x00000000,0x00000000,0x00000000
+FTEN: 	.long	0x41200000,0x00000000,0x00000000,0x00000000
+F4933:	.long	0x459A2800,0x00000000,0x00000000,0x00000000
+
+RBDTBL: 	.byte	0,0,0,0
+	.byte	3,3,2,2
+	.byte	3,2,2,3
+	.byte	2,3,3,2
+
+	|xref	binstr
+	|xref	sintdo
+	|xref	ptenrn,ptenrm,ptenrp
+
+	.global	bindec
+	.global	sc_mul
+bindec:
+	moveml	%d2-%d7/%a2,-(%a7)
+	fmovemx %fp0-%fp2,-(%a7)
+
+| A1. Set RM and size ext. Set SIGMA = sign input;
+|     The k-factor is saved for use in d7.  Clear BINDEC_FLG for
+|     separating  normalized/denormalized input.  If the input
+|     is a denormalized number, set the BINDEC_FLG memory word
+|     to signal denorm.  If the input is unnormalized, normalize
+|     the input and test for denormalized result.  
+|
+	fmovel	#rm_mode,%FPCR	|set RM and ext
+	movel	(%a0),L_SCR2(%a6)	|save exponent for sign check
+	movel	%d0,%d7		|move k-factor to d7
+	clrb	BINDEC_FLG(%a6)	|clr norm/denorm flag
+	movew	STAG(%a6),%d0	|get stag
+	andiw	#0xe000,%d0	|isolate stag bits
+	beq	A2_str		|if zero, input is norm
+|
+| Normalize the denorm
+|
+un_de_norm:
+	movew	(%a0),%d0
+	andiw	#0x7fff,%d0	|strip sign of normalized exp
+	movel	4(%a0),%d1
+	movel	8(%a0),%d2
+norm_loop:
+	subw	#1,%d0
+	lsll	#1,%d2
+	roxll	#1,%d1
+	tstl	%d1
+	bges	norm_loop
+|
+| Test if the normalized input is denormalized
+|
+	tstw	%d0
+	bgts	pos_exp		|if greater than zero, it is a norm
+	st	BINDEC_FLG(%a6)	|set flag for denorm
+pos_exp:
+	andiw	#0x7fff,%d0	|strip sign of normalized exp
+	movew	%d0,(%a0)
+	movel	%d1,4(%a0)
+	movel	%d2,8(%a0)
+
+| A2. Set X = abs(input).
+|
+A2_str:
+	movel	(%a0),FP_SCR2(%a6) | move input to work space
+	movel	4(%a0),FP_SCR2+4(%a6) | move input to work space
+	movel	8(%a0),FP_SCR2+8(%a6) | move input to work space
+	andil	#0x7fffffff,FP_SCR2(%a6) |create abs(X)
+
+| A3. Compute ILOG.
+|     ILOG is the log base 10 of the input value.  It is approx-
+|     imated by adding e + 0.f when the original value is viewed
+|     as 2^^e * 1.f in extended precision.  This value is stored
+|     in d6.
+|
+| Register usage:
+|	Input/Output
+|	d0: k-factor/exponent
+|	d2: x/x
+|	d3: x/x
+|	d4: x/x
+|	d5: x/x
+|	d6: x/ILOG
+|	d7: k-factor/Unchanged
+|	a0: ptr for original operand/final result
+|	a1: x/x
+|	a2: x/x
+|	fp0: x/float(ILOG)
+|	fp1: x/x
+|	fp2: x/x
+|	F_SCR1:x/x
+|	F_SCR2:Abs(X)/Abs(X) with $3fff exponent
+|	L_SCR1:x/x
+|	L_SCR2:first word of X packed/Unchanged
+
+	tstb	BINDEC_FLG(%a6)	|check for denorm
+	beqs	A3_cont		|if clr, continue with norm
+	movel	#-4933,%d6	|force ILOG = -4933
+	bras	A4_str
+A3_cont:
+	movew	FP_SCR2(%a6),%d0	|move exp to d0
+	movew	#0x3fff,FP_SCR2(%a6) |replace exponent with 0x3fff
+	fmovex	FP_SCR2(%a6),%fp0	|now fp0 has 1.f
+	subw	#0x3fff,%d0	|strip off bias
+	faddw	%d0,%fp0		|add in exp
+	fsubs	FONE,%fp0	|subtract off 1.0
+	fbge	pos_res		|if pos, branch 
+	fmulx	LOG2UP1,%fp0	|if neg, mul by LOG2UP1
+	fmovel	%fp0,%d6		|put ILOG in d6 as a lword
+	bras	A4_str		|go move out ILOG
+pos_res:
+	fmulx	LOG2,%fp0	|if pos, mul by LOG2
+	fmovel	%fp0,%d6		|put ILOG in d6 as a lword
+
+
+| A4. Clr INEX bit.
+|     The operation in A3 above may have set INEX2.  
+
+A4_str:	
+	fmovel	#0,%FPSR		|zero all of fpsr - nothing needed
+
+
+| A5. Set ICTR = 0;
+|     ICTR is a flag used in A13.  It must be set before the 
+|     loop entry A6. The lower word of d5 is used for ICTR.
+
+	clrw	%d5		|clear ICTR
+
+
+| A6. Calculate LEN.
+|     LEN is the number of digits to be displayed.  The k-factor
+|     can dictate either the total number of digits, if it is
+|     a positive number, or the number of digits after the
+|     original decimal point which are to be included as
+|     significant.  See the 68882 manual for examples.
+|     If LEN is computed to be greater than 17, set OPERR in
+|     USER_FPSR.  LEN is stored in d4.
+|
+| Register usage:
+|	Input/Output
+|	d0: exponent/Unchanged
+|	d2: x/x/scratch
+|	d3: x/x
+|	d4: exc picture/LEN
+|	d5: ICTR/Unchanged
+|	d6: ILOG/Unchanged
+|	d7: k-factor/Unchanged
+|	a0: ptr for original operand/final result
+|	a1: x/x
+|	a2: x/x
+|	fp0: float(ILOG)/Unchanged
+|	fp1: x/x
+|	fp2: x/x
+|	F_SCR1:x/x
+|	F_SCR2:Abs(X) with $3fff exponent/Unchanged
+|	L_SCR1:x/x
+|	L_SCR2:first word of X packed/Unchanged
+
+A6_str:	
+	tstl	%d7		|branch on sign of k
+	bles	k_neg		|if k <= 0, LEN = ILOG + 1 - k
+	movel	%d7,%d4		|if k > 0, LEN = k
+	bras	len_ck		|skip to LEN check
+k_neg:
+	movel	%d6,%d4		|first load ILOG to d4
+	subl	%d7,%d4		|subtract off k
+	addql	#1,%d4		|add in the 1
+len_ck:
+	tstl	%d4		|LEN check: branch on sign of LEN
+	bles	LEN_ng		|if neg, set LEN = 1
+	cmpl	#17,%d4		|test if LEN > 17
+	bles	A7_str		|if not, forget it
+	movel	#17,%d4		|set max LEN = 17
+	tstl	%d7		|if negative, never set OPERR
+	bles	A7_str		|if positive, continue
+	orl	#opaop_mask,USER_FPSR(%a6) |set OPERR & AIOP in USER_FPSR
+	bras	A7_str		|finished here
+LEN_ng:
+	moveql	#1,%d4		|min LEN is 1
+
+
+| A7. Calculate SCALE.
+|     SCALE is equal to 10^ISCALE, where ISCALE is the number
+|     of decimal places needed to insure LEN integer digits
+|     in the output before conversion to bcd. LAMBDA is the sign
+|     of ISCALE, used in A9.  Fp1 contains 10^^(abs(ISCALE)) using
+|     the rounding mode as given in the following table (see
+|     Coonen, p. 7.23 as ref.; however, the SCALE variable is
+|     of opposite sign in bindec.sa from Coonen).
+|
+|	Initial					USE
+|	FPCR[6:5]	LAMBDA	SIGN(X)		FPCR[6:5]
+|	----------------------------------------------
+|	 RN	00	   0	   0		00/0	RN
+|	 RN	00	   0	   1		00/0	RN
+|	 RN	00	   1	   0		00/0	RN
+|	 RN	00	   1	   1		00/0	RN
+|	 RZ	01	   0	   0		11/3	RP
+|	 RZ	01	   0	   1		11/3	RP
+|	 RZ	01	   1	   0		10/2	RM
+|	 RZ	01	   1	   1		10/2	RM
+|	 RM	10	   0	   0		11/3	RP
+|	 RM	10	   0	   1		10/2	RM
+|	 RM	10	   1	   0		10/2	RM
+|	 RM	10	   1	   1		11/3	RP
+|	 RP	11	   0	   0		10/2	RM
+|	 RP	11	   0	   1		11/3	RP
+|	 RP	11	   1	   0		11/3	RP
+|	 RP	11	   1	   1		10/2	RM
+|
+| Register usage:
+|	Input/Output
+|	d0: exponent/scratch - final is 0
+|	d2: x/0 or 24 for A9
+|	d3: x/scratch - offset ptr into PTENRM array
+|	d4: LEN/Unchanged
+|	d5: 0/ICTR:LAMBDA
+|	d6: ILOG/ILOG or k if ((k<=0)&(ILOG<k))
+|	d7: k-factor/Unchanged
+|	a0: ptr for original operand/final result
+|	a1: x/ptr to PTENRM array
+|	a2: x/x
+|	fp0: float(ILOG)/Unchanged
+|	fp1: x/10^ISCALE
+|	fp2: x/x
+|	F_SCR1:x/x
+|	F_SCR2:Abs(X) with $3fff exponent/Unchanged
+|	L_SCR1:x/x
+|	L_SCR2:first word of X packed/Unchanged
+
+A7_str:	
+	tstl	%d7		|test sign of k
+	bgts	k_pos		|if pos and > 0, skip this
+	cmpl	%d6,%d7		|test k - ILOG
+	blts	k_pos		|if ILOG >= k, skip this
+	movel	%d7,%d6		|if ((k<0) & (ILOG < k)) ILOG = k
+k_pos:	
+	movel	%d6,%d0		|calc ILOG + 1 - LEN in d0
+	addql	#1,%d0		|add the 1
+	subl	%d4,%d0		|sub off LEN
+	swap	%d5		|use upper word of d5 for LAMBDA
+	clrw	%d5		|set it zero initially
+	clrw	%d2		|set up d2 for very small case
+	tstl	%d0		|test sign of ISCALE
+	bges	iscale		|if pos, skip next inst
+	addqw	#1,%d5		|if neg, set LAMBDA true
+	cmpl	#0xffffecd4,%d0	|test iscale <= -4908
+	bgts	no_inf		|if false, skip rest
+	addil	#24,%d0		|add in 24 to iscale
+	movel	#24,%d2		|put 24 in d2 for A9
+no_inf:	
+	negl	%d0		|and take abs of ISCALE
+iscale:	
+	fmoves	FONE,%fp1	|init fp1 to 1
+	bfextu	USER_FPCR(%a6){#26:#2},%d1 |get initial rmode bits
+	lslw	#1,%d1		|put them in bits 2:1
+	addw	%d5,%d1		|add in LAMBDA
+	lslw	#1,%d1		|put them in bits 3:1
+	tstl	L_SCR2(%a6)	|test sign of original x
+	bges	x_pos		|if pos, don't set bit 0
+	addql	#1,%d1		|if neg, set bit 0
+x_pos:
+	leal	RBDTBL,%a2	|load rbdtbl base
+	moveb	(%a2,%d1),%d3	|load d3 with new rmode
+	lsll	#4,%d3		|put bits in proper position
+	fmovel	%d3,%fpcr		|load bits into fpu
+	lsrl	#4,%d3		|put bits in proper position
+	tstb	%d3		|decode new rmode for pten table
+	bnes	not_rn		|if zero, it is RN
+	leal	PTENRN,%a1	|load a1 with RN table base
+	bras	rmode		|exit decode
+not_rn:
+	lsrb	#1,%d3		|get lsb in carry
+	bccs	not_rp		|if carry clear, it is RM
+	leal	PTENRP,%a1	|load a1 with RP table base
+	bras	rmode		|exit decode
+not_rp:
+	leal	PTENRM,%a1	|load a1 with RM table base
+rmode:
+	clrl	%d3		|clr table index
+e_loop:	
+	lsrl	#1,%d0		|shift next bit into carry
+	bccs	e_next		|if zero, skip the mul
+	fmulx	(%a1,%d3),%fp1	|mul by 10**(d3_bit_no)
+e_next:	
+	addl	#12,%d3		|inc d3 to next pwrten table entry
+	tstl	%d0		|test if ISCALE is zero
+	bnes	e_loop		|if not, loop
+
+
+| A8. Clr INEX; Force RZ.
+|     The operation in A3 above may have set INEX2.  
+|     RZ mode is forced for the scaling operation to insure
+|     only one rounding error.  The grs bits are collected in 
+|     the INEX flag for use in A10.
+|
+| Register usage:
+|	Input/Output
+
+	fmovel	#0,%FPSR		|clr INEX 
+	fmovel	#rz_mode,%FPCR	|set RZ rounding mode
+
+
+| A9. Scale X -> Y.
+|     The mantissa is scaled to the desired number of significant
+|     digits.  The excess digits are collected in INEX2. If mul,
+|     Check d2 for excess 10 exponential value.  If not zero, 
+|     the iscale value would have caused the pwrten calculation
+|     to overflow.  Only a negative iscale can cause this, so
+|     multiply by 10^(d2), which is now only allowed to be 24,
+|     with a multiply by 10^8 and 10^16, which is exact since
+|     10^24 is exact.  If the input was denormalized, we must
+|     create a busy stack frame with the mul command and the
+|     two operands, and allow the fpu to complete the multiply.
+|
+| Register usage:
+|	Input/Output
+|	d0: FPCR with RZ mode/Unchanged
+|	d2: 0 or 24/unchanged
+|	d3: x/x
+|	d4: LEN/Unchanged
+|	d5: ICTR:LAMBDA
+|	d6: ILOG/Unchanged
+|	d7: k-factor/Unchanged
+|	a0: ptr for original operand/final result
+|	a1: ptr to PTENRM array/Unchanged
+|	a2: x/x
+|	fp0: float(ILOG)/X adjusted for SCALE (Y)
+|	fp1: 10^ISCALE/Unchanged
+|	fp2: x/x
+|	F_SCR1:x/x
+|	F_SCR2:Abs(X) with $3fff exponent/Unchanged
+|	L_SCR1:x/x
+|	L_SCR2:first word of X packed/Unchanged
+
+A9_str:	
+	fmovex	(%a0),%fp0	|load X from memory
+	fabsx	%fp0		|use abs(X)
+	tstw	%d5		|LAMBDA is in lower word of d5
+	bnes	sc_mul		|if neg (LAMBDA = 1), scale by mul
+	fdivx	%fp1,%fp0		|calculate X / SCALE -> Y to fp0
+	bras	A10_st		|branch to A10
+
+sc_mul:
+	tstb	BINDEC_FLG(%a6)	|check for denorm
+	beqs	A9_norm		|if norm, continue with mul
+	fmovemx %fp1-%fp1,-(%a7)	|load ETEMP with 10^ISCALE
+	movel	8(%a0),-(%a7)	|load FPTEMP with input arg
+	movel	4(%a0),-(%a7)
+	movel	(%a0),-(%a7)
+	movel	#18,%d3		|load count for busy stack
+A9_loop:
+	clrl	-(%a7)		|clear lword on stack
+	dbf	%d3,A9_loop	
+	moveb	VER_TMP(%a6),(%a7) |write current version number
+	moveb	#BUSY_SIZE-4,1(%a7) |write current busy size 
+	moveb	#0x10,0x44(%a7)	|set fcefpte[15] bit
+	movew	#0x0023,0x40(%a7)	|load cmdreg1b with mul command
+	moveb	#0xfe,0x8(%a7)	|load all 1s to cu savepc
+	frestore (%a7)+		|restore frame to fpu for completion
+	fmulx	36(%a1),%fp0	|multiply fp0 by 10^8
+	fmulx	48(%a1),%fp0	|multiply fp0 by 10^16
+	bras	A10_st
+A9_norm:
+	tstw	%d2		|test for small exp case
+	beqs	A9_con		|if zero, continue as normal
+	fmulx	36(%a1),%fp0	|multiply fp0 by 10^8
+	fmulx	48(%a1),%fp0	|multiply fp0 by 10^16
+A9_con:
+	fmulx	%fp1,%fp0		|calculate X * SCALE -> Y to fp0
+
+
+| A10. Or in INEX.
+|      If INEX is set, round error occured.  This is compensated
+|      for by 'or-ing' in the INEX2 flag to the lsb of Y.
+|
+| Register usage:
+|	Input/Output
+|	d0: FPCR with RZ mode/FPSR with INEX2 isolated
+|	d2: x/x
+|	d3: x/x
+|	d4: LEN/Unchanged
+|	d5: ICTR:LAMBDA
+|	d6: ILOG/Unchanged
+|	d7: k-factor/Unchanged
+|	a0: ptr for original operand/final result
+|	a1: ptr to PTENxx array/Unchanged
+|	a2: x/ptr to FP_SCR2(a6)
+|	fp0: Y/Y with lsb adjusted
+|	fp1: 10^ISCALE/Unchanged
+|	fp2: x/x
+
+A10_st:	
+	fmovel	%FPSR,%d0		|get FPSR
+	fmovex	%fp0,FP_SCR2(%a6)	|move Y to memory
+	leal	FP_SCR2(%a6),%a2	|load a2 with ptr to FP_SCR2
+	btstl	#9,%d0		|check if INEX2 set
+	beqs	A11_st		|if clear, skip rest
+	oril	#1,8(%a2)	|or in 1 to lsb of mantissa
+	fmovex	FP_SCR2(%a6),%fp0	|write adjusted Y back to fpu
+
+
+| A11. Restore original FPCR; set size ext.
+|      Perform FINT operation in the user's rounding mode.  Keep
+|      the size to extended.  The sintdo entry point in the sint
+|      routine expects the FPCR value to be in USER_FPCR for
+|      mode and precision.  The original FPCR is saved in L_SCR1.
+
+A11_st:	
+	movel	USER_FPCR(%a6),L_SCR1(%a6) |save it for later
+	andil	#0x00000030,USER_FPCR(%a6) |set size to ext, 
+|					;block exceptions
+
+
+| A12. Calculate YINT = FINT(Y) according to user's rounding mode.
+|      The FPSP routine sintd0 is used.  The output is in fp0.
+|
+| Register usage:
+|	Input/Output
+|	d0: FPSR with AINEX cleared/FPCR with size set to ext
+|	d2: x/x/scratch
+|	d3: x/x
+|	d4: LEN/Unchanged
+|	d5: ICTR:LAMBDA/Unchanged
+|	d6: ILOG/Unchanged
+|	d7: k-factor/Unchanged
+|	a0: ptr for original operand/src ptr for sintdo
+|	a1: ptr to PTENxx array/Unchanged
+|	a2: ptr to FP_SCR2(a6)/Unchanged
+|	a6: temp pointer to FP_SCR2(a6) - orig value saved and restored
+|	fp0: Y/YINT
+|	fp1: 10^ISCALE/Unchanged
+|	fp2: x/x
+|	F_SCR1:x/x
+|	F_SCR2:Y adjusted for inex/Y with original exponent
+|	L_SCR1:x/original USER_FPCR
+|	L_SCR2:first word of X packed/Unchanged
+
+A12_st:
+	moveml	%d0-%d1/%a0-%a1,-(%a7)	|save regs used by sintd0	
+	movel	L_SCR1(%a6),-(%a7)
+	movel	L_SCR2(%a6),-(%a7)
+	leal	FP_SCR2(%a6),%a0		|a0 is ptr to F_SCR2(a6)
+	fmovex	%fp0,(%a0)		|move Y to memory at FP_SCR2(a6)
+	tstl	L_SCR2(%a6)		|test sign of original operand
+	bges	do_fint			|if pos, use Y 
+	orl	#0x80000000,(%a0)		|if neg, use -Y
+do_fint:
+	movel	USER_FPSR(%a6),-(%a7)
+	bsr	sintdo			|sint routine returns int in fp0
+	moveb	(%a7),USER_FPSR(%a6)
+	addl	#4,%a7
+	movel	(%a7)+,L_SCR2(%a6)
+	movel	(%a7)+,L_SCR1(%a6)
+	moveml	(%a7)+,%d0-%d1/%a0-%a1	|restore regs used by sint	
+	movel	L_SCR2(%a6),FP_SCR2(%a6)	|restore original exponent
+	movel	L_SCR1(%a6),USER_FPCR(%a6) |restore user's FPCR
+
+
+| A13. Check for LEN digits.
+|      If the int operation results in more than LEN digits,
+|      or less than LEN -1 digits, adjust ILOG and repeat from
+|      A6.  This test occurs only on the first pass.  If the
+|      result is exactly 10^LEN, decrement ILOG and divide
+|      the mantissa by 10.  The calculation of 10^LEN cannot
+|      be inexact, since all powers of ten upto 10^27 are exact
+|      in extended precision, so the use of a previous power-of-ten
+|      table will introduce no error.
+|
+|
+| Register usage:
+|	Input/Output
+|	d0: FPCR with size set to ext/scratch final = 0
+|	d2: x/x
+|	d3: x/scratch final = x
+|	d4: LEN/LEN adjusted
+|	d5: ICTR:LAMBDA/LAMBDA:ICTR
+|	d6: ILOG/ILOG adjusted
+|	d7: k-factor/Unchanged
+|	a0: pointer into memory for packed bcd string formation
+|	a1: ptr to PTENxx array/Unchanged
+|	a2: ptr to FP_SCR2(a6)/Unchanged
+|	fp0: int portion of Y/abs(YINT) adjusted
+|	fp1: 10^ISCALE/Unchanged
+|	fp2: x/10^LEN
+|	F_SCR1:x/x
+|	F_SCR2:Y with original exponent/Unchanged
+|	L_SCR1:original USER_FPCR/Unchanged
+|	L_SCR2:first word of X packed/Unchanged
+
+A13_st:	
+	swap	%d5		|put ICTR in lower word of d5
+	tstw	%d5		|check if ICTR = 0
+	bne	not_zr		|if non-zero, go to second test
+|
+| Compute 10^(LEN-1)
+|
+	fmoves	FONE,%fp2	|init fp2 to 1.0
+	movel	%d4,%d0		|put LEN in d0
+	subql	#1,%d0		|d0 = LEN -1
+	clrl	%d3		|clr table index
+l_loop:	
+	lsrl	#1,%d0		|shift next bit into carry
+	bccs	l_next		|if zero, skip the mul
+	fmulx	(%a1,%d3),%fp2	|mul by 10**(d3_bit_no)
+l_next:
+	addl	#12,%d3		|inc d3 to next pwrten table entry
+	tstl	%d0		|test if LEN is zero
+	bnes	l_loop		|if not, loop
+|
+| 10^LEN-1 is computed for this test and A14.  If the input was
+| denormalized, check only the case in which YINT > 10^LEN.
+|
+	tstb	BINDEC_FLG(%a6)	|check if input was norm
+	beqs	A13_con		|if norm, continue with checking
+	fabsx	%fp0		|take abs of YINT
+	bra	test_2
+|
+| Compare abs(YINT) to 10^(LEN-1) and 10^LEN
+|
+A13_con:
+	fabsx	%fp0		|take abs of YINT
+	fcmpx	%fp2,%fp0		|compare abs(YINT) with 10^(LEN-1)
+	fbge	test_2		|if greater, do next test
+	subql	#1,%d6		|subtract 1 from ILOG
+	movew	#1,%d5		|set ICTR
+	fmovel	#rm_mode,%FPCR	|set rmode to RM
+	fmuls	FTEN,%fp2	|compute 10^LEN 
+	bra	A6_str		|return to A6 and recompute YINT
+test_2:
+	fmuls	FTEN,%fp2	|compute 10^LEN
+	fcmpx	%fp2,%fp0		|compare abs(YINT) with 10^LEN
+	fblt	A14_st		|if less, all is ok, go to A14
+	fbgt	fix_ex		|if greater, fix and redo
+	fdivs	FTEN,%fp0	|if equal, divide by 10
+	addql	#1,%d6		| and inc ILOG
+	bras	A14_st		| and continue elsewhere
+fix_ex:
+	addql	#1,%d6		|increment ILOG by 1
+	movew	#1,%d5		|set ICTR
+	fmovel	#rm_mode,%FPCR	|set rmode to RM
+	bra	A6_str		|return to A6 and recompute YINT
+|
+| Since ICTR <> 0, we have already been through one adjustment, 
+| and shouldn't have another; this is to check if abs(YINT) = 10^LEN
+| 10^LEN is again computed using whatever table is in a1 since the
+| value calculated cannot be inexact.
+|
+not_zr:
+	fmoves	FONE,%fp2	|init fp2 to 1.0
+	movel	%d4,%d0		|put LEN in d0
+	clrl	%d3		|clr table index
+z_loop:
+	lsrl	#1,%d0		|shift next bit into carry
+	bccs	z_next		|if zero, skip the mul
+	fmulx	(%a1,%d3),%fp2	|mul by 10**(d3_bit_no)
+z_next:
+	addl	#12,%d3		|inc d3 to next pwrten table entry
+	tstl	%d0		|test if LEN is zero
+	bnes	z_loop		|if not, loop
+	fabsx	%fp0		|get abs(YINT)
+	fcmpx	%fp2,%fp0		|check if abs(YINT) = 10^LEN
+	fbne	A14_st		|if not, skip this
+	fdivs	FTEN,%fp0	|divide abs(YINT) by 10
+	addql	#1,%d6		|and inc ILOG by 1
+	addql	#1,%d4		| and inc LEN
+	fmuls	FTEN,%fp2	| if LEN++, the get 10^^LEN
+
+
+| A14. Convert the mantissa to bcd.
+|      The binstr routine is used to convert the LEN digit 
+|      mantissa to bcd in memory.  The input to binstr is
+|      to be a fraction; i.e. (mantissa)/10^LEN and adjusted
+|      such that the decimal point is to the left of bit 63.
+|      The bcd digits are stored in the correct position in 
+|      the final string area in memory.
+|
+|
+| Register usage:
+|	Input/Output
+|	d0: x/LEN call to binstr - final is 0
+|	d1: x/0
+|	d2: x/ms 32-bits of mant of abs(YINT)
+|	d3: x/ls 32-bits of mant of abs(YINT)
+|	d4: LEN/Unchanged
+|	d5: ICTR:LAMBDA/LAMBDA:ICTR
+|	d6: ILOG
+|	d7: k-factor/Unchanged
+|	a0: pointer into memory for packed bcd string formation
+|	    /ptr to first mantissa byte in result string
+|	a1: ptr to PTENxx array/Unchanged
+|	a2: ptr to FP_SCR2(a6)/Unchanged
+|	fp0: int portion of Y/abs(YINT) adjusted
+|	fp1: 10^ISCALE/Unchanged
+|	fp2: 10^LEN/Unchanged
+|	F_SCR1:x/Work area for final result
+|	F_SCR2:Y with original exponent/Unchanged
+|	L_SCR1:original USER_FPCR/Unchanged
+|	L_SCR2:first word of X packed/Unchanged
+
+A14_st:	
+	fmovel	#rz_mode,%FPCR	|force rz for conversion
+	fdivx	%fp2,%fp0		|divide abs(YINT) by 10^LEN
+	leal	FP_SCR1(%a6),%a0
+	fmovex	%fp0,(%a0)	|move abs(YINT)/10^LEN to memory
+	movel	4(%a0),%d2	|move 2nd word of FP_RES to d2
+	movel	8(%a0),%d3	|move 3rd word of FP_RES to d3
+	clrl	4(%a0)		|zero word 2 of FP_RES
+	clrl	8(%a0)		|zero word 3 of FP_RES
+	movel	(%a0),%d0		|move exponent to d0
+	swap	%d0		|put exponent in lower word
+	beqs	no_sft		|if zero, don't shift
+	subil	#0x3ffd,%d0	|sub bias less 2 to make fract
+	tstl	%d0		|check if > 1
+	bgts	no_sft		|if so, don't shift
+	negl	%d0		|make exp positive
+m_loop:
+	lsrl	#1,%d2		|shift d2:d3 right, add 0s 
+	roxrl	#1,%d3		|the number of places
+	dbf	%d0,m_loop	|given in d0
+no_sft:
+	tstl	%d2		|check for mantissa of zero
+	bnes	no_zr		|if not, go on
+	tstl	%d3		|continue zero check
+	beqs	zer_m		|if zero, go directly to binstr
+no_zr:
+	clrl	%d1		|put zero in d1 for addx
+	addil	#0x00000080,%d3	|inc at bit 7
+	addxl	%d1,%d2		|continue inc
+	andil	#0xffffff80,%d3	|strip off lsb not used by 882
+zer_m:
+	movel	%d4,%d0		|put LEN in d0 for binstr call
+	addql	#3,%a0		|a0 points to M16 byte in result
+	bsr	binstr		|call binstr to convert mant
+
+
+| A15. Convert the exponent to bcd.
+|      As in A14 above, the exp is converted to bcd and the
+|      digits are stored in the final string.
+|
+|      Digits are stored in L_SCR1(a6) on return from BINDEC as:
+|
+|  	 32               16 15                0
+|	-----------------------------------------
+|  	|  0 | e3 | e2 | e1 | e4 |  X |  X |  X |
+|	-----------------------------------------
+|
+| And are moved into their proper places in FP_SCR1.  If digit e4
+| is non-zero, OPERR is signaled.  In all cases, all 4 digits are
+| written as specified in the 881/882 manual for packed decimal.
+|
+| Register usage:
+|	Input/Output
+|	d0: x/LEN call to binstr - final is 0
+|	d1: x/scratch (0);shift count for final exponent packing
+|	d2: x/ms 32-bits of exp fraction/scratch
+|	d3: x/ls 32-bits of exp fraction
+|	d4: LEN/Unchanged
+|	d5: ICTR:LAMBDA/LAMBDA:ICTR
+|	d6: ILOG
+|	d7: k-factor/Unchanged
+|	a0: ptr to result string/ptr to L_SCR1(a6)
+|	a1: ptr to PTENxx array/Unchanged
+|	a2: ptr to FP_SCR2(a6)/Unchanged
+|	fp0: abs(YINT) adjusted/float(ILOG)
+|	fp1: 10^ISCALE/Unchanged
+|	fp2: 10^LEN/Unchanged
+|	F_SCR1:Work area for final result/BCD result
+|	F_SCR2:Y with original exponent/ILOG/10^4
+|	L_SCR1:original USER_FPCR/Exponent digits on return from binstr
+|	L_SCR2:first word of X packed/Unchanged
+
+A15_st:	
+	tstb	BINDEC_FLG(%a6)	|check for denorm
+	beqs	not_denorm
+	ftstx	%fp0		|test for zero
+	fbeq	den_zero	|if zero, use k-factor or 4933
+	fmovel	%d6,%fp0		|float ILOG
+	fabsx	%fp0		|get abs of ILOG
+	bras	convrt
+den_zero:
+	tstl	%d7		|check sign of the k-factor
+	blts	use_ilog	|if negative, use ILOG
+	fmoves	F4933,%fp0	|force exponent to 4933
+	bras	convrt		|do it
+use_ilog:
+	fmovel	%d6,%fp0		|float ILOG
+	fabsx	%fp0		|get abs of ILOG
+	bras	convrt
+not_denorm:
+	ftstx	%fp0		|test for zero
+	fbne	not_zero	|if zero, force exponent
+	fmoves	FONE,%fp0	|force exponent to 1
+	bras	convrt		|do it
+not_zero:	
+	fmovel	%d6,%fp0		|float ILOG
+	fabsx	%fp0		|get abs of ILOG
+convrt:
+	fdivx	24(%a1),%fp0	|compute ILOG/10^4
+	fmovex	%fp0,FP_SCR2(%a6)	|store fp0 in memory
+	movel	4(%a2),%d2	|move word 2 to d2
+	movel	8(%a2),%d3	|move word 3 to d3
+	movew	(%a2),%d0		|move exp to d0
+	beqs	x_loop_fin	|if zero, skip the shift
+	subiw	#0x3ffd,%d0	|subtract off bias
+	negw	%d0		|make exp positive
+x_loop:
+	lsrl	#1,%d2		|shift d2:d3 right 
+	roxrl	#1,%d3		|the number of places
+	dbf	%d0,x_loop	|given in d0
+x_loop_fin:
+	clrl	%d1		|put zero in d1 for addx
+	addil	#0x00000080,%d3	|inc at bit 6
+	addxl	%d1,%d2		|continue inc
+	andil	#0xffffff80,%d3	|strip off lsb not used by 882
+	movel	#4,%d0		|put 4 in d0 for binstr call
+	leal	L_SCR1(%a6),%a0	|a0 is ptr to L_SCR1 for exp digits
+	bsr	binstr		|call binstr to convert exp
+	movel	L_SCR1(%a6),%d0	|load L_SCR1 lword to d0 
+	movel	#12,%d1		|use d1 for shift count
+	lsrl	%d1,%d0		|shift d0 right by 12
+	bfins	%d0,FP_SCR1(%a6){#4:#12} |put e3:e2:e1 in FP_SCR1
+	lsrl	%d1,%d0		|shift d0 right by 12
+	bfins	%d0,FP_SCR1(%a6){#16:#4} |put e4 in FP_SCR1 
+	tstb	%d0		|check if e4 is zero
+	beqs	A16_st		|if zero, skip rest
+	orl	#opaop_mask,USER_FPSR(%a6) |set OPERR & AIOP in USER_FPSR
+
+
+| A16. Write sign bits to final string.
+|	   Sigma is bit 31 of initial value; RHO is bit 31 of d6 (ILOG).
+|
+| Register usage:
+|	Input/Output
+|	d0: x/scratch - final is x
+|	d2: x/x
+|	d3: x/x
+|	d4: LEN/Unchanged
+|	d5: ICTR:LAMBDA/LAMBDA:ICTR
+|	d6: ILOG/ILOG adjusted
+|	d7: k-factor/Unchanged
+|	a0: ptr to L_SCR1(a6)/Unchanged
+|	a1: ptr to PTENxx array/Unchanged
+|	a2: ptr to FP_SCR2(a6)/Unchanged
+|	fp0: float(ILOG)/Unchanged
+|	fp1: 10^ISCALE/Unchanged
+|	fp2: 10^LEN/Unchanged
+|	F_SCR1:BCD result with correct signs
+|	F_SCR2:ILOG/10^4
+|	L_SCR1:Exponent digits on return from binstr
+|	L_SCR2:first word of X packed/Unchanged
+
+A16_st:
+	clrl	%d0		|clr d0 for collection of signs
+	andib	#0x0f,FP_SCR1(%a6) |clear first nibble of FP_SCR1 
+	tstl	L_SCR2(%a6)	|check sign of original mantissa
+	bges	mant_p		|if pos, don't set SM
+	moveql	#2,%d0		|move 2 in to d0 for SM
+mant_p:
+	tstl	%d6		|check sign of ILOG
+	bges	wr_sgn		|if pos, don't set SE
+	addql	#1,%d0		|set bit 0 in d0 for SE 
+wr_sgn:
+	bfins	%d0,FP_SCR1(%a6){#0:#2} |insert SM and SE into FP_SCR1
+
+| Clean up and restore all registers used.
+
+	fmovel	#0,%FPSR		|clear possible inex2/ainex bits
+	fmovemx (%a7)+,%fp0-%fp2
+	moveml	(%a7)+,%d2-%d7/%a2
+	rts
+
+	|end
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/fpsp040/binstr.S linux/arch/m68k/fpsp040/binstr.S
--- v1.3.93/linux/arch/m68k/fpsp040/binstr.S	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/fpsp040/binstr.S	Sat Feb 24 22:58:42 1996
@@ -0,0 +1,140 @@
+|
+|	binstr.sa 3.3 12/19/90
+|
+|
+|	Description: Converts a 64-bit binary integer to bcd.
+|
+|	Input: 64-bit binary integer in d2:d3, desired length (LEN) in
+|          d0, and a  pointer to start in memory for bcd characters
+|          in d0. (This pointer must point to byte 4 of the first
+|          lword of the packed decimal memory string.)
+|
+|	Output:	LEN bcd digits representing the 64-bit integer.
+|
+|	Algorithm:
+|		The 64-bit binary is assumed to have a decimal point before
+|		bit 63.  The fraction is multiplied by 10 using a mul by 2
+|		shift and a mul by 8 shift.  The bits shifted out of the
+|		msb form a decimal digit.  This process is iterated until
+|		LEN digits are formed.
+|
+|	A1. Init d7 to 1.  D7 is the byte digit counter, and if 1, the
+|		digit formed will be assumed the least significant.  This is
+|		to force the first byte formed to have a 0 in the upper 4 bits.
+|
+|	A2. Beginning of the loop:
+|		Copy the fraction in d2:d3 to d4:d5.
+|
+|	A3. Multiply the fraction in d2:d3 by 8 using bit-field
+|		extracts and shifts.  The three msbs from d2 will go into
+|		d1.
+|
+|	A4. Multiply the fraction in d4:d5 by 2 using shifts.  The msb
+|		will be collected by the carry.
+|
+|	A5. Add using the carry the 64-bit quantities in d2:d3 and d4:d5
+|		into d2:d3.  D1 will contain the bcd digit formed.
+|
+|	A6. Test d7.  If zero, the digit formed is the ms digit.  If non-
+|		zero, it is the ls digit.  Put the digit in its place in the
+|		upper word of d0.  If it is the ls digit, write the word
+|		from d0 to memory.
+|
+|	A7. Decrement d6 (LEN counter) and repeat the loop until zero.
+|
+|	Implementation Notes:
+|
+|	The registers are used as follows:
+|
+|		d0: LEN counter
+|		d1: temp used to form the digit
+|		d2: upper 32-bits of fraction for mul by 8
+|		d3: lower 32-bits of fraction for mul by 8
+|		d4: upper 32-bits of fraction for mul by 2
+|		d5: lower 32-bits of fraction for mul by 2
+|		d6: temp for bit-field extracts
+|		d7: byte digit formation word;digit count {0,1}
+|		a0: pointer into memory for packed bcd string formation
+|
+
+|		Copyright (C) Motorola, Inc. 1990
+|			All Rights Reserved
+|
+|	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA 
+|	The copyright notice above does not evidence any  
+|	actual or intended publication of such source code.
+
+|BINSTR    idnt    2,1 | Motorola 040 Floating Point Software Package
+
+	|section	8
+
+	.include "fpsp.h"
+
+	.global	binstr
+binstr:
+	moveml	%d0-%d7,-(%a7)
+|
+| A1: Init d7
+|
+	moveql	#1,%d7			|init d7 for second digit
+	subql	#1,%d0			|for dbf d0 would have LEN+1 passes
+|
+| A2. Copy d2:d3 to d4:d5.  Start loop.
+|
+loop:
+	movel	%d2,%d4			|copy the fraction before muls
+	movel	%d3,%d5			|to d4:d5
+|
+| A3. Multiply d2:d3 by 8; extract msbs into d1.
+|
+	bfextu	%d2{#0:#3},%d1		|copy 3 msbs of d2 into d1
+	asll	#3,%d2			|shift d2 left by 3 places
+	bfextu	%d3{#0:#3},%d6		|copy 3 msbs of d3 into d6
+	asll	#3,%d3			|shift d3 left by 3 places
+	orl	%d6,%d2			|or in msbs from d3 into d2
+|
+| A4. Multiply d4:d5 by 2; add carry out to d1.
+|
+	asll	#1,%d5			|mul d5 by 2
+	roxll	#1,%d4			|mul d4 by 2
+	swap	%d6			|put 0 in d6 lower word
+	addxw	%d6,%d1			|add in extend from mul by 2
+|
+| A5. Add mul by 8 to mul by 2.  D1 contains the digit formed.
+|
+	addl	%d5,%d3			|add lower 32 bits
+	nop				|ERRATA ; FIX #13 (Rev. 1.2 6/6/90)
+	addxl	%d4,%d2			|add with extend upper 32 bits
+	nop				|ERRATA ; FIX #13 (Rev. 1.2 6/6/90)
+	addxw	%d6,%d1			|add in extend from add to d1
+	swap	%d6			|with d6 = 0; put 0 in upper word
+|
+| A6. Test d7 and branch.
+|
+	tstw	%d7			|if zero, store digit & to loop
+	beqs	first_d			|if non-zero, form byte & write
+sec_d:
+	swap	%d7			|bring first digit to word d7b
+	aslw	#4,%d7			|first digit in upper 4 bits d7b
+	addw	%d1,%d7			|add in ls digit to d7b
+	moveb	%d7,(%a0)+		|store d7b byte in memory
+	swap	%d7			|put LEN counter in word d7a
+	clrw	%d7			|set d7a to signal no digits done
+	dbf	%d0,loop		|do loop some more!
+	bras	end_bstr		|finished, so exit
+first_d:
+	swap	%d7			|put digit word in d7b
+	movew	%d1,%d7			|put new digit in d7b
+	swap	%d7			|put LEN counter in word d7a
+	addqw	#1,%d7			|set d7a to signal first digit done
+	dbf	%d0,loop		|do loop some more!
+	swap	%d7			|put last digit in string
+	lslw	#4,%d7			|move it to upper 4 bits
+	moveb	%d7,(%a0)+		|store it in memory string
+|
+| Clean up and return with result in fp0.
+|
+end_bstr:
+	moveml	(%a7)+,%d0-%d7
+	rts
+	|end
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/fpsp040/bugfix.S linux/arch/m68k/fpsp040/bugfix.S
--- v1.3.93/linux/arch/m68k/fpsp040/bugfix.S	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/fpsp040/bugfix.S	Sat Feb 24 22:58:42 1996
@@ -0,0 +1,496 @@
+|
+|	bugfix.sa 3.2 1/31/91
+|
+|
+|	This file contains workarounds for bugs in the 040
+|	relating to the Floating-Point Software Package (FPSP)
+|
+|	Fixes for bugs: 1238
+|
+|	Bug: 1238 
+|
+|
+|    /* The following dirty_bit clear should be left in
+|     * the handler permanently to improve throughput.
+|     * The dirty_bits are located at bits [23:16] in
+|     * longword $08 in the busy frame $4x60.  Bit 16
+|     * corresponds to FP0, bit 17 corresponds to FP1,
+|     * and so on.
+|     */
+|    if  (E3_exception_just_serviced)   {
+|         dirty_bit[cmdreg3b[9:7]] = 0;
+|         }
+|
+|    if  (fsave_format_version != $40)  {goto NOFIX}
+|
+|    if !(E3_exception_just_serviced)   {goto NOFIX}
+|    if  (cupc == 0000000)              {goto NOFIX}
+|    if  ((cmdreg1b[15:13] != 000) &&
+|         (cmdreg1b[15:10] != 010001))  {goto NOFIX}
+|    if (((cmdreg1b[15:13] != 000) || ((cmdreg1b[12:10] != cmdreg2b[9:7]) &&
+|				      (cmdreg1b[12:10] != cmdreg3b[9:7]))  ) &&
+|	 ((cmdreg1b[ 9: 7] != cmdreg2b[9:7]) &&
+|	  (cmdreg1b[ 9: 7] != cmdreg3b[9:7])) )  {goto NOFIX}
+|
+|    /* Note: for 6d43b or 8d43b, you may want to add the following code
+|     * to get better coverage.  (If you do not insert this code, the part
+|     * won't lock up; it will simply get the wrong answer.)
+|     * Do NOT insert this code for 10d43b or later parts.
+|     *
+|     *  if (fpiarcu == integer stack return address) {
+|     *       cupc = 0000000;
+|     *       goto NOFIX;
+|     *       }
+|     */
+|
+|    if (cmdreg1b[15:13] != 000)   {goto FIX_OPCLASS2}
+|    FIX_OPCLASS0:
+|    if (((cmdreg1b[12:10] == cmdreg2b[9:7]) ||
+|	 (cmdreg1b[ 9: 7] == cmdreg2b[9:7])) &&
+|	(cmdreg1b[12:10] != cmdreg3b[9:7]) &&
+|	(cmdreg1b[ 9: 7] != cmdreg3b[9:7]))  {  /* xu conflict only */
+|	/* We execute the following code if there is an
+|	   xu conflict and NOT an nu conflict */
+|
+|	/* first save some values on the fsave frame */
+|	stag_temp     = STAG[fsave_frame];
+|	cmdreg1b_temp = CMDREG1B[fsave_frame];
+|	dtag_temp     = DTAG[fsave_frame];
+|	ete15_temp    = ETE15[fsave_frame];
+|
+|	CUPC[fsave_frame] = 0000000;
+|	FRESTORE
+|	FSAVE
+|
+|	/* If the xu instruction is exceptional, we punt.
+|	 * Otherwise, we would have to include OVFL/UNFL handler
+|	 * code here to get the correct answer.
+|	 */
+|	if (fsave_frame_format == $4060) {goto KILL_PROCESS}
+|
+|	fsave_frame = /* build a long frame of all zeros */
+|	fsave_frame_format = $4060;  /* label it as long frame */
+|
+|	/* load it with the temps we saved */
+|	STAG[fsave_frame]     =  stag_temp;
+|	CMDREG1B[fsave_frame] =  cmdreg1b_temp;
+|	DTAG[fsave_frame]     =  dtag_temp;
+|	ETE15[fsave_frame]    =  ete15_temp;
+|
+|	/* Make sure that the cmdreg3b dest reg is not going to
+|	 * be destroyed by a FMOVEM at the end of all this code.
+|	 * If it is, you should move the current value of the reg
+|	 * onto the stack so that the reg will loaded with that value.
+|	 */
+|
+|	/* All done.  Proceed with the code below */
+|    }
+|
+|    etemp  = FP_reg_[cmdreg1b[12:10]];
+|    ete15  = ~ete14;
+|    cmdreg1b[15:10] = 010010;
+|    clear(bug_flag_procIDxxxx);
+|    FRESTORE and return;
+|
+|
+|    FIX_OPCLASS2:
+|    if ((cmdreg1b[9:7] == cmdreg2b[9:7]) &&
+|	(cmdreg1b[9:7] != cmdreg3b[9:7]))  {  /* xu conflict only */
+|	/* We execute the following code if there is an
+|	   xu conflict and NOT an nu conflict */
+|
+|	/* first save some values on the fsave frame */
+|	stag_temp     = STAG[fsave_frame];
+|	cmdreg1b_temp = CMDREG1B[fsave_frame];
+|	dtag_temp     = DTAG[fsave_frame];
+|	ete15_temp    = ETE15[fsave_frame];
+|	etemp_temp    = ETEMP[fsave_frame];
+|
+|	CUPC[fsave_frame] = 0000000;
+|	FRESTORE
+|	FSAVE
+|
+|
+|	/* If the xu instruction is exceptional, we punt.
+|	 * Otherwise, we would have to include OVFL/UNFL handler
+|	 * code here to get the correct answer.
+|	 */
+|	if (fsave_frame_format == $4060) {goto KILL_PROCESS}
+|
+|	fsave_frame = /* build a long frame of all zeros */
+|	fsave_frame_format = $4060;  /* label it as long frame */
+|
+|	/* load it with the temps we saved */
+|	STAG[fsave_frame]     =  stag_temp;
+|	CMDREG1B[fsave_frame] =  cmdreg1b_temp;
+|	DTAG[fsave_frame]     =  dtag_temp;
+|	ETE15[fsave_frame]    =  ete15_temp;
+|	ETEMP[fsave_frame]    =  etemp_temp;
+|
+|	/* Make sure that the cmdreg3b dest reg is not going to
+|	 * be destroyed by a FMOVEM at the end of all this code.
+|	 * If it is, you should move the current value of the reg
+|	 * onto the stack so that the reg will loaded with that value.
+|	 */
+|
+|	/* All done.  Proceed with the code below */
+|    }
+|
+|    if (etemp_exponent == min_sgl)   etemp_exponent = min_dbl;
+|    if (etemp_exponent == max_sgl)   etemp_exponent = max_dbl;
+|    cmdreg1b[15:10] = 010101;
+|    clear(bug_flag_procIDxxxx);
+|    FRESTORE and return;
+|
+|
+|    NOFIX:
+|    clear(bug_flag_procIDxxxx);
+|    FRESTORE and return;
+|
+
+
+|		Copyright (C) Motorola, Inc. 1990
+|			All Rights Reserved
+|
+|	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA 
+|	The copyright notice above does not evidence any  
+|	actual or intended publication of such source code.
+
+|BUGFIX    idnt    2,1 | Motorola 040 Floating Point Software Package
+
+	|section	8
+
+	.include "fpsp.h"
+
+	|xref	fpsp_fmt_error
+
+	.global	b1238_fix
+b1238_fix:
+|
+| This code is entered only on completion of the handling of an 
+| nu-generated ovfl, unfl, or inex exception.  If the version 
+| number of the fsave is not $40, this handler is not necessary.
+| Simply branch to fix_done and exit normally.
+|
+	cmpib	#VER_40,4(%a7)
+	bne	fix_done
+|
+| Test for cu_savepc equal to zero.  If not, this is not a bug
+| #1238 case.
+|
+	moveb	CU_SAVEPC(%a6),%d0
+	andib	#0xFE,%d0
+	beq 	fix_done	|if zero, this is not bug #1238
+
+|
+| Test the register conflict aspect.  If opclass0, check for
+| cu src equal to xu dest or equal to nu dest.  If so, go to 
+| op0.  Else, or if opclass2, check for cu dest equal to
+| xu dest or equal to nu dest.  If so, go to tst_opcl.  Else,
+| exit, it is not the bug case.
+|
+| Check for opclass 0.  If not, go and check for opclass 2 and sgl.
+|
+	movew	CMDREG1B(%a6),%d0
+	andiw	#0xE000,%d0		|strip all but opclass
+	bne	op2sgl			|not opclass 0, check op2
+|
+| Check for cu and nu register conflict.  If one exists, this takes
+| priority over a cu and xu conflict. 
+|
+	bfextu	CMDREG1B(%a6){#3:#3},%d0	|get 1st src 
+	bfextu	CMDREG3B(%a6){#6:#3},%d1	|get 3rd dest
+	cmpb	%d0,%d1
+	beqs	op0			|if equal, continue bugfix
+|
+| Check for cu dest equal to nu dest.  If so, go and fix the 
+| bug condition.  Otherwise, exit.
+|
+	bfextu	CMDREG1B(%a6){#6:#3},%d0	|get 1st dest 
+	cmpb	%d0,%d1			|cmp 1st dest with 3rd dest
+	beqs	op0			|if equal, continue bugfix
+|
+| Check for cu and xu register conflict.
+|
+	bfextu	CMDREG2B(%a6){#6:#3},%d1	|get 2nd dest
+	cmpb	%d0,%d1			|cmp 1st dest with 2nd dest
+	beqs	op0_xu			|if equal, continue bugfix
+	bfextu	CMDREG1B(%a6){#3:#3},%d0	|get 1st src 
+	cmpb	%d0,%d1			|cmp 1st src with 2nd dest
+	beq	op0_xu
+	bne	fix_done		|if the reg checks fail, exit
+|
+| We have the opclass 0 situation.
+|
+op0:
+	bfextu	CMDREG1B(%a6){#3:#3},%d0	|get source register no
+	movel	#7,%d1
+	subl	%d0,%d1
+	clrl	%d0
+	bsetl	%d1,%d0
+	fmovemx %d0,ETEMP(%a6)		|load source to ETEMP
+
+	moveb	#0x12,%d0
+	bfins	%d0,CMDREG1B(%a6){#0:#6}	|opclass 2, extended
+|
+|	Set ETEMP exponent bit 15 as the opposite of ete14
+|
+	btst	#6,ETEMP_EX(%a6)		|check etemp exponent bit 14
+	beq	setete15
+	bclr	#etemp15_bit,STAG(%a6)
+	bra	finish
+setete15:
+	bset	#etemp15_bit,STAG(%a6)
+	bra	finish
+
+|
+| We have the case in which a conflict exists between the cu src or
+| dest and the dest of the xu.  We must clear the instruction in 
+| the cu and restore the state, allowing the instruction in the
+| xu to complete.  Remember, the instruction in the nu
+| was exceptional, and was completed by the appropriate handler.
+| If the result of the xu instruction is not exceptional, we can
+| restore the instruction from the cu to the frame and continue
+| processing the original exception.  If the result is also
+| exceptional, we choose to kill the process.
+|
+|	Items saved from the stack:
+|	
+|		$3c stag     - L_SCR1
+|		$40 cmdreg1b - L_SCR2
+|		$44 dtag     - L_SCR3
+|
+| The cu savepc is set to zero, and the frame is restored to the
+| fpu.
+|
+op0_xu:
+	movel	STAG(%a6),L_SCR1(%a6)	
+	movel	CMDREG1B(%a6),L_SCR2(%a6)	
+	movel	DTAG(%a6),L_SCR3(%a6)
+	andil	#0xe0000000,L_SCR3(%a6)
+	moveb	#0,CU_SAVEPC(%a6)
+	movel	(%a7)+,%d1		|save return address from bsr
+	frestore (%a7)+
+	fsave	-(%a7)
+|
+| Check if the instruction which just completed was exceptional.
+| 
+	cmpw	#0x4060,(%a7)
+	beq	op0_xb
+| 
+| It is necessary to isolate the result of the instruction in the
+| xu if it is to fp0 - fp3 and write that value to the USER_FPn
+| locations on the stack.  The correct destination register is in 
+| cmdreg2b.
+|
+	bfextu	CMDREG2B(%a6){#6:#3},%d0	|get dest register no
+	cmpil	#3,%d0
+	bgts	op0_xi
+	beqs	op0_fp3
+	cmpil	#1,%d0
+	blts	op0_fp0
+	beqs	op0_fp1
+op0_fp2:
+	fmovemx %fp2-%fp2,USER_FP2(%a6)
+	bras	op0_xi
+op0_fp1:
+	fmovemx %fp1-%fp1,USER_FP1(%a6)
+	bras	op0_xi
+op0_fp0:
+	fmovemx %fp0-%fp0,USER_FP0(%a6)
+	bras	op0_xi
+op0_fp3:
+	fmovemx %fp3-%fp3,USER_FP3(%a6)
+|
+| The frame returned is idle.  We must build a busy frame to hold
+| the cu state information and setup etemp.
+|
+op0_xi:
+	movel	#22,%d0		|clear 23 lwords
+	clrl	(%a7)
+op0_loop:
+	clrl	-(%a7)
+	dbf	%d0,op0_loop
+	movel	#0x40600000,-(%a7)
+	movel	L_SCR1(%a6),STAG(%a6)
+	movel	L_SCR2(%a6),CMDREG1B(%a6)
+	movel	L_SCR3(%a6),DTAG(%a6)
+	moveb	#0x6,CU_SAVEPC(%a6)
+	movel	%d1,-(%a7)		|return bsr return address
+	bfextu	CMDREG1B(%a6){#3:#3},%d0	|get source register no
+	movel	#7,%d1
+	subl	%d0,%d1
+	clrl	%d0
+	bsetl	%d1,%d0
+	fmovemx %d0,ETEMP(%a6)		|load source to ETEMP
+
+	moveb	#0x12,%d0
+	bfins	%d0,CMDREG1B(%a6){#0:#6}	|opclass 2, extended
+|
+|	Set ETEMP exponent bit 15 as the opposite of ete14
+|
+	btst	#6,ETEMP_EX(%a6)		|check etemp exponent bit 14
+	beq	op0_sete15
+	bclr	#etemp15_bit,STAG(%a6)
+	bra	finish
+op0_sete15:
+	bset	#etemp15_bit,STAG(%a6)
+	bra	finish
+
+|
+| The frame returned is busy.  It is not possible to reconstruct
+| the code sequence to allow completion.  We will jump to 
+| fpsp_fmt_error and allow the kernel to kill the process.
+|
+op0_xb:
+	jmp	fpsp_fmt_error
+
+|
+| Check for opclass 2 and single size.  If not both, exit.
+|
+op2sgl:
+	movew	CMDREG1B(%a6),%d0
+	andiw	#0xFC00,%d0		|strip all but opclass and size
+	cmpiw	#0x4400,%d0		|test for opclass 2 and size=sgl
+	bne	fix_done		|if not, it is not bug 1238
+|
+| Check for cu dest equal to nu dest or equal to xu dest, with 
+| a cu and nu conflict taking priority an nu conflict.  If either,
+| go and fix the bug condition.  Otherwise, exit.
+|
+	bfextu	CMDREG1B(%a6){#6:#3},%d0	|get 1st dest 
+	bfextu	CMDREG3B(%a6){#6:#3},%d1	|get 3rd dest
+	cmpb	%d0,%d1			|cmp 1st dest with 3rd dest
+	beq	op2_com			|if equal, continue bugfix
+	bfextu	CMDREG2B(%a6){#6:#3},%d1	|get 2nd dest 
+	cmpb	%d0,%d1			|cmp 1st dest with 2nd dest
+	bne	fix_done		|if the reg checks fail, exit
+|
+| We have the case in which a conflict exists between the cu src or
+| dest and the dest of the xu.  We must clear the instruction in 
+| the cu and restore the state, allowing the instruction in the
+| xu to complete.  Remember, the instruction in the nu
+| was exceptional, and was completed by the appropriate handler.
+| If the result of the xu instruction is not exceptional, we can
+| restore the instruction from the cu to the frame and continue
+| processing the original exception.  If the result is also
+| exceptional, we choose to kill the process.
+|
+|	Items saved from the stack:
+|	
+|		$3c stag     - L_SCR1
+|		$40 cmdreg1b - L_SCR2
+|		$44 dtag     - L_SCR3
+|		etemp        - FP_SCR2
+|
+| The cu savepc is set to zero, and the frame is restored to the
+| fpu.
+|
+op2_xu:
+	movel	STAG(%a6),L_SCR1(%a6)	
+	movel	CMDREG1B(%a6),L_SCR2(%a6)	
+	movel	DTAG(%a6),L_SCR3(%a6)	
+	andil	#0xe0000000,L_SCR3(%a6)
+	moveb	#0,CU_SAVEPC(%a6)
+	movel	ETEMP(%a6),FP_SCR2(%a6)
+	movel	ETEMP_HI(%a6),FP_SCR2+4(%a6)
+	movel	ETEMP_LO(%a6),FP_SCR2+8(%a6)
+	movel	(%a7)+,%d1		|save return address from bsr
+	frestore (%a7)+
+	fsave	-(%a7)
+|
+| Check if the instruction which just completed was exceptional.
+| 
+	cmpw	#0x4060,(%a7)
+	beq	op2_xb
+| 
+| It is necessary to isolate the result of the instruction in the
+| xu if it is to fp0 - fp3 and write that value to the USER_FPn
+| locations on the stack.  The correct destination register is in 
+| cmdreg2b.
+|
+	bfextu	CMDREG2B(%a6){#6:#3},%d0	|get dest register no
+	cmpil	#3,%d0
+	bgts	op2_xi
+	beqs	op2_fp3
+	cmpil	#1,%d0
+	blts	op2_fp0
+	beqs	op2_fp1
+op2_fp2:
+	fmovemx %fp2-%fp2,USER_FP2(%a6)
+	bras	op2_xi
+op2_fp1:
+	fmovemx %fp1-%fp1,USER_FP1(%a6)
+	bras	op2_xi
+op2_fp0:
+	fmovemx %fp0-%fp0,USER_FP0(%a6)
+	bras	op2_xi
+op2_fp3:
+	fmovemx %fp3-%fp3,USER_FP3(%a6)
+|
+| The frame returned is idle.  We must build a busy frame to hold
+| the cu state information and fix up etemp.
+|
+op2_xi:
+	movel	#22,%d0		|clear 23 lwords
+	clrl	(%a7)
+op2_loop:
+	clrl	-(%a7)
+	dbf	%d0,op2_loop
+	movel	#0x40600000,-(%a7)
+	movel	L_SCR1(%a6),STAG(%a6)
+	movel	L_SCR2(%a6),CMDREG1B(%a6)
+	movel	L_SCR3(%a6),DTAG(%a6)
+	moveb	#0x6,CU_SAVEPC(%a6)
+	movel	FP_SCR2(%a6),ETEMP(%a6)
+	movel	FP_SCR2+4(%a6),ETEMP_HI(%a6)
+	movel	FP_SCR2+8(%a6),ETEMP_LO(%a6)
+	movel	%d1,-(%a7)
+	bra	op2_com
+
+|
+| We have the opclass 2 single source situation.
+|
+op2_com:
+	moveb	#0x15,%d0
+	bfins	%d0,CMDREG1B(%a6){#0:#6}	|opclass 2, double
+
+	cmpw	#0x407F,ETEMP_EX(%a6)	|single +max
+	bnes	case2
+	movew	#0x43FF,ETEMP_EX(%a6)	|to double +max
+	bra	finish
+case2:	
+	cmpw	#0xC07F,ETEMP_EX(%a6)	|single -max
+	bnes	case3
+	movew	#0xC3FF,ETEMP_EX(%a6)	|to double -max
+	bra	finish
+case3:	
+	cmpw	#0x3F80,ETEMP_EX(%a6)	|single +min
+	bnes	case4
+	movew	#0x3C00,ETEMP_EX(%a6)	|to double +min
+	bra	finish
+case4:
+	cmpw	#0xBF80,ETEMP_EX(%a6)	|single -min
+	bne	fix_done
+	movew	#0xBC00,ETEMP_EX(%a6)	|to double -min
+	bra	finish
+|
+| The frame returned is busy.  It is not possible to reconstruct
+| the code sequence to allow completion.  fpsp_fmt_error causes
+| an fline illegal instruction to be executed.
+|
+| You should replace the jump to fpsp_fmt_error with a jump
+| to the entry point used to kill a process. 
+|
+op2_xb:
+	jmp	fpsp_fmt_error
+
+|
+| Enter here if the case is not of the situations affected by
+| bug #1238, or if the fix is completed, and exit.
+|
+finish:
+fix_done:
+	rts
+
+	|end
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/fpsp040/decbin.S linux/arch/m68k/fpsp040/decbin.S
--- v1.3.93/linux/arch/m68k/fpsp040/decbin.S	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/fpsp040/decbin.S	Sat Feb 24 22:58:42 1996
@@ -0,0 +1,506 @@
+|
+|	decbin.sa 3.3 12/19/90
+|
+|	Description: Converts normalized packed bcd value pointed to by
+|	register A6 to extended-precision value in FP0.
+|
+|	Input: Normalized packed bcd value in ETEMP(a6).
+|
+|	Output:	Exact floating-point representation of the packed bcd value.
+|
+|	Saves and Modifies: D2-D5
+|
+|	Speed: The program decbin takes ??? cycles to execute.
+|
+|	Object Size:
+|
+|	External Reference(s): None.
+|
+|	Algorithm:
+|	Expected is a normal bcd (i.e. non-exceptional; all inf, zero,
+|	and NaN operands are dispatched without entering this routine)
+|	value in 68881/882 format at location ETEMP(A6).
+|
+|	A1.	Convert the bcd exponent to binary by successive adds and muls.
+|	Set the sign according to SE. Subtract 16 to compensate
+|	for the mantissa which is to be interpreted as 17 integer
+|	digits, rather than 1 integer and 16 fraction digits.
+|	Note: this operation can never overflow.
+|
+|	A2. Convert the bcd mantissa to binary by successive
+|	adds and muls in FP0. Set the sign according to SM.
+|	The mantissa digits will be converted with the decimal point
+|	assumed following the least-significant digit.
+|	Note: this operation can never overflow.
+|
+|	A3. Count the number of leading/trailing zeros in the
+|	bcd string.  If SE is positive, count the leading zeros;
+|	if negative, count the trailing zeros.  Set the adjusted
+|	exponent equal to the exponent from A1 and the zero count
+|	added if SM = 1 and subtracted if SM = 0.  Scale the
+|	mantissa the equivalent of forcing in the bcd value:
+|
+|	SM = 0	a non-zero digit in the integer position
+|	SM = 1	a non-zero digit in Mant0, lsd of the fraction
+|
+|	this will insure that any value, regardless of its
+|	representation (ex. 0.1E2, 1E1, 10E0, 100E-1), is converted
+|	consistently.
+|
+|	A4. Calculate the factor 10^exp in FP1 using a table of
+|	10^(2^n) values.  To reduce the error in forming factors
+|	greater than 10^27, a directed rounding scheme is used with
+|	tables rounded to RN, RM, and RP, according to the table
+|	in the comments of the pwrten section.
+|
+|	A5. Form the final binary number by scaling the mantissa by
+|	the exponent factor.  This is done by multiplying the
+|	mantissa in FP0 by the factor in FP1 if the adjusted
+|	exponent sign is positive, and dividing FP0 by FP1 if
+|	it is negative.
+|
+|	Clean up and return.  Check if the final mul or div resulted
+|	in an inex2 exception.  If so, set inex1 in the fpsr and 
+|	check if the inex1 exception is enabled.  If so, set d7 upper
+|	word to $0100.  This will signal unimp.sa that an enabled inex1
+|	exception occured.  Unimp will fix the stack.
+|	
+
+|		Copyright (C) Motorola, Inc. 1990
+|			All Rights Reserved
+|
+|	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA 
+|	The copyright notice above does not evidence any  
+|	actual or intended publication of such source code.
+
+|DECBIN    idnt    2,1 | Motorola 040 Floating Point Software Package
+
+	|section	8
+
+	.include "fpsp.h"
+
+|
+|	PTENRN, PTENRM, and PTENRP are arrays of powers of 10 rounded
+|	to nearest, minus, and plus, respectively.  The tables include
+|	10**{1,2,4,8,16,32,64,128,256,512,1024,2048,4096}.  No rounding
+|	is required until the power is greater than 27, however, all
+|	tables include the first 5 for ease of indexing.
+|
+	|xref	PTENRN
+	|xref	PTENRM
+	|xref	PTENRP
+
+RTABLE:	.byte	0,0,0,0
+	.byte	2,3,2,3
+	.byte	2,3,3,2
+	.byte	3,2,2,3
+
+	.global	decbin
+	.global	calc_e
+	.global	pwrten
+	.global	calc_m
+	.global	norm
+	.global	ap_st_z
+	.global	ap_st_n
+|
+	.set	FNIBS,7
+	.set	FSTRT,0
+|
+	.set	ESTRT,4
+	.set	EDIGITS,2	| 
+|
+| Constants in single precision
+FZERO: 	.long	0x00000000
+FONE: 	.long	0x3F800000
+FTEN: 	.long	0x41200000
+
+	.set	TEN,10
+
+|
+decbin:
+	| fmovel	#0,FPCR		;clr real fpcr
+	moveml	%d2-%d5,-(%a7)
+|
+| Calculate exponent:
+|  1. Copy bcd value in memory for use as a working copy.
+|  2. Calculate absolute value of exponent in d1 by mul and add.
+|  3. Correct for exponent sign.
+|  4. Subtract 16 to compensate for interpreting the mant as all integer digits.
+|     (i.e., all digits assumed left of the decimal point.)
+|
+| Register usage:
+|
+|  calc_e:
+|	(*)  d0: temp digit storage
+|	(*)  d1: accumulator for binary exponent
+|	(*)  d2: digit count
+|	(*)  d3: offset pointer
+|	( )  d4: first word of bcd
+|	( )  a0: pointer to working bcd value
+|	( )  a6: pointer to original bcd value
+|	(*)  FP_SCR1: working copy of original bcd value
+|	(*)  L_SCR1: copy of original exponent word
+|
+calc_e:
+	movel	#EDIGITS,%d2	|# of nibbles (digits) in fraction part
+	moveql	#ESTRT,%d3	|counter to pick up digits
+	leal	FP_SCR1(%a6),%a0	|load tmp bcd storage address
+	movel	ETEMP(%a6),(%a0)	|save input bcd value
+	movel	ETEMP_HI(%a6),4(%a0) |save words 2 and 3
+	movel	ETEMP_LO(%a6),8(%a0) |and work with these
+	movel	(%a0),%d4	|get first word of bcd
+	clrl	%d1		|zero d1 for accumulator
+e_gd:
+	mulul	#TEN,%d1	|mul partial product by one digit place
+	bfextu	%d4{%d3:#4},%d0	|get the digit and zero extend into d0
+	addl	%d0,%d1		|d1 = d1 + d0
+	addqb	#4,%d3		|advance d3 to the next digit
+	dbf	%d2,e_gd	|if we have used all 3 digits, exit loop
+	btst	#30,%d4		|get SE
+	beqs	e_pos		|don't negate if pos
+	negl	%d1		|negate before subtracting
+e_pos:
+	subl	#16,%d1		|sub to compensate for shift of mant
+	bges	e_save		|if still pos, do not neg
+	negl	%d1		|now negative, make pos and set SE
+	orl	#0x40000000,%d4	|set SE in d4,
+	orl	#0x40000000,(%a0)	|and in working bcd
+e_save:
+	movel	%d1,L_SCR1(%a6)	|save exp in memory
+|
+|
+| Calculate mantissa:
+|  1. Calculate absolute value of mantissa in fp0 by mul and add.
+|  2. Correct for mantissa sign.
+|     (i.e., all digits assumed left of the decimal point.)
+|
+| Register usage:
+|
+|  calc_m:
+|	(*)  d0: temp digit storage
+|	(*)  d1: lword counter
+|	(*)  d2: digit count
+|	(*)  d3: offset pointer
+|	( )  d4: words 2 and 3 of bcd
+|	( )  a0: pointer to working bcd value
+|	( )  a6: pointer to original bcd value
+|	(*) fp0: mantissa accumulator
+|	( )  FP_SCR1: working copy of original bcd value
+|	( )  L_SCR1: copy of original exponent word
+|
+calc_m:
+	moveql	#1,%d1		|word counter, init to 1
+	fmoves	FZERO,%fp0	|accumulator
+|
+|
+|  Since the packed number has a long word between the first & second parts,
+|  get the integer digit then skip down & get the rest of the
+|  mantissa.  We will unroll the loop once.
+|
+	bfextu	(%a0){#28:#4},%d0	|integer part is ls digit in long word
+	faddb	%d0,%fp0		|add digit to sum in fp0
+|
+|
+|  Get the rest of the mantissa.
+|
+loadlw:
+	movel	(%a0,%d1.L*4),%d4	|load mantissa lonqword into d4
+	moveql	#FSTRT,%d3	|counter to pick up digits
+	moveql	#FNIBS,%d2	|reset number of digits per a0 ptr
+md2b:
+	fmuls	FTEN,%fp0	|fp0 = fp0 * 10
+	bfextu	%d4{%d3:#4},%d0	|get the digit and zero extend
+	faddb	%d0,%fp0	|fp0 = fp0 + digit
+|
+|
+|  If all the digits (8) in that long word have been converted (d2=0),
+|  then inc d1 (=2) to point to the next long word and reset d3 to 0
+|  to initialize the digit offset, and set d2 to 7 for the digit count;
+|  else continue with this long word.
+|
+	addqb	#4,%d3		|advance d3 to the next digit
+	dbf	%d2,md2b		|check for last digit in this lw
+nextlw:
+	addql	#1,%d1		|inc lw pointer in mantissa
+	cmpl	#2,%d1		|test for last lw
+	ble	loadlw		|if not, get last one
+	
+|
+|  Check the sign of the mant and make the value in fp0 the same sign.
+|
+m_sign:
+	btst	#31,(%a0)	|test sign of the mantissa
+	beqs	ap_st_z		|if clear, go to append/strip zeros
+	fnegx	%fp0		|if set, negate fp0
+	
+|
+| Append/strip zeros:
+|
+|  For adjusted exponents which have an absolute value greater than 27*,
+|  this routine calculates the amount needed to normalize the mantissa
+|  for the adjusted exponent.  That number is subtracted from the exp
+|  if the exp was positive, and added if it was negative.  The purpose
+|  of this is to reduce the value of the exponent and the possibility
+|  of error in calculation of pwrten.
+|
+|  1. Branch on the sign of the adjusted exponent.
+|  2p.(positive exp)
+|   2. Check M16 and the digits in lwords 2 and 3 in decending order.
+|   3. Add one for each zero encountered until a non-zero digit.
+|   4. Subtract the count from the exp.
+|   5. Check if the exp has crossed zero in #3 above; make the exp abs
+|	   and set SE.
+|	6. Multiply the mantissa by 10**count.
+|  2n.(negative exp)
+|   2. Check the digits in lwords 3 and 2 in decending order.
+|   3. Add one for each zero encountered until a non-zero digit.
+|   4. Add the count to the exp.
+|   5. Check if the exp has crossed zero in #3 above; clear SE.
+|   6. Divide the mantissa by 10**count.
+|
+|  *Why 27?  If the adjusted exponent is within -28 < expA < 28, than
+|   any adjustment due to append/strip zeros will drive the resultane
+|   exponent towards zero.  Since all pwrten constants with a power
+|   of 27 or less are exact, there is no need to use this routine to
+|   attempt to lessen the resultant exponent.
+|
+| Register usage:
+|
+|  ap_st_z:
+|	(*)  d0: temp digit storage
+|	(*)  d1: zero count
+|	(*)  d2: digit count
+|	(*)  d3: offset pointer
+|	( )  d4: first word of bcd
+|	(*)  d5: lword counter
+|	( )  a0: pointer to working bcd value
+|	( )  FP_SCR1: working copy of original bcd value
+|	( )  L_SCR1: copy of original exponent word
+|
+|
+| First check the absolute value of the exponent to see if this
+| routine is necessary.  If so, then check the sign of the exponent
+| and do append (+) or strip (-) zeros accordingly.
+| This section handles a positive adjusted exponent.
+|
+ap_st_z:
+	movel	L_SCR1(%a6),%d1	|load expA for range test
+	cmpl	#27,%d1		|test is with 27
+	ble	pwrten		|if abs(expA) <28, skip ap/st zeros
+	btst	#30,(%a0)	|check sign of exp
+	bnes	ap_st_n		|if neg, go to neg side
+	clrl	%d1		|zero count reg
+	movel	(%a0),%d4		|load lword 1 to d4
+	bfextu	%d4{#28:#4},%d0	|get M16 in d0
+	bnes	ap_p_fx		|if M16 is non-zero, go fix exp
+	addql	#1,%d1		|inc zero count
+	moveql	#1,%d5		|init lword counter
+	movel	(%a0,%d5.L*4),%d4	|get lword 2 to d4
+	bnes	ap_p_cl		|if lw 2 is zero, skip it
+	addql	#8,%d1		|and inc count by 8
+	addql	#1,%d5		|inc lword counter
+	movel	(%a0,%d5.L*4),%d4	|get lword 3 to d4
+ap_p_cl:
+	clrl	%d3		|init offset reg
+	moveql	#7,%d2		|init digit counter
+ap_p_gd:
+	bfextu	%d4{%d3:#4},%d0	|get digit
+	bnes	ap_p_fx		|if non-zero, go to fix exp
+	addql	#4,%d3		|point to next digit
+	addql	#1,%d1		|inc digit counter
+	dbf	%d2,ap_p_gd	|get next digit
+ap_p_fx:
+	movel	%d1,%d0		|copy counter to d2
+	movel	L_SCR1(%a6),%d1	|get adjusted exp from memory
+	subl	%d0,%d1		|subtract count from exp
+	bges	ap_p_fm		|if still pos, go to pwrten
+	negl	%d1		|now its neg; get abs
+	movel	(%a0),%d4		|load lword 1 to d4
+	orl	#0x40000000,%d4	| and set SE in d4
+	orl	#0x40000000,(%a0)	| and in memory
+|
+| Calculate the mantissa multiplier to compensate for the striping of
+| zeros from the mantissa.
+|
+ap_p_fm:
+	movel	#PTENRN,%a1	|get address of power-of-ten table
+	clrl	%d3		|init table index
+	fmoves	FONE,%fp1	|init fp1 to 1
+	moveql	#3,%d2		|init d2 to count bits in counter
+ap_p_el:
+	asrl	#1,%d0		|shift lsb into carry
+	bccs	ap_p_en		|if 1, mul fp1 by pwrten factor
+	fmulx	(%a1,%d3),%fp1	|mul by 10**(d3_bit_no)
+ap_p_en:
+	addl	#12,%d3		|inc d3 to next rtable entry
+	tstl	%d0		|check if d0 is zero
+	bnes	ap_p_el		|if not, get next bit
+	fmulx	%fp1,%fp0		|mul mantissa by 10**(no_bits_shifted)
+	bras	pwrten		|go calc pwrten
+|
+| This section handles a negative adjusted exponent.
+|
+ap_st_n:
+	clrl	%d1		|clr counter
+	moveql	#2,%d5		|set up d5 to point to lword 3
+	movel	(%a0,%d5.L*4),%d4	|get lword 3
+	bnes	ap_n_cl		|if not zero, check digits
+	subl	#1,%d5		|dec d5 to point to lword 2
+	addql	#8,%d1		|inc counter by 8
+	movel	(%a0,%d5.L*4),%d4	|get lword 2
+ap_n_cl:
+	movel	#28,%d3		|point to last digit
+	moveql	#7,%d2		|init digit counter
+ap_n_gd:
+	bfextu	%d4{%d3:#4},%d0	|get digit
+	bnes	ap_n_fx		|if non-zero, go to exp fix
+	subql	#4,%d3		|point to previous digit
+	addql	#1,%d1		|inc digit counter
+	dbf	%d2,ap_n_gd	|get next digit
+ap_n_fx:
+	movel	%d1,%d0		|copy counter to d0
+	movel	L_SCR1(%a6),%d1	|get adjusted exp from memory
+	subl	%d0,%d1		|subtract count from exp
+	bgts	ap_n_fm		|if still pos, go fix mantissa
+	negl	%d1		|take abs of exp and clr SE
+	movel	(%a0),%d4		|load lword 1 to d4
+	andl	#0xbfffffff,%d4	| and clr SE in d4
+	andl	#0xbfffffff,(%a0)	| and in memory
+|
+| Calculate the mantissa multiplier to compensate for the appending of
+| zeros to the mantissa.
+|
+ap_n_fm:
+	movel	#PTENRN,%a1	|get address of power-of-ten table
+	clrl	%d3		|init table index
+	fmoves	FONE,%fp1	|init fp1 to 1
+	moveql	#3,%d2		|init d2 to count bits in counter
+ap_n_el:
+	asrl	#1,%d0		|shift lsb into carry
+	bccs	ap_n_en		|if 1, mul fp1 by pwrten factor
+	fmulx	(%a1,%d3),%fp1	|mul by 10**(d3_bit_no)
+ap_n_en:
+	addl	#12,%d3		|inc d3 to next rtable entry
+	tstl	%d0		|check if d0 is zero
+	bnes	ap_n_el		|if not, get next bit
+	fdivx	%fp1,%fp0		|div mantissa by 10**(no_bits_shifted)
+|
+|
+| Calculate power-of-ten factor from adjusted and shifted exponent.
+|
+| Register usage:
+|
+|  pwrten:
+|	(*)  d0: temp
+|	( )  d1: exponent
+|	(*)  d2: {FPCR[6:5],SM,SE} as index in RTABLE; temp
+|	(*)  d3: FPCR work copy
+|	( )  d4: first word of bcd
+|	(*)  a1: RTABLE pointer
+|  calc_p:
+|	(*)  d0: temp
+|	( )  d1: exponent
+|	(*)  d3: PWRTxx table index
+|	( )  a0: pointer to working copy of bcd
+|	(*)  a1: PWRTxx pointer
+|	(*) fp1: power-of-ten accumulator
+|
+| Pwrten calculates the exponent factor in the selected rounding mode
+| according to the following table:
+|	
+|	Sign of Mant  Sign of Exp  Rounding Mode  PWRTEN Rounding Mode
+|
+|	ANY	  ANY	RN	RN
+|
+|	 +	   +	RP	RP
+|	 -	   +	RP	RM
+|	 +	   -	RP	RM
+|	 -	   -	RP	RP
+|
+|	 +	   +	RM	RM
+|	 -	   +	RM	RP
+|	 +	   -	RM	RP
+|	 -	   -	RM	RM
+|
+|	 +	   +	RZ	RM
+|	 -	   +	RZ	RM
+|	 +	   -	RZ	RP
+|	 -	   -	RZ	RP
+|
+|
+pwrten:
+	movel	USER_FPCR(%a6),%d3 |get user's FPCR
+	bfextu	%d3{#26:#2},%d2	|isolate rounding mode bits
+	movel	(%a0),%d4		|reload 1st bcd word to d4
+	asll	#2,%d2		|format d2 to be
+	bfextu	%d4{#0:#2},%d0	| {FPCR[6],FPCR[5],SM,SE}
+	addl	%d0,%d2		|in d2 as index into RTABLE
+	leal	RTABLE,%a1	|load rtable base
+	moveb	(%a1,%d2),%d0	|load new rounding bits from table
+	clrl	%d3			|clear d3 to force no exc and extended
+	bfins	%d0,%d3{#26:#2}	|stuff new rounding bits in FPCR
+	fmovel	%d3,%FPCR		|write new FPCR
+	asrl	#1,%d0		|write correct PTENxx table
+	bccs	not_rp		|to a1
+	leal	PTENRP,%a1	|it is RP
+	bras	calc_p		|go to init section
+not_rp:
+	asrl	#1,%d0		|keep checking
+	bccs	not_rm
+	leal	PTENRM,%a1	|it is RM
+	bras	calc_p		|go to init section
+not_rm:
+	leal	PTENRN,%a1	|it is RN
+calc_p:
+	movel	%d1,%d0		|copy exp to d0;use d0
+	bpls	no_neg		|if exp is negative,
+	negl	%d0		|invert it
+	orl	#0x40000000,(%a0)	|and set SE bit
+no_neg:
+	clrl	%d3		|table index
+	fmoves	FONE,%fp1	|init fp1 to 1
+e_loop:
+	asrl	#1,%d0		|shift next bit into carry
+	bccs	e_next		|if zero, skip the mul
+	fmulx	(%a1,%d3),%fp1	|mul by 10**(d3_bit_no)
+e_next:
+	addl	#12,%d3		|inc d3 to next rtable entry
+	tstl	%d0		|check if d0 is zero
+	bnes	e_loop		|not zero, continue shifting
+|
+|
+|  Check the sign of the adjusted exp and make the value in fp0 the
+|  same sign. If the exp was pos then multiply fp1*fp0;
+|  else divide fp0/fp1.
+|
+| Register Usage:
+|  norm:
+|	( )  a0: pointer to working bcd value
+|	(*) fp0: mantissa accumulator
+|	( ) fp1: scaling factor - 10**(abs(exp))
+|
+norm:
+	btst	#30,(%a0)	|test the sign of the exponent
+	beqs	mul		|if clear, go to multiply
+div:
+	fdivx	%fp1,%fp0		|exp is negative, so divide mant by exp
+	bras	end_dec
+mul:
+	fmulx	%fp1,%fp0		|exp is positive, so multiply by exp
+|
+|
+| Clean up and return with result in fp0.
+|
+| If the final mul/div in decbin incurred an inex exception,
+| it will be inex2, but will be reported as inex1 by get_op.
+|
+end_dec:
+	fmovel	%FPSR,%d0		|get status register	
+	bclrl	#inex2_bit+8,%d0	|test for inex2 and clear it
+	fmovel	%d0,%FPSR		|return status reg w/o inex2
+	beqs	no_exc		|skip this if no exc
+	orl	#inx1a_mask,USER_FPSR(%a6) |set inex1/ainex
+no_exc:
+	moveml	(%a7)+,%d2-%d5
+	rts
+	|end
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/fpsp040/do_func.S linux/arch/m68k/fpsp040/do_func.S
--- v1.3.93/linux/arch/m68k/fpsp040/do_func.S	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/fpsp040/do_func.S	Sat Feb 24 22:58:42 1996
@@ -0,0 +1,559 @@
+|
+|	do_func.sa 3.4 2/18/91
+|
+| Do_func performs the unimplemented operation.  The operation
+| to be performed is determined from the lower 7 bits of the
+| extension word (except in the case of fmovecr and fsincos).
+| The opcode and tag bits form an index into a jump table in 
+| tbldo.sa.  Cases of zero, infinity and NaN are handled in 
+| do_func by forcing the default result.  Normalized and
+| denormalized (there are no unnormalized numbers at this
+| point) are passed onto the emulation code.  
+|
+| CMDREG1B and STAG are extracted from the fsave frame
+| and combined to form the table index.  The function called
+| will start with a0 pointing to the ETEMP operand.  Dyadic
+| functions can find FPTEMP at -12(a0).
+|
+| Called functions return their result in fp0.  Sincos returns
+| sin(x) in fp0 and cos(x) in fp1.
+|
+
+|		Copyright (C) Motorola, Inc. 1990
+|			All Rights Reserved
+|
+|	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA 
+|	The copyright notice above does not evidence any  
+|	actual or intended publication of such source code.
+
+DO_FUNC:	|idnt    2,1 | Motorola 040 Floating Point Software Package
+
+	|section	8
+
+	.include "fpsp.h"
+
+	|xref	t_dz2
+	|xref	t_operr
+	|xref	t_inx2
+	|xref 	t_resdnrm
+	|xref	dst_nan
+	|xref	src_nan
+	|xref	nrm_set
+	|xref	sto_cos
+
+	|xref	tblpre
+	|xref	slognp1,slogn,slog10,slog2
+	|xref	slognd,slog10d,slog2d
+	|xref	smod,srem
+	|xref	sscale
+	|xref	smovcr
+
+PONE:	.long	0x3fff0000,0x80000000,0x00000000	|+1
+MONE:	.long	0xbfff0000,0x80000000,0x00000000	|-1
+PZERO:	.long	0x00000000,0x00000000,0x00000000	|+0
+MZERO:	.long	0x80000000,0x00000000,0x00000000	|-0
+PINF:	.long	0x7fff0000,0x00000000,0x00000000	|+inf
+MINF:	.long	0xffff0000,0x00000000,0x00000000	|-inf
+QNAN:	.long	0x7fff0000,0xffffffff,0xffffffff	|non-signaling nan
+PPIBY2:  .long	0x3FFF0000,0xC90FDAA2,0x2168C235	|+PI/2
+MPIBY2:  .long	0xbFFF0000,0xC90FDAA2,0x2168C235	|-PI/2
+
+	.global	do_func
+do_func:
+	clrb	CU_ONLY(%a6)
+|
+| Check for fmovecr.  It does not follow the format of fp gen
+| unimplemented instructions.  The test is on the upper 6 bits;
+| if they are $17, the inst is fmovecr.  Call entry smovcr
+| directly.
+|
+	bfextu	CMDREG1B(%a6){#0:#6},%d0 |get opclass and src fields
+	cmpil	#0x17,%d0		|if op class and size fields are $17, 
+|				;it is FMOVECR; if not, continue
+	bnes	not_fmovecr
+	jmp	smovcr		|fmovecr; jmp directly to emulation
+
+not_fmovecr:
+	movew	CMDREG1B(%a6),%d0
+	andl	#0x7F,%d0
+	cmpil	#0x38,%d0		|if the extension is >= $38, 
+	bges	serror		|it is illegal
+	bfextu	STAG(%a6){#0:#3},%d1
+	lsll	#3,%d0		|make room for STAG
+	addl	%d1,%d0		|combine for final index into table
+	leal	tblpre,%a1	|start of monster jump table
+	movel	(%a1,%d0.w*4),%a1	|real target address
+	leal	ETEMP(%a6),%a0	|a0 is pointer to src op
+	movel	USER_FPCR(%a6),%d1
+	andl	#0xFF,%d1		| discard all but rounding mode/prec
+	fmovel	#0,%fpcr
+	jmp	(%a1)
+|
+|	ERROR
+|
+	.global	serror
+serror:
+	st	STORE_FLG(%a6)
+	rts
+|
+| These routines load forced values into fp0.  They are called
+| by index into tbldo.
+|
+| Load a signed zero to fp0 and set inex2/ainex
+|
+	.global	snzrinx
+snzrinx:
+	btstb	#sign_bit,LOCAL_EX(%a0)	|get sign of source operand
+	bnes	ld_mzinx	|if negative, branch
+	bsr	ld_pzero	|bsr so we can return and set inx
+	bra	t_inx2		|now, set the inx for the next inst
+ld_mzinx:
+	bsr	ld_mzero	|if neg, load neg zero, return here
+	bra	t_inx2		|now, set the inx for the next inst
+|
+| Load a signed zero to fp0; do not set inex2/ainex 
+|
+	.global	szero
+szero:
+	btstb	#sign_bit,LOCAL_EX(%a0) |get sign of source operand
+	bne	ld_mzero	|if neg, load neg zero
+	bra	ld_pzero	|load positive zero
+|
+| Load a signed infinity to fp0; do not set inex2/ainex 
+|
+	.global	sinf
+sinf:
+	btstb	#sign_bit,LOCAL_EX(%a0)	|get sign of source operand
+	bne	ld_minf			|if negative branch
+	bra	ld_pinf
+|
+| Load a signed one to fp0; do not set inex2/ainex 
+|
+	.global	sone
+sone:
+	btstb	#sign_bit,LOCAL_EX(%a0)	|check sign of source
+	bne	ld_mone
+	bra	ld_pone
+|
+| Load a signed pi/2 to fp0; do not set inex2/ainex 
+|
+	.global	spi_2
+spi_2:
+	btstb	#sign_bit,LOCAL_EX(%a0)	|check sign of source
+	bne	ld_mpi2
+	bra	ld_ppi2
+|
+| Load either a +0 or +inf for plus/minus operand
+|
+	.global	szr_inf
+szr_inf:
+	btstb	#sign_bit,LOCAL_EX(%a0)	|check sign of source
+	bne	ld_pzero
+	bra	ld_pinf
+|
+| Result is either an operr or +inf for plus/minus operand
+| [Used by slogn, slognp1, slog10, and slog2]
+|
+	.global	sopr_inf
+sopr_inf:
+	btstb	#sign_bit,LOCAL_EX(%a0)	|check sign of source
+	bne	t_operr
+	bra	ld_pinf
+|
+|	FLOGNP1 
+|
+	.global	sslognp1
+sslognp1:
+	fmovemx (%a0),%fp0-%fp0
+	fcmpb	#-1,%fp0
+	fbgt	slognp1		
+	fbeq	t_dz2		|if = -1, divide by zero exception
+	fmovel	#0,%FPSR		|clr N flag
+	bra	t_operr		|take care of operands < -1
+|
+|	FETOXM1
+|
+	.global	setoxm1i
+setoxm1i:
+	btstb	#sign_bit,LOCAL_EX(%a0)	|check sign of source
+	bne	ld_mone
+	bra	ld_pinf
+|
+|	FLOGN
+|
+| Test for 1.0 as an input argument, returning +zero.  Also check
+| the sign and return operr if negative.
+|
+	.global	sslogn
+sslogn:
+	btstb	#sign_bit,LOCAL_EX(%a0) 
+	bne	t_operr		|take care of operands < 0
+	cmpiw	#0x3fff,LOCAL_EX(%a0) |test for 1.0 input
+	bne	slogn
+	cmpil	#0x80000000,LOCAL_HI(%a0)
+	bne	slogn
+	tstl	LOCAL_LO(%a0)
+	bne	slogn
+	fmovex	PZERO,%fp0
+	rts
+
+	.global	sslognd
+sslognd:
+	btstb	#sign_bit,LOCAL_EX(%a0) 
+	beq	slognd
+	bra	t_operr		|take care of operands < 0
+
+|
+|	FLOG10
+|
+	.global	sslog10
+sslog10:
+	btstb	#sign_bit,LOCAL_EX(%a0)
+	bne	t_operr		|take care of operands < 0
+	cmpiw	#0x3fff,LOCAL_EX(%a0) |test for 1.0 input
+	bne	slog10
+	cmpil	#0x80000000,LOCAL_HI(%a0)
+	bne	slog10
+	tstl	LOCAL_LO(%a0)
+	bne	slog10
+	fmovex	PZERO,%fp0
+	rts
+
+	.global	sslog10d
+sslog10d:
+	btstb	#sign_bit,LOCAL_EX(%a0) 
+	beq	slog10d
+	bra	t_operr		|take care of operands < 0
+
+|
+|	FLOG2
+|
+	.global	sslog2
+sslog2:
+	btstb	#sign_bit,LOCAL_EX(%a0)
+	bne	t_operr		|take care of operands < 0
+	cmpiw	#0x3fff,LOCAL_EX(%a0) |test for 1.0 input
+	bne	slog2
+	cmpil	#0x80000000,LOCAL_HI(%a0)
+	bne	slog2
+	tstl	LOCAL_LO(%a0)
+	bne	slog2
+	fmovex	PZERO,%fp0
+	rts
+
+	.global	sslog2d
+sslog2d:
+	btstb	#sign_bit,LOCAL_EX(%a0) 
+	beq	slog2d
+	bra	t_operr		|take care of operands < 0
+
+|
+|	FMOD
+|
+pmodt:
+|				;$21 fmod
+|				;dtag,stag
+	.long	smod		|  00,00  norm,norm = normal
+	.long	smod_oper	|  00,01  norm,zero = nan with operr
+	.long	smod_fpn	|  00,10  norm,inf  = fpn
+	.long	smod_snan	|  00,11  norm,nan  = nan
+	.long	smod_zro	|  01,00  zero,norm = +-zero
+	.long	smod_oper	|  01,01  zero,zero = nan with operr
+	.long	smod_zro	|  01,10  zero,inf  = +-zero
+	.long	smod_snan	|  01,11  zero,nan  = nan
+	.long	smod_oper	|  10,00  inf,norm  = nan with operr
+	.long	smod_oper	|  10,01  inf,zero  = nan with operr
+	.long	smod_oper	|  10,10  inf,inf   = nan with operr
+	.long	smod_snan	|  10,11  inf,nan   = nan
+	.long	smod_dnan	|  11,00  nan,norm  = nan
+	.long	smod_dnan	|  11,01  nan,zero  = nan
+	.long	smod_dnan	|  11,10  nan,inf   = nan
+	.long	smod_dnan	|  11,11  nan,nan   = nan
+
+	.global	pmod
+pmod:
+	clrb	FPSR_QBYTE(%a6) | clear quotient field
+	bfextu	STAG(%a6){#0:#3},%d0 |stag = d0
+	bfextu	DTAG(%a6){#0:#3},%d1 |dtag = d1
+
+|
+| Alias extended denorms to norms for the jump table.
+|
+	bclrl	#2,%d0
+	bclrl	#2,%d1
+
+	lslb	#2,%d1
+	orb	%d0,%d1		|d1{3:2} = dtag, d1{1:0} = stag
+|				;Tag values:
+|				;00 = norm or denorm
+|				;01 = zero
+|				;10 = inf
+|				;11 = nan
+	lea	pmodt,%a1
+	movel	(%a1,%d1.w*4),%a1
+	jmp	(%a1)
+
+smod_snan:
+	bra	src_nan
+smod_dnan:
+	bra	dst_nan
+smod_oper:
+	bra	t_operr
+smod_zro:
+	moveb	ETEMP(%a6),%d1	|get sign of src op
+	moveb	FPTEMP(%a6),%d0	|get sign of dst op
+	eorb	%d0,%d1		|get exor of sign bits
+	btstl	#7,%d1		|test for sign
+	beqs	smod_zsn	|if clr, do not set sign big
+	bsetb	#q_sn_bit,FPSR_QBYTE(%a6) |set q-byte sign bit
+smod_zsn:
+	btstl	#7,%d0		|test if + or -
+	beq	ld_pzero	|if pos then load +0
+	bra	ld_mzero	|else neg load -0
+	
+smod_fpn:
+	moveb	ETEMP(%a6),%d1	|get sign of src op
+	moveb	FPTEMP(%a6),%d0	|get sign of dst op
+	eorb	%d0,%d1		|get exor of sign bits
+	btstl	#7,%d1		|test for sign
+	beqs	smod_fsn	|if clr, do not set sign big
+	bsetb	#q_sn_bit,FPSR_QBYTE(%a6) |set q-byte sign bit
+smod_fsn:
+	tstb	DTAG(%a6)	|filter out denormal destination case
+	bpls	smod_nrm	|
+	leal	FPTEMP(%a6),%a0	|a0<- addr(FPTEMP)
+	bra	t_resdnrm	|force UNFL(but exact) result
+smod_nrm:
+	fmovel USER_FPCR(%a6),%fpcr |use user's rmode and precision
+	fmovex FPTEMP(%a6),%fp0	|return dest to fp0
+	rts
+		
+|
+|	FREM
+|
+premt:
+|				;$25 frem
+|				;dtag,stag
+	.long	srem		|  00,00  norm,norm = normal
+	.long	srem_oper	|  00,01  norm,zero = nan with operr
+	.long	srem_fpn	|  00,10  norm,inf  = fpn
+	.long	srem_snan	|  00,11  norm,nan  = nan
+	.long	srem_zro	|  01,00  zero,norm = +-zero
+	.long	srem_oper	|  01,01  zero,zero = nan with operr
+	.long	srem_zro	|  01,10  zero,inf  = +-zero
+	.long	srem_snan	|  01,11  zero,nan  = nan
+	.long	srem_oper	|  10,00  inf,norm  = nan with operr
+	.long	srem_oper	|  10,01  inf,zero  = nan with operr
+	.long	srem_oper	|  10,10  inf,inf   = nan with operr
+	.long	srem_snan	|  10,11  inf,nan   = nan
+	.long	srem_dnan	|  11,00  nan,norm  = nan
+	.long	srem_dnan	|  11,01  nan,zero  = nan
+	.long	srem_dnan	|  11,10  nan,inf   = nan
+	.long	srem_dnan	|  11,11  nan,nan   = nan
+
+	.global	prem
+prem:
+	clrb	FPSR_QBYTE(%a6)   |clear quotient field
+	bfextu	STAG(%a6){#0:#3},%d0 |stag = d0
+	bfextu	DTAG(%a6){#0:#3},%d1 |dtag = d1
+|
+| Alias extended denorms to norms for the jump table.
+|
+	bclr	#2,%d0
+	bclr	#2,%d1
+
+	lslb	#2,%d1
+	orb	%d0,%d1		|d1{3:2} = dtag, d1{1:0} = stag
+|				;Tag values:
+|				;00 = norm or denorm
+|				;01 = zero
+|				;10 = inf
+|				;11 = nan
+	lea	premt,%a1
+	movel	(%a1,%d1.w*4),%a1
+	jmp	(%a1)
+	
+srem_snan:
+	bra	src_nan
+srem_dnan:
+	bra	dst_nan
+srem_oper:
+	bra	t_operr
+srem_zro:
+	moveb	ETEMP(%a6),%d1	|get sign of src op
+	moveb	FPTEMP(%a6),%d0	|get sign of dst op
+	eorb	%d0,%d1		|get exor of sign bits
+	btstl	#7,%d1		|test for sign
+	beqs	srem_zsn	|if clr, do not set sign big
+	bsetb	#q_sn_bit,FPSR_QBYTE(%a6) |set q-byte sign bit
+srem_zsn:
+	btstl	#7,%d0		|test if + or -
+	beq	ld_pzero	|if pos then load +0
+	bra	ld_mzero	|else neg load -0
+	
+srem_fpn:
+	moveb	ETEMP(%a6),%d1	|get sign of src op
+	moveb	FPTEMP(%a6),%d0	|get sign of dst op
+	eorb	%d0,%d1		|get exor of sign bits
+	btstl	#7,%d1		|test for sign
+	beqs	srem_fsn	|if clr, do not set sign big
+	bsetb	#q_sn_bit,FPSR_QBYTE(%a6) |set q-byte sign bit
+srem_fsn:
+	tstb	DTAG(%a6)	|filter out denormal destination case
+	bpls	srem_nrm	|
+	leal	FPTEMP(%a6),%a0	|a0<- addr(FPTEMP)
+	bra	t_resdnrm	|force UNFL(but exact) result
+srem_nrm:
+	fmovel USER_FPCR(%a6),%fpcr |use user's rmode and precision
+	fmovex FPTEMP(%a6),%fp0	|return dest to fp0
+	rts
+|
+|	FSCALE
+|
+pscalet:
+|				;$26 fscale
+|				;dtag,stag
+	.long	sscale		|  00,00  norm,norm = result
+	.long	sscale		|  00,01  norm,zero = fpn
+	.long	scl_opr		|  00,10  norm,inf  = nan with operr
+	.long	scl_snan	|  00,11  norm,nan  = nan
+	.long	scl_zro		|  01,00  zero,norm = +-zero
+	.long	scl_zro		|  01,01  zero,zero = +-zero
+	.long	scl_opr		|  01,10  zero,inf  = nan with operr
+	.long	scl_snan	|  01,11  zero,nan  = nan
+	.long	scl_inf		|  10,00  inf,norm  = +-inf
+	.long	scl_inf		|  10,01  inf,zero  = +-inf
+	.long	scl_opr		|  10,10  inf,inf   = nan with operr
+ 	.long	scl_snan	|  10,11  inf,nan   = nan
+ 	.long	scl_dnan	|  11,00  nan,norm  = nan
+ 	.long	scl_dnan	|  11,01  nan,zero  = nan
+ 	.long	scl_dnan	|  11,10  nan,inf   = nan
+	.long	scl_dnan	|  11,11  nan,nan   = nan
+
+	.global	pscale
+pscale:
+	bfextu	STAG(%a6){#0:#3},%d0 |stag in d0
+	bfextu	DTAG(%a6){#0:#3},%d1 |dtag in d1
+	bclrl	#2,%d0		|alias  denorm into norm
+	bclrl	#2,%d1		|alias  denorm into norm
+	lslb	#2,%d1
+	orb	%d0,%d1		|d1{4:2} = dtag, d1{1:0} = stag
+|				;dtag values     stag values:
+|				;000 = norm      00 = norm
+|				;001 = zero	 01 = zero
+|				;010 = inf	 10 = inf
+|				;011 = nan	 11 = nan
+|				;100 = dnrm
+|
+|
+	leal	pscalet,%a1	|load start of jump table
+	movel	(%a1,%d1.w*4),%a1	|load a1 with label depending on tag
+	jmp	(%a1)		|go to the routine
+
+scl_opr:
+	bra	t_operr
+
+scl_dnan:
+	bra	dst_nan
+
+scl_zro:
+	btstb	#sign_bit,FPTEMP_EX(%a6)	|test if + or -
+	beq	ld_pzero		|if pos then load +0
+	bra	ld_mzero		|if neg then load -0
+scl_inf:
+	btstb	#sign_bit,FPTEMP_EX(%a6)	|test if + or -
+	beq	ld_pinf			|if pos then load +inf
+	bra	ld_minf			|else neg load -inf
+scl_snan:
+	bra	src_nan
+|
+|	FSINCOS
+|
+	.global	ssincosz
+ssincosz:
+	btstb	#sign_bit,ETEMP(%a6)	|get sign
+	beqs	sincosp
+	fmovex	MZERO,%fp0
+	bras	sincoscom
+sincosp:
+	fmovex PZERO,%fp0
+sincoscom:
+  	fmovemx PONE,%fp1-%fp1	|do not allow FPSR to be affected
+	bra	sto_cos		|store cosine result
+
+	.global	ssincosi
+ssincosi:
+	fmovex QNAN,%fp1	|load NAN
+	bsr	sto_cos		|store cosine result
+	fmovex QNAN,%fp0	|load NAN
+	bra	t_operr
+
+	.global	ssincosnan
+ssincosnan:
+	movel	ETEMP_EX(%a6),FP_SCR1(%a6)
+	movel	ETEMP_HI(%a6),FP_SCR1+4(%a6)
+	movel	ETEMP_LO(%a6),FP_SCR1+8(%a6)
+	bsetb	#signan_bit,FP_SCR1+4(%a6)
+	fmovemx FP_SCR1(%a6),%fp1-%fp1
+	bsr	sto_cos
+	bra	src_nan
+|
+| This code forces default values for the zero, inf, and nan cases 
+| in the transcendentals code.  The CC bits must be set in the
+| stacked FPSR to be correctly reported.
+|
+|**Returns +PI/2
+	.global	ld_ppi2
+ld_ppi2:
+	fmovex PPIBY2,%fp0		|load +pi/2
+	bra	t_inx2			|set inex2 exc
+
+|**Returns -PI/2
+	.global	ld_mpi2
+ld_mpi2:
+	fmovex MPIBY2,%fp0		|load -pi/2
+	orl	#neg_mask,USER_FPSR(%a6)	|set N bit
+	bra	t_inx2			|set inex2 exc
+
+|**Returns +inf
+	.global	ld_pinf
+ld_pinf:
+	fmovex PINF,%fp0		|load +inf
+	orl	#inf_mask,USER_FPSR(%a6)	|set I bit
+	rts
+
+|**Returns -inf
+	.global	ld_minf
+ld_minf:
+	fmovex MINF,%fp0		|load -inf
+	orl	#neg_mask+inf_mask,USER_FPSR(%a6)	|set N and I bits
+	rts
+
+|**Returns +1
+	.global	ld_pone
+ld_pone:
+	fmovex PONE,%fp0		|load +1
+	rts
+
+|**Returns -1
+	.global	ld_mone
+ld_mone:
+	fmovex MONE,%fp0		|load -1
+	orl	#neg_mask,USER_FPSR(%a6)	|set N bit
+	rts
+
+|**Returns +0
+	.global	ld_pzero
+ld_pzero:
+	fmovex PZERO,%fp0		|load +0
+	orl	#z_mask,USER_FPSR(%a6)	|set Z bit
+	rts
+
+|**Returns -0
+	.global	ld_mzero
+ld_mzero:
+	fmovex MZERO,%fp0		|load -0
+	orl	#neg_mask+z_mask,USER_FPSR(%a6)	|set N and Z bits
+	rts
+
+	|end
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/fpsp040/fpsp.h linux/arch/m68k/fpsp040/fpsp.h
--- v1.3.93/linux/arch/m68k/fpsp040/fpsp.h	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/fpsp040/fpsp.h	Wed Dec 27 22:44:57 1995
@@ -0,0 +1,348 @@
+|
+|	fpsp.h 3.3 3.3
+|
+
+|		Copyright (C) Motorola, Inc. 1990
+|			All Rights Reserved
+|
+|	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA 
+|	The copyright notice above does not evidence any  
+|	actual or intended publication of such source code.
+
+|	fpsp.h --- stack frame offsets during FPSP exception handling
+|
+|	These equates are used to access the exception frame, the fsave
+|	frame and any local variables needed by the FPSP package.
+|	
+|	All FPSP handlers begin by executing:
+|
+|		link	a6,#-LOCAL_SIZE
+|		fsave	-(a7)
+|		movem.l	d0-d1/a0-a1,USER_DA(a6)
+|		fmovem.x fp0-fp3,USER_FP0(a6)
+|		fmove.l	fpsr/fpcr/fpiar,USER_FPSR(a6)
+|
+|	After initialization, the stack looks like this:
+|
+|	A7 --->	+-------------------------------+
+|		|				|
+|		|	FPU fsave area		|
+|		|				|
+|		+-------------------------------+
+|		|				|
+|		|	FPSP Local Variables	|
+|		|	     including		|
+|		|	  saved registers	|
+|		|				|
+|		+-------------------------------+
+|	A6 --->	|	Saved A6		|
+|		+-------------------------------+
+|		|				|
+|		|	Exception Frame		|
+|		|				|
+|		|				|
+|
+|	Positive offsets from A6 refer to the exception frame.  Negative
+|	offsets refer to the Local Variable area and the fsave area.
+|	The fsave frame is also accessible from the top via A7.
+|
+|	On exit, the handlers execute:
+|
+|		movem.l	USER_DA(a6),d0-d1/a0-a1
+|		fmovem.x USER_FP0(a6),fp0-fp3
+|		fmove.l	USER_FPSR(a6),fpsr/fpcr/fpiar
+|		frestore (a7)+
+|		unlk	a6
+|
+|	and then either "bra fpsp_done" if the exception was completely
+|	handled	by the package, or "bra real_xxxx" which is an external
+|	label to a routine that will process a real exception of the
+|	type that was generated.  Some handlers may omit the "frestore"
+|	if the FPU state after the exception is idle.
+|
+|	Sometimes the exception handler will transform the fsave area
+|	because it needs to report an exception back to the user.  This
+|	can happen if the package is entered for an unimplemented float
+|	instruction that generates (say) an underflow.  Alternatively,
+|	a second fsave frame can be pushed onto the stack and the
+|	handler	exit code will reload the new frame and discard the old.
+|
+|	The registers d0, d1, a0, a1 and fp0-fp3 are always saved and
+|	restored from the "local variable" area and can be used as
+|	temporaries.  If a routine needs to change any
+|	of these registers, it should modify the saved copy and let
+|	the handler exit code restore the value.
+|
+|----------------------------------------------------------------------
+|
+|	Local Variables on the stack
+|
+	.set	LOCAL_SIZE,192		| bytes needed for local variables
+	.set	LV,-LOCAL_SIZE	| convenient base value
+|
+	.set	USER_DA,LV+0		| save space for D0-D1,A0-A1
+	.set	USER_D0,LV+0		| saved user D0
+	.set	USER_D1,LV+4		| saved user D1
+	.set	USER_A0,LV+8		| saved user A0
+	.set	USER_A1,LV+12		| saved user A1
+	.set	USER_FP0,LV+16		| saved user FP0
+	.set	USER_FP1,LV+28		| saved user FP1
+	.set	USER_FP2,LV+40		| saved user FP2
+	.set	USER_FP3,LV+52		| saved user FP3
+	.set	USER_FPCR,LV+64		| saved user FPCR
+	.set	FPCR_ENABLE,USER_FPCR+2	| 	FPCR exception enable 
+	.set	FPCR_MODE,USER_FPCR+3	| 	FPCR rounding mode control
+	.set	USER_FPSR,LV+68		| saved user FPSR
+	.set	FPSR_CC,USER_FPSR+0	| 	FPSR condition code
+	.set	FPSR_QBYTE,USER_FPSR+1	| 	FPSR quotient
+	.set	FPSR_EXCEPT,USER_FPSR+2	| 	FPSR exception
+	.set	FPSR_AEXCEPT,USER_FPSR+3	| 	FPSR accrued exception
+	.set	USER_FPIAR,LV+72		| saved user FPIAR
+	.set	FP_SCR1,LV+76		| room for a temporary float value
+	.set	FP_SCR2,LV+92		| room for a temporary float value
+	.set	L_SCR1,LV+108		| room for a temporary long value
+	.set	L_SCR2,LV+112		| room for a temporary long value
+	.set	STORE_FLG,LV+116
+	.set	BINDEC_FLG,LV+117		| used in bindec
+	.set	DNRM_FLG,LV+118		| used in res_func
+	.set	RES_FLG,LV+119		| used in res_func
+	.set	DY_MO_FLG,LV+120		| dyadic/monadic flag
+	.set	UFLG_TMP,LV+121		| temporary for uflag errata
+	.set	CU_ONLY,LV+122		| cu-only flag
+	.set	VER_TMP,LV+123		| temp holding for version number
+	.set	L_SCR3,LV+124		| room for a temporary long value
+	.set	FP_SCR3,LV+128		| room for a temporary float value
+	.set	FP_SCR4,LV+144		| room for a temporary float value
+	.set	FP_SCR5,LV+160		| room for a temporary float value
+	.set	FP_SCR6,LV+176
+|
+|NEXT		equ	LV+192		;need to increase LOCAL_SIZE
+|
+|--------------------------------------------------------------------------
+|
+|	fsave offsets and bit definitions
+|
+|	Offsets are defined from the end of an fsave because the last 10
+|	words of a busy frame are the same as the unimplemented frame.
+|
+	.set	CU_SAVEPC,LV-92		| micro-pc for CU (1 byte)
+	.set	FPR_DIRTY_BITS,LV-91		| fpr dirty bits
+|
+	.set	WBTEMP,LV-76		| write back temp (12 bytes)
+	.set	WBTEMP_EX,WBTEMP		| wbtemp sign and exponent (2 bytes)
+	.set	WBTEMP_HI,WBTEMP+4	| wbtemp mantissa [63:32] (4 bytes)
+	.set	WBTEMP_LO,WBTEMP+8	| wbtemp mantissa [31:00] (4 bytes)
+|
+	.set	WBTEMP_SGN,WBTEMP+2	| used to store sign
+|
+	.set	FPSR_SHADOW,LV-64		| fpsr shadow reg
+|
+	.set	FPIARCU,LV-60		| Instr. addr. reg. for CU (4 bytes)
+|
+	.set	CMDREG2B,LV-52		| cmd reg for machine 2
+	.set	CMDREG3B,LV-48		| cmd reg for E3 exceptions (2 bytes)
+|
+	.set	NMNEXC,LV-44		| NMNEXC (unsup,snan bits only)
+	.set	nmn_unsup_bit,1	| 
+	.set	nmn_snan_bit,0	| 
+|
+	.set	NMCEXC,LV-43		| NMNEXC & NMCEXC
+	.set	nmn_operr_bit,7
+	.set	nmn_ovfl_bit,6
+	.set	nmn_unfl_bit,5
+	.set	nmc_unsup_bit,4
+	.set	nmc_snan_bit,3
+	.set	nmc_operr_bit,2
+	.set	nmc_ovfl_bit,1
+	.set	nmc_unfl_bit,0
+|
+	.set	STAG,LV-40		| source tag (1 byte)
+	.set	WBTEMP_GRS,LV-40		| alias wbtemp guard, round, sticky
+	.set	guard_bit,1		| guard bit is bit number 1
+	.set	round_bit,0		| round bit is bit number 0
+	.set	stag_mask,0xE0		| upper 3 bits are source tag type
+	.set	denorm_bit,7		| bit determins if denorm or unnorm
+	.set	etemp15_bit,4		| etemp exponent bit #15
+	.set	wbtemp66_bit,2		| wbtemp mantissa bit #66
+	.set	wbtemp1_bit,1		| wbtemp mantissa bit #1
+	.set	wbtemp0_bit,0		| wbtemp mantissa bit #0
+|
+	.set	STICKY,LV-39		| holds sticky bit
+	.set	sticky_bit,7
+|
+	.set	CMDREG1B,LV-36		| cmd reg for E1 exceptions (2 bytes)
+	.set	kfact_bit,12		| distinguishes static/dynamic k-factor
+|					;on packed move outs.  NOTE: this
+|					;equate only works when CMDREG1B is in
+|					;a register.
+|
+	.set	CMDWORD,LV-35		| command word in cmd1b
+	.set	direction_bit,5		| bit 0 in opclass
+	.set	size_bit2,12		| bit 2 in size field
+|
+	.set	DTAG,LV-32		| dest tag (1 byte)
+	.set	dtag_mask,0xE0		| upper 3 bits are dest type tag
+	.set	fptemp15_bit,4		| fptemp exponent bit #15
+|
+	.set	WB_BYTE,LV-31		| holds WBTE15 bit (1 byte)
+	.set	wbtemp15_bit,4		| wbtemp exponent bit #15
+|
+	.set	E_BYTE,LV-28		| holds E1 and E3 bits (1 byte)
+	.set	E1,2		| which bit is E1 flag
+	.set	E3,1		| which bit is E3 flag
+	.set	SFLAG,0		| which bit is S flag
+|
+	.set	T_BYTE,LV-27		| holds T and U bits (1 byte)
+	.set	XFLAG,7		| which bit is X flag
+	.set	UFLAG,5		| which bit is U flag
+	.set	TFLAG,4		| which bit is T flag
+|
+	.set	FPTEMP,LV-24		| fptemp (12 bytes)
+	.set	FPTEMP_EX,FPTEMP		| fptemp sign and exponent (2 bytes)
+	.set	FPTEMP_HI,FPTEMP+4	| fptemp mantissa [63:32] (4 bytes)
+	.set	FPTEMP_LO,FPTEMP+8	| fptemp mantissa [31:00] (4 bytes)
+|
+	.set	FPTEMP_SGN,FPTEMP+2	| used to store sign
+|
+	.set	ETEMP,LV-12		| etemp (12 bytes)
+	.set	ETEMP_EX,ETEMP		| etemp sign and exponent (2 bytes)
+	.set	ETEMP_HI,ETEMP+4		| etemp mantissa [63:32] (4 bytes)
+	.set	ETEMP_LO,ETEMP+8		| etemp mantissa [31:00] (4 bytes)
+|
+	.set	ETEMP_SGN,ETEMP+2		| used to store sign
+|
+	.set	EXC_SR,4		| exception frame status register
+	.set	EXC_PC,6		| exception frame program counter
+	.set	EXC_VEC,10		| exception frame vector (format+vector#)
+	.set	EXC_EA,12		| exception frame effective address
+|
+|--------------------------------------------------------------------------
+|
+|	FPSR/FPCR bits
+|
+	.set	neg_bit,3	|  negative result
+	.set	z_bit,2	|  zero result
+	.set	inf_bit,1	|  infinity result
+	.set	nan_bit,0	|  not-a-number result
+|
+	.set	q_sn_bit,7	|  sign bit of quotient byte
+|
+	.set	bsun_bit,7	|  branch on unordered
+	.set	snan_bit,6	|  signalling nan
+	.set	operr_bit,5	|  operand error
+	.set	ovfl_bit,4	|  overflow
+	.set	unfl_bit,3	|  underflow
+	.set	dz_bit,2	|  divide by zero
+	.set	inex2_bit,1	|  inexact result 2
+	.set	inex1_bit,0	|  inexact result 1
+|
+	.set	aiop_bit,7	|  accrued illegal operation
+	.set	aovfl_bit,6	|  accrued overflow
+	.set	aunfl_bit,5	|  accrued underflow
+	.set	adz_bit,4	|  accrued divide by zero
+	.set	ainex_bit,3	|  accrued inexact
+|
+|	FPSR individual bit masks
+|
+	.set	neg_mask,0x08000000
+	.set	z_mask,0x04000000
+	.set	inf_mask,0x02000000
+	.set	nan_mask,0x01000000
+|
+	.set	bsun_mask,0x00008000	| 
+	.set	snan_mask,0x00004000
+	.set	operr_mask,0x00002000
+	.set	ovfl_mask,0x00001000
+	.set	unfl_mask,0x00000800
+	.set	dz_mask,0x00000400
+	.set	inex2_mask,0x00000200
+	.set	inex1_mask,0x00000100
+|
+	.set	aiop_mask,0x00000080	|  accrued illegal operation
+	.set	aovfl_mask,0x00000040	|  accrued overflow
+	.set	aunfl_mask,0x00000020	|  accrued underflow
+	.set	adz_mask,0x00000010	|  accrued divide by zero
+	.set	ainex_mask,0x00000008	|  accrued inexact
+|
+|	FPSR combinations used in the FPSP
+|
+	.set	dzinf_mask,inf_mask+dz_mask+adz_mask
+	.set	opnan_mask,nan_mask+operr_mask+aiop_mask
+	.set	nzi_mask,0x01ffffff 	|  clears N, Z, and I
+	.set	unfinx_mask,unfl_mask+inex2_mask+aunfl_mask+ainex_mask
+	.set	unf2inx_mask,unfl_mask+inex2_mask+ainex_mask
+	.set	ovfinx_mask,ovfl_mask+inex2_mask+aovfl_mask+ainex_mask
+	.set	inx1a_mask,inex1_mask+ainex_mask
+	.set	inx2a_mask,inex2_mask+ainex_mask
+	.set	snaniop_mask,nan_mask+snan_mask+aiop_mask
+	.set	naniop_mask,nan_mask+aiop_mask
+	.set	neginf_mask,neg_mask+inf_mask
+	.set	infaiop_mask,inf_mask+aiop_mask
+	.set	negz_mask,neg_mask+z_mask
+	.set	opaop_mask,operr_mask+aiop_mask
+	.set	unfl_inx_mask,unfl_mask+aunfl_mask+ainex_mask
+	.set	ovfl_inx_mask,ovfl_mask+aovfl_mask+ainex_mask
+|
+|--------------------------------------------------------------------------
+|
+|	FPCR rounding modes
+|
+	.set	x_mode,0x00	|  round to extended
+	.set	s_mode,0x40	|  round to single
+	.set	d_mode,0x80	|  round to double
+|
+	.set	rn_mode,0x00	|  round nearest
+	.set	rz_mode,0x10	|  round to zero
+	.set	rm_mode,0x20	|  round to minus infinity
+	.set	rp_mode,0x30	|  round to plus infinity
+|
+|--------------------------------------------------------------------------
+|
+|	Miscellaneous equates
+|
+	.set	signan_bit,6	|  signalling nan bit in mantissa
+	.set	sign_bit,7
+|
+	.set	rnd_stky_bit,29	|  round/sticky bit of mantissa
+|				this can only be used if in a data register
+	.set	sx_mask,0x01800000 |  set s and x bits in word $48
+|
+	.set	LOCAL_EX,0
+	.set	LOCAL_SGN,2
+	.set	LOCAL_HI,4
+	.set	LOCAL_LO,8
+	.set	LOCAL_GRS,12	|  valid ONLY for FP_SCR1, FP_SCR2
+|
+|
+	.set	norm_tag,0x00	|  tag bits in {7:5} position
+	.set	zero_tag,0x20
+	.set	inf_tag,0x40
+	.set	nan_tag,0x60
+	.set	dnrm_tag,0x80
+|
+|	fsave sizes and formats
+|
+	.set	VER_4,0x40		|  fpsp compatible version numbers
+|					are in the $40s {$40-$4f}
+	.set	VER_40,0x40		|  original version number
+	.set	VER_41,0x41		|  revision version number
+|
+	.set	BUSY_SIZE,100		|  size of busy frame
+	.set	BUSY_FRAME,LV-BUSY_SIZE	|  start of busy frame
+|
+	.set	UNIMP_40_SIZE,44		|  size of orig unimp frame
+	.set	UNIMP_41_SIZE,52		|  size of rev unimp frame
+|
+	.set	IDLE_SIZE,4		|  size of idle frame
+	.set	IDLE_FRAME,LV-IDLE_SIZE	|  start of idle frame
+|
+|	exception vectors
+|
+	.set	TRACE_VEC,0x2024		|  trace trap
+	.set	FLINE_VEC,0x002C		|  real F-line
+	.set	UNIMP_VEC,0x202C		|  unimplemented
+	.set	INEX_VEC,0x00C4
+|
+	.set	dbl_thresh,0x3C01
+	.set	sgl_thresh,0x3F81
+|
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/fpsp040/gen_except.S linux/arch/m68k/fpsp040/gen_except.S
--- v1.3.93/linux/arch/m68k/fpsp040/gen_except.S	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/fpsp040/gen_except.S	Sat Feb 24 22:58:43 1996
@@ -0,0 +1,468 @@
+|
+|	gen_except.sa 3.7 1/16/92
+|
+|	gen_except --- FPSP routine to detect reportable exceptions
+|	
+|	This routine compares the exception enable byte of the
+|	user_fpcr on the stack with the exception status byte
+|	of the user_fpsr. 
+|
+|	Any routine which may report an exceptions must load
+|	the stack frame in memory with the exceptional operand(s).
+|
+|	Priority for exceptions is:
+|
+|	Highest:	bsun
+|			snan
+|			operr
+|			ovfl
+|			unfl
+|			dz
+|			inex2
+|	Lowest:		inex1
+|
+|	Note: The IEEE standard specifies that inex2 is to be
+|	reported if ovfl occurs and the ovfl enable bit is not
+|	set but the inex2 enable bit is.  
+|
+|
+|		Copyright (C) Motorola, Inc. 1990
+|			All Rights Reserved
+|
+|	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA 
+|	The copyright notice above does not evidence any  
+|	actual or intended publication of such source code.
+
+GEN_EXCEPT:    |idnt    2,1 | Motorola 040 Floating Point Software Package
+
+	|section 8
+
+	.include "fpsp.h"
+
+	|xref	real_trace
+	|xref	fpsp_done
+	|xref	fpsp_fmt_error
+
+exc_tbl:
+	.long	bsun_exc
+	.long	commonE1
+	.long	commonE1
+	.long	ovfl_unfl
+	.long	ovfl_unfl
+	.long	commonE1
+	.long	commonE3
+	.long	commonE3
+	.long	no_match
+
+	.global	gen_except
+gen_except:
+	cmpib	#IDLE_SIZE-4,1(%a7)	|test for idle frame
+	beq	do_check		|go handle idle frame
+	cmpib	#UNIMP_40_SIZE-4,1(%a7)	|test for orig unimp frame
+	beqs	unimp_x			|go handle unimp frame
+	cmpib	#UNIMP_41_SIZE-4,1(%a7)	|test for rev unimp frame
+	beqs	unimp_x			|go handle unimp frame
+	cmpib	#BUSY_SIZE-4,1(%a7)	|if size <> $60, fmt error
+	bnel	fpsp_fmt_error
+	leal	BUSY_SIZE+LOCAL_SIZE(%a7),%a1 |init a1 so fpsp.h
+|					;equates will work
+| Fix up the new busy frame with entries from the unimp frame
+|
+	movel	ETEMP_EX(%a6),ETEMP_EX(%a1) |copy etemp from unimp
+	movel	ETEMP_HI(%a6),ETEMP_HI(%a1) |frame to busy frame
+	movel	ETEMP_LO(%a6),ETEMP_LO(%a1) 
+	movel	CMDREG1B(%a6),CMDREG1B(%a1) |set inst in frame to unimp
+	movel	CMDREG1B(%a6),%d0		|fix cmd1b to make it
+	andl	#0x03c30000,%d0		|work for cmd3b
+	bfextu	CMDREG1B(%a6){#13:#1},%d1	|extract bit 2
+	lsll	#5,%d1			
+	swap	%d1
+	orl	%d1,%d0			|put it in the right place
+	bfextu	CMDREG1B(%a6){#10:#3},%d1	|extract bit 3,4,5
+	lsll	#2,%d1
+	swap	%d1
+	orl	%d1,%d0			|put them in the right place
+	movel	%d0,CMDREG3B(%a1)		|in the busy frame
+|
+| Or in the FPSR from the emulation with the USER_FPSR on the stack.
+|
+	fmovel	%FPSR,%d0		
+	orl	%d0,USER_FPSR(%a6)
+	movel	USER_FPSR(%a6),FPSR_SHADOW(%a1) |set exc bits
+	orl	#sx_mask,E_BYTE(%a1)
+	bra	do_clean
+
+|
+| Frame is an unimp frame possible resulting from an fmove <ea>,fp0
+| that caused an exception
+|
+| a1 is modified to point into the new frame allowing fpsp equates
+| to be valid.
+|
+unimp_x:
+	cmpib	#UNIMP_40_SIZE-4,1(%a7)	|test for orig unimp frame
+	bnes	test_rev
+	leal	UNIMP_40_SIZE+LOCAL_SIZE(%a7),%a1
+	bras	unimp_con
+test_rev:
+	cmpib	#UNIMP_41_SIZE-4,1(%a7)	|test for rev unimp frame
+	bnel	fpsp_fmt_error		|if not $28 or $30
+	leal	UNIMP_41_SIZE+LOCAL_SIZE(%a7),%a1
+	
+unimp_con:
+|
+| Fix up the new unimp frame with entries from the old unimp frame
+|
+	movel	CMDREG1B(%a6),CMDREG1B(%a1) |set inst in frame to unimp
+|
+| Or in the FPSR from the emulation with the USER_FPSR on the stack.
+|
+	fmovel	%FPSR,%d0		
+	orl	%d0,USER_FPSR(%a6)
+	bra	do_clean
+
+|
+| Frame is idle, so check for exceptions reported through
+| USER_FPSR and set the unimp frame accordingly.  
+| A7 must be incremented to the point before the
+| idle fsave vector to the unimp vector.
+|
+	
+do_check:
+	addl	#4,%a7			|point A7 back to unimp frame
+|
+| Or in the FPSR from the emulation with the USER_FPSR on the stack.
+|
+	fmovel	%FPSR,%d0		
+	orl	%d0,USER_FPSR(%a6)
+|
+| On a busy frame, we must clear the nmnexc bits.
+|
+	cmpib	#BUSY_SIZE-4,1(%a7)	|check frame type
+	bnes	check_fr		|if busy, clr nmnexc
+	clrw	NMNEXC(%a6)		|clr nmnexc & nmcexc
+	btstb	#5,CMDREG1B(%a6)		|test for fmove out
+	bnes	frame_com
+	movel	USER_FPSR(%a6),FPSR_SHADOW(%a6) |set exc bits
+	orl	#sx_mask,E_BYTE(%a6)
+	bras	frame_com
+check_fr:
+	cmpb	#UNIMP_40_SIZE-4,1(%a7)
+	beqs	frame_com
+	clrw	NMNEXC(%a6)
+frame_com:
+	moveb	FPCR_ENABLE(%a6),%d0	|get fpcr enable byte
+	andb	FPSR_EXCEPT(%a6),%d0	|and in the fpsr exc byte
+	bfffo	%d0{#24:#8},%d1		|test for first set bit
+	leal	exc_tbl,%a0		|load jmp table address
+	subib	#24,%d1			|normalize bit offset to 0-8
+	movel	(%a0,%d1.w*4),%a0		|load routine address based
+|					;based on first enabled exc
+	jmp	(%a0)			|jump to routine
+|
+| Bsun is not possible in unimp or unsupp
+|
+bsun_exc:
+	bra	do_clean
+|
+| The typical work to be done to the unimp frame to report an 
+| exception is to set the E1/E3 byte and clr the U flag.
+| commonE1 does this for E1 exceptions, which are snan, 
+| operr, and dz.  commonE3 does this for E3 exceptions, which 
+| are inex2 and inex1, and also clears the E1 exception bit
+| left over from the unimp exception.
+|
+commonE1:
+	bsetb	#E1,E_BYTE(%a6)		|set E1 flag
+	bra	commonE			|go clean and exit
+
+commonE3:
+	tstb	UFLG_TMP(%a6)		|test flag for unsup/unimp state
+	bnes	unsE3
+uniE3:
+	bsetb	#E3,E_BYTE(%a6)		|set E3 flag
+	bclrb	#E1,E_BYTE(%a6)		|clr E1 from unimp
+	bra	commonE
+
+unsE3:
+	tstb	RES_FLG(%a6)
+	bnes	unsE3_0	
+unsE3_1:
+	bsetb	#E3,E_BYTE(%a6)		|set E3 flag
+unsE3_0:
+	bclrb	#E1,E_BYTE(%a6)		|clr E1 flag
+	movel	CMDREG1B(%a6),%d0
+	andl	#0x03c30000,%d0		|work for cmd3b
+	bfextu	CMDREG1B(%a6){#13:#1},%d1	|extract bit 2
+	lsll	#5,%d1			
+	swap	%d1
+	orl	%d1,%d0			|put it in the right place
+	bfextu	CMDREG1B(%a6){#10:#3},%d1	|extract bit 3,4,5
+	lsll	#2,%d1
+	swap	%d1
+	orl	%d1,%d0			|put them in the right place
+	movel	%d0,CMDREG3B(%a6)		|in the busy frame
+
+commonE:
+	bclrb	#UFLAG,T_BYTE(%a6)	|clr U flag from unimp
+	bra	do_clean		|go clean and exit
+|
+| No bits in the enable byte match existing exceptions.  Check for
+| the case of the ovfl exc without the ovfl enabled, but with
+| inex2 enabled.
+|
+no_match:
+	btstb	#inex2_bit,FPCR_ENABLE(%a6) |check for ovfl/inex2 case
+	beqs	no_exc			|if clear, exit
+	btstb	#ovfl_bit,FPSR_EXCEPT(%a6) |now check ovfl
+	beqs	no_exc			|if clear, exit
+	bras	ovfl_unfl		|go to unfl_ovfl to determine if
+|					;it is an unsupp or unimp exc
+	
+| No exceptions are to be reported.  If the instruction was 
+| unimplemented, no FPU restore is necessary.  If it was
+| unsupported, we must perform the restore.
+no_exc:
+	tstb	UFLG_TMP(%a6)	|test flag for unsupp/unimp state
+	beqs	uni_no_exc
+uns_no_exc:
+	tstb	RES_FLG(%a6)	|check if frestore is needed
+	bne	do_clean 	|if clear, no frestore needed
+uni_no_exc:
+	moveml	USER_DA(%a6),%d0-%d1/%a0-%a1
+	fmovemx USER_FP0(%a6),%fp0-%fp3
+	fmoveml USER_FPCR(%a6),%fpcr/%fpsr/%fpiar
+	unlk	%a6
+	bra	finish_up
+|
+| Unsupported Data Type Handler:
+| Ovfl:
+|   An fmoveout that results in an overflow is reported this way.
+| Unfl:
+|   An fmoveout that results in an underflow is reported this way.
+|
+| Unimplemented Instruction Handler:
+| Ovfl:
+|   Only scosh, setox, ssinh, stwotox, and scale can set overflow in 
+|   this manner.
+| Unfl:
+|   Stwotox, setox, and scale can set underflow in this manner.
+|   Any of the other Library Routines such that f(x)=x in which
+|   x is an extended denorm can report an underflow exception. 
+|   It is the responsibility of the exception-causing exception 
+|   to make sure that WBTEMP is correct.
+|
+|   The exceptional operand is in FP_SCR1.
+|
+ovfl_unfl:
+	tstb	UFLG_TMP(%a6)	|test flag for unsupp/unimp state
+	beqs	ofuf_con
+|
+| The caller was from an unsupported data type trap.  Test if the
+| caller set CU_ONLY.  If so, the exceptional operand is expected in
+| FPTEMP, rather than WBTEMP.
+|
+	tstb	CU_ONLY(%a6)		|test if inst is cu-only
+	beq	unsE3
+|	move.w	#$fe,CU_SAVEPC(%a6)
+	clrb	CU_SAVEPC(%a6)
+	bsetb	#E1,E_BYTE(%a6)		|set E1 exception flag
+	movew	ETEMP_EX(%a6),FPTEMP_EX(%a6)
+	movel	ETEMP_HI(%a6),FPTEMP_HI(%a6)
+	movel	ETEMP_LO(%a6),FPTEMP_LO(%a6)
+	bsetb	#fptemp15_bit,DTAG(%a6)	|set fpte15
+	bclrb	#UFLAG,T_BYTE(%a6)	|clr U flag from unimp
+	bra	do_clean		|go clean and exit
+
+ofuf_con:
+	moveb	(%a7),VER_TMP(%a6)	|save version number
+	cmpib	#BUSY_SIZE-4,1(%a7)	|check for busy frame
+	beqs	busy_fr			|if unimp, grow to busy
+	cmpib	#VER_40,(%a7)		|test for orig unimp frame
+	bnes	try_41			|if not, test for rev frame
+	moveql	#13,%d0			|need to zero 14 lwords
+	bras	ofuf_fin
+try_41:
+	cmpib	#VER_41,(%a7)		|test for rev unimp frame
+	bnel	fpsp_fmt_error		|if neither, exit with error
+	moveql	#11,%d0			|need to zero 12 lwords
+
+ofuf_fin:
+	clrl	(%a7)
+loop1:
+	clrl	-(%a7)			|clear and dec a7
+	dbra	%d0,loop1
+	moveb	VER_TMP(%a6),(%a7)
+	moveb	#BUSY_SIZE-4,1(%a7)		|write busy fmt word.
+busy_fr:
+	movel	FP_SCR1(%a6),WBTEMP_EX(%a6)	|write
+	movel	FP_SCR1+4(%a6),WBTEMP_HI(%a6)	|execptional op to
+	movel	FP_SCR1+8(%a6),WBTEMP_LO(%a6)	|wbtemp
+	bsetb	#E3,E_BYTE(%a6)			|set E3 flag
+	bclrb	#E1,E_BYTE(%a6)			|make sure E1 is clear
+	bclrb	#UFLAG,T_BYTE(%a6)		|clr U flag
+	movel	USER_FPSR(%a6),FPSR_SHADOW(%a6)
+	orl	#sx_mask,E_BYTE(%a6)
+	movel	CMDREG1B(%a6),%d0		|fix cmd1b to make it
+	andl	#0x03c30000,%d0		|work for cmd3b
+	bfextu	CMDREG1B(%a6){#13:#1},%d1	|extract bit 2
+	lsll	#5,%d1			
+	swap	%d1
+	orl	%d1,%d0			|put it in the right place
+	bfextu	CMDREG1B(%a6){#10:#3},%d1	|extract bit 3,4,5
+	lsll	#2,%d1
+	swap	%d1
+	orl	%d1,%d0			|put them in the right place
+	movel	%d0,CMDREG3B(%a6)		|in the busy frame
+
+|
+| Check if the frame to be restored is busy or unimp.
+|** NOTE *** Bug fix for errata (0d43b #3)
+| If the frame is unimp, we must create a busy frame to 
+| fix the bug with the nmnexc bits in cases in which they
+| are set by a previous instruction and not cleared by
+| the save. The frame will be unimp only if the final 
+| instruction in an emulation routine caused the exception
+| by doing an fmove <ea>,fp0.  The exception operand, in
+| internal format, is in fptemp.
+|
+do_clean:
+	cmpib	#UNIMP_40_SIZE-4,1(%a7)
+	bnes	do_con
+	moveql	#13,%d0			|in orig, need to zero 14 lwords
+	bras	do_build
+do_con:
+	cmpib	#UNIMP_41_SIZE-4,1(%a7)
+	bnes	do_restore		|frame must be busy
+	moveql	#11,%d0			|in rev, need to zero 12 lwords
+
+do_build:
+	moveb	(%a7),VER_TMP(%a6)
+	clrl	(%a7)
+loop2:
+	clrl	-(%a7)			|clear and dec a7
+	dbra	%d0,loop2
+|
+| Use a1 as pointer into new frame.  a6 is not correct if an unimp or
+| busy frame was created as the result of an exception on the final
+| instruction of an emulation routine.
+|
+| We need to set the nmcexc bits if the exception is E1. Otherwise,
+| the exc taken will be inex2.
+|
+	leal	BUSY_SIZE+LOCAL_SIZE(%a7),%a1	|init a1 for new frame
+	moveb	VER_TMP(%a6),(%a7)	|write busy fmt word
+	moveb	#BUSY_SIZE-4,1(%a7)
+	movel	FP_SCR1(%a6),WBTEMP_EX(%a1) 	|write
+	movel	FP_SCR1+4(%a6),WBTEMP_HI(%a1)	|exceptional op to
+	movel	FP_SCR1+8(%a6),WBTEMP_LO(%a1)	|wbtemp
+|	btst.b	#E1,E_BYTE(%a1)
+|	beq.b	do_restore
+	bfextu	USER_FPSR(%a6){#17:#4},%d0	|get snan/operr/ovfl/unfl bits
+	bfins	%d0,NMCEXC(%a1){#4:#4}	|and insert them in nmcexc
+	movel	USER_FPSR(%a6),FPSR_SHADOW(%a1) |set exc bits
+	orl	#sx_mask,E_BYTE(%a1)
+	
+do_restore:
+	moveml	USER_DA(%a6),%d0-%d1/%a0-%a1
+	fmovemx USER_FP0(%a6),%fp0-%fp3
+	fmoveml USER_FPCR(%a6),%fpcr/%fpsr/%fpiar
+	frestore (%a7)+
+	tstb	RES_FLG(%a6)	|RES_FLG indicates a "continuation" frame
+	beq	cont
+	bsr	bug1384
+cont:
+	unlk	%a6
+|
+| If trace mode enabled, then go to trace handler.  This handler 
+| cannot have any fp instructions.  If there are fp inst's and an 
+| exception has been restored into the machine then the exception 
+| will occur upon execution of the fp inst.  This is not desirable 
+| in the kernel (supervisor mode).  See MC68040 manual Section 9.3.8.
+|
+finish_up:
+	btstb	#7,(%a7)		|test T1 in SR
+	bnes	g_trace
+	btstb	#6,(%a7)		|test T0 in SR
+	bnes	g_trace
+	bral	fpsp_done
+|
+| Change integer stack to look like trace stack
+| The address of the instruction that caused the
+| exception is already in the integer stack (is
+| the same as the saved friar)
+|
+| If the current frame is already a 6-word stack then all
+| that needs to be done is to change the vector# to TRACE.
+| If the frame is only a 4-word stack (meaning we got here
+| on an Unsupported data type exception), then we need to grow
+| the stack an extra 2 words and get the FPIAR from the FPU.
+|
+g_trace:
+	bftst	EXC_VEC-4(%sp){#0:#4}
+	bne	g_easy
+
+	subw	#4,%sp		| make room
+	movel	4(%sp),(%sp)
+	movel	8(%sp),4(%sp)
+	subw	#BUSY_SIZE,%sp
+	fsave	(%sp)
+	fmovel	%fpiar,BUSY_SIZE+EXC_EA-4(%sp)
+	frestore (%sp)
+	addw	#BUSY_SIZE,%sp
+
+g_easy:
+	movew	#TRACE_VEC,EXC_VEC-4(%a7)
+	bral	real_trace
+|
+|  This is a work-around for hardware bug 1384.
+|
+bug1384:
+	link	%a5,#0
+	fsave	-(%sp)
+	cmpib	#0x41,(%sp)	| check for correct frame
+	beq	frame_41
+	bgt	nofix		| if more advanced mask, do nada
+
+frame_40:
+	tstb	1(%sp)		| check to see if idle
+	bne	notidle
+idle40:
+	clrl	(%sp)		| get rid of old fsave frame
+        movel  %d1,USER_D1(%a6)  | save d1
+	movew	#8,%d1		| place unimp frame instead
+loop40:	clrl	-(%sp)
+	dbra	%d1,loop40
+        movel  USER_D1(%a6),%d1  | restore d1
+	movel	#0x40280000,-(%sp)
+	frestore (%sp)+
+	unlk  	%a5	
+	rts
+
+frame_41:
+	tstb	1(%sp)		| check to see if idle
+	bne	notidle	
+idle41:
+	clrl	(%sp)		| get rid of old fsave frame
+        movel  %d1,USER_D1(%a6)  | save d1
+	movew	#10,%d1		| place unimp frame instead
+loop41:	clrl	-(%sp)
+	dbra	%d1,loop41
+        movel  USER_D1(%a6),%d1  | restore d1
+	movel	#0x41300000,-(%sp)
+	frestore (%sp)+
+	unlk	%a5	
+	rts
+
+notidle:
+	bclrb	#etemp15_bit,-40(%a5) 
+	frestore (%sp)+
+	unlk	%a5	
+	rts
+
+nofix:
+	frestore (%sp)+
+	unlk	%a5	
+	rts
+
+	|end
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/fpsp040/get_op.S linux/arch/m68k/fpsp040/get_op.S
--- v1.3.93/linux/arch/m68k/fpsp040/get_op.S	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/fpsp040/get_op.S	Sat Feb 24 22:58:43 1996
@@ -0,0 +1,676 @@
+|
+|	get_op.sa 3.6 5/19/92
+|
+|	get_op.sa 3.5 4/26/91
+|
+|  Description: This routine is called by the unsupported format/data
+| type exception handler ('unsupp' - vector 55) and the unimplemented
+| instruction exception handler ('unimp' - vector 11).  'get_op'
+| determines the opclass (0, 2, or 3) and branches to the
+| opclass handler routine.  See 68881/2 User's Manual table 4-11
+| for a description of the opclasses.
+|
+| For UNSUPPORTED data/format (exception vector 55) and for
+| UNIMPLEMENTED instructions (exception vector 11) the following
+| applies:
+|
+| - For unnormormalized numbers (opclass 0, 2, or 3) the
+| number(s) is normalized and the operand type tag is updated.
+|		
+| - For a packed number (opclass 2) the number is unpacked and the
+| operand type tag is updated.
+|
+| - For denormalized numbers (opclass 0 or 2) the number(s) is not
+| changed but passed to the next module.  The next module for
+| unimp is do_func, the next module for unsupp is res_func.
+|
+| For UNSUPPORTED data/format (exception vector 55) only the
+| following applies:
+|
+| - If there is a move out with a packed number (opclass 3) the
+| number is packed and written to user memory.  For the other
+| opclasses the number(s) are written back to the fsave stack
+| and the instruction is then restored back into the '040.  The
+| '040 is then able to complete the instruction.
+|
+| For example:
+| fadd.x fpm,fpn where the fpm contains an unnormalized number.
+| The '040 takes an unsupported data trap and gets to this
+| routine.  The number is normalized, put back on the stack and
+| then an frestore is done to restore the instruction back into
+| the '040.  The '040 then re-executes the fadd.x fpm,fpn with
+| a normalized number in the source and the instruction is
+| successful.
+|		
+| Next consider if in the process of normalizing the un-
+| normalized number it becomes a denormalized number.  The
+| routine which converts the unnorm to a norm (called mk_norm)
+| detects this and tags the number as a denorm.  The routine
+| res_func sees the denorm tag and converts the denorm to a
+| norm.  The instruction is then restored back into the '040
+| which re_executess the instruction.
+|
+|
+|		Copyright (C) Motorola, Inc. 1990
+|			All Rights Reserved
+|
+|	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA 
+|	The copyright notice above does not evidence any  
+|	actual or intended publication of such source code.
+
+GET_OP:    |idnt    2,1 | Motorola 040 Floating Point Software Package
+
+	|section	8
+
+	.include "fpsp.h"
+
+	.global	PIRN,PIRZRM,PIRP
+	.global	SMALRN,SMALRZRM,SMALRP
+	.global	BIGRN,BIGRZRM,BIGRP
+
+PIRN:
+	.long 0x40000000,0xc90fdaa2,0x2168c235    |pi
+PIRZRM:
+	.long 0x40000000,0xc90fdaa2,0x2168c234    |pi
+PIRP:
+	.long 0x40000000,0xc90fdaa2,0x2168c235    |pi
+
+|round to nearest
+SMALRN:
+	.long 0x3ffd0000,0x9a209a84,0xfbcff798    |log10(2)
+	.long 0x40000000,0xadf85458,0xa2bb4a9a    |e
+	.long 0x3fff0000,0xb8aa3b29,0x5c17f0bc    |log2(e)
+	.long 0x3ffd0000,0xde5bd8a9,0x37287195    |log10(e)
+	.long 0x00000000,0x00000000,0x00000000    |0.0
+| round to zero;round to negative infinity
+SMALRZRM:
+	.long 0x3ffd0000,0x9a209a84,0xfbcff798    |log10(2)
+	.long 0x40000000,0xadf85458,0xa2bb4a9a    |e
+	.long 0x3fff0000,0xb8aa3b29,0x5c17f0bb    |log2(e)
+	.long 0x3ffd0000,0xde5bd8a9,0x37287195    |log10(e)
+	.long 0x00000000,0x00000000,0x00000000    |0.0
+| round to positive infinity
+SMALRP:
+	.long 0x3ffd0000,0x9a209a84,0xfbcff799    |log10(2)
+	.long 0x40000000,0xadf85458,0xa2bb4a9b    |e
+	.long 0x3fff0000,0xb8aa3b29,0x5c17f0bc    |log2(e)
+	.long 0x3ffd0000,0xde5bd8a9,0x37287195    |log10(e)
+	.long 0x00000000,0x00000000,0x00000000    |0.0
+
+|round to nearest
+BIGRN:
+	.long 0x3ffe0000,0xb17217f7,0xd1cf79ac    |ln(2)
+	.long 0x40000000,0x935d8ddd,0xaaa8ac17    |ln(10)
+	.long 0x3fff0000,0x80000000,0x00000000    |10 ^ 0
+
+	.global	PTENRN
+PTENRN:
+	.long 0x40020000,0xA0000000,0x00000000    |10 ^ 1
+	.long 0x40050000,0xC8000000,0x00000000    |10 ^ 2
+	.long 0x400C0000,0x9C400000,0x00000000    |10 ^ 4
+	.long 0x40190000,0xBEBC2000,0x00000000    |10 ^ 8
+	.long 0x40340000,0x8E1BC9BF,0x04000000    |10 ^ 16
+	.long 0x40690000,0x9DC5ADA8,0x2B70B59E    |10 ^ 32
+	.long 0x40D30000,0xC2781F49,0xFFCFA6D5    |10 ^ 64
+	.long 0x41A80000,0x93BA47C9,0x80E98CE0    |10 ^ 128
+	.long 0x43510000,0xAA7EEBFB,0x9DF9DE8E    |10 ^ 256
+	.long 0x46A30000,0xE319A0AE,0xA60E91C7    |10 ^ 512
+	.long 0x4D480000,0xC9767586,0x81750C17    |10 ^ 1024
+	.long 0x5A920000,0x9E8B3B5D,0xC53D5DE5    |10 ^ 2048
+	.long 0x75250000,0xC4605202,0x8A20979B    |10 ^ 4096
+|round to minus infinity
+BIGRZRM:
+	.long 0x3ffe0000,0xb17217f7,0xd1cf79ab    |ln(2)
+	.long 0x40000000,0x935d8ddd,0xaaa8ac16    |ln(10)
+	.long 0x3fff0000,0x80000000,0x00000000    |10 ^ 0
+
+	.global	PTENRM
+PTENRM:
+	.long 0x40020000,0xA0000000,0x00000000    |10 ^ 1
+	.long 0x40050000,0xC8000000,0x00000000    |10 ^ 2
+	.long 0x400C0000,0x9C400000,0x00000000    |10 ^ 4
+	.long 0x40190000,0xBEBC2000,0x00000000    |10 ^ 8
+	.long 0x40340000,0x8E1BC9BF,0x04000000    |10 ^ 16
+	.long 0x40690000,0x9DC5ADA8,0x2B70B59D    |10 ^ 32
+	.long 0x40D30000,0xC2781F49,0xFFCFA6D5    |10 ^ 64
+	.long 0x41A80000,0x93BA47C9,0x80E98CDF    |10 ^ 128
+	.long 0x43510000,0xAA7EEBFB,0x9DF9DE8D    |10 ^ 256
+	.long 0x46A30000,0xE319A0AE,0xA60E91C6    |10 ^ 512
+	.long 0x4D480000,0xC9767586,0x81750C17    |10 ^ 1024
+	.long 0x5A920000,0x9E8B3B5D,0xC53D5DE5    |10 ^ 2048
+	.long 0x75250000,0xC4605202,0x8A20979A    |10 ^ 4096
+|round to positive infinity
+BIGRP:
+	.long 0x3ffe0000,0xb17217f7,0xd1cf79ac    |ln(2)
+	.long 0x40000000,0x935d8ddd,0xaaa8ac17    |ln(10)
+	.long 0x3fff0000,0x80000000,0x00000000    |10 ^ 0
+
+	.global	PTENRP
+PTENRP:
+	.long 0x40020000,0xA0000000,0x00000000    |10 ^ 1
+	.long 0x40050000,0xC8000000,0x00000000    |10 ^ 2
+	.long 0x400C0000,0x9C400000,0x00000000    |10 ^ 4
+	.long 0x40190000,0xBEBC2000,0x00000000    |10 ^ 8
+	.long 0x40340000,0x8E1BC9BF,0x04000000    |10 ^ 16
+	.long 0x40690000,0x9DC5ADA8,0x2B70B59E    |10 ^ 32
+	.long 0x40D30000,0xC2781F49,0xFFCFA6D6    |10 ^ 64
+	.long 0x41A80000,0x93BA47C9,0x80E98CE0    |10 ^ 128
+	.long 0x43510000,0xAA7EEBFB,0x9DF9DE8E    |10 ^ 256
+	.long 0x46A30000,0xE319A0AE,0xA60E91C7    |10 ^ 512
+	.long 0x4D480000,0xC9767586,0x81750C18    |10 ^ 1024
+	.long 0x5A920000,0x9E8B3B5D,0xC53D5DE6    |10 ^ 2048
+	.long 0x75250000,0xC4605202,0x8A20979B    |10 ^ 4096
+
+	|xref	nrm_zero
+	|xref	decbin
+	|xref	round
+
+	.global    get_op
+	.global    uns_getop
+	.global    uni_getop
+get_op:
+	clrb	DY_MO_FLG(%a6)
+	tstb	UFLG_TMP(%a6)	|test flag for unsupp/unimp state
+	beqs	uni_getop
+
+uns_getop:
+	btstb	#direction_bit,CMDREG1B(%a6)
+	bne	opclass3	|branch if a fmove out (any kind)
+	btstb	#6,CMDREG1B(%a6)
+	beqs	uns_notpacked
+
+	bfextu	CMDREG1B(%a6){#3:#3},%d0
+	cmpb	#3,%d0
+	beq	pack_source	|check for a packed src op, branch if so
+uns_notpacked:
+	bsr	chk_dy_mo	|set the dyadic/monadic flag
+	tstb	DY_MO_FLG(%a6)
+	beqs	src_op_ck	|if monadic, go check src op
+|				;else, check dst op (fall through)
+
+	btstb	#7,DTAG(%a6)
+	beqs	src_op_ck	|if dst op is norm, check src op
+	bras	dst_ex_dnrm	|else, handle destination unnorm/dnrm
+
+uni_getop:
+	bfextu	CMDREG1B(%a6){#0:#6},%d0 |get opclass and src fields
+	cmpil	#0x17,%d0		|if op class and size fields are $17, 
+|				;it is FMOVECR; if not, continue
+|
+| If the instruction is fmovecr, exit get_op.  It is handled
+| in do_func and smovecr.sa.
+|
+	bne	not_fmovecr	|handle fmovecr as an unimplemented inst
+	rts
+
+not_fmovecr:
+	btstb	#E1,E_BYTE(%a6)	|if set, there is a packed operand
+	bne	pack_source	|check for packed src op, branch if so
+
+| The following lines of are coded to optimize on normalized operands
+	moveb	STAG(%a6),%d0
+	orb	DTAG(%a6),%d0	|check if either of STAG/DTAG msb set
+	bmis	dest_op_ck	|if so, some op needs to be fixed
+	rts
+
+dest_op_ck:
+	btstb	#7,DTAG(%a6)	|check for unsupported data types in
+	beqs	src_op_ck	|the destination, if not, check src op
+	bsr	chk_dy_mo	|set dyadic/monadic flag
+	tstb	DY_MO_FLG(%a6)	|
+	beqs	src_op_ck	|if monadic, check src op
+|
+| At this point, destination has an extended denorm or unnorm.
+|
+dst_ex_dnrm:
+	movew	FPTEMP_EX(%a6),%d0 |get destination exponent
+	andiw	#0x7fff,%d0	|mask sign, check if exp = 0000
+	beqs	src_op_ck	|if denorm then check source op.
+|				;denorms are taken care of in res_func 
+|				;(unsupp) or do_func (unimp)
+|				;else unnorm fall through
+	leal	FPTEMP(%a6),%a0	|point a0 to dop - used in mk_norm
+	bsr	mk_norm		|go normalize - mk_norm returns:
+|				;L_SCR1{7:5} = operand tag 
+|				;	(000 = norm, 100 = denorm)
+|				;L_SCR1{4} = fpte15 or ete15 
+|				;	0 = exp >  $3fff
+|				;	1 = exp <= $3fff
+|				;and puts the normalized num back 
+|				;on the fsave stack
+|
+	moveb L_SCR1(%a6),DTAG(%a6) |write the new tag & fpte15 
+|				;to the fsave stack and fall 
+|				;through to check source operand
+|
+src_op_ck:
+	btstb	#7,STAG(%a6)
+	beq	end_getop	|check for unsupported data types on the
+|				;source operand
+	btstb	#5,STAG(%a6)
+	bnes	src_sd_dnrm	|if bit 5 set, handle sgl/dbl denorms
+|
+| At this point only unnorms or extended denorms are possible.
+|
+src_ex_dnrm:
+	movew	ETEMP_EX(%a6),%d0 |get source exponent
+	andiw	#0x7fff,%d0	|mask sign, check if exp = 0000
+	beq	end_getop	|if denorm then exit, denorms are 
+|				;handled in do_func
+	leal	ETEMP(%a6),%a0	|point a0 to sop - used in mk_norm
+	bsr	mk_norm		|go normalize - mk_norm returns:
+|				;L_SCR1{7:5} = operand tag 
+|				;	(000 = norm, 100 = denorm)
+|				;L_SCR1{4} = fpte15 or ete15 
+|				;	0 = exp >  $3fff
+|				;	1 = exp <= $3fff
+|				;and puts the normalized num back 
+|				;on the fsave stack
+|
+	moveb	L_SCR1(%a6),STAG(%a6) |write the new tag & ete15 
+	rts			|end_getop
+
+|
+| At this point, only single or double denorms are possible.
+| If the inst is not fmove, normalize the source.  If it is,
+| do nothing to the input.
+|
+src_sd_dnrm:
+	btstb	#4,CMDREG1B(%a6)	|differentiate between sgl/dbl denorm
+	bnes	is_double
+is_single:
+	movew	#0x3f81,%d1	|write bias for sgl denorm
+	bras	common		|goto the common code
+is_double:
+	movew	#0x3c01,%d1	|write the bias for a dbl denorm
+common:
+	btstb	#sign_bit,ETEMP_EX(%a6) |grab sign bit of mantissa
+	beqs	pos	
+	bset	#15,%d1		|set sign bit because it is negative
+pos:
+	movew	%d1,ETEMP_EX(%a6)
+|				;put exponent on stack
+
+	movew	CMDREG1B(%a6),%d1
+	andw	#0xe3ff,%d1	|clear out source specifier
+	orw	#0x0800,%d1	|set source specifier to extended prec
+	movew	%d1,CMDREG1B(%a6)	|write back to the command word in stack
+|				;this is needed to fix unsupp data stack
+	leal	ETEMP(%a6),%a0	|point a0 to sop
+	
+	bsr	mk_norm		|convert sgl/dbl denorm to norm
+	moveb	L_SCR1(%a6),STAG(%a6) |put tag into source tag reg - d0
+	rts			|end_getop
+|
+| At this point, the source is definitely packed, whether
+| instruction is dyadic or monadic is still unknown
+|
+pack_source:
+	movel	FPTEMP_LO(%a6),ETEMP(%a6)	|write ms part of packed 
+|				;number to etemp slot
+	bsr	chk_dy_mo	|set dyadic/monadic flag
+	bsr	unpack
+
+	tstb	DY_MO_FLG(%a6)
+	beqs	end_getop	|if monadic, exit
+|				;else, fix FPTEMP
+pack_dya:
+	bfextu	CMDREG1B(%a6){#6:#3},%d0 |extract dest fp reg
+	movel	#7,%d1
+	subl	%d0,%d1
+	clrl	%d0
+	bsetl	%d1,%d0		|set up d0 as a dynamic register mask
+	fmovemx %d0,FPTEMP(%a6)	|write to FPTEMP
+
+	btstb	#7,DTAG(%a6)	|check dest tag for unnorm or denorm
+	bne	dst_ex_dnrm	|else, handle the unnorm or ext denorm
+|
+| Dest is not denormalized.  Check for norm, and set fpte15 
+| accordingly.
+|
+	moveb	DTAG(%a6),%d0
+	andib	#0xf0,%d0		|strip to only dtag:fpte15
+	tstb	%d0		|check for normalized value
+	bnes	end_getop	|if inf/nan/zero leave get_op
+	movew	FPTEMP_EX(%a6),%d0
+	andiw	#0x7fff,%d0
+	cmpiw	#0x3fff,%d0	|check if fpte15 needs setting
+	bges	end_getop	|if >= $3fff, leave fpte15=0
+	orb	#0x10,DTAG(%a6)
+	bras	end_getop
+
+|
+| At this point, it is either an fmoveout packed, unnorm or denorm
+|
+opclass3:
+	clrb	DY_MO_FLG(%a6)	|set dyadic/monadic flag to monadic
+	bfextu	CMDREG1B(%a6){#4:#2},%d0
+	cmpib	#3,%d0
+	bne	src_ex_dnrm	|if not equal, must be unnorm or denorm
+|				;else it is a packed move out
+|				;exit
+end_getop:
+	rts
+
+|
+| Sets the DY_MO_FLG correctly. This is used only on if it is an
+| unuspported data type exception.  Set if dyadic.
+|
+chk_dy_mo:
+	movew	CMDREG1B(%a6),%d0	
+	btstl	#5,%d0		|testing extension command word
+	beqs	set_mon		|if bit 5 = 0 then monadic
+	btstl	#4,%d0		|know that bit 5 = 1
+	beqs	set_dya		|if bit 4 = 0 then dyadic
+	andiw	#0x007f,%d0	|get rid of all but extension bits {6:0}
+	cmpiw 	#0x0038,%d0	|if extension = $38 then fcmp (dyadic)
+	bnes	set_mon
+set_dya:
+	st	DY_MO_FLG(%a6)	|set the inst flag type to dyadic
+	rts
+set_mon:
+	clrb	DY_MO_FLG(%a6)	|set the inst flag type to monadic
+	rts
+|
+|	MK_NORM
+|
+| Normalizes unnormalized numbers, sets tag to norm or denorm, sets unfl
+| exception if denorm.
+|
+| CASE opclass 0x0 unsupp
+|	mk_norm till msb set
+|	set tag = norm
+|
+| CASE opclass 0x0 unimp
+|	mk_norm till msb set or exp = 0
+|	if integer bit = 0
+|	   tag = denorm
+|	else
+|	   tag = norm
+|
+| CASE opclass 011 unsupp
+|	mk_norm till msb set or exp = 0
+|	if integer bit = 0
+|	   tag = denorm
+|	   set unfl_nmcexe = 1
+|	else
+|	   tag = norm
+|
+| if exp <= $3fff
+|   set ete15 or fpte15 = 1
+| else set ete15 or fpte15 = 0
+
+| input:
+|	a0 = points to operand to be normalized
+| output:
+|	L_SCR1{7:5} = operand tag (000 = norm, 100 = denorm)
+|	L_SCR1{4}   = fpte15 or ete15 (0 = exp > $3fff, 1 = exp <=$3fff)
+|	the normalized operand is placed back on the fsave stack
+mk_norm:	
+	clrl	L_SCR1(%a6)
+	bclrb	#sign_bit,LOCAL_EX(%a0)
+	sne	LOCAL_SGN(%a0)	|transform into internal extended format
+
+	cmpib	#0x2c,1+EXC_VEC(%a6) |check if unimp
+	bnes	uns_data	|branch if unsupp
+	bsr	uni_inst	|call if unimp (opclass 0x0)
+	bras	reload
+uns_data:
+	btstb	#direction_bit,CMDREG1B(%a6) |check transfer direction
+	bnes	bit_set		|branch if set (opclass 011)
+	bsr	uns_opx		|call if opclass 0x0
+	bras	reload
+bit_set:
+	bsr	uns_op3		|opclass 011
+reload:
+	cmpw	#0x3fff,LOCAL_EX(%a0) |if exp > $3fff
+	bgts	end_mk		|   fpte15/ete15 already set to 0
+	bsetb	#4,L_SCR1(%a6)	|else set fpte15/ete15 to 1
+|				;calling routine actually sets the 
+|				;value on the stack (along with the 
+|				;tag), since this routine doesn't 
+|				;know if it should set ete15 or fpte15
+|				;ie, it doesn't know if this is the 
+|				;src op or dest op.
+end_mk:
+	bfclr	LOCAL_SGN(%a0){#0:#8}
+	beqs	end_mk_pos
+	bsetb	#sign_bit,LOCAL_EX(%a0) |convert back to IEEE format
+end_mk_pos:
+	rts
+|
+|     CASE opclass 011 unsupp
+|
+uns_op3:
+	bsr	nrm_zero	|normalize till msb = 1 or exp = zero
+	btstb	#7,LOCAL_HI(%a0)	|if msb = 1
+	bnes	no_unfl		|then branch
+set_unfl:
+	orw	#dnrm_tag,L_SCR1(%a6) |set denorm tag
+	bsetb	#unfl_bit,FPSR_EXCEPT(%a6) |set unfl exception bit
+no_unfl:
+	rts
+|
+|     CASE opclass 0x0 unsupp
+|
+uns_opx:
+	bsr	nrm_zero	|normalize the number
+	btstb	#7,LOCAL_HI(%a0)	|check if integer bit (j-bit) is set 
+	beqs	uns_den		|if clear then now have a denorm
+uns_nrm:
+	orb	#norm_tag,L_SCR1(%a6) |set tag to norm
+	rts
+uns_den:
+	orb	#dnrm_tag,L_SCR1(%a6) |set tag to denorm
+	rts
+|
+|     CASE opclass 0x0 unimp
+|
+uni_inst:
+	bsr	nrm_zero
+	btstb	#7,LOCAL_HI(%a0)	|check if integer bit (j-bit) is set 
+	beqs	uni_den		|if clear then now have a denorm
+uni_nrm:
+	orb	#norm_tag,L_SCR1(%a6) |set tag to norm
+	rts
+uni_den:
+	orb	#dnrm_tag,L_SCR1(%a6) |set tag to denorm
+	rts
+
+|
+|	Decimal to binary conversion
+|
+| Special cases of inf and NaNs are completed outside of decbin.  
+| If the input is an snan, the snan bit is not set.
+| 
+| input:
+|	ETEMP(a6)	- points to packed decimal string in memory
+| output:
+|	fp0	- contains packed string converted to extended precision
+|	ETEMP	- same as fp0
+unpack:
+	movew	CMDREG1B(%a6),%d0	|examine command word, looking for fmove's
+	andw	#0x3b,%d0
+	beq	move_unpack	|special handling for fmove: must set FPSR_CC
+
+	movew	ETEMP(%a6),%d0	|get word with inf information
+	bfextu	%d0{#20:#12},%d1	|get exponent into d1
+	cmpiw	#0x0fff,%d1	|test for inf or NaN
+	bnes	try_zero	|if not equal, it is not special
+	bfextu	%d0{#17:#3},%d1	|get SE and y bits into d1
+	cmpiw	#7,%d1		|SE and y bits must be on for special
+	bnes	try_zero	|if not on, it is not special
+|input is of the special cases of inf and NaN
+	tstl	ETEMP_HI(%a6)	|check ms mantissa
+	bnes	fix_nan		|if non-zero, it is a NaN
+	tstl	ETEMP_LO(%a6)	|check ls mantissa
+	bnes	fix_nan		|if non-zero, it is a NaN
+	bra	finish		|special already on stack
+fix_nan:
+	btstb	#signan_bit,ETEMP_HI(%a6) |test for snan
+	bne	finish
+	orl	#snaniop_mask,USER_FPSR(%a6) |always set snan if it is so
+	bra	finish
+try_zero:
+	movew	ETEMP_EX+2(%a6),%d0 |get word 4
+	andiw	#0x000f,%d0	|clear all but last ni(y)bble
+	tstw	%d0		|check for zero.
+	bne	not_spec
+	tstl	ETEMP_HI(%a6)	|check words 3 and 2
+	bne	not_spec
+	tstl	ETEMP_LO(%a6)	|check words 1 and 0
+	bne	not_spec
+	tstl	ETEMP(%a6)	|test sign of the zero
+	bges	pos_zero
+	movel	#0x80000000,ETEMP(%a6) |write neg zero to etemp
+	clrl	ETEMP_HI(%a6)
+	clrl	ETEMP_LO(%a6)
+	bra	finish
+pos_zero:
+	clrl	ETEMP(%a6)
+	clrl	ETEMP_HI(%a6)
+	clrl	ETEMP_LO(%a6)
+	bra	finish
+
+not_spec:
+	fmovemx %fp0-%fp1,-(%a7)	|save fp0 - decbin returns in it
+	bsr	decbin
+	fmovex %fp0,ETEMP(%a6)	|put the unpacked sop in the fsave stack
+	fmovemx (%a7)+,%fp0-%fp1
+	fmovel	#0,%FPSR		|clr fpsr from decbin
+	bra	finish
+
+|
+| Special handling for packed move in:  Same results as all other
+| packed cases, but we must set the FPSR condition codes properly.
+|
+move_unpack:
+	movew	ETEMP(%a6),%d0	|get word with inf information
+	bfextu	%d0{#20:#12},%d1	|get exponent into d1
+	cmpiw	#0x0fff,%d1	|test for inf or NaN
+	bnes	mtry_zero	|if not equal, it is not special
+	bfextu	%d0{#17:#3},%d1	|get SE and y bits into d1
+	cmpiw	#7,%d1		|SE and y bits must be on for special
+	bnes	mtry_zero	|if not on, it is not special
+|input is of the special cases of inf and NaN
+	tstl	ETEMP_HI(%a6)	|check ms mantissa
+	bnes	mfix_nan		|if non-zero, it is a NaN
+	tstl	ETEMP_LO(%a6)	|check ls mantissa
+	bnes	mfix_nan		|if non-zero, it is a NaN
+|input is inf
+	orl	#inf_mask,USER_FPSR(%a6) |set I bit
+	tstl	ETEMP(%a6)	|check sign
+	bge	finish
+	orl	#neg_mask,USER_FPSR(%a6) |set N bit
+	bra	finish		|special already on stack
+mfix_nan:
+	orl	#nan_mask,USER_FPSR(%a6) |set NaN bit
+	moveb	#nan_tag,STAG(%a6)	|set stag to NaN
+	btstb	#signan_bit,ETEMP_HI(%a6) |test for snan
+	bnes	mn_snan
+	orl	#snaniop_mask,USER_FPSR(%a6) |set snan bit
+	btstb	#snan_bit,FPCR_ENABLE(%a6) |test for snan enabled
+	bnes	mn_snan
+	bsetb	#signan_bit,ETEMP_HI(%a6) |force snans to qnans
+mn_snan:
+	tstl	ETEMP(%a6)	|check for sign
+	bge	finish		|if clr, go on
+	orl	#neg_mask,USER_FPSR(%a6) |set N bit
+	bra	finish
+
+mtry_zero:
+	movew	ETEMP_EX+2(%a6),%d0 |get word 4
+	andiw	#0x000f,%d0	|clear all but last ni(y)bble
+	tstw	%d0		|check for zero.
+	bnes	mnot_spec
+	tstl	ETEMP_HI(%a6)	|check words 3 and 2
+	bnes	mnot_spec
+	tstl	ETEMP_LO(%a6)	|check words 1 and 0
+	bnes	mnot_spec
+	tstl	ETEMP(%a6)	|test sign of the zero
+	bges	mpos_zero
+	orl	#neg_mask+z_mask,USER_FPSR(%a6) |set N and Z
+	movel	#0x80000000,ETEMP(%a6) |write neg zero to etemp
+	clrl	ETEMP_HI(%a6)
+	clrl	ETEMP_LO(%a6)
+	bras	finish
+mpos_zero:
+	orl	#z_mask,USER_FPSR(%a6) |set Z
+	clrl	ETEMP(%a6)
+	clrl	ETEMP_HI(%a6)
+	clrl	ETEMP_LO(%a6)
+	bras	finish
+
+mnot_spec:
+	fmovemx %fp0-%fp1,-(%a7)	|save fp0 ,fp1 - decbin returns in fp0
+	bsr	decbin
+	fmovex %fp0,ETEMP(%a6)
+|				;put the unpacked sop in the fsave stack
+	fmovemx (%a7)+,%fp0-%fp1
+
+finish:
+	movew	CMDREG1B(%a6),%d0	|get the command word
+	andw	#0xfbff,%d0	|change the source specifier field to 
+|				;extended (was packed).
+	movew	%d0,CMDREG1B(%a6)	|write command word back to fsave stack
+|				;we need to do this so the 040 will 
+|				;re-execute the inst. without taking 
+|				;another packed trap.
+
+fix_stag:
+|Converted result is now in etemp on fsave stack, now set the source 
+|tag (stag) 
+|	if (ete =$7fff) then INF or NAN
+|		if (etemp = $x.0----0) then
+|			stag = INF
+|		else
+|			stag = NAN
+|	else
+|		if (ete = $0000) then
+|			stag = ZERO
+|		else
+|			stag = NORM
+|
+| Note also that the etemp_15 bit (just right of the stag) must
+| be set accordingly.  
+|
+	movew		ETEMP_EX(%a6),%d1
+	andiw		#0x7fff,%d1   |strip sign
+	cmpw  		#0x7fff,%d1
+	bnes  		z_or_nrm
+	movel		ETEMP_HI(%a6),%d1
+	bnes		is_nan
+	movel		ETEMP_LO(%a6),%d1
+	bnes		is_nan
+is_inf:
+	moveb		#0x40,STAG(%a6)
+	movel		#0x40,%d0
+	rts
+is_nan:
+	moveb		#0x60,STAG(%a6)
+	movel		#0x60,%d0
+	rts
+z_or_nrm:
+	tstw		%d1  
+	bnes		is_nrm
+is_zro:
+| For a zero, set etemp_15
+	moveb		#0x30,STAG(%a6)
+	movel		#0x20,%d0
+	rts
+is_nrm:
+| For a norm, check if the exp <= $3fff; if so, set etemp_15
+	cmpiw		#0x3fff,%d1
+	bles		set_bit15
+	moveb		#0,STAG(%a6)
+	bras		end_is_nrm
+set_bit15:
+	moveb		#0x10,STAG(%a6)
+end_is_nrm:
+	movel		#0,%d0
+end_fix:
+	rts
+ 
+end_get:
+	rts
+	|end
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/fpsp040/kernel_ex.S linux/arch/m68k/fpsp040/kernel_ex.S
--- v1.3.93/linux/arch/m68k/fpsp040/kernel_ex.S	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/fpsp040/kernel_ex.S	Sat Feb 24 22:58:43 1996
@@ -0,0 +1,494 @@
+|
+|	kernel_ex.sa 3.3 12/19/90 
+|
+| This file contains routines to force exception status in the 
+| fpu for exceptional cases detected or reported within the
+| transcendental functions.  Typically, the t_xx routine will
+| set the appropriate bits in the USER_FPSR word on the stack.
+| The bits are tested in gen_except.sa to determine if an exceptional
+| situation needs to be created on return from the FPSP. 
+|
+
+|		Copyright (C) Motorola, Inc. 1990
+|			All Rights Reserved
+|
+|	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA 
+|	The copyright notice above does not evidence any  
+|	actual or intended publication of such source code.
+
+KERNEL_EX:    |idnt    2,1 | Motorola 040 Floating Point Software Package
+
+	|section    8
+
+	.include "fpsp.h"
+
+mns_inf:  .long 0xffff0000,0x00000000,0x00000000
+pls_inf:  .long 0x7fff0000,0x00000000,0x00000000
+nan:      .long 0x7fff0000,0xffffffff,0xffffffff
+huge:     .long 0x7ffe0000,0xffffffff,0xffffffff
+
+	|xref	  ovf_r_k
+	|xref	  unf_sub
+	|xref	  nrm_set
+
+	.global   	  t_dz
+	.global      t_dz2
+	.global      t_operr
+	.global      t_unfl
+	.global      t_ovfl
+	.global      t_ovfl2
+	.global      t_inx2
+	.global	  t_frcinx
+	.global	  t_extdnrm
+	.global	  t_resdnrm
+	.global	  dst_nan
+	.global	  src_nan
+|
+|	DZ exception
+|
+|
+|	if dz trap disabled
+|		store properly signed inf (use sign of etemp) into fp0
+|		set FPSR exception status dz bit, condition code 
+|		inf bit, and accrued dz bit
+|		return
+|		frestore the frame into the machine (done by unimp_hd)
+|
+|	else dz trap enabled
+|		set exception status bit & accrued bits in FPSR
+|		set flag to disable sto_res from corrupting fp register
+|		return
+|		frestore the frame into the machine (done by unimp_hd)
+|
+| t_dz2 is used by monadic functions such as flogn (from do_func).
+| t_dz is used by monadic functions such as satanh (from the 
+| transcendental function).
+|
+t_dz2:
+	bsetb	#neg_bit,FPSR_CC(%a6)	|set neg bit in FPSR
+	fmovel	#0,%FPSR			|clr status bits (Z set)
+	btstb	#dz_bit,FPCR_ENABLE(%a6)	|test FPCR for dz exc enabled
+	bnes	dz_ena_end
+	bras	m_inf			|flogx always returns -inf
+t_dz:
+	fmovel	#0,%FPSR			|clr status bits (Z set)
+	btstb	#dz_bit,FPCR_ENABLE(%a6)	|test FPCR for dz exc enabled
+	bnes	dz_ena
+|
+|	dz disabled
+|
+	btstb	#sign_bit,ETEMP_EX(%a6)	|check sign for neg or pos
+	beqs	p_inf			|branch if pos sign
+
+m_inf:
+	fmovemx mns_inf,%fp0-%fp0		|load -inf
+	bsetb	#neg_bit,FPSR_CC(%a6)	|set neg bit in FPSR
+	bras	set_fpsr
+p_inf:
+	fmovemx pls_inf,%fp0-%fp0		|load +inf
+set_fpsr:
+	orl	#dzinf_mask,USER_FPSR(%a6) |set I,DZ,ADZ
+	rts
+|
+|	dz enabled
+|
+dz_ena:
+	btstb	#sign_bit,ETEMP_EX(%a6)	|check sign for neg or pos
+	beqs	dz_ena_end
+	bsetb	#neg_bit,FPSR_CC(%a6)	|set neg bit in FPSR
+dz_ena_end:
+	orl	#dzinf_mask,USER_FPSR(%a6) |set I,DZ,ADZ
+	st	STORE_FLG(%a6)
+	rts
+|
+|	OPERR exception
+|
+|	if (operr trap disabled)
+|		set FPSR exception status operr bit, condition code 
+|		nan bit; Store default NAN into fp0
+|		frestore the frame into the machine (done by unimp_hd)
+|	
+|	else (operr trap enabled)
+|		set FPSR exception status operr bit, accrued operr bit
+|		set flag to disable sto_res from corrupting fp register
+|		frestore the frame into the machine (done by unimp_hd)
+|
+t_operr:
+	orl	#opnan_mask,USER_FPSR(%a6) |set NaN, OPERR, AIOP
+
+	btstb	#operr_bit,FPCR_ENABLE(%a6) |test FPCR for operr enabled
+	bnes	op_ena
+
+	fmovemx nan,%fp0-%fp0		|load default nan
+	rts
+op_ena:
+	st	STORE_FLG(%a6)		|do not corrupt destination
+	rts
+
+|
+|	t_unfl --- UNFL exception
+|
+| This entry point is used by all routines requiring unfl, inex2,
+| aunfl, and ainex to be set on exit.
+|
+| On entry, a0 points to the exceptional operand.  The final exceptional
+| operand is built in FP_SCR1 and only the sign from the original operand
+| is used.
+|
+t_unfl:
+	clrl	FP_SCR1(%a6)		|set exceptional operand to zero
+	clrl	FP_SCR1+4(%a6)
+	clrl	FP_SCR1+8(%a6)
+	tstb	(%a0)			|extract sign from caller's exop
+	bpls	unfl_signok
+	bset	#sign_bit,FP_SCR1(%a6)
+unfl_signok:
+	leal	FP_SCR1(%a6),%a0
+	orl	#unfinx_mask,USER_FPSR(%a6)
+|					;set UNFL, INEX2, AUNFL, AINEX
+unfl_con:
+	btstb	#unfl_bit,FPCR_ENABLE(%a6)
+	beqs	unfl_dis
+
+unfl_ena:
+	bfclr	STAG(%a6){#5:#3}		|clear wbtm66,wbtm1,wbtm0
+	bsetb	#wbtemp15_bit,WB_BYTE(%a6) |set wbtemp15
+	bsetb	#sticky_bit,STICKY(%a6)	|set sticky bit
+
+	bclrb	#E1,E_BYTE(%a6)
+
+unfl_dis:
+	bfextu	FPCR_MODE(%a6){#0:#2},%d0	|get round precision
+	
+	bclrb	#sign_bit,LOCAL_EX(%a0)
+	sne	LOCAL_SGN(%a0)		|convert to internal ext format
+
+	bsr	unf_sub			|returns IEEE result at a0
+|					;and sets FPSR_CC accordingly
+	
+	bfclr	LOCAL_SGN(%a0){#0:#8}	|convert back to IEEE ext format
+	beqs	unfl_fin
+
+	bsetb	#sign_bit,LOCAL_EX(%a0)
+	bsetb	#sign_bit,FP_SCR1(%a6)	|set sign bit of exc operand
+
+unfl_fin:
+	fmovemx (%a0),%fp0-%fp0		|store result in fp0
+	rts
+	
+
+|
+|	t_ovfl2 --- OVFL exception (without inex2 returned)
+|
+| This entry is used by scale to force catastrophic overflow.  The
+| ovfl, aovfl, and ainex bits are set, but not the inex2 bit.
+|
+t_ovfl2:
+	orl	#ovfl_inx_mask,USER_FPSR(%a6)
+	movel	ETEMP(%a6),FP_SCR1(%a6)
+	movel	ETEMP_HI(%a6),FP_SCR1+4(%a6)
+	movel	ETEMP_LO(%a6),FP_SCR1+8(%a6)
+|
+| Check for single or double round precision.  If single, check if
+| the lower 40 bits of ETEMP are zero; if not, set inex2.  If double,
+| check if the lower 21 bits are zero; if not, set inex2.
+|
+	moveb	FPCR_MODE(%a6),%d0
+	andib	#0xc0,%d0
+	beq	t_work		|if extended, finish ovfl processing
+	cmpib	#0x40,%d0		|test for single
+	bnes	t_dbl
+t_sgl:
+	tstb	ETEMP_LO(%a6)
+	bnes	t_setinx2
+	movel	ETEMP_HI(%a6),%d0
+	andil	#0xff,%d0		|look at only lower 8 bits
+	bnes	t_setinx2
+	bra	t_work
+t_dbl:
+	movel	ETEMP_LO(%a6),%d0
+	andil	#0x7ff,%d0	|look at only lower 11 bits
+	beq	t_work
+t_setinx2:
+	orl	#inex2_mask,USER_FPSR(%a6)
+	bras	t_work
+|
+|	t_ovfl --- OVFL exception
+|
+|** Note: the exc operand is returned in ETEMP.
+|
+t_ovfl:
+	orl	#ovfinx_mask,USER_FPSR(%a6)
+t_work:
+	btstb	#ovfl_bit,FPCR_ENABLE(%a6) |test FPCR for ovfl enabled
+	beqs	ovf_dis
+
+ovf_ena:
+	clrl	FP_SCR1(%a6)		|set exceptional operand
+	clrl	FP_SCR1+4(%a6)
+	clrl	FP_SCR1+8(%a6)
+
+	bfclr	STAG(%a6){#5:#3}		|clear wbtm66,wbtm1,wbtm0
+	bclrb	#wbtemp15_bit,WB_BYTE(%a6) |clear wbtemp15
+	bsetb	#sticky_bit,STICKY(%a6)	|set sticky bit
+
+	bclrb	#E1,E_BYTE(%a6)
+|					;fall through to disabled case
+
+| For disabled overflow call 'ovf_r_k'.  This routine loads the
+| correct result based on the rounding precision, destination
+| format, rounding mode and sign.
+|
+ovf_dis:
+	bsr	ovf_r_k			|returns unsigned ETEMP_EX
+|					;and sets FPSR_CC accordingly.
+	bfclr	ETEMP_SGN(%a6){#0:#8}	|fix sign
+	beqs	ovf_pos
+	bsetb	#sign_bit,ETEMP_EX(%a6)
+	bsetb	#sign_bit,FP_SCR1(%a6)	|set exceptional operand sign
+ovf_pos:
+	fmovemx ETEMP(%a6),%fp0-%fp0		|move the result to fp0
+	rts
+
+
+|
+|	INEX2 exception
+|
+| The inex2 and ainex bits are set.
+|
+t_inx2:
+	orl	#inx2a_mask,USER_FPSR(%a6) |set INEX2, AINEX
+	rts
+
+|
+|	Force Inex2
+|
+| This routine is called by the transcendental routines to force
+| the inex2 exception bits set in the FPSR.  If the underflow bit
+| is set, but the underflow trap was not taken, the aunfl bit in
+| the FPSR must be set.
+|
+t_frcinx:
+	orl	#inx2a_mask,USER_FPSR(%a6) |set INEX2, AINEX
+	btstb	#unfl_bit,FPSR_EXCEPT(%a6) |test for unfl bit set
+	beqs	no_uacc1		|if clear, do not set aunfl
+	bsetb	#aunfl_bit,FPSR_AEXCEPT(%a6)
+no_uacc1:
+	rts
+
+|
+|	DST_NAN
+|
+| Determine if the destination nan is signalling or non-signalling,
+| and set the FPSR bits accordingly.  See the MC68040 User's Manual 
+| section 3.2.2.5 NOT-A-NUMBERS.
+|
+dst_nan:
+	btstb	#sign_bit,FPTEMP_EX(%a6) |test sign of nan
+	beqs	dst_pos			|if clr, it was positive
+	bsetb	#neg_bit,FPSR_CC(%a6)	|set N bit
+dst_pos:
+	btstb	#signan_bit,FPTEMP_HI(%a6) |check if signalling 
+	beqs	dst_snan		|branch if signalling
+
+	fmovel	%d1,%fpcr			|restore user's rmode/prec
+	fmovex FPTEMP(%a6),%fp0		|return the non-signalling nan
+|
+| Check the source nan.  If it is signalling, snan will be reported.
+|
+	moveb	STAG(%a6),%d0
+	andib	#0xe0,%d0
+	cmpib	#0x60,%d0
+	bnes	no_snan
+	btstb	#signan_bit,ETEMP_HI(%a6) |check if signalling 
+	bnes	no_snan
+	orl	#snaniop_mask,USER_FPSR(%a6) |set NAN, SNAN, AIOP
+no_snan:
+	rts	
+
+dst_snan:
+	btstb	#snan_bit,FPCR_ENABLE(%a6) |check if trap enabled 
+	beqs	dst_dis			|branch if disabled
+
+	orb	#nan_tag,DTAG(%a6)	|set up dtag for nan
+	st	STORE_FLG(%a6)		|do not store a result
+	orl	#snaniop_mask,USER_FPSR(%a6) |set NAN, SNAN, AIOP
+	rts
+
+dst_dis:
+	bsetb	#signan_bit,FPTEMP_HI(%a6) |set SNAN bit in sop 
+	fmovel	%d1,%fpcr			|restore user's rmode/prec
+	fmovex FPTEMP(%a6),%fp0		|load non-sign. nan 
+	orl	#snaniop_mask,USER_FPSR(%a6) |set NAN, SNAN, AIOP
+	rts
+
+|
+|	SRC_NAN
+|
+| Determine if the source nan is signalling or non-signalling,
+| and set the FPSR bits accordingly.  See the MC68040 User's Manual 
+| section 3.2.2.5 NOT-A-NUMBERS.
+|
+src_nan:
+	btstb	#sign_bit,ETEMP_EX(%a6) |test sign of nan
+	beqs	src_pos			|if clr, it was positive
+	bsetb	#neg_bit,FPSR_CC(%a6)	|set N bit
+src_pos:
+	btstb	#signan_bit,ETEMP_HI(%a6) |check if signalling 
+	beqs	src_snan		|branch if signalling
+	fmovel	%d1,%fpcr			|restore user's rmode/prec
+	fmovex ETEMP(%a6),%fp0		|return the non-signalling nan
+	rts	
+
+src_snan:
+	btstb	#snan_bit,FPCR_ENABLE(%a6) |check if trap enabled 
+	beqs	src_dis			|branch if disabled
+	bsetb	#signan_bit,ETEMP_HI(%a6) |set SNAN bit in sop 
+	orb	#norm_tag,DTAG(%a6)	|set up dtag for norm
+	orb	#nan_tag,STAG(%a6)	|set up stag for nan
+	st	STORE_FLG(%a6)		|do not store a result
+	orl	#snaniop_mask,USER_FPSR(%a6) |set NAN, SNAN, AIOP
+	rts
+
+src_dis:
+	bsetb	#signan_bit,ETEMP_HI(%a6) |set SNAN bit in sop 
+	fmovel	%d1,%fpcr			|restore user's rmode/prec
+	fmovex ETEMP(%a6),%fp0		|load non-sign. nan 
+	orl	#snaniop_mask,USER_FPSR(%a6) |set NAN, SNAN, AIOP
+	rts
+
+|
+| For all functions that have a denormalized input and that f(x)=x,
+| this is the entry point
+|
+t_extdnrm:
+	orl	#unfinx_mask,USER_FPSR(%a6)
+|					;set UNFL, INEX2, AUNFL, AINEX
+	bras	xdnrm_con
+|
+| Entry point for scale with extended denorm.  The function does
+| not set inex2, aunfl, or ainex.  
+|
+t_resdnrm:
+	orl	#unfl_mask,USER_FPSR(%a6)
+
+xdnrm_con:
+	btstb	#unfl_bit,FPCR_ENABLE(%a6)
+	beqs	xdnrm_dis
+
+|
+| If exceptions are enabled, the additional task of setting up WBTEMP
+| is needed so that when the underflow exception handler is entered,
+| the user perceives no difference between what the 040 provides vs.
+| what the FPSP provides.
+|
+xdnrm_ena:
+	movel	%a0,-(%a7)
+
+	movel	LOCAL_EX(%a0),FP_SCR1(%a6)
+	movel	LOCAL_HI(%a0),FP_SCR1+4(%a6)
+	movel	LOCAL_LO(%a0),FP_SCR1+8(%a6)
+
+	lea	FP_SCR1(%a6),%a0
+
+	bclrb	#sign_bit,LOCAL_EX(%a0)
+	sne	LOCAL_SGN(%a0)		|convert to internal ext format
+	tstw	LOCAL_EX(%a0)		|check if input is denorm
+	beqs	xdnrm_dn		|if so, skip nrm_set
+	bsr	nrm_set			|normalize the result (exponent
+|					;will be negative
+xdnrm_dn:
+	bclrb	#sign_bit,LOCAL_EX(%a0)	|take off false sign
+	bfclr	LOCAL_SGN(%a0){#0:#8}	|change back to IEEE ext format
+	beqs	xdep
+	bsetb	#sign_bit,LOCAL_EX(%a0)
+xdep:	
+	bfclr	STAG(%a6){#5:#3}		|clear wbtm66,wbtm1,wbtm0
+	bsetb	#wbtemp15_bit,WB_BYTE(%a6) |set wbtemp15
+	bclrb	#sticky_bit,STICKY(%a6)	|clear sticky bit
+	bclrb	#E1,E_BYTE(%a6)
+	movel	(%a7)+,%a0
+xdnrm_dis:
+	bfextu	FPCR_MODE(%a6){#0:#2},%d0	|get round precision
+	bnes	not_ext			|if not round extended, store
+|					;IEEE defaults
+is_ext:
+	btstb	#sign_bit,LOCAL_EX(%a0)
+	beqs	xdnrm_store
+
+	bsetb	#neg_bit,FPSR_CC(%a6)	|set N bit in FPSR_CC
+
+	bras	xdnrm_store
+
+not_ext:
+	bclrb	#sign_bit,LOCAL_EX(%a0)
+	sne	LOCAL_SGN(%a0)		|convert to internal ext format
+	bsr	unf_sub			|returns IEEE result pointed by
+|					;a0; sets FPSR_CC accordingly
+	bfclr	LOCAL_SGN(%a0){#0:#8}	|convert back to IEEE ext format
+	beqs	xdnrm_store
+	bsetb	#sign_bit,LOCAL_EX(%a0)
+xdnrm_store:
+	fmovemx (%a0),%fp0-%fp0		|store result in fp0
+	rts
+
+|
+| This subroutine is used for dyadic operations that use an extended
+| denorm within the kernel. The approach used is to capture the frame,
+| fix/restore.
+|
+	.global	t_avoid_unsupp
+t_avoid_unsupp:
+	link	%a2,#-LOCAL_SIZE		|so that a2 fpsp.h negative 
+|					;offsets may be used
+	fsave	-(%a7)
+	tstb	1(%a7)			|check if idle, exit if so
+	beq	idle_end
+	btstb	#E1,E_BYTE(%a2)		|check for an E1 exception if
+|					;enabled, there is an unsupp
+	beq	end_avun		|else, exit
+	btstb	#7,DTAG(%a2)		|check for denorm destination
+	beqs	src_den			|else, must be a source denorm
+|
+| handle destination denorm
+|
+	lea	FPTEMP(%a2),%a0
+	btstb	#sign_bit,LOCAL_EX(%a0)
+	sne	LOCAL_SGN(%a0)		|convert to internal ext format
+	bclrb	#7,DTAG(%a2)		|set DTAG to norm
+	bsr	nrm_set			|normalize result, exponent
+|					;will become negative
+	bclrb	#sign_bit,LOCAL_EX(%a0)	|get rid of fake sign
+	bfclr	LOCAL_SGN(%a0){#0:#8}	|convert back to IEEE ext format
+	beqs	ck_src_den		|check if source is also denorm
+	bsetb	#sign_bit,LOCAL_EX(%a0)
+ck_src_den:
+	btstb	#7,STAG(%a2)
+	beqs	end_avun
+src_den:
+	lea	ETEMP(%a2),%a0
+	btstb	#sign_bit,LOCAL_EX(%a0)
+	sne	LOCAL_SGN(%a0)		|convert to internal ext format
+	bclrb	#7,STAG(%a2)		|set STAG to norm
+	bsr	nrm_set			|normalize result, exponent
+|					;will become negative
+	bclrb	#sign_bit,LOCAL_EX(%a0)	|get rid of fake sign
+	bfclr	LOCAL_SGN(%a0){#0:#8}	|convert back to IEEE ext format
+	beqs	den_com
+	bsetb	#sign_bit,LOCAL_EX(%a0)
+den_com:
+	moveb	#0xfe,CU_SAVEPC(%a2)	|set continue frame
+	clrw	NMNEXC(%a2)		|clear NMNEXC
+	bclrb	#E1,E_BYTE(%a2)
+|	fmove.l	%FPSR,FPSR_SHADOW(%a2)
+|	bset.b	#SFLAG,E_BYTE(%a2)
+|	bset.b	#XFLAG,T_BYTE(%a2)
+end_avun:
+	frestore (%a7)+
+	unlk	%a2
+	rts
+idle_end:
+	addl	#4,%a7
+	unlk	%a2
+	rts
+	|end
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/fpsp040/res_func.S linux/arch/m68k/fpsp040/res_func.S
--- v1.3.93/linux/arch/m68k/fpsp040/res_func.S	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/fpsp040/res_func.S	Sat Feb 24 22:58:43 1996
@@ -0,0 +1,2040 @@
+|
+|	res_func.sa 3.9 7/29/91
+|
+| Normalizes denormalized numbers if necessary and updates the
+| stack frame.  The function is then restored back into the
+| machine and the 040 completes the operation.  This routine
+| is only used by the unsupported data type/format handler.
+| (Exception vector 55).
+|
+| For packed move out (fmove.p fpm,<ea>) the operation is
+| completed here; data is packed and moved to user memory. 
+| The stack is restored to the 040 only in the case of a
+| reportable exception in the conversion.
+|
+|
+|		Copyright (C) Motorola, Inc. 1990
+|			All Rights Reserved
+|
+|	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA 
+|	The copyright notice above does not evidence any  
+|	actual or intended publication of such source code.
+
+RES_FUNC:    |idnt    2,1 | Motorola 040 Floating Point Software Package
+
+	|section	8
+
+	.include "fpsp.h"
+
+sp_bnds:	.short	0x3f81,0x407e
+		.short	0x3f6a,0x0000
+dp_bnds:	.short	0x3c01,0x43fe
+		.short	0x3bcd,0x0000
+
+	|xref	mem_write
+	|xref	bindec
+	|xref	get_fline
+	|xref	round
+	|xref	denorm
+	|xref	dest_ext
+	|xref	dest_dbl
+	|xref	dest_sgl
+	|xref	unf_sub
+	|xref	nrm_set
+	|xref	dnrm_lp
+	|xref	ovf_res
+	|xref	reg_dest
+	|xref	t_ovfl
+	|xref	t_unfl
+
+	.global	res_func
+	.global 	p_move
+
+res_func:
+	clrb	DNRM_FLG(%a6)
+	clrb	RES_FLG(%a6)
+	clrb	CU_ONLY(%a6)
+	tstb	DY_MO_FLG(%a6)
+	beqs	monadic
+dyadic:
+	btstb	#7,DTAG(%a6)	|if dop = norm=000, zero=001,
+|				;inf=010 or nan=011
+	beqs	monadic		|then branch
+|				;else denorm
+| HANDLE DESTINATION DENORM HERE
+|				;set dtag to norm
+|				;write the tag & fpte15 to the fstack
+	leal	FPTEMP(%a6),%a0
+
+	bclrb	#sign_bit,LOCAL_EX(%a0)
+	sne	LOCAL_SGN(%a0)
+
+	bsr	nrm_set		|normalize number (exp will go negative)
+	bclrb	#sign_bit,LOCAL_EX(%a0) |get rid of false sign
+	bfclr	LOCAL_SGN(%a0){#0:#8}	|change back to IEEE ext format
+	beqs	dpos
+	bsetb	#sign_bit,LOCAL_EX(%a0)
+dpos:
+	bfclr	DTAG(%a6){#0:#4}	|set tag to normalized, FPTE15 = 0
+	bsetb	#4,DTAG(%a6)	|set FPTE15
+	orb	#0x0f,DNRM_FLG(%a6)
+monadic:
+	leal	ETEMP(%a6),%a0
+	btstb	#direction_bit,CMDREG1B(%a6)	|check direction
+	bne	opclass3			|it is a mv out
+|
+| At this point, only oplcass 0 and 2 possible
+|
+	btstb	#7,STAG(%a6)	|if sop = norm=000, zero=001,
+|				;inf=010 or nan=011
+	bne	mon_dnrm	|else denorm
+	tstb	DY_MO_FLG(%a6)	|all cases of dyadic instructions would
+	bne	normal		|require normalization of denorm
+
+| At this point:
+|	monadic instructions:	fabs  = $18  fneg   = $1a  ftst   = $3a
+|				fmove = $00  fsmove = $40  fdmove = $44
+|				fsqrt = $05* fssqrt = $41  fdsqrt = $45
+|				(*fsqrt reencoded to $05)
+|
+	movew	CMDREG1B(%a6),%d0	|get command register
+	andil	#0x7f,%d0			|strip to only command word
+|
+| At this point, fabs, fneg, fsmove, fdmove, ftst, fsqrt, fssqrt, and 
+| fdsqrt are possible.
+| For cases fabs, fneg, fsmove, and fdmove goto spos (do not normalize)
+| For cases fsqrt, fssqrt, and fdsqrt goto nrm_src (do normalize)
+|
+	btstl	#0,%d0
+	bne	normal			|weed out fsqrt instructions
+|
+| cu_norm handles fmove in instructions with normalized inputs.
+| The routine round is used to correctly round the input for the
+| destination precision and mode.
+|
+cu_norm:
+	st	CU_ONLY(%a6)		|set cu-only inst flag
+	movew	CMDREG1B(%a6),%d0
+	andib	#0x3b,%d0		|isolate bits to select inst
+	tstb	%d0
+	beql	cu_nmove	|if zero, it is an fmove
+	cmpib	#0x18,%d0
+	beql	cu_nabs		|if $18, it is fabs
+	cmpib	#0x1a,%d0
+	beql	cu_nneg		|if $1a, it is fneg
+|
+| Inst is ftst.  Check the source operand and set the cc's accordingly.
+| No write is done, so simply rts.
+|
+cu_ntst:
+	movew	LOCAL_EX(%a0),%d0
+	bclrl	#15,%d0
+	sne	LOCAL_SGN(%a0)
+	beqs	cu_ntpo
+	orl	#neg_mask,USER_FPSR(%a6) |set N
+cu_ntpo:
+	cmpiw	#0x7fff,%d0	|test for inf/nan
+	bnes	cu_ntcz
+	tstl	LOCAL_HI(%a0)
+	bnes	cu_ntn
+	tstl	LOCAL_LO(%a0)
+	bnes	cu_ntn
+	orl	#inf_mask,USER_FPSR(%a6)
+	rts
+cu_ntn:
+	orl	#nan_mask,USER_FPSR(%a6)
+	movel	ETEMP_EX(%a6),FPTEMP_EX(%a6)	|set up fptemp sign for 
+|						;snan handler
+
+	rts
+cu_ntcz:
+	tstl	LOCAL_HI(%a0)
+	bnel	cu_ntsx
+	tstl	LOCAL_LO(%a0)
+	bnel	cu_ntsx
+	orl	#z_mask,USER_FPSR(%a6)
+cu_ntsx:
+	rts
+|
+| Inst is fabs.  Execute the absolute value function on the input.
+| Branch to the fmove code.  If the operand is NaN, do nothing.
+|
+cu_nabs:
+	moveb	STAG(%a6),%d0
+	btstl	#5,%d0			|test for NaN or zero
+	bne	wr_etemp		|if either, simply write it
+	bclrb	#7,LOCAL_EX(%a0)		|do abs
+	bras	cu_nmove		|fmove code will finish
+|
+| Inst is fneg.  Execute the negate value function on the input.
+| Fall though to the fmove code.  If the operand is NaN, do nothing.
+|
+cu_nneg:
+	moveb	STAG(%a6),%d0
+	btstl	#5,%d0			|test for NaN or zero
+	bne	wr_etemp		|if either, simply write it
+	bchgb	#7,LOCAL_EX(%a0)		|do neg
+|
+| Inst is fmove.  This code also handles all result writes.
+| If bit 2 is set, round is forced to double.  If it is clear,
+| and bit 6 is set, round is forced to single.  If both are clear,
+| the round precision is found in the fpcr.  If the rounding precision
+| is double or single, round the result before the write.
+|
+cu_nmove:
+	moveb	STAG(%a6),%d0
+	andib	#0xe0,%d0			|isolate stag bits
+	bne	wr_etemp		|if not norm, simply write it
+	btstb	#2,CMDREG1B+1(%a6)	|check for rd
+	bne	cu_nmrd
+	btstb	#6,CMDREG1B+1(%a6)	|check for rs
+	bne	cu_nmrs
+|
+| The move or operation is not with forced precision.  Test for
+| nan or inf as the input; if so, simply write it to FPn.  Use the
+| FPCR_MODE byte to get rounding on norms and zeros.
+|
+cu_nmnr:
+	bfextu	FPCR_MODE(%a6){#0:#2},%d0
+	tstb	%d0			|check for extended
+	beq	cu_wrexn		|if so, just write result
+	cmpib	#1,%d0			|check for single
+	beq	cu_nmrs			|fall through to double
+|
+| The move is fdmove or round precision is double.
+|
+cu_nmrd:
+	movel	#2,%d0			|set up the size for denorm
+	movew	LOCAL_EX(%a0),%d1		|compare exponent to double threshold
+	andw	#0x7fff,%d1	
+	cmpw	#0x3c01,%d1
+	bls	cu_nunfl
+	bfextu	FPCR_MODE(%a6){#2:#2},%d1	|get rmode
+	orl	#0x00020000,%d1		|or in rprec (double)
+	clrl	%d0			|clear g,r,s for round
+	bclrb	#sign_bit,LOCAL_EX(%a0)	|convert to internal format
+	sne	LOCAL_SGN(%a0)
+	bsrl	round
+	bfclr	LOCAL_SGN(%a0){#0:#8}
+	beqs	cu_nmrdc
+	bsetb	#sign_bit,LOCAL_EX(%a0)
+cu_nmrdc:
+	movew	LOCAL_EX(%a0),%d1		|check for overflow
+	andw	#0x7fff,%d1
+	cmpw	#0x43ff,%d1
+	bge	cu_novfl		|take care of overflow case
+	bra	cu_wrexn
+|
+| The move is fsmove or round precision is single.
+|
+cu_nmrs:
+	movel	#1,%d0
+	movew	LOCAL_EX(%a0),%d1
+	andw	#0x7fff,%d1
+	cmpw	#0x3f81,%d1
+	bls	cu_nunfl
+	bfextu	FPCR_MODE(%a6){#2:#2},%d1
+	orl	#0x00010000,%d1
+	clrl	%d0
+	bclrb	#sign_bit,LOCAL_EX(%a0)
+	sne	LOCAL_SGN(%a0)
+	bsrl	round
+	bfclr	LOCAL_SGN(%a0){#0:#8}
+	beqs	cu_nmrsc
+	bsetb	#sign_bit,LOCAL_EX(%a0)
+cu_nmrsc:
+	movew	LOCAL_EX(%a0),%d1
+	andw	#0x7FFF,%d1
+	cmpw	#0x407f,%d1
+	blt	cu_wrexn
+|
+| The operand is above precision boundaries.  Use t_ovfl to
+| generate the correct value.
+|
+cu_novfl:
+	bsr	t_ovfl
+	bra	cu_wrexn
+|
+| The operand is below precision boundaries.  Use denorm to
+| generate the correct value.
+|
+cu_nunfl:
+	bclrb	#sign_bit,LOCAL_EX(%a0)
+	sne	LOCAL_SGN(%a0)
+	bsr	denorm
+	bfclr	LOCAL_SGN(%a0){#0:#8}	|change back to IEEE ext format
+	beqs	cu_nucont
+	bsetb	#sign_bit,LOCAL_EX(%a0)
+cu_nucont:
+	bfextu	FPCR_MODE(%a6){#2:#2},%d1
+	btstb	#2,CMDREG1B+1(%a6)	|check for rd
+	bne	inst_d
+	btstb	#6,CMDREG1B+1(%a6)	|check for rs
+	bne	inst_s
+	swap	%d1
+	moveb	FPCR_MODE(%a6),%d1
+	lsrb	#6,%d1
+	swap	%d1
+	bra	inst_sd
+inst_d:
+	orl	#0x00020000,%d1
+	bra	inst_sd
+inst_s:
+	orl	#0x00010000,%d1
+inst_sd:
+	bclrb	#sign_bit,LOCAL_EX(%a0)
+	sne	LOCAL_SGN(%a0)
+	bsrl	round
+	bfclr	LOCAL_SGN(%a0){#0:#8}
+	beqs	cu_nuflp
+	bsetb	#sign_bit,LOCAL_EX(%a0)
+cu_nuflp:
+	btstb	#inex2_bit,FPSR_EXCEPT(%a6)
+	beqs	cu_nuninx
+	orl	#aunfl_mask,USER_FPSR(%a6) |if the round was inex, set AUNFL
+cu_nuninx:
+	tstl	LOCAL_HI(%a0)		|test for zero
+	bnes	cu_nunzro
+	tstl	LOCAL_LO(%a0)
+	bnes	cu_nunzro
+|
+| The mantissa is zero from the denorm loop.  Check sign and rmode
+| to see if rounding should have occured which would leave the lsb.
+|
+	movel	USER_FPCR(%a6),%d0
+	andil	#0x30,%d0		|isolate rmode
+	cmpil	#0x20,%d0
+	blts	cu_nzro
+	bnes	cu_nrp
+cu_nrm:
+	tstw	LOCAL_EX(%a0)	|if positive, set lsb
+	bges	cu_nzro
+	btstb	#7,FPCR_MODE(%a6) |check for double
+	beqs	cu_nincs
+	bras	cu_nincd
+cu_nrp:
+	tstw	LOCAL_EX(%a0)	|if positive, set lsb
+	blts	cu_nzro
+	btstb	#7,FPCR_MODE(%a6) |check for double
+	beqs	cu_nincs
+cu_nincd:
+	orl	#0x800,LOCAL_LO(%a0) |inc for double
+	bra	cu_nunzro
+cu_nincs:
+	orl	#0x100,LOCAL_HI(%a0) |inc for single
+	bra	cu_nunzro
+cu_nzro:
+	orl	#z_mask,USER_FPSR(%a6)
+	moveb	STAG(%a6),%d0
+	andib	#0xe0,%d0
+	cmpib	#0x40,%d0		|check if input was tagged zero
+	beqs	cu_numv
+cu_nunzro:
+	orl	#unfl_mask,USER_FPSR(%a6) |set unfl
+cu_numv:
+	movel	(%a0),ETEMP(%a6)
+	movel	4(%a0),ETEMP_HI(%a6)
+	movel	8(%a0),ETEMP_LO(%a6)
+|
+| Write the result to memory, setting the fpsr cc bits.  NaN and Inf
+| bypass cu_wrexn.
+|
+cu_wrexn:
+	tstw	LOCAL_EX(%a0)		|test for zero
+	beqs	cu_wrzero
+	cmpw	#0x8000,LOCAL_EX(%a0)	|test for zero
+	bnes	cu_wreon
+cu_wrzero:
+	orl	#z_mask,USER_FPSR(%a6)	|set Z bit
+cu_wreon:
+	tstw	LOCAL_EX(%a0)
+	bpl	wr_etemp
+	orl	#neg_mask,USER_FPSR(%a6)
+	bra	wr_etemp
+
+|
+| HANDLE SOURCE DENORM HERE
+|
+|				;clear denorm stag to norm
+|				;write the new tag & ete15 to the fstack
+mon_dnrm:
+|
+| At this point, check for the cases in which normalizing the 
+| denorm produces incorrect results.
+|
+	tstb	DY_MO_FLG(%a6)	|all cases of dyadic instructions would
+	bnes	nrm_src		|require normalization of denorm
+
+| At this point:
+|	monadic instructions:	fabs  = $18  fneg   = $1a  ftst   = $3a
+|				fmove = $00  fsmove = $40  fdmove = $44
+|				fsqrt = $05* fssqrt = $41  fdsqrt = $45
+|				(*fsqrt reencoded to $05)
+|
+	movew	CMDREG1B(%a6),%d0	|get command register
+	andil	#0x7f,%d0			|strip to only command word
+|
+| At this point, fabs, fneg, fsmove, fdmove, ftst, fsqrt, fssqrt, and 
+| fdsqrt are possible.
+| For cases fabs, fneg, fsmove, and fdmove goto spos (do not normalize)
+| For cases fsqrt, fssqrt, and fdsqrt goto nrm_src (do normalize)
+|
+	btstl	#0,%d0
+	bnes	nrm_src		|weed out fsqrt instructions
+	st	CU_ONLY(%a6)	|set cu-only inst flag
+	bra	cu_dnrm		|fmove, fabs, fneg, ftst 
+|				;cases go to cu_dnrm
+nrm_src:
+	bclrb	#sign_bit,LOCAL_EX(%a0)
+	sne	LOCAL_SGN(%a0)
+	bsr	nrm_set		|normalize number (exponent will go 
+|				; negative)
+	bclrb	#sign_bit,LOCAL_EX(%a0) |get rid of false sign
+
+	bfclr	LOCAL_SGN(%a0){#0:#8}	|change back to IEEE ext format
+	beqs	spos
+	bsetb	#sign_bit,LOCAL_EX(%a0)
+spos:
+	bfclr	STAG(%a6){#0:#4}	|set tag to normalized, FPTE15 = 0
+	bsetb	#4,STAG(%a6)	|set ETE15
+	orb	#0xf0,DNRM_FLG(%a6)
+normal:
+	tstb	DNRM_FLG(%a6)	|check if any of the ops were denorms
+	bne	ck_wrap		|if so, check if it is a potential
+|				;wrap-around case
+fix_stk:
+	moveb	#0xfe,CU_SAVEPC(%a6)
+	bclrb	#E1,E_BYTE(%a6)
+
+	clrw	NMNEXC(%a6)
+
+	st	RES_FLG(%a6)	|indicate that a restore is needed
+	rts
+
+|
+| cu_dnrm handles all cu-only instructions (fmove, fabs, fneg, and
+| ftst) completly in software without an frestore to the 040. 
+|
+cu_dnrm:
+	st	CU_ONLY(%a6)
+	movew	CMDREG1B(%a6),%d0
+	andib	#0x3b,%d0		|isolate bits to select inst
+	tstb	%d0
+	beql	cu_dmove	|if zero, it is an fmove
+	cmpib	#0x18,%d0
+	beql	cu_dabs		|if $18, it is fabs
+	cmpib	#0x1a,%d0
+	beql	cu_dneg		|if $1a, it is fneg
+|
+| Inst is ftst.  Check the source operand and set the cc's accordingly.
+| No write is done, so simply rts.
+|
+cu_dtst:
+	movew	LOCAL_EX(%a0),%d0
+	bclrl	#15,%d0
+	sne	LOCAL_SGN(%a0)
+	beqs	cu_dtpo
+	orl	#neg_mask,USER_FPSR(%a6) |set N
+cu_dtpo:
+	cmpiw	#0x7fff,%d0	|test for inf/nan
+	bnes	cu_dtcz
+	tstl	LOCAL_HI(%a0)
+	bnes	cu_dtn
+	tstl	LOCAL_LO(%a0)
+	bnes	cu_dtn
+	orl	#inf_mask,USER_FPSR(%a6)
+	rts
+cu_dtn:
+	orl	#nan_mask,USER_FPSR(%a6)
+	movel	ETEMP_EX(%a6),FPTEMP_EX(%a6)	|set up fptemp sign for 
+|						;snan handler
+	rts
+cu_dtcz:
+	tstl	LOCAL_HI(%a0)
+	bnel	cu_dtsx
+	tstl	LOCAL_LO(%a0)
+	bnel	cu_dtsx
+	orl	#z_mask,USER_FPSR(%a6)
+cu_dtsx:
+	rts
+|
+| Inst is fabs.  Execute the absolute value function on the input.
+| Branch to the fmove code.
+|
+cu_dabs:
+	bclrb	#7,LOCAL_EX(%a0)		|do abs
+	bras	cu_dmove		|fmove code will finish
+|
+| Inst is fneg.  Execute the negate value function on the input.
+| Fall though to the fmove code.
+|
+cu_dneg:
+	bchgb	#7,LOCAL_EX(%a0)		|do neg
+|
+| Inst is fmove.  This code also handles all result writes.
+| If bit 2 is set, round is forced to double.  If it is clear,
+| and bit 6 is set, round is forced to single.  If both are clear,
+| the round precision is found in the fpcr.  If the rounding precision
+| is double or single, the result is zero, and the mode is checked
+| to determine if the lsb of the result should be set.
+|
+cu_dmove:
+	btstb	#2,CMDREG1B+1(%a6)	|check for rd
+	bne	cu_dmrd
+	btstb	#6,CMDREG1B+1(%a6)	|check for rs
+	bne	cu_dmrs
+|
+| The move or operation is not with forced precision.  Use the
+| FPCR_MODE byte to get rounding.
+|
+cu_dmnr:
+	bfextu	FPCR_MODE(%a6){#0:#2},%d0
+	tstb	%d0			|check for extended
+	beq	cu_wrexd		|if so, just write result
+	cmpib	#1,%d0			|check for single
+	beq	cu_dmrs			|fall through to double
+|
+| The move is fdmove or round precision is double.  Result is zero.
+| Check rmode for rp or rm and set lsb accordingly.
+|
+cu_dmrd:
+	bfextu	FPCR_MODE(%a6){#2:#2},%d1	|get rmode
+	tstw	LOCAL_EX(%a0)		|check sign
+	blts	cu_dmdn
+	cmpib	#3,%d1			|check for rp
+	bne	cu_dpd			|load double pos zero
+	bra	cu_dpdr			|load double pos zero w/lsb
+cu_dmdn:
+	cmpib	#2,%d1			|check for rm
+	bne	cu_dnd			|load double neg zero
+	bra	cu_dndr			|load double neg zero w/lsb
+|
+| The move is fsmove or round precision is single.  Result is zero.
+| Check for rp or rm and set lsb accordingly.
+|
+cu_dmrs:
+	bfextu	FPCR_MODE(%a6){#2:#2},%d1	|get rmode
+	tstw	LOCAL_EX(%a0)		|check sign
+	blts	cu_dmsn
+	cmpib	#3,%d1			|check for rp
+	bne	cu_spd			|load single pos zero
+	bra	cu_spdr			|load single pos zero w/lsb
+cu_dmsn:
+	cmpib	#2,%d1			|check for rm
+	bne	cu_snd			|load single neg zero
+	bra	cu_sndr			|load single neg zero w/lsb
+|
+| The precision is extended, so the result in etemp is correct.
+| Simply set unfl (not inex2 or aunfl) and write the result to 
+| the correct fp register.
+cu_wrexd:
+	orl	#unfl_mask,USER_FPSR(%a6)
+	tstw	LOCAL_EX(%a0)
+	beq	wr_etemp
+	orl	#neg_mask,USER_FPSR(%a6)
+	bra	wr_etemp
+|
+| These routines write +/- zero in double format.  The routines
+| cu_dpdr and cu_dndr set the double lsb.
+|
+cu_dpd:
+	movel	#0x3c010000,LOCAL_EX(%a0)	|force pos double zero
+	clrl	LOCAL_HI(%a0)
+	clrl	LOCAL_LO(%a0)
+	orl	#z_mask,USER_FPSR(%a6)
+	orl	#unfinx_mask,USER_FPSR(%a6)
+	bra	wr_etemp
+cu_dpdr:
+	movel	#0x3c010000,LOCAL_EX(%a0)	|force pos double zero
+	clrl	LOCAL_HI(%a0)
+	movel	#0x800,LOCAL_LO(%a0)	|with lsb set
+	orl	#unfinx_mask,USER_FPSR(%a6)
+	bra	wr_etemp
+cu_dnd:
+	movel	#0xbc010000,LOCAL_EX(%a0)	|force pos double zero
+	clrl	LOCAL_HI(%a0)
+	clrl	LOCAL_LO(%a0)
+	orl	#z_mask,USER_FPSR(%a6)
+	orl	#neg_mask,USER_FPSR(%a6)
+	orl	#unfinx_mask,USER_FPSR(%a6)
+	bra	wr_etemp
+cu_dndr:
+	movel	#0xbc010000,LOCAL_EX(%a0)	|force pos double zero
+	clrl	LOCAL_HI(%a0)
+	movel	#0x800,LOCAL_LO(%a0)	|with lsb set
+	orl	#neg_mask,USER_FPSR(%a6)
+	orl	#unfinx_mask,USER_FPSR(%a6)
+	bra	wr_etemp
+|
+| These routines write +/- zero in single format.  The routines
+| cu_dpdr and cu_dndr set the single lsb.
+|
+cu_spd:
+	movel	#0x3f810000,LOCAL_EX(%a0)	|force pos single zero
+	clrl	LOCAL_HI(%a0)
+	clrl	LOCAL_LO(%a0)
+	orl	#z_mask,USER_FPSR(%a6)
+	orl	#unfinx_mask,USER_FPSR(%a6)
+	bra	wr_etemp
+cu_spdr:
+	movel	#0x3f810000,LOCAL_EX(%a0)	|force pos single zero
+	movel	#0x100,LOCAL_HI(%a0)	|with lsb set
+	clrl	LOCAL_LO(%a0)
+	orl	#unfinx_mask,USER_FPSR(%a6)
+	bra	wr_etemp
+cu_snd:
+	movel	#0xbf810000,LOCAL_EX(%a0)	|force pos single zero
+	clrl	LOCAL_HI(%a0)
+	clrl	LOCAL_LO(%a0)
+	orl	#z_mask,USER_FPSR(%a6)
+	orl	#neg_mask,USER_FPSR(%a6)
+	orl	#unfinx_mask,USER_FPSR(%a6)
+	bra	wr_etemp
+cu_sndr:
+	movel	#0xbf810000,LOCAL_EX(%a0)	|force pos single zero
+	movel	#0x100,LOCAL_HI(%a0)	|with lsb set
+	clrl	LOCAL_LO(%a0)
+	orl	#neg_mask,USER_FPSR(%a6)
+	orl	#unfinx_mask,USER_FPSR(%a6)
+	bra	wr_etemp
+	
+|
+| This code checks for 16-bit overflow conditions on dyadic
+| operations which are not restorable into the floating-point
+| unit and must be completed in software.  Basically, this
+| condition exists with a very large norm and a denorm.  One
+| of the operands must be denormalized to enter this code.
+|
+| Flags used:
+|	DY_MO_FLG contains 0 for monadic op, $ff for dyadic
+|	DNRM_FLG contains $00 for neither op denormalized
+|	                  $0f for the destination op denormalized
+|	                  $f0 for the source op denormalized
+|	                  $ff for both ops denormalzed
+|
+| The wrap-around condition occurs for add, sub, div, and cmp
+| when 
+|
+|	abs(dest_exp - src_exp) >= $8000
+|
+| and for mul when
+|
+|	(dest_exp + src_exp) < $0
+|
+| we must process the operation here if this case is true.
+|
+| The rts following the frcfpn routine is the exit from res_func
+| for this condition.  The restore flag (RES_FLG) is left clear.
+| No frestore is done unless an exception is to be reported.
+|
+| For fadd: 
+|	if(sign_of(dest) != sign_of(src))
+|		replace exponent of src with $3fff (keep sign)
+|		use fpu to perform dest+new_src (user's rmode and X)
+|		clr sticky
+|	else
+|		set sticky
+|	call round with user's precision and mode
+|	move result to fpn and wbtemp
+|
+| For fsub:
+|	if(sign_of(dest) == sign_of(src))
+|		replace exponent of src with $3fff (keep sign)
+|		use fpu to perform dest+new_src (user's rmode and X)
+|		clr sticky
+|	else
+|		set sticky
+|	call round with user's precision and mode
+|	move result to fpn and wbtemp
+|
+| For fdiv/fsgldiv:
+|	if(both operands are denorm)
+|		restore_to_fpu;
+|	if(dest is norm)
+|		force_ovf;
+|	else(dest is denorm)
+|		force_unf:
+|
+| For fcmp:
+|	if(dest is norm)
+|		N = sign_of(dest);
+|	else(dest is denorm)
+|		N = sign_of(src);
+|
+| For fmul:
+|	if(both operands are denorm)
+|		force_unf;
+|	if((dest_exp + src_exp) < 0)
+|		force_unf:
+|	else
+|		restore_to_fpu;
+|
+| local equates:
+	.set	addcode,0x22
+	.set	subcode,0x28
+	.set	mulcode,0x23
+	.set	divcode,0x20
+	.set	cmpcode,0x38
+ck_wrap:
+	| tstb	DY_MO_FLG(%a6)	;check for fsqrt
+	beq	fix_stk		|if zero, it is fsqrt
+	movew	CMDREG1B(%a6),%d0
+	andiw	#0x3b,%d0		|strip to command bits
+	cmpiw	#addcode,%d0
+	beq	wrap_add
+	cmpiw	#subcode,%d0
+	beq	wrap_sub
+	cmpiw	#mulcode,%d0
+	beq	wrap_mul
+	cmpiw	#cmpcode,%d0
+	beq	wrap_cmp
+|
+| Inst is fdiv.  
+|
+wrap_div:
+	cmpb	#0xff,DNRM_FLG(%a6) |if both ops denorm, 
+	beq	fix_stk		 |restore to fpu
+|
+| One of the ops is denormalized.  Test for wrap condition
+| and force the result.
+|
+	cmpb	#0x0f,DNRM_FLG(%a6) |check for dest denorm
+	bnes	div_srcd
+div_destd:
+	bsrl	ckinf_ns
+	bne	fix_stk
+	bfextu	ETEMP_EX(%a6){#1:#15},%d0	|get src exp (always pos)
+	bfexts	FPTEMP_EX(%a6){#1:#15},%d1	|get dest exp (always neg)
+	subl	%d1,%d0			|subtract dest from src
+	cmpl	#0x7fff,%d0
+	blt	fix_stk			|if less, not wrap case
+	clrb	WBTEMP_SGN(%a6)
+	movew	ETEMP_EX(%a6),%d0		|find the sign of the result
+	movew	FPTEMP_EX(%a6),%d1
+	eorw	%d1,%d0
+	andiw	#0x8000,%d0
+	beq	force_unf
+	st	WBTEMP_SGN(%a6)
+	bra	force_unf
+
+ckinf_ns:
+	moveb	STAG(%a6),%d0		|check source tag for inf or nan
+	bra	ck_in_com
+ckinf_nd:
+	moveb	DTAG(%a6),%d0		|check destination tag for inf or nan
+ck_in_com:	
+	andib	#0x60,%d0			|isolate tag bits
+	cmpb	#0x40,%d0			|is it inf?
+	beq	nan_or_inf		|not wrap case
+	cmpb	#0x60,%d0			|is it nan?
+	beq	nan_or_inf		|yes, not wrap case?
+	cmpb	#0x20,%d0			|is it a zero?
+	beq	nan_or_inf		|yes
+	clrl	%d0
+	rts				|then ; it is either a zero of norm,
+|					;check wrap case
+nan_or_inf:
+	moveql	#-1,%d0
+	rts
+
+
+
+div_srcd:
+	bsrl	ckinf_nd
+	bne	fix_stk
+	bfextu	FPTEMP_EX(%a6){#1:#15},%d0	|get dest exp (always pos)
+	bfexts	ETEMP_EX(%a6){#1:#15},%d1	|get src exp (always neg)
+	subl	%d1,%d0			|subtract src from dest
+	cmpl	#0x8000,%d0
+	blt	fix_stk			|if less, not wrap case
+	clrb	WBTEMP_SGN(%a6)
+	movew	ETEMP_EX(%a6),%d0		|find the sign of the result
+	movew	FPTEMP_EX(%a6),%d1
+	eorw	%d1,%d0
+	andiw	#0x8000,%d0
+	beqs	force_ovf
+	st	WBTEMP_SGN(%a6)
+|
+| This code handles the case of the instruction resulting in 
+| an overflow condition.
+|
+force_ovf:
+	bclrb	#E1,E_BYTE(%a6)
+	orl	#ovfl_inx_mask,USER_FPSR(%a6)
+	clrw	NMNEXC(%a6)
+	leal	WBTEMP(%a6),%a0		|point a0 to memory location
+	movew	CMDREG1B(%a6),%d0
+	btstl	#6,%d0			|test for forced precision
+	beqs	frcovf_fpcr
+	btstl	#2,%d0			|check for double
+	bnes	frcovf_dbl
+	movel	#0x1,%d0			|inst is forced single
+	bras	frcovf_rnd
+frcovf_dbl:
+	movel	#0x2,%d0			|inst is forced double
+	bras	frcovf_rnd
+frcovf_fpcr:
+	bfextu	FPCR_MODE(%a6){#0:#2},%d0	|inst not forced - use fpcr prec
+frcovf_rnd:
+
+| The 881/882 does not set inex2 for the following case, so the 
+| line is commented out to be compatible with 881/882
+|	tst.b	%d0
+|	beq.b	frcovf_x
+|	or.l	#inex2_mask,USER_FPSR(%a6) ;if prec is s or d, set inex2
+
+|frcovf_x:
+	bsrl	ovf_res			|get correct result based on
+|					;round precision/mode.  This 
+|					;sets FPSR_CC correctly
+|					;returns in external format
+	bfclr	WBTEMP_SGN(%a6){#0:#8}
+	beq	frcfpn
+	bsetb	#sign_bit,WBTEMP_EX(%a6)
+	bra	frcfpn
+|
+| Inst is fadd.
+|
+wrap_add:
+	cmpb	#0xff,DNRM_FLG(%a6) |if both ops denorm, 
+	beq	fix_stk		 |restore to fpu
+|
+| One of the ops is denormalized.  Test for wrap condition
+| and complete the instruction.
+|
+	cmpb	#0x0f,DNRM_FLG(%a6) |check for dest denorm
+	bnes	add_srcd
+add_destd:
+	bsrl	ckinf_ns
+	bne	fix_stk
+	bfextu	ETEMP_EX(%a6){#1:#15},%d0	|get src exp (always pos)
+	bfexts	FPTEMP_EX(%a6){#1:#15},%d1	|get dest exp (always neg)
+	subl	%d1,%d0			|subtract dest from src
+	cmpl	#0x8000,%d0
+	blt	fix_stk			|if less, not wrap case
+	bra	add_wrap
+add_srcd:
+	bsrl	ckinf_nd
+	bne	fix_stk
+	bfextu	FPTEMP_EX(%a6){#1:#15},%d0	|get dest exp (always pos)
+	bfexts	ETEMP_EX(%a6){#1:#15},%d1	|get src exp (always neg)
+	subl	%d1,%d0			|subtract src from dest
+	cmpl	#0x8000,%d0
+	blt	fix_stk			|if less, not wrap case
+|
+| Check the signs of the operands.  If they are unlike, the fpu
+| can be used to add the norm and 1.0 with the sign of the
+| denorm and it will correctly generate the result in extended
+| precision.  We can then call round with no sticky and the result
+| will be correct for the user's rounding mode and precision.  If
+| the signs are the same, we call round with the sticky bit set
+| and the result will be correctfor the user's rounding mode and
+| precision.
+|
+add_wrap:
+	movew	ETEMP_EX(%a6),%d0
+	movew	FPTEMP_EX(%a6),%d1
+	eorw	%d1,%d0
+	andiw	#0x8000,%d0
+	beq	add_same
+|
+| The signs are unlike.
+|
+	cmpb	#0x0f,DNRM_FLG(%a6) |is dest the denorm?
+	bnes	add_u_srcd
+	movew	FPTEMP_EX(%a6),%d0
+	andiw	#0x8000,%d0
+	orw	#0x3fff,%d0	|force the exponent to +/- 1
+	movew	%d0,FPTEMP_EX(%a6) |in the denorm
+	movel	USER_FPCR(%a6),%d0
+	andil	#0x30,%d0
+	fmovel	%d0,%fpcr		|set up users rmode and X
+	fmovex	ETEMP(%a6),%fp0
+	faddx	FPTEMP(%a6),%fp0
+	leal	WBTEMP(%a6),%a0	|point a0 to wbtemp in frame
+	fmovel	%fpsr,%d1
+	orl	%d1,USER_FPSR(%a6) |capture cc's and inex from fadd
+	fmovex	%fp0,WBTEMP(%a6)	|write result to memory
+	lsrl	#4,%d0		|put rmode in lower 2 bits
+	movel	USER_FPCR(%a6),%d1
+	andil	#0xc0,%d1
+	lsrl	#6,%d1		|put precision in upper word
+	swap	%d1
+	orl	%d0,%d1		|set up for round call
+	clrl	%d0		|force sticky to zero
+	bclrb	#sign_bit,WBTEMP_EX(%a6)
+	sne	WBTEMP_SGN(%a6)
+	bsrl	round		|round result to users rmode & prec
+	bfclr	WBTEMP_SGN(%a6){#0:#8}	|convert back to IEEE ext format
+	beq	frcfpnr
+	bsetb	#sign_bit,WBTEMP_EX(%a6)
+	bra	frcfpnr
+add_u_srcd:
+	movew	ETEMP_EX(%a6),%d0
+	andiw	#0x8000,%d0
+	orw	#0x3fff,%d0	|force the exponent to +/- 1
+	movew	%d0,ETEMP_EX(%a6) |in the denorm
+	movel	USER_FPCR(%a6),%d0
+	andil	#0x30,%d0
+	fmovel	%d0,%fpcr		|set up users rmode and X
+	fmovex	ETEMP(%a6),%fp0
+	faddx	FPTEMP(%a6),%fp0
+	fmovel	%fpsr,%d1
+	orl	%d1,USER_FPSR(%a6) |capture cc's and inex from fadd
+	leal	WBTEMP(%a6),%a0	|point a0 to wbtemp in frame
+	fmovex	%fp0,WBTEMP(%a6)	|write result to memory
+	lsrl	#4,%d0		|put rmode in lower 2 bits
+	movel	USER_FPCR(%a6),%d1
+	andil	#0xc0,%d1
+	lsrl	#6,%d1		|put precision in upper word
+	swap	%d1
+	orl	%d0,%d1		|set up for round call
+	clrl	%d0		|force sticky to zero
+	bclrb	#sign_bit,WBTEMP_EX(%a6)
+	sne	WBTEMP_SGN(%a6)	|use internal format for round
+	bsrl	round		|round result to users rmode & prec
+	bfclr	WBTEMP_SGN(%a6){#0:#8}	|convert back to IEEE ext format
+	beq	frcfpnr
+	bsetb	#sign_bit,WBTEMP_EX(%a6)
+	bra	frcfpnr
+|
+| Signs are alike:
+|
+add_same:
+	cmpb	#0x0f,DNRM_FLG(%a6) |is dest the denorm?
+	bnes	add_s_srcd
+add_s_destd:
+	leal	ETEMP(%a6),%a0
+	movel	USER_FPCR(%a6),%d0
+	andil	#0x30,%d0
+	lsrl	#4,%d0		|put rmode in lower 2 bits
+	movel	USER_FPCR(%a6),%d1
+	andil	#0xc0,%d1
+	lsrl	#6,%d1		|put precision in upper word
+	swap	%d1
+	orl	%d0,%d1		|set up for round call
+	movel	#0x20000000,%d0	|set sticky for round
+	bclrb	#sign_bit,ETEMP_EX(%a6)
+	sne	ETEMP_SGN(%a6)
+	bsrl	round		|round result to users rmode & prec
+	bfclr	ETEMP_SGN(%a6){#0:#8}	|convert back to IEEE ext format
+	beqs	add_s_dclr
+	bsetb	#sign_bit,ETEMP_EX(%a6)
+add_s_dclr:
+	leal	WBTEMP(%a6),%a0
+	movel	ETEMP(%a6),(%a0)	|write result to wbtemp
+	movel	ETEMP_HI(%a6),4(%a0)
+	movel	ETEMP_LO(%a6),8(%a0)
+	tstw	ETEMP_EX(%a6)
+	bgt	add_ckovf
+	orl	#neg_mask,USER_FPSR(%a6)
+	bra	add_ckovf
+add_s_srcd:
+	leal	FPTEMP(%a6),%a0
+	movel	USER_FPCR(%a6),%d0
+	andil	#0x30,%d0
+	lsrl	#4,%d0		|put rmode in lower 2 bits
+	movel	USER_FPCR(%a6),%d1
+	andil	#0xc0,%d1
+	lsrl	#6,%d1		|put precision in upper word
+	swap	%d1
+	orl	%d0,%d1		|set up for round call
+	movel	#0x20000000,%d0	|set sticky for round
+	bclrb	#sign_bit,FPTEMP_EX(%a6)
+	sne	FPTEMP_SGN(%a6)
+	bsrl	round		|round result to users rmode & prec
+	bfclr	FPTEMP_SGN(%a6){#0:#8}	|convert back to IEEE ext format
+	beqs	add_s_sclr
+	bsetb	#sign_bit,FPTEMP_EX(%a6)
+add_s_sclr:
+	leal	WBTEMP(%a6),%a0
+	movel	FPTEMP(%a6),(%a0)	|write result to wbtemp
+	movel	FPTEMP_HI(%a6),4(%a0)
+	movel	FPTEMP_LO(%a6),8(%a0)
+	tstw	FPTEMP_EX(%a6)
+	bgt	add_ckovf
+	orl	#neg_mask,USER_FPSR(%a6)
+add_ckovf:
+	movew	WBTEMP_EX(%a6),%d0
+	andiw	#0x7fff,%d0
+	cmpiw	#0x7fff,%d0
+	bne	frcfpnr
+|
+| The result has overflowed to $7fff exponent.  Set I, ovfl,
+| and aovfl, and clr the mantissa (incorrectly set by the
+| round routine.)
+|
+	orl	#inf_mask+ovfl_inx_mask,USER_FPSR(%a6)	
+	clrl	4(%a0)
+	bra	frcfpnr
+|
+| Inst is fsub.
+|
+wrap_sub:
+	cmpb	#0xff,DNRM_FLG(%a6) |if both ops denorm, 
+	beq	fix_stk		 |restore to fpu
+|
+| One of the ops is denormalized.  Test for wrap condition
+| and complete the instruction.
+|
+	cmpb	#0x0f,DNRM_FLG(%a6) |check for dest denorm
+	bnes	sub_srcd
+sub_destd:
+	bsrl	ckinf_ns
+	bne	fix_stk
+	bfextu	ETEMP_EX(%a6){#1:#15},%d0	|get src exp (always pos)
+	bfexts	FPTEMP_EX(%a6){#1:#15},%d1	|get dest exp (always neg)
+	subl	%d1,%d0			|subtract src from dest
+	cmpl	#0x8000,%d0
+	blt	fix_stk			|if less, not wrap case
+	bra	sub_wrap
+sub_srcd:
+	bsrl	ckinf_nd
+	bne	fix_stk
+	bfextu	FPTEMP_EX(%a6){#1:#15},%d0	|get dest exp (always pos)
+	bfexts	ETEMP_EX(%a6){#1:#15},%d1	|get src exp (always neg)
+	subl	%d1,%d0			|subtract dest from src
+	cmpl	#0x8000,%d0
+	blt	fix_stk			|if less, not wrap case
+|
+| Check the signs of the operands.  If they are alike, the fpu
+| can be used to subtract from the norm 1.0 with the sign of the
+| denorm and it will correctly generate the result in extended
+| precision.  We can then call round with no sticky and the result
+| will be correct for the user's rounding mode and precision.  If
+| the signs are unlike, we call round with the sticky bit set
+| and the result will be correctfor the user's rounding mode and
+| precision.
+|
+sub_wrap:
+	movew	ETEMP_EX(%a6),%d0
+	movew	FPTEMP_EX(%a6),%d1
+	eorw	%d1,%d0
+	andiw	#0x8000,%d0
+	bne	sub_diff
+|
+| The signs are alike.
+|
+	cmpb	#0x0f,DNRM_FLG(%a6) |is dest the denorm?
+	bnes	sub_u_srcd
+	movew	FPTEMP_EX(%a6),%d0
+	andiw	#0x8000,%d0
+	orw	#0x3fff,%d0	|force the exponent to +/- 1
+	movew	%d0,FPTEMP_EX(%a6) |in the denorm
+	movel	USER_FPCR(%a6),%d0
+	andil	#0x30,%d0
+	fmovel	%d0,%fpcr		|set up users rmode and X
+	fmovex	FPTEMP(%a6),%fp0
+	fsubx	ETEMP(%a6),%fp0
+	fmovel	%fpsr,%d1
+	orl	%d1,USER_FPSR(%a6) |capture cc's and inex from fadd
+	leal	WBTEMP(%a6),%a0	|point a0 to wbtemp in frame
+	fmovex	%fp0,WBTEMP(%a6)	|write result to memory
+	lsrl	#4,%d0		|put rmode in lower 2 bits
+	movel	USER_FPCR(%a6),%d1
+	andil	#0xc0,%d1
+	lsrl	#6,%d1		|put precision in upper word
+	swap	%d1
+	orl	%d0,%d1		|set up for round call
+	clrl	%d0		|force sticky to zero
+	bclrb	#sign_bit,WBTEMP_EX(%a6)
+	sne	WBTEMP_SGN(%a6)
+	bsrl	round		|round result to users rmode & prec
+	bfclr	WBTEMP_SGN(%a6){#0:#8}	|convert back to IEEE ext format
+	beq	frcfpnr
+	bsetb	#sign_bit,WBTEMP_EX(%a6)
+	bra	frcfpnr
+sub_u_srcd:
+	movew	ETEMP_EX(%a6),%d0
+	andiw	#0x8000,%d0
+	orw	#0x3fff,%d0	|force the exponent to +/- 1
+	movew	%d0,ETEMP_EX(%a6) |in the denorm
+	movel	USER_FPCR(%a6),%d0
+	andil	#0x30,%d0
+	fmovel	%d0,%fpcr		|set up users rmode and X
+	fmovex	FPTEMP(%a6),%fp0
+	fsubx	ETEMP(%a6),%fp0
+	fmovel	%fpsr,%d1
+	orl	%d1,USER_FPSR(%a6) |capture cc's and inex from fadd
+	leal	WBTEMP(%a6),%a0	|point a0 to wbtemp in frame
+	fmovex	%fp0,WBTEMP(%a6)	|write result to memory
+	lsrl	#4,%d0		|put rmode in lower 2 bits
+	movel	USER_FPCR(%a6),%d1
+	andil	#0xc0,%d1
+	lsrl	#6,%d1		|put precision in upper word
+	swap	%d1
+	orl	%d0,%d1		|set up for round call
+	clrl	%d0		|force sticky to zero
+	bclrb	#sign_bit,WBTEMP_EX(%a6)
+	sne	WBTEMP_SGN(%a6)
+	bsrl	round		|round result to users rmode & prec
+	bfclr	WBTEMP_SGN(%a6){#0:#8}	|convert back to IEEE ext format
+	beq	frcfpnr
+	bsetb	#sign_bit,WBTEMP_EX(%a6)
+	bra	frcfpnr
+|
+| Signs are unlike:
+|
+sub_diff:
+	cmpb	#0x0f,DNRM_FLG(%a6) |is dest the denorm?
+	bnes	sub_s_srcd
+sub_s_destd:
+	leal	ETEMP(%a6),%a0
+	movel	USER_FPCR(%a6),%d0
+	andil	#0x30,%d0
+	lsrl	#4,%d0		|put rmode in lower 2 bits
+	movel	USER_FPCR(%a6),%d1
+	andil	#0xc0,%d1
+	lsrl	#6,%d1		|put precision in upper word
+	swap	%d1
+	orl	%d0,%d1		|set up for round call
+	movel	#0x20000000,%d0	|set sticky for round
+|
+| Since the dest is the denorm, the sign is the opposite of the
+| norm sign.
+|
+	eoriw	#0x8000,ETEMP_EX(%a6)	|flip sign on result
+	tstw	ETEMP_EX(%a6)
+	bgts	sub_s_dwr
+	orl	#neg_mask,USER_FPSR(%a6)
+sub_s_dwr:
+	bclrb	#sign_bit,ETEMP_EX(%a6)
+	sne	ETEMP_SGN(%a6)
+	bsrl	round		|round result to users rmode & prec
+	bfclr	ETEMP_SGN(%a6){#0:#8}	|convert back to IEEE ext format
+	beqs	sub_s_dclr
+	bsetb	#sign_bit,ETEMP_EX(%a6)
+sub_s_dclr:
+	leal	WBTEMP(%a6),%a0
+	movel	ETEMP(%a6),(%a0)	|write result to wbtemp
+	movel	ETEMP_HI(%a6),4(%a0)
+	movel	ETEMP_LO(%a6),8(%a0)
+	bra	sub_ckovf
+sub_s_srcd:
+	leal	FPTEMP(%a6),%a0
+	movel	USER_FPCR(%a6),%d0
+	andil	#0x30,%d0
+	lsrl	#4,%d0		|put rmode in lower 2 bits
+	movel	USER_FPCR(%a6),%d1
+	andil	#0xc0,%d1
+	lsrl	#6,%d1		|put precision in upper word
+	swap	%d1
+	orl	%d0,%d1		|set up for round call
+	movel	#0x20000000,%d0	|set sticky for round
+	bclrb	#sign_bit,FPTEMP_EX(%a6)
+	sne	FPTEMP_SGN(%a6)
+	bsrl	round		|round result to users rmode & prec
+	bfclr	FPTEMP_SGN(%a6){#0:#8}	|convert back to IEEE ext format
+	beqs	sub_s_sclr
+	bsetb	#sign_bit,FPTEMP_EX(%a6)
+sub_s_sclr:
+	leal	WBTEMP(%a6),%a0
+	movel	FPTEMP(%a6),(%a0)	|write result to wbtemp
+	movel	FPTEMP_HI(%a6),4(%a0)
+	movel	FPTEMP_LO(%a6),8(%a0)
+	tstw	FPTEMP_EX(%a6)
+	bgt	sub_ckovf
+	orl	#neg_mask,USER_FPSR(%a6)
+sub_ckovf:
+	movew	WBTEMP_EX(%a6),%d0
+	andiw	#0x7fff,%d0
+	cmpiw	#0x7fff,%d0
+	bne	frcfpnr
+|
+| The result has overflowed to $7fff exponent.  Set I, ovfl,
+| and aovfl, and clr the mantissa (incorrectly set by the
+| round routine.)
+|
+	orl	#inf_mask+ovfl_inx_mask,USER_FPSR(%a6)	
+	clrl	4(%a0)
+	bra	frcfpnr
+|
+| Inst is fcmp.
+|
+wrap_cmp:
+	cmpb	#0xff,DNRM_FLG(%a6) |if both ops denorm, 
+	beq	fix_stk		 |restore to fpu
+|
+| One of the ops is denormalized.  Test for wrap condition
+| and complete the instruction.
+|
+	cmpb	#0x0f,DNRM_FLG(%a6) |check for dest denorm
+	bnes	cmp_srcd
+cmp_destd:
+	bsrl	ckinf_ns
+	bne	fix_stk
+	bfextu	ETEMP_EX(%a6){#1:#15},%d0	|get src exp (always pos)
+	bfexts	FPTEMP_EX(%a6){#1:#15},%d1	|get dest exp (always neg)
+	subl	%d1,%d0			|subtract dest from src
+	cmpl	#0x8000,%d0
+	blt	fix_stk			|if less, not wrap case
+	tstw	ETEMP_EX(%a6)		|set N to ~sign_of(src)
+	bge	cmp_setn
+	rts
+cmp_srcd:
+	bsrl	ckinf_nd
+	bne	fix_stk
+	bfextu	FPTEMP_EX(%a6){#1:#15},%d0	|get dest exp (always pos)
+	bfexts	ETEMP_EX(%a6){#1:#15},%d1	|get src exp (always neg)
+	subl	%d1,%d0			|subtract src from dest
+	cmpl	#0x8000,%d0
+	blt	fix_stk			|if less, not wrap case
+	tstw	FPTEMP_EX(%a6)		|set N to sign_of(dest)
+	blt	cmp_setn
+	rts
+cmp_setn:
+	orl	#neg_mask,USER_FPSR(%a6)
+	rts
+
+|
+| Inst is fmul.
+|
+wrap_mul:
+	cmpb	#0xff,DNRM_FLG(%a6) |if both ops denorm, 
+	beq	force_unf	|force an underflow (really!)
+|
+| One of the ops is denormalized.  Test for wrap condition
+| and complete the instruction.
+|
+	cmpb	#0x0f,DNRM_FLG(%a6) |check for dest denorm
+	bnes	mul_srcd
+mul_destd:
+	bsrl	ckinf_ns
+	bne	fix_stk
+	bfextu	ETEMP_EX(%a6){#1:#15},%d0	|get src exp (always pos)
+	bfexts	FPTEMP_EX(%a6){#1:#15},%d1	|get dest exp (always neg)
+	addl	%d1,%d0			|subtract dest from src
+	bgt	fix_stk
+	bra	force_unf
+mul_srcd:
+	bsrl	ckinf_nd
+	bne	fix_stk
+	bfextu	FPTEMP_EX(%a6){#1:#15},%d0	|get dest exp (always pos)
+	bfexts	ETEMP_EX(%a6){#1:#15},%d1	|get src exp (always neg)
+	addl	%d1,%d0			|subtract src from dest
+	bgt	fix_stk
+	
+|
+| This code handles the case of the instruction resulting in 
+| an underflow condition.
+|
+force_unf:
+	bclrb	#E1,E_BYTE(%a6)
+	orl	#unfinx_mask,USER_FPSR(%a6)
+	clrw	NMNEXC(%a6)
+	clrb	WBTEMP_SGN(%a6)
+	movew	ETEMP_EX(%a6),%d0		|find the sign of the result
+	movew	FPTEMP_EX(%a6),%d1
+	eorw	%d1,%d0
+	andiw	#0x8000,%d0
+	beqs	frcunfcont
+	st	WBTEMP_SGN(%a6)
+frcunfcont:
+	lea	WBTEMP(%a6),%a0		|point a0 to memory location
+	movew	CMDREG1B(%a6),%d0
+	btstl	#6,%d0			|test for forced precision
+	beqs	frcunf_fpcr
+	btstl	#2,%d0			|check for double
+	bnes	frcunf_dbl
+	movel	#0x1,%d0			|inst is forced single
+	bras	frcunf_rnd
+frcunf_dbl:
+	movel	#0x2,%d0			|inst is forced double
+	bras	frcunf_rnd
+frcunf_fpcr:
+	bfextu	FPCR_MODE(%a6){#0:#2},%d0	|inst not forced - use fpcr prec
+frcunf_rnd:
+	bsrl	unf_sub			|get correct result based on
+|					;round precision/mode.  This 
+|					;sets FPSR_CC correctly
+	bfclr	WBTEMP_SGN(%a6){#0:#8}	|convert back to IEEE ext format
+	beqs	frcfpn
+	bsetb	#sign_bit,WBTEMP_EX(%a6)
+	bra	frcfpn
+
+|
+| Write the result to the user's fpn.  All results must be HUGE to be
+| written; otherwise the results would have overflowed or underflowed.
+| If the rounding precision is single or double, the ovf_res routine
+| is needed to correctly supply the max value.
+|
+frcfpnr:
+	movew	CMDREG1B(%a6),%d0
+	btstl	#6,%d0			|test for forced precision
+	beqs	frcfpn_fpcr
+	btstl	#2,%d0			|check for double
+	bnes	frcfpn_dbl
+	movel	#0x1,%d0			|inst is forced single
+	bras	frcfpn_rnd
+frcfpn_dbl:
+	movel	#0x2,%d0			|inst is forced double
+	bras	frcfpn_rnd
+frcfpn_fpcr:
+	bfextu	FPCR_MODE(%a6){#0:#2},%d0	|inst not forced - use fpcr prec
+	tstb	%d0
+	beqs	frcfpn			|if extended, write what you got
+frcfpn_rnd:
+	bclrb	#sign_bit,WBTEMP_EX(%a6)
+	sne	WBTEMP_SGN(%a6)
+	bsrl	ovf_res			|get correct result based on
+|					;round precision/mode.  This 
+|					;sets FPSR_CC correctly
+	bfclr	WBTEMP_SGN(%a6){#0:#8}	|convert back to IEEE ext format
+	beqs	frcfpn_clr
+	bsetb	#sign_bit,WBTEMP_EX(%a6)
+frcfpn_clr:
+	orl	#ovfinx_mask,USER_FPSR(%a6)
+| 
+| Perform the write.
+|
+frcfpn:
+	bfextu	CMDREG1B(%a6){#6:#3},%d0	|extract fp destination register
+	cmpib	#3,%d0
+	bles	frc0123			|check if dest is fp0-fp3
+	movel	#7,%d1
+	subl	%d0,%d1
+	clrl	%d0
+	bsetl	%d1,%d0
+	fmovemx WBTEMP(%a6),%d0
+	rts
+frc0123:
+	cmpib	#0,%d0
+	beqs	frc0_dst
+	cmpib	#1,%d0
+	beqs	frc1_dst 
+	cmpib	#2,%d0
+	beqs	frc2_dst 
+frc3_dst:
+	movel	WBTEMP_EX(%a6),USER_FP3(%a6)
+	movel	WBTEMP_HI(%a6),USER_FP3+4(%a6)
+	movel	WBTEMP_LO(%a6),USER_FP3+8(%a6)
+	rts
+frc2_dst:
+	movel	WBTEMP_EX(%a6),USER_FP2(%a6)
+	movel	WBTEMP_HI(%a6),USER_FP2+4(%a6)
+	movel	WBTEMP_LO(%a6),USER_FP2+8(%a6)
+	rts
+frc1_dst:
+	movel	WBTEMP_EX(%a6),USER_FP1(%a6)
+	movel	WBTEMP_HI(%a6),USER_FP1+4(%a6)
+	movel	WBTEMP_LO(%a6),USER_FP1+8(%a6)
+	rts
+frc0_dst:
+	movel	WBTEMP_EX(%a6),USER_FP0(%a6)
+	movel	WBTEMP_HI(%a6),USER_FP0+4(%a6)
+	movel	WBTEMP_LO(%a6),USER_FP0+8(%a6)
+	rts
+
+|
+| Write etemp to fpn.
+| A check is made on enabled and signalled snan exceptions,
+| and the destination is not overwritten if this condition exists.
+| This code is designed to make fmoveins of unsupported data types
+| faster.
+|
+wr_etemp:
+	btstb	#snan_bit,FPSR_EXCEPT(%a6)	|if snan is set, and
+	beqs	fmoveinc		|enabled, force restore
+	btstb	#snan_bit,FPCR_ENABLE(%a6) |and don't overwrite
+	beqs	fmoveinc		|the dest
+	movel	ETEMP_EX(%a6),FPTEMP_EX(%a6)	|set up fptemp sign for 
+|						;snan handler
+	tstb	ETEMP(%a6)		|check for negative
+	blts	snan_neg
+	rts
+snan_neg:
+	orl	#neg_bit,USER_FPSR(%a6)	|snan is negative; set N
+	rts
+fmoveinc:
+	clrw	NMNEXC(%a6)
+	bclrb	#E1,E_BYTE(%a6)
+	moveb	STAG(%a6),%d0		|check if stag is inf
+	andib	#0xe0,%d0
+	cmpib	#0x40,%d0
+	bnes	fminc_cnan
+	orl	#inf_mask,USER_FPSR(%a6) |if inf, nothing yet has set I
+	tstw	LOCAL_EX(%a0)		|check sign
+	bges	fminc_con
+	orl	#neg_mask,USER_FPSR(%a6)
+	bra	fminc_con
+fminc_cnan:
+	cmpib	#0x60,%d0			|check if stag is NaN
+	bnes	fminc_czero
+	orl	#nan_mask,USER_FPSR(%a6) |if nan, nothing yet has set NaN
+	movel	ETEMP_EX(%a6),FPTEMP_EX(%a6)	|set up fptemp sign for 
+|						;snan handler
+	tstw	LOCAL_EX(%a0)		|check sign
+	bges	fminc_con
+	orl	#neg_mask,USER_FPSR(%a6)
+	bra	fminc_con
+fminc_czero:
+	cmpib	#0x20,%d0			|check if zero
+	bnes	fminc_con
+	orl	#z_mask,USER_FPSR(%a6)	|if zero, set Z
+	tstw	LOCAL_EX(%a0)		|check sign
+	bges	fminc_con
+	orl	#neg_mask,USER_FPSR(%a6)
+fminc_con:
+	bfextu	CMDREG1B(%a6){#6:#3},%d0	|extract fp destination register
+	cmpib	#3,%d0
+	bles	fp0123			|check if dest is fp0-fp3
+	movel	#7,%d1
+	subl	%d0,%d1
+	clrl	%d0
+	bsetl	%d1,%d0
+	fmovemx ETEMP(%a6),%d0
+	rts
+
+fp0123:
+	cmpib	#0,%d0
+	beqs	fp0_dst
+	cmpib	#1,%d0
+	beqs	fp1_dst 
+	cmpib	#2,%d0
+	beqs	fp2_dst 
+fp3_dst:
+	movel	ETEMP_EX(%a6),USER_FP3(%a6)
+	movel	ETEMP_HI(%a6),USER_FP3+4(%a6)
+	movel	ETEMP_LO(%a6),USER_FP3+8(%a6)
+	rts
+fp2_dst:
+	movel	ETEMP_EX(%a6),USER_FP2(%a6)
+	movel	ETEMP_HI(%a6),USER_FP2+4(%a6)
+	movel	ETEMP_LO(%a6),USER_FP2+8(%a6)
+	rts
+fp1_dst:
+	movel	ETEMP_EX(%a6),USER_FP1(%a6)
+	movel	ETEMP_HI(%a6),USER_FP1+4(%a6)
+	movel	ETEMP_LO(%a6),USER_FP1+8(%a6)
+	rts
+fp0_dst:
+	movel	ETEMP_EX(%a6),USER_FP0(%a6)
+	movel	ETEMP_HI(%a6),USER_FP0+4(%a6)
+	movel	ETEMP_LO(%a6),USER_FP0+8(%a6)
+	rts
+
+opclass3:
+	st	CU_ONLY(%a6)
+	movew	CMDREG1B(%a6),%d0	|check if packed moveout
+	andiw	#0x0c00,%d0	|isolate last 2 bits of size field
+	cmpiw	#0x0c00,%d0	|if size is 011 or 111, it is packed
+	beq	pack_out	|else it is norm or denorm
+	bra	mv_out
+
+	
+|
+|	MOVE OUT
+|
+
+mv_tbl:
+	.long	li
+	.long 	sgp
+	.long 	xp
+	.long 	mvout_end	|should never be taken
+	.long 	wi
+	.long 	dp
+	.long 	bi
+	.long 	mvout_end	|should never be taken
+mv_out:
+	bfextu	CMDREG1B(%a6){#3:#3},%d1	|put source specifier in d1
+	leal	mv_tbl,%a0
+	movel	%a0@(%d1:l:4),%a0
+	jmp	(%a0)
+
+|
+| This exit is for move-out to memory.  The aunfl bit is 
+| set if the result is inex and unfl is signalled.
+|
+mvout_end:
+	btstb	#inex2_bit,FPSR_EXCEPT(%a6)
+	beqs	no_aufl
+	btstb	#unfl_bit,FPSR_EXCEPT(%a6)
+	beqs	no_aufl
+	bsetb	#aunfl_bit,FPSR_AEXCEPT(%a6)
+no_aufl:
+	clrw	NMNEXC(%a6)
+	bclrb	#E1,E_BYTE(%a6)
+	fmovel	#0,%FPSR			|clear any cc bits from res_func
+|
+| Return ETEMP to extended format from internal extended format so
+| that gen_except will have a correctly signed value for ovfl/unfl
+| handlers.
+|
+	bfclr	ETEMP_SGN(%a6){#0:#8}
+	beqs	mvout_con
+	bsetb	#sign_bit,ETEMP_EX(%a6)
+mvout_con:
+	rts
+|
+| This exit is for move-out to int register.  The aunfl bit is 
+| not set in any case for this move.
+|
+mvouti_end:
+	clrw	NMNEXC(%a6)
+	bclrb	#E1,E_BYTE(%a6)
+	fmovel	#0,%FPSR			|clear any cc bits from res_func
+|
+| Return ETEMP to extended format from internal extended format so
+| that gen_except will have a correctly signed value for ovfl/unfl
+| handlers.
+|
+	bfclr	ETEMP_SGN(%a6){#0:#8}
+	beqs	mvouti_con
+	bsetb	#sign_bit,ETEMP_EX(%a6)
+mvouti_con:
+	rts
+|
+| li is used to handle a long integer source specifier
+|
+
+li:
+	moveql	#4,%d0		|set byte count
+
+	btstb	#7,STAG(%a6)	|check for extended denorm
+	bne	int_dnrm	|if so, branch
+
+	fmovemx ETEMP(%a6),%fp0-%fp0
+	fcmpd	#0x41dfffffffc00000,%fp0
+| 41dfffffffc00000 in dbl prec = 401d0000fffffffe00000000 in ext prec
+	fbge	lo_plrg	
+	fcmpd	#0xc1e0000000000000,%fp0
+| c1e0000000000000 in dbl prec = c01e00008000000000000000 in ext prec
+	fble	lo_nlrg
+|
+| at this point, the answer is between the largest pos and neg values
+|
+	movel	USER_FPCR(%a6),%d1	|use user's rounding mode
+	andil	#0x30,%d1
+	fmovel	%d1,%fpcr
+	fmovel	%fp0,L_SCR1(%a6)	|let the 040 perform conversion
+	fmovel %fpsr,%d1
+	orl	%d1,USER_FPSR(%a6)	|capture inex2/ainex if set
+	bra	int_wrt
+
+
+lo_plrg:
+	movel	#0x7fffffff,L_SCR1(%a6)	|answer is largest positive int
+	fbeq	int_wrt			|exact answer
+	fcmpd	#0x41dfffffffe00000,%fp0
+| 41dfffffffe00000 in dbl prec = 401d0000ffffffff00000000 in ext prec
+	fbge	int_operr		|set operr
+	bra	int_inx			|set inexact
+
+lo_nlrg:
+	movel	#0x80000000,L_SCR1(%a6)
+	fbeq	int_wrt			|exact answer
+	fcmpd	#0xc1e0000000100000,%fp0
+| c1e0000000100000 in dbl prec = c01e00008000000080000000 in ext prec
+	fblt	int_operr		|set operr
+	bra	int_inx			|set inexact
+
+|
+| wi is used to handle a word integer source specifier
+|
+
+wi:
+	moveql	#2,%d0		|set byte count
+
+	btstb	#7,STAG(%a6)	|check for extended denorm
+	bne	int_dnrm	|branch if so
+
+	fmovemx ETEMP(%a6),%fp0-%fp0
+	fcmps	#0x46fffe00,%fp0
+| 46fffe00 in sgl prec = 400d0000fffe000000000000 in ext prec
+	fbge	wo_plrg	
+	fcmps	#0xc7000000,%fp0
+| c7000000 in sgl prec = c00e00008000000000000000 in ext prec
+	fble	wo_nlrg
+
+|
+| at this point, the answer is between the largest pos and neg values
+|
+	movel	USER_FPCR(%a6),%d1	|use user's rounding mode
+	andil	#0x30,%d1
+	fmovel	%d1,%fpcr
+	fmovew	%fp0,L_SCR1(%a6)	|let the 040 perform conversion
+	fmovel %fpsr,%d1
+	orl	%d1,USER_FPSR(%a6)	|capture inex2/ainex if set
+	bra	int_wrt
+
+wo_plrg:
+	movew	#0x7fff,L_SCR1(%a6)	|answer is largest positive int
+	fbeq	int_wrt			|exact answer
+	fcmps	#0x46ffff00,%fp0
+| 46ffff00 in sgl prec = 400d0000ffff000000000000 in ext prec
+	fbge	int_operr		|set operr
+	bra	int_inx			|set inexact
+
+wo_nlrg:
+	movew	#0x8000,L_SCR1(%a6)
+	fbeq	int_wrt			|exact answer
+	fcmps	#0xc7000080,%fp0
+| c7000080 in sgl prec = c00e00008000800000000000 in ext prec
+	fblt	int_operr		|set operr
+	bra	int_inx			|set inexact
+
+|
+| bi is used to handle a byte integer source specifier
+|
+
+bi:
+	moveql	#1,%d0		|set byte count
+
+	btstb	#7,STAG(%a6)	|check for extended denorm
+	bne	int_dnrm	|branch if so
+
+	fmovemx ETEMP(%a6),%fp0-%fp0
+	fcmps	#0x42fe0000,%fp0
+| 42fe0000 in sgl prec = 40050000fe00000000000000 in ext prec
+	fbge	by_plrg	
+	fcmps	#0xc3000000,%fp0
+| c3000000 in sgl prec = c00600008000000000000000 in ext prec
+	fble	by_nlrg
+
+|
+| at this point, the answer is between the largest pos and neg values
+|
+	movel	USER_FPCR(%a6),%d1	|use user's rounding mode
+	andil	#0x30,%d1
+	fmovel	%d1,%fpcr
+	fmoveb	%fp0,L_SCR1(%a6)	|let the 040 perform conversion
+	fmovel %fpsr,%d1
+	orl	%d1,USER_FPSR(%a6)	|capture inex2/ainex if set
+	bra	int_wrt
+
+by_plrg:
+	moveb	#0x7f,L_SCR1(%a6)		|answer is largest positive int
+	fbeq	int_wrt			|exact answer
+	fcmps	#0x42ff0000,%fp0
+| 42ff0000 in sgl prec = 40050000ff00000000000000 in ext prec
+	fbge	int_operr		|set operr
+	bra	int_inx			|set inexact
+
+by_nlrg:
+	moveb	#0x80,L_SCR1(%a6)
+	fbeq	int_wrt			|exact answer
+	fcmps	#0xc3008000,%fp0
+| c3008000 in sgl prec = c00600008080000000000000 in ext prec
+	fblt	int_operr		|set operr
+	bra	int_inx			|set inexact
+
+|
+| Common integer routines
+|
+| int_drnrm---account for possible nonzero result for round up with positive
+| operand and round down for negative answer.  In the first case (result = 1)
+| byte-width (store in d0) of result must be honored.  In the second case,
+| -1 in L_SCR1(a6) will cover all contingencies (FMOVE.B/W/L out).
+
+int_dnrm:
+	movel	#0,L_SCR1(%a6)	| initialize result to 0
+	bfextu	FPCR_MODE(%a6){#2:#2},%d1	| d1 is the rounding mode
+	cmpb	#2,%d1		
+	bmis	int_inx		| if RN or RZ, done
+	bnes	int_rp		| if RP, continue below
+	tstw	ETEMP(%a6)	| RM: store -1 in L_SCR1 if src is negative
+	bpls	int_inx		| otherwise result is 0
+	movel	#-1,L_SCR1(%a6)
+	bras	int_inx
+int_rp:
+	tstw	ETEMP(%a6)	| RP: store +1 of proper width in L_SCR1 if
+|				; source is greater than 0
+	bmis	int_inx		| otherwise, result is 0
+	lea	L_SCR1(%a6),%a1	| a1 is address of L_SCR1
+	addal	%d0,%a1		| offset by destination width -1
+	subal	#1,%a1		
+	bsetb	#0,(%a1)		| set low bit at a1 address
+int_inx:
+	oril	#inx2a_mask,USER_FPSR(%a6)
+	bras	int_wrt
+int_operr:
+	fmovemx %fp0-%fp0,FPTEMP(%a6)	|FPTEMP must contain the extended
+|				;precision source that needs to be
+|				;converted to integer this is required
+|				;if the operr exception is enabled.
+|				;set operr/aiop (no inex2 on int ovfl)
+
+	oril	#opaop_mask,USER_FPSR(%a6)
+|				;fall through to perform int_wrt
+int_wrt: 
+	movel	EXC_EA(%a6),%a1	|load destination address
+	tstl	%a1		|check to see if it is a dest register
+	beqs	wrt_dn		|write data register 
+	lea	L_SCR1(%a6),%a0	|point to supervisor source address
+	bsrl	mem_write
+	bra	mvouti_end
+
+wrt_dn:
+	movel	%d0,-(%sp)	|d0 currently contains the size to write
+	bsrl	get_fline	|get_fline returns Dn in d0
+	andiw	#0x7,%d0		|isolate register
+	movel	(%sp)+,%d1	|get size
+	cmpil	#4,%d1		|most frequent case
+	beqs	sz_long
+	cmpil	#2,%d1
+	bnes	sz_con
+	orl	#8,%d0		|add 'word' size to register#
+	bras	sz_con
+sz_long:
+	orl	#0x10,%d0		|add 'long' size to register#
+sz_con:
+	movel	%d0,%d1		|reg_dest expects size:reg in d1
+	bsrl	reg_dest	|load proper data register
+	bra	mvouti_end 
+xp:
+	lea	ETEMP(%a6),%a0
+	bclrb	#sign_bit,LOCAL_EX(%a0)
+	sne	LOCAL_SGN(%a0)
+	btstb	#7,STAG(%a6)	|check for extended denorm
+	bne	xdnrm
+	clrl	%d0
+	bras	do_fp		|do normal case
+sgp:
+	lea	ETEMP(%a6),%a0
+	bclrb	#sign_bit,LOCAL_EX(%a0)
+	sne	LOCAL_SGN(%a0)
+	btstb	#7,STAG(%a6)	|check for extended denorm
+	bne	sp_catas	|branch if so
+	movew	LOCAL_EX(%a0),%d0
+	lea	sp_bnds,%a1
+	cmpw	(%a1),%d0
+	blt	sp_under
+	cmpw	2(%a1),%d0
+	bgt	sp_over
+	movel	#1,%d0		|set destination format to single
+	bras	do_fp		|do normal case
+dp:
+	lea	ETEMP(%a6),%a0
+	bclrb	#sign_bit,LOCAL_EX(%a0)
+	sne	LOCAL_SGN(%a0)
+
+	btstb	#7,STAG(%a6)	|check for extended denorm
+	bne	dp_catas	|branch if so
+
+	movew	LOCAL_EX(%a0),%d0
+	lea	dp_bnds,%a1
+
+	cmpw	(%a1),%d0
+	blt	dp_under
+	cmpw	2(%a1),%d0
+	bgt	dp_over
+	
+	movel	#2,%d0		|set destination format to double
+|				;fall through to do_fp
+|
+do_fp:
+	bfextu	FPCR_MODE(%a6){#2:#2},%d1	|rnd mode in d1
+	swap	%d0			|rnd prec in upper word
+	addl	%d0,%d1			|d1 has PREC/MODE info
+	
+	clrl	%d0			|clear g,r,s 
+
+	bsrl	round			|round 
+
+	movel	%a0,%a1
+	movel	EXC_EA(%a6),%a0
+
+	bfextu	CMDREG1B(%a6){#3:#3},%d1	|extract destination format
+|					;at this point only the dest
+|					;formats sgl, dbl, ext are
+|					;possible
+	cmpb	#2,%d1
+	bgts	ddbl			|double=5, extended=2, single=1
+	bnes	dsgl
+|					;fall through to dext
+dext:
+	bsrl	dest_ext
+	bra	mvout_end
+dsgl:
+	bsrl	dest_sgl
+	bra	mvout_end
+ddbl:
+	bsrl	dest_dbl
+	bra	mvout_end
+
+|
+| Handle possible denorm or catastrophic underflow cases here
+|
+xdnrm:
+	bsr	set_xop		|initialize WBTEMP
+	bsetb	#wbtemp15_bit,WB_BYTE(%a6) |set wbtemp15
+
+	movel	%a0,%a1
+	movel	EXC_EA(%a6),%a0	|a0 has the destination pointer
+	bsrl	dest_ext	|store to memory
+	bsetb	#unfl_bit,FPSR_EXCEPT(%a6)
+	bra	mvout_end
+	
+sp_under:
+	bsetb	#etemp15_bit,STAG(%a6)
+
+	cmpw	4(%a1),%d0
+	blts	sp_catas	|catastrophic underflow case	
+
+	movel	#1,%d0		|load in round precision
+	movel	#sgl_thresh,%d1	|load in single denorm threshold
+	bsrl	dpspdnrm	|expects d1 to have the proper
+|				;denorm threshold
+	bsrl	dest_sgl	|stores value to destination
+	bsetb	#unfl_bit,FPSR_EXCEPT(%a6)
+	bra	mvout_end	|exit
+
+dp_under:
+	bsetb	#etemp15_bit,STAG(%a6)
+
+	cmpw	4(%a1),%d0
+	blts	dp_catas	|catastrophic underflow case
+		
+	movel	#dbl_thresh,%d1	|load in double precision threshold
+	movel	#2,%d0		
+	bsrl	dpspdnrm	|expects d1 to have proper
+|				;denorm threshold
+|				;expects d0 to have round precision
+	bsrl	dest_dbl	|store value to destination
+	bsetb	#unfl_bit,FPSR_EXCEPT(%a6)
+	bra	mvout_end	|exit
+
+|
+| Handle catastrophic underflow cases here
+|
+sp_catas:
+| Temp fix for z bit set in unf_sub
+	movel	USER_FPSR(%a6),-(%a7)
+
+	movel	#1,%d0		|set round precision to sgl
+
+	bsrl	unf_sub		|a0 points to result
+
+	movel	(%a7)+,USER_FPSR(%a6)
+
+	movel	#1,%d0
+	subw	%d0,LOCAL_EX(%a0) |account for difference between
+|				;denorm/norm bias
+
+	movel	%a0,%a1		|a1 has the operand input
+	movel	EXC_EA(%a6),%a0	|a0 has the destination pointer
+	
+	bsrl	dest_sgl	|store the result
+	oril	#unfinx_mask,USER_FPSR(%a6)
+	bra	mvout_end
+	
+dp_catas:
+| Temp fix for z bit set in unf_sub
+	movel	USER_FPSR(%a6),-(%a7)
+
+	movel	#2,%d0		|set round precision to dbl
+	bsrl	unf_sub		|a0 points to result
+
+	movel	(%a7)+,USER_FPSR(%a6)
+
+	movel	#1,%d0
+	subw	%d0,LOCAL_EX(%a0) |account for difference between 
+|				;denorm/norm bias
+
+	movel	%a0,%a1		|a1 has the operand input
+	movel	EXC_EA(%a6),%a0	|a0 has the destination pointer
+	
+	bsrl	dest_dbl	|store the result
+	oril	#unfinx_mask,USER_FPSR(%a6)
+	bra	mvout_end
+
+|
+| Handle catastrophic overflow cases here
+|
+sp_over:
+| Temp fix for z bit set in unf_sub
+	movel	USER_FPSR(%a6),-(%a7)
+
+	movel	#1,%d0
+	leal	FP_SCR1(%a6),%a0	|use FP_SCR1 for creating result
+	movel	ETEMP_EX(%a6),(%a0)
+	movel	ETEMP_HI(%a6),4(%a0)
+	movel	ETEMP_LO(%a6),8(%a0)
+	bsrl	ovf_res
+
+	movel	(%a7)+,USER_FPSR(%a6)
+
+	movel	%a0,%a1
+	movel	EXC_EA(%a6),%a0
+	bsrl	dest_sgl
+	orl	#ovfinx_mask,USER_FPSR(%a6)
+	bra	mvout_end
+
+dp_over:
+| Temp fix for z bit set in ovf_res
+	movel	USER_FPSR(%a6),-(%a7)
+
+	movel	#2,%d0
+	leal	FP_SCR1(%a6),%a0	|use FP_SCR1 for creating result
+	movel	ETEMP_EX(%a6),(%a0)
+	movel	ETEMP_HI(%a6),4(%a0)
+	movel	ETEMP_LO(%a6),8(%a0)
+	bsrl	ovf_res
+
+	movel	(%a7)+,USER_FPSR(%a6)
+
+	movel	%a0,%a1
+	movel	EXC_EA(%a6),%a0
+	bsrl	dest_dbl
+	orl	#ovfinx_mask,USER_FPSR(%a6)
+	bra	mvout_end
+
+|
+| 	DPSPDNRM
+|
+| This subroutine takes an extended normalized number and denormalizes
+| it to the given round precision. This subroutine also decrements
+| the input operand's exponent by 1 to account for the fact that
+| dest_sgl or dest_dbl expects a normalized number's bias.
+|
+| Input: a0  points to a normalized number in internal extended format
+|	 d0  is the round precision (=1 for sgl; =2 for dbl)
+|	 d1  is the the single precision or double precision
+|	     denorm threshold
+|
+| Output: (In the format for dest_sgl or dest_dbl)
+|	 a0   points to the destination
+|   	 a1   points to the operand
+|
+| Exceptions: Reports inexact 2 exception by setting USER_FPSR bits
+|
+dpspdnrm:
+	movel	%d0,-(%a7)	|save round precision
+	clrl	%d0		|clear initial g,r,s
+	bsrl	dnrm_lp		|careful with d0, it's needed by round
+
+	bfextu	FPCR_MODE(%a6){#2:#2},%d1 |get rounding mode
+	swap	%d1
+	movew	2(%a7),%d1	|set rounding precision 
+	swap	%d1		|at this point d1 has PREC/MODE info
+	bsrl	round		|round result, sets the inex bit in
+|				;USER_FPSR if needed
+
+	movew	#1,%d0
+	subw	%d0,LOCAL_EX(%a0) |account for difference in denorm
+|				;vs norm bias
+
+	movel	%a0,%a1		|a1 has the operand input
+	movel	EXC_EA(%a6),%a0	|a0 has the destination pointer
+	addw	#4,%a7		|pop stack
+	rts
+|
+| SET_XOP initialized WBTEMP with the value pointed to by a0
+| input: a0 points to input operand in the internal extended format
+|
+set_xop:
+	movel	LOCAL_EX(%a0),WBTEMP_EX(%a6)
+	movel	LOCAL_HI(%a0),WBTEMP_HI(%a6)
+	movel	LOCAL_LO(%a0),WBTEMP_LO(%a6)
+	bfclr	WBTEMP_SGN(%a6){#0:#8}
+	beqs	sxop
+	bsetb	#sign_bit,WBTEMP_EX(%a6)
+sxop:
+	bfclr	STAG(%a6){#5:#4}	|clear wbtm66,wbtm1,wbtm0,sbit
+	rts
+|
+|	P_MOVE
+|
+p_movet:
+	.long	p_move
+	.long	p_movez
+	.long	p_movei
+	.long	p_moven
+	.long	p_move
+p_regd:
+	.long	p_dyd0
+	.long	p_dyd1
+	.long	p_dyd2
+	.long	p_dyd3
+	.long	p_dyd4
+	.long	p_dyd5
+	.long	p_dyd6
+	.long	p_dyd7
+
+pack_out:
+ 	leal	p_movet,%a0	|load jmp table address
+	movew	STAG(%a6),%d0	|get source tag
+	bfextu	%d0{#16:#3},%d0	|isolate source bits
+	movel	(%a0,%d0.w*4),%a0	|load a0 with routine label for tag
+	jmp	(%a0)		|go to the routine
+
+p_write:
+	movel	#0x0c,%d0 	|get byte count
+	movel	EXC_EA(%a6),%a1	|get the destination address
+	bsr 	mem_write	|write the user's destination
+	moveb	#0,CU_SAVEPC(%a6) |set the cu save pc to all 0's
+
+|
+| Also note that the dtag must be set to norm here - this is because 
+| the 040 uses the dtag to execute the correct microcode.
+|
+        bfclr    DTAG(%a6){#0:#3}  |set dtag to norm
+
+	rts
+
+| Notes on handling of special case (zero, inf, and nan) inputs:
+|	1. Operr is not signalled if the k-factor is greater than 18.
+|	2. Per the manual, status bits are not set.
+|
+
+p_move:
+	movew	CMDREG1B(%a6),%d0
+	btstl	#kfact_bit,%d0	|test for dynamic k-factor
+	beqs	statick		|if clear, k-factor is static
+dynamick:
+	bfextu	%d0{#25:#3},%d0	|isolate register for dynamic k-factor
+	lea	p_regd,%a0
+	movel	%a0@(%d0:l:4),%a0
+	jmp	(%a0)
+statick:
+	andiw	#0x007f,%d0	|get k-factor
+	bfexts	%d0{#25:#7},%d0	|sign extend d0 for bindec
+	leal	ETEMP(%a6),%a0	|a0 will point to the packed decimal
+	bsrl	bindec		|perform the convert; data at a6
+	leal	FP_SCR1(%a6),%a0	|load a0 with result address
+	bral	p_write
+p_movez:
+	leal	ETEMP(%a6),%a0	|a0 will point to the packed decimal
+	clrw	2(%a0)		|clear lower word of exp
+	clrl	4(%a0)		|load second lword of ZERO
+	clrl	8(%a0)		|load third lword of ZERO
+	bra	p_write		|go write results
+p_movei:
+	fmovel	#0,%FPSR		|clear aiop
+	leal	ETEMP(%a6),%a0	|a0 will point to the packed decimal
+	clrw	2(%a0)		|clear lower word of exp
+	bra	p_write		|go write the result
+p_moven:
+	leal	ETEMP(%a6),%a0	|a0 will point to the packed decimal
+	clrw	2(%a0)		|clear lower word of exp
+	bra	p_write		|go write the result
+
+|
+| Routines to read the dynamic k-factor from Dn.
+|
+p_dyd0:
+	movel	USER_D0(%a6),%d0
+	bras	statick
+p_dyd1:
+	movel	USER_D1(%a6),%d0
+	bras	statick
+p_dyd2:
+	movel	%d2,%d0
+	bras	statick
+p_dyd3:
+	movel	%d3,%d0
+	bras	statick
+p_dyd4:
+	movel	%d4,%d0
+	bras	statick
+p_dyd5:
+	movel	%d5,%d0
+	bras	statick
+p_dyd6:
+	movel	%d6,%d0
+	bra	statick
+p_dyd7:
+	movel	%d7,%d0
+	bra	statick
+
+	|end
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/fpsp040/round.S linux/arch/m68k/fpsp040/round.S
--- v1.3.93/linux/arch/m68k/fpsp040/round.S	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/fpsp040/round.S	Sat Feb 24 22:58:43 1996
@@ -0,0 +1,649 @@
+|
+|	round.sa 3.4 7/29/91
+|
+|	handle rounding and normalization tasks
+|
+|
+|
+|		Copyright (C) Motorola, Inc. 1990
+|			All Rights Reserved
+|
+|	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA 
+|	The copyright notice above does not evidence any  
+|	actual or intended publication of such source code.
+
+|ROUND	idnt    2,1 | Motorola 040 Floating Point Software Package
+
+	|section	8
+
+	.include "fpsp.h"
+
+|
+|	round --- round result according to precision/mode
+|
+|	a0 points to the input operand in the internal extended format 
+|	d1(high word) contains rounding precision:
+|		ext = $0000xxxx
+|		sgl = $0001xxxx
+|		dbl = $0002xxxx
+|	d1(low word) contains rounding mode:
+|		RN  = $xxxx0000
+|		RZ  = $xxxx0001
+|		RM  = $xxxx0010
+|		RP  = $xxxx0011
+|	d0{31:29} contains the g,r,s bits (extended)
+|
+|	On return the value pointed to by a0 is correctly rounded,
+|	a0 is preserved and the g-r-s bits in d0 are cleared.
+|	The result is not typed - the tag field is invalid.  The
+|	result is still in the internal extended format.
+|
+|	The INEX bit of USER_FPSR will be set if the rounded result was
+|	inexact (i.e. if any of the g-r-s bits were set).
+|
+
+	.global	round
+round:
+| If g=r=s=0 then result is exact and round is done, else set 
+| the inex flag in status reg and continue.  
+|
+	bsrs	ext_grs			|this subroutine looks at the 
+|					:rounding precision and sets 
+|					;the appropriate g-r-s bits.
+	tstl	%d0			|if grs are zero, go force
+	bne	rnd_cont		|lower bits to zero for size
+	
+	swap	%d1			|set up d1.w for round prec.
+	bra	truncate
+
+rnd_cont:
+|
+| Use rounding mode as an index into a jump table for these modes.
+|
+	orl	#inx2a_mask,USER_FPSR(%a6) |set inex2/ainex
+	lea	mode_tab,%a1
+	movel	(%a1,%d1.w*4),%a1
+	jmp	(%a1)
+|
+| Jump table indexed by rounding mode in d1.w.  All following assumes
+| grs != 0.
+|
+mode_tab:
+	.long	rnd_near
+	.long	rnd_zero
+	.long	rnd_mnus
+	.long	rnd_plus
+|
+|	ROUND PLUS INFINITY
+|
+|	If sign of fp number = 0 (positive), then add 1 to l.
+|
+rnd_plus:
+	swap 	%d1			|set up d1 for round prec.
+	tstb	LOCAL_SGN(%a0)		|check for sign
+	bmi	truncate		|if positive then truncate
+	movel	#0xffffffff,%d0		|force g,r,s to be all f's
+	lea	add_to_l,%a1
+	movel	(%a1,%d1.w*4),%a1
+	jmp	(%a1)
+|
+|	ROUND MINUS INFINITY
+|
+|	If sign of fp number = 1 (negative), then add 1 to l.
+|
+rnd_mnus:
+	swap 	%d1			|set up d1 for round prec.
+	tstb	LOCAL_SGN(%a0)		|check for sign	
+	bpl	truncate		|if negative then truncate
+	movel	#0xffffffff,%d0		|force g,r,s to be all f's
+	lea	add_to_l,%a1
+	movel	(%a1,%d1.w*4),%a1
+	jmp	(%a1)
+|
+|	ROUND ZERO
+|
+|	Always truncate.
+rnd_zero:
+	swap 	%d1			|set up d1 for round prec.
+	bra	truncate
+|
+|
+|	ROUND NEAREST
+|
+|	If (g=1), then add 1 to l and if (r=s=0), then clear l
+|	Note that this will round to even in case of a tie.
+|
+rnd_near:
+	swap 	%d1			|set up d1 for round prec.
+	asll	#1,%d0			|shift g-bit to c-bit
+	bcc	truncate		|if (g=1) then
+	lea	add_to_l,%a1
+	movel	(%a1,%d1.w*4),%a1
+	jmp	(%a1)
+
+|
+|	ext_grs --- extract guard, round and sticky bits
+|
+| Input:	d1 =		PREC:ROUND
+| Output:  	d0{31:29}=	guard, round, sticky
+|
+| The ext_grs extract the guard/round/sticky bits according to the
+| selected rounding precision. It is called by the round subroutine
+| only.  All registers except d0 are kept intact. d0 becomes an 
+| updated guard,round,sticky in d0{31:29}
+|
+| Notes: the ext_grs uses the round PREC, and therefore has to swap d1
+|	 prior to usage, and needs to restore d1 to original.
+|
+ext_grs:
+	swap	%d1			|have d1.w point to round precision
+	cmpiw	#0,%d1
+	bnes	sgl_or_dbl
+	bras	end_ext_grs
+ 
+sgl_or_dbl:
+	moveml	%d2/%d3,-(%a7)		|make some temp registers
+	cmpiw	#1,%d1
+	bnes	grs_dbl
+grs_sgl:
+	bfextu	LOCAL_HI(%a0){#24:#2},%d3	|sgl prec. g-r are 2 bits right
+	movel	#30,%d2			|of the sgl prec. limits
+	lsll	%d2,%d3			|shift g-r bits to MSB of d3
+	movel	LOCAL_HI(%a0),%d2		|get word 2 for s-bit test
+	andil	#0x0000003f,%d2		|s bit is the or of all other 
+	bnes	st_stky			|bits to the right of g-r
+	tstl	LOCAL_LO(%a0)		|test lower mantissa
+	bnes	st_stky			|if any are set, set sticky
+	tstl	%d0			|test original g,r,s
+	bnes	st_stky			|if any are set, set sticky
+	bras	end_sd			|if words 3 and 4 are clr, exit
+grs_dbl:    
+	bfextu	LOCAL_LO(%a0){#21:#2},%d3	|dbl-prec. g-r are 2 bits right
+	movel	#30,%d2			|of the dbl prec. limits
+	lsll	%d2,%d3			|shift g-r bits to the MSB of d3
+	movel	LOCAL_LO(%a0),%d2		|get lower mantissa  for s-bit test
+	andil	#0x000001ff,%d2		|s bit is the or-ing of all 
+	bnes	st_stky			|other bits to the right of g-r
+	tstl	%d0			|test word original g,r,s
+	bnes	st_stky			|if any are set, set sticky
+	bras	end_sd			|if clear, exit
+st_stky:
+	bset	#rnd_stky_bit,%d3
+end_sd:
+	movel	%d3,%d0			|return grs to d0
+	moveml	(%a7)+,%d2/%d3		|restore scratch registers
+end_ext_grs:
+	swap	%d1			|restore d1 to original
+	rts
+
+|*******************  Local Equates
+	.set	ad_1_sgl,0x00000100	|  constant to add 1 to l-bit in sgl prec
+	.set	ad_1_dbl,0x00000800	|  constant to add 1 to l-bit in dbl prec
+
+
+|Jump table for adding 1 to the l-bit indexed by rnd prec
+
+add_to_l:
+	.long	add_ext
+	.long	add_sgl
+	.long	add_dbl
+	.long	add_dbl
+|
+|	ADD SINGLE
+|
+add_sgl:
+	addl	#ad_1_sgl,LOCAL_HI(%a0)
+	bccs	scc_clr			|no mantissa overflow
+	roxrw  LOCAL_HI(%a0)		|shift v-bit back in
+	roxrw  LOCAL_HI+2(%a0)		|shift v-bit back in
+	addw	#0x1,LOCAL_EX(%a0)	|and incr exponent
+scc_clr:
+	tstl	%d0			|test for rs = 0
+	bnes	sgl_done
+	andiw  #0xfe00,LOCAL_HI+2(%a0)	|clear the l-bit
+sgl_done:
+	andil	#0xffffff00,LOCAL_HI(%a0) |truncate bits beyond sgl limit
+	clrl	LOCAL_LO(%a0)		|clear d2
+	rts
+
+|
+|	ADD EXTENDED
+|
+add_ext:
+	addql  #1,LOCAL_LO(%a0)		|add 1 to l-bit
+	bccs	xcc_clr			|test for carry out
+	addql  #1,LOCAL_HI(%a0)		|propogate carry
+	bccs	xcc_clr
+	roxrw  LOCAL_HI(%a0)		|mant is 0 so restore v-bit
+	roxrw  LOCAL_HI+2(%a0)		|mant is 0 so restore v-bit
+	roxrw	LOCAL_LO(%a0)
+	roxrw	LOCAL_LO+2(%a0)
+	addw	#0x1,LOCAL_EX(%a0)	|and inc exp
+xcc_clr:
+	tstl	%d0			|test rs = 0
+	bnes	add_ext_done
+	andib	#0xfe,LOCAL_LO+3(%a0)	|clear the l bit
+add_ext_done:
+	rts
+|
+|	ADD DOUBLE
+|
+add_dbl:
+	addl	#ad_1_dbl,LOCAL_LO(%a0)
+	bccs	dcc_clr
+	addql	#1,LOCAL_HI(%a0)		|propogate carry
+	bccs	dcc_clr
+	roxrw	LOCAL_HI(%a0)		|mant is 0 so restore v-bit
+	roxrw	LOCAL_HI+2(%a0)		|mant is 0 so restore v-bit
+	roxrw	LOCAL_LO(%a0)
+	roxrw	LOCAL_LO+2(%a0)
+	addw	#0x1,LOCAL_EX(%a0)	|incr exponent
+dcc_clr:
+	tstl	%d0			|test for rs = 0
+	bnes	dbl_done
+	andiw	#0xf000,LOCAL_LO+2(%a0)	|clear the l-bit
+
+dbl_done:
+	andil	#0xfffff800,LOCAL_LO(%a0) |truncate bits beyond dbl limit
+	rts
+
+error:
+	rts
+|
+| Truncate all other bits
+|
+trunct:
+	.long	end_rnd
+	.long	sgl_done
+	.long	dbl_done
+	.long	dbl_done
+
+truncate:
+	lea	trunct,%a1
+	movel	(%a1,%d1.w*4),%a1
+	jmp	(%a1)
+
+end_rnd:
+	rts
+
+|
+|	NORMALIZE
+|
+| These routines (nrm_zero & nrm_set) normalize the unnorm.  This 
+| is done by shifting the mantissa left while decrementing the 
+| exponent.
+|
+| NRM_SET shifts and decrements until there is a 1 set in the integer 
+| bit of the mantissa (msb in d1).
+|
+| NRM_ZERO shifts and decrements until there is a 1 set in the integer 
+| bit of the mantissa (msb in d1) unless this would mean the exponent 
+| would go less than 0.  In that case the number becomes a denorm - the 
+| exponent (d0) is set to 0 and the mantissa (d1 & d2) is not 
+| normalized.
+|
+| Note that both routines have been optimized (for the worst case) and 
+| therefore do not have the easy to follow decrement/shift loop.
+|
+|	NRM_ZERO
+|
+|	Distance to first 1 bit in mantissa = X
+|	Distance to 0 from exponent = Y
+|	If X < Y
+|	Then
+|	  nrm_set
+|	Else
+|	  shift mantissa by Y
+|	  set exponent = 0
+|
+|input:
+|	FP_SCR1 = exponent, ms mantissa part, ls mantissa part
+|output:
+|	L_SCR1{4} = fpte15 or ete15 bit
+|
+	.global	nrm_zero
+nrm_zero:
+	movew	LOCAL_EX(%a0),%d0
+	cmpw   #64,%d0          |see if exp > 64 
+	bmis	d0_less
+	bsr	nrm_set		|exp > 64 so exp won't exceed 0 
+	rts
+d0_less:
+	moveml	%d2/%d3/%d5/%d6,-(%a7)
+	movel	LOCAL_HI(%a0),%d1
+	movel	LOCAL_LO(%a0),%d2
+
+	bfffo	%d1{#0:#32},%d3	|get the distance to the first 1 
+|				;in ms mant
+	beqs	ms_clr		|branch if no bits were set
+	cmpw	%d3,%d0		|of X>Y
+	bmis	greater		|then exp will go past 0 (neg) if 
+|				;it is just shifted
+	bsr	nrm_set		|else exp won't go past 0
+	moveml	(%a7)+,%d2/%d3/%d5/%d6
+	rts	
+greater:
+	movel	%d2,%d6		|save ls mant in d6
+	lsll	%d0,%d2		|shift ls mant by count
+	lsll	%d0,%d1		|shift ms mant by count
+	movel	#32,%d5
+	subl	%d0,%d5		|make op a denorm by shifting bits 
+	lsrl	%d5,%d6		|by the number in the exp, then 
+|				;set exp = 0.
+	orl	%d6,%d1		|shift the ls mant bits into the ms mant
+	movel	#0,%d0		|same as if decremented exp to 0 
+|				;while shifting
+	movew	%d0,LOCAL_EX(%a0)
+	movel	%d1,LOCAL_HI(%a0)
+	movel	%d2,LOCAL_LO(%a0)
+	moveml	(%a7)+,%d2/%d3/%d5/%d6
+	rts
+ms_clr:
+	bfffo	%d2{#0:#32},%d3	|check if any bits set in ls mant
+	beqs	all_clr		|branch if none set
+	addw	#32,%d3
+	cmpw	%d3,%d0		|if X>Y
+	bmis	greater		|then branch
+	bsr	nrm_set		|else exp won't go past 0
+	moveml	(%a7)+,%d2/%d3/%d5/%d6
+	rts
+all_clr:
+	movew	#0,LOCAL_EX(%a0)	|no mantissa bits set. Set exp = 0.
+	moveml	(%a7)+,%d2/%d3/%d5/%d6
+	rts
+|
+|	NRM_SET
+|
+	.global	nrm_set
+nrm_set:
+	movel	%d7,-(%a7)
+	bfffo	LOCAL_HI(%a0){#0:#32},%d7 |find first 1 in ms mant to d7)
+	beqs	lower		|branch if ms mant is all 0's
+
+	movel	%d6,-(%a7)
+
+	subw	%d7,LOCAL_EX(%a0)	|sub exponent by count
+	movel	LOCAL_HI(%a0),%d0	|d0 has ms mant
+	movel	LOCAL_LO(%a0),%d1 |d1 has ls mant
+
+	lsll	%d7,%d0		|shift first 1 to j bit position
+	movel	%d1,%d6		|copy ls mant into d6
+	lsll	%d7,%d6		|shift ls mant by count
+	movel	%d6,LOCAL_LO(%a0)	|store ls mant into memory
+	moveql	#32,%d6
+	subl	%d7,%d6		|continue shift
+	lsrl	%d6,%d1		|shift off all bits but those that will
+|				;be shifted into ms mant
+	orl	%d1,%d0		|shift the ls mant bits into the ms mant
+	movel	%d0,LOCAL_HI(%a0)	|store ms mant into memory
+	moveml	(%a7)+,%d7/%d6	|restore registers
+	rts
+
+|
+| We get here if ms mant was = 0, and we assume ls mant has bits 
+| set (otherwise this would have been tagged a zero not a denorm).
+|
+lower:
+	movew	LOCAL_EX(%a0),%d0	|d0 has exponent
+	movel	LOCAL_LO(%a0),%d1	|d1 has ls mant
+	subw	#32,%d0		|account for ms mant being all zeros
+	bfffo	%d1{#0:#32},%d7	|find first 1 in ls mant to d7)
+	subw	%d7,%d0		|subtract shift count from exp
+	lsll	%d7,%d1		|shift first 1 to integer bit in ms mant
+	movew	%d0,LOCAL_EX(%a0)	|store ms mant
+	movel	%d1,LOCAL_HI(%a0)	|store exp
+	clrl	LOCAL_LO(%a0)	|clear ls mant
+	movel	(%a7)+,%d7
+	rts
+|
+|	denorm --- denormalize an intermediate result
+|
+|	Used by underflow.
+|
+| Input: 
+|	a0	 points to the operand to be denormalized
+|		 (in the internal extended format)
+|		 
+|	d0: 	 rounding precision
+| Output:
+|	a0	 points to the denormalized result
+|		 (in the internal extended format)
+|
+|	d0 	is guard,round,sticky
+|
+| d0 comes into this routine with the rounding precision. It 
+| is then loaded with the denormalized exponent threshold for the 
+| rounding precision.
+|
+
+	.global	denorm
+denorm:
+	btstb	#6,LOCAL_EX(%a0)	|check for exponents between $7fff-$4000
+	beqs	no_sgn_ext	
+	bsetb	#7,LOCAL_EX(%a0)	|sign extend if it is so
+no_sgn_ext:
+
+	cmpib	#0,%d0		|if 0 then extended precision
+	bnes	not_ext		|else branch
+
+	clrl	%d1		|load d1 with ext threshold
+	clrl	%d0		|clear the sticky flag
+	bsr	dnrm_lp		|denormalize the number
+	tstb	%d1		|check for inex
+	beq	no_inex		|if clr, no inex
+	bras	dnrm_inex	|if set, set inex
+
+not_ext:
+	cmpil	#1,%d0		|if 1 then single precision
+	beqs	load_sgl	|else must be 2, double prec
+
+load_dbl:
+	movew	#dbl_thresh,%d1	|put copy of threshold in d1
+	movel	%d1,%d0		|copy d1 into d0
+	subw	LOCAL_EX(%a0),%d0	|diff = threshold - exp
+	cmpw	#67,%d0		|if diff > 67 (mant + grs bits)
+	bpls	chk_stky	|then branch (all bits would be 
+|				; shifted off in denorm routine)
+	clrl	%d0		|else clear the sticky flag
+	bsr	dnrm_lp		|denormalize the number
+	tstb	%d1		|check flag
+	beqs	no_inex		|if clr, no inex
+	bras	dnrm_inex	|if set, set inex
+
+load_sgl:
+	movew	#sgl_thresh,%d1	|put copy of threshold in d1
+	movel	%d1,%d0		|copy d1 into d0
+	subw	LOCAL_EX(%a0),%d0	|diff = threshold - exp
+	cmpw	#67,%d0		|if diff > 67 (mant + grs bits)
+	bpls	chk_stky	|then branch (all bits would be 
+|				; shifted off in denorm routine)
+	clrl	%d0		|else clear the sticky flag
+	bsr	dnrm_lp		|denormalize the number
+	tstb	%d1		|check flag
+	beqs	no_inex		|if clr, no inex
+	bras	dnrm_inex	|if set, set inex
+
+chk_stky:
+	tstl	LOCAL_HI(%a0)	|check for any bits set
+	bnes	set_stky
+	tstl	LOCAL_LO(%a0)	|check for any bits set
+	bnes	set_stky
+	bras	clr_mant
+set_stky:
+	orl	#inx2a_mask,USER_FPSR(%a6) |set inex2/ainex
+	movel	#0x20000000,%d0	|set sticky bit in return value
+clr_mant:
+	movew	%d1,LOCAL_EX(%a0)		|load exp with threshold
+	movel	#0,LOCAL_HI(%a0) 	|set d1 = 0 (ms mantissa)
+	movel	#0,LOCAL_LO(%a0)		|set d2 = 0 (ms mantissa)
+	rts
+dnrm_inex:
+	orl	#inx2a_mask,USER_FPSR(%a6) |set inex2/ainex
+no_inex:
+	rts
+
+|
+|	dnrm_lp --- normalize exponent/mantissa to specified threshhold
+|
+| Input:
+|	a0		points to the operand to be denormalized
+|	d0{31:29} 	initial guard,round,sticky
+|	d1{15:0}	denormalization threshold
+| Output:
+|	a0		points to the denormalized operand
+|	d0{31:29}	final guard,round,sticky
+|	d1.b		inexact flag:  all ones means inexact result
+|
+| The LOCAL_LO and LOCAL_GRS parts of the value are copied to FP_SCR2
+| so that bfext can be used to extract the new low part of the mantissa.
+| Dnrm_lp can be called with a0 pointing to ETEMP or WBTEMP and there 
+| is no LOCAL_GRS scratch word following it on the fsave frame.
+|
+	.global	dnrm_lp
+dnrm_lp:
+	movel	%d2,-(%sp)		|save d2 for temp use
+	btstb	#E3,E_BYTE(%a6)		|test for type E3 exception
+	beqs	not_E3			|not type E3 exception
+	bfextu	WBTEMP_GRS(%a6){#6:#3},%d2	|extract guard,round, sticky  bit
+	movel	#29,%d0
+	lsll	%d0,%d2			|shift g,r,s to their postions
+	movel	%d2,%d0
+not_E3:
+	movel	(%sp)+,%d2		|restore d2
+	movel	LOCAL_LO(%a0),FP_SCR2+LOCAL_LO(%a6)
+	movel	%d0,FP_SCR2+LOCAL_GRS(%a6)
+	movel	%d1,%d0			|copy the denorm threshold
+	subw	LOCAL_EX(%a0),%d1		|d1 = threshold - uns exponent
+	bles	no_lp			|d1 <= 0
+	cmpw	#32,%d1			
+	blts	case_1			|0 = d1 < 32 
+	cmpw	#64,%d1
+	blts	case_2			|32 <= d1 < 64
+	bra	case_3			|d1 >= 64
+|
+| No normalization necessary
+|
+no_lp:
+	clrb	%d1			|set no inex2 reported
+	movel	FP_SCR2+LOCAL_GRS(%a6),%d0	|restore original g,r,s
+	rts
+|
+| case (0<d1<32)
+|
+case_1:
+	movel	%d2,-(%sp)
+	movew	%d0,LOCAL_EX(%a0)		|exponent = denorm threshold
+	movel	#32,%d0
+	subw	%d1,%d0			|d0 = 32 - d1
+	bfextu	LOCAL_EX(%a0){%d0:#32},%d2
+	bfextu	%d2{%d1:%d0},%d2		|d2 = new LOCAL_HI
+	bfextu	LOCAL_HI(%a0){%d0:#32},%d1	|d1 = new LOCAL_LO
+	bfextu	FP_SCR2+LOCAL_LO(%a6){%d0:#32},%d0	|d0 = new G,R,S
+	movel	%d2,LOCAL_HI(%a0)		|store new LOCAL_HI
+	movel	%d1,LOCAL_LO(%a0)		|store new LOCAL_LO
+	clrb	%d1
+	bftst	%d0{#2:#30}	
+	beqs	c1nstky
+	bsetl	#rnd_stky_bit,%d0
+	st	%d1
+c1nstky:
+	movel	FP_SCR2+LOCAL_GRS(%a6),%d2	|restore original g,r,s
+	andil	#0xe0000000,%d2		|clear all but G,R,S
+	tstl	%d2			|test if original G,R,S are clear
+	beqs	grs_clear
+	orl	#0x20000000,%d0		|set sticky bit in d0
+grs_clear:
+	andil	#0xe0000000,%d0		|clear all but G,R,S
+	movel	(%sp)+,%d2
+	rts
+|
+| case (32<=d1<64)
+|
+case_2:
+	movel	%d2,-(%sp)
+	movew	%d0,LOCAL_EX(%a0)		|unsigned exponent = threshold
+	subw	#32,%d1			|d1 now between 0 and 32
+	movel	#32,%d0
+	subw	%d1,%d0			|d0 = 32 - d1
+	bfextu	LOCAL_EX(%a0){%d0:#32},%d2
+	bfextu	%d2{%d1:%d0},%d2		|d2 = new LOCAL_LO
+	bfextu	LOCAL_HI(%a0){%d0:#32},%d1	|d1 = new G,R,S
+	bftst	%d1{#2:#30}
+	bnes	c2_sstky		|bra if sticky bit to be set
+	bftst	FP_SCR2+LOCAL_LO(%a6){%d0:#32}
+	bnes	c2_sstky		|bra if sticky bit to be set
+	movel	%d1,%d0
+	clrb	%d1
+	bras	end_c2
+c2_sstky:
+	movel	%d1,%d0
+	bsetl	#rnd_stky_bit,%d0
+	st	%d1
+end_c2:
+	clrl	LOCAL_HI(%a0)		|store LOCAL_HI = 0
+	movel	%d2,LOCAL_LO(%a0)		|store LOCAL_LO
+	movel	FP_SCR2+LOCAL_GRS(%a6),%d2	|restore original g,r,s
+	andil	#0xe0000000,%d2		|clear all but G,R,S
+	tstl	%d2			|test if original G,R,S are clear
+	beqs	clear_grs		
+	orl	#0x20000000,%d0		|set sticky bit in d0
+clear_grs:
+	andil	#0xe0000000,%d0		|get rid of all but G,R,S
+	movel	(%sp)+,%d2
+	rts
+|
+| d1 >= 64 Force the exponent to be the denorm threshold with the
+| correct sign.
+|
+case_3:
+	movew	%d0,LOCAL_EX(%a0)
+	tstw	LOCAL_SGN(%a0)
+	bges	c3con
+c3neg:
+	orl	#0x80000000,LOCAL_EX(%a0)
+c3con:
+	cmpw	#64,%d1
+	beqs	sixty_four
+	cmpw	#65,%d1
+	beqs	sixty_five
+|
+| Shift value is out of range.  Set d1 for inex2 flag and
+| return a zero with the given threshold.
+|
+	clrl	LOCAL_HI(%a0)
+	clrl	LOCAL_LO(%a0)
+	movel	#0x20000000,%d0
+	st	%d1
+	rts
+
+sixty_four:
+	movel	LOCAL_HI(%a0),%d0
+	bfextu	%d0{#2:#30},%d1
+	andil	#0xc0000000,%d0
+	bras	c3com
+	
+sixty_five:
+	movel	LOCAL_HI(%a0),%d0
+	bfextu	%d0{#1:#31},%d1
+	andil	#0x80000000,%d0
+	lsrl	#1,%d0			|shift high bit into R bit
+
+c3com:
+	tstl	%d1
+	bnes	c3ssticky
+	tstl	LOCAL_LO(%a0)
+	bnes	c3ssticky
+	tstb	FP_SCR2+LOCAL_GRS(%a6)
+	bnes	c3ssticky
+	clrb	%d1
+	bras	c3end
+
+c3ssticky:
+	bsetl	#rnd_stky_bit,%d0
+	st	%d1
+c3end:
+	clrl	LOCAL_HI(%a0)
+	clrl	LOCAL_LO(%a0)
+	rts
+
+	|end
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/fpsp040/sacos.S linux/arch/m68k/fpsp040/sacos.S
--- v1.3.93/linux/arch/m68k/fpsp040/sacos.S	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/fpsp040/sacos.S	Sat Feb 24 22:58:43 1996
@@ -0,0 +1,115 @@
+|
+|	sacos.sa 3.3 12/19/90
+|
+|	Description: The entry point sAcos computes the inverse cosine of
+|		an input argument; sAcosd does the same except for denormalized
+|		input.
+|
+|	Input: Double-extended number X in location pointed to
+|		by address register a0.
+|
+|	Output: The value arccos(X) returned in floating-point register Fp0.
+|
+|	Accuracy and Monotonicity: The returned result is within 3 ulps in
+|		64 significant bit, i.e. within 0.5001 ulp to 53 bits if the
+|		result is subsequently rounded to double precision. The 
+|		result is provably monotonic in double precision.
+|
+|	Speed: The program sCOS takes approximately 310 cycles.
+|
+|	Algorithm:
+|
+|	ACOS
+|	1. If |X| >= 1, go to 3.
+|
+|	2. (|X| < 1) Calculate acos(X) by
+|		z := (1-X) / (1+X)
+|		acos(X) = 2 * atan( sqrt(z) ).
+|		Exit.
+|
+|	3. If |X| > 1, go to 5.
+|
+|	4. (|X| = 1) If X > 0, return 0. Otherwise, return Pi. Exit.
+|
+|	5. (|X| > 1) Generate an invalid operation by 0 * infinity.
+|		Exit.
+|
+
+|		Copyright (C) Motorola, Inc. 1990
+|			All Rights Reserved
+|
+|	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA 
+|	The copyright notice above does not evidence any  
+|	actual or intended publication of such source code.
+
+|SACOS	idnt	2,1 | Motorola 040 Floating Point Software Package
+
+	|section	8
+
+PI:	.long 0x40000000,0xC90FDAA2,0x2168C235,0x00000000
+PIBY2:	.long 0x3FFF0000,0xC90FDAA2,0x2168C235,0x00000000
+
+	|xref	t_operr
+	|xref	t_frcinx
+	|xref	satan
+
+	.global	sacosd
+sacosd:
+|--ACOS(X) = PI/2 FOR DENORMALIZED X
+	fmovel		%d1,%fpcr		| ...load user's rounding mode/precision
+	fmovex		PIBY2,%fp0
+	bra		t_frcinx
+
+	.global	sacos
+sacos:
+	fmovex		(%a0),%fp0	| ...LOAD INPUT
+
+	movel		(%a0),%d0		| ...pack exponent with upper 16 fraction
+	movew		4(%a0),%d0
+	andil		#0x7FFFFFFF,%d0
+	cmpil		#0x3FFF8000,%d0
+	bges		ACOSBIG
+
+|--THIS IS THE USUAL CASE, |X| < 1
+|--ACOS(X) = 2 * ATAN(	SQRT( (1-X)/(1+X) )	)
+
+	fmoves		#0x3F800000,%fp1
+	faddx		%fp0,%fp1	 	| ...1+X
+	fnegx		%fp0	 	| ... -X
+	fadds		#0x3F800000,%fp0	| ...1-X
+	fdivx		%fp1,%fp0	 	| ...(1-X)/(1+X)
+	fsqrtx		%fp0		| ...SQRT((1-X)/(1+X))
+	fmovemx	%fp0-%fp0,(%a0)	| ...overwrite input
+	movel		%d1,-(%sp)	|save original users fpcr
+	clrl		%d1
+	bsr		satan		| ...ATAN(SQRT([1-X]/[1+X]))
+	fmovel		(%sp)+,%fpcr	|restore users exceptions
+	faddx		%fp0,%fp0	 	| ...2 * ATAN( STUFF )
+	bra		t_frcinx
+
+ACOSBIG:
+	fabsx		%fp0
+	fcmps		#0x3F800000,%fp0
+	fbgt		t_operr		|cause an operr exception
+
+|--|X| = 1, ACOS(X) = 0 OR PI
+	movel		(%a0),%d0		| ...pack exponent with upper 16 fraction
+	movew		4(%a0),%d0
+	cmpl		#0,%d0		|D0 has original exponent+fraction
+	bgts		ACOSP1
+
+|--X = -1
+|Returns PI and inexact exception
+	fmovex		PI,%fp0
+	fmovel		%d1,%FPCR
+	fadds		#0x00800000,%fp0	|cause an inexact exception to be put
+|					;into the 040 - will not trap until next
+|					;fp inst.
+	bra		t_frcinx
+
+ACOSP1:
+	fmovel		%d1,%FPCR
+	fmoves		#0x00000000,%fp0
+	rts				|Facos ; of +1 is exact	
+
+	|end
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/fpsp040/sasin.S linux/arch/m68k/fpsp040/sasin.S
--- v1.3.93/linux/arch/m68k/fpsp040/sasin.S	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/fpsp040/sasin.S	Sat Feb 24 22:58:43 1996
@@ -0,0 +1,104 @@
+|
+|	sasin.sa 3.3 12/19/90
+|
+|	Description: The entry point sAsin computes the inverse sine of
+|		an input argument; sAsind does the same except for denormalized
+|		input.
+|
+|	Input: Double-extended number X in location pointed to
+|		by address register a0.
+|
+|	Output: The value arcsin(X) returned in floating-point register Fp0.
+|
+|	Accuracy and Monotonicity: The returned result is within 3 ulps in
+|		64 significant bit, i.e. within 0.5001 ulp to 53 bits if the
+|		result is subsequently rounded to double precision. The 
+|		result is provably monotonic in double precision.
+|
+|	Speed: The program sASIN takes approximately 310 cycles.
+|
+|	Algorithm:
+|
+|	ASIN
+|	1. If |X| >= 1, go to 3.
+|
+|	2. (|X| < 1) Calculate asin(X) by
+|		z := sqrt( [1-X][1+X] )
+|		asin(X) = atan( x / z ).
+|		Exit.
+|
+|	3. If |X| > 1, go to 5.
+|
+|	4. (|X| = 1) sgn := sign(X), return asin(X) := sgn * Pi/2. Exit.
+|
+|	5. (|X| > 1) Generate an invalid operation by 0 * infinity.
+|		Exit.
+|
+
+|		Copyright (C) Motorola, Inc. 1990
+|			All Rights Reserved
+|
+|	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA 
+|	The copyright notice above does not evidence any  
+|	actual or intended publication of such source code.
+
+|SASIN	idnt	2,1 | Motorola 040 Floating Point Software Package
+
+	|section	8
+
+PIBY2:	.long 0x3FFF0000,0xC90FDAA2,0x2168C235,0x00000000
+
+	|xref	t_operr
+	|xref	t_frcinx
+	|xref	t_extdnrm
+	|xref	satan
+
+	.global	sasind
+sasind:
+|--ASIN(X) = X FOR DENORMALIZED X
+
+	bra		t_extdnrm
+
+	.global	sasin
+sasin:
+	fmovex		(%a0),%fp0	| ...LOAD INPUT
+
+	movel		(%a0),%d0
+	movew		4(%a0),%d0
+	andil		#0x7FFFFFFF,%d0
+	cmpil		#0x3FFF8000,%d0
+	bges		asinbig
+
+|--THIS IS THE USUAL CASE, |X| < 1
+|--ASIN(X) = ATAN( X / SQRT( (1-X)(1+X) ) )
+
+	fmoves		#0x3F800000,%fp1
+	fsubx		%fp0,%fp1		| ...1-X
+	fmovemx	%fp2-%fp2,-(%a7)
+	fmoves		#0x3F800000,%fp2
+	faddx		%fp0,%fp2		| ...1+X
+	fmulx		%fp2,%fp1		| ...(1+X)(1-X)
+	fmovemx	(%a7)+,%fp2-%fp2
+	fsqrtx		%fp1		| ...SQRT([1-X][1+X])
+	fdivx		%fp1,%fp0	 	| ...X/SQRT([1-X][1+X])
+	fmovemx	%fp0-%fp0,(%a0)
+	bsr		satan
+	bra		t_frcinx
+
+asinbig:
+	fabsx		%fp0	 | ...|X|
+	fcmps		#0x3F800000,%fp0
+	fbgt		t_operr		|cause an operr exception
+
+|--|X| = 1, ASIN(X) = +- PI/2.
+
+	fmovex		PIBY2,%fp0
+	movel		(%a0),%d0
+	andil		#0x80000000,%d0	| ...SIGN BIT OF X
+	oril		#0x3F800000,%d0	| ...+-1 IN SGL FORMAT
+	movel		%d0,-(%sp)	| ...push SIGN(X) IN SGL-FMT
+	fmovel		%d1,%FPCR		
+	fmuls		(%sp)+,%fp0
+	bra		t_frcinx
+
+	|end
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/fpsp040/satan.S linux/arch/m68k/fpsp040/satan.S
--- v1.3.93/linux/arch/m68k/fpsp040/satan.S	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/fpsp040/satan.S	Sat Feb 24 22:58:43 1996
@@ -0,0 +1,478 @@
+|
+|	satan.sa 3.3 12/19/90
+|
+|	The entry point satan computes the arctagent of an
+|	input value. satand does the same except the input value is a
+|	denormalized number.
+|
+|	Input: Double-extended value in memory location pointed to by address
+|		register a0.
+|
+|	Output:	Arctan(X) returned in floating-point register Fp0.
+|
+|	Accuracy and Monotonicity: The returned result is within 2 ulps in
+|		64 significant bit, i.e. within 0.5001 ulp to 53 bits if the
+|		result is subsequently rounded to double precision. The
+|		result is provably monotonic in double precision.
+|
+|	Speed: The program satan takes approximately 160 cycles for input
+|		argument X such that 1/16 < |X| < 16. For the other arguments,
+|		the program will run no worse than 10% slower.
+|
+|	Algorithm:
+|	Step 1. If |X| >= 16 or |X| < 1/16, go to Step 5.
+|
+|	Step 2. Let X = sgn * 2**k * 1.xxxxxxxx...x. Note that k = -4, -3,..., or 3.
+|		Define F = sgn * 2**k * 1.xxxx1, i.e. the first 5 significant bits
+|		of X with a bit-1 attached at the 6-th bit position. Define u
+|		to be u = (X-F) / (1 + X*F).
+|
+|	Step 3. Approximate arctan(u) by a polynomial poly.
+|
+|	Step 4. Return arctan(F) + poly, arctan(F) is fetched from a table of values
+|		calculated beforehand. Exit.
+|
+|	Step 5. If |X| >= 16, go to Step 7.
+|
+|	Step 6. Approximate arctan(X) by an odd polynomial in X. Exit.
+|
+|	Step 7. Define X' = -1/X. Approximate arctan(X') by an odd polynomial in X'.
+|		Arctan(X) = sign(X)*Pi/2 + arctan(X'). Exit.
+|
+
+|		Copyright (C) Motorola, Inc. 1990
+|			All Rights Reserved
+|
+|	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA 
+|	The copyright notice above does not evidence any  
+|	actual or intended publication of such source code.
+
+|satan	idnt	2,1 | Motorola 040 Floating Point Software Package
+
+	|section	8
+
+	.include "fpsp.h"
+	
+BOUNDS1:	.long 0x3FFB8000,0x4002FFFF
+
+ONE:	.long 0x3F800000
+
+	.long 0x00000000
+
+ATANA3:	.long 0xBFF6687E,0x314987D8
+ATANA2:	.long 0x4002AC69,0x34A26DB3
+
+ATANA1:	.long 0xBFC2476F,0x4E1DA28E
+ATANB6:	.long 0x3FB34444,0x7F876989
+
+ATANB5:	.long 0xBFB744EE,0x7FAF45DB
+ATANB4:	.long 0x3FBC71C6,0x46940220
+
+ATANB3:	.long 0xBFC24924,0x921872F9
+ATANB2:	.long 0x3FC99999,0x99998FA9
+
+ATANB1:	.long 0xBFD55555,0x55555555
+ATANC5:	.long 0xBFB70BF3,0x98539E6A
+
+ATANC4:	.long 0x3FBC7187,0x962D1D7D
+ATANC3:	.long 0xBFC24924,0x827107B8
+
+ATANC2:	.long 0x3FC99999,0x9996263E
+ATANC1:	.long 0xBFD55555,0x55555536
+
+PPIBY2:	.long 0x3FFF0000,0xC90FDAA2,0x2168C235,0x00000000
+NPIBY2:	.long 0xBFFF0000,0xC90FDAA2,0x2168C235,0x00000000
+PTINY:	.long 0x00010000,0x80000000,0x00000000,0x00000000
+NTINY:	.long 0x80010000,0x80000000,0x00000000,0x00000000
+
+ATANTBL:
+	.long	0x3FFB0000,0x83D152C5,0x060B7A51,0x00000000
+	.long	0x3FFB0000,0x8BC85445,0x65498B8B,0x00000000
+	.long	0x3FFB0000,0x93BE4060,0x17626B0D,0x00000000
+	.long	0x3FFB0000,0x9BB3078D,0x35AEC202,0x00000000
+	.long	0x3FFB0000,0xA3A69A52,0x5DDCE7DE,0x00000000
+	.long	0x3FFB0000,0xAB98E943,0x62765619,0x00000000
+	.long	0x3FFB0000,0xB389E502,0xF9C59862,0x00000000
+	.long	0x3FFB0000,0xBB797E43,0x6B09E6FB,0x00000000
+	.long	0x3FFB0000,0xC367A5C7,0x39E5F446,0x00000000
+	.long	0x3FFB0000,0xCB544C61,0xCFF7D5C6,0x00000000
+	.long	0x3FFB0000,0xD33F62F8,0x2488533E,0x00000000
+	.long	0x3FFB0000,0xDB28DA81,0x62404C77,0x00000000
+	.long	0x3FFB0000,0xE310A407,0x8AD34F18,0x00000000
+	.long	0x3FFB0000,0xEAF6B0A8,0x188EE1EB,0x00000000
+	.long	0x3FFB0000,0xF2DAF194,0x9DBE79D5,0x00000000
+	.long	0x3FFB0000,0xFABD5813,0x61D47E3E,0x00000000
+	.long	0x3FFC0000,0x8346AC21,0x0959ECC4,0x00000000
+	.long	0x3FFC0000,0x8B232A08,0x304282D8,0x00000000
+	.long	0x3FFC0000,0x92FB70B8,0xD29AE2F9,0x00000000
+	.long	0x3FFC0000,0x9ACF476F,0x5CCD1CB4,0x00000000
+	.long	0x3FFC0000,0xA29E7630,0x4954F23F,0x00000000
+	.long	0x3FFC0000,0xAA68C5D0,0x8AB85230,0x00000000
+	.long	0x3FFC0000,0xB22DFFFD,0x9D539F83,0x00000000
+	.long	0x3FFC0000,0xB9EDEF45,0x3E900EA5,0x00000000
+	.long	0x3FFC0000,0xC1A85F1C,0xC75E3EA5,0x00000000
+	.long	0x3FFC0000,0xC95D1BE8,0x28138DE6,0x00000000
+	.long	0x3FFC0000,0xD10BF300,0x840D2DE4,0x00000000
+	.long	0x3FFC0000,0xD8B4B2BA,0x6BC05E7A,0x00000000
+	.long	0x3FFC0000,0xE0572A6B,0xB42335F6,0x00000000
+	.long	0x3FFC0000,0xE7F32A70,0xEA9CAA8F,0x00000000
+	.long	0x3FFC0000,0xEF888432,0x64ECEFAA,0x00000000
+	.long	0x3FFC0000,0xF7170A28,0xECC06666,0x00000000
+	.long	0x3FFD0000,0x812FD288,0x332DAD32,0x00000000
+	.long	0x3FFD0000,0x88A8D1B1,0x218E4D64,0x00000000
+	.long	0x3FFD0000,0x9012AB3F,0x23E4AEE8,0x00000000
+	.long	0x3FFD0000,0x976CC3D4,0x11E7F1B9,0x00000000
+	.long	0x3FFD0000,0x9EB68949,0x3889A227,0x00000000
+	.long	0x3FFD0000,0xA5EF72C3,0x4487361B,0x00000000
+	.long	0x3FFD0000,0xAD1700BA,0xF07A7227,0x00000000
+	.long	0x3FFD0000,0xB42CBCFA,0xFD37EFB7,0x00000000
+	.long	0x3FFD0000,0xBB303A94,0x0BA80F89,0x00000000
+	.long	0x3FFD0000,0xC22115C6,0xFCAEBBAF,0x00000000
+	.long	0x3FFD0000,0xC8FEF3E6,0x86331221,0x00000000
+	.long	0x3FFD0000,0xCFC98330,0xB4000C70,0x00000000
+	.long	0x3FFD0000,0xD6807AA1,0x102C5BF9,0x00000000
+	.long	0x3FFD0000,0xDD2399BC,0x31252AA3,0x00000000
+	.long	0x3FFD0000,0xE3B2A855,0x6B8FC517,0x00000000
+	.long	0x3FFD0000,0xEA2D764F,0x64315989,0x00000000
+	.long	0x3FFD0000,0xF3BF5BF8,0xBAD1A21D,0x00000000
+	.long	0x3FFE0000,0x801CE39E,0x0D205C9A,0x00000000
+	.long	0x3FFE0000,0x8630A2DA,0xDA1ED066,0x00000000
+	.long	0x3FFE0000,0x8C1AD445,0xF3E09B8C,0x00000000
+	.long	0x3FFE0000,0x91DB8F16,0x64F350E2,0x00000000
+	.long	0x3FFE0000,0x97731420,0x365E538C,0x00000000
+	.long	0x3FFE0000,0x9CE1C8E6,0xA0B8CDBA,0x00000000
+	.long	0x3FFE0000,0xA22832DB,0xCADAAE09,0x00000000
+	.long	0x3FFE0000,0xA746F2DD,0xB7602294,0x00000000
+	.long	0x3FFE0000,0xAC3EC0FB,0x997DD6A2,0x00000000
+	.long	0x3FFE0000,0xB110688A,0xEBDC6F6A,0x00000000
+	.long	0x3FFE0000,0xB5BCC490,0x59ECC4B0,0x00000000
+	.long	0x3FFE0000,0xBA44BC7D,0xD470782F,0x00000000
+	.long	0x3FFE0000,0xBEA94144,0xFD049AAC,0x00000000
+	.long	0x3FFE0000,0xC2EB4ABB,0x661628B6,0x00000000
+	.long	0x3FFE0000,0xC70BD54C,0xE602EE14,0x00000000
+	.long	0x3FFE0000,0xCD000549,0xADEC7159,0x00000000
+	.long	0x3FFE0000,0xD48457D2,0xD8EA4EA3,0x00000000
+	.long	0x3FFE0000,0xDB948DA7,0x12DECE3B,0x00000000
+	.long	0x3FFE0000,0xE23855F9,0x69E8096A,0x00000000
+	.long	0x3FFE0000,0xE8771129,0xC4353259,0x00000000
+	.long	0x3FFE0000,0xEE57C16E,0x0D379C0D,0x00000000
+	.long	0x3FFE0000,0xF3E10211,0xA87C3779,0x00000000
+	.long	0x3FFE0000,0xF919039D,0x758B8D41,0x00000000
+	.long	0x3FFE0000,0xFE058B8F,0x64935FB3,0x00000000
+	.long	0x3FFF0000,0x8155FB49,0x7B685D04,0x00000000
+	.long	0x3FFF0000,0x83889E35,0x49D108E1,0x00000000
+	.long	0x3FFF0000,0x859CFA76,0x511D724B,0x00000000
+	.long	0x3FFF0000,0x87952ECF,0xFF8131E7,0x00000000
+	.long	0x3FFF0000,0x89732FD1,0x9557641B,0x00000000
+	.long	0x3FFF0000,0x8B38CAD1,0x01932A35,0x00000000
+	.long	0x3FFF0000,0x8CE7A8D8,0x301EE6B5,0x00000000
+	.long	0x3FFF0000,0x8F46A39E,0x2EAE5281,0x00000000
+	.long	0x3FFF0000,0x922DA7D7,0x91888487,0x00000000
+	.long	0x3FFF0000,0x94D19FCB,0xDEDF5241,0x00000000
+	.long	0x3FFF0000,0x973AB944,0x19D2A08B,0x00000000
+	.long	0x3FFF0000,0x996FF00E,0x08E10B96,0x00000000
+	.long	0x3FFF0000,0x9B773F95,0x12321DA7,0x00000000
+	.long	0x3FFF0000,0x9D55CC32,0x0F935624,0x00000000
+	.long	0x3FFF0000,0x9F100575,0x006CC571,0x00000000
+	.long	0x3FFF0000,0xA0A9C290,0xD97CC06C,0x00000000
+	.long	0x3FFF0000,0xA22659EB,0xEBC0630A,0x00000000
+	.long	0x3FFF0000,0xA388B4AF,0xF6EF0EC9,0x00000000
+	.long	0x3FFF0000,0xA4D35F10,0x61D292C4,0x00000000
+	.long	0x3FFF0000,0xA60895DC,0xFBE3187E,0x00000000
+	.long	0x3FFF0000,0xA72A51DC,0x7367BEAC,0x00000000
+	.long	0x3FFF0000,0xA83A5153,0x0956168F,0x00000000
+	.long	0x3FFF0000,0xA93A2007,0x7539546E,0x00000000
+	.long	0x3FFF0000,0xAA9E7245,0x023B2605,0x00000000
+	.long	0x3FFF0000,0xAC4C84BA,0x6FE4D58F,0x00000000
+	.long	0x3FFF0000,0xADCE4A4A,0x606B9712,0x00000000
+	.long	0x3FFF0000,0xAF2A2DCD,0x8D263C9C,0x00000000
+	.long	0x3FFF0000,0xB0656F81,0xF22265C7,0x00000000
+	.long	0x3FFF0000,0xB1846515,0x0F71496A,0x00000000
+	.long	0x3FFF0000,0xB28AAA15,0x6F9ADA35,0x00000000
+	.long	0x3FFF0000,0xB37B44FF,0x3766B895,0x00000000
+	.long	0x3FFF0000,0xB458C3DC,0xE9630433,0x00000000
+	.long	0x3FFF0000,0xB525529D,0x562246BD,0x00000000
+	.long	0x3FFF0000,0xB5E2CCA9,0x5F9D88CC,0x00000000
+	.long	0x3FFF0000,0xB692CADA,0x7ACA1ADA,0x00000000
+	.long	0x3FFF0000,0xB736AEA7,0xA6925838,0x00000000
+	.long	0x3FFF0000,0xB7CFAB28,0x7E9F7B36,0x00000000
+	.long	0x3FFF0000,0xB85ECC66,0xCB219835,0x00000000
+	.long	0x3FFF0000,0xB8E4FD5A,0x20A593DA,0x00000000
+	.long	0x3FFF0000,0xB99F41F6,0x4AFF9BB5,0x00000000
+	.long	0x3FFF0000,0xBA7F1E17,0x842BBE7B,0x00000000
+	.long	0x3FFF0000,0xBB471285,0x7637E17D,0x00000000
+	.long	0x3FFF0000,0xBBFABE8A,0x4788DF6F,0x00000000
+	.long	0x3FFF0000,0xBC9D0FAD,0x2B689D79,0x00000000
+	.long	0x3FFF0000,0xBD306A39,0x471ECD86,0x00000000
+	.long	0x3FFF0000,0xBDB6C731,0x856AF18A,0x00000000
+	.long	0x3FFF0000,0xBE31CAC5,0x02E80D70,0x00000000
+	.long	0x3FFF0000,0xBEA2D55C,0xE33194E2,0x00000000
+	.long	0x3FFF0000,0xBF0B10B7,0xC03128F0,0x00000000
+	.long	0x3FFF0000,0xBF6B7A18,0xDACB778D,0x00000000
+	.long	0x3FFF0000,0xBFC4EA46,0x63FA18F6,0x00000000
+	.long	0x3FFF0000,0xC0181BDE,0x8B89A454,0x00000000
+	.long	0x3FFF0000,0xC065B066,0xCFBF6439,0x00000000
+	.long	0x3FFF0000,0xC0AE345F,0x56340AE6,0x00000000
+	.long	0x3FFF0000,0xC0F22291,0x9CB9E6A7,0x00000000
+
+	.set	X,FP_SCR1
+	.set	XDCARE,X+2
+	.set	XFRAC,X+4
+	.set	XFRACLO,X+8
+
+	.set	ATANF,FP_SCR2
+	.set	ATANFHI,ATANF+4
+	.set	ATANFLO,ATANF+8
+
+
+	| xref	t_frcinx
+	|xref	t_extdnrm
+
+	.global	satand
+satand:
+|--ENTRY POINT FOR ATAN(X) FOR DENORMALIZED ARGUMENT
+
+	bra		t_extdnrm
+
+	.global	satan
+satan:
+|--ENTRY POINT FOR ATAN(X), HERE X IS FINITE, NON-ZERO, AND NOT NAN'S
+
+	fmovex		(%a0),%fp0	| ...LOAD INPUT
+
+	movel		(%a0),%d0
+	movew		4(%a0),%d0
+	fmovex		%fp0,X(%a6)
+	andil		#0x7FFFFFFF,%d0
+
+	cmpil		#0x3FFB8000,%d0		| ...|X| >= 1/16?
+	bges		ATANOK1
+	bra		ATANSM
+
+ATANOK1:
+	cmpil		#0x4002FFFF,%d0		| ...|X| < 16 ?
+	bles		ATANMAIN
+	bra		ATANBIG
+
+
+|--THE MOST LIKELY CASE, |X| IN [1/16, 16). WE USE TABLE TECHNIQUE
+|--THE IDEA IS ATAN(X) = ATAN(F) + ATAN( [X-F] / [1+XF] ).
+|--SO IF F IS CHOSEN TO BE CLOSE TO X AND ATAN(F) IS STORED IN
+|--A TABLE, ALL WE NEED IS TO APPROXIMATE ATAN(U) WHERE
+|--U = (X-F)/(1+XF) IS SMALL (REMEMBER F IS CLOSE TO X). IT IS
+|--TRUE THAT A DIVIDE IS NOW NEEDED, BUT THE APPROXIMATION FOR
+|--ATAN(U) IS A VERY SHORT POLYNOMIAL AND THE INDEXING TO
+|--FETCH F AND SAVING OF REGISTERS CAN BE ALL HIDED UNDER THE
+|--DIVIDE. IN THE END THIS METHOD IS MUCH FASTER THAN A TRADITIONAL
+|--ONE. NOTE ALSO THAT THE TRADITIONAL SCHEME THAT APPROXIMATE
+|--ATAN(X) DIRECTLY WILL NEED TO USE A RATIONAL APPROXIMATION
+|--(DIVISION NEEDED) ANYWAY BECAUSE A POLYNOMIAL APPROXIMATION
+|--WILL INVOLVE A VERY LONG POLYNOMIAL.
+
+|--NOW WE SEE X AS +-2^K * 1.BBBBBBB....B <- 1. + 63 BITS
+|--WE CHOSE F TO BE +-2^K * 1.BBBB1
+|--THAT IS IT MATCHES THE EXPONENT AND FIRST 5 BITS OF X, THE
+|--SIXTH BITS IS SET TO BE 1. SINCE K = -4, -3, ..., 3, THERE
+|--ARE ONLY 8 TIMES 16 = 2^7 = 128 |F|'S. SINCE ATAN(-|F|) IS
+|-- -ATAN(|F|), WE NEED TO STORE ONLY ATAN(|F|).
+
+ATANMAIN:
+
+	movew		#0x0000,XDCARE(%a6)	| ...CLEAN UP X JUST IN CASE
+	andil		#0xF8000000,XFRAC(%a6)	| ...FIRST 5 BITS
+	oril		#0x04000000,XFRAC(%a6)	| ...SET 6-TH BIT TO 1
+	movel		#0x00000000,XFRACLO(%a6)	| ...LOCATION OF X IS NOW F
+
+	fmovex		%fp0,%fp1			| ...FP1 IS X
+	fmulx		X(%a6),%fp1		| ...FP1 IS X*F, NOTE THAT X*F > 0
+	fsubx		X(%a6),%fp0		| ...FP0 IS X-F
+	fadds		#0x3F800000,%fp1		| ...FP1 IS 1 + X*F
+	fdivx		%fp1,%fp0			| ...FP0 IS U = (X-F)/(1+X*F)
+
+|--WHILE THE DIVISION IS TAKING ITS TIME, WE FETCH ATAN(|F|)
+|--CREATE ATAN(F) AND STORE IT IN ATANF, AND
+|--SAVE REGISTERS FP2.
+
+	movel		%d2,-(%a7)	| ...SAVE d2 TEMPORARILY
+	movel		%d0,%d2		| ...THE EXPO AND 16 BITS OF X
+	andil		#0x00007800,%d0	| ...4 VARYING BITS OF F'S FRACTION
+	andil		#0x7FFF0000,%d2	| ...EXPONENT OF F
+	subil		#0x3FFB0000,%d2	| ...K+4
+	asrl		#1,%d2
+	addl		%d2,%d0		| ...THE 7 BITS IDENTIFYING F
+	asrl		#7,%d0		| ...INDEX INTO TBL OF ATAN(|F|)
+	lea		ATANTBL,%a1
+	addal		%d0,%a1		| ...ADDRESS OF ATAN(|F|)
+	movel		(%a1)+,ATANF(%a6)
+	movel		(%a1)+,ATANFHI(%a6)
+	movel		(%a1)+,ATANFLO(%a6)	| ...ATANF IS NOW ATAN(|F|)
+	movel		X(%a6),%d0		| ...LOAD SIGN AND EXPO. AGAIN
+	andil		#0x80000000,%d0	| ...SIGN(F)
+	orl		%d0,ATANF(%a6)	| ...ATANF IS NOW SIGN(F)*ATAN(|F|)
+	movel		(%a7)+,%d2	| ...RESTORE d2
+
+|--THAT'S ALL I HAVE TO DO FOR NOW,
+|--BUT ALAS, THE DIVIDE IS STILL CRANKING!
+
+|--U IN FP0, WE ARE NOW READY TO COMPUTE ATAN(U) AS
+|--U + A1*U*V*(A2 + V*(A3 + V)), V = U*U
+|--THE POLYNOMIAL MAY LOOK STRANGE, BUT IS NEVERTHELESS CORRECT.
+|--THE NATURAL FORM IS U + U*V*(A1 + V*(A2 + V*A3))
+|--WHAT WE HAVE HERE IS MERELY	A1 = A3, A2 = A1/A3, A3 = A2/A3.
+|--THE REASON FOR THIS REARRANGEMENT IS TO MAKE THE INDEPENDENT
+|--PARTS A1*U*V AND (A2 + ... STUFF) MORE LOAD-BALANCED
+
+	
+	fmovex		%fp0,%fp1
+	fmulx		%fp1,%fp1
+	fmoved		ATANA3,%fp2
+	faddx		%fp1,%fp2		| ...A3+V
+	fmulx		%fp1,%fp2		| ...V*(A3+V)
+	fmulx		%fp0,%fp1		| ...U*V
+	faddd		ATANA2,%fp2	| ...A2+V*(A3+V)
+	fmuld		ATANA1,%fp1	| ...A1*U*V
+	fmulx		%fp2,%fp1		| ...A1*U*V*(A2+V*(A3+V))
+	
+	faddx		%fp1,%fp0		| ...ATAN(U), FP1 RELEASED
+	fmovel		%d1,%FPCR		|restore users exceptions
+	faddx		ATANF(%a6),%fp0	| ...ATAN(X)
+	bra		t_frcinx
+
+ATANBORS:
+|--|X| IS IN d0 IN COMPACT FORM. FP1, d0 SAVED.
+|--FP0 IS X AND |X| <= 1/16 OR |X| >= 16.
+	cmpil		#0x3FFF8000,%d0
+	bgt		ATANBIG	| ...I.E. |X| >= 16
+
+ATANSM:
+|--|X| <= 1/16
+|--IF |X| < 2^(-40), RETURN X AS ANSWER. OTHERWISE, APPROXIMATE
+|--ATAN(X) BY X + X*Y*(B1+Y*(B2+Y*(B3+Y*(B4+Y*(B5+Y*B6)))))
+|--WHICH IS X + X*Y*( [B1+Z*(B3+Z*B5)] + [Y*(B2+Z*(B4+Z*B6)] )
+|--WHERE Y = X*X, AND Z = Y*Y.
+
+	cmpil		#0x3FD78000,%d0
+	blt		ATANTINY
+|--COMPUTE POLYNOMIAL
+	fmulx		%fp0,%fp0	| ...FP0 IS Y = X*X
+
+	
+	movew		#0x0000,XDCARE(%a6)
+
+	fmovex		%fp0,%fp1
+	fmulx		%fp1,%fp1		| ...FP1 IS Z = Y*Y
+
+	fmoved		ATANB6,%fp2
+	fmoved		ATANB5,%fp3
+
+	fmulx		%fp1,%fp2		| ...Z*B6
+	fmulx		%fp1,%fp3		| ...Z*B5
+
+	faddd		ATANB4,%fp2	| ...B4+Z*B6
+	faddd		ATANB3,%fp3	| ...B3+Z*B5
+
+	fmulx		%fp1,%fp2		| ...Z*(B4+Z*B6)
+	fmulx		%fp3,%fp1		| ...Z*(B3+Z*B5)
+
+	faddd		ATANB2,%fp2	| ...B2+Z*(B4+Z*B6)
+	faddd		ATANB1,%fp1	| ...B1+Z*(B3+Z*B5)
+
+	fmulx		%fp0,%fp2		| ...Y*(B2+Z*(B4+Z*B6))
+	fmulx		X(%a6),%fp0		| ...X*Y
+
+	faddx		%fp2,%fp1		| ...[B1+Z*(B3+Z*B5)]+[Y*(B2+Z*(B4+Z*B6))]
+	
+
+	fmulx		%fp1,%fp0	| ...X*Y*([B1+Z*(B3+Z*B5)]+[Y*(B2+Z*(B4+Z*B6))])
+
+	fmovel		%d1,%FPCR		|restore users exceptions
+	faddx		X(%a6),%fp0
+
+	bra		t_frcinx
+
+ATANTINY:
+|--|X| < 2^(-40), ATAN(X) = X
+	movew		#0x0000,XDCARE(%a6)
+
+	fmovel		%d1,%FPCR		|restore users exceptions
+	fmovex		X(%a6),%fp0	|last inst - possible exception set
+
+	bra		t_frcinx
+
+ATANBIG:
+|--IF |X| > 2^(100), RETURN	SIGN(X)*(PI/2 - TINY). OTHERWISE,
+|--RETURN SIGN(X)*PI/2 + ATAN(-1/X).
+	cmpil		#0x40638000,%d0
+	bgt		ATANHUGE
+
+|--APPROXIMATE ATAN(-1/X) BY
+|--X'+X'*Y*(C1+Y*(C2+Y*(C3+Y*(C4+Y*C5)))), X' = -1/X, Y = X'*X'
+|--THIS CAN BE RE-WRITTEN AS
+|--X'+X'*Y*( [C1+Z*(C3+Z*C5)] + [Y*(C2+Z*C4)] ), Z = Y*Y.
+
+	fmoves		#0xBF800000,%fp1	| ...LOAD -1
+	fdivx		%fp0,%fp1		| ...FP1 IS -1/X
+
+	
+|--DIVIDE IS STILL CRANKING
+
+	fmovex		%fp1,%fp0		| ...FP0 IS X'
+	fmulx		%fp0,%fp0		| ...FP0 IS Y = X'*X'
+	fmovex		%fp1,X(%a6)		| ...X IS REALLY X'
+
+	fmovex		%fp0,%fp1
+	fmulx		%fp1,%fp1		| ...FP1 IS Z = Y*Y
+
+	fmoved		ATANC5,%fp3
+	fmoved		ATANC4,%fp2
+
+	fmulx		%fp1,%fp3		| ...Z*C5
+	fmulx		%fp1,%fp2		| ...Z*B4
+
+	faddd		ATANC3,%fp3	| ...C3+Z*C5
+	faddd		ATANC2,%fp2	| ...C2+Z*C4
+
+	fmulx		%fp3,%fp1		| ...Z*(C3+Z*C5), FP3 RELEASED
+	fmulx		%fp0,%fp2		| ...Y*(C2+Z*C4)
+
+	faddd		ATANC1,%fp1	| ...C1+Z*(C3+Z*C5)
+	fmulx		X(%a6),%fp0		| ...X'*Y
+
+	faddx		%fp2,%fp1		| ...[Y*(C2+Z*C4)]+[C1+Z*(C3+Z*C5)]
+	
+
+	fmulx		%fp1,%fp0		| ...X'*Y*([B1+Z*(B3+Z*B5)]
+|					...	+[Y*(B2+Z*(B4+Z*B6))])
+	faddx		X(%a6),%fp0
+
+	fmovel		%d1,%FPCR		|restore users exceptions
+	
+	btstb		#7,(%a0)
+	beqs		pos_big
+
+neg_big:
+	faddx		NPIBY2,%fp0
+	bra		t_frcinx
+
+pos_big:
+	faddx		PPIBY2,%fp0
+	bra		t_frcinx
+
+ATANHUGE:
+|--RETURN SIGN(X)*(PIBY2 - TINY) = SIGN(X)*PIBY2 - SIGN(X)*TINY
+	btstb		#7,(%a0)
+	beqs		pos_huge
+
+neg_huge:
+	fmovex		NPIBY2,%fp0
+	fmovel		%d1,%fpcr
+	fsubx		NTINY,%fp0
+	bra		t_frcinx
+
+pos_huge:
+	fmovex		PPIBY2,%fp0
+	fmovel		%d1,%fpcr
+	fsubx		PTINY,%fp0
+	bra		t_frcinx
+	
+	|end
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/fpsp040/satanh.S linux/arch/m68k/fpsp040/satanh.S
--- v1.3.93/linux/arch/m68k/fpsp040/satanh.S	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/fpsp040/satanh.S	Sat Feb 24 22:58:43 1996
@@ -0,0 +1,104 @@
+|
+|	satanh.sa 3.3 12/19/90
+|
+|	The entry point satanh computes the inverse
+|	hyperbolic tangent of
+|	an input argument; satanhd does the same except for denormalized
+|	input.
+|
+|	Input: Double-extended number X in location pointed to
+|		by address register a0.
+|
+|	Output: The value arctanh(X) returned in floating-point register Fp0.
+|
+|	Accuracy and Monotonicity: The returned result is within 3 ulps in
+|		64 significant bit, i.e. within 0.5001 ulp to 53 bits if the
+|		result is subsequently rounded to double precision. The 
+|		result is provably monotonic in double precision.
+|
+|	Speed: The program satanh takes approximately 270 cycles.
+|
+|	Algorithm:
+|
+|	ATANH
+|	1. If |X| >= 1, go to 3.
+|
+|	2. (|X| < 1) Calculate atanh(X) by
+|		sgn := sign(X)
+|		y := |X|
+|		z := 2y/(1-y)
+|		atanh(X) := sgn * (1/2) * logp1(z)
+|		Exit.
+|
+|	3. If |X| > 1, go to 5.
+|
+|	4. (|X| = 1) Generate infinity with an appropriate sign and
+|		divide-by-zero by	
+|		sgn := sign(X)
+|		atan(X) := sgn / (+0).
+|		Exit.
+|
+|	5. (|X| > 1) Generate an invalid operation by 0 * infinity.
+|		Exit.
+|
+
+|		Copyright (C) Motorola, Inc. 1990
+|			All Rights Reserved
+|
+|	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA 
+|	The copyright notice above does not evidence any  
+|	actual or intended publication of such source code.
+
+|satanh	idnt	2,1 | Motorola 040 Floating Point Software Package
+
+	|section	8
+
+	|xref	t_dz
+	|xref	t_operr
+	|xref	t_frcinx
+	|xref	t_extdnrm
+	|xref	slognp1
+
+	.global	satanhd
+satanhd:
+|--ATANH(X) = X FOR DENORMALIZED X
+
+	bra		t_extdnrm
+
+	.global	satanh
+satanh:
+	movel		(%a0),%d0
+	movew		4(%a0),%d0
+	andil		#0x7FFFFFFF,%d0
+	cmpil		#0x3FFF8000,%d0
+	bges		ATANHBIG
+
+|--THIS IS THE USUAL CASE, |X| < 1
+|--Y = |X|, Z = 2Y/(1-Y), ATANH(X) = SIGN(X) * (1/2) * LOG1P(Z).
+
+	fabsx		(%a0),%fp0	| ...Y = |X|
+	fmovex		%fp0,%fp1
+	fnegx		%fp1		| ...-Y
+	faddx		%fp0,%fp0		| ...2Y
+	fadds		#0x3F800000,%fp1	| ...1-Y
+	fdivx		%fp1,%fp0		| ...2Y/(1-Y)
+	movel		(%a0),%d0
+	andil		#0x80000000,%d0
+	oril		#0x3F000000,%d0	| ...SIGN(X)*HALF
+	movel		%d0,-(%sp)
+
+	fmovemx	%fp0-%fp0,(%a0)	| ...overwrite input
+	movel		%d1,-(%sp)
+	clrl		%d1
+	bsr		slognp1		| ...LOG1P(Z)
+	fmovel		(%sp)+,%fpcr
+	fmuls		(%sp)+,%fp0
+	bra		t_frcinx
+
+ATANHBIG:
+	fabsx		(%a0),%fp0	| ...|X|
+	fcmps		#0x3F800000,%fp0
+	fbgt		t_operr
+	bra		t_dz
+
+	|end
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/fpsp040/scale.S linux/arch/m68k/fpsp040/scale.S
--- v1.3.93/linux/arch/m68k/fpsp040/scale.S	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/fpsp040/scale.S	Sat Feb 24 22:58:43 1996
@@ -0,0 +1,371 @@
+|
+|	scale.sa 3.3 7/30/91
+|
+|	The entry point sSCALE computes the destination operand
+|	scaled by the source operand.  If the absoulute value of
+|	the source operand is (>= 2^14) an overflow or underflow
+|	is returned.
+|
+|	The entry point sscale is called from do_func to emulate
+|	the fscale unimplemented instruction.
+|
+|	Input: Double-extended destination operand in FPTEMP, 
+|		double-extended source operand in ETEMP.
+|
+|	Output: The function returns scale(X,Y) to fp0.
+|
+|	Modifies: fp0.
+|
+|	Algorithm:
+|		
+|		Copyright (C) Motorola, Inc. 1990
+|			All Rights Reserved
+|
+|	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA 
+|	The copyright notice above does not evidence any  
+|	actual or intended publication of such source code.
+
+|SCALE    idnt    2,1 | Motorola 040 Floating Point Software Package
+
+	|section	8
+
+	.include "fpsp.h"
+
+	|xref	t_ovfl2
+	|xref	t_unfl
+	|xref	round
+	|xref	t_resdnrm
+
+SRC_BNDS: .short	0x3fff,0x400c
+
+|
+| This entry point is used by the unimplemented instruction exception
+| handler.
+|
+|
+|
+|	FSCALE
+|
+	.global	sscale
+sscale:
+	fmovel		#0,%fpcr		|clr user enabled exc
+	clrl		%d1
+	movew		FPTEMP(%a6),%d1	|get dest exponent
+	smi		L_SCR1(%a6)	|use L_SCR1 to hold sign
+	andil		#0x7fff,%d1	|strip sign
+	movew		ETEMP(%a6),%d0	|check src bounds
+	andiw		#0x7fff,%d0	|clr sign bit
+	cmp2w		SRC_BNDS,%d0
+	bccs		src_in
+	cmpiw		#0x400c,%d0	|test for too large
+	bge		src_out
+|
+| The source input is below 1, so we check for denormalized numbers
+| and set unfl.
+|
+src_small:
+	moveb		DTAG(%a6),%d0
+	andib		#0xe0,%d0
+	tstb		%d0
+	beqs		no_denorm
+	st		STORE_FLG(%a6)	|dest already contains result
+	orl		#unfl_mask,USER_FPSR(%a6) |set UNFL
+den_done:
+	leal		FPTEMP(%a6),%a0
+	bra		t_resdnrm
+no_denorm:
+	fmovel		USER_FPCR(%a6),%FPCR
+	fmovex		FPTEMP(%a6),%fp0	|simply return dest
+	rts
+
+
+|
+| Source is within 2^14 range.  To perform the int operation,
+| move it to d0.
+|
+src_in:
+	fmovex		ETEMP(%a6),%fp0	|move in src for int
+	fmovel		#rz_mode,%fpcr	|force rz for src conversion
+	fmovel		%fp0,%d0		|int src to d0
+	fmovel		#0,%FPSR		|clr status from above
+	tstw		ETEMP(%a6)	|check src sign
+	blt		src_neg
+|
+| Source is positive.  Add the src to the dest exponent.
+| The result can be denormalized, if src = 0, or overflow,
+| if the result of the add sets a bit in the upper word.
+|
+src_pos:
+	tstw		%d1		|check for denorm
+	beq		dst_dnrm
+	addl		%d0,%d1		|add src to dest exp
+	beqs		denorm		|if zero, result is denorm
+	cmpil		#0x7fff,%d1	|test for overflow
+	bges		ovfl
+	tstb		L_SCR1(%a6)
+	beqs		spos_pos
+	orw		#0x8000,%d1
+spos_pos:
+	movew		%d1,FPTEMP(%a6)	|result in FPTEMP
+	fmovel		USER_FPCR(%a6),%FPCR
+	fmovex		FPTEMP(%a6),%fp0	|write result to fp0
+	rts
+ovfl:
+	tstb		L_SCR1(%a6)
+	beqs		sovl_pos
+	orw		#0x8000,%d1
+sovl_pos:
+	movew		FPTEMP(%a6),ETEMP(%a6)	|result in ETEMP
+	movel		FPTEMP_HI(%a6),ETEMP_HI(%a6)
+	movel		FPTEMP_LO(%a6),ETEMP_LO(%a6)
+	bra		t_ovfl2
+
+denorm:
+	tstb		L_SCR1(%a6)
+	beqs		den_pos
+	orw		#0x8000,%d1
+den_pos:
+	tstl		FPTEMP_HI(%a6)	|check j bit
+	blts		nden_exit	|if set, not denorm
+	movew		%d1,ETEMP(%a6)	|input expected in ETEMP
+	movel		FPTEMP_HI(%a6),ETEMP_HI(%a6)
+	movel		FPTEMP_LO(%a6),ETEMP_LO(%a6)
+	orl		#unfl_bit,USER_FPSR(%a6)	|set unfl
+	leal		ETEMP(%a6),%a0
+	bra		t_resdnrm
+nden_exit:
+	movew		%d1,FPTEMP(%a6)	|result in FPTEMP
+	fmovel		USER_FPCR(%a6),%FPCR
+	fmovex		FPTEMP(%a6),%fp0	|write result to fp0
+	rts
+
+|
+| Source is negative.  Add the src to the dest exponent.
+| (The result exponent will be reduced).  The result can be
+| denormalized.
+|
+src_neg:
+	addl		%d0,%d1		|add src to dest
+	beqs		denorm		|if zero, result is denorm
+	blts		fix_dnrm	|if negative, result is 
+|					;needing denormalization
+	tstb		L_SCR1(%a6)
+	beqs		sneg_pos
+	orw		#0x8000,%d1
+sneg_pos:
+	movew		%d1,FPTEMP(%a6)	|result in FPTEMP
+	fmovel		USER_FPCR(%a6),%FPCR
+	fmovex		FPTEMP(%a6),%fp0	|write result to fp0
+	rts
+
+
+|
+| The result exponent is below denorm value.  Test for catastrophic
+| underflow and force zero if true.  If not, try to shift the 
+| mantissa right until a zero exponent exists.
+|
+fix_dnrm:
+	cmpiw		#0xffc0,%d1	|lower bound for normalization
+	blt		fix_unfl	|if lower, catastrophic unfl
+	movew		%d1,%d0		|use d0 for exp
+	movel		%d2,-(%a7)	|free d2 for norm
+	movel		FPTEMP_HI(%a6),%d1
+	movel		FPTEMP_LO(%a6),%d2
+	clrl		L_SCR2(%a6)
+fix_loop:
+	addw		#1,%d0		|drive d0 to 0
+	lsrl		#1,%d1		|while shifting the
+	roxrl		#1,%d2		|mantissa to the right
+	bccs		no_carry
+	st		L_SCR2(%a6)	|use L_SCR2 to capture inex
+no_carry:
+	tstw		%d0		|it is finished when
+	blts		fix_loop	|d0 is zero or the mantissa
+	tstb		L_SCR2(%a6)
+	beqs		tst_zero
+	orl		#unfl_inx_mask,USER_FPSR(%a6)
+|					;set unfl, aunfl, ainex
+|
+| Test for zero. If zero, simply use fmove to return +/- zero
+| to the fpu.
+|
+tst_zero:
+	clrw		FPTEMP_EX(%a6)
+	tstb		L_SCR1(%a6)	|test for sign
+	beqs		tst_con
+	orw		#0x8000,FPTEMP_EX(%a6) |set sign bit
+tst_con:
+	movel		%d1,FPTEMP_HI(%a6)
+	movel		%d2,FPTEMP_LO(%a6)
+	movel		(%a7)+,%d2
+	tstl		%d1
+	bnes		not_zero
+	tstl		FPTEMP_LO(%a6)
+	bnes		not_zero
+|
+| Result is zero.  Check for rounding mode to set lsb.  If the
+| mode is rp, and the zero is positive, return smallest denorm.
+| If the mode is rm, and the zero is negative, return smallest
+| negative denorm.
+|
+	btstb		#5,FPCR_MODE(%a6) |test if rm or rp
+	beqs		no_dir
+	btstb		#4,FPCR_MODE(%a6) |check which one
+	beqs		zer_rm
+zer_rp:
+	tstb		L_SCR1(%a6)	|check sign
+	bnes		no_dir		|if set, neg op, no inc
+	movel		#1,FPTEMP_LO(%a6) |set lsb
+	bras		sm_dnrm
+zer_rm:
+	tstb		L_SCR1(%a6)	|check sign
+	beqs		no_dir		|if clr, neg op, no inc
+	movel		#1,FPTEMP_LO(%a6) |set lsb
+	orl		#neg_mask,USER_FPSR(%a6) |set N
+	bras		sm_dnrm
+no_dir:
+	fmovel		USER_FPCR(%a6),%FPCR
+	fmovex		FPTEMP(%a6),%fp0	|use fmove to set cc's
+	rts
+
+|
+| The rounding mode changed the zero to a smallest denorm. Call 
+| t_resdnrm with exceptional operand in ETEMP.
+|
+sm_dnrm:
+	movel		FPTEMP_EX(%a6),ETEMP_EX(%a6)
+	movel		FPTEMP_HI(%a6),ETEMP_HI(%a6)
+	movel		FPTEMP_LO(%a6),ETEMP_LO(%a6)
+	leal		ETEMP(%a6),%a0
+	bra		t_resdnrm
+
+|
+| Result is still denormalized.
+|
+not_zero:
+	orl		#unfl_mask,USER_FPSR(%a6) |set unfl
+	tstb		L_SCR1(%a6)	|check for sign
+	beqs		fix_exit
+	orl		#neg_mask,USER_FPSR(%a6) |set N
+fix_exit:
+	bras		sm_dnrm
+
+	
+|
+| The result has underflowed to zero. Return zero and set
+| unfl, aunfl, and ainex.
+|
+fix_unfl:
+	orl		#unfl_inx_mask,USER_FPSR(%a6)
+	btstb		#5,FPCR_MODE(%a6) |test if rm or rp
+	beqs		no_dir2
+	btstb		#4,FPCR_MODE(%a6) |check which one
+	beqs		zer_rm2
+zer_rp2:
+	tstb		L_SCR1(%a6)	|check sign
+	bnes		no_dir2		|if set, neg op, no inc
+	clrl		FPTEMP_EX(%a6)
+	clrl		FPTEMP_HI(%a6)
+	movel		#1,FPTEMP_LO(%a6) |set lsb
+	bras		sm_dnrm		|return smallest denorm
+zer_rm2:
+	tstb		L_SCR1(%a6)	|check sign
+	beqs		no_dir2		|if clr, neg op, no inc
+	movew		#0x8000,FPTEMP_EX(%a6)
+	clrl		FPTEMP_HI(%a6)
+	movel		#1,FPTEMP_LO(%a6) |set lsb
+	orl		#neg_mask,USER_FPSR(%a6) |set N
+	bra		sm_dnrm		|return smallest denorm
+
+no_dir2:
+	tstb		L_SCR1(%a6)
+	bges		pos_zero
+neg_zero:
+	clrl		FP_SCR1(%a6)	|clear the exceptional operand
+	clrl		FP_SCR1+4(%a6)	|for gen_except.
+	clrl		FP_SCR1+8(%a6)
+	fmoves		#0x80000000,%fp0	
+	rts
+pos_zero:
+	clrl		FP_SCR1(%a6)	|clear the exceptional operand
+	clrl		FP_SCR1+4(%a6)	|for gen_except.
+	clrl		FP_SCR1+8(%a6)
+	fmoves		#0x00000000,%fp0
+	rts
+
+|
+| The destination is a denormalized number.  It must be handled
+| by first shifting the bits in the mantissa until it is normalized,
+| then adding the remainder of the source to the exponent.
+|
+dst_dnrm:
+	moveml		%d2/%d3,-(%a7)	
+	movew		FPTEMP_EX(%a6),%d1
+	movel		FPTEMP_HI(%a6),%d2
+	movel		FPTEMP_LO(%a6),%d3
+dst_loop:
+	tstl		%d2		|test for normalized result
+	blts		dst_norm	|exit loop if so
+	tstl		%d0		|otherwise, test shift count
+	beqs		dst_fin		|if zero, shifting is done
+	subil		#1,%d0		|dec src
+	lsll		#1,%d3
+	roxll		#1,%d2
+	bras		dst_loop
+|
+| Destination became normalized.  Simply add the remaining 
+| portion of the src to the exponent.
+|
+dst_norm:
+	addw		%d0,%d1		|dst is normalized; add src
+	tstb		L_SCR1(%a6)
+	beqs		dnrm_pos
+	orl		#0x8000,%d1
+dnrm_pos:
+	movemw		%d1,FPTEMP_EX(%a6)
+	moveml		%d2,FPTEMP_HI(%a6)
+	moveml		%d3,FPTEMP_LO(%a6)
+	fmovel		USER_FPCR(%a6),%FPCR
+	fmovex		FPTEMP(%a6),%fp0
+	moveml		(%a7)+,%d2/%d3
+	rts
+
+|
+| Destination remained denormalized.  Call t_excdnrm with
+| exceptional operand in ETEMP.
+|
+dst_fin:
+	tstb		L_SCR1(%a6)	|check for sign
+	beqs		dst_exit
+	orl		#neg_mask,USER_FPSR(%a6) |set N
+	orl		#0x8000,%d1
+dst_exit:
+	movemw		%d1,ETEMP_EX(%a6)
+	moveml		%d2,ETEMP_HI(%a6)
+	moveml		%d3,ETEMP_LO(%a6)
+	orl		#unfl_mask,USER_FPSR(%a6) |set unfl
+	moveml		(%a7)+,%d2/%d3
+	leal		ETEMP(%a6),%a0
+	bra		t_resdnrm
+
+|
+| Source is outside of 2^14 range.  Test the sign and branch
+| to the appropriate exception handler.
+|
+src_out:
+	tstb		L_SCR1(%a6)
+	beqs		scro_pos
+	orl		#0x8000,%d1
+scro_pos:
+	movel		FPTEMP_HI(%a6),ETEMP_HI(%a6)
+	movel		FPTEMP_LO(%a6),ETEMP_LO(%a6)
+	tstw		ETEMP(%a6)
+	blts		res_neg
+res_pos:
+	movew		%d1,ETEMP(%a6)	|result in ETEMP
+	bra		t_ovfl2
+res_neg:
+	movew		%d1,ETEMP(%a6)	|result in ETEMP
+	leal		ETEMP(%a6),%a0
+	bra		t_unfl
+	|end
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/fpsp040/scosh.S linux/arch/m68k/fpsp040/scosh.S
--- v1.3.93/linux/arch/m68k/fpsp040/scosh.S	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/fpsp040/scosh.S	Sat Feb 24 22:58:43 1996
@@ -0,0 +1,132 @@
+|
+|	scosh.sa 3.1 12/10/90
+|
+|	The entry point sCosh computes the hyperbolic cosine of
+|	an input argument; sCoshd does the same except for denormalized
+|	input.
+|
+|	Input: Double-extended number X in location pointed to
+|		by address register a0.
+|
+|	Output: The value cosh(X) returned in floating-point register Fp0.
+|
+|	Accuracy and Monotonicity: The returned result is within 3 ulps in
+|		64 significant bit, i.e. within 0.5001 ulp to 53 bits if the
+|		result is subsequently rounded to double precision. The
+|		result is provably monotonic in double precision.
+|
+|	Speed: The program sCOSH takes approximately 250 cycles.
+|
+|	Algorithm:
+|
+|	COSH
+|	1. If |X| > 16380 log2, go to 3.
+|
+|	2. (|X| <= 16380 log2) Cosh(X) is obtained by the formulae
+|		y = |X|, z = exp(Y), and
+|		cosh(X) = (1/2)*( z + 1/z ).
+|		Exit.
+|
+|	3. (|X| > 16380 log2). If |X| > 16480 log2, go to 5.
+|
+|	4. (16380 log2 < |X| <= 16480 log2)
+|		cosh(X) = sign(X) * exp(|X|)/2.
+|		However, invoking exp(|X|) may cause premature overflow.
+|		Thus, we calculate sinh(X) as follows:
+|		Y	:= |X|
+|		Fact	:=	2**(16380)
+|		Y'	:= Y - 16381 log2
+|		cosh(X) := Fact * exp(Y').
+|		Exit.
+|
+|	5. (|X| > 16480 log2) sinh(X) must overflow. Return
+|		Huge*Huge to generate overflow and an infinity with
+|		the appropriate sign. Huge is the largest finite number in
+|		extended format. Exit.
+|
+|
+
+|		Copyright (C) Motorola, Inc. 1990
+|			All Rights Reserved
+|
+|	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA 
+|	The copyright notice above does not evidence any  
+|	actual or intended publication of such source code.
+
+|SCOSH	idnt	2,1 | Motorola 040 Floating Point Software Package
+
+	|section	8
+
+	|xref	t_ovfl
+	|xref	t_frcinx
+	|xref	setox
+
+T1:	.long 0x40C62D38,0xD3D64634 | ... 16381 LOG2 LEAD
+T2:	.long 0x3D6F90AE,0xB1E75CC7 | ... 16381 LOG2 TRAIL
+
+TWO16380: .long 0x7FFB0000,0x80000000,0x00000000,0x00000000
+
+	.global	scoshd
+scoshd:
+|--COSH(X) = 1 FOR DENORMALIZED X
+
+	fmoves		#0x3F800000,%fp0
+
+	fmovel		%d1,%FPCR
+	fadds		#0x00800000,%fp0
+	bra		t_frcinx
+
+	.global	scosh
+scosh:
+	fmovex		(%a0),%fp0	| ...LOAD INPUT
+
+	movel		(%a0),%d0
+	movew		4(%a0),%d0
+	andil		#0x7FFFFFFF,%d0
+	cmpil		#0x400CB167,%d0
+	bgts		COSHBIG
+
+|--THIS IS THE USUAL CASE, |X| < 16380 LOG2
+|--COSH(X) = (1/2) * ( EXP(X) + 1/EXP(X) )
+
+	fabsx		%fp0		| ...|X|
+
+	movel		%d1,-(%sp)
+	clrl		%d1
+	fmovemx	%fp0-%fp0,(%a0)	|pass parameter to setox
+	bsr		setox		| ...FP0 IS EXP(|X|)
+	fmuls		#0x3F000000,%fp0	| ...(1/2)EXP(|X|)
+	movel		(%sp)+,%d1
+
+	fmoves		#0x3E800000,%fp1	| ...(1/4)
+	fdivx		%fp0,%fp1	 	| ...1/(2 EXP(|X|))
+
+	fmovel		%d1,%FPCR
+	faddx		%fp1,%fp0
+
+	bra		t_frcinx
+
+COSHBIG:
+	cmpil		#0x400CB2B3,%d0
+	bgts		COSHHUGE
+
+	fabsx		%fp0
+	fsubd		T1(%pc),%fp0		| ...(|X|-16381LOG2_LEAD)
+	fsubd		T2(%pc),%fp0		| ...|X| - 16381 LOG2, ACCURATE
+
+	movel		%d1,-(%sp)
+	clrl		%d1
+	fmovemx	%fp0-%fp0,(%a0)
+	bsr		setox
+	fmovel		(%sp)+,%fpcr
+
+	fmulx		TWO16380(%pc),%fp0
+	bra		t_frcinx
+
+COSHHUGE:
+	fmovel		#0,%fpsr		|clr N bit if set by source
+	bclrb		#7,(%a0)		|always return positive value
+	fmovemx	(%a0),%fp0-%fp0
+	bra		t_ovfl
+
+	|end
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/fpsp040/setox.S linux/arch/m68k/fpsp040/setox.S
--- v1.3.93/linux/arch/m68k/fpsp040/setox.S	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/fpsp040/setox.S	Sat Feb 24 22:58:44 1996
@@ -0,0 +1,865 @@
+|
+|	setox.sa 3.1 12/10/90
+|
+|	The entry point setox computes the exponential of a value.
+|	setoxd does the same except the input value is a denormalized
+|	number.	setoxm1 computes exp(X)-1, and setoxm1d computes
+|	exp(X)-1 for denormalized X.
+|
+|	INPUT
+|	-----
+|	Double-extended value in memory location pointed to by address
+|	register a0.
+|
+|	OUTPUT
+|	------
+|	exp(X) or exp(X)-1 returned in floating-point register fp0.
+|
+|	ACCURACY and MONOTONICITY
+|	-------------------------
+|	The returned result is within 0.85 ulps in 64 significant bit, i.e.
+|	within 0.5001 ulp to 53 bits if the result is subsequently rounded
+|	to double precision. The result is provably monotonic in double
+|	precision.
+|
+|	SPEED
+|	-----
+|	Two timings are measured, both in the copy-back mode. The
+|	first one is measured when the function is invoked the first time
+|	(so the instructions and data are not in cache), and the
+|	second one is measured when the function is reinvoked at the same
+|	input argument.
+|
+|	The program setox takes approximately 210/190 cycles for input
+|	argument X whose magnitude is less than 16380 log2, which
+|	is the usual situation.	For the less common arguments,
+|	depending on their values, the program may run faster or slower --
+|	but no worse than 10% slower even in the extreme cases.
+|
+|	The program setoxm1 takes approximately ???/??? cycles for input
+|	argument X, 0.25 <= |X| < 70log2. For |X| < 0.25, it takes
+|	approximately ???/??? cycles. For the less common arguments,
+|	depending on their values, the program may run faster or slower --
+|	but no worse than 10% slower even in the extreme cases.
+|
+|	ALGORITHM and IMPLEMENTATION NOTES
+|	----------------------------------
+|
+|	setoxd
+|	------
+|	Step 1.	Set ans := 1.0
+|
+|	Step 2.	Return	ans := ans + sign(X)*2^(-126). Exit.
+|	Notes:	This will always generate one exception -- inexact.
+|
+|
+|	setox
+|	-----
+|
+|	Step 1.	Filter out extreme cases of input argument.
+|		1.1	If |X| >= 2^(-65), go to Step 1.3.
+|		1.2	Go to Step 7.
+|		1.3	If |X| < 16380 log(2), go to Step 2.
+|		1.4	Go to Step 8.
+|	Notes:	The usual case should take the branches 1.1 -> 1.3 -> 2.
+|		 To avoid the use of floating-point comparisons, a
+|		 compact representation of |X| is used. This format is a
+|		 32-bit integer, the upper (more significant) 16 bits are
+|		 the sign and biased exponent field of |X|; the lower 16
+|		 bits are the 16 most significant fraction (including the
+|		 explicit bit) bits of |X|. Consequently, the comparisons
+|		 in Steps 1.1 and 1.3 can be performed by integer comparison.
+|		 Note also that the constant 16380 log(2) used in Step 1.3
+|		 is also in the compact form. Thus taking the branch
+|		 to Step 2 guarantees |X| < 16380 log(2). There is no harm
+|		 to have a small number of cases where |X| is less than,
+|		 but close to, 16380 log(2) and the branch to Step 9 is
+|		 taken.
+|
+|	Step 2.	Calculate N = round-to-nearest-int( X * 64/log2 ).
+|		2.1	Set AdjFlag := 0 (indicates the branch 1.3 -> 2 was taken)
+|		2.2	N := round-to-nearest-integer( X * 64/log2 ).
+|		2.3	Calculate	J = N mod 64; so J = 0,1,2,..., or 63.
+|		2.4	Calculate	M = (N - J)/64; so N = 64M + J.
+|		2.5	Calculate the address of the stored value of 2^(J/64).
+|		2.6	Create the value Scale = 2^M.
+|	Notes:	The calculation in 2.2 is really performed by
+|
+|			Z := X * constant
+|			N := round-to-nearest-integer(Z)
+|
+|		 where
+|
+|			constant := single-precision( 64/log 2 ).
+|
+|		 Using a single-precision constant avoids memory access.
+|		 Another effect of using a single-precision "constant" is
+|		 that the calculated value Z is
+|
+|			Z = X*(64/log2)*(1+eps), |eps| <= 2^(-24).
+|
+|		 This error has to be considered later in Steps 3 and 4.
+|
+|	Step 3.	Calculate X - N*log2/64.
+|		3.1	R := X + N*L1, where L1 := single-precision(-log2/64).
+|		3.2	R := R + N*L2, L2 := extended-precision(-log2/64 - L1).
+|	Notes:	a) The way L1 and L2 are chosen ensures L1+L2 approximate
+|		 the value	-log2/64	to 88 bits of accuracy.
+|		 b) N*L1 is exact because N is no longer than 22 bits and
+|		 L1 is no longer than 24 bits.
+|		 c) The calculation X+N*L1 is also exact due to cancellation.
+|		 Thus, R is practically X+N(L1+L2) to full 64 bits.
+|		 d) It is important to estimate how large can |R| be after
+|		 Step 3.2.
+|
+|			N = rnd-to-int( X*64/log2 (1+eps) ), |eps|<=2^(-24)
+|			X*64/log2 (1+eps)	=	N + f,	|f| <= 0.5
+|			X*64/log2 - N	=	f - eps*X 64/log2
+|			X - N*log2/64	=	f*log2/64 - eps*X
+|
+|
+|		 Now |X| <= 16446 log2, thus
+|
+|			|X - N*log2/64| <= (0.5 + 16446/2^(18))*log2/64
+|					<= 0.57 log2/64.
+|		 This bound will be used in Step 4.
+|
+|	Step 4.	Approximate exp(R)-1 by a polynomial
+|			p = R + R*R*(A1 + R*(A2 + R*(A3 + R*(A4 + R*A5))))
+|	Notes:	a) In order to reduce memory access, the coefficients are
+|		 made as "short" as possible: A1 (which is 1/2), A4 and A5
+|		 are single precision; A2 and A3 are double precision.
+|		 b) Even with the restrictions above,
+|			|p - (exp(R)-1)| < 2^(-68.8) for all |R| <= 0.0062.
+|		 Note that 0.0062 is slightly bigger than 0.57 log2/64.
+|		 c) To fully utilize the pipeline, p is separated into
+|		 two independent pieces of roughly equal complexities
+|			p = [ R + R*S*(A2 + S*A4) ]	+
+|				[ S*(A1 + S*(A3 + S*A5)) ]
+|		 where S = R*R.
+|
+|	Step 5.	Compute 2^(J/64)*exp(R) = 2^(J/64)*(1+p) by
+|				ans := T + ( T*p + t)
+|		 where T and t are the stored values for 2^(J/64).
+|	Notes:	2^(J/64) is stored as T and t where T+t approximates
+|		 2^(J/64) to roughly 85 bits; T is in extended precision
+|		 and t is in single precision. Note also that T is rounded
+|		 to 62 bits so that the last two bits of T are zero. The
+|		 reason for such a special form is that T-1, T-2, and T-8
+|		 will all be exact --- a property that will give much
+|		 more accurate computation of the function EXPM1.
+|
+|	Step 6.	Reconstruction of exp(X)
+|			exp(X) = 2^M * 2^(J/64) * exp(R).
+|		6.1	If AdjFlag = 0, go to 6.3
+|		6.2	ans := ans * AdjScale
+|		6.3	Restore the user FPCR
+|		6.4	Return ans := ans * Scale. Exit.
+|	Notes:	If AdjFlag = 0, we have X = Mlog2 + Jlog2/64 + R,
+|		 |M| <= 16380, and Scale = 2^M. Moreover, exp(X) will
+|		 neither overflow nor underflow. If AdjFlag = 1, that
+|		 means that
+|			X = (M1+M)log2 + Jlog2/64 + R, |M1+M| >= 16380.
+|		 Hence, exp(X) may overflow or underflow or neither.
+|		 When that is the case, AdjScale = 2^(M1) where M1 is
+|		 approximately M. Thus 6.2 will never cause over/underflow.
+|		 Possible exception in 6.4 is overflow or underflow.
+|		 The inexact exception is not generated in 6.4. Although
+|		 one can argue that the inexact flag should always be
+|		 raised, to simulate that exception cost to much than the
+|		 flag is worth in practical uses.
+|
+|	Step 7.	Return 1 + X.
+|		7.1	ans := X
+|		7.2	Restore user FPCR.
+|		7.3	Return ans := 1 + ans. Exit
+|	Notes:	For non-zero X, the inexact exception will always be
+|		 raised by 7.3. That is the only exception raised by 7.3.
+|		 Note also that we use the FMOVEM instruction to move X
+|		 in Step 7.1 to avoid unnecessary trapping. (Although
+|		 the FMOVEM may not seem relevant since X is normalized,
+|		 the precaution will be useful in the library version of
+|		 this code where the separate entry for denormalized inputs
+|		 will be done away with.)
+|
+|	Step 8.	Handle exp(X) where |X| >= 16380log2.
+|		8.1	If |X| > 16480 log2, go to Step 9.
+|		(mimic 2.2 - 2.6)
+|		8.2	N := round-to-integer( X * 64/log2 )
+|		8.3	Calculate J = N mod 64, J = 0,1,...,63
+|		8.4	K := (N-J)/64, M1 := truncate(K/2), M = K-M1, AdjFlag := 1.
+|		8.5	Calculate the address of the stored value 2^(J/64).
+|		8.6	Create the values Scale = 2^M, AdjScale = 2^M1.
+|		8.7	Go to Step 3.
+|	Notes:	Refer to notes for 2.2 - 2.6.
+|
+|	Step 9.	Handle exp(X), |X| > 16480 log2.
+|		9.1	If X < 0, go to 9.3
+|		9.2	ans := Huge, go to 9.4
+|		9.3	ans := Tiny.
+|		9.4	Restore user FPCR.
+|		9.5	Return ans := ans * ans. Exit.
+|	Notes:	Exp(X) will surely overflow or underflow, depending on
+|		 X's sign. "Huge" and "Tiny" are respectively large/tiny
+|		 extended-precision numbers whose square over/underflow
+|		 with an inexact result. Thus, 9.5 always raises the
+|		 inexact together with either overflow or underflow.
+|
+|
+|	setoxm1d
+|	--------
+|
+|	Step 1.	Set ans := 0
+|
+|	Step 2.	Return	ans := X + ans. Exit.
+|	Notes:	This will return X with the appropriate rounding
+|		 precision prescribed by the user FPCR.
+|
+|	setoxm1
+|	-------
+|
+|	Step 1.	Check |X|
+|		1.1	If |X| >= 1/4, go to Step 1.3.
+|		1.2	Go to Step 7.
+|		1.3	If |X| < 70 log(2), go to Step 2.
+|		1.4	Go to Step 10.
+|	Notes:	The usual case should take the branches 1.1 -> 1.3 -> 2.
+|		 However, it is conceivable |X| can be small very often
+|		 because EXPM1 is intended to evaluate exp(X)-1 accurately
+|		 when |X| is small. For further details on the comparisons,
+|		 see the notes on Step 1 of setox.
+|
+|	Step 2.	Calculate N = round-to-nearest-int( X * 64/log2 ).
+|		2.1	N := round-to-nearest-integer( X * 64/log2 ).
+|		2.2	Calculate	J = N mod 64; so J = 0,1,2,..., or 63.
+|		2.3	Calculate	M = (N - J)/64; so N = 64M + J.
+|		2.4	Calculate the address of the stored value of 2^(J/64).
+|		2.5	Create the values Sc = 2^M and OnebySc := -2^(-M).
+|	Notes:	See the notes on Step 2 of setox.
+|
+|	Step 3.	Calculate X - N*log2/64.
+|		3.1	R := X + N*L1, where L1 := single-precision(-log2/64).
+|		3.2	R := R + N*L2, L2 := extended-precision(-log2/64 - L1).
+|	Notes:	Applying the analysis of Step 3 of setox in this case
+|		 shows that |R| <= 0.0055 (note that |X| <= 70 log2 in
+|		 this case).
+|
+|	Step 4.	Approximate exp(R)-1 by a polynomial
+|			p = R+R*R*(A1+R*(A2+R*(A3+R*(A4+R*(A5+R*A6)))))
+|	Notes:	a) In order to reduce memory access, the coefficients are
+|		 made as "short" as possible: A1 (which is 1/2), A5 and A6
+|		 are single precision; A2, A3 and A4 are double precision.
+|		 b) Even with the restriction above,
+|			|p - (exp(R)-1)| <	|R| * 2^(-72.7)
+|		 for all |R| <= 0.0055.
+|		 c) To fully utilize the pipeline, p is separated into
+|		 two independent pieces of roughly equal complexity
+|			p = [ R*S*(A2 + S*(A4 + S*A6)) ]	+
+|				[ R + S*(A1 + S*(A3 + S*A5)) ]
+|		 where S = R*R.
+|
+|	Step 5.	Compute 2^(J/64)*p by
+|				p := T*p
+|		 where T and t are the stored values for 2^(J/64).
+|	Notes:	2^(J/64) is stored as T and t where T+t approximates
+|		 2^(J/64) to roughly 85 bits; T is in extended precision
+|		 and t is in single precision. Note also that T is rounded
+|		 to 62 bits so that the last two bits of T are zero. The
+|		 reason for such a special form is that T-1, T-2, and T-8
+|		 will all be exact --- a property that will be exploited
+|		 in Step 6 below. The total relative error in p is no
+|		 bigger than 2^(-67.7) compared to the final result.
+|
+|	Step 6.	Reconstruction of exp(X)-1
+|			exp(X)-1 = 2^M * ( 2^(J/64) + p - 2^(-M) ).
+|		6.1	If M <= 63, go to Step 6.3.
+|		6.2	ans := T + (p + (t + OnebySc)). Go to 6.6
+|		6.3	If M >= -3, go to 6.5.
+|		6.4	ans := (T + (p + t)) + OnebySc. Go to 6.6
+|		6.5	ans := (T + OnebySc) + (p + t).
+|		6.6	Restore user FPCR.
+|		6.7	Return ans := Sc * ans. Exit.
+|	Notes:	The various arrangements of the expressions give accurate
+|		 evaluations.
+|
+|	Step 7.	exp(X)-1 for |X| < 1/4.
+|		7.1	If |X| >= 2^(-65), go to Step 9.
+|		7.2	Go to Step 8.
+|
+|	Step 8.	Calculate exp(X)-1, |X| < 2^(-65).
+|		8.1	If |X| < 2^(-16312), goto 8.3
+|		8.2	Restore FPCR; return ans := X - 2^(-16382). Exit.
+|		8.3	X := X * 2^(140).
+|		8.4	Restore FPCR; ans := ans - 2^(-16382).
+|		 Return ans := ans*2^(140). Exit
+|	Notes:	The idea is to return "X - tiny" under the user
+|		 precision and rounding modes. To avoid unnecessary
+|		 inefficiency, we stay away from denormalized numbers the
+|		 best we can. For |X| >= 2^(-16312), the straightforward
+|		 8.2 generates the inexact exception as the case warrants.
+|
+|	Step 9.	Calculate exp(X)-1, |X| < 1/4, by a polynomial
+|			p = X + X*X*(B1 + X*(B2 + ... + X*B12))
+|	Notes:	a) In order to reduce memory access, the coefficients are
+|		 made as "short" as possible: B1 (which is 1/2), B9 to B12
+|		 are single precision; B3 to B8 are double precision; and
+|		 B2 is double extended.
+|		 b) Even with the restriction above,
+|			|p - (exp(X)-1)| < |X| 2^(-70.6)
+|		 for all |X| <= 0.251.
+|		 Note that 0.251 is slightly bigger than 1/4.
+|		 c) To fully preserve accuracy, the polynomial is computed
+|		 as	X + ( S*B1 +	Q ) where S = X*X and
+|			Q	=	X*S*(B2 + X*(B3 + ... + X*B12))
+|		 d) To fully utilize the pipeline, Q is separated into
+|		 two independent pieces of roughly equal complexity
+|			Q = [ X*S*(B2 + S*(B4 + ... + S*B12)) ] +
+|				[ S*S*(B3 + S*(B5 + ... + S*B11)) ]
+|
+|	Step 10.	Calculate exp(X)-1 for |X| >= 70 log 2.
+|		10.1 If X >= 70log2 , exp(X) - 1 = exp(X) for all practical
+|		 purposes. Therefore, go to Step 1 of setox.
+|		10.2 If X <= -70log2, exp(X) - 1 = -1 for all practical purposes.
+|		 ans := -1
+|		 Restore user FPCR
+|		 Return ans := ans + 2^(-126). Exit.
+|	Notes:	10.2 will always create an inexact and return -1 + tiny
+|		 in the user rounding precision and mode.
+|
+|
+
+|		Copyright (C) Motorola, Inc. 1990
+|			All Rights Reserved
+|
+|	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA 
+|	The copyright notice above does not evidence any  
+|	actual or intended publication of such source code.
+
+|setox	idnt	2,1 | Motorola 040 Floating Point Software Package
+
+	|section	8
+
+	.include "fpsp.h"
+
+L2:	.long	0x3FDC0000,0x82E30865,0x4361C4C6,0x00000000
+
+EXPA3:	.long	0x3FA55555,0x55554431
+EXPA2:	.long	0x3FC55555,0x55554018
+
+HUGE:	.long	0x7FFE0000,0xFFFFFFFF,0xFFFFFFFF,0x00000000
+TINY:	.long	0x00010000,0xFFFFFFFF,0xFFFFFFFF,0x00000000
+
+EM1A4:	.long	0x3F811111,0x11174385
+EM1A3:	.long	0x3FA55555,0x55554F5A
+
+EM1A2:	.long	0x3FC55555,0x55555555,0x00000000,0x00000000
+
+EM1B8:	.long	0x3EC71DE3,0xA5774682
+EM1B7:	.long	0x3EFA01A0,0x19D7CB68
+
+EM1B6:	.long	0x3F2A01A0,0x1A019DF3
+EM1B5:	.long	0x3F56C16C,0x16C170E2
+
+EM1B4:	.long	0x3F811111,0x11111111
+EM1B3:	.long	0x3FA55555,0x55555555
+
+EM1B2:	.long	0x3FFC0000,0xAAAAAAAA,0xAAAAAAAB
+	.long	0x00000000
+
+TWO140:	.long	0x48B00000,0x00000000
+TWON140:	.long	0x37300000,0x00000000
+
+EXPTBL:
+	.long	0x3FFF0000,0x80000000,0x00000000,0x00000000
+	.long	0x3FFF0000,0x8164D1F3,0xBC030774,0x9F841A9B
+	.long	0x3FFF0000,0x82CD8698,0xAC2BA1D8,0x9FC1D5B9
+	.long	0x3FFF0000,0x843A28C3,0xACDE4048,0xA0728369
+	.long	0x3FFF0000,0x85AAC367,0xCC487B14,0x1FC5C95C
+	.long	0x3FFF0000,0x871F6196,0x9E8D1010,0x1EE85C9F
+	.long	0x3FFF0000,0x88980E80,0x92DA8528,0x9FA20729
+	.long	0x3FFF0000,0x8A14D575,0x496EFD9C,0xA07BF9AF
+	.long	0x3FFF0000,0x8B95C1E3,0xEA8BD6E8,0xA0020DCF
+	.long	0x3FFF0000,0x8D1ADF5B,0x7E5BA9E4,0x205A63DA
+	.long	0x3FFF0000,0x8EA4398B,0x45CD53C0,0x1EB70051
+	.long	0x3FFF0000,0x9031DC43,0x1466B1DC,0x1F6EB029
+	.long	0x3FFF0000,0x91C3D373,0xAB11C338,0xA0781494
+	.long	0x3FFF0000,0x935A2B2F,0x13E6E92C,0x9EB319B0
+	.long	0x3FFF0000,0x94F4EFA8,0xFEF70960,0x2017457D
+	.long	0x3FFF0000,0x96942D37,0x20185A00,0x1F11D537
+	.long	0x3FFF0000,0x9837F051,0x8DB8A970,0x9FB952DD
+	.long	0x3FFF0000,0x99E04593,0x20B7FA64,0x1FE43087
+	.long	0x3FFF0000,0x9B8D39B9,0xD54E5538,0x1FA2A818
+	.long	0x3FFF0000,0x9D3ED9A7,0x2CFFB750,0x1FDE494D
+	.long	0x3FFF0000,0x9EF53260,0x91A111AC,0x20504890
+	.long	0x3FFF0000,0xA0B0510F,0xB9714FC4,0xA073691C
+	.long	0x3FFF0000,0xA2704303,0x0C496818,0x1F9B7A05
+	.long	0x3FFF0000,0xA43515AE,0x09E680A0,0xA0797126
+	.long	0x3FFF0000,0xA5FED6A9,0xB15138EC,0xA071A140
+	.long	0x3FFF0000,0xA7CD93B4,0xE9653568,0x204F62DA
+	.long	0x3FFF0000,0xA9A15AB4,0xEA7C0EF8,0x1F283C4A
+	.long	0x3FFF0000,0xAB7A39B5,0xA93ED338,0x9F9A7FDC
+	.long	0x3FFF0000,0xAD583EEA,0x42A14AC8,0xA05B3FAC
+	.long	0x3FFF0000,0xAF3B78AD,0x690A4374,0x1FDF2610
+	.long	0x3FFF0000,0xB123F581,0xD2AC2590,0x9F705F90
+	.long	0x3FFF0000,0xB311C412,0xA9112488,0x201F678A
+	.long	0x3FFF0000,0xB504F333,0xF9DE6484,0x1F32FB13
+	.long	0x3FFF0000,0xB6FD91E3,0x28D17790,0x20038B30
+	.long	0x3FFF0000,0xB8FBAF47,0x62FB9EE8,0x200DC3CC
+	.long	0x3FFF0000,0xBAFF5AB2,0x133E45FC,0x9F8B2AE6
+	.long	0x3FFF0000,0xBD08A39F,0x580C36C0,0xA02BBF70
+	.long	0x3FFF0000,0xBF1799B6,0x7A731084,0xA00BF518
+	.long	0x3FFF0000,0xC12C4CCA,0x66709458,0xA041DD41
+	.long	0x3FFF0000,0xC346CCDA,0x24976408,0x9FDF137B
+	.long	0x3FFF0000,0xC5672A11,0x5506DADC,0x201F1568
+	.long	0x3FFF0000,0xC78D74C8,0xABB9B15C,0x1FC13A2E
+	.long	0x3FFF0000,0xC9B9BD86,0x6E2F27A4,0xA03F8F03
+	.long	0x3FFF0000,0xCBEC14FE,0xF2727C5C,0x1FF4907D
+	.long	0x3FFF0000,0xCE248C15,0x1F8480E4,0x9E6E53E4
+	.long	0x3FFF0000,0xD06333DA,0xEF2B2594,0x1FD6D45C
+	.long	0x3FFF0000,0xD2A81D91,0xF12AE45C,0xA076EDB9
+	.long	0x3FFF0000,0xD4F35AAB,0xCFEDFA20,0x9FA6DE21
+	.long	0x3FFF0000,0xD744FCCA,0xD69D6AF4,0x1EE69A2F
+	.long	0x3FFF0000,0xD99D15C2,0x78AFD7B4,0x207F439F
+	.long	0x3FFF0000,0xDBFBB797,0xDAF23754,0x201EC207
+	.long	0x3FFF0000,0xDE60F482,0x5E0E9124,0x9E8BE175
+	.long	0x3FFF0000,0xE0CCDEEC,0x2A94E110,0x20032C4B
+	.long	0x3FFF0000,0xE33F8972,0xBE8A5A50,0x2004DFF5
+	.long	0x3FFF0000,0xE5B906E7,0x7C8348A8,0x1E72F47A
+	.long	0x3FFF0000,0xE8396A50,0x3C4BDC68,0x1F722F22
+	.long	0x3FFF0000,0xEAC0C6E7,0xDD243930,0xA017E945
+	.long	0x3FFF0000,0xED4F301E,0xD9942B84,0x1F401A5B
+	.long	0x3FFF0000,0xEFE4B99B,0xDCDAF5CC,0x9FB9A9E3
+	.long	0x3FFF0000,0xF281773C,0x59FFB138,0x20744C05
+	.long	0x3FFF0000,0xF5257D15,0x2486CC2C,0x1F773A19
+	.long	0x3FFF0000,0xF7D0DF73,0x0AD13BB8,0x1FFE90D5
+	.long	0x3FFF0000,0xFA83B2DB,0x722A033C,0xA041ED22
+	.long	0x3FFF0000,0xFD3E0C0C,0xF486C174,0x1F853F3A
+
+	.set	ADJFLAG,L_SCR2
+	.set	SCALE,FP_SCR1
+	.set	ADJSCALE,FP_SCR2
+	.set	SC,FP_SCR3
+	.set	ONEBYSC,FP_SCR4
+
+	| xref	t_frcinx
+	|xref	t_extdnrm
+	|xref	t_unfl
+	|xref	t_ovfl
+
+	.global	setoxd
+setoxd:
+|--entry point for EXP(X), X is denormalized
+	movel		(%a0),%d0
+	andil		#0x80000000,%d0
+	oril		#0x00800000,%d0		| ...sign(X)*2^(-126)
+	movel		%d0,-(%sp)
+	fmoves		#0x3F800000,%fp0
+	fmovel		%d1,%fpcr
+	fadds		(%sp)+,%fp0
+	bra		t_frcinx
+
+	.global	setox
+setox:
+|--entry point for EXP(X), here X is finite, non-zero, and not NaN's
+
+|--Step 1.
+	movel		(%a0),%d0	 | ...load part of input X
+	andil		#0x7FFF0000,%d0	| ...biased expo. of X
+	cmpil		#0x3FBE0000,%d0	| ...2^(-65)
+	bges		EXPC1		| ...normal case
+	bra		EXPSM
+
+EXPC1:
+|--The case |X| >= 2^(-65)
+	movew		4(%a0),%d0	| ...expo. and partial sig. of |X|
+	cmpil		#0x400CB167,%d0	| ...16380 log2 trunc. 16 bits
+	blts		EXPMAIN	 | ...normal case
+	bra		EXPBIG
+
+EXPMAIN:
+|--Step 2.
+|--This is the normal branch:	2^(-65) <= |X| < 16380 log2.
+	fmovex		(%a0),%fp0	| ...load input from (a0)
+
+	fmovex		%fp0,%fp1
+	fmuls		#0x42B8AA3B,%fp0	| ...64/log2 * X
+	fmovemx	%fp2-%fp2/%fp3,-(%a7)		| ...save fp2
+	movel		#0,ADJFLAG(%a6)
+	fmovel		%fp0,%d0		| ...N = int( X * 64/log2 )
+	lea		EXPTBL,%a1
+	fmovel		%d0,%fp0		| ...convert to floating-format
+
+	movel		%d0,L_SCR1(%a6)	| ...save N temporarily
+	andil		#0x3F,%d0		| ...D0 is J = N mod 64
+	lsll		#4,%d0
+	addal		%d0,%a1		| ...address of 2^(J/64)
+	movel		L_SCR1(%a6),%d0
+	asrl		#6,%d0		| ...D0 is M
+	addiw		#0x3FFF,%d0	| ...biased expo. of 2^(M)
+	movew		L2,L_SCR1(%a6)	| ...prefetch L2, no need in CB
+
+EXPCONT1:
+|--Step 3.
+|--fp1,fp2 saved on the stack. fp0 is N, fp1 is X,
+|--a0 points to 2^(J/64), D0 is biased expo. of 2^(M)
+	fmovex		%fp0,%fp2
+	fmuls		#0xBC317218,%fp0	| ...N * L1, L1 = lead(-log2/64)
+	fmulx		L2,%fp2		| ...N * L2, L1+L2 = -log2/64
+	faddx		%fp1,%fp0	 	| ...X + N*L1
+	faddx		%fp2,%fp0		| ...fp0 is R, reduced arg.
+|	MOVE.W		#$3FA5,EXPA3	...load EXPA3 in cache
+
+|--Step 4.
+|--WE NOW COMPUTE EXP(R)-1 BY A POLYNOMIAL
+|-- R + R*R*(A1 + R*(A2 + R*(A3 + R*(A4 + R*A5))))
+|--TO FULLY UTILIZE THE PIPELINE, WE COMPUTE S = R*R
+|--[R+R*S*(A2+S*A4)] + [S*(A1+S*(A3+S*A5))]
+
+	fmovex		%fp0,%fp1
+	fmulx		%fp1,%fp1	 	| ...fp1 IS S = R*R
+
+	fmoves		#0x3AB60B70,%fp2	| ...fp2 IS A5
+|	MOVE.W		#0,2(%a1)	...load 2^(J/64) in cache
+
+	fmulx		%fp1,%fp2	 	| ...fp2 IS S*A5
+	fmovex		%fp1,%fp3
+	fmuls		#0x3C088895,%fp3	| ...fp3 IS S*A4
+
+	faddd		EXPA3,%fp2	| ...fp2 IS A3+S*A5
+	faddd		EXPA2,%fp3	| ...fp3 IS A2+S*A4
+
+	fmulx		%fp1,%fp2	 	| ...fp2 IS S*(A3+S*A5)
+	movew		%d0,SCALE(%a6)	| ...SCALE is 2^(M) in extended
+	clrw		SCALE+2(%a6)
+	movel		#0x80000000,SCALE+4(%a6)
+	clrl		SCALE+8(%a6)
+
+	fmulx		%fp1,%fp3	 	| ...fp3 IS S*(A2+S*A4)
+
+	fadds		#0x3F000000,%fp2	| ...fp2 IS A1+S*(A3+S*A5)
+	fmulx		%fp0,%fp3	 	| ...fp3 IS R*S*(A2+S*A4)
+
+	fmulx		%fp1,%fp2	 	| ...fp2 IS S*(A1+S*(A3+S*A5))
+	faddx		%fp3,%fp0	 	| ...fp0 IS R+R*S*(A2+S*A4),
+|					...fp3 released
+
+	fmovex		(%a1)+,%fp1	| ...fp1 is lead. pt. of 2^(J/64)
+	faddx		%fp2,%fp0	 	| ...fp0 is EXP(R) - 1
+|					...fp2 released
+
+|--Step 5
+|--final reconstruction process
+|--EXP(X) = 2^M * ( 2^(J/64) + 2^(J/64)*(EXP(R)-1) )
+
+	fmulx		%fp1,%fp0	 	| ...2^(J/64)*(Exp(R)-1)
+	fmovemx	(%a7)+,%fp2-%fp2/%fp3	| ...fp2 restored
+	fadds		(%a1),%fp0	| ...accurate 2^(J/64)
+
+	faddx		%fp1,%fp0	 	| ...2^(J/64) + 2^(J/64)*...
+	movel		ADJFLAG(%a6),%d0
+
+|--Step 6
+	tstl		%d0
+	beqs		NORMAL
+ADJUST:
+	fmulx		ADJSCALE(%a6),%fp0
+NORMAL:
+	fmovel		%d1,%FPCR	 	| ...restore user FPCR
+	fmulx		SCALE(%a6),%fp0	| ...multiply 2^(M)
+	bra		t_frcinx
+
+EXPSM:
+|--Step 7
+	fmovemx	(%a0),%fp0-%fp0	| ...in case X is denormalized
+	fmovel		%d1,%FPCR
+	fadds		#0x3F800000,%fp0	| ...1+X in user mode
+	bra		t_frcinx
+
+EXPBIG:
+|--Step 8
+	cmpil		#0x400CB27C,%d0	| ...16480 log2
+	bgts		EXP2BIG
+|--Steps 8.2 -- 8.6
+	fmovex		(%a0),%fp0	| ...load input from (a0)
+
+	fmovex		%fp0,%fp1
+	fmuls		#0x42B8AA3B,%fp0	| ...64/log2 * X
+	fmovemx	 %fp2-%fp2/%fp3,-(%a7)		| ...save fp2
+	movel		#1,ADJFLAG(%a6)
+	fmovel		%fp0,%d0		| ...N = int( X * 64/log2 )
+	lea		EXPTBL,%a1
+	fmovel		%d0,%fp0		| ...convert to floating-format
+	movel		%d0,L_SCR1(%a6)			| ...save N temporarily
+	andil		#0x3F,%d0		 | ...D0 is J = N mod 64
+	lsll		#4,%d0
+	addal		%d0,%a1			| ...address of 2^(J/64)
+	movel		L_SCR1(%a6),%d0
+	asrl		#6,%d0			| ...D0 is K
+	movel		%d0,L_SCR1(%a6)			| ...save K temporarily
+	asrl		#1,%d0			| ...D0 is M1
+	subl		%d0,L_SCR1(%a6)			| ...a1 is M
+	addiw		#0x3FFF,%d0		| ...biased expo. of 2^(M1)
+	movew		%d0,ADJSCALE(%a6)		| ...ADJSCALE := 2^(M1)
+	clrw		ADJSCALE+2(%a6)
+	movel		#0x80000000,ADJSCALE+4(%a6)
+	clrl		ADJSCALE+8(%a6)
+	movel		L_SCR1(%a6),%d0			| ...D0 is M
+	addiw		#0x3FFF,%d0		| ...biased expo. of 2^(M)
+	bra		EXPCONT1		| ...go back to Step 3
+
+EXP2BIG:
+|--Step 9
+	fmovel		%d1,%FPCR
+	movel		(%a0),%d0
+	bclrb		#sign_bit,(%a0)		| ...setox always returns positive
+	cmpil		#0,%d0
+	blt		t_unfl
+	bra		t_ovfl
+
+	.global	setoxm1d
+setoxm1d:
+|--entry point for EXPM1(X), here X is denormalized
+|--Step 0.
+	bra		t_extdnrm
+
+
+	.global	setoxm1
+setoxm1:
+|--entry point for EXPM1(X), here X is finite, non-zero, non-NaN
+
+|--Step 1.
+|--Step 1.1
+	movel		(%a0),%d0	 | ...load part of input X
+	andil		#0x7FFF0000,%d0	| ...biased expo. of X
+	cmpil		#0x3FFD0000,%d0	| ...1/4
+	bges		EM1CON1	 | ...|X| >= 1/4
+	bra		EM1SM
+
+EM1CON1:
+|--Step 1.3
+|--The case |X| >= 1/4
+	movew		4(%a0),%d0	| ...expo. and partial sig. of |X|
+	cmpil		#0x4004C215,%d0	| ...70log2 rounded up to 16 bits
+	bles		EM1MAIN	 | ...1/4 <= |X| <= 70log2
+	bra		EM1BIG
+
+EM1MAIN:
+|--Step 2.
+|--This is the case:	1/4 <= |X| <= 70 log2.
+	fmovex		(%a0),%fp0	| ...load input from (a0)
+
+	fmovex		%fp0,%fp1
+	fmuls		#0x42B8AA3B,%fp0	| ...64/log2 * X
+	fmovemx	%fp2-%fp2/%fp3,-(%a7)		| ...save fp2
+|	MOVE.W		#$3F81,EM1A4		...prefetch in CB mode
+	fmovel		%fp0,%d0		| ...N = int( X * 64/log2 )
+	lea		EXPTBL,%a1
+	fmovel		%d0,%fp0		| ...convert to floating-format
+
+	movel		%d0,L_SCR1(%a6)			| ...save N temporarily
+	andil		#0x3F,%d0		 | ...D0 is J = N mod 64
+	lsll		#4,%d0
+	addal		%d0,%a1			| ...address of 2^(J/64)
+	movel		L_SCR1(%a6),%d0
+	asrl		#6,%d0			| ...D0 is M
+	movel		%d0,L_SCR1(%a6)			| ...save a copy of M
+|	MOVE.W		#$3FDC,L2		...prefetch L2 in CB mode
+
+|--Step 3.
+|--fp1,fp2 saved on the stack. fp0 is N, fp1 is X,
+|--a0 points to 2^(J/64), D0 and a1 both contain M
+	fmovex		%fp0,%fp2
+	fmuls		#0xBC317218,%fp0	| ...N * L1, L1 = lead(-log2/64)
+	fmulx		L2,%fp2		| ...N * L2, L1+L2 = -log2/64
+	faddx		%fp1,%fp0	 | ...X + N*L1
+	faddx		%fp2,%fp0	 | ...fp0 is R, reduced arg.
+|	MOVE.W		#$3FC5,EM1A2		...load EM1A2 in cache
+	addiw		#0x3FFF,%d0		| ...D0 is biased expo. of 2^M
+
+|--Step 4.
+|--WE NOW COMPUTE EXP(R)-1 BY A POLYNOMIAL
+|-- R + R*R*(A1 + R*(A2 + R*(A3 + R*(A4 + R*(A5 + R*A6)))))
+|--TO FULLY UTILIZE THE PIPELINE, WE COMPUTE S = R*R
+|--[R*S*(A2+S*(A4+S*A6))] + [R+S*(A1+S*(A3+S*A5))]
+
+	fmovex		%fp0,%fp1
+	fmulx		%fp1,%fp1		| ...fp1 IS S = R*R
+
+	fmoves		#0x3950097B,%fp2	| ...fp2 IS a6
+|	MOVE.W		#0,2(%a1)	...load 2^(J/64) in cache
+
+	fmulx		%fp1,%fp2		| ...fp2 IS S*A6
+	fmovex		%fp1,%fp3
+	fmuls		#0x3AB60B6A,%fp3	| ...fp3 IS S*A5
+
+	faddd		EM1A4,%fp2	| ...fp2 IS A4+S*A6
+	faddd		EM1A3,%fp3	| ...fp3 IS A3+S*A5
+	movew		%d0,SC(%a6)		| ...SC is 2^(M) in extended
+	clrw		SC+2(%a6)
+	movel		#0x80000000,SC+4(%a6)
+	clrl		SC+8(%a6)
+
+	fmulx		%fp1,%fp2		| ...fp2 IS S*(A4+S*A6)
+	movel		L_SCR1(%a6),%d0		| ...D0 is	M
+	negw		%d0		| ...D0 is -M
+	fmulx		%fp1,%fp3		| ...fp3 IS S*(A3+S*A5)
+	addiw		#0x3FFF,%d0	| ...biased expo. of 2^(-M)
+	faddd		EM1A2,%fp2	| ...fp2 IS A2+S*(A4+S*A6)
+	fadds		#0x3F000000,%fp3	| ...fp3 IS A1+S*(A3+S*A5)
+
+	fmulx		%fp1,%fp2		| ...fp2 IS S*(A2+S*(A4+S*A6))
+	oriw		#0x8000,%d0	| ...signed/expo. of -2^(-M)
+	movew		%d0,ONEBYSC(%a6)	| ...OnebySc is -2^(-M)
+	clrw		ONEBYSC+2(%a6)
+	movel		#0x80000000,ONEBYSC+4(%a6)
+	clrl		ONEBYSC+8(%a6)
+	fmulx		%fp3,%fp1		| ...fp1 IS S*(A1+S*(A3+S*A5))
+|					...fp3 released
+
+	fmulx		%fp0,%fp2		| ...fp2 IS R*S*(A2+S*(A4+S*A6))
+	faddx		%fp1,%fp0		| ...fp0 IS R+S*(A1+S*(A3+S*A5))
+|					...fp1 released
+
+	faddx		%fp2,%fp0		| ...fp0 IS EXP(R)-1
+|					...fp2 released
+	fmovemx	(%a7)+,%fp2-%fp2/%fp3	| ...fp2 restored
+
+|--Step 5
+|--Compute 2^(J/64)*p
+
+	fmulx		(%a1),%fp0	| ...2^(J/64)*(Exp(R)-1)
+
+|--Step 6
+|--Step 6.1
+	movel		L_SCR1(%a6),%d0		| ...retrieve M
+	cmpil		#63,%d0
+	bles		MLE63
+|--Step 6.2	M >= 64
+	fmoves		12(%a1),%fp1	| ...fp1 is t
+	faddx		ONEBYSC(%a6),%fp1	| ...fp1 is t+OnebySc
+	faddx		%fp1,%fp0		| ...p+(t+OnebySc), fp1 released
+	faddx		(%a1),%fp0	| ...T+(p+(t+OnebySc))
+	bras		EM1SCALE
+MLE63:
+|--Step 6.3	M <= 63
+	cmpil		#-3,%d0
+	bges		MGEN3
+MLTN3:
+|--Step 6.4	M <= -4
+	fadds		12(%a1),%fp0	| ...p+t
+	faddx		(%a1),%fp0	| ...T+(p+t)
+	faddx		ONEBYSC(%a6),%fp0	| ...OnebySc + (T+(p+t))
+	bras		EM1SCALE
+MGEN3:
+|--Step 6.5	-3 <= M <= 63
+	fmovex		(%a1)+,%fp1	| ...fp1 is T
+	fadds		(%a1),%fp0	| ...fp0 is p+t
+	faddx		ONEBYSC(%a6),%fp1	| ...fp1 is T+OnebySc
+	faddx		%fp1,%fp0		| ...(T+OnebySc)+(p+t)
+
+EM1SCALE:
+|--Step 6.6
+	fmovel		%d1,%FPCR
+	fmulx		SC(%a6),%fp0
+
+	bra		t_frcinx
+
+EM1SM:
+|--Step 7	|X| < 1/4.
+	cmpil		#0x3FBE0000,%d0	| ...2^(-65)
+	bges		EM1POLY
+
+EM1TINY:
+|--Step 8	|X| < 2^(-65)
+	cmpil		#0x00330000,%d0	| ...2^(-16312)
+	blts		EM12TINY
+|--Step 8.2
+	movel		#0x80010000,SC(%a6)	| ...SC is -2^(-16382)
+	movel		#0x80000000,SC+4(%a6)
+	clrl		SC+8(%a6)
+	fmovex		(%a0),%fp0
+	fmovel		%d1,%FPCR
+	faddx		SC(%a6),%fp0
+
+	bra		t_frcinx
+
+EM12TINY:
+|--Step 8.3
+	fmovex		(%a0),%fp0
+	fmuld		TWO140,%fp0
+	movel		#0x80010000,SC(%a6)
+	movel		#0x80000000,SC+4(%a6)
+	clrl		SC+8(%a6)
+	faddx		SC(%a6),%fp0
+	fmovel		%d1,%FPCR
+	fmuld		TWON140,%fp0
+
+	bra		t_frcinx
+
+EM1POLY:
+|--Step 9	exp(X)-1 by a simple polynomial
+	fmovex		(%a0),%fp0	| ...fp0 is X
+	fmulx		%fp0,%fp0		| ...fp0 is S := X*X
+	fmovemx	%fp2-%fp2/%fp3,-(%a7)	| ...save fp2
+	fmoves		#0x2F30CAA8,%fp1	| ...fp1 is B12
+	fmulx		%fp0,%fp1		| ...fp1 is S*B12
+	fmoves		#0x310F8290,%fp2	| ...fp2 is B11
+	fadds		#0x32D73220,%fp1	| ...fp1 is B10+S*B12
+
+	fmulx		%fp0,%fp2		| ...fp2 is S*B11
+	fmulx		%fp0,%fp1		| ...fp1 is S*(B10 + ...
+
+	fadds		#0x3493F281,%fp2	| ...fp2 is B9+S*...
+	faddd		EM1B8,%fp1	| ...fp1 is B8+S*...
+
+	fmulx		%fp0,%fp2		| ...fp2 is S*(B9+...
+	fmulx		%fp0,%fp1		| ...fp1 is S*(B8+...
+
+	faddd		EM1B7,%fp2	| ...fp2 is B7+S*...
+	faddd		EM1B6,%fp1	| ...fp1 is B6+S*...
+
+	fmulx		%fp0,%fp2		| ...fp2 is S*(B7+...
+	fmulx		%fp0,%fp1		| ...fp1 is S*(B6+...
+
+	faddd		EM1B5,%fp2	| ...fp2 is B5+S*...
+	faddd		EM1B4,%fp1	| ...fp1 is B4+S*...
+
+	fmulx		%fp0,%fp2		| ...fp2 is S*(B5+...
+	fmulx		%fp0,%fp1		| ...fp1 is S*(B4+...
+
+	faddd		EM1B3,%fp2	| ...fp2 is B3+S*...
+	faddx		EM1B2,%fp1	| ...fp1 is B2+S*...
+
+	fmulx		%fp0,%fp2		| ...fp2 is S*(B3+...
+	fmulx		%fp0,%fp1		| ...fp1 is S*(B2+...
+
+	fmulx		%fp0,%fp2		| ...fp2 is S*S*(B3+...)
+	fmulx		(%a0),%fp1	| ...fp1 is X*S*(B2...
+
+	fmuls		#0x3F000000,%fp0	| ...fp0 is S*B1
+	faddx		%fp2,%fp1		| ...fp1 is Q
+|					...fp2 released
+
+	fmovemx	(%a7)+,%fp2-%fp2/%fp3	| ...fp2 restored
+
+	faddx		%fp1,%fp0		| ...fp0 is S*B1+Q
+|					...fp1 released
+
+	fmovel		%d1,%FPCR
+	faddx		(%a0),%fp0
+
+	bra		t_frcinx
+
+EM1BIG:
+|--Step 10	|X| > 70 log2
+	movel		(%a0),%d0
+	cmpil		#0,%d0
+	bgt		EXPC1
+|--Step 10.2
+	fmoves		#0xBF800000,%fp0	| ...fp0 is -1
+	fmovel		%d1,%FPCR
+	fadds		#0x00800000,%fp0	| ...-1 + 2^(-126)
+
+	bra		t_frcinx
+
+	|end
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/fpsp040/sgetem.S linux/arch/m68k/fpsp040/sgetem.S
--- v1.3.93/linux/arch/m68k/fpsp040/sgetem.S	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/fpsp040/sgetem.S	Sat Feb 24 22:58:44 1996
@@ -0,0 +1,141 @@
+|
+|	sgetem.sa 3.1 12/10/90
+|
+|	The entry point sGETEXP returns the exponent portion 
+|	of the input argument.  The exponent bias is removed
+|	and the exponent value is returned as an extended 
+|	precision number in fp0.  sGETEXPD handles denormalized
+|	numbers.
+|
+|	The entry point sGETMAN extracts the mantissa of the 
+|	input argument.  The mantissa is converted to an 
+|	extended precision number and returned in fp0.  The
+|	range of the result is [1.0 - 2.0).
+|
+|
+|	Input:  Double-extended number X in the ETEMP space in
+|		the floating-point save stack.
+|
+|	Output:	The functions return exp(X) or man(X) in fp0.
+|
+|	Modified: fp0.
+|
+|
+|		Copyright (C) Motorola, Inc. 1990
+|			All Rights Reserved
+|
+|	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA 
+|	The copyright notice above does not evidence any  
+|	actual or intended publication of such source code.
+
+|SGETEM	idnt	2,1 | Motorola 040 Floating Point Software Package
+
+	|section 8
+
+	.include "fpsp.h"
+
+	|xref	nrm_set
+
+|
+| This entry point is used by the unimplemented instruction exception
+| handler.  It points a0 to the input operand.
+|
+|
+|
+|	SGETEXP
+|
+
+	.global	sgetexp
+sgetexp:
+	movew	LOCAL_EX(%a0),%d0	|get the exponent
+	bclrl	#15,%d0		|clear the sign bit
+	subw	#0x3fff,%d0	|subtract off the bias
+	fmovew  %d0,%fp0		|move the exp to fp0
+	rts
+
+	.global	sgetexpd
+sgetexpd:
+	bclrb	#sign_bit,LOCAL_EX(%a0)
+	bsr	nrm_set		|normalize (exp will go negative)
+	movew	LOCAL_EX(%a0),%d0	|load resulting exponent into d0
+	subw	#0x3fff,%d0	|subtract off the bias
+	fmovew	%d0,%fp0		|move the exp to fp0
+	rts
+|
+|
+| This entry point is used by the unimplemented instruction exception
+| handler.  It points a0 to the input operand.
+|
+|
+|
+|	SGETMAN
+|
+|
+| For normalized numbers, leave the mantissa alone, simply load
+| with an exponent of +/- $3fff.
+|
+	.global	sgetman
+sgetman:
+	movel	USER_FPCR(%a6),%d0
+	andil	#0xffffff00,%d0	|clear rounding precision and mode
+	fmovel	%d0,%fpcr		|this fpcr setting is used by the 882
+	movew	LOCAL_EX(%a0),%d0	|get the exp (really just want sign bit)
+	orw	#0x7fff,%d0	|clear old exp
+	bclrl	#14,%d0	 	|make it the new exp +-3fff
+	movew	%d0,LOCAL_EX(%a0)	|move the sign & exp back to fsave stack
+	fmovex	(%a0),%fp0	|put new value back in fp0
+	rts
+
+|
+| For denormalized numbers, shift the mantissa until the j-bit = 1,
+| then load the exponent with +/1 $3fff.
+|
+	.global	sgetmand
+sgetmand:
+	movel	LOCAL_HI(%a0),%d0	|load ms mant in d0
+	movel	LOCAL_LO(%a0),%d1	|load ls mant in d1
+	bsr	shft		|shift mantissa bits till msbit is set
+	movel	%d0,LOCAL_HI(%a0)	|put ms mant back on stack
+	movel	%d1,LOCAL_LO(%a0)	|put ls mant back on stack
+	bras	sgetman
+
+|
+|	SHFT
+|
+|	Shifts the mantissa bits until msbit is set.
+|	input:
+|		ms mantissa part in d0
+|		ls mantissa part in d1
+|	output:
+|		shifted bits in d0 and d1
+shft:
+	tstl	%d0		|if any bits set in ms mant
+	bnes	upper		|then branch
+|				;else no bits set in ms mant
+	tstl	%d1		|test if any bits set in ls mant
+	bnes	cont		|if set then continue
+	bras	shft_end	|else return
+cont:
+	movel	%d3,-(%a7)	|save d3
+	exg	%d0,%d1		|shift ls mant to ms mant
+	bfffo	%d0{#0:#32},%d3	|find first 1 in ls mant to d0
+	lsll	%d3,%d0		|shift first 1 to integer bit in ms mant
+	movel	(%a7)+,%d3	|restore d3
+	bras	shft_end
+upper:
+
+	moveml	%d3/%d5/%d6,-(%a7)	|save registers
+	bfffo	%d0{#0:#32},%d3	|find first 1 in ls mant to d0
+	lsll	%d3,%d0		|shift ms mant until j-bit is set
+	movel	%d1,%d6		|save ls mant in d6
+	lsll	%d3,%d1		|shift ls mant by count
+	movel	#32,%d5
+	subl	%d3,%d5		|sub 32 from shift for ls mant
+	lsrl	%d5,%d6		|shift off all bits but those that will
+|				;be shifted into ms mant
+	orl	%d6,%d0		|shift the ls mant bits into the ms mant
+	moveml	(%a7)+,%d3/%d5/%d6	|restore registers
+shft_end:
+	rts
+
+	|end
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/fpsp040/sint.S linux/arch/m68k/fpsp040/sint.S
--- v1.3.93/linux/arch/m68k/fpsp040/sint.S	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/fpsp040/sint.S	Sat Feb 24 22:58:44 1996
@@ -0,0 +1,247 @@
+|
+|	sint.sa 3.1 12/10/90
+|
+|	The entry point sINT computes the rounded integer 
+|	equivalent of the input argument, sINTRZ computes 
+|	the integer rounded to zero of the input argument.
+|
+|	Entry points sint and sintrz are called from do_func
+|	to emulate the fint and fintrz unimplemented instructions,
+|	respectively.  Entry point sintdo is used by bindec.
+|
+|	Input: (Entry points sint and sintrz) Double-extended
+|		number X in the ETEMP space in the floating-point
+|		save stack.
+|	       (Entry point sintdo) Double-extended number X in
+|		location pointed to by the address register a0.
+|	       (Entry point sintd) Double-extended denormalized
+|		number X in the ETEMP space in the floating-point
+|		save stack.
+|
+|	Output: The function returns int(X) or intrz(X) in fp0.
+|
+|	Modifies: fp0.
+|
+|	Algorithm: (sint and sintrz)
+|
+|	1. If exp(X) >= 63, return X. 
+|	   If exp(X) < 0, return +/- 0 or +/- 1, according to
+|	   the rounding mode.
+|	
+|	2. (X is in range) set rsc = 63 - exp(X). Unnormalize the
+|	   result to the exponent $403e.
+|
+|	3. Round the result in the mode given in USER_FPCR. For
+|	   sintrz, force round-to-zero mode.
+|
+|	4. Normalize the rounded result; store in fp0.
+|
+|	For the denormalized cases, force the correct result
+|	for the given sign and rounding mode.
+|
+|		        Sign(X)
+|		RMODE   +    -
+|		-----  --------
+|		 RN    +0   -0
+|		 RZ    +0   -0
+|		 RM    +0   -1
+|		 RP    +1   -0
+|
+|
+|		Copyright (C) Motorola, Inc. 1990
+|			All Rights Reserved
+|
+|	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA 
+|	The copyright notice above does not evidence any  
+|	actual or intended publication of such source code.
+
+|SINT    idnt    2,1 | Motorola 040 Floating Point Software Package
+
+	|section	8
+
+	.include "fpsp.h"
+
+	|xref	dnrm_lp
+	|xref	nrm_set
+	|xref	round
+	|xref	t_inx2
+	|xref	ld_pone
+	|xref	ld_mone
+	|xref	ld_pzero
+	|xref	ld_mzero
+	|xref	snzrinx
+
+|
+|	FINT
+|
+	.global	sint
+sint:
+	bfextu	FPCR_MODE(%a6){#2:#2},%d1	|use user's mode for rounding
+|					;implicity has extend precision
+|					;in upper word. 
+	movel	%d1,L_SCR1(%a6)		|save mode bits
+	bras	sintexc			
+
+|
+|	FINT with extended denorm inputs.
+|
+	.global	sintd
+sintd:
+	btstb	#5,FPCR_MODE(%a6)
+	beq	snzrinx		|if round nearest or round zero, +/- 0
+	btstb	#4,FPCR_MODE(%a6)
+	beqs	rnd_mns
+rnd_pls:
+	btstb	#sign_bit,LOCAL_EX(%a0)
+	bnes	sintmz
+	bsr	ld_pone		|if round plus inf and pos, answer is +1
+	bra	t_inx2
+rnd_mns:
+	btstb	#sign_bit,LOCAL_EX(%a0)
+	beqs	sintpz
+	bsr	ld_mone		|if round mns inf and neg, answer is -1
+	bra	t_inx2
+sintpz:
+	bsr	ld_pzero
+	bra	t_inx2
+sintmz:
+	bsr	ld_mzero
+	bra	t_inx2
+
+|
+|	FINTRZ
+|
+	.global	sintrz
+sintrz:
+	movel	#1,L_SCR1(%a6)		|use rz mode for rounding
+|					;implicity has extend precision
+|					;in upper word. 
+	bras	sintexc			
+|
+|	SINTDO
+|
+|	Input:	a0 points to an IEEE extended format operand
+| 	Output:	fp0 has the result 
+|
+| Exeptions:
+|
+| If the subroutine results in an inexact operation, the inx2 and
+| ainx bits in the USER_FPSR are set.
+|
+|
+	.global	sintdo
+sintdo:
+	bfextu	FPCR_MODE(%a6){#2:#2},%d1	|use user's mode for rounding
+|					;implicitly has ext precision
+|					;in upper word. 
+	movel	%d1,L_SCR1(%a6)		|save mode bits
+|
+| Real work of sint is in sintexc
+|
+sintexc:
+	bclrb	#sign_bit,LOCAL_EX(%a0)	|convert to internal extended
+|					;format
+	sne	LOCAL_SGN(%a0)		
+	cmpw	#0x403e,LOCAL_EX(%a0)	|check if (unbiased) exp > 63
+	bgts	out_rnge			|branch if exp < 63
+	cmpw	#0x3ffd,LOCAL_EX(%a0)	|check if (unbiased) exp < 0
+	bgt	in_rnge			|if 63 >= exp > 0, do calc
+|
+| Input is less than zero.  Restore sign, and check for directed
+| rounding modes.  L_SCR1 contains the rmode in the lower byte.
+|
+un_rnge:
+	btstb	#1,L_SCR1+3(%a6)		|check for rn and rz
+	beqs	un_rnrz
+	tstb	LOCAL_SGN(%a0)		|check for sign
+	bnes	un_rmrp_neg
+|
+| Sign is +.  If rp, load +1.0, if rm, load +0.0
+|
+	cmpib	#3,L_SCR1+3(%a6)		|check for rp
+	beqs	un_ldpone		|if rp, load +1.0
+	bsr	ld_pzero		|if rm, load +0.0
+	bra	t_inx2
+un_ldpone:
+	bsr	ld_pone
+	bra	t_inx2
+|
+| Sign is -.  If rm, load -1.0, if rp, load -0.0
+|
+un_rmrp_neg:
+	cmpib	#2,L_SCR1+3(%a6)		|check for rm
+	beqs	un_ldmone		|if rm, load -1.0
+	bsr	ld_mzero		|if rp, load -0.0
+	bra	t_inx2
+un_ldmone:
+	bsr	ld_mone
+	bra	t_inx2
+|
+| Rmode is rn or rz; return signed zero
+|
+un_rnrz:
+	tstb	LOCAL_SGN(%a0)		|check for sign
+	bnes	un_rnrz_neg
+	bsr	ld_pzero
+	bra	t_inx2
+un_rnrz_neg:
+	bsr	ld_mzero
+	bra	t_inx2
+	
+|
+| Input is greater than 2^63.  All bits are significant.  Return
+| the input.
+|
+out_rnge:
+	bfclr	LOCAL_SGN(%a0){#0:#8}	|change back to IEEE ext format
+	beqs	intps
+	bsetb	#sign_bit,LOCAL_EX(%a0)
+intps:
+	fmovel	%fpcr,-(%sp)
+	fmovel	#0,%fpcr
+	fmovex LOCAL_EX(%a0),%fp0	|if exp > 63
+|					;then return X to the user
+|					;there are no fraction bits
+	fmovel	(%sp)+,%fpcr
+	rts
+
+in_rnge:
+| 					;shift off fraction bits
+	clrl	%d0			|clear d0 - initial g,r,s for
+|					;dnrm_lp
+	movel	#0x403e,%d1		|set threshold for dnrm_lp
+|					;assumes a0 points to operand
+	bsr	dnrm_lp
+|					;returns unnormalized number
+|					;pointed by a0
+|					;output d0 supplies g,r,s
+|					;used by round
+	movel	L_SCR1(%a6),%d1		|use selected rounding mode
+|
+|
+	bsr	round			|round the unnorm based on users
+|					;input	a0 ptr to ext X
+|					;	d0 g,r,s bits
+|					;	d1 PREC/MODE info
+|					;output a0 ptr to rounded result
+|					;inexact flag set in USER_FPSR
+|					;if initial grs set
+|
+| normalize the rounded result and store value in fp0
+|
+	bsr	nrm_set			|normalize the unnorm
+|					;Input: a0 points to operand to
+|					;be normalized
+|					;Output: a0 points to normalized
+|					;result
+	bfclr	LOCAL_SGN(%a0){#0:#8}
+	beqs	nrmrndp
+	bsetb	#sign_bit,LOCAL_EX(%a0)	|return to IEEE extended format
+nrmrndp:
+	fmovel	%fpcr,-(%sp)
+	fmovel	#0,%fpcr
+	fmovex LOCAL_EX(%a0),%fp0	|move result to fp0
+	fmovel	(%sp)+,%fpcr
+	rts
+
+	|end
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/fpsp040/skeleton.S linux/arch/m68k/fpsp040/skeleton.S
--- v1.3.93/linux/arch/m68k/fpsp040/skeleton.S	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/fpsp040/skeleton.S	Sat Apr 13 19:59:44 1996
@@ -0,0 +1,568 @@
+|
+|	skeleton.sa 3.2 4/26/91
+|
+|	This file contains code that is system dependent and will
+|	need to be modified to install the FPSP.
+|
+|	Each entry point for exception 'xxxx' begins with a 'jmp fpsp_xxxx'.
+|	Put any target system specific handling that must be done immediately
+|	before the jump instruction.  If there no handling necessary, then
+|	the 'fpsp_xxxx' handler entry point should be placed in the exception
+|	table so that the 'jmp' can be eliminated. If the FPSP determines that the
+|	exception is one that must be reported then there will be a
+|	return from the package by a 'jmp real_xxxx'.  At that point
+|	the machine state will be identical to the state before
+|	the FPSP was entered.  In particular, whatever condition
+|	that caused the exception will still be pending when the FPSP
+|	package returns.  Thus, there will be system specific code
+|	to handle the exception.
+|
+|	If the exception was completely handled by the package, then
+|	the return will be via a 'jmp fpsp_done'.  Unless there is 
+|	OS specific work to be done (such as handling a context switch or
+|	interrupt) the user program can be resumed via 'rte'.
+|
+|	In the following skeleton code, some typical 'real_xxxx' handling
+|	code is shown.  This code may need to be moved to an appropriate
+|	place in the target system, or rewritten.
+|	
+
+|		Copyright (C) Motorola, Inc. 1990
+|			All Rights Reserved
+|
+|	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA 
+|	The copyright notice above does not evidence any  
+|	actual or intended publication of such source code.
+
+|
+|	Modified for Linux-1.3.x by Jes Sorensen (jds@kom.auc.dk)
+|
+
+#include <linux/linkage.h>
+
+|SKELETON	idnt    2,1 | Motorola 040 Floating Point Software Package
+
+	|section 15
+|
+|	The following counters are used for standalone testing
+|
+sigunimp:	.long	0
+sigbsun:		.long	0
+siginex:		.long	0
+sigdz:		.long	0
+sigunfl:		.long	0
+sigovfl:		.long	0
+sigoperr:	.long	0
+sigsnan:		.long	0
+sigunsupp:	.long	0
+
+	|section 8
+ 
+	.include "fpsp.h"
+
+LOFF_ORIG_D0	= 0x20
+
+#define SAVE_ALL				\
+	clrl	%sp@-;     /* stk_adj */	\
+	movel	%d0,%sp@-; /* orig d0 */	\
+	movel	%d0,%sp@-; /* d0 */		\
+	moveml	%d1-%d5/%a0-%a1,%sp@-
+
+	|xref	b1238_fix
+
+|
+|	Divide by Zero exception
+|
+|	All dz exceptions are 'real', hence no fpsp_dz entry point.
+|
+	.global	dz
+	.global	real_dz
+dz:
+real_dz:
+	link		%a6,#-LOCAL_SIZE
+	fsave		-(%sp)
+	bclrb		#E1,E_BYTE(%a6)
+	frestore	(%sp)+
+	unlk		%a6
+
+	addl	#1,sigdz		|for standalone testing
+
+	SAVE_ALL
+	moveq	#-1,%d0
+	movel	%d0,%sp@(LOFF_ORIG_D0)    | a -1 in the ORIG_D0 field
+					| signifies that the stack frame
+					| is NOT for syscall
+	movel	%sp,%sp@- 		| stack frame pointer argument
+	bsrl	SYMBOL_NAME(trap_c)
+	addql	#4,%sp
+	bral	SYMBOL_NAME(ret_from_exception)
+
+|
+|	Inexact exception
+|
+|	All inexact exceptions are real, but the 'real' handler
+|	will probably want to clear the pending exception.
+|	The provided code will clear the E3 exception (if pending), 
+|	otherwise clear the E1 exception.  The frestore is not really
+|	necessary for E1 exceptions.
+|
+| Code following the 'inex' label is to handle bug #1232.  In this
+| bug, if an E1 snan, ovfl, or unfl occured, and the process was
+| swapped out before taking the exception, the exception taken on
+| return was inex, rather than the correct exception.  The snan, ovfl,
+| and unfl exception to be taken must not have been enabled.  The
+| fix is to check for E1, and the existence of one of snan, ovfl,
+| or unfl bits set in the fpsr.  If any of these are set, branch
+| to the appropriate  handler for the exception in the fpsr.  Note
+| that this fix is only for d43b parts, and is skipped if the
+| version number is not $40.
+| 
+|
+	.global	real_inex
+	.global	inex
+inex:
+	link		%a6,#-LOCAL_SIZE
+	fsave		-(%sp)
+	cmpib		#VER_40,(%sp)		|test version number
+	bnes		not_fmt40
+	fmovel		%fpsr,-(%sp)
+	btstb		#E1,E_BYTE(%a6)		|test for E1 set
+	beqs		not_b1232
+	btstb		#snan_bit,2(%sp) |test for snan
+	beq		inex_ckofl
+	addl		#4,%sp
+	frestore	(%sp)+
+	unlk		%a6
+	bra		snan
+inex_ckofl:
+	btstb		#ovfl_bit,2(%sp) |test for ovfl
+	beq		inex_ckufl 
+	addl		#4,%sp
+	frestore	(%sp)+
+	unlk		%a6
+	bra		ovfl
+inex_ckufl:
+	btstb		#unfl_bit,2(%sp) |test for unfl
+	beq		not_b1232
+	addl		#4,%sp
+	frestore	(%sp)+
+	unlk		%a6
+	bra		unfl
+
+|
+| We do not have the bug 1232 case.  Clean up the stack and call
+| real_inex.
+|
+not_b1232:
+	addl		#4,%sp
+	frestore	(%sp)+
+	unlk		%a6
+
+real_inex:
+
+	addl		#1,siginex		|for standalone testing
+
+	link		%a6,#-LOCAL_SIZE
+	fsave		-(%sp)
+not_fmt40:
+	bclrb		#E3,E_BYTE(%a6)		|clear and test E3 flag
+	beqs		inex_cke1
+|
+| Clear dirty bit on dest resister in the frame before branching
+| to b1238_fix.
+|
+	moveml		%d0/%d1,USER_DA(%a6)
+	bfextu		CMDREG1B(%a6){#6:#3},%d0		|get dest reg no
+	bclrb		%d0,FPR_DIRTY_BITS(%a6)	|clr dest dirty bit
+	bsrl		b1238_fix		|test for bug1238 case
+	moveml		USER_DA(%a6),%d0/%d1
+	bras		inex_done
+inex_cke1:
+	bclrb		#E1,E_BYTE(%a6)
+inex_done:
+	frestore	(%sp)+
+	unlk		%a6
+
+	SAVE_ALL
+	moveq	#-1,%d0
+	movel	%d0,%sp@(LOFF_ORIG_D0)    | a -1 in the ORIG_D0 field
+					| signifies that the stack frame
+					| is NOT for syscall
+	movel	%sp,%sp@- 		| stack frame pointer argument
+	bsrl	SYMBOL_NAME(trap_c)
+	addql	#4,%sp
+	bral	SYMBOL_NAME(ret_from_exception)
+	
+|
+|	Overflow exception
+|
+	|xref	fpsp_ovfl
+	.global	real_ovfl
+	.global	ovfl
+ovfl:
+	jmp	fpsp_ovfl
+real_ovfl:
+
+	addl		#1,sigovfl		|for standalone testing
+
+	link		%a6,#-LOCAL_SIZE
+	fsave		-(%sp)
+	bclrb		#E3,E_BYTE(%a6)		|clear and test E3 flag
+	bnes		ovfl_done
+	bclrb		#E1,E_BYTE(%a6)
+ovfl_done:
+	frestore	(%sp)+
+	unlk		%a6
+
+	SAVE_ALL
+	moveq	#-1,%d0
+	movel	%d0,%sp@(LOFF_ORIG_D0)    | a -1 in the ORIG_D0 field
+					| signifies that the stack frame
+					| is NOT for syscall
+	movel	%sp,%sp@- 		| stack frame pointer argument
+	bsrl	SYMBOL_NAME(trap_c)
+	addql	#4,%sp
+	bral	SYMBOL_NAME(ret_from_exception)
+	
+|
+|	Underflow exception
+|
+	|xref	fpsp_unfl
+	.global	real_unfl
+	.global	unfl
+unfl:
+	jmp	fpsp_unfl
+real_unfl:
+
+	addl		#1,sigunfl		|for standalone testing
+
+	link		%a6,#-LOCAL_SIZE
+	fsave		-(%sp)
+	bclrb		#E3,E_BYTE(%a6)		|clear and test E3 flag
+	bnes		unfl_done
+	bclrb		#E1,E_BYTE(%a6)
+unfl_done:
+	frestore	(%sp)+
+	unlk		%a6
+
+	SAVE_ALL
+	moveq	#-1,%d0
+	movel	%d0,%sp@(LOFF_ORIG_D0)    | a -1 in the ORIG_D0 field
+					| signifies that the stack frame
+					| is NOT for syscall
+	movel	%sp,%sp@- 		| stack frame pointer argument
+	bsrl	SYMBOL_NAME(trap_c)
+	addql	#4,%sp
+	bral	SYMBOL_NAME(ret_from_exception)
+	
+|
+|	Signalling NAN exception
+|
+	|xref	fpsp_snan
+	.global	real_snan
+	.global	snan
+snan:
+	jmp	fpsp_snan
+real_snan:
+	link		%a6,#-LOCAL_SIZE
+	fsave		-(%sp)
+	bclrb		#E1,E_BYTE(%a6)	|snan is always an E1 exception
+	frestore	(%sp)+
+	unlk		%a6
+
+	addl		#1,sigsnan		|for standalone testing
+
+	SAVE_ALL
+	moveq	#-1,%d0
+	movel	%d0,%sp@(LOFF_ORIG_D0)    | a -1 in the ORIG_D0 field
+					| signifies that the stack frame
+					| is NOT for syscall
+	movel	%sp,%sp@- 		| stack frame pointer argument
+	bsrl	SYMBOL_NAME(trap_c)
+	addql	#4,%sp
+	bral	SYMBOL_NAME(ret_from_exception)
+	
+|
+|	Operand Error exception
+|
+	|xref	fpsp_operr
+	.global	real_operr
+	.global	operr
+operr:
+	jmp	fpsp_operr
+real_operr:
+	link		%a6,#-LOCAL_SIZE
+	fsave		-(%sp)
+	bclrb		#E1,E_BYTE(%a6)	|operr is always an E1 exception
+	frestore	(%sp)+
+	unlk		%a6
+
+	addl		#1,sigoperr		|for standalone testing
+
+
+	SAVE_ALL
+	moveq	#-1,%d0
+	movel	%d0,%sp@(LOFF_ORIG_D0)    | a -1 in the ORIG_D0 field
+					| signifies that the stack frame
+					| is NOT for syscall
+	movel	%sp,%sp@- 		| stack frame pointer argument
+	bsrl	SYMBOL_NAME(trap_c)
+	addql	#4,%sp
+	bral	SYMBOL_NAME(ret_from_exception)
+
+	
+|
+|	BSUN exception
+|
+|	This sample handler simply clears the nan bit in the FPSR.
+|
+	|xref	fpsp_bsun
+	.global	real_bsun
+	.global	bsun
+bsun:
+	jmp	fpsp_bsun
+real_bsun:
+	link		%a6,#-LOCAL_SIZE
+	fsave		-(%sp)
+	bclrb		#E1,E_BYTE(%a6)	|bsun is always an E1 exception
+	fmovel		%FPSR,-(%sp)
+	bclrb		#nan_bit,(%sp)
+	fmovel		(%sp)+,%FPSR
+	frestore	(%sp)+
+	unlk		%a6
+
+	addl		#1,sigbsun		|for standalone testing
+
+
+
+	SAVE_ALL
+	moveq	#-1,%d0
+	movel	%d0,%sp@(LOFF_ORIG_D0)    | a -1 in the ORIG_D0 field
+					| signifies that the stack frame
+					| is NOT for syscall
+	movel	%sp,%sp@- 		| stack frame pointer argument
+	bsrl	SYMBOL_NAME(trap_c)
+	addql	#4,%sp
+	bral	SYMBOL_NAME(ret_from_exception)
+
+|
+|	F-line exception
+|
+|	A 'real' F-line exception is one that the FPSP isn't supposed to 
+|	handle. E.g. an instruction with a co-processor ID that is not 1.
+|
+|
+	|xref	fpsp_fline
+	.global	real_fline
+	.global	fline
+fline:
+	jmp	fpsp_fline
+real_fline:
+
+	addl		#1,sigunimp		|for standalone testing
+
+
+	SAVE_ALL
+	moveq	#-1,%d0
+	movel	%d0,%sp@(LOFF_ORIG_D0)    | a -1 in the ORIG_D0 field
+					| signifies that the stack frame
+					| is NOT for syscall
+	movel	%sp,%sp@- 		| stack frame pointer argument
+	bsrl	SYMBOL_NAME(trap_c)
+	addql	#4,%sp
+	bral	SYMBOL_NAME(ret_from_exception)
+
+|
+|	Unsupported data type exception
+|
+	|xref	fpsp_unsupp
+	.global	real_unsupp
+	.global	unsupp
+unsupp:
+	jmp	fpsp_unsupp
+real_unsupp:
+	link		%a6,#-LOCAL_SIZE
+	fsave		-(%sp)
+	bclrb		#E1,E_BYTE(%a6)	|unsupp is always an E1 exception
+	frestore	(%sp)+
+	unlk		%a6
+
+	addl		#1,sigunsupp		|for standalone testing
+
+
+	SAVE_ALL
+	moveq	#-1,%d0
+	movel	%d0,%sp@(LOFF_ORIG_D0)    | a -1 in the ORIG_D0 field
+					| signifies that the stack frame
+					| is NOT for syscall
+	movel	%sp,%sp@- 		| stack frame pointer argument
+	bsrl	SYMBOL_NAME(trap_c)
+	addql	#4,%sp
+	bral	SYMBOL_NAME(ret_from_exception)
+
+|
+|	Trace exception
+|
+	.global	real_trace
+real_trace:
+	|
+	bral	SYMBOL_NAME(trap)
+
+|
+|	fpsp_fmt_error --- exit point for frame format error
+|
+|	The fpu stack frame does not match the frames existing
+|	or planned at the time of this writing.  The fpsp is
+|	unable to handle frame sizes not in the following
+|	version:size pairs:
+|
+|	{4060, 4160} - busy frame
+|	{4028, 4130} - unimp frame
+|	{4000, 4100} - idle frame
+|
+|	This entry point simply holds an f-line illegal value.  
+|	Replace this with a call to your kernel panic code or
+|	code to handle future revisions of the fpu.
+|
+	.global	fpsp_fmt_error
+fpsp_fmt_error:
+
+	.long	0xf27f0000	|f-line illegal 
+
+|
+|	fpsp_done --- FPSP exit point
+|
+|	The exception has been handled by the package and we are ready
+|	to return to user mode, but there may be OS specific code
+|	to execute before we do.  If there is, do it now.
+|
+|
+
+	.global	fpsp_done
+fpsp_done:
+	btst	#0x5,%sp@		| supervisor bit set in saved SR?
+	beq	Lnotkern
+	rte
+Lnotkern:
+	tstl	SYMBOL_NAME(need_resched)
+	bne	Lmustsched
+	rte
+Lmustsched:
+	SAVE_ALL
+	moveq	#-1,%d0
+	movel	%d0,%sp@(LOFF_ORIG_D0)    | indicate stack frame not for syscall
+	bral	SYMBOL_NAME(ret_from_exception)	| deliver signals, reschedule etc..
+	
+
+|
+|	mem_write --- write to user or supervisor address space
+|
+| Writes to memory while in supervisor mode.  copyout accomplishes
+| this via a 'moves' instruction.  copyout is a UNIX SVR3 (and later) function.
+| If you don't have copyout, use the local copy of the function below.
+|
+|	a0 - supervisor source address
+|	a1 - user destination address
+|	d0 - number of bytes to write (maximum count is 12)
+|
+| The supervisor source address is guaranteed to point into the supervisor
+| stack.  The result is that a UNIX
+| process is allowed to sleep as a consequence of a page fault during
+| copyout.  The probability of a page fault is exceedingly small because
+| the 68040 always reads the destination address and thus the page
+| faults should have already been handled.
+|
+| If the EXC_SR shows that the exception was from supervisor space,
+| then just do a dumb (and slow) memory move.  In a UNIX environment
+| there shouldn't be any supervisor mode floating point exceptions.
+|
+	.global	mem_write
+mem_write:
+	btstb	#5,EXC_SR(%a6)	|check for supervisor state
+	beqs	user_write
+super_write:
+	moveb	(%a0)+,(%a1)+
+	subql	#1,%d0
+	bnes	super_write
+	rts
+user_write:
+	movel	%d1,-(%sp)	|preserve d1 just in case
+	movel	%d0,-(%sp)
+	movel	%a1,-(%sp)
+	movel	%a0,-(%sp)
+	jsr		copyout
+	addw	#12,%sp
+	movel	(%sp)+,%d1
+	rts
+|
+|	mem_read --- read from user or supervisor address space
+|
+| Reads from memory while in supervisor mode.  copyin accomplishes
+| this via a 'moves' instruction.  copyin is a UNIX SVR3 (and later) function.
+| If you don't have copyin, use the local copy of the function below.
+|
+| The FPSP calls mem_read to read the original F-line instruction in order
+| to extract the data register number when the 'Dn' addressing mode is
+| used.
+|
+|Input:
+|	a0 - user source address
+|	a1 - supervisor destination address
+|	d0 - number of bytes to read (maximum count is 12)
+|
+| Like mem_write, mem_read always reads with a supervisor 
+| destination address on the supervisor stack.  Also like mem_write,
+| the EXC_SR is checked and a simple memory copy is done if reading
+| from supervisor space is indicated.
+|
+	.global	mem_read
+mem_read:
+	btstb	#5,EXC_SR(%a6)	|check for supervisor state
+	beqs	user_read
+super_read:
+	moveb	(%a0)+,(%a1)+
+	subql	#1,%d0
+	bnes	super_read
+	rts
+user_read:
+	movel	%d1,-(%sp)	|preserve d1 just in case
+	movel	%d0,-(%sp)
+	movel	%a1,-(%sp)
+	movel	%a0,-(%sp)
+	jsr		copyin
+	addw	#12,%sp
+	movel	(%sp)+,%d1
+	rts
+
+|
+| Use these routines if your kernel doesn't have copyout/copyin equivalents.
+| Assumes that D0/D1/A0/A1 are scratch registers. copyout overwrites DFC,
+| and copyin overwrites SFC.
+|
+copyout:
+	movel	4(%sp),%a0	| source
+	movel	8(%sp),%a1	| destination
+	movel	12(%sp),%d0	| count
+	subl	#1,%d0		| dec count by 1 for dbra
+	movel	#1,%d1
+	movec	%d1,%DFC		| set dfc for user data space
+moreout:
+	moveb	(%a0)+,%d1	| fetch supervisor byte
+	movesb	%d1,(%a1)+	| write user byte
+	dbf	%d0,moreout
+	rts
+
+copyin:
+	movel	4(%sp),%a0	| source
+	movel	8(%sp),%a1	| destination
+	movel	12(%sp),%d0	| count
+	subl	#1,%d0		| dec count by 1 for dbra
+	movel	#1,%d1
+	movec	%d1,%SFC		| set sfc for user space
+morein:
+	movesb	(%a0)+,%d1	| fetch user byte
+	moveb	%d1,(%a1)+	| write supervisor byte
+	dbf	%d0,morein
+	rts
+
+	|end
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/fpsp040/slog2.S linux/arch/m68k/fpsp040/slog2.S
--- v1.3.93/linux/arch/m68k/fpsp040/slog2.S	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/fpsp040/slog2.S	Sat Feb 24 22:58:44 1996
@@ -0,0 +1,188 @@
+|
+|	slog2.sa 3.1 12/10/90
+|
+|       The entry point slog10 computes the base-10 
+|	logarithm of an input argument X.
+|	slog10d does the same except the input value is a 
+|	denormalized number.  
+|	sLog2 and sLog2d are the base-2 analogues.
+|
+|       INPUT:	Double-extended value in memory location pointed to 
+|		by address register a0.
+|
+|       OUTPUT: log_10(X) or log_2(X) returned in floating-point 
+|		register fp0.
+|
+|       ACCURACY and MONOTONICITY: The returned result is within 1.7 
+|		ulps in 64 significant bit, i.e. within 0.5003 ulp 
+|		to 53 bits if the result is subsequently rounded 
+|		to double precision. The result is provably monotonic 
+|		in double precision.
+|
+|       SPEED:	Two timings are measured, both in the copy-back mode. 
+|		The first one is measured when the function is invoked 
+|		the first time (so the instructions and data are not 
+|		in cache), and the second one is measured when the 
+|		function is reinvoked at the same input argument.
+|
+|       ALGORITHM and IMPLEMENTATION NOTES:
+|
+|       slog10d:
+|
+|       Step 0.   If X < 0, create a NaN and raise the invalid operation
+|                 flag. Otherwise, save FPCR in D1; set FpCR to default.
+|       Notes:    Default means round-to-nearest mode, no floating-point
+|                 traps, and precision control = double extended.
+|
+|       Step 1.   Call slognd to obtain Y = log(X), the natural log of X.
+|       Notes:    Even if X is denormalized, log(X) is always normalized.
+|
+|       Step 2.   Compute log_10(X) = log(X) * (1/log(10)).
+|            2.1  Restore the user FPCR
+|            2.2  Return ans := Y * INV_L10.
+|
+|
+|       slog10: 
+|
+|       Step 0.   If X < 0, create a NaN and raise the invalid operation
+|                 flag. Otherwise, save FPCR in D1; set FpCR to default.
+|       Notes:    Default means round-to-nearest mode, no floating-point
+|                 traps, and precision control = double extended.
+|
+|       Step 1.   Call sLogN to obtain Y = log(X), the natural log of X.
+|
+|       Step 2.   Compute log_10(X) = log(X) * (1/log(10)).
+|            2.1  Restore the user FPCR
+|            2.2  Return ans := Y * INV_L10.
+|
+|
+|       sLog2d:
+|
+|       Step 0.   If X < 0, create a NaN and raise the invalid operation
+|                 flag. Otherwise, save FPCR in D1; set FpCR to default.
+|       Notes:    Default means round-to-nearest mode, no floating-point
+|                 traps, and precision control = double extended.
+|
+|       Step 1.   Call slognd to obtain Y = log(X), the natural log of X.
+|       Notes:    Even if X is denormalized, log(X) is always normalized.
+|
+|       Step 2.   Compute log_10(X) = log(X) * (1/log(2)).
+|            2.1  Restore the user FPCR
+|            2.2  Return ans := Y * INV_L2.
+|
+|
+|       sLog2:
+|
+|       Step 0.   If X < 0, create a NaN and raise the invalid operation
+|                 flag. Otherwise, save FPCR in D1; set FpCR to default.
+|       Notes:    Default means round-to-nearest mode, no floating-point
+|                 traps, and precision control = double extended.
+|
+|       Step 1.   If X is not an integer power of two, i.e., X != 2^k,
+|                 go to Step 3.
+|
+|       Step 2.   Return k.
+|            2.1  Get integer k, X = 2^k.
+|            2.2  Restore the user FPCR.
+|            2.3  Return ans := convert-to-double-extended(k).
+|
+|       Step 3.   Call sLogN to obtain Y = log(X), the natural log of X.
+|
+|       Step 4.   Compute log_2(X) = log(X) * (1/log(2)).
+|            4.1  Restore the user FPCR
+|            4.2  Return ans := Y * INV_L2.
+|
+
+|		Copyright (C) Motorola, Inc. 1990
+|			All Rights Reserved
+|
+|	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA 
+|	The copyright notice above does not evidence any  
+|	actual or intended publication of such source code.
+
+|SLOG2    idnt    2,1 | Motorola 040 Floating Point Software Package
+
+	|section	8
+
+	|xref	t_frcinx	
+	|xref	t_operr
+	|xref	slogn
+	|xref	slognd
+
+INV_L10:  .long 0x3FFD0000,0xDE5BD8A9,0x37287195,0x00000000
+
+INV_L2:   .long 0x3FFF0000,0xB8AA3B29,0x5C17F0BC,0x00000000
+
+	.global	slog10d
+slog10d:
+|--entry point for Log10(X), X is denormalized
+	movel		(%a0),%d0
+	blt		invalid
+	movel		%d1,-(%sp)
+	clrl		%d1
+	bsr		slognd			| ...log(X), X denorm.
+	fmovel		(%sp)+,%fpcr
+	fmulx		INV_L10,%fp0
+	bra		t_frcinx
+
+	.global	slog10
+slog10:
+|--entry point for Log10(X), X is normalized
+
+	movel		(%a0),%d0
+	blt		invalid
+	movel		%d1,-(%sp)
+	clrl		%d1
+	bsr		slogn			| ...log(X), X normal.
+	fmovel		(%sp)+,%fpcr
+	fmulx		INV_L10,%fp0
+	bra		t_frcinx
+
+
+	.global	slog2d
+slog2d:
+|--entry point for Log2(X), X is denormalized
+
+	movel		(%a0),%d0
+	blt		invalid
+	movel		%d1,-(%sp)
+	clrl		%d1
+	bsr		slognd			| ...log(X), X denorm.
+	fmovel		(%sp)+,%fpcr
+	fmulx		INV_L2,%fp0
+	bra		t_frcinx
+
+	.global	slog2
+slog2:
+|--entry point for Log2(X), X is normalized
+	movel		(%a0),%d0
+	blt		invalid
+
+	movel		8(%a0),%d0
+	bnes		continue		| ...X is not 2^k
+
+	movel		4(%a0),%d0
+	andl		#0x7FFFFFFF,%d0
+	tstl		%d0
+	bnes		continue
+
+|--X = 2^k.
+	movew		(%a0),%d0
+	andl		#0x00007FFF,%d0
+	subl		#0x3FFF,%d0
+	fmovel		%d1,%fpcr
+	fmovel		%d0,%fp0
+	bra		t_frcinx
+
+continue:
+	movel		%d1,-(%sp)
+	clrl		%d1
+	bsr		slogn			| ...log(X), X normal.
+	fmovel		(%sp)+,%fpcr
+	fmulx		INV_L2,%fp0
+	bra		t_frcinx
+
+invalid:
+	bra		t_operr
+
+	|end
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/fpsp040/slogn.S linux/arch/m68k/fpsp040/slogn.S
--- v1.3.93/linux/arch/m68k/fpsp040/slogn.S	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/fpsp040/slogn.S	Sat Feb 24 22:58:44 1996
@@ -0,0 +1,592 @@
+|
+|	slogn.sa 3.1 12/10/90
+|
+|	slogn computes the natural logarithm of an
+|	input value. slognd does the same except the input value is a
+|	denormalized number. slognp1 computes log(1+X), and slognp1d
+|	computes log(1+X) for denormalized X.
+|
+|	Input: Double-extended value in memory location pointed to by address
+|		register a0.
+|
+|	Output:	log(X) or log(1+X) returned in floating-point register Fp0.
+|
+|	Accuracy and Monotonicity: The returned result is within 2 ulps in
+|		64 significant bit, i.e. within 0.5001 ulp to 53 bits if the
+|		result is subsequently rounded to double precision. The 
+|		result is provably monotonic in double precision.
+|
+|	Speed: The program slogn takes approximately 190 cycles for input 
+|		argument X such that |X-1| >= 1/16, which is the the usual 
+|		situation. For those arguments, slognp1 takes approximately
+|		 210 cycles. For the less common arguments, the program will
+|		 run no worse than 10% slower.
+|
+|	Algorithm:
+|	LOGN:
+|	Step 1. If |X-1| < 1/16, approximate log(X) by an odd polynomial in
+|		u, where u = 2(X-1)/(X+1). Otherwise, move on to Step 2.
+|
+|	Step 2. X = 2**k * Y where 1 <= Y < 2. Define F to be the first seven
+|		significant bits of Y plus 2**(-7), i.e. F = 1.xxxxxx1 in base
+|		2 where the six "x" match those of Y. Note that |Y-F| <= 2**(-7).
+|
+|	Step 3. Define u = (Y-F)/F. Approximate log(1+u) by a polynomial in u,
+|		log(1+u) = poly.
+|
+|	Step 4. Reconstruct log(X) = log( 2**k * Y ) = k*log(2) + log(F) + log(1+u)
+|		by k*log(2) + (log(F) + poly). The values of log(F) are calculated
+|		beforehand and stored in the program.
+|
+|	lognp1:
+|	Step 1: If |X| < 1/16, approximate log(1+X) by an odd polynomial in
+|		u where u = 2X/(2+X). Otherwise, move on to Step 2.
+|
+|	Step 2: Let 1+X = 2**k * Y, where 1 <= Y < 2. Define F as done in Step 2
+|		of the algorithm for LOGN and compute log(1+X) as
+|		k*log(2) + log(F) + poly where poly approximates log(1+u),
+|		u = (Y-F)/F. 
+|
+|	Implementation Notes:
+|	Note 1. There are 64 different possible values for F, thus 64 log(F)'s
+|		need to be tabulated. Moreover, the values of 1/F are also 
+|		tabulated so that the division in (Y-F)/F can be performed by a
+|		multiplication.
+|
+|	Note 2. In Step 2 of lognp1, in order to preserved accuracy, the value
+|		Y-F has to be calculated carefully when 1/2 <= X < 3/2. 
+|
+|	Note 3. To fully exploit the pipeline, polynomials are usually separated
+|		into two parts evaluated independently before being added up.
+|	
+
+|		Copyright (C) Motorola, Inc. 1990
+|			All Rights Reserved
+|
+|	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA 
+|	The copyright notice above does not evidence any  
+|	actual or intended publication of such source code.
+
+|slogn	idnt	2,1 | Motorola 040 Floating Point Software Package
+
+	|section	8
+
+	.include "fpsp.h"
+
+BOUNDS1:  .long 0x3FFEF07D,0x3FFF8841
+BOUNDS2:  .long 0x3FFE8000,0x3FFFC000
+
+LOGOF2:	.long 0x3FFE0000,0xB17217F7,0xD1CF79AC,0x00000000
+
+one:	.long 0x3F800000
+zero:	.long 0x00000000
+infty:	.long 0x7F800000
+negone:	.long 0xBF800000
+
+LOGA6:	.long 0x3FC2499A,0xB5E4040B
+LOGA5:	.long 0xBFC555B5,0x848CB7DB
+
+LOGA4:	.long 0x3FC99999,0x987D8730
+LOGA3:	.long 0xBFCFFFFF,0xFF6F7E97
+
+LOGA2:	.long 0x3FD55555,0x555555a4
+LOGA1:	.long 0xBFE00000,0x00000008
+
+LOGB5:	.long 0x3F175496,0xADD7DAD6
+LOGB4:	.long 0x3F3C71C2,0xFE80C7E0
+
+LOGB3:	.long 0x3F624924,0x928BCCFF
+LOGB2:	.long 0x3F899999,0x999995EC
+
+LOGB1:	.long 0x3FB55555,0x55555555
+TWO:	.long 0x40000000,0x00000000
+
+LTHOLD:	.long 0x3f990000,0x80000000,0x00000000,0x00000000
+
+LOGTBL:
+	.long  0x3FFE0000,0xFE03F80F,0xE03F80FE,0x00000000
+	.long  0x3FF70000,0xFF015358,0x833C47E2,0x00000000
+	.long  0x3FFE0000,0xFA232CF2,0x52138AC0,0x00000000
+	.long  0x3FF90000,0xBDC8D83E,0xAD88D549,0x00000000
+	.long  0x3FFE0000,0xF6603D98,0x0F6603DA,0x00000000
+	.long  0x3FFA0000,0x9CF43DCF,0xF5EAFD48,0x00000000
+	.long  0x3FFE0000,0xF2B9D648,0x0F2B9D65,0x00000000
+	.long  0x3FFA0000,0xDA16EB88,0xCB8DF614,0x00000000
+	.long  0x3FFE0000,0xEF2EB71F,0xC4345238,0x00000000
+	.long  0x3FFB0000,0x8B29B775,0x1BD70743,0x00000000
+	.long  0x3FFE0000,0xEBBDB2A5,0xC1619C8C,0x00000000
+	.long  0x3FFB0000,0xA8D839F8,0x30C1FB49,0x00000000
+	.long  0x3FFE0000,0xE865AC7B,0x7603A197,0x00000000
+	.long  0x3FFB0000,0xC61A2EB1,0x8CD907AD,0x00000000
+	.long  0x3FFE0000,0xE525982A,0xF70C880E,0x00000000
+	.long  0x3FFB0000,0xE2F2A47A,0xDE3A18AF,0x00000000
+	.long  0x3FFE0000,0xE1FC780E,0x1FC780E2,0x00000000
+	.long  0x3FFB0000,0xFF64898E,0xDF55D551,0x00000000
+	.long  0x3FFE0000,0xDEE95C4C,0xA037BA57,0x00000000
+	.long  0x3FFC0000,0x8DB956A9,0x7B3D0148,0x00000000
+	.long  0x3FFE0000,0xDBEB61EE,0xD19C5958,0x00000000
+	.long  0x3FFC0000,0x9B8FE100,0xF47BA1DE,0x00000000
+	.long  0x3FFE0000,0xD901B203,0x6406C80E,0x00000000
+	.long  0x3FFC0000,0xA9372F1D,0x0DA1BD17,0x00000000
+	.long  0x3FFE0000,0xD62B80D6,0x2B80D62C,0x00000000
+	.long  0x3FFC0000,0xB6B07F38,0xCE90E46B,0x00000000
+	.long  0x3FFE0000,0xD3680D36,0x80D3680D,0x00000000
+	.long  0x3FFC0000,0xC3FD0329,0x06488481,0x00000000
+	.long  0x3FFE0000,0xD0B69FCB,0xD2580D0B,0x00000000
+	.long  0x3FFC0000,0xD11DE0FF,0x15AB18CA,0x00000000
+	.long  0x3FFE0000,0xCE168A77,0x25080CE1,0x00000000
+	.long  0x3FFC0000,0xDE1433A1,0x6C66B150,0x00000000
+	.long  0x3FFE0000,0xCB8727C0,0x65C393E0,0x00000000
+	.long  0x3FFC0000,0xEAE10B5A,0x7DDC8ADD,0x00000000
+	.long  0x3FFE0000,0xC907DA4E,0x871146AD,0x00000000
+	.long  0x3FFC0000,0xF7856E5E,0xE2C9B291,0x00000000
+	.long  0x3FFE0000,0xC6980C69,0x80C6980C,0x00000000
+	.long  0x3FFD0000,0x82012CA5,0xA68206D7,0x00000000
+	.long  0x3FFE0000,0xC4372F85,0x5D824CA6,0x00000000
+	.long  0x3FFD0000,0x882C5FCD,0x7256A8C5,0x00000000
+	.long  0x3FFE0000,0xC1E4BBD5,0x95F6E947,0x00000000
+	.long  0x3FFD0000,0x8E44C60B,0x4CCFD7DE,0x00000000
+	.long  0x3FFE0000,0xBFA02FE8,0x0BFA02FF,0x00000000
+	.long  0x3FFD0000,0x944AD09E,0xF4351AF6,0x00000000
+	.long  0x3FFE0000,0xBD691047,0x07661AA3,0x00000000
+	.long  0x3FFD0000,0x9A3EECD4,0xC3EAA6B2,0x00000000
+	.long  0x3FFE0000,0xBB3EE721,0xA54D880C,0x00000000
+	.long  0x3FFD0000,0xA0218434,0x353F1DE8,0x00000000
+	.long  0x3FFE0000,0xB92143FA,0x36F5E02E,0x00000000
+	.long  0x3FFD0000,0xA5F2FCAB,0xBBC506DA,0x00000000
+	.long  0x3FFE0000,0xB70FBB5A,0x19BE3659,0x00000000
+	.long  0x3FFD0000,0xABB3B8BA,0x2AD362A5,0x00000000
+	.long  0x3FFE0000,0xB509E68A,0x9B94821F,0x00000000
+	.long  0x3FFD0000,0xB1641795,0xCE3CA97B,0x00000000
+	.long  0x3FFE0000,0xB30F6352,0x8917C80B,0x00000000
+	.long  0x3FFD0000,0xB7047551,0x5D0F1C61,0x00000000
+	.long  0x3FFE0000,0xB11FD3B8,0x0B11FD3C,0x00000000
+	.long  0x3FFD0000,0xBC952AFE,0xEA3D13E1,0x00000000
+	.long  0x3FFE0000,0xAF3ADDC6,0x80AF3ADE,0x00000000
+	.long  0x3FFD0000,0xC2168ED0,0xF458BA4A,0x00000000
+	.long  0x3FFE0000,0xAD602B58,0x0AD602B6,0x00000000
+	.long  0x3FFD0000,0xC788F439,0xB3163BF1,0x00000000
+	.long  0x3FFE0000,0xAB8F69E2,0x8359CD11,0x00000000
+	.long  0x3FFD0000,0xCCECAC08,0xBF04565D,0x00000000
+	.long  0x3FFE0000,0xA9C84A47,0xA07F5638,0x00000000
+	.long  0x3FFD0000,0xD2420487,0x2DD85160,0x00000000
+	.long  0x3FFE0000,0xA80A80A8,0x0A80A80B,0x00000000
+	.long  0x3FFD0000,0xD7894992,0x3BC3588A,0x00000000
+	.long  0x3FFE0000,0xA655C439,0x2D7B73A8,0x00000000
+	.long  0x3FFD0000,0xDCC2C4B4,0x9887DACC,0x00000000
+	.long  0x3FFE0000,0xA4A9CF1D,0x96833751,0x00000000
+	.long  0x3FFD0000,0xE1EEBD3E,0x6D6A6B9E,0x00000000
+	.long  0x3FFE0000,0xA3065E3F,0xAE7CD0E0,0x00000000
+	.long  0x3FFD0000,0xE70D785C,0x2F9F5BDC,0x00000000
+	.long  0x3FFE0000,0xA16B312E,0xA8FC377D,0x00000000
+	.long  0x3FFD0000,0xEC1F392C,0x5179F283,0x00000000
+	.long  0x3FFE0000,0x9FD809FD,0x809FD80A,0x00000000
+	.long  0x3FFD0000,0xF12440D3,0xE36130E6,0x00000000
+	.long  0x3FFE0000,0x9E4CAD23,0xDD5F3A20,0x00000000
+	.long  0x3FFD0000,0xF61CCE92,0x346600BB,0x00000000
+	.long  0x3FFE0000,0x9CC8E160,0xC3FB19B9,0x00000000
+	.long  0x3FFD0000,0xFB091FD3,0x8145630A,0x00000000
+	.long  0x3FFE0000,0x9B4C6F9E,0xF03A3CAA,0x00000000
+	.long  0x3FFD0000,0xFFE97042,0xBFA4C2AD,0x00000000
+	.long  0x3FFE0000,0x99D722DA,0xBDE58F06,0x00000000
+	.long  0x3FFE0000,0x825EFCED,0x49369330,0x00000000
+	.long  0x3FFE0000,0x9868C809,0x868C8098,0x00000000
+	.long  0x3FFE0000,0x84C37A7A,0xB9A905C9,0x00000000
+	.long  0x3FFE0000,0x97012E02,0x5C04B809,0x00000000
+	.long  0x3FFE0000,0x87224C2E,0x8E645FB7,0x00000000
+	.long  0x3FFE0000,0x95A02568,0x095A0257,0x00000000
+	.long  0x3FFE0000,0x897B8CAC,0x9F7DE298,0x00000000
+	.long  0x3FFE0000,0x94458094,0x45809446,0x00000000
+	.long  0x3FFE0000,0x8BCF55DE,0xC4CD05FE,0x00000000
+	.long  0x3FFE0000,0x92F11384,0x0497889C,0x00000000
+	.long  0x3FFE0000,0x8E1DC0FB,0x89E125E5,0x00000000
+	.long  0x3FFE0000,0x91A2B3C4,0xD5E6F809,0x00000000
+	.long  0x3FFE0000,0x9066E68C,0x955B6C9B,0x00000000
+	.long  0x3FFE0000,0x905A3863,0x3E06C43B,0x00000000
+	.long  0x3FFE0000,0x92AADE74,0xC7BE59E0,0x00000000
+	.long  0x3FFE0000,0x8F1779D9,0xFDC3A219,0x00000000
+	.long  0x3FFE0000,0x94E9BFF6,0x15845643,0x00000000
+	.long  0x3FFE0000,0x8DDA5202,0x37694809,0x00000000
+	.long  0x3FFE0000,0x9723A1B7,0x20134203,0x00000000
+	.long  0x3FFE0000,0x8CA29C04,0x6514E023,0x00000000
+	.long  0x3FFE0000,0x995899C8,0x90EB8990,0x00000000
+	.long  0x3FFE0000,0x8B70344A,0x139BC75A,0x00000000
+	.long  0x3FFE0000,0x9B88BDAA,0x3A3DAE2F,0x00000000
+	.long  0x3FFE0000,0x8A42F870,0x5669DB46,0x00000000
+	.long  0x3FFE0000,0x9DB4224F,0xFFE1157C,0x00000000
+	.long  0x3FFE0000,0x891AC73A,0xE9819B50,0x00000000
+	.long  0x3FFE0000,0x9FDADC26,0x8B7A12DA,0x00000000
+	.long  0x3FFE0000,0x87F78087,0xF78087F8,0x00000000
+	.long  0x3FFE0000,0xA1FCFF17,0xCE733BD4,0x00000000
+	.long  0x3FFE0000,0x86D90544,0x7A34ACC6,0x00000000
+	.long  0x3FFE0000,0xA41A9E8F,0x5446FB9F,0x00000000
+	.long  0x3FFE0000,0x85BF3761,0x2CEE3C9B,0x00000000
+	.long  0x3FFE0000,0xA633CD7E,0x6771CD8B,0x00000000
+	.long  0x3FFE0000,0x84A9F9C8,0x084A9F9D,0x00000000
+	.long  0x3FFE0000,0xA8489E60,0x0B435A5E,0x00000000
+	.long  0x3FFE0000,0x83993052,0x3FBE3368,0x00000000
+	.long  0x3FFE0000,0xAA59233C,0xCCA4BD49,0x00000000
+	.long  0x3FFE0000,0x828CBFBE,0xB9A020A3,0x00000000
+	.long  0x3FFE0000,0xAC656DAE,0x6BCC4985,0x00000000
+	.long  0x3FFE0000,0x81848DA8,0xFAF0D277,0x00000000
+	.long  0x3FFE0000,0xAE6D8EE3,0x60BB2468,0x00000000
+	.long  0x3FFE0000,0x80808080,0x80808081,0x00000000
+	.long  0x3FFE0000,0xB07197A2,0x3C46C654,0x00000000
+
+	.set	ADJK,L_SCR1
+
+	.set	X,FP_SCR1
+	.set	XDCARE,X+2
+	.set	XFRAC,X+4
+
+	.set	F,FP_SCR2
+	.set	FFRAC,F+4
+
+	.set	KLOG2,FP_SCR3
+
+	.set	SAVEU,FP_SCR4
+
+	| xref	t_frcinx
+	|xref	t_extdnrm
+	|xref	t_operr
+	|xref	t_dz
+
+	.global	slognd
+slognd:
+|--ENTRY POINT FOR LOG(X) FOR DENORMALIZED INPUT
+
+	movel		#-100,ADJK(%a6)	| ...INPUT = 2^(ADJK) * FP0
+
+|----normalize the input value by left shifting k bits (k to be determined
+|----below), adjusting exponent and storing -k to  ADJK
+|----the value TWOTO100 is no longer needed.
+|----Note that this code assumes the denormalized input is NON-ZERO.
+
+     moveml	%d2-%d7,-(%a7)		| ...save some registers 
+     movel	#0x00000000,%d3		| ...D3 is exponent of smallest norm. #
+     movel	4(%a0),%d4
+     movel	8(%a0),%d5		| ...(D4,D5) is (Hi_X,Lo_X)
+     clrl	%d2			| ...D2 used for holding K
+
+     tstl	%d4
+     bnes	HiX_not0
+
+HiX_0:
+     movel	%d5,%d4
+     clrl	%d5
+     movel	#32,%d2
+     clrl	%d6
+     bfffo      %d4{#0:#32},%d6
+     lsll      %d6,%d4
+     addl	%d6,%d2			| ...(D3,D4,D5) is normalized
+
+     movel	%d3,X(%a6)
+     movel	%d4,XFRAC(%a6)
+     movel	%d5,XFRAC+4(%a6)
+     negl	%d2
+     movel	%d2,ADJK(%a6)
+     fmovex	X(%a6),%fp0
+     moveml	(%a7)+,%d2-%d7		| ...restore registers
+     lea	X(%a6),%a0
+     bras	LOGBGN			| ...begin regular log(X)
+
+
+HiX_not0:
+     clrl	%d6
+     bfffo	%d4{#0:#32},%d6		| ...find first 1
+     movel	%d6,%d2			| ...get k
+     lsll	%d6,%d4
+     movel	%d5,%d7			| ...a copy of D5
+     lsll	%d6,%d5
+     negl	%d6
+     addil	#32,%d6
+     lsrl	%d6,%d7
+     orl	%d7,%d4			| ...(D3,D4,D5) normalized
+
+     movel	%d3,X(%a6)
+     movel	%d4,XFRAC(%a6)
+     movel	%d5,XFRAC+4(%a6)
+     negl	%d2
+     movel	%d2,ADJK(%a6)
+     fmovex	X(%a6),%fp0
+     moveml	(%a7)+,%d2-%d7		| ...restore registers
+     lea	X(%a6),%a0
+     bras	LOGBGN			| ...begin regular log(X)
+
+
+	.global	slogn
+slogn:
+|--ENTRY POINT FOR LOG(X) FOR X FINITE, NON-ZERO, NOT NAN'S
+
+	fmovex		(%a0),%fp0	| ...LOAD INPUT
+	movel		#0x00000000,ADJK(%a6)
+
+LOGBGN:
+|--FPCR SAVED AND CLEARED, INPUT IS 2^(ADJK)*FP0, FP0 CONTAINS
+|--A FINITE, NON-ZERO, NORMALIZED NUMBER.
+
+	movel	(%a0),%d0
+	movew	4(%a0),%d0
+
+	movel	(%a0),X(%a6)
+	movel	4(%a0),X+4(%a6)
+	movel	8(%a0),X+8(%a6)
+
+	cmpil	#0,%d0		| ...CHECK IF X IS NEGATIVE
+	blt	LOGNEG		| ...LOG OF NEGATIVE ARGUMENT IS INVALID
+	cmp2l	BOUNDS1,%d0	| ...X IS POSITIVE, CHECK IF X IS NEAR 1
+	bcc	LOGNEAR1	| ...BOUNDS IS ROUGHLY [15/16, 17/16]
+
+LOGMAIN:
+|--THIS SHOULD BE THE USUAL CASE, X NOT VERY CLOSE TO 1
+
+|--X = 2^(K) * Y, 1 <= Y < 2. THUS, Y = 1.XXXXXXXX....XX IN BINARY.
+|--WE DEFINE F = 1.XXXXXX1, I.E. FIRST 7 BITS OF Y AND ATTACH A 1.
+|--THE IDEA IS THAT LOG(X) = K*LOG2 + LOG(Y)
+|--			 = K*LOG2 + LOG(F) + LOG(1 + (Y-F)/F).
+|--NOTE THAT U = (Y-F)/F IS VERY SMALL AND THUS APPROXIMATING
+|--LOG(1+U) CAN BE VERY EFFICIENT.
+|--ALSO NOTE THAT THE VALUE 1/F IS STORED IN A TABLE SO THAT NO
+|--DIVISION IS NEEDED TO CALCULATE (Y-F)/F. 
+
+|--GET K, Y, F, AND ADDRESS OF 1/F.
+	asrl	#8,%d0
+	asrl	#8,%d0		| ...SHIFTED 16 BITS, BIASED EXPO. OF X
+	subil	#0x3FFF,%d0 	| ...THIS IS K
+	addl	ADJK(%a6),%d0	| ...ADJUST K, ORIGINAL INPUT MAY BE  DENORM.
+	lea	LOGTBL,%a0 	| ...BASE ADDRESS OF 1/F AND LOG(F)
+	fmovel	%d0,%fp1		| ...CONVERT K TO FLOATING-POINT FORMAT
+
+|--WHILE THE CONVERSION IS GOING ON, WE GET F AND ADDRESS OF 1/F
+	movel	#0x3FFF0000,X(%a6)	| ...X IS NOW Y, I.E. 2^(-K)*X
+	movel	XFRAC(%a6),FFRAC(%a6)
+	andil	#0xFE000000,FFRAC(%a6) | ...FIRST 7 BITS OF Y
+	oril	#0x01000000,FFRAC(%a6) | ...GET F: ATTACH A 1 AT THE EIGHTH BIT
+	movel	FFRAC(%a6),%d0	| ...READY TO GET ADDRESS OF 1/F
+	andil	#0x7E000000,%d0	
+	asrl	#8,%d0
+	asrl	#8,%d0
+	asrl	#4,%d0		| ...SHIFTED 20, D0 IS THE DISPLACEMENT
+	addal	%d0,%a0		| ...A0 IS THE ADDRESS FOR 1/F
+
+	fmovex	X(%a6),%fp0
+	movel	#0x3fff0000,F(%a6)
+	clrl	F+8(%a6)
+	fsubx	F(%a6),%fp0		| ...Y-F
+	fmovemx %fp2-%fp2/%fp3,-(%sp)	| ...SAVE FP2 WHILE FP0 IS NOT READY
+|--SUMMARY: FP0 IS Y-F, A0 IS ADDRESS OF 1/F, FP1 IS K
+|--REGISTERS SAVED: FPCR, FP1, FP2
+
+LP1CONT1:
+|--AN RE-ENTRY POINT FOR LOGNP1
+	fmulx	(%a0),%fp0	| ...FP0 IS U = (Y-F)/F
+	fmulx	LOGOF2,%fp1	| ...GET K*LOG2 WHILE FP0 IS NOT READY
+	fmovex	%fp0,%fp2
+	fmulx	%fp2,%fp2		| ...FP2 IS V=U*U
+	fmovex	%fp1,KLOG2(%a6)	| ...PUT K*LOG2 IN MEMEORY, FREE FP1
+
+|--LOG(1+U) IS APPROXIMATED BY
+|--U + V*(A1+U*(A2+U*(A3+U*(A4+U*(A5+U*A6))))) WHICH IS
+|--[U + V*(A1+V*(A3+V*A5))]  +  [U*V*(A2+V*(A4+V*A6))]
+
+	fmovex	%fp2,%fp3
+	fmovex	%fp2,%fp1	
+
+	fmuld	LOGA6,%fp1	| ...V*A6
+	fmuld	LOGA5,%fp2	| ...V*A5
+
+	faddd	LOGA4,%fp1	| ...A4+V*A6
+	faddd	LOGA3,%fp2	| ...A3+V*A5
+
+	fmulx	%fp3,%fp1		| ...V*(A4+V*A6)
+	fmulx	%fp3,%fp2		| ...V*(A3+V*A5)
+
+	faddd	LOGA2,%fp1	| ...A2+V*(A4+V*A6)
+	faddd	LOGA1,%fp2	| ...A1+V*(A3+V*A5)
+
+	fmulx	%fp3,%fp1		| ...V*(A2+V*(A4+V*A6))
+	addal	#16,%a0		| ...ADDRESS OF LOG(F)
+	fmulx	%fp3,%fp2		| ...V*(A1+V*(A3+V*A5)), FP3 RELEASED
+
+	fmulx	%fp0,%fp1		| ...U*V*(A2+V*(A4+V*A6))
+	faddx	%fp2,%fp0		| ...U+V*(A1+V*(A3+V*A5)), FP2 RELEASED
+
+	faddx	(%a0),%fp1	| ...LOG(F)+U*V*(A2+V*(A4+V*A6))
+	fmovemx  (%sp)+,%fp2-%fp2/%fp3	| ...RESTORE FP2
+	faddx	%fp1,%fp0		| ...FP0 IS LOG(F) + LOG(1+U)
+
+	fmovel	%d1,%fpcr
+	faddx	KLOG2(%a6),%fp0	| ...FINAL ADD
+	bra	t_frcinx
+
+
+LOGNEAR1:
+|--REGISTERS SAVED: FPCR, FP1. FP0 CONTAINS THE INPUT.
+	fmovex	%fp0,%fp1
+	fsubs	one,%fp1		| ...FP1 IS X-1
+	fadds	one,%fp0		| ...FP0 IS X+1
+	faddx	%fp1,%fp1		| ...FP1 IS 2(X-1)
+|--LOG(X) = LOG(1+U/2)-LOG(1-U/2) WHICH IS AN ODD POLYNOMIAL
+|--IN U, U = 2(X-1)/(X+1) = FP1/FP0
+
+LP1CONT2:
+|--THIS IS AN RE-ENTRY POINT FOR LOGNP1
+	fdivx	%fp0,%fp1		| ...FP1 IS U
+	fmovemx %fp2-%fp2/%fp3,-(%sp)	 | ...SAVE FP2
+|--REGISTERS SAVED ARE NOW FPCR,FP1,FP2,FP3
+|--LET V=U*U, W=V*V, CALCULATE
+|--U + U*V*(B1 + V*(B2 + V*(B3 + V*(B4 + V*B5)))) BY
+|--U + U*V*(  [B1 + W*(B3 + W*B5)]  +  [V*(B2 + W*B4)]  )
+	fmovex	%fp1,%fp0
+	fmulx	%fp0,%fp0	| ...FP0 IS V
+	fmovex	%fp1,SAVEU(%a6) | ...STORE U IN MEMORY, FREE FP1
+	fmovex	%fp0,%fp1	
+	fmulx	%fp1,%fp1	| ...FP1 IS W
+
+	fmoved	LOGB5,%fp3
+	fmoved	LOGB4,%fp2
+
+	fmulx	%fp1,%fp3	| ...W*B5
+	fmulx	%fp1,%fp2	| ...W*B4
+
+	faddd	LOGB3,%fp3 | ...B3+W*B5
+	faddd	LOGB2,%fp2 | ...B2+W*B4
+
+	fmulx	%fp3,%fp1	| ...W*(B3+W*B5), FP3 RELEASED
+
+	fmulx	%fp0,%fp2	| ...V*(B2+W*B4)
+
+	faddd	LOGB1,%fp1 | ...B1+W*(B3+W*B5)
+	fmulx	SAVEU(%a6),%fp0 | ...FP0 IS U*V
+
+	faddx	%fp2,%fp1	| ...B1+W*(B3+W*B5) + V*(B2+W*B4), FP2 RELEASED
+	fmovemx (%sp)+,%fp2-%fp2/%fp3 | ...FP2 RESTORED
+
+	fmulx	%fp1,%fp0	| ...U*V*( [B1+W*(B3+W*B5)] + [V*(B2+W*B4)] )
+
+	fmovel	%d1,%fpcr
+	faddx	SAVEU(%a6),%fp0		
+	bra	t_frcinx
+	rts
+
+LOGNEG:
+|--REGISTERS SAVED FPCR. LOG(-VE) IS INVALID
+	bra	t_operr
+
+	.global	slognp1d
+slognp1d:
+|--ENTRY POINT FOR LOG(1+Z) FOR DENORMALIZED INPUT
+| Simply return the denorm
+
+	bra	t_extdnrm
+
+	.global	slognp1
+slognp1:
+|--ENTRY POINT FOR LOG(1+X) FOR X FINITE, NON-ZERO, NOT NAN'S
+
+	fmovex	(%a0),%fp0	| ...LOAD INPUT
+	fabsx	%fp0		|test magnitude
+	fcmpx	LTHOLD,%fp0	|compare with min threshold
+	fbgt	LP1REAL		|if greater, continue
+	fmovel	#0,%fpsr		|clr N flag from compare
+	fmovel	%d1,%fpcr
+	fmovex	(%a0),%fp0	|return signed argument
+	bra	t_frcinx
+
+LP1REAL:
+	fmovex	(%a0),%fp0	| ...LOAD INPUT
+	movel	#0x00000000,ADJK(%a6)
+	fmovex	%fp0,%fp1	| ...FP1 IS INPUT Z
+	fadds	one,%fp0	| ...X := ROUND(1+Z)
+	fmovex	%fp0,X(%a6)
+	movew	XFRAC(%a6),XDCARE(%a6)
+	movel	X(%a6),%d0
+	cmpil	#0,%d0
+	ble	LP1NEG0	| ...LOG OF ZERO OR -VE
+	cmp2l	BOUNDS2,%d0
+	bcs	LOGMAIN	| ...BOUNDS2 IS [1/2,3/2]
+|--IF 1+Z > 3/2 OR 1+Z < 1/2, THEN X, WHICH IS ROUNDING 1+Z,
+|--CONTAINS AT LEAST 63 BITS OF INFORMATION OF Z. IN THAT CASE,
+|--SIMPLY INVOKE LOG(X) FOR LOG(1+Z).
+
+LP1NEAR1:
+|--NEXT SEE IF EXP(-1/16) < X < EXP(1/16)
+	cmp2l	BOUNDS1,%d0
+	bcss	LP1CARE
+
+LP1ONE16:
+|--EXP(-1/16) < X < EXP(1/16). LOG(1+Z) = LOG(1+U/2) - LOG(1-U/2)
+|--WHERE U = 2Z/(2+Z) = 2Z/(1+X).
+	faddx	%fp1,%fp1	| ...FP1 IS 2Z
+	fadds	one,%fp0	| ...FP0 IS 1+X
+|--U = FP1/FP0
+	bra	LP1CONT2
+
+LP1CARE:
+|--HERE WE USE THE USUAL TABLE DRIVEN APPROACH. CARE HAS TO BE
+|--TAKEN BECAUSE 1+Z CAN HAVE 67 BITS OF INFORMATION AND WE MUST
+|--PRESERVE ALL THE INFORMATION. BECAUSE 1+Z IS IN [1/2,3/2],
+|--THERE ARE ONLY TWO CASES.
+|--CASE 1: 1+Z < 1, THEN K = -1 AND Y-F = (2-F) + 2Z
+|--CASE 2: 1+Z > 1, THEN K = 0  AND Y-F = (1-F) + Z
+|--ON RETURNING TO LP1CONT1, WE MUST HAVE K IN FP1, ADDRESS OF
+|--(1/F) IN A0, Y-F IN FP0, AND FP2 SAVED.
+
+	movel	XFRAC(%a6),FFRAC(%a6)
+	andil	#0xFE000000,FFRAC(%a6)
+	oril	#0x01000000,FFRAC(%a6)	| ...F OBTAINED
+	cmpil	#0x3FFF8000,%d0	| ...SEE IF 1+Z > 1
+	bges	KISZERO
+
+KISNEG1:
+	fmoves	TWO,%fp0
+	movel	#0x3fff0000,F(%a6)
+	clrl	F+8(%a6)
+	fsubx	F(%a6),%fp0	| ...2-F
+	movel	FFRAC(%a6),%d0
+	andil	#0x7E000000,%d0
+	asrl	#8,%d0
+	asrl	#8,%d0
+	asrl	#4,%d0		| ...D0 CONTAINS DISPLACEMENT FOR 1/F
+	faddx	%fp1,%fp1		| ...GET 2Z
+	fmovemx %fp2-%fp2/%fp3,-(%sp)	| ...SAVE FP2 
+	faddx	%fp1,%fp0		| ...FP0 IS Y-F = (2-F)+2Z
+	lea	LOGTBL,%a0	| ...A0 IS ADDRESS OF 1/F
+	addal	%d0,%a0
+	fmoves	negone,%fp1	| ...FP1 IS K = -1
+	bra	LP1CONT1
+
+KISZERO:
+	fmoves	one,%fp0
+	movel	#0x3fff0000,F(%a6)
+	clrl	F+8(%a6)
+	fsubx	F(%a6),%fp0		| ...1-F
+	movel	FFRAC(%a6),%d0
+	andil	#0x7E000000,%d0
+	asrl	#8,%d0
+	asrl	#8,%d0
+	asrl	#4,%d0
+	faddx	%fp1,%fp0		| ...FP0 IS Y-F
+	fmovemx %fp2-%fp2/%fp3,-(%sp)	| ...FP2 SAVED
+	lea	LOGTBL,%a0
+	addal	%d0,%a0	 	| ...A0 IS ADDRESS OF 1/F
+	fmoves	zero,%fp1	| ...FP1 IS K = 0
+	bra	LP1CONT1
+
+LP1NEG0:
+|--FPCR SAVED. D0 IS X IN COMPACT FORM.
+	cmpil	#0,%d0
+	blts	LP1NEG
+LP1ZERO:
+	fmoves	negone,%fp0
+
+	fmovel	%d1,%fpcr
+	bra t_dz
+
+LP1NEG:
+	fmoves	zero,%fp0
+
+	fmovel	%d1,%fpcr
+	bra	t_operr
+
+	|end
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/fpsp040/smovecr.S linux/arch/m68k/fpsp040/smovecr.S
--- v1.3.93/linux/arch/m68k/fpsp040/smovecr.S	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/fpsp040/smovecr.S	Sat Feb 24 22:58:44 1996
@@ -0,0 +1,162 @@
+|
+|	smovecr.sa 3.1 12/10/90
+|
+|	The entry point sMOVECR returns the constant at the
+|	offset given in the instruction field.
+|
+|	Input: An offset in the instruction word.
+|
+|	Output:	The constant rounded to the user's rounding
+|		mode unchecked for overflow.
+|
+|	Modified: fp0.
+|
+|
+|		Copyright (C) Motorola, Inc. 1990
+|			All Rights Reserved
+|
+|	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA 
+|	The copyright notice above does not evidence any  
+|	actual or intended publication of such source code.
+
+|SMOVECR	idnt	2,1 | Motorola 040 Floating Point Software Package
+
+	|section 8
+
+	.include "fpsp.h"
+
+	|xref	nrm_set
+	|xref	round
+	|xref	PIRN
+	|xref	PIRZRM
+	|xref	PIRP
+	|xref	SMALRN
+	|xref	SMALRZRM
+	|xref	SMALRP
+	|xref	BIGRN
+	|xref	BIGRZRM
+	|xref	BIGRP
+
+FZERO:	.long	00000000
+|
+|	FMOVECR 
+|
+	.global	smovcr
+smovcr:
+	bfextu	CMDREG1B(%a6){#9:#7},%d0 |get offset
+	bfextu	USER_FPCR(%a6){#26:#2},%d1 |get rmode
+|
+| check range of offset
+|
+	tstb	%d0		|if zero, offset is to pi
+	beqs	PI_TBL		|it is pi
+	cmpib	#0x0a,%d0		|check range $01 - $0a
+	bles	Z_VAL		|if in this range, return zero
+	cmpib	#0x0e,%d0		|check range $0b - $0e
+	bles	SM_TBL		|valid constants in this range
+	cmpib	#0x2f,%d0		|check range $10 - $2f
+	bles	Z_VAL		|if in this range, return zero 
+	cmpib	#0x3f,%d0		|check range $30 - $3f
+	ble  	BG_TBL		|valid constants in this range
+Z_VAL:
+	fmoves	FZERO,%fp0
+	rts
+PI_TBL:
+	tstb	%d1		|offset is zero, check for rmode
+	beqs	PI_RN		|if zero, rn mode
+	cmpib	#0x3,%d1		|check for rp
+	beqs	PI_RP		|if 3, rp mode
+PI_RZRM:
+	leal	PIRZRM,%a0	|rmode is rz or rm, load PIRZRM in a0
+	bra	set_finx
+PI_RN:
+	leal	PIRN,%a0		|rmode is rn, load PIRN in a0
+	bra	set_finx
+PI_RP:
+	leal	PIRP,%a0		|rmode is rp, load PIRP in a0
+	bra	set_finx
+SM_TBL:
+	subil	#0xb,%d0		|make offset in 0 - 4 range
+	tstb	%d1		|check for rmode
+	beqs	SM_RN		|if zero, rn mode
+	cmpib	#0x3,%d1		|check for rp
+	beqs	SM_RP		|if 3, rp mode
+SM_RZRM:
+	leal	SMALRZRM,%a0	|rmode is rz or rm, load SMRZRM in a0
+	cmpib	#0x2,%d0		|check if result is inex
+	ble	set_finx	|if 0 - 2, it is inexact
+	bra	no_finx		|if 3, it is exact
+SM_RN:
+	leal	SMALRN,%a0	|rmode is rn, load SMRN in a0
+	cmpib	#0x2,%d0		|check if result is inex
+	ble	set_finx	|if 0 - 2, it is inexact
+	bra	no_finx		|if 3, it is exact
+SM_RP:
+	leal	SMALRP,%a0	|rmode is rp, load SMRP in a0
+	cmpib	#0x2,%d0		|check if result is inex
+	ble	set_finx	|if 0 - 2, it is inexact
+	bra	no_finx		|if 3, it is exact
+BG_TBL:
+	subil	#0x30,%d0		|make offset in 0 - f range
+	tstb	%d1		|check for rmode
+	beqs	BG_RN		|if zero, rn mode
+	cmpib	#0x3,%d1		|check for rp
+	beqs	BG_RP		|if 3, rp mode
+BG_RZRM:
+	leal	BIGRZRM,%a0	|rmode is rz or rm, load BGRZRM in a0
+	cmpib	#0x1,%d0		|check if result is inex
+	ble	set_finx	|if 0 - 1, it is inexact
+	cmpib	#0x7,%d0		|second check
+	ble	no_finx		|if 0 - 7, it is exact
+	bra	set_finx	|if 8 - f, it is inexact
+BG_RN:
+	leal	BIGRN,%a0	|rmode is rn, load BGRN in a0
+	cmpib	#0x1,%d0		|check if result is inex
+	ble	set_finx	|if 0 - 1, it is inexact
+	cmpib	#0x7,%d0		|second check
+	ble	no_finx		|if 0 - 7, it is exact
+	bra	set_finx	|if 8 - f, it is inexact
+BG_RP:
+	leal	BIGRP,%a0	|rmode is rp, load SMRP in a0
+	cmpib	#0x1,%d0		|check if result is inex
+	ble	set_finx	|if 0 - 1, it is inexact
+	cmpib	#0x7,%d0		|second check
+	ble	no_finx		|if 0 - 7, it is exact
+|	bra	set_finx	;if 8 - f, it is inexact
+set_finx:
+	orl	#inx2a_mask,USER_FPSR(%a6) |set inex2/ainex
+no_finx:
+	mulul	#12,%d0			|use offset to point into tables
+	movel	%d1,L_SCR1(%a6)		|load mode for round call
+	bfextu	USER_FPCR(%a6){#24:#2},%d1	|get precision
+	tstl	%d1			|check if extended precision
+|
+| Precision is extended
+|
+	bnes	not_ext			|if extended, do not call round
+	fmovemx (%a0,%d0),%fp0-%fp0		|return result in fp0
+	rts
+|
+| Precision is single or double
+|
+not_ext:
+	swap	%d1			|rnd prec in upper word of d1
+	addl	L_SCR1(%a6),%d1		|merge rmode in low word of d1
+	movel	(%a0,%d0),FP_SCR1(%a6)	|load first word to temp storage
+	movel	4(%a0,%d0),FP_SCR1+4(%a6)	|load second word
+	movel	8(%a0,%d0),FP_SCR1+8(%a6)	|load third word
+	clrl	%d0			|clear g,r,s
+	lea	FP_SCR1(%a6),%a0
+	btstb	#sign_bit,LOCAL_EX(%a0)
+	sne	LOCAL_SGN(%a0)		|convert to internal ext. format
+	
+	bsr	round			|go round the mantissa
+
+	bfclr	LOCAL_SGN(%a0){#0:#8}	|convert back to IEEE ext format
+	beqs	fin_fcr
+	bsetb	#sign_bit,LOCAL_EX(%a0)
+fin_fcr:
+	fmovemx (%a0),%fp0-%fp0
+	rts
+
+	|end
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/fpsp040/srem_mod.S linux/arch/m68k/fpsp040/srem_mod.S
--- v1.3.93/linux/arch/m68k/fpsp040/srem_mod.S	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/fpsp040/srem_mod.S	Sat Feb 24 22:58:44 1996
@@ -0,0 +1,422 @@
+|
+|	srem_mod.sa 3.1 12/10/90
+|
+|      The entry point sMOD computes the floating point MOD of the
+|      input values X and Y. The entry point sREM computes the floating
+|      point (IEEE) REM of the input values X and Y.
+|
+|      INPUT
+|      -----
+|      Double-extended value Y is pointed to by address in register
+|      A0. Double-extended value X is located in -12(A0). The values
+|      of X and Y are both nonzero and finite; although either or both
+|      of them can be denormalized. The special cases of zeros, NaNs,
+|      and infinities are handled elsewhere.
+|
+|      OUTPUT
+|      ------
+|      FREM(X,Y) or FMOD(X,Y), depending on entry point.
+|
+|       ALGORITHM
+|       ---------
+|
+|       Step 1.  Save and strip signs of X and Y: signX := sign(X),
+|                signY := sign(Y), X := |X|, Y := |Y|, 
+|                signQ := signX EOR signY. Record whether MOD or REM
+|                is requested.
+|
+|       Step 2.  Set L := expo(X)-expo(Y), k := 0, Q := 0.
+|                If (L < 0) then
+|                   R := X, go to Step 4.
+|                else
+|                   R := 2^(-L)X, j := L.
+|                endif
+|
+|       Step 3.  Perform MOD(X,Y)
+|            3.1 If R = Y, go to Step 9.
+|            3.2 If R > Y, then { R := R - Y, Q := Q + 1}
+|            3.3 If j = 0, go to Step 4.
+|            3.4 k := k + 1, j := j - 1, Q := 2Q, R := 2R. Go to
+|                Step 3.1.
+|
+|       Step 4.  At this point, R = X - QY = MOD(X,Y). Set
+|                Last_Subtract := false (used in Step 7 below). If
+|                MOD is requested, go to Step 6. 
+|
+|       Step 5.  R = MOD(X,Y), but REM(X,Y) is requested.
+|            5.1 If R < Y/2, then R = MOD(X,Y) = REM(X,Y). Go to
+|                Step 6.
+|            5.2 If R > Y/2, then { set Last_Subtract := true,
+|                Q := Q + 1, Y := signY*Y }. Go to Step 6.
+|            5.3 This is the tricky case of R = Y/2. If Q is odd,
+|                then { Q := Q + 1, signX := -signX }.
+|
+|       Step 6.  R := signX*R.
+|
+|       Step 7.  If Last_Subtract = true, R := R - Y.
+|
+|       Step 8.  Return signQ, last 7 bits of Q, and R as required.
+|
+|       Step 9.  At this point, R = 2^(-j)*X - Q Y = Y. Thus,
+|                X = 2^(j)*(Q+1)Y. set Q := 2^(j)*(Q+1),
+|                R := 0. Return signQ, last 7 bits of Q, and R.
+|
+|                
+             
+|		Copyright (C) Motorola, Inc. 1990
+|			All Rights Reserved
+|
+|	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA 
+|	The copyright notice above does not evidence any  
+|	actual or intended publication of such source code.
+
+SREM_MOD:    |idnt    2,1 | Motorola 040 Floating Point Software Package
+
+	|section    8
+
+	.include "fpsp.h"
+
+	.set	Mod_Flag,L_SCR3
+	.set	SignY,FP_SCR3+4
+	.set	SignX,FP_SCR3+8
+	.set	SignQ,FP_SCR3+12
+	.set	Sc_Flag,FP_SCR4
+
+	.set	Y,FP_SCR1
+	.set	Y_Hi,Y+4
+	.set	Y_Lo,Y+8
+
+	.set	R,FP_SCR2
+	.set	R_Hi,R+4
+	.set	R_Lo,R+8
+
+
+Scale:     .long	0x00010000,0x80000000,0x00000000,0x00000000
+
+	|xref	t_avoid_unsupp
+
+        .global        smod
+smod:
+
+   movel               #0,Mod_Flag(%a6)
+   bras                Mod_Rem
+
+        .global        srem
+srem:
+
+   movel               #1,Mod_Flag(%a6)
+
+Mod_Rem:
+|..Save sign of X and Y
+   moveml              %d2-%d7,-(%a7)     | ...save data registers
+   movew               (%a0),%d3
+   movew               %d3,SignY(%a6)
+   andil               #0x00007FFF,%d3   | ...Y := |Y|
+
+|
+   movel               4(%a0),%d4
+   movel               8(%a0),%d5        | ...(D3,D4,D5) is |Y|
+
+   tstl                %d3
+   bnes                Y_Normal
+
+   movel               #0x00003FFE,%d3	| ...$3FFD + 1
+   tstl                %d4
+   bnes                HiY_not0
+
+HiY_0:
+   movel               %d5,%d4
+   clrl                %d5
+   subil               #32,%d3
+   clrl                %d6
+   bfffo                %d4{#0:#32},%d6
+   lsll                %d6,%d4
+   subl                %d6,%d3           | ...(D3,D4,D5) is normalized
+|                                       ...with bias $7FFD
+   bras                Chk_X
+
+HiY_not0:
+   clrl                %d6
+   bfffo                %d4{#0:#32},%d6
+   subl                %d6,%d3
+   lsll                %d6,%d4
+   movel               %d5,%d7           | ...a copy of D5
+   lsll                %d6,%d5
+   negl                %d6
+   addil               #32,%d6
+   lsrl                %d6,%d7
+   orl                 %d7,%d4           | ...(D3,D4,D5) normalized
+|                                       ...with bias $7FFD
+   bras                Chk_X
+
+Y_Normal:
+   addil               #0x00003FFE,%d3   | ...(D3,D4,D5) normalized
+|                                       ...with bias $7FFD
+
+Chk_X:
+   movew               -12(%a0),%d0
+   movew               %d0,SignX(%a6)
+   movew               SignY(%a6),%d1
+   eorl                %d0,%d1
+   andil               #0x00008000,%d1
+   movew               %d1,SignQ(%a6)	| ...sign(Q) obtained
+   andil               #0x00007FFF,%d0
+   movel               -8(%a0),%d1
+   movel               -4(%a0),%d2       | ...(D0,D1,D2) is |X|
+   tstl                %d0
+   bnes                X_Normal
+   movel               #0x00003FFE,%d0
+   tstl                %d1
+   bnes                HiX_not0
+
+HiX_0:
+   movel               %d2,%d1
+   clrl                %d2
+   subil               #32,%d0
+   clrl                %d6
+   bfffo                %d1{#0:#32},%d6
+   lsll                %d6,%d1
+   subl                %d6,%d0           | ...(D0,D1,D2) is normalized
+|                                       ...with bias $7FFD
+   bras                Init
+
+HiX_not0:
+   clrl                %d6
+   bfffo                %d1{#0:#32},%d6
+   subl                %d6,%d0
+   lsll                %d6,%d1
+   movel               %d2,%d7           | ...a copy of D2
+   lsll                %d6,%d2
+   negl                %d6
+   addil               #32,%d6
+   lsrl                %d6,%d7
+   orl                 %d7,%d1           | ...(D0,D1,D2) normalized
+|                                       ...with bias $7FFD
+   bras                Init
+
+X_Normal:
+   addil               #0x00003FFE,%d0   | ...(D0,D1,D2) normalized
+|                                       ...with bias $7FFD
+
+Init:
+|
+   movel               %d3,L_SCR1(%a6)   | ...save biased expo(Y)
+   movel		%d0,L_SCR2(%a6)	|save d0
+   subl                %d3,%d0           | ...L := expo(X)-expo(Y)
+|   Move.L               D0,L            ...D0 is j
+   clrl                %d6              | ...D6 := carry <- 0
+   clrl                %d3              | ...D3 is Q
+   moveal              #0,%a1           | ...A1 is k; j+k=L, Q=0
+
+|..(Carry,D1,D2) is R
+   tstl                %d0
+   bges                Mod_Loop
+
+|..expo(X) < expo(Y). Thus X = mod(X,Y)
+|
+   movel		L_SCR2(%a6),%d0	|restore d0
+   bra                Get_Mod
+
+|..At this point  R = 2^(-L)X; Q = 0; k = 0; and  k+j = L
+
+
+Mod_Loop:
+   tstl                %d6              | ...test carry bit
+   bgts                R_GT_Y
+
+|..At this point carry = 0, R = (D1,D2), Y = (D4,D5)
+   cmpl                %d4,%d1           | ...compare hi(R) and hi(Y)
+   bnes                R_NE_Y
+   cmpl                %d5,%d2           | ...compare lo(R) and lo(Y)
+   bnes                R_NE_Y
+
+|..At this point, R = Y
+   bra                Rem_is_0
+
+R_NE_Y:
+|..use the borrow of the previous compare
+   bcss                R_LT_Y          | ...borrow is set iff R < Y
+
+R_GT_Y:
+|..If Carry is set, then Y < (Carry,D1,D2) < 2Y. Otherwise, Carry = 0
+|..and Y < (D1,D2) < 2Y. Either way, perform R - Y
+   subl                %d5,%d2           | ...lo(R) - lo(Y)
+   subxl               %d4,%d1           | ...hi(R) - hi(Y)
+   clrl                %d6              | ...clear carry
+   addql               #1,%d3           | ...Q := Q + 1
+
+R_LT_Y:
+|..At this point, Carry=0, R < Y. R = 2^(k-L)X - QY; k+j = L; j >= 0.
+   tstl                %d0              | ...see if j = 0.
+   beqs                PostLoop
+
+   addl                %d3,%d3           | ...Q := 2Q
+   addl                %d2,%d2           | ...lo(R) = 2lo(R)
+   roxll               #1,%d1           | ...hi(R) = 2hi(R) + carry
+   scs                  %d6              | ...set Carry if 2(R) overflows
+   addql               #1,%a1           | ...k := k+1
+   subql               #1,%d0           | ...j := j - 1
+|..At this point, R=(Carry,D1,D2) = 2^(k-L)X - QY, j+k=L, j >= 0, R < 2Y.
+
+   bras                Mod_Loop
+
+PostLoop:
+|..k = L, j = 0, Carry = 0, R = (D1,D2) = X - QY, R < Y.
+
+|..normalize R.
+   movel               L_SCR1(%a6),%d0           | ...new biased expo of R
+   tstl                %d1
+   bnes                HiR_not0
+
+HiR_0:
+   movel               %d2,%d1
+   clrl                %d2
+   subil               #32,%d0
+   clrl                %d6
+   bfffo                %d1{#0:#32},%d6
+   lsll                %d6,%d1
+   subl                %d6,%d0           | ...(D0,D1,D2) is normalized
+|                                       ...with bias $7FFD
+   bras                Get_Mod
+
+HiR_not0:
+   clrl                %d6
+   bfffo                %d1{#0:#32},%d6
+   bmis                Get_Mod         | ...already normalized
+   subl                %d6,%d0
+   lsll                %d6,%d1
+   movel               %d2,%d7           | ...a copy of D2
+   lsll                %d6,%d2
+   negl                %d6
+   addil               #32,%d6
+   lsrl                %d6,%d7
+   orl                 %d7,%d1           | ...(D0,D1,D2) normalized
+
+|
+Get_Mod:
+   cmpil		#0x000041FE,%d0
+   bges		No_Scale
+Do_Scale:
+   movew		%d0,R(%a6)
+   clrw		R+2(%a6)
+   movel		%d1,R_Hi(%a6)
+   movel		%d2,R_Lo(%a6)
+   movel		L_SCR1(%a6),%d6
+   movew		%d6,Y(%a6)
+   clrw		Y+2(%a6)
+   movel		%d4,Y_Hi(%a6)
+   movel		%d5,Y_Lo(%a6)
+   fmovex		R(%a6),%fp0		| ...no exception
+   movel		#1,Sc_Flag(%a6)
+   bras		ModOrRem
+No_Scale:
+   movel		%d1,R_Hi(%a6)
+   movel		%d2,R_Lo(%a6)
+   subil		#0x3FFE,%d0
+   movew		%d0,R(%a6)
+   clrw		R+2(%a6)
+   movel		L_SCR1(%a6),%d6
+   subil		#0x3FFE,%d6
+   movel		%d6,L_SCR1(%a6)
+   fmovex		R(%a6),%fp0
+   movew		%d6,Y(%a6)
+   movel		%d4,Y_Hi(%a6)
+   movel		%d5,Y_Lo(%a6)
+   movel		#0,Sc_Flag(%a6)
+
+|
+
+
+ModOrRem:
+   movel               Mod_Flag(%a6),%d6
+   beqs                Fix_Sign
+
+   movel               L_SCR1(%a6),%d6           | ...new biased expo(Y)
+   subql               #1,%d6           | ...biased expo(Y/2)
+   cmpl                %d6,%d0
+   blts                Fix_Sign
+   bgts                Last_Sub
+
+   cmpl                %d4,%d1
+   bnes                Not_EQ
+   cmpl                %d5,%d2
+   bnes                Not_EQ
+   bra                Tie_Case
+
+Not_EQ:
+   bcss                Fix_Sign
+
+Last_Sub:
+|
+   fsubx		Y(%a6),%fp0		| ...no exceptions
+   addql               #1,%d3           | ...Q := Q + 1
+
+|
+
+Fix_Sign:
+|..Get sign of X
+   movew               SignX(%a6),%d6
+   bges		Get_Q
+   fnegx		%fp0
+
+|..Get Q
+|
+Get_Q:
+   clrl		%d6		
+   movew               SignQ(%a6),%d6        | ...D6 is sign(Q)
+   movel               #8,%d7
+   lsrl                %d7,%d6           
+   andil               #0x0000007F,%d3   | ...7 bits of Q
+   orl                 %d6,%d3           | ...sign and bits of Q
+   swap                 %d3
+   fmovel              %fpsr,%d6
+   andil               #0xFF00FFFF,%d6
+   orl                 %d3,%d6
+   fmovel              %d6,%fpsr         | ...put Q in fpsr
+
+|
+Restore:
+   moveml              (%a7)+,%d2-%d7
+   fmovel              USER_FPCR(%a6),%fpcr
+   movel               Sc_Flag(%a6),%d0
+   beqs                Finish
+   fmulx		Scale(%pc),%fp0	| ...may cause underflow
+   bra			t_avoid_unsupp	|check for denorm as a
+|					;result of the scaling
+
+Finish:
+	fmovex		%fp0,%fp0		|capture exceptions & round
+	rts
+
+Rem_is_0:
+|..R = 2^(-j)X - Q Y = Y, thus R = 0 and quotient = 2^j (Q+1)
+   addql               #1,%d3
+   cmpil               #8,%d0           | ...D0 is j 
+   bges                Q_Big
+
+   lsll                %d0,%d3
+   bras                Set_R_0
+
+Q_Big:
+   clrl                %d3
+
+Set_R_0:
+   fmoves		#0x00000000,%fp0
+   movel		#0,Sc_Flag(%a6)
+   bra                Fix_Sign
+
+Tie_Case:
+|..Check parity of Q
+   movel               %d3,%d6
+   andil               #0x00000001,%d6
+   tstl                %d6
+   beq                Fix_Sign	| ...Q is even
+
+|..Q is odd, Q := Q + 1, signX := -signX
+   addql               #1,%d3
+   movew               SignX(%a6),%d6
+   eoril               #0x00008000,%d6
+   movew               %d6,SignX(%a6)
+   bra                Fix_Sign
+
+   |end
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/fpsp040/ssin.S linux/arch/m68k/fpsp040/ssin.S
--- v1.3.93/linux/arch/m68k/fpsp040/ssin.S	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/fpsp040/ssin.S	Sat Feb 24 22:58:44 1996
@@ -0,0 +1,746 @@
+|
+|	ssin.sa 3.3 7/29/91
+|
+|	The entry point sSIN computes the sine of an input argument
+|	sCOS computes the cosine, and sSINCOS computes both. The
+|	corresponding entry points with a "d" computes the same
+|	corresponding function values for denormalized inputs.
+|
+|	Input: Double-extended number X in location pointed to
+|		by address register a0.
+|
+|	Output: The funtion value sin(X) or cos(X) returned in Fp0 if SIN or
+|		COS is requested. Otherwise, for SINCOS, sin(X) is returned
+|		in Fp0, and cos(X) is returned in Fp1.
+|
+|	Modifies: Fp0 for SIN or COS; both Fp0 and Fp1 for SINCOS.
+|
+|	Accuracy and Monotonicity: The returned result is within 1 ulp in
+|		64 significant bit, i.e. within 0.5001 ulp to 53 bits if the
+|		result is subsequently rounded to double precision. The
+|		result is provably monotonic in double precision.
+|
+|	Speed: The programs sSIN and sCOS take approximately 150 cycles for
+|		input argument X such that |X| < 15Pi, which is the the usual
+|		situation. The speed for sSINCOS is approximately 190 cycles.
+|
+|	Algorithm:
+|
+|	SIN and COS:
+|	1. If SIN is invoked, set AdjN := 0; otherwise, set AdjN := 1.
+|
+|	2. If |X| >= 15Pi or |X| < 2**(-40), go to 7.
+|
+|	3. Decompose X as X = N(Pi/2) + r where |r| <= Pi/4. Let
+|		k = N mod 4, so in particular, k = 0,1,2,or 3. Overwirte
+|		k by k := k + AdjN.
+|
+|	4. If k is even, go to 6.
+|
+|	5. (k is odd) Set j := (k-1)/2, sgn := (-1)**j. Return sgn*cos(r)
+|		where cos(r) is approximated by an even polynomial in r,
+|		1 + r*r*(B1+s*(B2+ ... + s*B8)),	s = r*r.
+|		Exit.
+|
+|	6. (k is even) Set j := k/2, sgn := (-1)**j. Return sgn*sin(r)
+|		where sin(r) is approximated by an odd polynomial in r
+|		r + r*s*(A1+s*(A2+ ... + s*A7)),	s = r*r.
+|		Exit.
+|
+|	7. If |X| > 1, go to 9.
+|
+|	8. (|X|<2**(-40)) If SIN is invoked, return X; otherwise return 1.
+|
+|	9. Overwrite X by X := X rem 2Pi. Now that |X| <= Pi, go back to 3.
+|
+|	SINCOS:
+|	1. If |X| >= 15Pi or |X| < 2**(-40), go to 6.
+|
+|	2. Decompose X as X = N(Pi/2) + r where |r| <= Pi/4. Let
+|		k = N mod 4, so in particular, k = 0,1,2,or 3.
+|
+|	3. If k is even, go to 5.
+|
+|	4. (k is odd) Set j1 := (k-1)/2, j2 := j1 (EOR) (k mod 2), i.e.
+|		j1 exclusive or with the l.s.b. of k.
+|		sgn1 := (-1)**j1, sgn2 := (-1)**j2.
+|		SIN(X) = sgn1 * cos(r) and COS(X) = sgn2*sin(r) where
+|		sin(r) and cos(r) are computed as odd and even polynomials
+|		in r, respectively. Exit
+|
+|	5. (k is even) Set j1 := k/2, sgn1 := (-1)**j1.
+|		SIN(X) = sgn1 * sin(r) and COS(X) = sgn1*cos(r) where
+|		sin(r) and cos(r) are computed as odd and even polynomials
+|		in r, respectively. Exit
+|
+|	6. If |X| > 1, go to 8.
+|
+|	7. (|X|<2**(-40)) SIN(X) = X and COS(X) = 1. Exit.
+|
+|	8. Overwrite X by X := X rem 2Pi. Now that |X| <= Pi, go back to 2.
+|
+
+|		Copyright (C) Motorola, Inc. 1990
+|			All Rights Reserved
+|
+|	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA 
+|	The copyright notice above does not evidence any  
+|	actual or intended publication of such source code.
+
+|SSIN	idnt	2,1 | Motorola 040 Floating Point Software Package
+
+	|section	8
+
+	.include "fpsp.h"
+
+BOUNDS1:	.long 0x3FD78000,0x4004BC7E
+TWOBYPI:	.long 0x3FE45F30,0x6DC9C883
+
+SINA7:	.long 0xBD6AAA77,0xCCC994F5
+SINA6:	.long 0x3DE61209,0x7AAE8DA1
+
+SINA5:	.long 0xBE5AE645,0x2A118AE4
+SINA4:	.long 0x3EC71DE3,0xA5341531
+
+SINA3:	.long 0xBF2A01A0,0x1A018B59,0x00000000,0x00000000
+
+SINA2:	.long 0x3FF80000,0x88888888,0x888859AF,0x00000000
+
+SINA1:	.long 0xBFFC0000,0xAAAAAAAA,0xAAAAAA99,0x00000000
+
+COSB8:	.long 0x3D2AC4D0,0xD6011EE3
+COSB7:	.long 0xBDA9396F,0x9F45AC19
+
+COSB6:	.long 0x3E21EED9,0x0612C972
+COSB5:	.long 0xBE927E4F,0xB79D9FCF
+
+COSB4:	.long 0x3EFA01A0,0x1A01D423,0x00000000,0x00000000
+
+COSB3:	.long 0xBFF50000,0xB60B60B6,0x0B61D438,0x00000000
+
+COSB2:	.long 0x3FFA0000,0xAAAAAAAA,0xAAAAAB5E
+COSB1:	.long 0xBF000000
+
+INVTWOPI: .long 0x3FFC0000,0xA2F9836E,0x4E44152A
+
+TWOPI1:	.long 0x40010000,0xC90FDAA2,0x00000000,0x00000000
+TWOPI2:	.long 0x3FDF0000,0x85A308D4,0x00000000,0x00000000
+
+	|xref	PITBL
+
+	.set	INARG,FP_SCR4
+
+	.set	X,FP_SCR5
+	.set	XDCARE,X+2
+	.set	XFRAC,X+4
+
+	.set	RPRIME,FP_SCR1
+	.set	SPRIME,FP_SCR2
+
+	.set	POSNEG1,L_SCR1
+	.set	TWOTO63,L_SCR1
+
+	.set	ENDFLAG,L_SCR2
+	.set	N,L_SCR2
+
+	.set	ADJN,L_SCR3
+
+	| xref	t_frcinx
+	|xref	t_extdnrm
+	|xref	sto_cos
+
+	.global	ssind
+ssind:
+|--SIN(X) = X FOR DENORMALIZED X
+	bra		t_extdnrm
+
+	.global	scosd
+scosd:
+|--COS(X) = 1 FOR DENORMALIZED X
+
+	fmoves		#0x3F800000,%fp0
+|
+|	9D25B Fix: Sometimes the previous fmove.s sets fpsr bits
+|
+	fmovel		#0,%fpsr
+|
+	bra		t_frcinx
+
+	.global	ssin
+ssin:
+|--SET ADJN TO 0
+	movel		#0,ADJN(%a6)
+	bras		SINBGN
+
+	.global	scos
+scos:
+|--SET ADJN TO 1
+	movel		#1,ADJN(%a6)
+
+SINBGN:
+|--SAVE FPCR, FP1. CHECK IF |X| IS TOO SMALL OR LARGE
+
+	fmovex		(%a0),%fp0	| ...LOAD INPUT
+
+	movel		(%a0),%d0
+	movew		4(%a0),%d0
+	fmovex		%fp0,X(%a6)
+	andil		#0x7FFFFFFF,%d0		| ...COMPACTIFY X
+
+	cmpil		#0x3FD78000,%d0		| ...|X| >= 2**(-40)?
+	bges		SOK1
+	bra		SINSM
+
+SOK1:
+	cmpil		#0x4004BC7E,%d0		| ...|X| < 15 PI?
+	blts		SINMAIN
+	bra		REDUCEX
+
+SINMAIN:
+|--THIS IS THE USUAL CASE, |X| <= 15 PI.
+|--THE ARGUMENT REDUCTION IS DONE BY TABLE LOOK UP.
+	fmovex		%fp0,%fp1
+	fmuld		TWOBYPI,%fp1	| ...X*2/PI
+
+|--HIDE THE NEXT THREE INSTRUCTIONS
+	lea		PITBL+0x200,%a1 | ...TABLE OF N*PI/2, N = -32,...,32
+	
+
+|--FP1 IS NOW READY
+	fmovel		%fp1,N(%a6)		| ...CONVERT TO INTEGER
+
+	movel		N(%a6),%d0
+	asll		#4,%d0
+	addal		%d0,%a1	| ...A1 IS THE ADDRESS OF N*PIBY2
+|				...WHICH IS IN TWO PIECES Y1 & Y2
+
+	fsubx		(%a1)+,%fp0	| ...X-Y1
+|--HIDE THE NEXT ONE
+	fsubs		(%a1),%fp0	| ...FP0 IS R = (X-Y1)-Y2
+
+SINCONT:
+|--continuation from REDUCEX
+
+|--GET N+ADJN AND SEE IF SIN(R) OR COS(R) IS NEEDED
+	movel		N(%a6),%d0
+	addl		ADJN(%a6),%d0	| ...SEE IF D0 IS ODD OR EVEN
+	rorl		#1,%d0	| ...D0 WAS ODD IFF D0 IS NEGATIVE
+	cmpil		#0,%d0
+	blt		COSPOLY
+
+SINPOLY:
+|--LET J BE THE LEAST SIG. BIT OF D0, LET SGN := (-1)**J.
+|--THEN WE RETURN	SGN*SIN(R). SGN*SIN(R) IS COMPUTED BY
+|--R' + R'*S*(A1 + S(A2 + S(A3 + S(A4 + ... + SA7)))), WHERE
+|--R' = SGN*R, S=R*R. THIS CAN BE REWRITTEN AS
+|--R' + R'*S*( [A1+T(A3+T(A5+TA7))] + [S(A2+T(A4+TA6))])
+|--WHERE T=S*S.
+|--NOTE THAT A3 THROUGH A7 ARE STORED IN DOUBLE PRECISION
+|--WHILE A1 AND A2 ARE IN DOUBLE-EXTENDED FORMAT.
+	fmovex		%fp0,X(%a6)	| ...X IS R
+	fmulx		%fp0,%fp0	| ...FP0 IS S
+|---HIDE THE NEXT TWO WHILE WAITING FOR FP0
+	fmoved		SINA7,%fp3
+	fmoved		SINA6,%fp2
+|--FP0 IS NOW READY
+	fmovex		%fp0,%fp1
+	fmulx		%fp1,%fp1	| ...FP1 IS T
+|--HIDE THE NEXT TWO WHILE WAITING FOR FP1
+
+	rorl		#1,%d0
+	andil		#0x80000000,%d0
+|				...LEAST SIG. BIT OF D0 IN SIGN POSITION
+	eorl		%d0,X(%a6)	| ...X IS NOW R'= SGN*R
+
+	fmulx		%fp1,%fp3	| ...TA7
+	fmulx		%fp1,%fp2	| ...TA6
+
+	faddd		SINA5,%fp3 | ...A5+TA7
+	faddd		SINA4,%fp2 | ...A4+TA6
+
+	fmulx		%fp1,%fp3	| ...T(A5+TA7)
+	fmulx		%fp1,%fp2	| ...T(A4+TA6)
+
+	faddd		SINA3,%fp3 | ...A3+T(A5+TA7)
+	faddx		SINA2,%fp2 | ...A2+T(A4+TA6)
+
+	fmulx		%fp3,%fp1	| ...T(A3+T(A5+TA7))
+
+	fmulx		%fp0,%fp2	| ...S(A2+T(A4+TA6))
+	faddx		SINA1,%fp1 | ...A1+T(A3+T(A5+TA7))
+	fmulx		X(%a6),%fp0	| ...R'*S
+
+	faddx		%fp2,%fp1	| ...[A1+T(A3+T(A5+TA7))]+[S(A2+T(A4+TA6))]
+|--FP3 RELEASED, RESTORE NOW AND TAKE SOME ADVANTAGE OF HIDING
+|--FP2 RELEASED, RESTORE NOW AND TAKE FULL ADVANTAGE OF HIDING
+	
+
+	fmulx		%fp1,%fp0		| ...SIN(R')-R'
+|--FP1 RELEASED.
+
+	fmovel		%d1,%FPCR		|restore users exceptions
+	faddx		X(%a6),%fp0		|last inst - possible exception set
+	bra		t_frcinx
+
+
+COSPOLY:
+|--LET J BE THE LEAST SIG. BIT OF D0, LET SGN := (-1)**J.
+|--THEN WE RETURN	SGN*COS(R). SGN*COS(R) IS COMPUTED BY
+|--SGN + S'*(B1 + S(B2 + S(B3 + S(B4 + ... + SB8)))), WHERE
+|--S=R*R AND S'=SGN*S. THIS CAN BE REWRITTEN AS
+|--SGN + S'*([B1+T(B3+T(B5+TB7))] + [S(B2+T(B4+T(B6+TB8)))])
+|--WHERE T=S*S.
+|--NOTE THAT B4 THROUGH B8 ARE STORED IN DOUBLE PRECISION
+|--WHILE B2 AND B3 ARE IN DOUBLE-EXTENDED FORMAT, B1 IS -1/2
+|--AND IS THEREFORE STORED AS SINGLE PRECISION.
+
+	fmulx		%fp0,%fp0	| ...FP0 IS S
+|---HIDE THE NEXT TWO WHILE WAITING FOR FP0
+	fmoved		COSB8,%fp2
+	fmoved		COSB7,%fp3
+|--FP0 IS NOW READY
+	fmovex		%fp0,%fp1
+	fmulx		%fp1,%fp1	| ...FP1 IS T
+|--HIDE THE NEXT TWO WHILE WAITING FOR FP1
+	fmovex		%fp0,X(%a6)	| ...X IS S
+	rorl		#1,%d0
+	andil		#0x80000000,%d0
+|			...LEAST SIG. BIT OF D0 IN SIGN POSITION
+
+	fmulx		%fp1,%fp2	| ...TB8
+|--HIDE THE NEXT TWO WHILE WAITING FOR THE XU
+	eorl		%d0,X(%a6)	| ...X IS NOW S'= SGN*S
+	andil		#0x80000000,%d0
+
+	fmulx		%fp1,%fp3	| ...TB7
+|--HIDE THE NEXT TWO WHILE WAITING FOR THE XU
+	oril		#0x3F800000,%d0	| ...D0 IS SGN IN SINGLE
+	movel		%d0,POSNEG1(%a6)
+
+	faddd		COSB6,%fp2 | ...B6+TB8
+	faddd		COSB5,%fp3 | ...B5+TB7
+
+	fmulx		%fp1,%fp2	| ...T(B6+TB8)
+	fmulx		%fp1,%fp3	| ...T(B5+TB7)
+
+	faddd		COSB4,%fp2 | ...B4+T(B6+TB8)
+	faddx		COSB3,%fp3 | ...B3+T(B5+TB7)
+
+	fmulx		%fp1,%fp2	| ...T(B4+T(B6+TB8))
+	fmulx		%fp3,%fp1	| ...T(B3+T(B5+TB7))
+
+	faddx		COSB2,%fp2 | ...B2+T(B4+T(B6+TB8))
+	fadds		COSB1,%fp1 | ...B1+T(B3+T(B5+TB7))
+
+	fmulx		%fp2,%fp0	| ...S(B2+T(B4+T(B6+TB8)))
+|--FP3 RELEASED, RESTORE NOW AND TAKE SOME ADVANTAGE OF HIDING
+|--FP2 RELEASED.
+	
+
+	faddx		%fp1,%fp0
+|--FP1 RELEASED
+
+	fmulx		X(%a6),%fp0
+
+	fmovel		%d1,%FPCR		|restore users exceptions
+	fadds		POSNEG1(%a6),%fp0	|last inst - possible exception set
+	bra		t_frcinx
+
+
+SINBORS:
+|--IF |X| > 15PI, WE USE THE GENERAL ARGUMENT REDUCTION.
+|--IF |X| < 2**(-40), RETURN X OR 1.
+	cmpil		#0x3FFF8000,%d0
+	bgts		REDUCEX
+        
+
+SINSM:
+	movel		ADJN(%a6),%d0
+	cmpil		#0,%d0
+	bgts		COSTINY
+
+SINTINY:
+	movew		#0x0000,XDCARE(%a6)	| ...JUST IN CASE
+	fmovel		%d1,%FPCR		|restore users exceptions
+	fmovex		X(%a6),%fp0		|last inst - possible exception set
+	bra		t_frcinx
+
+
+COSTINY:
+	fmoves		#0x3F800000,%fp0
+
+	fmovel		%d1,%FPCR		|restore users exceptions
+	fsubs		#0x00800000,%fp0	|last inst - possible exception set
+	bra		t_frcinx
+
+
+REDUCEX:
+|--WHEN REDUCEX IS USED, THE CODE WILL INEVITABLY BE SLOW.
+|--THIS REDUCTION METHOD, HOWEVER, IS MUCH FASTER THAN USING
+|--THE REMAINDER INSTRUCTION WHICH IS NOW IN SOFTWARE.
+
+	fmovemx	%fp2-%fp5,-(%a7)	| ...save FP2 through FP5
+	movel		%d2,-(%a7)
+        fmoves         #0x00000000,%fp1
+|--If compact form of abs(arg) in d0=$7ffeffff, argument is so large that
+|--there is a danger of unwanted overflow in first LOOP iteration.  In this
+|--case, reduce argument by one remainder step to make subsequent reduction
+|--safe.
+	cmpil	#0x7ffeffff,%d0		|is argument dangerously large?
+	bnes	LOOP
+	movel	#0x7ffe0000,FP_SCR2(%a6)	|yes
+|					;create 2**16383*PI/2
+	movel	#0xc90fdaa2,FP_SCR2+4(%a6)
+	clrl	FP_SCR2+8(%a6)
+	ftstx	%fp0			|test sign of argument
+	movel	#0x7fdc0000,FP_SCR3(%a6)	|create low half of 2**16383*
+|					;PI/2 at FP_SCR3
+	movel	#0x85a308d3,FP_SCR3+4(%a6)
+	clrl   FP_SCR3+8(%a6)
+	fblt	red_neg
+	orw	#0x8000,FP_SCR2(%a6)	|positive arg
+	orw	#0x8000,FP_SCR3(%a6)
+red_neg:
+	faddx  FP_SCR2(%a6),%fp0		|high part of reduction is exact
+	fmovex  %fp0,%fp1		|save high result in fp1
+	faddx  FP_SCR3(%a6),%fp0		|low part of reduction
+	fsubx  %fp0,%fp1			|determine low component of result
+	faddx  FP_SCR3(%a6),%fp1		|fp0/fp1 are reduced argument.
+
+|--ON ENTRY, FP0 IS X, ON RETURN, FP0 IS X REM PI/2, |X| <= PI/4.
+|--integer quotient will be stored in N
+|--Intermeditate remainder is 66-bit long; (R,r) in (FP0,FP1)
+
+LOOP:
+	fmovex		%fp0,INARG(%a6)	| ...+-2**K * F, 1 <= F < 2
+	movew		INARG(%a6),%d0
+        movel          %d0,%a1		| ...save a copy of D0
+	andil		#0x00007FFF,%d0
+	subil		#0x00003FFF,%d0	| ...D0 IS K
+	cmpil		#28,%d0
+	bles		LASTLOOP
+CONTLOOP:
+	subil		#27,%d0	 | ...D0 IS L := K-27
+	movel		#0,ENDFLAG(%a6)
+	bras		WORK
+LASTLOOP:
+	clrl		%d0		| ...D0 IS L := 0
+	movel		#1,ENDFLAG(%a6)
+
+WORK:
+|--FIND THE REMAINDER OF (R,r) W.R.T.	2**L * (PI/2). L IS SO CHOSEN
+|--THAT	INT( X * (2/PI) / 2**(L) ) < 2**29.
+
+|--CREATE 2**(-L) * (2/PI), SIGN(INARG)*2**(63),
+|--2**L * (PIby2_1), 2**L * (PIby2_2)
+
+	movel		#0x00003FFE,%d2	| ...BIASED EXPO OF 2/PI
+	subl		%d0,%d2		| ...BIASED EXPO OF 2**(-L)*(2/PI)
+
+	movel		#0xA2F9836E,FP_SCR1+4(%a6)
+	movel		#0x4E44152A,FP_SCR1+8(%a6)
+	movew		%d2,FP_SCR1(%a6)	| ...FP_SCR1 is 2**(-L)*(2/PI)
+
+	fmovex		%fp0,%fp2
+	fmulx		FP_SCR1(%a6),%fp2
+|--WE MUST NOW FIND INT(FP2). SINCE WE NEED THIS VALUE IN
+|--FLOATING POINT FORMAT, THE TWO FMOVE'S	FMOVE.L FP <--> N
+|--WILL BE TOO INEFFICIENT. THE WAY AROUND IT IS THAT
+|--(SIGN(INARG)*2**63	+	FP2) - SIGN(INARG)*2**63 WILL GIVE
+|--US THE DESIRED VALUE IN FLOATING POINT.
+
+|--HIDE SIX CYCLES OF INSTRUCTION
+        movel		%a1,%d2
+        swap		%d2
+	andil		#0x80000000,%d2
+	oril		#0x5F000000,%d2	| ...D2 IS SIGN(INARG)*2**63 IN SGL
+	movel		%d2,TWOTO63(%a6)
+
+	movel		%d0,%d2
+	addil		#0x00003FFF,%d2	| ...BIASED EXPO OF 2**L * (PI/2)
+
+|--FP2 IS READY
+	fadds		TWOTO63(%a6),%fp2	| ...THE FRACTIONAL PART OF FP1 IS ROUNDED
+
+|--HIDE 4 CYCLES OF INSTRUCTION; creating 2**(L)*Piby2_1  and  2**(L)*Piby2_2
+        movew		%d2,FP_SCR2(%a6)
+	clrw           FP_SCR2+2(%a6)
+	movel		#0xC90FDAA2,FP_SCR2+4(%a6)
+	clrl		FP_SCR2+8(%a6)		| ...FP_SCR2 is  2**(L) * Piby2_1	
+
+|--FP2 IS READY
+	fsubs		TWOTO63(%a6),%fp2		| ...FP2 is N
+
+	addil		#0x00003FDD,%d0
+        movew		%d0,FP_SCR3(%a6)
+	clrw           FP_SCR3+2(%a6)
+	movel		#0x85A308D3,FP_SCR3+4(%a6)
+	clrl		FP_SCR3+8(%a6)		| ...FP_SCR3 is 2**(L) * Piby2_2
+
+	movel		ENDFLAG(%a6),%d0
+
+|--We are now ready to perform (R+r) - N*P1 - N*P2, P1 = 2**(L) * Piby2_1 and
+|--P2 = 2**(L) * Piby2_2
+	fmovex		%fp2,%fp4
+	fmulx		FP_SCR2(%a6),%fp4		| ...W = N*P1
+	fmovex		%fp2,%fp5
+	fmulx		FP_SCR3(%a6),%fp5		| ...w = N*P2
+	fmovex		%fp4,%fp3
+|--we want P+p = W+w  but  |p| <= half ulp of P
+|--Then, we need to compute  A := R-P   and  a := r-p
+	faddx		%fp5,%fp3			| ...FP3 is P
+	fsubx		%fp3,%fp4			| ...W-P
+
+	fsubx		%fp3,%fp0			| ...FP0 is A := R - P
+        faddx		%fp5,%fp4			| ...FP4 is p = (W-P)+w
+
+	fmovex		%fp0,%fp3			| ...FP3 A
+	fsubx		%fp4,%fp1			| ...FP1 is a := r - p
+
+|--Now we need to normalize (A,a) to  "new (R,r)" where R+r = A+a but
+|--|r| <= half ulp of R.
+	faddx		%fp1,%fp0			| ...FP0 is R := A+a
+|--No need to calculate r if this is the last loop
+	cmpil		#0,%d0
+	bgt		RESTORE
+
+|--Need to calculate r
+	fsubx		%fp0,%fp3			| ...A-R
+	faddx		%fp3,%fp1			| ...FP1 is r := (A-R)+a
+	bra		LOOP
+
+RESTORE:
+        fmovel		%fp2,N(%a6)
+	movel		(%a7)+,%d2
+	fmovemx	(%a7)+,%fp2-%fp5
+
+	
+	movel		ADJN(%a6),%d0
+	cmpil		#4,%d0
+
+	blt		SINCONT
+	bras		SCCONT
+
+	.global	ssincosd
+ssincosd:
+|--SIN AND COS OF X FOR DENORMALIZED X
+
+	fmoves		#0x3F800000,%fp1
+	bsr		sto_cos		|store cosine result
+	bra		t_extdnrm
+
+	.global	ssincos
+ssincos:
+|--SET ADJN TO 4
+	movel		#4,ADJN(%a6)
+
+	fmovex		(%a0),%fp0	| ...LOAD INPUT
+
+	movel		(%a0),%d0
+	movew		4(%a0),%d0
+	fmovex		%fp0,X(%a6)
+	andil		#0x7FFFFFFF,%d0		| ...COMPACTIFY X
+
+	cmpil		#0x3FD78000,%d0		| ...|X| >= 2**(-40)?
+	bges		SCOK1
+	bra		SCSM
+
+SCOK1:
+	cmpil		#0x4004BC7E,%d0		| ...|X| < 15 PI?
+	blts		SCMAIN
+	bra		REDUCEX
+
+
+SCMAIN:
+|--THIS IS THE USUAL CASE, |X| <= 15 PI.
+|--THE ARGUMENT REDUCTION IS DONE BY TABLE LOOK UP.
+	fmovex		%fp0,%fp1
+	fmuld		TWOBYPI,%fp1	| ...X*2/PI
+
+|--HIDE THE NEXT THREE INSTRUCTIONS
+	lea		PITBL+0x200,%a1 | ...TABLE OF N*PI/2, N = -32,...,32
+	
+
+|--FP1 IS NOW READY
+	fmovel		%fp1,N(%a6)		| ...CONVERT TO INTEGER
+
+	movel		N(%a6),%d0
+	asll		#4,%d0
+	addal		%d0,%a1		| ...ADDRESS OF N*PIBY2, IN Y1, Y2
+
+	fsubx		(%a1)+,%fp0	| ...X-Y1
+        fsubs		(%a1),%fp0	| ...FP0 IS R = (X-Y1)-Y2
+
+SCCONT:
+|--continuation point from REDUCEX
+
+|--HIDE THE NEXT TWO
+	movel		N(%a6),%d0
+	rorl		#1,%d0
+	
+	cmpil		#0,%d0		| ...D0 < 0 IFF N IS ODD
+	bge		NEVEN
+
+NODD:
+|--REGISTERS SAVED SO FAR: D0, A0, FP2.
+
+	fmovex		%fp0,RPRIME(%a6)
+	fmulx		%fp0,%fp0	 | ...FP0 IS S = R*R
+	fmoved		SINA7,%fp1	| ...A7
+	fmoved		COSB8,%fp2	| ...B8
+	fmulx		%fp0,%fp1	 | ...SA7
+	movel		%d2,-(%a7)
+	movel		%d0,%d2
+	fmulx		%fp0,%fp2	 | ...SB8
+	rorl		#1,%d2
+	andil		#0x80000000,%d2
+
+	faddd		SINA6,%fp1	| ...A6+SA7
+	eorl		%d0,%d2
+	andil		#0x80000000,%d2
+	faddd		COSB7,%fp2	| ...B7+SB8
+
+	fmulx		%fp0,%fp1	 | ...S(A6+SA7)
+	eorl		%d2,RPRIME(%a6)
+	movel		(%a7)+,%d2
+	fmulx		%fp0,%fp2	 | ...S(B7+SB8)
+	rorl		#1,%d0
+	andil		#0x80000000,%d0
+
+	faddd		SINA5,%fp1	| ...A5+S(A6+SA7)
+	movel		#0x3F800000,POSNEG1(%a6)
+	eorl		%d0,POSNEG1(%a6)
+	faddd		COSB6,%fp2	| ...B6+S(B7+SB8)
+
+	fmulx		%fp0,%fp1	 | ...S(A5+S(A6+SA7))
+	fmulx		%fp0,%fp2	 | ...S(B6+S(B7+SB8))
+	fmovex		%fp0,SPRIME(%a6)
+
+	faddd		SINA4,%fp1	| ...A4+S(A5+S(A6+SA7))
+	eorl		%d0,SPRIME(%a6)
+	faddd		COSB5,%fp2	| ...B5+S(B6+S(B7+SB8))
+
+	fmulx		%fp0,%fp1	 | ...S(A4+...)
+	fmulx		%fp0,%fp2	 | ...S(B5+...)
+
+	faddd		SINA3,%fp1	| ...A3+S(A4+...)
+	faddd		COSB4,%fp2	| ...B4+S(B5+...)
+
+	fmulx		%fp0,%fp1	 | ...S(A3+...)
+	fmulx		%fp0,%fp2	 | ...S(B4+...)
+
+	faddx		SINA2,%fp1	| ...A2+S(A3+...)
+	faddx		COSB3,%fp2	| ...B3+S(B4+...)
+
+	fmulx		%fp0,%fp1	 | ...S(A2+...)
+	fmulx		%fp0,%fp2	 | ...S(B3+...)
+
+	faddx		SINA1,%fp1	| ...A1+S(A2+...)
+	faddx		COSB2,%fp2	| ...B2+S(B3+...)
+
+	fmulx		%fp0,%fp1	 | ...S(A1+...)
+	fmulx		%fp2,%fp0	 | ...S(B2+...)
+
+	
+
+	fmulx		RPRIME(%a6),%fp1	| ...R'S(A1+...)
+	fadds		COSB1,%fp0	| ...B1+S(B2...)
+	fmulx		SPRIME(%a6),%fp0	| ...S'(B1+S(B2+...))
+
+	movel		%d1,-(%sp)	|restore users mode & precision
+	andil		#0xff,%d1		|mask off all exceptions
+	fmovel		%d1,%FPCR
+	faddx		RPRIME(%a6),%fp1	| ...COS(X)
+	bsr		sto_cos		|store cosine result
+	fmovel		(%sp)+,%FPCR	|restore users exceptions
+	fadds		POSNEG1(%a6),%fp0	| ...SIN(X)
+
+	bra		t_frcinx
+
+
+NEVEN:
+|--REGISTERS SAVED SO FAR: FP2.
+
+	fmovex		%fp0,RPRIME(%a6)
+	fmulx		%fp0,%fp0	 | ...FP0 IS S = R*R
+	fmoved		COSB8,%fp1			| ...B8
+	fmoved		SINA7,%fp2			| ...A7
+	fmulx		%fp0,%fp1	 | ...SB8
+	fmovex		%fp0,SPRIME(%a6)
+	fmulx		%fp0,%fp2	 | ...SA7
+	rorl		#1,%d0
+	andil		#0x80000000,%d0
+	faddd		COSB7,%fp1	| ...B7+SB8
+	faddd		SINA6,%fp2	| ...A6+SA7
+	eorl		%d0,RPRIME(%a6)
+	eorl		%d0,SPRIME(%a6)
+	fmulx		%fp0,%fp1	 | ...S(B7+SB8)
+	oril		#0x3F800000,%d0
+	movel		%d0,POSNEG1(%a6)
+	fmulx		%fp0,%fp2	 | ...S(A6+SA7)
+
+	faddd		COSB6,%fp1	| ...B6+S(B7+SB8)
+	faddd		SINA5,%fp2	| ...A5+S(A6+SA7)
+
+	fmulx		%fp0,%fp1	 | ...S(B6+S(B7+SB8))
+	fmulx		%fp0,%fp2	 | ...S(A5+S(A6+SA7))
+
+	faddd		COSB5,%fp1	| ...B5+S(B6+S(B7+SB8))
+	faddd		SINA4,%fp2	| ...A4+S(A5+S(A6+SA7))
+
+	fmulx		%fp0,%fp1	 | ...S(B5+...)
+	fmulx		%fp0,%fp2	 | ...S(A4+...)
+
+	faddd		COSB4,%fp1	| ...B4+S(B5+...)
+	faddd		SINA3,%fp2	| ...A3+S(A4+...)
+
+	fmulx		%fp0,%fp1	 | ...S(B4+...)
+	fmulx		%fp0,%fp2	 | ...S(A3+...)
+
+	faddx		COSB3,%fp1	| ...B3+S(B4+...)
+	faddx		SINA2,%fp2	| ...A2+S(A3+...)
+
+	fmulx		%fp0,%fp1	 | ...S(B3+...)
+	fmulx		%fp0,%fp2	 | ...S(A2+...)
+
+	faddx		COSB2,%fp1	| ...B2+S(B3+...)
+	faddx		SINA1,%fp2	| ...A1+S(A2+...)
+
+	fmulx		%fp0,%fp1	 | ...S(B2+...)
+	fmulx		%fp2,%fp0	 | ...s(a1+...)
+
+	
+
+	fadds		COSB1,%fp1	| ...B1+S(B2...)
+	fmulx		RPRIME(%a6),%fp0	| ...R'S(A1+...)
+	fmulx		SPRIME(%a6),%fp1	| ...S'(B1+S(B2+...))
+
+	movel		%d1,-(%sp)	|save users mode & precision
+	andil		#0xff,%d1		|mask off all exceptions
+	fmovel		%d1,%FPCR
+	fadds		POSNEG1(%a6),%fp1	| ...COS(X)
+	bsr		sto_cos		|store cosine result
+	fmovel		(%sp)+,%FPCR	|restore users exceptions
+	faddx		RPRIME(%a6),%fp0	| ...SIN(X)
+
+	bra		t_frcinx
+
+SCBORS:
+	cmpil		#0x3FFF8000,%d0
+	bgt		REDUCEX
+        
+
+SCSM:
+	movew		#0x0000,XDCARE(%a6)
+	fmoves		#0x3F800000,%fp1
+
+	movel		%d1,-(%sp)	|save users mode & precision
+	andil		#0xff,%d1		|mask off all exceptions
+	fmovel		%d1,%FPCR
+	fsubs		#0x00800000,%fp1
+	bsr		sto_cos		|store cosine result
+	fmovel		(%sp)+,%FPCR	|restore users exceptions
+	fmovex		X(%a6),%fp0
+	bra		t_frcinx
+
+	|end
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/fpsp040/ssinh.S linux/arch/m68k/fpsp040/ssinh.S
--- v1.3.93/linux/arch/m68k/fpsp040/ssinh.S	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/fpsp040/ssinh.S	Sat Feb 24 22:58:44 1996
@@ -0,0 +1,135 @@
+|
+|	ssinh.sa 3.1 12/10/90
+|
+|       The entry point sSinh computes the hyperbolic sine of
+|       an input argument; sSinhd does the same except for denormalized
+|       input.
+|
+|       Input: Double-extended number X in location pointed to 
+|		by address register a0.
+|
+|       Output: The value sinh(X) returned in floating-point register Fp0.
+|
+|       Accuracy and Monotonicity: The returned result is within 3 ulps in
+|               64 significant bit, i.e. within 0.5001 ulp to 53 bits if the
+|               result is subsequently rounded to double precision. The
+|               result is provably monotonic in double precision.
+|
+|       Speed: The program sSINH takes approximately 280 cycles.
+|
+|       Algorithm:
+|
+|       SINH
+|       1. If |X| > 16380 log2, go to 3.
+|
+|       2. (|X| <= 16380 log2) Sinh(X) is obtained by the formulae
+|               y = |X|, sgn = sign(X), and z = expm1(Y),
+|               sinh(X) = sgn*(1/2)*( z + z/(1+z) ).
+|          Exit.
+|
+|       3. If |X| > 16480 log2, go to 5.
+|
+|       4. (16380 log2 < |X| <= 16480 log2)
+|               sinh(X) = sign(X) * exp(|X|)/2.
+|          However, invoking exp(|X|) may cause premature overflow.
+|          Thus, we calculate sinh(X) as follows:
+|             Y       := |X|
+|             sgn     := sign(X)
+|             sgnFact := sgn * 2**(16380)
+|             Y'      := Y - 16381 log2
+|             sinh(X) := sgnFact * exp(Y').
+|          Exit.
+|
+|       5. (|X| > 16480 log2) sinh(X) must overflow. Return
+|          sign(X)*Huge*Huge to generate overflow and an infinity with
+|          the appropriate sign. Huge is the largest finite number in
+|          extended format. Exit.
+|
+
+|		Copyright (C) Motorola, Inc. 1990
+|			All Rights Reserved
+|
+|	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA 
+|	The copyright notice above does not evidence any  
+|	actual or intended publication of such source code.
+
+|SSINH	idnt	2,1 | Motorola 040 Floating Point Software Package
+
+	|section	8
+
+T1:	.long 0x40C62D38,0xD3D64634 | ... 16381 LOG2 LEAD
+T2:	.long 0x3D6F90AE,0xB1E75CC7 | ... 16381 LOG2 TRAIL
+
+	|xref	t_frcinx
+	|xref	t_ovfl
+	|xref	t_extdnrm
+	|xref	setox
+	|xref	setoxm1
+
+	.global	ssinhd
+ssinhd:
+|--SINH(X) = X FOR DENORMALIZED X
+
+	bra	t_extdnrm
+
+	.global	ssinh
+ssinh:
+	fmovex	(%a0),%fp0	| ...LOAD INPUT
+
+	movel	(%a0),%d0
+	movew	4(%a0),%d0
+	movel	%d0,%a1		| save a copy of original (compacted) operand
+	andl	#0x7FFFFFFF,%d0
+	cmpl	#0x400CB167,%d0
+	bgts	SINHBIG
+
+|--THIS IS THE USUAL CASE, |X| < 16380 LOG2
+|--Y = |X|, Z = EXPM1(Y), SINH(X) = SIGN(X)*(1/2)*( Z + Z/(1+Z) )
+
+	fabsx	%fp0		| ...Y = |X|
+
+	moveml	%a1/%d1,-(%sp)
+	fmovemx %fp0-%fp0,(%a0)
+	clrl	%d1
+	bsr	setoxm1	 	| ...FP0 IS Z = EXPM1(Y)
+	fmovel	#0,%fpcr
+	moveml	(%sp)+,%a1/%d1
+
+	fmovex	%fp0,%fp1
+	fadds	#0x3F800000,%fp1	| ...1+Z
+	fmovex	%fp0,-(%sp)
+	fdivx	%fp1,%fp0		| ...Z/(1+Z)
+	movel	%a1,%d0
+	andl	#0x80000000,%d0
+	orl	#0x3F000000,%d0
+	faddx	(%sp)+,%fp0
+	movel	%d0,-(%sp)
+
+	fmovel	%d1,%fpcr
+	fmuls	(%sp)+,%fp0	|last fp inst - possible exceptions set
+
+	bra	t_frcinx
+
+SINHBIG:
+	cmpl	#0x400CB2B3,%d0
+	bgt	t_ovfl
+	fabsx	%fp0
+	fsubd	T1(%pc),%fp0	| ...(|X|-16381LOG2_LEAD)
+	movel	#0,-(%sp)
+	movel	#0x80000000,-(%sp)
+	movel	%a1,%d0
+	andl	#0x80000000,%d0
+	orl	#0x7FFB0000,%d0
+	movel	%d0,-(%sp)	| ...EXTENDED FMT
+	fsubd	T2(%pc),%fp0	| ...|X| - 16381 LOG2, ACCURATE
+
+	movel	%d1,-(%sp)
+	clrl	%d1
+	fmovemx %fp0-%fp0,(%a0)
+	bsr	setox
+	fmovel	(%sp)+,%fpcr
+
+	fmulx	(%sp)+,%fp0	|possible exception
+	bra	t_frcinx
+
+	|end
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/fpsp040/stan.S linux/arch/m68k/fpsp040/stan.S
--- v1.3.93/linux/arch/m68k/fpsp040/stan.S	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/fpsp040/stan.S	Sat Feb 24 22:58:44 1996
@@ -0,0 +1,455 @@
+|
+|	stan.sa 3.3 7/29/91
+|
+|	The entry point stan computes the tangent of
+|	an input argument;
+|	stand does the same except for denormalized input.
+|
+|	Input: Double-extended number X in location pointed to
+|		by address register a0.
+|
+|	Output: The value tan(X) returned in floating-point register Fp0.
+|
+|	Accuracy and Monotonicity: The returned result is within 3 ulp in
+|		64 significant bit, i.e. within 0.5001 ulp to 53 bits if the
+|		result is subsequently rounded to double precision. The
+|		result is provably monotonic in double precision.
+|
+|	Speed: The program sTAN takes approximately 170 cycles for
+|		input argument X such that |X| < 15Pi, which is the the usual
+|		situation.
+|
+|	Algorithm:
+|
+|	1. If |X| >= 15Pi or |X| < 2**(-40), go to 6.
+|
+|	2. Decompose X as X = N(Pi/2) + r where |r| <= Pi/4. Let
+|		k = N mod 2, so in particular, k = 0 or 1.
+|
+|	3. If k is odd, go to 5.
+|
+|	4. (k is even) Tan(X) = tan(r) and tan(r) is approximated by a
+|		rational function U/V where
+|		U = r + r*s*(P1 + s*(P2 + s*P3)), and
+|		V = 1 + s*(Q1 + s*(Q2 + s*(Q3 + s*Q4))),  s = r*r.
+|		Exit.
+|
+|	4. (k is odd) Tan(X) = -cot(r). Since tan(r) is approximated by a
+|		rational function U/V where
+|		U = r + r*s*(P1 + s*(P2 + s*P3)), and
+|		V = 1 + s*(Q1 + s*(Q2 + s*(Q3 + s*Q4))), s = r*r,
+|		-Cot(r) = -V/U. Exit.
+|
+|	6. If |X| > 1, go to 8.
+|
+|	7. (|X|<2**(-40)) Tan(X) = X. Exit.
+|
+|	8. Overwrite X by X := X rem 2Pi. Now that |X| <= Pi, go back to 2.
+|
+
+|		Copyright (C) Motorola, Inc. 1990
+|			All Rights Reserved
+|
+|	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA 
+|	The copyright notice above does not evidence any  
+|	actual or intended publication of such source code.
+
+|STAN	idnt	2,1 | Motorola 040 Floating Point Software Package
+
+	|section	8
+
+	.include "fpsp.h"
+
+BOUNDS1:	.long 0x3FD78000,0x4004BC7E
+TWOBYPI:	.long 0x3FE45F30,0x6DC9C883
+
+TANQ4:	.long 0x3EA0B759,0xF50F8688
+TANP3:	.long 0xBEF2BAA5,0xA8924F04
+
+TANQ3:	.long 0xBF346F59,0xB39BA65F,0x00000000,0x00000000
+
+TANP2:	.long 0x3FF60000,0xE073D3FC,0x199C4A00,0x00000000
+
+TANQ2:	.long 0x3FF90000,0xD23CD684,0x15D95FA1,0x00000000
+
+TANP1:	.long 0xBFFC0000,0x8895A6C5,0xFB423BCA,0x00000000
+
+TANQ1:	.long 0xBFFD0000,0xEEF57E0D,0xA84BC8CE,0x00000000
+
+INVTWOPI: .long 0x3FFC0000,0xA2F9836E,0x4E44152A,0x00000000
+
+TWOPI1:	.long 0x40010000,0xC90FDAA2,0x00000000,0x00000000
+TWOPI2:	.long 0x3FDF0000,0x85A308D4,0x00000000,0x00000000
+
+|--N*PI/2, -32 <= N <= 32, IN A LEADING TERM IN EXT. AND TRAILING
+|--TERM IN SGL. NOTE THAT PI IS 64-BIT LONG, THUS N*PI/2 IS AT
+|--MOST 69 BITS LONG.
+	.global	PITBL
+PITBL:
+  .long  0xC0040000,0xC90FDAA2,0x2168C235,0x21800000
+  .long  0xC0040000,0xC2C75BCD,0x105D7C23,0xA0D00000
+  .long  0xC0040000,0xBC7EDCF7,0xFF523611,0xA1E80000
+  .long  0xC0040000,0xB6365E22,0xEE46F000,0x21480000
+  .long  0xC0040000,0xAFEDDF4D,0xDD3BA9EE,0xA1200000
+  .long  0xC0040000,0xA9A56078,0xCC3063DD,0x21FC0000
+  .long  0xC0040000,0xA35CE1A3,0xBB251DCB,0x21100000
+  .long  0xC0040000,0x9D1462CE,0xAA19D7B9,0xA1580000
+  .long  0xC0040000,0x96CBE3F9,0x990E91A8,0x21E00000
+  .long  0xC0040000,0x90836524,0x88034B96,0x20B00000
+  .long  0xC0040000,0x8A3AE64F,0x76F80584,0xA1880000
+  .long  0xC0040000,0x83F2677A,0x65ECBF73,0x21C40000
+  .long  0xC0030000,0xFB53D14A,0xA9C2F2C2,0x20000000
+  .long  0xC0030000,0xEEC2D3A0,0x87AC669F,0x21380000
+  .long  0xC0030000,0xE231D5F6,0x6595DA7B,0xA1300000
+  .long  0xC0030000,0xD5A0D84C,0x437F4E58,0x9FC00000
+  .long  0xC0030000,0xC90FDAA2,0x2168C235,0x21000000
+  .long  0xC0030000,0xBC7EDCF7,0xFF523611,0xA1680000
+  .long  0xC0030000,0xAFEDDF4D,0xDD3BA9EE,0xA0A00000
+  .long  0xC0030000,0xA35CE1A3,0xBB251DCB,0x20900000
+  .long  0xC0030000,0x96CBE3F9,0x990E91A8,0x21600000
+  .long  0xC0030000,0x8A3AE64F,0x76F80584,0xA1080000
+  .long  0xC0020000,0xFB53D14A,0xA9C2F2C2,0x1F800000
+  .long  0xC0020000,0xE231D5F6,0x6595DA7B,0xA0B00000
+  .long  0xC0020000,0xC90FDAA2,0x2168C235,0x20800000
+  .long  0xC0020000,0xAFEDDF4D,0xDD3BA9EE,0xA0200000
+  .long  0xC0020000,0x96CBE3F9,0x990E91A8,0x20E00000
+  .long  0xC0010000,0xFB53D14A,0xA9C2F2C2,0x1F000000
+  .long  0xC0010000,0xC90FDAA2,0x2168C235,0x20000000
+  .long  0xC0010000,0x96CBE3F9,0x990E91A8,0x20600000
+  .long  0xC0000000,0xC90FDAA2,0x2168C235,0x1F800000
+  .long  0xBFFF0000,0xC90FDAA2,0x2168C235,0x1F000000
+  .long  0x00000000,0x00000000,0x00000000,0x00000000
+  .long  0x3FFF0000,0xC90FDAA2,0x2168C235,0x9F000000
+  .long  0x40000000,0xC90FDAA2,0x2168C235,0x9F800000
+  .long  0x40010000,0x96CBE3F9,0x990E91A8,0xA0600000
+  .long  0x40010000,0xC90FDAA2,0x2168C235,0xA0000000
+  .long  0x40010000,0xFB53D14A,0xA9C2F2C2,0x9F000000
+  .long  0x40020000,0x96CBE3F9,0x990E91A8,0xA0E00000
+  .long  0x40020000,0xAFEDDF4D,0xDD3BA9EE,0x20200000
+  .long  0x40020000,0xC90FDAA2,0x2168C235,0xA0800000
+  .long  0x40020000,0xE231D5F6,0x6595DA7B,0x20B00000
+  .long  0x40020000,0xFB53D14A,0xA9C2F2C2,0x9F800000
+  .long  0x40030000,0x8A3AE64F,0x76F80584,0x21080000
+  .long  0x40030000,0x96CBE3F9,0x990E91A8,0xA1600000
+  .long  0x40030000,0xA35CE1A3,0xBB251DCB,0xA0900000
+  .long  0x40030000,0xAFEDDF4D,0xDD3BA9EE,0x20A00000
+  .long  0x40030000,0xBC7EDCF7,0xFF523611,0x21680000
+  .long  0x40030000,0xC90FDAA2,0x2168C235,0xA1000000
+  .long  0x40030000,0xD5A0D84C,0x437F4E58,0x1FC00000
+  .long  0x40030000,0xE231D5F6,0x6595DA7B,0x21300000
+  .long  0x40030000,0xEEC2D3A0,0x87AC669F,0xA1380000
+  .long  0x40030000,0xFB53D14A,0xA9C2F2C2,0xA0000000
+  .long  0x40040000,0x83F2677A,0x65ECBF73,0xA1C40000
+  .long  0x40040000,0x8A3AE64F,0x76F80584,0x21880000
+  .long  0x40040000,0x90836524,0x88034B96,0xA0B00000
+  .long  0x40040000,0x96CBE3F9,0x990E91A8,0xA1E00000
+  .long  0x40040000,0x9D1462CE,0xAA19D7B9,0x21580000
+  .long  0x40040000,0xA35CE1A3,0xBB251DCB,0xA1100000
+  .long  0x40040000,0xA9A56078,0xCC3063DD,0xA1FC0000
+  .long  0x40040000,0xAFEDDF4D,0xDD3BA9EE,0x21200000
+  .long  0x40040000,0xB6365E22,0xEE46F000,0xA1480000
+  .long  0x40040000,0xBC7EDCF7,0xFF523611,0x21E80000
+  .long  0x40040000,0xC2C75BCD,0x105D7C23,0x20D00000
+  .long  0x40040000,0xC90FDAA2,0x2168C235,0xA1800000
+
+	.set	INARG,FP_SCR4
+
+	.set	TWOTO63,L_SCR1
+	.set	ENDFLAG,L_SCR2
+	.set	N,L_SCR3
+
+	| xref	t_frcinx
+	|xref	t_extdnrm
+
+	.global	stand
+stand:
+|--TAN(X) = X FOR DENORMALIZED X
+
+	bra		t_extdnrm
+
+	.global	stan
+stan:
+	fmovex		(%a0),%fp0	| ...LOAD INPUT
+
+	movel		(%a0),%d0
+	movew		4(%a0),%d0
+	andil		#0x7FFFFFFF,%d0
+
+	cmpil		#0x3FD78000,%d0		| ...|X| >= 2**(-40)?
+	bges		TANOK1
+	bra		TANSM
+TANOK1:
+	cmpil		#0x4004BC7E,%d0		| ...|X| < 15 PI?
+	blts		TANMAIN
+	bra		REDUCEX
+
+
+TANMAIN:
+|--THIS IS THE USUAL CASE, |X| <= 15 PI.
+|--THE ARGUMENT REDUCTION IS DONE BY TABLE LOOK UP.
+	fmovex		%fp0,%fp1
+	fmuld		TWOBYPI,%fp1	| ...X*2/PI
+
+|--HIDE THE NEXT TWO INSTRUCTIONS
+	leal		PITBL+0x200,%a1 | ...TABLE OF N*PI/2, N = -32,...,32
+
+|--FP1 IS NOW READY
+	fmovel		%fp1,%d0		| ...CONVERT TO INTEGER
+
+	asll		#4,%d0
+	addal		%d0,%a1		| ...ADDRESS N*PIBY2 IN Y1, Y2
+
+	fsubx		(%a1)+,%fp0	| ...X-Y1
+|--HIDE THE NEXT ONE
+
+	fsubs		(%a1),%fp0	| ...FP0 IS R = (X-Y1)-Y2
+
+	rorl		#5,%d0
+	andil		#0x80000000,%d0	| ...D0 WAS ODD IFF D0 < 0
+
+TANCONT:
+
+	cmpil		#0,%d0
+	blt		NODD
+
+	fmovex		%fp0,%fp1
+	fmulx		%fp1,%fp1	 	| ...S = R*R
+
+	fmoved		TANQ4,%fp3
+	fmoved		TANP3,%fp2
+
+	fmulx		%fp1,%fp3	 	| ...SQ4
+	fmulx		%fp1,%fp2	 	| ...SP3
+
+	faddd		TANQ3,%fp3	| ...Q3+SQ4
+	faddx		TANP2,%fp2	| ...P2+SP3
+
+	fmulx		%fp1,%fp3	 	| ...S(Q3+SQ4)
+	fmulx		%fp1,%fp2	 	| ...S(P2+SP3)
+
+	faddx		TANQ2,%fp3	| ...Q2+S(Q3+SQ4)
+	faddx		TANP1,%fp2	| ...P1+S(P2+SP3)
+
+	fmulx		%fp1,%fp3	 	| ...S(Q2+S(Q3+SQ4))
+	fmulx		%fp1,%fp2	 	| ...S(P1+S(P2+SP3))
+
+	faddx		TANQ1,%fp3	| ...Q1+S(Q2+S(Q3+SQ4))
+	fmulx		%fp0,%fp2	 	| ...RS(P1+S(P2+SP3))
+
+	fmulx		%fp3,%fp1	 	| ...S(Q1+S(Q2+S(Q3+SQ4)))
+	
+
+	faddx		%fp2,%fp0	 	| ...R+RS(P1+S(P2+SP3))
+	
+
+	fadds		#0x3F800000,%fp1	| ...1+S(Q1+...)
+
+	fmovel		%d1,%fpcr		|restore users exceptions
+	fdivx		%fp1,%fp0		|last inst - possible exception set
+
+	bra		t_frcinx
+
+NODD:
+	fmovex		%fp0,%fp1
+	fmulx		%fp0,%fp0	 	| ...S = R*R
+
+	fmoved		TANQ4,%fp3
+	fmoved		TANP3,%fp2
+
+	fmulx		%fp0,%fp3	 	| ...SQ4
+	fmulx		%fp0,%fp2	 	| ...SP3
+
+	faddd		TANQ3,%fp3	| ...Q3+SQ4
+	faddx		TANP2,%fp2	| ...P2+SP3
+
+	fmulx		%fp0,%fp3	 	| ...S(Q3+SQ4)
+	fmulx		%fp0,%fp2	 	| ...S(P2+SP3)
+
+	faddx		TANQ2,%fp3	| ...Q2+S(Q3+SQ4)
+	faddx		TANP1,%fp2	| ...P1+S(P2+SP3)
+
+	fmulx		%fp0,%fp3	 	| ...S(Q2+S(Q3+SQ4))
+	fmulx		%fp0,%fp2	 	| ...S(P1+S(P2+SP3))
+
+	faddx		TANQ1,%fp3	| ...Q1+S(Q2+S(Q3+SQ4))
+	fmulx		%fp1,%fp2	 	| ...RS(P1+S(P2+SP3))
+
+	fmulx		%fp3,%fp0	 	| ...S(Q1+S(Q2+S(Q3+SQ4)))
+	
+
+	faddx		%fp2,%fp1	 	| ...R+RS(P1+S(P2+SP3))
+	fadds		#0x3F800000,%fp0	| ...1+S(Q1+...)
+	
+
+	fmovex		%fp1,-(%sp)
+	eoril		#0x80000000,(%sp)
+
+	fmovel		%d1,%fpcr	 	|restore users exceptions
+	fdivx		(%sp)+,%fp0	|last inst - possible exception set
+
+	bra		t_frcinx
+
+TANBORS:
+|--IF |X| > 15PI, WE USE THE GENERAL ARGUMENT REDUCTION.
+|--IF |X| < 2**(-40), RETURN X OR 1.
+	cmpil		#0x3FFF8000,%d0
+	bgts		REDUCEX
+
+TANSM:
+
+	fmovex		%fp0,-(%sp)
+	fmovel		%d1,%fpcr		 |restore users exceptions
+	fmovex		(%sp)+,%fp0	|last inst - posibble exception set
+
+	bra		t_frcinx
+
+
+REDUCEX:
+|--WHEN REDUCEX IS USED, THE CODE WILL INEVITABLY BE SLOW.
+|--THIS REDUCTION METHOD, HOWEVER, IS MUCH FASTER THAN USING
+|--THE REMAINDER INSTRUCTION WHICH IS NOW IN SOFTWARE.
+
+	fmovemx	%fp2-%fp5,-(%a7)	| ...save FP2 through FP5
+	movel		%d2,-(%a7)
+        fmoves         #0x00000000,%fp1
+
+|--If compact form of abs(arg) in d0=$7ffeffff, argument is so large that
+|--there is a danger of unwanted overflow in first LOOP iteration.  In this
+|--case, reduce argument by one remainder step to make subsequent reduction
+|--safe.
+	cmpil	#0x7ffeffff,%d0		|is argument dangerously large?
+	bnes	LOOP
+	movel	#0x7ffe0000,FP_SCR2(%a6)	|yes
+|					;create 2**16383*PI/2
+	movel	#0xc90fdaa2,FP_SCR2+4(%a6)
+	clrl	FP_SCR2+8(%a6)
+	ftstx	%fp0			|test sign of argument
+	movel	#0x7fdc0000,FP_SCR3(%a6)	|create low half of 2**16383*
+|					;PI/2 at FP_SCR3
+	movel	#0x85a308d3,FP_SCR3+4(%a6)
+	clrl   FP_SCR3+8(%a6)
+	fblt	red_neg
+	orw	#0x8000,FP_SCR2(%a6)	|positive arg
+	orw	#0x8000,FP_SCR3(%a6)
+red_neg:
+	faddx  FP_SCR2(%a6),%fp0		|high part of reduction is exact
+	fmovex  %fp0,%fp1		|save high result in fp1
+	faddx  FP_SCR3(%a6),%fp0		|low part of reduction
+	fsubx  %fp0,%fp1			|determine low component of result
+	faddx  FP_SCR3(%a6),%fp1		|fp0/fp1 are reduced argument.
+
+|--ON ENTRY, FP0 IS X, ON RETURN, FP0 IS X REM PI/2, |X| <= PI/4.
+|--integer quotient will be stored in N
+|--Intermeditate remainder is 66-bit long; (R,r) in (FP0,FP1)
+
+LOOP:
+	fmovex		%fp0,INARG(%a6)	| ...+-2**K * F, 1 <= F < 2
+	movew		INARG(%a6),%d0
+        movel          %d0,%a1		| ...save a copy of D0
+	andil		#0x00007FFF,%d0
+	subil		#0x00003FFF,%d0	| ...D0 IS K
+	cmpil		#28,%d0
+	bles		LASTLOOP
+CONTLOOP:
+	subil		#27,%d0	 | ...D0 IS L := K-27
+	movel		#0,ENDFLAG(%a6)
+	bras		WORK
+LASTLOOP:
+	clrl		%d0		| ...D0 IS L := 0
+	movel		#1,ENDFLAG(%a6)
+
+WORK:
+|--FIND THE REMAINDER OF (R,r) W.R.T.	2**L * (PI/2). L IS SO CHOSEN
+|--THAT	INT( X * (2/PI) / 2**(L) ) < 2**29.
+
+|--CREATE 2**(-L) * (2/PI), SIGN(INARG)*2**(63),
+|--2**L * (PIby2_1), 2**L * (PIby2_2)
+
+	movel		#0x00003FFE,%d2	| ...BIASED EXPO OF 2/PI
+	subl		%d0,%d2		| ...BIASED EXPO OF 2**(-L)*(2/PI)
+
+	movel		#0xA2F9836E,FP_SCR1+4(%a6)
+	movel		#0x4E44152A,FP_SCR1+8(%a6)
+	movew		%d2,FP_SCR1(%a6)	| ...FP_SCR1 is 2**(-L)*(2/PI)
+
+	fmovex		%fp0,%fp2
+	fmulx		FP_SCR1(%a6),%fp2
+|--WE MUST NOW FIND INT(FP2). SINCE WE NEED THIS VALUE IN
+|--FLOATING POINT FORMAT, THE TWO FMOVE'S	FMOVE.L FP <--> N
+|--WILL BE TOO INEFFICIENT. THE WAY AROUND IT IS THAT
+|--(SIGN(INARG)*2**63	+	FP2) - SIGN(INARG)*2**63 WILL GIVE
+|--US THE DESIRED VALUE IN FLOATING POINT.
+
+|--HIDE SIX CYCLES OF INSTRUCTION
+        movel		%a1,%d2
+        swap		%d2
+	andil		#0x80000000,%d2
+	oril		#0x5F000000,%d2	| ...D2 IS SIGN(INARG)*2**63 IN SGL
+	movel		%d2,TWOTO63(%a6)
+
+	movel		%d0,%d2
+	addil		#0x00003FFF,%d2	| ...BIASED EXPO OF 2**L * (PI/2)
+
+|--FP2 IS READY
+	fadds		TWOTO63(%a6),%fp2	| ...THE FRACTIONAL PART OF FP1 IS ROUNDED
+
+|--HIDE 4 CYCLES OF INSTRUCTION; creating 2**(L)*Piby2_1  and  2**(L)*Piby2_2
+        movew		%d2,FP_SCR2(%a6)
+	clrw           FP_SCR2+2(%a6)
+	movel		#0xC90FDAA2,FP_SCR2+4(%a6)
+	clrl		FP_SCR2+8(%a6)		| ...FP_SCR2 is  2**(L) * Piby2_1	
+
+|--FP2 IS READY
+	fsubs		TWOTO63(%a6),%fp2		| ...FP2 is N
+
+	addil		#0x00003FDD,%d0
+        movew		%d0,FP_SCR3(%a6)
+	clrw           FP_SCR3+2(%a6)
+	movel		#0x85A308D3,FP_SCR3+4(%a6)
+	clrl		FP_SCR3+8(%a6)		| ...FP_SCR3 is 2**(L) * Piby2_2
+
+	movel		ENDFLAG(%a6),%d0
+
+|--We are now ready to perform (R+r) - N*P1 - N*P2, P1 = 2**(L) * Piby2_1 and
+|--P2 = 2**(L) * Piby2_2
+	fmovex		%fp2,%fp4
+	fmulx		FP_SCR2(%a6),%fp4		| ...W = N*P1
+	fmovex		%fp2,%fp5
+	fmulx		FP_SCR3(%a6),%fp5		| ...w = N*P2
+	fmovex		%fp4,%fp3
+|--we want P+p = W+w  but  |p| <= half ulp of P
+|--Then, we need to compute  A := R-P   and  a := r-p
+	faddx		%fp5,%fp3			| ...FP3 is P
+	fsubx		%fp3,%fp4			| ...W-P
+
+	fsubx		%fp3,%fp0			| ...FP0 is A := R - P
+        faddx		%fp5,%fp4			| ...FP4 is p = (W-P)+w
+
+	fmovex		%fp0,%fp3			| ...FP3 A
+	fsubx		%fp4,%fp1			| ...FP1 is a := r - p
+
+|--Now we need to normalize (A,a) to  "new (R,r)" where R+r = A+a but
+|--|r| <= half ulp of R.
+	faddx		%fp1,%fp0			| ...FP0 is R := A+a
+|--No need to calculate r if this is the last loop
+	cmpil		#0,%d0
+	bgt		RESTORE
+
+|--Need to calculate r
+	fsubx		%fp0,%fp3			| ...A-R
+	faddx		%fp3,%fp1			| ...FP1 is r := (A-R)+a
+	bra		LOOP
+
+RESTORE:
+        fmovel		%fp2,N(%a6)
+	movel		(%a7)+,%d2
+	fmovemx	(%a7)+,%fp2-%fp5
+
+	
+	movel		N(%a6),%d0
+        rorl		#1,%d0
+
+
+	bra		TANCONT
+
+	|end
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/fpsp040/stanh.S linux/arch/m68k/fpsp040/stanh.S
--- v1.3.93/linux/arch/m68k/fpsp040/stanh.S	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/fpsp040/stanh.S	Sat Feb 24 22:58:44 1996
@@ -0,0 +1,185 @@
+|
+|	stanh.sa 3.1 12/10/90
+|
+|	The entry point sTanh computes the hyperbolic tangent of
+|	an input argument; sTanhd does the same except for denormalized
+|	input.
+|
+|	Input: Double-extended number X in location pointed to
+|		by address register a0.
+|
+|	Output: The value tanh(X) returned in floating-point register Fp0.
+|
+|	Accuracy and Monotonicity: The returned result is within 3 ulps in
+|		64 significant bit, i.e. within 0.5001 ulp to 53 bits if the
+|		result is subsequently rounded to double precision. The
+|		result is provably monotonic in double precision.
+|
+|	Speed: The program stanh takes approximately 270 cycles.
+|
+|	Algorithm:
+|
+|	TANH
+|	1. If |X| >= (5/2) log2 or |X| <= 2**(-40), go to 3.
+|
+|	2. (2**(-40) < |X| < (5/2) log2) Calculate tanh(X) by
+|		sgn := sign(X), y := 2|X|, z := expm1(Y), and
+|		tanh(X) = sgn*( z/(2+z) ).
+|		Exit.
+|
+|	3. (|X| <= 2**(-40) or |X| >= (5/2) log2). If |X| < 1,
+|		go to 7.
+|
+|	4. (|X| >= (5/2) log2) If |X| >= 50 log2, go to 6.
+|
+|	5. ((5/2) log2 <= |X| < 50 log2) Calculate tanh(X) by
+|		sgn := sign(X), y := 2|X|, z := exp(Y),
+|		tanh(X) = sgn - [ sgn*2/(1+z) ].
+|		Exit.
+|
+|	6. (|X| >= 50 log2) Tanh(X) = +-1 (round to nearest). Thus, we
+|		calculate Tanh(X) by
+|		sgn := sign(X), Tiny := 2**(-126),
+|		tanh(X) := sgn - sgn*Tiny.
+|		Exit.
+|
+|	7. (|X| < 2**(-40)). Tanh(X) = X.	Exit.
+|
+
+|		Copyright (C) Motorola, Inc. 1990
+|			All Rights Reserved
+|
+|	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA 
+|	The copyright notice above does not evidence any  
+|	actual or intended publication of such source code.
+
+|STANH	idnt	2,1 | Motorola 040 Floating Point Software Package
+
+	|section	8
+	
+	.include "fpsp.h"
+
+	.set	X,FP_SCR5
+	.set	XDCARE,X+2
+	.set	XFRAC,X+4
+
+	.set	SGN,L_SCR3
+
+	.set	V,FP_SCR6
+
+BOUNDS1:	.long 0x3FD78000,0x3FFFDDCE | ... 2^(-40), (5/2)LOG2
+
+	|xref	t_frcinx
+	|xref	t_extdnrm
+	|xref	setox
+	|xref	setoxm1
+
+	.global	stanhd
+stanhd:
+|--TANH(X) = X FOR DENORMALIZED X
+
+	bra		t_extdnrm
+
+	.global	stanh
+stanh:
+	fmovex		(%a0),%fp0	| ...LOAD INPUT
+
+	fmovex		%fp0,X(%a6)
+	movel		(%a0),%d0
+	movew		4(%a0),%d0
+	movel		%d0,X(%a6)
+	andl		#0x7FFFFFFF,%d0
+	cmp2l		BOUNDS1(%pc),%d0	| ...2**(-40) < |X| < (5/2)LOG2 ?
+	bcss		TANHBORS
+
+|--THIS IS THE USUAL CASE
+|--Y = 2|X|, Z = EXPM1(Y), TANH(X) = SIGN(X) * Z / (Z+2).
+
+	movel		X(%a6),%d0
+	movel		%d0,SGN(%a6)
+	andl		#0x7FFF0000,%d0
+	addl		#0x00010000,%d0	| ...EXPONENT OF 2|X|
+	movel		%d0,X(%a6)
+	andl		#0x80000000,SGN(%a6)
+	fmovex		X(%a6),%fp0		| ...FP0 IS Y = 2|X|
+
+	movel		%d1,-(%a7)
+	clrl		%d1
+	fmovemx	%fp0-%fp0,(%a0)
+	bsr		setoxm1	 	| ...FP0 IS Z = EXPM1(Y)
+	movel		(%a7)+,%d1
+
+	fmovex		%fp0,%fp1
+	fadds		#0x40000000,%fp1	| ...Z+2
+	movel		SGN(%a6),%d0
+	fmovex		%fp1,V(%a6)
+	eorl		%d0,V(%a6)
+
+	fmovel		%d1,%FPCR		|restore users exceptions
+	fdivx		V(%a6),%fp0
+	bra		t_frcinx
+
+TANHBORS:
+	cmpl		#0x3FFF8000,%d0
+	blt		TANHSM
+
+	cmpl		#0x40048AA1,%d0
+	bgt		TANHHUGE
+
+|-- (5/2) LOG2 < |X| < 50 LOG2,
+|--TANH(X) = 1 - (2/[EXP(2X)+1]). LET Y = 2|X|, SGN = SIGN(X),
+|--TANH(X) = SGN -	SGN*2/[EXP(Y)+1].
+
+	movel		X(%a6),%d0
+	movel		%d0,SGN(%a6)
+	andl		#0x7FFF0000,%d0
+	addl		#0x00010000,%d0	| ...EXPO OF 2|X|
+	movel		%d0,X(%a6)		| ...Y = 2|X|
+	andl		#0x80000000,SGN(%a6)
+	movel		SGN(%a6),%d0
+	fmovex		X(%a6),%fp0		| ...Y = 2|X|
+
+	movel		%d1,-(%a7)
+	clrl		%d1
+	fmovemx	%fp0-%fp0,(%a0)
+	bsr		setox		| ...FP0 IS EXP(Y)
+	movel		(%a7)+,%d1
+	movel		SGN(%a6),%d0
+	fadds		#0x3F800000,%fp0	| ...EXP(Y)+1
+
+	eorl		#0xC0000000,%d0	| ...-SIGN(X)*2
+	fmoves		%d0,%fp1		| ...-SIGN(X)*2 IN SGL FMT
+	fdivx		%fp0,%fp1	 	| ...-SIGN(X)2 / [EXP(Y)+1 ]
+
+	movel		SGN(%a6),%d0
+	orl		#0x3F800000,%d0	| ...SGN
+	fmoves		%d0,%fp0		| ...SGN IN SGL FMT
+
+	fmovel		%d1,%FPCR		|restore users exceptions
+	faddx		%fp1,%fp0
+
+	bra		t_frcinx
+
+TANHSM:
+	movew		#0x0000,XDCARE(%a6)
+
+	fmovel		%d1,%FPCR		|restore users exceptions
+	fmovex		X(%a6),%fp0		|last inst - possible exception set
+
+	bra		t_frcinx
+
+TANHHUGE:
+|---RETURN SGN(X) - SGN(X)EPS
+	movel		X(%a6),%d0
+	andl		#0x80000000,%d0
+	orl		#0x3F800000,%d0
+	fmoves		%d0,%fp0
+	andl		#0x80000000,%d0
+	eorl		#0x80800000,%d0	| ...-SIGN(X)*EPS
+
+	fmovel		%d1,%FPCR		|restore users exceptions
+	fadds		%d0,%fp0
+
+	bra		t_frcinx
+
+	|end
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/fpsp040/sto_res.S linux/arch/m68k/fpsp040/sto_res.S
--- v1.3.93/linux/arch/m68k/fpsp040/sto_res.S	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/fpsp040/sto_res.S	Sat Feb 24 22:58:44 1996
@@ -0,0 +1,98 @@
+|
+|	sto_res.sa 3.1 12/10/90
+|
+|	Takes the result and puts it in where the user expects it.
+|	Library functions return result in fp0.	If fp0 is not the
+|	users destination register then fp0 is moved to the the
+|	correct floating-point destination register.  fp0 and fp1
+|	are then restored to the original contents. 
+|
+|	Input:	result in fp0,fp1 
+|
+|		d2 & a0 should be kept unmodified
+|
+|	Output:	moves the result to the true destination reg or mem
+|
+|	Modifies: destination floating point register
+|
+
+|		Copyright (C) Motorola, Inc. 1990
+|			All Rights Reserved
+|
+|	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA 
+|	The copyright notice above does not evidence any  
+|	actual or intended publication of such source code.
+
+STO_RES:	|idnt	2,1 | Motorola 040 Floating Point Software Package
+
+
+	|section	8
+
+	.include "fpsp.h"
+
+	.global	sto_cos
+sto_cos:
+	bfextu		CMDREG1B(%a6){#13:#3},%d0	|extract cos destination
+	cmpib		#3,%d0		|check for fp0/fp1 cases
+	bles		c_fp0123
+	fmovemx	%fp1-%fp1,-(%a7)
+	moveql		#7,%d1
+	subl		%d0,%d1		|d1 = 7- (dest. reg. no.)
+	clrl		%d0
+	bsetl		%d1,%d0		|d0 is dynamic register mask
+	fmovemx	(%a7)+,%d0
+	rts
+c_fp0123:
+	cmpib		#0,%d0
+	beqs		c_is_fp0
+	cmpib		#1,%d0
+	beqs		c_is_fp1
+	cmpib		#2,%d0
+	beqs		c_is_fp2
+c_is_fp3:
+	fmovemx	%fp1-%fp1,USER_FP3(%a6)
+	rts
+c_is_fp2:
+	fmovemx	%fp1-%fp1,USER_FP2(%a6)
+	rts
+c_is_fp1:
+	fmovemx	%fp1-%fp1,USER_FP1(%a6)
+	rts
+c_is_fp0:
+	fmovemx	%fp1-%fp1,USER_FP0(%a6)
+	rts
+
+
+	.global	sto_res
+sto_res:
+	bfextu		CMDREG1B(%a6){#6:#3},%d0	|extract destination register
+	cmpib		#3,%d0		|check for fp0/fp1 cases
+	bles		fp0123
+	fmovemx	%fp0-%fp0,-(%a7)
+	moveql		#7,%d1
+	subl		%d0,%d1		|d1 = 7- (dest. reg. no.)
+	clrl		%d0
+	bsetl		%d1,%d0		|d0 is dynamic register mask
+	fmovemx	(%a7)+,%d0
+	rts
+fp0123:
+	cmpib		#0,%d0
+	beqs		is_fp0
+	cmpib		#1,%d0
+	beqs		is_fp1
+	cmpib		#2,%d0
+	beqs		is_fp2
+is_fp3:
+	fmovemx	%fp0-%fp0,USER_FP3(%a6)
+	rts
+is_fp2:
+	fmovemx	%fp0-%fp0,USER_FP2(%a6)
+	rts
+is_fp1:
+	fmovemx	%fp0-%fp0,USER_FP1(%a6)
+	rts
+is_fp0:
+	fmovemx	%fp0-%fp0,USER_FP0(%a6)
+	rts
+
+	|end
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/fpsp040/stwotox.S linux/arch/m68k/fpsp040/stwotox.S
--- v1.3.93/linux/arch/m68k/fpsp040/stwotox.S	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/fpsp040/stwotox.S	Sat Feb 24 22:58:44 1996
@@ -0,0 +1,427 @@
+|
+|	stwotox.sa 3.1 12/10/90
+|
+|	stwotox  --- 2**X
+|	stwotoxd --- 2**X for denormalized X
+|	stentox  --- 10**X
+|	stentoxd --- 10**X for denormalized X
+|
+|	Input: Double-extended number X in location pointed to
+|		by address register a0.
+|
+|	Output: The function values are returned in Fp0.
+|
+|	Accuracy and Monotonicity: The returned result is within 2 ulps in
+|		64 significant bit, i.e. within 0.5001 ulp to 53 bits if the
+|		result is subsequently rounded to double precision. The
+|		result is provably monotonic in double precision.
+|
+|	Speed: The program stwotox takes approximately 190 cycles and the
+|		program stentox takes approximately 200 cycles.
+|
+|	Algorithm:
+|
+|	twotox
+|	1. If |X| > 16480, go to ExpBig.
+|
+|	2. If |X| < 2**(-70), go to ExpSm.
+|
+|	3. Decompose X as X = N/64 + r where |r| <= 1/128. Furthermore
+|		decompose N as
+|		 N = 64(M + M') + j,  j = 0,1,2,...,63.
+|
+|	4. Overwrite r := r * log2. Then
+|		2**X = 2**(M') * 2**(M) * 2**(j/64) * exp(r).
+|		Go to expr to compute that expression.
+|
+|	tentox
+|	1. If |X| > 16480*log_10(2) (base 10 log of 2), go to ExpBig.
+|
+|	2. If |X| < 2**(-70), go to ExpSm.
+|
+|	3. Set y := X*log_2(10)*64 (base 2 log of 10). Set
+|		N := round-to-int(y). Decompose N as
+|		 N = 64(M + M') + j,  j = 0,1,2,...,63.
+|
+|	4. Define r as
+|		r := ((X - N*L1)-N*L2) * L10
+|		where L1, L2 are the leading and trailing parts of log_10(2)/64
+|		and L10 is the natural log of 10. Then
+|		10**X = 2**(M') * 2**(M) * 2**(j/64) * exp(r).
+|		Go to expr to compute that expression.
+|
+|	expr
+|	1. Fetch 2**(j/64) from table as Fact1 and Fact2.
+|
+|	2. Overwrite Fact1 and Fact2 by
+|		Fact1 := 2**(M) * Fact1
+|		Fact2 := 2**(M) * Fact2
+|		Thus Fact1 + Fact2 = 2**(M) * 2**(j/64).
+|
+|	3. Calculate P where 1 + P approximates exp(r):
+|		P = r + r*r*(A1+r*(A2+...+r*A5)).
+|
+|	4. Let AdjFact := 2**(M'). Return
+|		AdjFact * ( Fact1 + ((Fact1*P) + Fact2) ).
+|		Exit.
+|
+|	ExpBig
+|	1. Generate overflow by Huge * Huge if X > 0; otherwise, generate
+|		underflow by Tiny * Tiny.
+|
+|	ExpSm
+|	1. Return 1 + X.
+|
+
+|		Copyright (C) Motorola, Inc. 1990
+|			All Rights Reserved
+|
+|	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA 
+|	The copyright notice above does not evidence any  
+|	actual or intended publication of such source code.
+
+|STWOTOX	idnt	2,1 | Motorola 040 Floating Point Software Package
+
+	|section	8
+
+	.include "fpsp.h"
+
+BOUNDS1:	.long 0x3FB98000,0x400D80C0 | ... 2^(-70),16480
+BOUNDS2:	.long 0x3FB98000,0x400B9B07 | ... 2^(-70),16480 LOG2/LOG10
+
+L2TEN64:	.long 0x406A934F,0x0979A371 | ... 64LOG10/LOG2
+L10TWO1:	.long 0x3F734413,0x509F8000 | ... LOG2/64LOG10
+
+L10TWO2:	.long 0xBFCD0000,0xC0219DC1,0xDA994FD2,0x00000000
+
+LOG10:	.long 0x40000000,0x935D8DDD,0xAAA8AC17,0x00000000
+
+LOG2:	.long 0x3FFE0000,0xB17217F7,0xD1CF79AC,0x00000000
+
+EXPA5:	.long 0x3F56C16D,0x6F7BD0B2
+EXPA4:	.long 0x3F811112,0x302C712C
+EXPA3:	.long 0x3FA55555,0x55554CC1
+EXPA2:	.long 0x3FC55555,0x55554A54
+EXPA1:	.long 0x3FE00000,0x00000000,0x00000000,0x00000000
+
+HUGE:	.long 0x7FFE0000,0xFFFFFFFF,0xFFFFFFFF,0x00000000
+TINY:	.long 0x00010000,0xFFFFFFFF,0xFFFFFFFF,0x00000000
+
+EXPTBL:
+	.long  0x3FFF0000,0x80000000,0x00000000,0x3F738000
+	.long  0x3FFF0000,0x8164D1F3,0xBC030773,0x3FBEF7CA
+	.long  0x3FFF0000,0x82CD8698,0xAC2BA1D7,0x3FBDF8A9
+	.long  0x3FFF0000,0x843A28C3,0xACDE4046,0x3FBCD7C9
+	.long  0x3FFF0000,0x85AAC367,0xCC487B15,0xBFBDE8DA
+	.long  0x3FFF0000,0x871F6196,0x9E8D1010,0x3FBDE85C
+	.long  0x3FFF0000,0x88980E80,0x92DA8527,0x3FBEBBF1
+	.long  0x3FFF0000,0x8A14D575,0x496EFD9A,0x3FBB80CA
+	.long  0x3FFF0000,0x8B95C1E3,0xEA8BD6E7,0xBFBA8373
+	.long  0x3FFF0000,0x8D1ADF5B,0x7E5BA9E6,0xBFBE9670
+	.long  0x3FFF0000,0x8EA4398B,0x45CD53C0,0x3FBDB700
+	.long  0x3FFF0000,0x9031DC43,0x1466B1DC,0x3FBEEEB0
+	.long  0x3FFF0000,0x91C3D373,0xAB11C336,0x3FBBFD6D
+	.long  0x3FFF0000,0x935A2B2F,0x13E6E92C,0xBFBDB319
+	.long  0x3FFF0000,0x94F4EFA8,0xFEF70961,0x3FBDBA2B
+	.long  0x3FFF0000,0x96942D37,0x20185A00,0x3FBE91D5
+	.long  0x3FFF0000,0x9837F051,0x8DB8A96F,0x3FBE8D5A
+	.long  0x3FFF0000,0x99E04593,0x20B7FA65,0xBFBCDE7B
+	.long  0x3FFF0000,0x9B8D39B9,0xD54E5539,0xBFBEBAAF
+	.long  0x3FFF0000,0x9D3ED9A7,0x2CFFB751,0xBFBD86DA
+	.long  0x3FFF0000,0x9EF53260,0x91A111AE,0xBFBEBEDD
+	.long  0x3FFF0000,0xA0B0510F,0xB9714FC2,0x3FBCC96E
+	.long  0x3FFF0000,0xA2704303,0x0C496819,0xBFBEC90B
+	.long  0x3FFF0000,0xA43515AE,0x09E6809E,0x3FBBD1DB
+	.long  0x3FFF0000,0xA5FED6A9,0xB15138EA,0x3FBCE5EB
+	.long  0x3FFF0000,0xA7CD93B4,0xE965356A,0xBFBEC274
+	.long  0x3FFF0000,0xA9A15AB4,0xEA7C0EF8,0x3FBEA83C
+	.long  0x3FFF0000,0xAB7A39B5,0xA93ED337,0x3FBECB00
+	.long  0x3FFF0000,0xAD583EEA,0x42A14AC6,0x3FBE9301
+	.long  0x3FFF0000,0xAF3B78AD,0x690A4375,0xBFBD8367
+	.long  0x3FFF0000,0xB123F581,0xD2AC2590,0xBFBEF05F
+	.long  0x3FFF0000,0xB311C412,0xA9112489,0x3FBDFB3C
+	.long  0x3FFF0000,0xB504F333,0xF9DE6484,0x3FBEB2FB
+	.long  0x3FFF0000,0xB6FD91E3,0x28D17791,0x3FBAE2CB
+	.long  0x3FFF0000,0xB8FBAF47,0x62FB9EE9,0x3FBCDC3C
+	.long  0x3FFF0000,0xBAFF5AB2,0x133E45FB,0x3FBEE9AA
+	.long  0x3FFF0000,0xBD08A39F,0x580C36BF,0xBFBEAEFD
+	.long  0x3FFF0000,0xBF1799B6,0x7A731083,0xBFBCBF51
+	.long  0x3FFF0000,0xC12C4CCA,0x66709456,0x3FBEF88A
+	.long  0x3FFF0000,0xC346CCDA,0x24976407,0x3FBD83B2
+	.long  0x3FFF0000,0xC5672A11,0x5506DADD,0x3FBDF8AB
+	.long  0x3FFF0000,0xC78D74C8,0xABB9B15D,0xBFBDFB17
+	.long  0x3FFF0000,0xC9B9BD86,0x6E2F27A3,0xBFBEFE3C
+	.long  0x3FFF0000,0xCBEC14FE,0xF2727C5D,0xBFBBB6F8
+	.long  0x3FFF0000,0xCE248C15,0x1F8480E4,0xBFBCEE53
+	.long  0x3FFF0000,0xD06333DA,0xEF2B2595,0xBFBDA4AE
+	.long  0x3FFF0000,0xD2A81D91,0xF12AE45A,0x3FBC9124
+	.long  0x3FFF0000,0xD4F35AAB,0xCFEDFA1F,0x3FBEB243
+	.long  0x3FFF0000,0xD744FCCA,0xD69D6AF4,0x3FBDE69A
+	.long  0x3FFF0000,0xD99D15C2,0x78AFD7B6,0xBFB8BC61
+	.long  0x3FFF0000,0xDBFBB797,0xDAF23755,0x3FBDF610
+	.long  0x3FFF0000,0xDE60F482,0x5E0E9124,0xBFBD8BE1
+	.long  0x3FFF0000,0xE0CCDEEC,0x2A94E111,0x3FBACB12
+	.long  0x3FFF0000,0xE33F8972,0xBE8A5A51,0x3FBB9BFE
+	.long  0x3FFF0000,0xE5B906E7,0x7C8348A8,0x3FBCF2F4
+	.long  0x3FFF0000,0xE8396A50,0x3C4BDC68,0x3FBEF22F
+	.long  0x3FFF0000,0xEAC0C6E7,0xDD24392F,0xBFBDBF4A
+	.long  0x3FFF0000,0xED4F301E,0xD9942B84,0x3FBEC01A
+	.long  0x3FFF0000,0xEFE4B99B,0xDCDAF5CB,0x3FBE8CAC
+	.long  0x3FFF0000,0xF281773C,0x59FFB13A,0xBFBCBB3F
+	.long  0x3FFF0000,0xF5257D15,0x2486CC2C,0x3FBEF73A
+	.long  0x3FFF0000,0xF7D0DF73,0x0AD13BB9,0xBFB8B795
+	.long  0x3FFF0000,0xFA83B2DB,0x722A033A,0x3FBEF84B
+	.long  0x3FFF0000,0xFD3E0C0C,0xF486C175,0xBFBEF581
+
+	.set	N,L_SCR1
+
+	.set	X,FP_SCR1
+	.set	XDCARE,X+2
+	.set	XFRAC,X+4
+
+	.set	ADJFACT,FP_SCR2
+
+	.set	FACT1,FP_SCR3
+	.set	FACT1HI,FACT1+4
+	.set	FACT1LOW,FACT1+8
+
+	.set	FACT2,FP_SCR4
+	.set	FACT2HI,FACT2+4
+	.set	FACT2LOW,FACT2+8
+
+	| xref	t_unfl
+	|xref	t_ovfl
+	|xref	t_frcinx
+
+	.global	stwotoxd
+stwotoxd:
+|--ENTRY POINT FOR 2**(X) FOR DENORMALIZED ARGUMENT
+
+	fmovel		%d1,%fpcr		| ...set user's rounding mode/precision
+	fmoves		#0x3F800000,%fp0  | ...RETURN 1 + X
+	movel		(%a0),%d0
+	orl		#0x00800001,%d0
+	fadds		%d0,%fp0
+	bra		t_frcinx
+
+	.global	stwotox
+stwotox:
+|--ENTRY POINT FOR 2**(X), HERE X IS FINITE, NON-ZERO, AND NOT NAN'S
+	fmovemx	(%a0),%fp0-%fp0	| ...LOAD INPUT, do not set cc's
+
+	movel		(%a0),%d0
+	movew		4(%a0),%d0
+	fmovex		%fp0,X(%a6)
+	andil		#0x7FFFFFFF,%d0
+
+	cmpil		#0x3FB98000,%d0		| ...|X| >= 2**(-70)?
+	bges		TWOOK1
+	bra		EXPBORS
+
+TWOOK1:
+	cmpil		#0x400D80C0,%d0		| ...|X| > 16480?
+	bles		TWOMAIN
+	bra		EXPBORS
+	
+
+TWOMAIN:
+|--USUAL CASE, 2^(-70) <= |X| <= 16480
+
+	fmovex		%fp0,%fp1
+	fmuls		#0x42800000,%fp1  | ...64 * X
+	
+	fmovel		%fp1,N(%a6)		| ...N = ROUND-TO-INT(64 X)
+	movel		%d2,-(%sp)
+	lea		EXPTBL,%a1 	| ...LOAD ADDRESS OF TABLE OF 2^(J/64)
+	fmovel		N(%a6),%fp1		| ...N --> FLOATING FMT
+	movel		N(%a6),%d0
+	movel		%d0,%d2
+	andil		#0x3F,%d0		| ...D0 IS J
+	asll		#4,%d0		| ...DISPLACEMENT FOR 2^(J/64)
+	addal		%d0,%a1		| ...ADDRESS FOR 2^(J/64)
+	asrl		#6,%d2		| ...d2 IS L, N = 64L + J
+	movel		%d2,%d0
+	asrl		#1,%d0		| ...D0 IS M
+	subl		%d0,%d2		| ...d2 IS M', N = 64(M+M') + J
+	addil		#0x3FFF,%d2
+	movew		%d2,ADJFACT(%a6) 	| ...ADJFACT IS 2^(M')
+	movel		(%sp)+,%d2
+|--SUMMARY: a1 IS ADDRESS FOR THE LEADING PORTION OF 2^(J/64),
+|--D0 IS M WHERE N = 64(M+M') + J. NOTE THAT |M| <= 16140 BY DESIGN.
+|--ADJFACT = 2^(M').
+|--REGISTERS SAVED SO FAR ARE (IN ORDER) FPCR, D0, FP1, a1, AND FP2.
+
+	fmuls		#0x3C800000,%fp1  | ...(1/64)*N
+	movel		(%a1)+,FACT1(%a6)
+	movel		(%a1)+,FACT1HI(%a6)
+	movel		(%a1)+,FACT1LOW(%a6)
+	movew		(%a1)+,FACT2(%a6)
+	clrw		FACT2+2(%a6)
+
+	fsubx		%fp1,%fp0	 	| ...X - (1/64)*INT(64 X)
+
+	movew		(%a1)+,FACT2HI(%a6)
+	clrw		FACT2HI+2(%a6)
+	clrl		FACT2LOW(%a6)
+	addw		%d0,FACT1(%a6)
+	
+	fmulx		LOG2,%fp0	| ...FP0 IS R
+	addw		%d0,FACT2(%a6)
+
+	bra		expr
+
+EXPBORS:
+|--FPCR, D0 SAVED
+	cmpil		#0x3FFF8000,%d0
+	bgts		EXPBIG
+
+EXPSM:
+|--|X| IS SMALL, RETURN 1 + X
+
+	fmovel		%d1,%FPCR		|restore users exceptions
+	fadds		#0x3F800000,%fp0  | ...RETURN 1 + X
+
+	bra		t_frcinx
+
+EXPBIG:
+|--|X| IS LARGE, GENERATE OVERFLOW IF X > 0; ELSE GENERATE UNDERFLOW
+|--REGISTERS SAVE SO FAR ARE FPCR AND  D0
+	movel		X(%a6),%d0
+	cmpil		#0,%d0
+	blts		EXPNEG
+
+	bclrb		#7,(%a0)		|t_ovfl expects positive value
+	bra		t_ovfl
+
+EXPNEG:
+	bclrb		#7,(%a0)		|t_unfl expects positive value
+	bra		t_unfl
+
+	.global	stentoxd
+stentoxd:
+|--ENTRY POINT FOR 10**(X) FOR DENORMALIZED ARGUMENT
+
+	fmovel		%d1,%fpcr		| ...set user's rounding mode/precision
+	fmoves		#0x3F800000,%fp0  | ...RETURN 1 + X
+	movel		(%a0),%d0
+	orl		#0x00800001,%d0
+	fadds		%d0,%fp0
+	bra		t_frcinx
+
+	.global	stentox
+stentox:
+|--ENTRY POINT FOR 10**(X), HERE X IS FINITE, NON-ZERO, AND NOT NAN'S
+	fmovemx	(%a0),%fp0-%fp0	| ...LOAD INPUT, do not set cc's
+
+	movel		(%a0),%d0
+	movew		4(%a0),%d0
+	fmovex		%fp0,X(%a6)
+	andil		#0x7FFFFFFF,%d0
+
+	cmpil		#0x3FB98000,%d0		| ...|X| >= 2**(-70)?
+	bges		TENOK1
+	bra		EXPBORS
+
+TENOK1:
+	cmpil		#0x400B9B07,%d0		| ...|X| <= 16480*log2/log10 ?
+	bles		TENMAIN
+	bra		EXPBORS
+
+TENMAIN:
+|--USUAL CASE, 2^(-70) <= |X| <= 16480 LOG 2 / LOG 10
+
+	fmovex		%fp0,%fp1
+	fmuld		L2TEN64,%fp1	| ...X*64*LOG10/LOG2
+	
+	fmovel		%fp1,N(%a6)		| ...N=INT(X*64*LOG10/LOG2)
+	movel		%d2,-(%sp)
+	lea		EXPTBL,%a1 	| ...LOAD ADDRESS OF TABLE OF 2^(J/64)
+	fmovel		N(%a6),%fp1		| ...N --> FLOATING FMT
+	movel		N(%a6),%d0
+	movel		%d0,%d2
+	andil		#0x3F,%d0		| ...D0 IS J
+	asll		#4,%d0		| ...DISPLACEMENT FOR 2^(J/64)
+	addal		%d0,%a1		| ...ADDRESS FOR 2^(J/64)
+	asrl		#6,%d2		| ...d2 IS L, N = 64L + J
+	movel		%d2,%d0
+	asrl		#1,%d0		| ...D0 IS M
+	subl		%d0,%d2		| ...d2 IS M', N = 64(M+M') + J
+	addil		#0x3FFF,%d2
+	movew		%d2,ADJFACT(%a6) 	| ...ADJFACT IS 2^(M')
+	movel		(%sp)+,%d2
+
+|--SUMMARY: a1 IS ADDRESS FOR THE LEADING PORTION OF 2^(J/64),
+|--D0 IS M WHERE N = 64(M+M') + J. NOTE THAT |M| <= 16140 BY DESIGN.
+|--ADJFACT = 2^(M').
+|--REGISTERS SAVED SO FAR ARE (IN ORDER) FPCR, D0, FP1, a1, AND FP2.
+
+	fmovex		%fp1,%fp2
+
+	fmuld		L10TWO1,%fp1	| ...N*(LOG2/64LOG10)_LEAD
+	movel		(%a1)+,FACT1(%a6)
+
+	fmulx		L10TWO2,%fp2	| ...N*(LOG2/64LOG10)_TRAIL
+
+	movel		(%a1)+,FACT1HI(%a6)
+	movel		(%a1)+,FACT1LOW(%a6)
+	fsubx		%fp1,%fp0		| ...X - N L_LEAD
+	movew		(%a1)+,FACT2(%a6)
+
+	fsubx		%fp2,%fp0		| ...X - N L_TRAIL
+
+	clrw		FACT2+2(%a6)
+	movew		(%a1)+,FACT2HI(%a6)
+	clrw		FACT2HI+2(%a6)
+	clrl		FACT2LOW(%a6)
+
+	fmulx		LOG10,%fp0	| ...FP0 IS R
+	
+	addw		%d0,FACT1(%a6)
+	addw		%d0,FACT2(%a6)
+
+expr:
+|--FPCR, FP2, FP3 ARE SAVED IN ORDER AS SHOWN.
+|--ADJFACT CONTAINS 2**(M'), FACT1 + FACT2 = 2**(M) * 2**(J/64).
+|--FP0 IS R. THE FOLLOWING CODE COMPUTES
+|--	2**(M'+M) * 2**(J/64) * EXP(R)
+
+	fmovex		%fp0,%fp1
+	fmulx		%fp1,%fp1		| ...FP1 IS S = R*R
+
+	fmoved		EXPA5,%fp2	| ...FP2 IS A5
+	fmoved		EXPA4,%fp3	| ...FP3 IS A4
+
+	fmulx		%fp1,%fp2		| ...FP2 IS S*A5
+	fmulx		%fp1,%fp3		| ...FP3 IS S*A4
+
+	faddd		EXPA3,%fp2	| ...FP2 IS A3+S*A5
+	faddd		EXPA2,%fp3	| ...FP3 IS A2+S*A4
+
+	fmulx		%fp1,%fp2		| ...FP2 IS S*(A3+S*A5)
+	fmulx		%fp1,%fp3		| ...FP3 IS S*(A2+S*A4)
+
+	faddd		EXPA1,%fp2	| ...FP2 IS A1+S*(A3+S*A5)
+	fmulx		%fp0,%fp3		| ...FP3 IS R*S*(A2+S*A4)
+
+	fmulx		%fp1,%fp2		| ...FP2 IS S*(A1+S*(A3+S*A5))
+	faddx		%fp3,%fp0		| ...FP0 IS R+R*S*(A2+S*A4)
+	
+	faddx		%fp2,%fp0		| ...FP0 IS EXP(R) - 1
+	
+
+|--FINAL RECONSTRUCTION PROCESS
+|--EXP(X) = 2^M*2^(J/64) + 2^M*2^(J/64)*(EXP(R)-1)  -  (1 OR 0)
+
+	fmulx		FACT1(%a6),%fp0
+	faddx		FACT2(%a6),%fp0
+	faddx		FACT1(%a6),%fp0
+
+	fmovel		%d1,%FPCR		|restore users exceptions
+	clrw		ADJFACT+2(%a6)
+	movel		#0x80000000,ADJFACT+4(%a6)
+	clrl		ADJFACT+8(%a6)
+	fmulx		ADJFACT(%a6),%fp0	| ...FINAL ADJUSTMENT
+
+	bra		t_frcinx
+
+	|end
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/fpsp040/tbldo.S linux/arch/m68k/fpsp040/tbldo.S
--- v1.3.93/linux/arch/m68k/fpsp040/tbldo.S	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/fpsp040/tbldo.S	Sat Feb 24 22:58:44 1996
@@ -0,0 +1,554 @@
+|
+|	tbldo.sa 3.1 12/10/90
+|
+| Modified:
+|	8/16/90	chinds	The table was constructed to use only one level
+|			of indirection in do_func for monoadic
+|			functions.  Dyadic functions require two
+|			levels, and the tables are still contained
+|			in do_func.  The table is arranged for 
+|			index with a 10-bit index, with the first
+|			7 bits the opcode, and the remaining 3
+|			the stag.  For dyadic functions, all
+|			valid addresses are to the generic entry
+|			point. 
+|
+
+|		Copyright (C) Motorola, Inc. 1990
+|			All Rights Reserved
+|
+|	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA 
+|	The copyright notice above does not evidence any  
+|	actual or intended publication of such source code.
+
+|TBLDO	idnt    2,1 | Motorola 040 Floating Point Software Package
+
+	|section	8
+
+	|xref	ld_pinf,ld_pone,ld_ppi2
+	|xref	t_dz2,t_operr
+	|xref	serror,sone,szero,sinf,snzrinx
+	|xref	sopr_inf,spi_2,src_nan,szr_inf
+
+	|xref	smovcr
+	|xref	pmod,prem,pscale
+	|xref	satanh,satanhd
+	|xref	sacos,sacosd,sasin,sasind,satan,satand
+	|xref	setox,setoxd,setoxm1,setoxm1d,setoxm1i
+	|xref	sgetexp,sgetexpd,sgetman,sgetmand
+	|xref	sint,sintd,sintrz
+	|xref	ssincos,ssincosd,ssincosi,ssincosnan,ssincosz
+	|xref	scos,scosd,ssin,ssind,stan,stand
+	|xref	scosh,scoshd,ssinh,ssinhd,stanh,stanhd
+	|xref	sslog10,sslog2,sslogn,sslognp1
+	|xref	sslog10d,sslog2d,sslognd,slognp1d
+	|xref	stentox,stentoxd,stwotox,stwotoxd
+
+|	instruction		;opcode-stag Notes
+	.global	tblpre
+tblpre:
+	.long	smovcr		|$00-0 fmovecr all
+	.long	smovcr		|$00-1 fmovecr all
+	.long	smovcr		|$00-2 fmovecr all
+	.long	smovcr		|$00-3 fmovecr all
+	.long	smovcr		|$00-4 fmovecr all
+	.long	smovcr		|$00-5 fmovecr all
+	.long	smovcr		|$00-6 fmovecr all
+	.long	smovcr		|$00-7 fmovecr all
+
+	.long	sint		|$01-0 fint norm
+	.long	szero		|$01-1 fint zero 
+	.long	sinf		|$01-2 fint inf
+	.long	src_nan		|$01-3 fint nan
+	.long	sintd		|$01-4 fint denorm inx
+	.long	serror		|$01-5 fint ERROR
+	.long	serror		|$01-6 fint ERROR
+	.long	serror		|$01-7 fint ERROR
+
+	.long	ssinh		|$02-0 fsinh norm
+	.long	szero		|$02-1 fsinh zero
+	.long	sinf		|$02-2 fsinh inf
+	.long	src_nan		|$02-3 fsinh nan
+	.long	ssinhd		|$02-4 fsinh denorm
+	.long	serror		|$02-5 fsinh ERROR
+	.long	serror		|$02-6 fsinh ERROR
+	.long	serror		|$02-7 fsinh ERROR
+
+	.long	sintrz		|$03-0 fintrz norm
+	.long	szero		|$03-1 fintrz zero
+	.long	sinf		|$03-2 fintrz inf
+	.long	src_nan		|$03-3 fintrz nan
+	.long	snzrinx		|$03-4 fintrz denorm inx
+	.long	serror		|$03-5 fintrz ERROR
+	.long	serror		|$03-6 fintrz ERROR
+	.long	serror		|$03-7 fintrz ERROR
+
+	.long	serror		|$04-0 ERROR - illegal extension
+	.long	serror		|$04-1 ERROR - illegal extension
+	.long	serror		|$04-2 ERROR - illegal extension
+	.long	serror		|$04-3 ERROR - illegal extension
+	.long	serror		|$04-4 ERROR - illegal extension
+	.long	serror		|$04-5 ERROR - illegal extension
+	.long	serror		|$04-6 ERROR - illegal extension
+	.long	serror		|$04-7 ERROR - illegal extension
+
+	.long	serror		|$05-0 ERROR - illegal extension
+	.long	serror		|$05-1 ERROR - illegal extension
+	.long	serror		|$05-2 ERROR - illegal extension
+	.long	serror		|$05-3 ERROR - illegal extension
+	.long	serror		|$05-4 ERROR - illegal extension
+	.long	serror		|$05-5 ERROR - illegal extension
+	.long	serror		|$05-6 ERROR - illegal extension
+	.long	serror		|$05-7 ERROR - illegal extension
+
+	.long	sslognp1	|$06-0 flognp1 norm
+	.long	szero		|$06-1 flognp1 zero
+	.long	sopr_inf	|$06-2 flognp1 inf
+	.long	src_nan		|$06-3 flognp1 nan
+	.long	slognp1d	|$06-4 flognp1 denorm
+	.long	serror		|$06-5 flognp1 ERROR
+	.long	serror		|$06-6 flognp1 ERROR
+	.long	serror		|$06-7 flognp1 ERROR
+
+	.long	serror		|$07-0 ERROR - illegal extension
+	.long	serror		|$07-1 ERROR - illegal extension
+	.long	serror		|$07-2 ERROR - illegal extension
+	.long	serror		|$07-3 ERROR - illegal extension
+	.long	serror		|$07-4 ERROR - illegal extension
+	.long	serror		|$07-5 ERROR - illegal extension
+	.long	serror		|$07-6 ERROR - illegal extension
+	.long	serror		|$07-7 ERROR - illegal extension
+
+	.long	setoxm1		|$08-0 fetoxm1 norm
+	.long	szero		|$08-1 fetoxm1 zero
+	.long	setoxm1i	|$08-2 fetoxm1 inf
+	.long	src_nan		|$08-3 fetoxm1 nan
+	.long	setoxm1d	|$08-4 fetoxm1 denorm
+	.long	serror		|$08-5 fetoxm1 ERROR
+	.long	serror		|$08-6 fetoxm1 ERROR
+	.long	serror		|$08-7 fetoxm1 ERROR
+
+	.long	stanh		|$09-0 ftanh norm
+	.long	szero		|$09-1 ftanh zero
+	.long	sone		|$09-2 ftanh inf
+	.long	src_nan		|$09-3 ftanh nan
+	.long	stanhd		|$09-4 ftanh denorm
+	.long	serror		|$09-5 ftanh ERROR
+	.long	serror		|$09-6 ftanh ERROR
+	.long	serror		|$09-7 ftanh ERROR
+
+	.long	satan		|$0a-0 fatan norm
+	.long	szero		|$0a-1 fatan zero
+	.long	spi_2		|$0a-2 fatan inf
+	.long	src_nan		|$0a-3 fatan nan
+	.long	satand		|$0a-4 fatan denorm
+	.long	serror		|$0a-5 fatan ERROR
+	.long	serror		|$0a-6 fatan ERROR
+	.long	serror		|$0a-7 fatan ERROR
+
+	.long	serror		|$0b-0 ERROR - illegal extension
+	.long	serror		|$0b-1 ERROR - illegal extension
+	.long	serror		|$0b-2 ERROR - illegal extension
+	.long	serror		|$0b-3 ERROR - illegal extension
+	.long	serror		|$0b-4 ERROR - illegal extension
+	.long	serror		|$0b-5 ERROR - illegal extension
+	.long	serror		|$0b-6 ERROR - illegal extension
+	.long	serror		|$0b-7 ERROR - illegal extension
+
+	.long	sasin		|$0c-0 fasin norm
+	.long	szero		|$0c-1 fasin zero
+	.long	t_operr		|$0c-2 fasin inf
+	.long	src_nan		|$0c-3 fasin nan
+	.long	sasind		|$0c-4 fasin denorm
+	.long	serror		|$0c-5 fasin ERROR
+	.long	serror		|$0c-6 fasin ERROR
+	.long	serror		|$0c-7 fasin ERROR
+
+	.long	satanh		|$0d-0 fatanh norm
+	.long	szero		|$0d-1 fatanh zero
+	.long	t_operr		|$0d-2 fatanh inf
+	.long	src_nan		|$0d-3 fatanh nan
+	.long	satanhd		|$0d-4 fatanh denorm
+	.long	serror		|$0d-5 fatanh ERROR
+	.long	serror		|$0d-6 fatanh ERROR
+	.long	serror		|$0d-7 fatanh ERROR
+
+	.long	ssin		|$0e-0 fsin norm
+	.long	szero		|$0e-1 fsin zero
+	.long	t_operr		|$0e-2 fsin inf
+	.long	src_nan		|$0e-3 fsin nan
+	.long	ssind		|$0e-4 fsin denorm
+	.long	serror		|$0e-5 fsin ERROR
+	.long	serror		|$0e-6 fsin ERROR
+	.long	serror		|$0e-7 fsin ERROR
+
+	.long	stan		|$0f-0 ftan norm
+	.long	szero		|$0f-1 ftan zero
+	.long	t_operr		|$0f-2 ftan inf
+	.long	src_nan		|$0f-3 ftan nan
+	.long	stand		|$0f-4 ftan denorm
+	.long	serror		|$0f-5 ftan ERROR
+	.long	serror		|$0f-6 ftan ERROR
+	.long	serror		|$0f-7 ftan ERROR
+
+	.long	setox		|$10-0 fetox norm
+	.long	ld_pone		|$10-1 fetox zero
+	.long	szr_inf		|$10-2 fetox inf
+	.long	src_nan		|$10-3 fetox nan
+	.long	setoxd		|$10-4 fetox denorm
+	.long	serror		|$10-5 fetox ERROR
+	.long	serror		|$10-6 fetox ERROR
+	.long	serror		|$10-7 fetox ERROR
+
+	.long	stwotox		|$11-0 ftwotox norm
+	.long	ld_pone		|$11-1 ftwotox zero
+	.long	szr_inf		|$11-2 ftwotox inf
+	.long	src_nan		|$11-3 ftwotox nan
+	.long	stwotoxd	|$11-4 ftwotox denorm
+	.long	serror		|$11-5 ftwotox ERROR
+	.long	serror		|$11-6 ftwotox ERROR
+	.long	serror		|$11-7 ftwotox ERROR
+
+	.long	stentox		|$12-0 ftentox norm
+	.long	ld_pone		|$12-1 ftentox zero
+	.long	szr_inf		|$12-2 ftentox inf
+	.long	src_nan		|$12-3 ftentox nan
+	.long	stentoxd	|$12-4 ftentox denorm
+	.long	serror		|$12-5 ftentox ERROR
+	.long	serror		|$12-6 ftentox ERROR
+	.long	serror		|$12-7 ftentox ERROR
+
+	.long	serror		|$13-0 ERROR - illegal extension
+	.long	serror		|$13-1 ERROR - illegal extension
+	.long	serror		|$13-2 ERROR - illegal extension
+	.long	serror		|$13-3 ERROR - illegal extension
+	.long	serror		|$13-4 ERROR - illegal extension
+	.long	serror		|$13-5 ERROR - illegal extension
+	.long	serror		|$13-6 ERROR - illegal extension
+	.long	serror		|$13-7 ERROR - illegal extension
+
+	.long	sslogn		|$14-0 flogn norm
+	.long	t_dz2		|$14-1 flogn zero
+	.long	sopr_inf	|$14-2 flogn inf
+	.long	src_nan		|$14-3 flogn nan
+	.long	sslognd		|$14-4 flogn denorm
+	.long	serror		|$14-5 flogn ERROR
+	.long	serror		|$14-6 flogn ERROR
+	.long	serror		|$14-7 flogn ERROR
+
+	.long	sslog10		|$15-0 flog10 norm
+	.long	t_dz2		|$15-1 flog10 zero
+	.long	sopr_inf	|$15-2 flog10 inf
+	.long	src_nan		|$15-3 flog10 nan
+	.long	sslog10d	|$15-4 flog10 denorm
+	.long	serror		|$15-5 flog10 ERROR
+	.long	serror		|$15-6 flog10 ERROR
+	.long	serror		|$15-7 flog10 ERROR
+
+	.long	sslog2		|$16-0 flog2 norm
+	.long	t_dz2		|$16-1 flog2 zero
+	.long	sopr_inf	|$16-2 flog2 inf
+	.long	src_nan		|$16-3 flog2 nan
+	.long	sslog2d		|$16-4 flog2 denorm
+	.long	serror		|$16-5 flog2 ERROR
+	.long	serror		|$16-6 flog2 ERROR
+	.long	serror		|$16-7 flog2 ERROR
+
+	.long	serror		|$17-0 ERROR - illegal extension
+	.long	serror		|$17-1 ERROR - illegal extension
+	.long	serror		|$17-2 ERROR - illegal extension
+	.long	serror		|$17-3 ERROR - illegal extension
+	.long	serror		|$17-4 ERROR - illegal extension
+	.long	serror		|$17-5 ERROR - illegal extension
+	.long	serror		|$17-6 ERROR - illegal extension
+	.long	serror		|$17-7 ERROR - illegal extension
+
+	.long	serror		|$18-0 ERROR - illegal extension
+	.long	serror		|$18-1 ERROR - illegal extension
+	.long	serror		|$18-2 ERROR - illegal extension
+	.long	serror		|$18-3 ERROR - illegal extension
+	.long	serror		|$18-4 ERROR - illegal extension
+	.long	serror		|$18-5 ERROR - illegal extension
+	.long	serror		|$18-6 ERROR - illegal extension
+	.long	serror		|$18-7 ERROR - illegal extension
+
+	.long	scosh		|$19-0 fcosh norm
+	.long	ld_pone		|$19-1 fcosh zero
+	.long	ld_pinf		|$19-2 fcosh inf
+	.long	src_nan		|$19-3 fcosh nan
+	.long	scoshd		|$19-4 fcosh denorm
+	.long	serror		|$19-5 fcosh ERROR
+	.long	serror		|$19-6 fcosh ERROR
+	.long	serror		|$19-7 fcosh ERROR
+
+	.long	serror		|$1a-0 ERROR - illegal extension
+	.long	serror		|$1a-1 ERROR - illegal extension
+	.long	serror		|$1a-2 ERROR - illegal extension
+	.long	serror		|$1a-3 ERROR - illegal extension
+	.long	serror		|$1a-4 ERROR - illegal extension
+	.long	serror		|$1a-5 ERROR - illegal extension
+	.long	serror		|$1a-6 ERROR - illegal extension
+	.long	serror		|$1a-7 ERROR - illegal extension
+
+	.long	serror		|$1b-0 ERROR - illegal extension
+	.long	serror		|$1b-1 ERROR - illegal extension
+	.long	serror		|$1b-2 ERROR - illegal extension
+	.long	serror		|$1b-3 ERROR - illegal extension
+	.long	serror		|$1b-4 ERROR - illegal extension
+	.long	serror		|$1b-5 ERROR - illegal extension
+	.long	serror		|$1b-6 ERROR - illegal extension
+	.long	serror		|$1b-7 ERROR - illegal extension
+
+	.long	sacos		|$1c-0 facos norm
+	.long	ld_ppi2		|$1c-1 facos zero
+	.long	t_operr		|$1c-2 facos inf
+	.long	src_nan		|$1c-3 facos nan
+	.long	sacosd		|$1c-4 facos denorm
+	.long	serror		|$1c-5 facos ERROR
+	.long	serror		|$1c-6 facos ERROR
+	.long	serror		|$1c-7 facos ERROR
+
+	.long	scos		|$1d-0 fcos norm
+	.long	ld_pone		|$1d-1 fcos zero
+	.long	t_operr		|$1d-2 fcos inf
+	.long	src_nan		|$1d-3 fcos nan
+	.long	scosd		|$1d-4 fcos denorm
+	.long	serror		|$1d-5 fcos ERROR
+	.long	serror		|$1d-6 fcos ERROR
+	.long	serror		|$1d-7 fcos ERROR
+
+	.long	sgetexp		|$1e-0 fgetexp norm
+	.long	szero		|$1e-1 fgetexp zero
+	.long	t_operr		|$1e-2 fgetexp inf
+	.long	src_nan		|$1e-3 fgetexp nan
+	.long	sgetexpd	|$1e-4 fgetexp denorm
+	.long	serror		|$1e-5 fgetexp ERROR
+	.long	serror		|$1e-6 fgetexp ERROR
+	.long	serror		|$1e-7 fgetexp ERROR
+
+	.long	sgetman		|$1f-0 fgetman norm
+	.long	szero		|$1f-1 fgetman zero
+	.long	t_operr		|$1f-2 fgetman inf
+	.long	src_nan		|$1f-3 fgetman nan
+	.long	sgetmand	|$1f-4 fgetman denorm
+	.long	serror		|$1f-5 fgetman ERROR
+	.long	serror		|$1f-6 fgetman ERROR
+	.long	serror		|$1f-7 fgetman ERROR
+
+	.long	serror		|$20-0 ERROR - illegal extension
+	.long	serror		|$20-1 ERROR - illegal extension
+	.long	serror		|$20-2 ERROR - illegal extension
+	.long	serror		|$20-3 ERROR - illegal extension
+	.long	serror		|$20-4 ERROR - illegal extension
+	.long	serror		|$20-5 ERROR - illegal extension
+	.long	serror		|$20-6 ERROR - illegal extension
+	.long	serror		|$20-7 ERROR - illegal extension
+
+	.long	pmod		|$21-0 fmod all
+	.long	pmod		|$21-1 fmod all
+	.long	pmod		|$21-2 fmod all
+	.long	pmod		|$21-3 fmod all
+	.long	pmod		|$21-4 fmod all
+	.long	serror		|$21-5 fmod ERROR
+	.long	serror		|$21-6 fmod ERROR
+	.long	serror		|$21-7 fmod ERROR
+
+	.long	serror		|$22-0 ERROR - illegal extension
+	.long	serror		|$22-1 ERROR - illegal extension
+	.long	serror		|$22-2 ERROR - illegal extension
+	.long	serror		|$22-3 ERROR - illegal extension
+	.long	serror		|$22-4 ERROR - illegal extension
+	.long	serror		|$22-5 ERROR - illegal extension
+	.long	serror		|$22-6 ERROR - illegal extension
+	.long	serror		|$22-7 ERROR - illegal extension
+
+	.long	serror		|$23-0 ERROR - illegal extension
+	.long	serror		|$23-1 ERROR - illegal extension
+	.long	serror		|$23-2 ERROR - illegal extension
+	.long	serror		|$23-3 ERROR - illegal extension
+	.long	serror		|$23-4 ERROR - illegal extension
+	.long	serror		|$23-5 ERROR - illegal extension
+	.long	serror		|$23-6 ERROR - illegal extension
+	.long	serror		|$23-7 ERROR - illegal extension
+
+	.long	serror		|$24-0 ERROR - illegal extension
+	.long	serror		|$24-1 ERROR - illegal extension
+	.long	serror		|$24-2 ERROR - illegal extension
+	.long	serror		|$24-3 ERROR - illegal extension
+	.long	serror		|$24-4 ERROR - illegal extension
+	.long	serror		|$24-5 ERROR - illegal extension
+	.long	serror		|$24-6 ERROR - illegal extension
+	.long	serror		|$24-7 ERROR - illegal extension
+
+	.long	prem		|$25-0 frem all
+	.long	prem		|$25-1 frem all
+	.long	prem		|$25-2 frem all
+	.long	prem		|$25-3 frem all
+	.long	prem		|$25-4 frem all
+	.long	serror		|$25-5 frem ERROR
+	.long	serror		|$25-6 frem ERROR
+	.long	serror		|$25-7 frem ERROR
+
+	.long	pscale		|$26-0 fscale all
+	.long	pscale		|$26-1 fscale all
+	.long	pscale		|$26-2 fscale all
+	.long	pscale		|$26-3 fscale all
+	.long	pscale		|$26-4 fscale all
+	.long	serror		|$26-5 fscale ERROR
+	.long	serror		|$26-6 fscale ERROR
+	.long	serror		|$26-7 fscale ERROR
+
+	.long	serror		|$27-0 ERROR - illegal extension
+	.long	serror		|$27-1 ERROR - illegal extension
+	.long	serror		|$27-2 ERROR - illegal extension
+	.long	serror		|$27-3 ERROR - illegal extension
+	.long	serror		|$27-4 ERROR - illegal extension
+	.long	serror		|$27-5 ERROR - illegal extension
+	.long	serror		|$27-6 ERROR - illegal extension
+	.long	serror		|$27-7 ERROR - illegal extension
+
+	.long	serror		|$28-0 ERROR - illegal extension
+	.long	serror		|$28-1 ERROR - illegal extension
+	.long	serror		|$28-2 ERROR - illegal extension
+	.long	serror		|$28-3 ERROR - illegal extension
+	.long	serror		|$28-4 ERROR - illegal extension
+	.long	serror		|$28-5 ERROR - illegal extension
+	.long	serror		|$28-6 ERROR - illegal extension
+	.long	serror		|$28-7 ERROR - illegal extension
+
+	.long	serror		|$29-0 ERROR - illegal extension
+	.long	serror		|$29-1 ERROR - illegal extension
+	.long	serror		|$29-2 ERROR - illegal extension
+	.long	serror		|$29-3 ERROR - illegal extension
+	.long	serror		|$29-4 ERROR - illegal extension
+	.long	serror		|$29-5 ERROR - illegal extension
+	.long	serror		|$29-6 ERROR - illegal extension
+	.long	serror		|$29-7 ERROR - illegal extension
+
+	.long	serror		|$2a-0 ERROR - illegal extension
+	.long	serror		|$2a-1 ERROR - illegal extension
+	.long	serror		|$2a-2 ERROR - illegal extension
+	.long	serror		|$2a-3 ERROR - illegal extension
+	.long	serror		|$2a-4 ERROR - illegal extension
+	.long	serror		|$2a-5 ERROR - illegal extension
+	.long	serror		|$2a-6 ERROR - illegal extension
+	.long	serror		|$2a-7 ERROR - illegal extension
+
+	.long	serror		|$2b-0 ERROR - illegal extension
+	.long	serror		|$2b-1 ERROR - illegal extension
+	.long	serror		|$2b-2 ERROR - illegal extension
+	.long	serror		|$2b-3 ERROR - illegal extension
+	.long	serror		|$2b-4 ERROR - illegal extension
+	.long	serror		|$2b-5 ERROR - illegal extension
+	.long	serror		|$2b-6 ERROR - illegal extension
+	.long	serror		|$2b-7 ERROR - illegal extension
+
+	.long	serror		|$2c-0 ERROR - illegal extension
+	.long	serror		|$2c-1 ERROR - illegal extension
+	.long	serror		|$2c-2 ERROR - illegal extension
+	.long	serror		|$2c-3 ERROR - illegal extension
+	.long	serror		|$2c-4 ERROR - illegal extension
+	.long	serror		|$2c-5 ERROR - illegal extension
+	.long	serror		|$2c-6 ERROR - illegal extension
+	.long	serror		|$2c-7 ERROR - illegal extension
+
+	.long	serror		|$2d-0 ERROR - illegal extension
+	.long	serror		|$2d-1 ERROR - illegal extension
+	.long	serror		|$2d-2 ERROR - illegal extension
+	.long	serror		|$2d-3 ERROR - illegal extension
+	.long	serror		|$2d-4 ERROR - illegal extension
+	.long	serror		|$2d-5 ERROR - illegal extension
+	.long	serror		|$2d-6 ERROR - illegal extension
+	.long	serror		|$2d-7 ERROR - illegal extension
+
+	.long	serror		|$2e-0 ERROR - illegal extension
+	.long	serror		|$2e-1 ERROR - illegal extension
+	.long	serror		|$2e-2 ERROR - illegal extension
+	.long	serror		|$2e-3 ERROR - illegal extension
+	.long	serror		|$2e-4 ERROR - illegal extension
+	.long	serror		|$2e-5 ERROR - illegal extension
+	.long	serror		|$2e-6 ERROR - illegal extension
+	.long	serror		|$2e-7 ERROR - illegal extension
+
+	.long	serror		|$2f-0 ERROR - illegal extension
+	.long	serror		|$2f-1 ERROR - illegal extension
+	.long	serror		|$2f-2 ERROR - illegal extension
+	.long	serror		|$2f-3 ERROR - illegal extension
+	.long	serror		|$2f-4 ERROR - illegal extension
+	.long	serror		|$2f-5 ERROR - illegal extension
+	.long	serror		|$2f-6 ERROR - illegal extension
+	.long	serror		|$2f-7 ERROR - illegal extension
+
+	.long	ssincos		|$30-0 fsincos norm
+	.long	ssincosz	|$30-1 fsincos zero
+	.long	ssincosi	|$30-2 fsincos inf
+	.long	ssincosnan	|$30-3 fsincos nan
+	.long	ssincosd	|$30-4 fsincos denorm
+	.long	serror		|$30-5 fsincos ERROR
+	.long	serror		|$30-6 fsincos ERROR
+	.long	serror		|$30-7 fsincos ERROR
+
+	.long	ssincos		|$31-0 fsincos norm
+	.long	ssincosz	|$31-1 fsincos zero
+	.long	ssincosi	|$31-2 fsincos inf
+	.long	ssincosnan	|$31-3 fsincos nan
+	.long	ssincosd	|$31-4 fsincos denorm
+	.long	serror		|$31-5 fsincos ERROR
+	.long	serror		|$31-6 fsincos ERROR
+	.long	serror		|$31-7 fsincos ERROR
+
+	.long	ssincos		|$32-0 fsincos norm
+	.long	ssincosz	|$32-1 fsincos zero
+	.long	ssincosi	|$32-2 fsincos inf
+	.long	ssincosnan	|$32-3 fsincos nan
+	.long	ssincosd	|$32-4 fsincos denorm
+	.long	serror		|$32-5 fsincos ERROR
+	.long	serror		|$32-6 fsincos ERROR
+	.long	serror		|$32-7 fsincos ERROR
+
+	.long	ssincos		|$33-0 fsincos norm
+	.long	ssincosz	|$33-1 fsincos zero
+	.long	ssincosi	|$33-2 fsincos inf
+	.long	ssincosnan	|$33-3 fsincos nan
+	.long	ssincosd	|$33-4 fsincos denorm
+	.long	serror		|$33-5 fsincos ERROR
+	.long	serror		|$33-6 fsincos ERROR
+	.long	serror		|$33-7 fsincos ERROR
+
+	.long	ssincos		|$34-0 fsincos norm
+	.long	ssincosz	|$34-1 fsincos zero
+	.long	ssincosi	|$34-2 fsincos inf
+	.long	ssincosnan	|$34-3 fsincos nan
+	.long	ssincosd	|$34-4 fsincos denorm
+	.long	serror		|$34-5 fsincos ERROR
+	.long	serror		|$34-6 fsincos ERROR
+	.long	serror		|$34-7 fsincos ERROR
+
+	.long	ssincos		|$35-0 fsincos norm
+	.long	ssincosz	|$35-1 fsincos zero
+	.long	ssincosi	|$35-2 fsincos inf
+	.long	ssincosnan	|$35-3 fsincos nan
+	.long	ssincosd	|$35-4 fsincos denorm
+	.long	serror		|$35-5 fsincos ERROR
+	.long	serror		|$35-6 fsincos ERROR
+	.long	serror		|$35-7 fsincos ERROR
+
+	.long	ssincos		|$36-0 fsincos norm
+	.long	ssincosz	|$36-1 fsincos zero
+	.long	ssincosi	|$36-2 fsincos inf
+	.long	ssincosnan	|$36-3 fsincos nan
+	.long	ssincosd	|$36-4 fsincos denorm
+	.long	serror		|$36-5 fsincos ERROR
+	.long	serror		|$36-6 fsincos ERROR
+	.long	serror		|$36-7 fsincos ERROR
+
+	.long	ssincos		|$37-0 fsincos norm
+	.long	ssincosz	|$37-1 fsincos zero
+	.long	ssincosi	|$37-2 fsincos inf
+	.long	ssincosnan	|$37-3 fsincos nan
+	.long	ssincosd	|$37-4 fsincos denorm
+	.long	serror		|$37-5 fsincos ERROR
+	.long	serror		|$37-6 fsincos ERROR
+	.long	serror		|$37-7 fsincos ERROR
+
+	|end
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/fpsp040/util.S linux/arch/m68k/fpsp040/util.S
--- v1.3.93/linux/arch/m68k/fpsp040/util.S	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/fpsp040/util.S	Sat Feb 24 22:58:45 1996
@@ -0,0 +1,748 @@
+|
+|	util.sa 3.7 7/29/91
+|
+|	This file contains routines used by other programs.
+|
+|	ovf_res: used by overflow to force the correct
+|		 result. ovf_r_k, ovf_r_x2, ovf_r_x3 are 
+|		 derivatives of this routine.
+|	get_fline: get user's opcode word
+|	g_dfmtou: returns the destination format.
+|	g_opcls: returns the opclass of the float instruction.
+|	g_rndpr: returns the rounding precision. 
+|	reg_dest: write byte, word, or long data to Dn
+|
+|
+|		Copyright (C) Motorola, Inc. 1990
+|			All Rights Reserved
+|
+|	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA 
+|	The copyright notice above does not evidence any  
+|	actual or intended publication of such source code.
+
+|UTIL	idnt    2,1 | Motorola 040 Floating Point Software Package
+
+	|section	8
+
+	.include "fpsp.h"
+
+	|xref	mem_read
+
+	.global	g_dfmtou
+	.global	g_opcls
+	.global	g_rndpr
+	.global	get_fline
+	.global	reg_dest
+
+|
+| Final result table for ovf_res. Note that the negative counterparts
+| are unnecessary as ovf_res always returns the sign separately from
+| the exponent.
+|					;+inf
+EXT_PINF:	.long	0x7fff0000,0x00000000,0x00000000,0x00000000	
+|					;largest +ext
+EXT_PLRG:	.long	0x7ffe0000,0xffffffff,0xffffffff,0x00000000	
+|					;largest magnitude +sgl in ext
+SGL_PLRG:	.long	0x407e0000,0xffffff00,0x00000000,0x00000000	
+|					;largest magnitude +dbl in ext
+DBL_PLRG:	.long	0x43fe0000,0xffffffff,0xfffff800,0x00000000	
+|					;largest -ext
+
+tblovfl:
+	.long	EXT_RN
+	.long	EXT_RZ
+	.long	EXT_RM
+	.long	EXT_RP
+	.long	SGL_RN
+	.long	SGL_RZ
+	.long	SGL_RM
+	.long	SGL_RP
+	.long	DBL_RN
+	.long	DBL_RZ
+	.long	DBL_RM
+	.long	DBL_RP
+	.long	error
+	.long	error
+	.long	error
+	.long	error
+
+
+|
+|	ovf_r_k --- overflow result calculation
+|
+| This entry point is used by kernel_ex.  
+|
+| This forces the destination precision to be extended
+|
+| Input:	operand in ETEMP
+| Output:	a result is in ETEMP (internal extended format)
+|
+	.global	ovf_r_k
+ovf_r_k:
+	lea	ETEMP(%a6),%a0	|a0 points to source operand	
+	bclrb	#sign_bit,ETEMP_EX(%a6)
+	sne	ETEMP_SGN(%a6)	|convert to internal IEEE format
+
+|
+|	ovf_r_x2 --- overflow result calculation
+|
+| This entry point used by x_ovfl.  (opclass 0 and 2)
+|
+| Input		a0  points to an operand in the internal extended format
+| Output	a0  points to the result in the internal extended format
+|
+| This sets the round precision according to the user's FPCR unless the
+| instruction is fsgldiv or fsglmul or fsadd, fdadd, fsub, fdsub, fsmul,
+| fdmul, fsdiv, fddiv, fssqrt, fsmove, fdmove, fsabs, fdabs, fsneg, fdneg.
+| If the instruction is fsgldiv of fsglmul, the rounding precision must be
+| extended.  If the instruction is not fsgldiv or fsglmul but a force-
+| precision instruction, the rounding precision is then set to the force
+| precision.
+
+	.global	ovf_r_x2
+ovf_r_x2:
+	btstb	#E3,E_BYTE(%a6)		|check for nu exception
+	beql	ovf_e1_exc		|it is cu exception
+ovf_e3_exc:
+	movew	CMDREG3B(%a6),%d0		|get the command word
+	andiw	#0x00000060,%d0		|clear all bits except 6 and 5
+	cmpil	#0x00000040,%d0
+	beql	ovff_sgl		|force precision is single
+	cmpil	#0x00000060,%d0
+	beql	ovff_dbl		|force precision is double
+	movew	CMDREG3B(%a6),%d0		|get the command word again
+	andil	#0x7f,%d0			|clear all except operation
+	cmpil	#0x33,%d0			
+	beql	ovf_fsgl		|fsglmul or fsgldiv
+	cmpil	#0x30,%d0
+	beql	ovf_fsgl		
+	bra	ovf_fpcr		|instruction is none of the above
+|					;use FPCR
+ovf_e1_exc:
+	movew	CMDREG1B(%a6),%d0		|get command word
+	andil	#0x00000044,%d0		|clear all bits except 6 and 2
+	cmpil	#0x00000040,%d0
+	beql	ovff_sgl		|the instruction is force single
+	cmpil	#0x00000044,%d0
+	beql	ovff_dbl		|the instruction is force double
+	movew	CMDREG1B(%a6),%d0		|again get the command word
+	andil	#0x0000007f,%d0		|clear all except the op code
+	cmpil	#0x00000027,%d0
+	beql	ovf_fsgl		|fsglmul
+	cmpil 	#0x00000024,%d0
+	beql	ovf_fsgl		|fsgldiv
+	bra	ovf_fpcr		|none of the above, use FPCR
+| 
+|
+| Inst is either fsgldiv or fsglmul.  Force extended precision.
+|
+ovf_fsgl:
+	clrl	%d0
+	bras	ovf_res
+
+ovff_sgl:
+	movel	#0x00000001,%d0		|set single
+	bras	ovf_res
+ovff_dbl:
+	movel	#0x00000002,%d0		|set double
+	bras	ovf_res
+|
+| The precision is in the fpcr.
+|
+ovf_fpcr:
+	bfextu	FPCR_MODE(%a6){#0:#2},%d0 |set round precision
+	bras	ovf_res
+	
+|
+|
+|	ovf_r_x3 --- overflow result calculation
+|
+| This entry point used by x_ovfl. (opclass 3 only)
+|
+| Input		a0  points to an operand in the internal extended format
+| Output	a0  points to the result in the internal extended format
+|
+| This sets the round precision according to the destination size.
+|
+	.global	ovf_r_x3
+ovf_r_x3:
+	bsr	g_dfmtou	|get dest fmt in d0{1:0}
+|				;for fmovout, the destination format
+|				;is the rounding precision
+
+|
+|	ovf_res --- overflow result calculation
+|
+| Input:
+|	a0 	points to operand in internal extended format
+| Output:
+|	a0 	points to result in internal extended format
+|
+	.global	ovf_res
+ovf_res:
+	lsll	#2,%d0		|move round precision to d0{3:2}
+	bfextu	FPCR_MODE(%a6){#2:#2},%d1 |set round mode
+	orl	%d1,%d0		|index is fmt:mode in d0{3:0}
+	leal	tblovfl,%a1	|load a1 with table address
+	movel	%a1@(%d0:l:4),%a1	|use d0 as index to the table
+	jmp	(%a1)		|go to the correct routine
+|
+|case DEST_FMT = EXT
+|
+EXT_RN:
+	leal	EXT_PINF,%a1	|answer is +/- infinity
+	bsetb	#inf_bit,FPSR_CC(%a6)
+	bra	set_sign	|now go set the sign	
+EXT_RZ:
+	leal	EXT_PLRG,%a1	|answer is +/- large number
+	bra	set_sign	|now go set the sign
+EXT_RM:
+	tstb	LOCAL_SGN(%a0)	|if negative overflow
+	beqs	e_rm_pos
+e_rm_neg:
+	leal	EXT_PINF,%a1	|answer is negative infinity
+	orl	#neginf_mask,USER_FPSR(%a6)
+	bra	end_ovfr
+e_rm_pos:
+	leal	EXT_PLRG,%a1	|answer is large positive number
+	bra	end_ovfr
+EXT_RP:
+	tstb	LOCAL_SGN(%a0)	|if negative overflow
+	beqs	e_rp_pos
+e_rp_neg:
+	leal	EXT_PLRG,%a1	|answer is large negative number
+	bsetb	#neg_bit,FPSR_CC(%a6)
+	bra	end_ovfr
+e_rp_pos:
+	leal	EXT_PINF,%a1	|answer is positive infinity
+	bsetb	#inf_bit,FPSR_CC(%a6)
+	bra	end_ovfr
+|
+|case DEST_FMT = DBL
+|
+DBL_RN:
+	leal	EXT_PINF,%a1	|answer is +/- infinity
+	bsetb	#inf_bit,FPSR_CC(%a6)
+	bra	set_sign
+DBL_RZ:
+	leal	DBL_PLRG,%a1	|answer is +/- large number
+	bra	set_sign	|now go set the sign
+DBL_RM:
+	tstb	LOCAL_SGN(%a0)	|if negative overflow
+	beqs	d_rm_pos
+d_rm_neg:
+	leal	EXT_PINF,%a1	|answer is negative infinity
+	orl	#neginf_mask,USER_FPSR(%a6)
+	bra	end_ovfr	|inf is same for all precisions (ext,dbl,sgl)
+d_rm_pos:
+	leal	DBL_PLRG,%a1	|answer is large positive number
+	bra	end_ovfr
+DBL_RP:
+	tstb	LOCAL_SGN(%a0)	|if negative overflow
+	beqs	d_rp_pos
+d_rp_neg:
+	leal	DBL_PLRG,%a1	|answer is large negative number
+	bsetb	#neg_bit,FPSR_CC(%a6)
+	bra	end_ovfr
+d_rp_pos:
+	leal	EXT_PINF,%a1	|answer is positive infinity
+	bsetb	#inf_bit,FPSR_CC(%a6)
+	bra	end_ovfr
+|
+|case DEST_FMT = SGL
+|
+SGL_RN:
+	leal	EXT_PINF,%a1	|answer is +/-  infinity
+	bsetb	#inf_bit,FPSR_CC(%a6)
+	bras	set_sign
+SGL_RZ:
+	leal	SGL_PLRG,%a1	|anwer is +/- large number
+	bras	set_sign
+SGL_RM:
+	tstb	LOCAL_SGN(%a0)	|if negative overflow
+	beqs	s_rm_pos
+s_rm_neg:
+	leal	EXT_PINF,%a1	|answer is negative infinity
+	orl	#neginf_mask,USER_FPSR(%a6)
+	bras	end_ovfr
+s_rm_pos:
+	leal	SGL_PLRG,%a1	|answer is large positive number
+	bras	end_ovfr
+SGL_RP:
+	tstb	LOCAL_SGN(%a0)	|if negative overflow
+	beqs	s_rp_pos
+s_rp_neg:
+	leal	SGL_PLRG,%a1	|answer is large negative number
+	bsetb	#neg_bit,FPSR_CC(%a6)
+	bras	end_ovfr
+s_rp_pos:
+	leal	EXT_PINF,%a1	|answer is postive infinity
+	bsetb	#inf_bit,FPSR_CC(%a6)
+	bras	end_ovfr
+
+set_sign:
+	tstb	LOCAL_SGN(%a0)	|if negative overflow
+	beqs	end_ovfr
+neg_sign:
+	bsetb	#neg_bit,FPSR_CC(%a6)
+
+end_ovfr:
+	movew	LOCAL_EX(%a1),LOCAL_EX(%a0) |do not overwrite sign
+	movel	LOCAL_HI(%a1),LOCAL_HI(%a0)
+	movel	LOCAL_LO(%a1),LOCAL_LO(%a0)
+	rts
+
+
+|
+|	ERROR
+|
+error:
+	rts
+|
+|	get_fline --- get f-line opcode of interrupted instruction
+|
+|	Returns opcode in the low word of d0.
+|
+get_fline:
+	movel	USER_FPIAR(%a6),%a0	|opcode address
+	movel	#0,-(%a7)	|reserve a word on the stack
+	leal	2(%a7),%a1	|point to low word of temporary
+	movel	#2,%d0		|count
+	bsrl	mem_read
+	movel	(%a7)+,%d0
+	rts
+|
+| 	g_rndpr --- put rounding precision in d0{1:0}
+|	
+|	valid return codes are:
+|		00 - extended 
+|		01 - single
+|		10 - double
+|
+| begin
+| get rounding precision (cmdreg3b{6:5})
+| begin
+|  case	opclass = 011 (move out)
+|	get destination format - this is the also the rounding precision
+|
+|  case	opclass = 0x0
+|	if E3
+|	    *case RndPr(from cmdreg3b{6:5} = 11  then RND_PREC = DBL
+|	    *case RndPr(from cmdreg3b{6:5} = 10  then RND_PREC = SGL
+|	     case RndPr(from cmdreg3b{6:5} = 00 | 01
+|		use precision from FPCR{7:6}
+|			case 00 then RND_PREC = EXT
+|			case 01 then RND_PREC = SGL
+|			case 10 then RND_PREC = DBL
+|	else E1
+|	     use precision in FPCR{7:6}
+|	     case 00 then RND_PREC = EXT
+|	     case 01 then RND_PREC = SGL
+|	     case 10 then RND_PREC = DBL
+| end
+|
+g_rndpr:
+	bsr	g_opcls		|get opclass in d0{2:0}
+	cmpw	#0x0003,%d0	|check for opclass 011
+	bnes	op_0x0
+
+|
+| For move out instructions (opclass 011) the destination format
+| is the same as the rounding precision.  Pass results from g_dfmtou.
+|
+	bsr 	g_dfmtou	
+	rts
+op_0x0:
+	btstb	#E3,E_BYTE(%a6)
+	beql	unf_e1_exc	|branch to e1 underflow
+unf_e3_exc:
+	movel	CMDREG3B(%a6),%d0	|rounding precision in d0{10:9}
+	bfextu	%d0{#9:#2},%d0	|move the rounding prec bits to d0{1:0}
+	cmpil	#0x2,%d0
+	beql	unff_sgl	|force precision is single
+	cmpil	#0x3,%d0		|force precision is double
+	beql	unff_dbl
+	movew	CMDREG3B(%a6),%d0	|get the command word again
+	andil	#0x7f,%d0		|clear all except operation
+	cmpil	#0x33,%d0			
+	beql	unf_fsgl	|fsglmul or fsgldiv
+	cmpil	#0x30,%d0
+	beql	unf_fsgl	|fsgldiv or fsglmul
+	bra	unf_fpcr
+unf_e1_exc:
+	movel	CMDREG1B(%a6),%d0	|get 32 bits off the stack, 1st 16 bits
+|				;are the command word
+	andil	#0x00440000,%d0	|clear all bits except bits 6 and 2
+	cmpil	#0x00400000,%d0
+	beql	unff_sgl	|force single
+	cmpil	#0x00440000,%d0	|force double
+	beql	unff_dbl
+	movel	CMDREG1B(%a6),%d0	|get the command word again
+	andil	#0x007f0000,%d0	|clear all bits except the operation
+	cmpil	#0x00270000,%d0
+	beql	unf_fsgl	|fsglmul
+	cmpil	#0x00240000,%d0
+	beql	unf_fsgl	|fsgldiv
+	bra	unf_fpcr
+
+|
+| Convert to return format.  The values from cmdreg3b and the return
+| values are:
+|	cmdreg3b	return	     precision
+|	--------	------	     ---------
+|	  00,01		  0		ext
+|	   10		  1		sgl
+|	   11		  2		dbl
+| Force single
+|
+unff_sgl:
+	movel	#1,%d0		|return 1
+	rts
+|
+| Force double
+|
+unff_dbl:
+	movel	#2,%d0		|return 2
+	rts
+|
+| Force extended
+|
+unf_fsgl:
+	movel	#0,%d0		
+	rts
+|
+| Get rounding precision set in FPCR{7:6}.
+|
+unf_fpcr:
+	movel	USER_FPCR(%a6),%d0 |rounding precision bits in d0{7:6}
+	bfextu	%d0{#24:#2},%d0	|move the rounding prec bits to d0{1:0}
+	rts
+|
+|	g_opcls --- put opclass in d0{2:0}
+|
+g_opcls:
+	btstb	#E3,E_BYTE(%a6)
+	beqs	opc_1b		|if set, go to cmdreg1b
+opc_3b:
+	clrl	%d0		|if E3, only opclass 0x0 is possible
+	rts
+opc_1b:
+	movel	CMDREG1B(%a6),%d0
+	bfextu	%d0{#0:#3},%d0	|shift opclass bits d0{31:29} to d0{2:0}
+	rts
+|
+|	g_dfmtou --- put destination format in d0{1:0}
+|
+|	If E1, the format is from cmdreg1b{12:10}
+|	If E3, the format is extended.
+|
+|	Dest. Fmt.	
+|		extended  010 -> 00
+|		single    001 -> 01
+|		double    101 -> 10
+|
+g_dfmtou:
+	btstb	#E3,E_BYTE(%a6)
+	beqs	op011
+	clrl	%d0		|if E1, size is always ext
+	rts
+op011:
+	movel	CMDREG1B(%a6),%d0
+	bfextu	%d0{#3:#3},%d0	|dest fmt from cmdreg1b{12:10}
+	cmpb	#1,%d0		|check for single
+	bnes	not_sgl
+	movel	#1,%d0
+	rts
+not_sgl:
+	cmpb	#5,%d0		|check for double
+	bnes	not_dbl
+	movel	#2,%d0
+	rts
+not_dbl:
+	clrl	%d0		|must be extended
+	rts
+
+|
+|
+| Final result table for unf_sub. Note that the negative counterparts
+| are unnecessary as unf_sub always returns the sign separately from
+| the exponent.
+|					;+zero
+EXT_PZRO:	.long	0x00000000,0x00000000,0x00000000,0x00000000	
+|					;+zero
+SGL_PZRO:	.long	0x3f810000,0x00000000,0x00000000,0x00000000	
+|					;+zero
+DBL_PZRO:	.long	0x3c010000,0x00000000,0x00000000,0x00000000	
+|					;smallest +ext denorm
+EXT_PSML:	.long	0x00000000,0x00000000,0x00000001,0x00000000	
+|					;smallest +sgl denorm
+SGL_PSML:	.long	0x3f810000,0x00000100,0x00000000,0x00000000	
+|					;smallest +dbl denorm
+DBL_PSML:	.long	0x3c010000,0x00000000,0x00000800,0x00000000	
+|
+|	UNF_SUB --- underflow result calculation
+|
+| Input:
+|	d0 	contains round precision
+|	a0	points to input operand in the internal extended format
+|
+| Output:
+|	a0 	points to correct internal extended precision result.
+|
+
+tblunf:
+	.long	uEXT_RN
+	.long	uEXT_RZ
+	.long	uEXT_RM
+	.long	uEXT_RP
+	.long	uSGL_RN
+	.long	uSGL_RZ
+	.long	uSGL_RM
+	.long	uSGL_RP
+	.long	uDBL_RN
+	.long	uDBL_RZ
+	.long	uDBL_RM
+	.long	uDBL_RP
+	.long	uDBL_RN
+	.long	uDBL_RZ
+	.long	uDBL_RM
+	.long	uDBL_RP
+
+	.global	unf_sub
+unf_sub:
+	lsll	#2,%d0		|move round precision to d0{3:2}
+	bfextu	FPCR_MODE(%a6){#2:#2},%d1 |set round mode
+	orl	%d1,%d0		|index is fmt:mode in d0{3:0}
+	leal	tblunf,%a1	|load a1 with table address
+	movel	%a1@(%d0:l:4),%a1	|use d0 as index to the table
+	jmp	(%a1)		|go to the correct routine
+|
+|case DEST_FMT = EXT
+|
+uEXT_RN:
+	leal	EXT_PZRO,%a1	|answer is +/- zero
+	bsetb	#z_bit,FPSR_CC(%a6)
+	bra	uset_sign	|now go set the sign	
+uEXT_RZ:
+	leal	EXT_PZRO,%a1	|answer is +/- zero
+	bsetb	#z_bit,FPSR_CC(%a6)
+	bra	uset_sign	|now go set the sign
+uEXT_RM:
+	tstb	LOCAL_SGN(%a0)	|if negative underflow
+	beqs	ue_rm_pos
+ue_rm_neg:
+	leal	EXT_PSML,%a1	|answer is negative smallest denorm
+	bsetb	#neg_bit,FPSR_CC(%a6)
+	bra	end_unfr
+ue_rm_pos:
+	leal	EXT_PZRO,%a1	|answer is positive zero
+	bsetb	#z_bit,FPSR_CC(%a6)
+	bra	end_unfr
+uEXT_RP:
+	tstb	LOCAL_SGN(%a0)	|if negative underflow
+	beqs	ue_rp_pos
+ue_rp_neg:
+	leal	EXT_PZRO,%a1	|answer is negative zero
+	oril	#negz_mask,USER_FPSR(%a6)
+	bra	end_unfr
+ue_rp_pos:
+	leal	EXT_PSML,%a1	|answer is positive smallest denorm
+	bra	end_unfr
+|
+|case DEST_FMT = DBL
+|
+uDBL_RN:
+	leal	DBL_PZRO,%a1	|answer is +/- zero
+	bsetb	#z_bit,FPSR_CC(%a6)
+	bra	uset_sign
+uDBL_RZ:
+	leal	DBL_PZRO,%a1	|answer is +/- zero
+	bsetb	#z_bit,FPSR_CC(%a6)
+	bra	uset_sign	|now go set the sign
+uDBL_RM:
+	tstb	LOCAL_SGN(%a0)	|if negative overflow
+	beqs	ud_rm_pos
+ud_rm_neg:
+	leal	DBL_PSML,%a1	|answer is smallest denormalized negative
+	bsetb	#neg_bit,FPSR_CC(%a6)
+	bra	end_unfr
+ud_rm_pos:
+	leal	DBL_PZRO,%a1	|answer is positive zero
+	bsetb	#z_bit,FPSR_CC(%a6)
+	bra	end_unfr
+uDBL_RP:
+	tstb	LOCAL_SGN(%a0)	|if negative overflow
+	beqs	ud_rp_pos
+ud_rp_neg:
+	leal	DBL_PZRO,%a1	|answer is negative zero
+	oril	#negz_mask,USER_FPSR(%a6)
+	bra	end_unfr
+ud_rp_pos:
+	leal	DBL_PSML,%a1	|answer is smallest denormalized negative
+	bra	end_unfr
+|
+|case DEST_FMT = SGL
+|
+uSGL_RN:
+	leal	SGL_PZRO,%a1	|answer is +/- zero
+	bsetb	#z_bit,FPSR_CC(%a6)
+	bras	uset_sign
+uSGL_RZ:
+	leal	SGL_PZRO,%a1	|answer is +/- zero
+	bsetb	#z_bit,FPSR_CC(%a6)
+	bras	uset_sign
+uSGL_RM:
+	tstb	LOCAL_SGN(%a0)	|if negative overflow
+	beqs	us_rm_pos
+us_rm_neg:
+	leal	SGL_PSML,%a1	|answer is smallest denormalized negative
+	bsetb	#neg_bit,FPSR_CC(%a6)
+	bras	end_unfr
+us_rm_pos:
+	leal	SGL_PZRO,%a1	|answer is positive zero
+	bsetb	#z_bit,FPSR_CC(%a6)
+	bras	end_unfr
+uSGL_RP:
+	tstb	LOCAL_SGN(%a0)	|if negative overflow
+	beqs	us_rp_pos
+us_rp_neg:
+	leal	SGL_PZRO,%a1	|answer is negative zero
+	oril	#negz_mask,USER_FPSR(%a6)
+	bras	end_unfr
+us_rp_pos:
+	leal	SGL_PSML,%a1	|answer is smallest denormalized positive
+	bras	end_unfr
+
+uset_sign:
+	tstb	LOCAL_SGN(%a0)	|if negative overflow
+	beqs	end_unfr
+uneg_sign:
+	bsetb	#neg_bit,FPSR_CC(%a6)
+
+end_unfr:
+	movew	LOCAL_EX(%a1),LOCAL_EX(%a0) |be careful not to overwrite sign
+	movel	LOCAL_HI(%a1),LOCAL_HI(%a0)
+	movel	LOCAL_LO(%a1),LOCAL_LO(%a0)
+	rts
+|
+|	reg_dest --- write byte, word, or long data to Dn
+|
+|
+| Input:
+|	L_SCR1: Data 
+|	d1:     data size and dest register number formatted as:
+|
+|	32		5    4     3     2     1     0
+|       -----------------------------------------------
+|       |        0        |    Size   |  Dest Reg #   |
+|       -----------------------------------------------
+|
+|	Size is:
+|		0 - Byte
+|		1 - Word
+|		2 - Long/Single
+|
+pregdst:
+	.long	byte_d0
+	.long	byte_d1
+	.long	byte_d2
+	.long	byte_d3
+	.long	byte_d4
+	.long	byte_d5
+	.long	byte_d6
+	.long	byte_d7
+	.long	word_d0
+	.long	word_d1
+	.long	word_d2
+	.long	word_d3
+	.long	word_d4
+	.long	word_d5
+	.long	word_d6
+	.long	word_d7
+	.long	long_d0
+	.long	long_d1
+	.long	long_d2
+	.long	long_d3
+	.long	long_d4
+	.long	long_d5
+	.long	long_d6
+	.long	long_d7
+
+reg_dest:
+	leal	pregdst,%a0
+	movel	%a0@(%d1:l:4),%a0
+	jmp	(%a0)
+
+byte_d0:
+	moveb	L_SCR1(%a6),USER_D0+3(%a6)
+	rts
+byte_d1:
+	moveb	L_SCR1(%a6),USER_D1+3(%a6)
+	rts
+byte_d2:
+	moveb	L_SCR1(%a6),%d2
+	rts
+byte_d3:
+	moveb	L_SCR1(%a6),%d3
+	rts
+byte_d4:
+	moveb	L_SCR1(%a6),%d4
+	rts
+byte_d5:
+	moveb	L_SCR1(%a6),%d5
+	rts
+byte_d6:
+	moveb	L_SCR1(%a6),%d6
+	rts
+byte_d7:
+	moveb	L_SCR1(%a6),%d7
+	rts
+word_d0:
+	movew	L_SCR1(%a6),USER_D0+2(%a6)
+	rts
+word_d1:
+	movew	L_SCR1(%a6),USER_D1+2(%a6)
+	rts
+word_d2:
+	movew	L_SCR1(%a6),%d2
+	rts
+word_d3:
+	movew	L_SCR1(%a6),%d3
+	rts
+word_d4:
+	movew	L_SCR1(%a6),%d4
+	rts
+word_d5:
+	movew	L_SCR1(%a6),%d5
+	rts
+word_d6:
+	movew	L_SCR1(%a6),%d6
+	rts
+word_d7:
+	movew	L_SCR1(%a6),%d7
+	rts
+long_d0:
+	movel	L_SCR1(%a6),USER_D0(%a6)
+	rts
+long_d1:
+	movel	L_SCR1(%a6),USER_D1(%a6)
+	rts
+long_d2:
+	movel	L_SCR1(%a6),%d2
+	rts
+long_d3:
+	movel	L_SCR1(%a6),%d3
+	rts
+long_d4:
+	movel	L_SCR1(%a6),%d4
+	rts
+long_d5:
+	movel	L_SCR1(%a6),%d5
+	rts
+long_d6:
+	movel	L_SCR1(%a6),%d6
+	rts
+long_d7:
+	movel	L_SCR1(%a6),%d7
+	rts
+	|end
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/fpsp040/x_bsun.S linux/arch/m68k/fpsp040/x_bsun.S
--- v1.3.93/linux/arch/m68k/fpsp040/x_bsun.S	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/fpsp040/x_bsun.S	Sat Feb 24 22:58:45 1996
@@ -0,0 +1,47 @@
+|
+|	x_bsun.sa 3.3 7/1/91
+|
+|	fpsp_bsun --- FPSP handler for branch/set on unordered exception
+|
+|	Copy the PC to FPIAR to maintain 881/882 compatability
+|
+|	The real_bsun handler will need to perform further corrective
+|	measures as outlined in the 040 User's Manual on pages
+|	9-41f, section 9.8.3.
+|
+
+|		Copyright (C) Motorola, Inc. 1990
+|			All Rights Reserved
+|
+|	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA 
+|	The copyright notice above does not evidence any  
+|	actual or intended publication of such source code.
+
+X_BSUN:	|idnt    2,1 | Motorola 040 Floating Point Software Package
+
+	|section	8
+
+	.include "fpsp.h"
+
+	|xref	real_bsun
+
+	.global	fpsp_bsun
+fpsp_bsun:
+|
+	link		%a6,#-LOCAL_SIZE
+	fsave		-(%a7)
+	moveml		%d0-%d1/%a0-%a1,USER_DA(%a6)
+	fmovemx	%fp0-%fp3,USER_FP0(%a6)
+	fmoveml	%fpcr/%fpsr/%fpiar,USER_FPCR(%a6)
+
+|
+	movel		EXC_PC(%a6),USER_FPIAR(%a6)
+|
+	moveml		USER_DA(%a6),%d0-%d1/%a0-%a1
+	fmovemx	USER_FP0(%a6),%fp0-%fp3
+	fmoveml	USER_FPCR(%a6),%fpcr/%fpsr/%fpiar
+	frestore	(%a7)+
+	unlk		%a6
+	bral		real_bsun
+|
+	|end
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/fpsp040/x_fline.S linux/arch/m68k/fpsp040/x_fline.S
--- v1.3.93/linux/arch/m68k/fpsp040/x_fline.S	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/fpsp040/x_fline.S	Sat Feb 24 22:58:45 1996
@@ -0,0 +1,104 @@
+|
+|	x_fline.sa 3.3 1/10/91
+|
+|	fpsp_fline --- FPSP handler for fline exception
+|
+|	First determine if the exception is one of the unimplemented
+|	floating point instructions.  If so, let fpsp_unimp handle it.
+|	Next, determine if the instruction is an fmovecr with a non-zero
+|	<ea> field.  If so, handle here and return.  Otherwise, it
+|	must be a real F-line exception.
+|
+
+|		Copyright (C) Motorola, Inc. 1990
+|			All Rights Reserved
+|
+|	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA 
+|	The copyright notice above does not evidence any  
+|	actual or intended publication of such source code.
+
+X_FLINE:	|idnt    2,1 | Motorola 040 Floating Point Software Package
+
+	|section	8
+
+	.include "fpsp.h"
+
+	|xref	real_fline
+	|xref	fpsp_unimp
+	|xref	uni_2
+	|xref	mem_read
+	|xref	fpsp_fmt_error
+
+	.global	fpsp_fline
+fpsp_fline:
+|
+|	check for unimplemented vector first.  Use EXC_VEC-4 because
+|	the equate is valid only after a 'link a6' has pushed one more
+|	long onto the stack.
+|
+	cmpw	#UNIMP_VEC,EXC_VEC-4(%a7)
+	beql	fpsp_unimp
+
+|
+|	fmovecr with non-zero <ea> handling here
+|
+	subl	#4,%a7		|4 accounts for 2-word difference
+|				;between six word frame (unimp) and
+|				;four word frame
+	link	%a6,#-LOCAL_SIZE
+	fsave	-(%a7)
+	moveml	%d0-%d1/%a0-%a1,USER_DA(%a6)
+	moveal	EXC_PC+4(%a6),%a0	|get address of fline instruction
+	leal	L_SCR1(%a6),%a1	|use L_SCR1 as scratch
+	movel	#4,%d0
+	addl	#4,%a6		|to offset the sub.l #4,a7 above so that
+|				;a6 can point correctly to the stack frame 
+|				;before branching to mem_read
+	bsrl	mem_read
+	subl	#4,%a6
+	movel	L_SCR1(%a6),%d0	|d0 contains the fline and command word
+	bfextu	%d0{#4:#3},%d1	|extract coprocessor id
+	cmpib	#1,%d1		|check if cpid=1
+	bne	not_mvcr	|exit if not
+	bfextu	%d0{#16:#6},%d1
+	cmpib	#0x17,%d1		|check if it is an FMOVECR encoding
+	bne	not_mvcr	
+|				;if an FMOVECR instruction, fix stack
+|				;and go to FPSP_UNIMP
+fix_stack:
+	cmpib	#VER_40,(%a7)	|test for orig unimp frame
+	bnes	ck_rev
+	subl	#UNIMP_40_SIZE-4,%a7 |emulate an orig fsave
+	moveb	#VER_40,(%a7)
+	moveb	#UNIMP_40_SIZE-4,1(%a7)
+	clrw	2(%a7)
+	bras	fix_con
+ck_rev:
+	cmpib	#VER_41,(%a7)	|test for rev unimp frame
+	bnel	fpsp_fmt_error	|if not $40 or $41, exit with error
+	subl	#UNIMP_41_SIZE-4,%a7 |emulate a rev fsave
+	moveb	#VER_41,(%a7)
+	moveb	#UNIMP_41_SIZE-4,1(%a7)
+	clrw	2(%a7)
+fix_con:
+	movew	EXC_SR+4(%a6),EXC_SR(%a6) |move stacked sr to new position
+	movel	EXC_PC+4(%a6),EXC_PC(%a6) |move stacked pc to new position
+	fmovel	EXC_PC(%a6),%FPIAR |point FPIAR to fline inst
+	movel	#4,%d1
+	addl	%d1,EXC_PC(%a6)	|increment stacked pc value to next inst
+	movew	#0x202c,EXC_VEC(%a6) |reformat vector to unimp
+	clrl	EXC_EA(%a6)	|clear the EXC_EA field
+	movew	%d0,CMDREG1B(%a6) |move the lower word into CMDREG1B
+	clrl	E_BYTE(%a6)
+	bsetb	#UFLAG,T_BYTE(%a6)
+	moveml	USER_DA(%a6),%d0-%d1/%a0-%a1 |restore data registers
+	bral	uni_2
+
+not_mvcr:
+	moveml	USER_DA(%a6),%d0-%d1/%a0-%a1 |restore data registers
+	frestore (%a7)+
+	unlk	%a6
+	addl	#4,%a7
+	bral	real_fline
+
+	|end
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/fpsp040/x_operr.S linux/arch/m68k/fpsp040/x_operr.S
--- v1.3.93/linux/arch/m68k/fpsp040/x_operr.S	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/fpsp040/x_operr.S	Sat Feb 24 22:58:45 1996
@@ -0,0 +1,356 @@
+|
+|	x_operr.sa 3.5 7/1/91
+|
+|	fpsp_operr --- FPSP handler for operand error exception
+|
+|	See 68040 User's Manual pp. 9-44f
+|
+| Note 1: For trap disabled 040 does the following:
+| If the dest is a fp reg, then an extended precision non_signaling
+| NAN is stored in the dest reg.  If the dest format is b, w, or l and
+| the source op is a NAN, then garbage is stored as the result (actually
+| the upper 32 bits of the mantissa are sent to the integer unit). If
+| the dest format is integer (b, w, l) and the operr is caused by
+| integer overflow, or the source op is inf, then the result stored is
+| garbage.
+| There are three cases in which operr is incorrectly signaled on the 
+| 040.  This occurs for move_out of format b, w, or l for the largest 
+| negative integer (-2^7 for b, -2^15 for w, -2^31 for l).
+|
+|	  On opclass = 011 fmove.(b,w,l) that causes a conversion
+|	  overflow -> OPERR, the exponent in wbte (and fpte) is:
+|		byte    56 - (62 - exp)
+|		word    48 - (62 - exp)
+|		long    32 - (62 - exp)
+|
+|			where exp = (true exp) - 1
+|
+|  So, wbtemp and fptemp will contain the following on erroneoulsy
+|	  signalled operr:
+|			fpts = 1
+|			fpte = $4000  (15 bit externally)
+|		byte	fptm = $ffffffff ffffff80
+|		word	fptm = $ffffffff ffff8000
+|		long	fptm = $ffffffff 80000000
+|
+| Note 2: For trap enabled 040 does the following:
+| If the inst is move_out, then same as Note 1.
+| If the inst is not move_out, the dest is not modified.
+| The exceptional operand is not defined for integer overflow 
+| during a move_out.
+|
+
+|		Copyright (C) Motorola, Inc. 1990
+|			All Rights Reserved
+|
+|	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA 
+|	The copyright notice above does not evidence any  
+|	actual or intended publication of such source code.
+
+X_OPERR:	|idnt    2,1 | Motorola 040 Floating Point Software Package
+
+	|section	8
+
+	.include "fpsp.h"
+
+	|xref	mem_write
+	|xref	real_operr
+	|xref	real_inex
+	|xref	get_fline
+	|xref	fpsp_done
+	|xref	reg_dest
+
+	.global	fpsp_operr
+fpsp_operr:
+|
+	link		%a6,#-LOCAL_SIZE
+	fsave		-(%a7)
+	moveml		%d0-%d1/%a0-%a1,USER_DA(%a6)
+	fmovemx	%fp0-%fp3,USER_FP0(%a6)
+	fmoveml	%fpcr/%fpsr/%fpiar,USER_FPCR(%a6)
+
+|
+| Check if this is an opclass 3 instruction.
+|  If so, fall through, else branch to operr_end
+|
+	btstb	#TFLAG,T_BYTE(%a6)
+	beqs	operr_end
+
+|
+| If the destination size is B,W,or L, the operr must be 
+| handled here.
+|
+	movel	CMDREG1B(%a6),%d0
+	bfextu	%d0{#3:#3},%d0	|0=long, 4=word, 6=byte
+	cmpib	#0,%d0		|determine size; check long
+	beq	operr_long
+	cmpib	#4,%d0		|check word
+	beq	operr_word
+	cmpib	#6,%d0		|check byte
+	beq	operr_byte
+
+|
+| The size is not B,W,or L, so the operr is handled by the 
+| kernel handler.  Set the operr bits and clean up, leaving
+| only the integer exception frame on the stack, and the 
+| fpu in the original exceptional state.
+|
+operr_end:
+	bsetb		#operr_bit,FPSR_EXCEPT(%a6)
+	bsetb		#aiop_bit,FPSR_AEXCEPT(%a6)
+
+	moveml		USER_DA(%a6),%d0-%d1/%a0-%a1
+	fmovemx	USER_FP0(%a6),%fp0-%fp3
+	fmoveml	USER_FPCR(%a6),%fpcr/%fpsr/%fpiar
+	frestore	(%a7)+
+	unlk		%a6
+	bral		real_operr
+
+operr_long:
+	moveql	#4,%d1		|write size to d1
+	moveb	STAG(%a6),%d0	|test stag for nan
+	andib	#0xe0,%d0		|clr all but tag
+	cmpib	#0x60,%d0		|check for nan
+	beq	operr_nan	
+	cmpil	#0x80000000,FPTEMP_LO(%a6) |test if ls lword is special
+	bnes	chklerr		|if not equal, check for incorrect operr
+	bsr	check_upper	|check if exp and ms mant are special
+	tstl	%d0
+	bnes	chklerr		|if d0 is true, check for incorrect operr
+	movel	#0x80000000,%d0	|store special case result
+	bsr	operr_store
+	bra	not_enabled	|clean and exit
+|
+|	CHECK FOR INCORRECTLY GENERATED OPERR EXCEPTION HERE
+|
+chklerr:
+	movew	FPTEMP_EX(%a6),%d0
+	andw	#0x7FFF,%d0	|ignore sign bit
+	cmpw	#0x3FFE,%d0	|this is the only possible exponent value
+	bnes	chklerr2
+fixlong:
+	movel	FPTEMP_LO(%a6),%d0
+	bsr	operr_store
+	bra	not_enabled
+chklerr2:
+	movew	FPTEMP_EX(%a6),%d0
+	andw	#0x7FFF,%d0	|ignore sign bit
+	cmpw	#0x4000,%d0
+	bcc	store_max	|exponent out of range
+
+	movel	FPTEMP_LO(%a6),%d0
+	andl	#0x7FFF0000,%d0	|look for all 1's on bits 30-16
+	cmpl	#0x7FFF0000,%d0
+	beqs	fixlong
+
+	tstl	FPTEMP_LO(%a6)
+	bpls	chklepos
+	cmpl	#0xFFFFFFFF,FPTEMP_HI(%a6)
+	beqs	fixlong
+	bra	store_max
+chklepos:
+	tstl	FPTEMP_HI(%a6)
+	beqs	fixlong
+	bra	store_max
+
+operr_word:
+	moveql	#2,%d1		|write size to d1
+	moveb	STAG(%a6),%d0	|test stag for nan
+	andib	#0xe0,%d0		|clr all but tag
+	cmpib	#0x60,%d0		|check for nan
+	beq	operr_nan	
+	cmpil	#0xffff8000,FPTEMP_LO(%a6) |test if ls lword is special
+	bnes	chkwerr		|if not equal, check for incorrect operr
+	bsr	check_upper	|check if exp and ms mant are special
+	tstl	%d0
+	bnes	chkwerr		|if d0 is true, check for incorrect operr
+	movel	#0x80000000,%d0	|store special case result
+	bsr	operr_store
+	bra	not_enabled	|clean and exit
+|
+|	CHECK FOR INCORRECTLY GENERATED OPERR EXCEPTION HERE
+|
+chkwerr:
+	movew	FPTEMP_EX(%a6),%d0
+	andw	#0x7FFF,%d0	|ignore sign bit
+	cmpw	#0x3FFE,%d0	|this is the only possible exponent value
+	bnes	store_max
+	movel	FPTEMP_LO(%a6),%d0
+	swap	%d0
+	bsr	operr_store
+	bra	not_enabled
+
+operr_byte:
+	moveql	#1,%d1		|write size to d1
+	moveb	STAG(%a6),%d0	|test stag for nan
+	andib	#0xe0,%d0		|clr all but tag
+	cmpib	#0x60,%d0		|check for nan
+	beqs	operr_nan	
+	cmpil	#0xffffff80,FPTEMP_LO(%a6) |test if ls lword is special
+	bnes	chkberr		|if not equal, check for incorrect operr
+	bsr	check_upper	|check if exp and ms mant are special
+	tstl	%d0
+	bnes	chkberr		|if d0 is true, check for incorrect operr
+	movel	#0x80000000,%d0	|store special case result
+	bsr	operr_store
+	bra	not_enabled	|clean and exit
+|
+|	CHECK FOR INCORRECTLY GENERATED OPERR EXCEPTION HERE
+|
+chkberr:
+	movew	FPTEMP_EX(%a6),%d0
+	andw	#0x7FFF,%d0	|ignore sign bit
+	cmpw	#0x3FFE,%d0	|this is the only possible exponent value
+	bnes	store_max
+	movel	FPTEMP_LO(%a6),%d0
+	asll	#8,%d0
+	swap	%d0
+	bsr	operr_store
+	bra	not_enabled
+
+|
+| This operr condition is not of the special case.  Set operr
+| and aiop and write the portion of the nan to memory for the
+| given size.
+|
+operr_nan:
+	orl	#opaop_mask,USER_FPSR(%a6) |set operr & aiop
+
+	movel	ETEMP_HI(%a6),%d0	|output will be from upper 32 bits
+	bsr	operr_store
+	bra	end_operr
+|
+| Store_max loads the max pos or negative for the size, sets
+| the operr and aiop bits, and clears inex and ainex, incorrectly
+| set by the 040.
+|
+store_max:
+	orl	#opaop_mask,USER_FPSR(%a6) |set operr & aiop
+	bclrb	#inex2_bit,FPSR_EXCEPT(%a6)
+	bclrb	#ainex_bit,FPSR_AEXCEPT(%a6)
+	fmovel	#0,%FPSR
+	
+	tstw	FPTEMP_EX(%a6)	|check sign
+	blts	load_neg
+	movel	#0x7fffffff,%d0
+	bsr	operr_store
+	bra	end_operr
+load_neg:
+	movel	#0x80000000,%d0
+	bsr	operr_store
+	bra	end_operr
+
+|
+| This routine stores the data in d0, for the given size in d1,
+| to memory or data register as required.  A read of the fline
+| is required to determine the destination.
+|
+operr_store:
+	movel	%d0,L_SCR1(%a6)	|move write data to L_SCR1
+	movel	%d1,-(%a7)	|save register size
+	bsrl	get_fline	|fline returned in d0
+	movel	(%a7)+,%d1
+	bftst	%d0{#26:#3}		|if mode is zero, dest is Dn
+	bnes	dest_mem
+|
+| Destination is Dn.  Get register number from d0. Data is on
+| the stack at (a7). D1 has size: 1=byte,2=word,4=long/single
+|
+	andil	#7,%d0		|isolate register number
+	cmpil	#4,%d1
+	beqs	op_long		|the most frequent case
+	cmpil	#2,%d1
+	bnes	op_con
+	orl	#8,%d0
+	bras	op_con
+op_long:
+	orl	#0x10,%d0
+op_con:
+	movel	%d0,%d1		|format size:reg for reg_dest
+	bral	reg_dest	|call to reg_dest returns to caller
+|				;of operr_store
+|
+| Destination is memory.  Get <ea> from integer exception frame
+| and call mem_write.
+|
+dest_mem:
+	leal	L_SCR1(%a6),%a0	|put ptr to write data in a0
+	movel	EXC_EA(%a6),%a1	|put user destination address in a1
+	movel	%d1,%d0		|put size in d0
+	bsrl	mem_write
+	rts
+|
+| Check the exponent for $c000 and the upper 32 bits of the 
+| mantissa for $ffffffff.  If both are true, return d0 clr
+| and store the lower n bits of the least lword of FPTEMP
+| to d0 for write out.  If not, it is a real operr, and set d0.
+|
+check_upper:
+	cmpil	#0xffffffff,FPTEMP_HI(%a6) |check if first byte is all 1's
+	bnes	true_operr	|if not all 1's then was true operr
+	cmpiw	#0xc000,FPTEMP_EX(%a6) |check if incorrectly signalled
+	beqs	not_true_operr	|branch if not true operr
+	cmpiw	#0xbfff,FPTEMP_EX(%a6) |check if incorrectly signalled
+	beqs	not_true_operr	|branch if not true operr
+true_operr:
+	movel	#1,%d0		|signal real operr
+	rts
+not_true_operr:
+	clrl	%d0		|signal no real operr
+	rts
+
+|
+| End_operr tests for operr enabled.  If not, it cleans up the stack
+| and does an rte.  If enabled, it cleans up the stack and branches
+| to the kernel operr handler with only the integer exception
+| frame on the stack and the fpu in the original exceptional state
+| with correct data written to the destination.
+|
+end_operr:
+	btstb		#operr_bit,FPCR_ENABLE(%a6)
+	beqs		not_enabled
+enabled:
+	moveml		USER_DA(%a6),%d0-%d1/%a0-%a1
+	fmovemx	USER_FP0(%a6),%fp0-%fp3
+	fmoveml	USER_FPCR(%a6),%fpcr/%fpsr/%fpiar
+	frestore	(%a7)+
+	unlk		%a6
+	bral		real_operr
+
+not_enabled:
+|
+| It is possible to have either inex2 or inex1 exceptions with the
+| operr.  If the inex enable bit is set in the FPCR, and either
+| inex2 or inex1 occured, we must clean up and branch to the
+| real inex handler.
+|
+ck_inex:
+	moveb	FPCR_ENABLE(%a6),%d0
+	andb	FPSR_EXCEPT(%a6),%d0
+	andib	#0x3,%d0
+	beq	operr_exit
+|
+| Inexact enabled and reported, and we must take an inexact exception.
+|
+take_inex:
+	moveb		#INEX_VEC,EXC_VEC+1(%a6)
+	movel		USER_FPSR(%a6),FPSR_SHADOW(%a6)
+	orl		#sx_mask,E_BYTE(%a6)
+	moveml		USER_DA(%a6),%d0-%d1/%a0-%a1
+	fmovemx	USER_FP0(%a6),%fp0-%fp3
+	fmoveml	USER_FPCR(%a6),%fpcr/%fpsr/%fpiar
+	frestore	(%a7)+
+	unlk		%a6
+	bral		real_inex
+|
+| Since operr is only an E1 exception, there is no need to frestore
+| any state back to the fpu.
+|
+operr_exit:
+	moveml		USER_DA(%a6),%d0-%d1/%a0-%a1
+	fmovemx	USER_FP0(%a6),%fp0-%fp3
+	fmoveml	USER_FPCR(%a6),%fpcr/%fpsr/%fpiar
+	unlk		%a6
+	bral		fpsp_done
+
+	|end
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/fpsp040/x_ovfl.S linux/arch/m68k/fpsp040/x_ovfl.S
--- v1.3.93/linux/arch/m68k/fpsp040/x_ovfl.S	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/fpsp040/x_ovfl.S	Sat Feb 24 22:58:45 1996
@@ -0,0 +1,186 @@
+|
+|	x_ovfl.sa 3.5 7/1/91
+|
+|	fpsp_ovfl --- FPSP handler for overflow exception
+|
+|	Overflow occurs when a floating-point intermediate result is
+|	too large to be represented in a floating-point data register,
+|	or when storing to memory, the contents of a floating-point
+|	data register are too large to be represented in the
+|	destination format.
+|		
+| Trap disabled results
+|
+| If the instruction is move_out, then garbage is stored in the
+| destination.  If the instruction is not move_out, then the
+| destination is not affected.  For 68881 compatibility, the
+| following values should be stored at the destination, based
+| on the current rounding mode:
+|
+|  RN	Infinity with the sign of the intermediate result.
+|  RZ	Largest magnitude number, with the sign of the
+|	intermediate result.
+|  RM   For pos overflow, the largest pos number. For neg overflow,
+|	-infinity
+|  RP   For pos overflow, +infinity. For neg overflow, the largest
+|	neg number
+|
+| Trap enabled results
+| All trap disabled code applies.  In addition the exceptional
+| operand needs to be made available to the users exception handler
+| with a bias of $6000 subtracted from the exponent.
+|
+|
+
+|		Copyright (C) Motorola, Inc. 1990
+|			All Rights Reserved
+|
+|	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA 
+|	The copyright notice above does not evidence any  
+|	actual or intended publication of such source code.
+
+X_OVFL:	|idnt    2,1 | Motorola 040 Floating Point Software Package
+
+	|section	8
+
+	.include "fpsp.h"
+
+	|xref	ovf_r_x2
+	|xref	ovf_r_x3
+	|xref	store
+	|xref	real_ovfl
+	|xref	real_inex
+	|xref	fpsp_done
+	|xref	g_opcls
+	|xref	b1238_fix
+
+	.global	fpsp_ovfl
+fpsp_ovfl:
+	link		%a6,#-LOCAL_SIZE
+	fsave		-(%a7)
+	moveml		%d0-%d1/%a0-%a1,USER_DA(%a6)
+	fmovemx	%fp0-%fp3,USER_FP0(%a6)
+	fmoveml	%fpcr/%fpsr/%fpiar,USER_FPCR(%a6)
+
+|
+|	The 040 doesn't set the AINEX bit in the FPSR, the following
+|	line temporarily rectifies this error.
+|
+	bsetb	#ainex_bit,FPSR_AEXCEPT(%a6)
+|
+	bsrl	ovf_adj		|denormalize, round & store interm op
+|
+|	if overflow traps not enabled check for inexact exception
+|
+	btstb	#ovfl_bit,FPCR_ENABLE(%a6)
+	beqs	ck_inex	
+|
+	btstb		#E3,E_BYTE(%a6)
+	beqs		no_e3_1
+	bfextu		CMDREG3B(%a6){#6:#3},%d0	|get dest reg no
+	bclrb		%d0,FPR_DIRTY_BITS(%a6)	|clr dest dirty bit
+	bsrl		b1238_fix
+	movel		USER_FPSR(%a6),FPSR_SHADOW(%a6)
+	orl		#sx_mask,E_BYTE(%a6)
+no_e3_1:
+	moveml		USER_DA(%a6),%d0-%d1/%a0-%a1
+	fmovemx	USER_FP0(%a6),%fp0-%fp3
+	fmoveml	USER_FPCR(%a6),%fpcr/%fpsr/%fpiar
+	frestore	(%a7)+
+	unlk		%a6
+	bral		real_ovfl
+|
+| It is possible to have either inex2 or inex1 exceptions with the
+| ovfl.  If the inex enable bit is set in the FPCR, and either
+| inex2 or inex1 occured, we must clean up and branch to the
+| real inex handler.
+|
+ck_inex:
+|	move.b		FPCR_ENABLE(%a6),%d0
+|	and.b		FPSR_EXCEPT(%a6),%d0
+|	andi.b		#$3,%d0
+	btstb		#inex2_bit,FPCR_ENABLE(%a6)
+	beqs		ovfl_exit
+|
+| Inexact enabled and reported, and we must take an inexact exception.
+|
+take_inex:
+	btstb		#E3,E_BYTE(%a6)
+	beqs		no_e3_2
+	bfextu		CMDREG3B(%a6){#6:#3},%d0	|get dest reg no
+	bclrb		%d0,FPR_DIRTY_BITS(%a6)	|clr dest dirty bit
+	bsrl		b1238_fix
+	movel		USER_FPSR(%a6),FPSR_SHADOW(%a6)
+	orl		#sx_mask,E_BYTE(%a6)
+no_e3_2:
+	moveb		#INEX_VEC,EXC_VEC+1(%a6)
+	moveml		USER_DA(%a6),%d0-%d1/%a0-%a1
+	fmovemx	USER_FP0(%a6),%fp0-%fp3
+	fmoveml	USER_FPCR(%a6),%fpcr/%fpsr/%fpiar
+	frestore	(%a7)+
+	unlk		%a6
+	bral		real_inex
+	
+ovfl_exit:
+	bclrb	#E3,E_BYTE(%a6)	|test and clear E3 bit
+	beqs	e1_set
+|
+| Clear dirty bit on dest resister in the frame before branching
+| to b1238_fix.
+|
+	bfextu		CMDREG3B(%a6){#6:#3},%d0	|get dest reg no
+	bclrb		%d0,FPR_DIRTY_BITS(%a6)	|clr dest dirty bit
+	bsrl		b1238_fix		|test for bug1238 case
+
+	movel		USER_FPSR(%a6),FPSR_SHADOW(%a6)
+	orl		#sx_mask,E_BYTE(%a6)
+	moveml		USER_DA(%a6),%d0-%d1/%a0-%a1
+	fmovemx	USER_FP0(%a6),%fp0-%fp3
+	fmoveml	USER_FPCR(%a6),%fpcr/%fpsr/%fpiar
+	frestore	(%a7)+
+	unlk		%a6
+	bral		fpsp_done
+e1_set:
+	moveml		USER_DA(%a6),%d0-%d1/%a0-%a1
+	fmovemx	USER_FP0(%a6),%fp0-%fp3
+	fmoveml	USER_FPCR(%a6),%fpcr/%fpsr/%fpiar
+	unlk		%a6
+	bral		fpsp_done
+
+|
+|	ovf_adj
+|
+ovf_adj:
+|
+| Have a0 point to the correct operand. 
+|
+	btstb	#E3,E_BYTE(%a6)	|test E3 bit
+	beqs	ovf_e1
+
+	lea	WBTEMP(%a6),%a0
+	bras	ovf_com
+ovf_e1:
+	lea	ETEMP(%a6),%a0
+
+ovf_com:
+	bclrb	#sign_bit,LOCAL_EX(%a0)
+	sne	LOCAL_SGN(%a0)
+
+	bsrl	g_opcls		|returns opclass in d0
+	cmpiw	#3,%d0		|check for opclass3
+	bnes	not_opc011
+
+|
+| FPSR_CC is saved and restored because ovf_r_x3 affects it. The
+| CCs are defined to be 'not affected' for the opclass3 instruction.
+|
+	moveb	FPSR_CC(%a6),L_SCR1(%a6)
+ 	bsrl	ovf_r_x3	|returns a0 pointing to result
+	moveb	L_SCR1(%a6),FPSR_CC(%a6)
+	bral	store		|stores to memory or register
+	
+not_opc011:
+	bsrl	ovf_r_x2	|returns a0 pointing to result
+	bral	store		|stores to memory or register
+
+	|end
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/fpsp040/x_snan.S linux/arch/m68k/fpsp040/x_snan.S
--- v1.3.93/linux/arch/m68k/fpsp040/x_snan.S	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/fpsp040/x_snan.S	Sat Feb 24 22:58:45 1996
@@ -0,0 +1,277 @@
+|
+|	x_snan.sa 3.3 7/1/91
+|
+| fpsp_snan --- FPSP handler for signalling NAN exception
+|
+| SNAN for float -> integer conversions (integer conversion of
+| an SNAN) is a non-maskable run-time exception.
+|
+| For trap disabled the 040 does the following:
+| If the dest data format is s, d, or x, then the SNAN bit in the NAN
+| is set to one and the resulting non-signaling NAN (truncated if
+| necessary) is transferred to the dest.  If the dest format is b, w,
+| or l, then garbage is written to the dest (actually the upper 32 bits
+| of the mantissa are sent to the integer unit).
+|
+| For trap enabled the 040 does the following:
+| If the inst is move_out, then the results are the same as for trap 
+| disabled with the exception posted.  If the instruction is not move_
+| out, the dest. is not modified, and the exception is posted.
+|
+
+|		Copyright (C) Motorola, Inc. 1990
+|			All Rights Reserved
+|
+|	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA 
+|	The copyright notice above does not evidence any  
+|	actual or intended publication of such source code.
+
+X_SNAN:	|idnt    2,1 | Motorola 040 Floating Point Software Package
+
+	|section	8
+
+	.include "fpsp.h"
+
+	|xref	get_fline
+	|xref	mem_write
+	|xref	real_snan
+	|xref	real_inex
+	|xref	fpsp_done
+	|xref	reg_dest
+
+	.global	fpsp_snan
+fpsp_snan:
+	link		%a6,#-LOCAL_SIZE
+	fsave		-(%a7)
+	moveml		%d0-%d1/%a0-%a1,USER_DA(%a6)
+	fmovemx	%fp0-%fp3,USER_FP0(%a6)
+	fmoveml	%fpcr/%fpsr/%fpiar,USER_FPCR(%a6)
+
+|
+| Check if trap enabled
+|
+	btstb		#snan_bit,FPCR_ENABLE(%a6)
+	bnes		ena		|If enabled, then branch
+
+	bsrl		move_out	|else SNAN disabled
+|
+| It is possible to have an inex1 exception with the
+| snan.  If the inex enable bit is set in the FPCR, and either
+| inex2 or inex1 occured, we must clean up and branch to the
+| real inex handler.
+|
+ck_inex:
+	moveb	FPCR_ENABLE(%a6),%d0
+	andb	FPSR_EXCEPT(%a6),%d0
+	andib	#0x3,%d0
+	beq	end_snan
+|
+| Inexact enabled and reported, and we must take an inexact exception.
+|
+take_inex:
+	moveb		#INEX_VEC,EXC_VEC+1(%a6)
+	moveml		USER_DA(%a6),%d0-%d1/%a0-%a1
+	fmovemx	USER_FP0(%a6),%fp0-%fp3
+	fmoveml	USER_FPCR(%a6),%fpcr/%fpsr/%fpiar
+	frestore	(%a7)+
+	unlk		%a6
+	bral		real_inex
+|
+| SNAN is enabled.  Check if inst is move_out.
+| Make any corrections to the 040 output as necessary.
+|
+ena:
+	btstb		#5,CMDREG1B(%a6) |if set, inst is move out
+	beq		not_out
+
+	bsrl		move_out
+
+report_snan:
+	moveb		(%a7),VER_TMP(%a6)
+	cmpib		#VER_40,(%a7)	|test for orig unimp frame
+	bnes		ck_rev
+	moveql		#13,%d0		|need to zero 14 lwords
+	bras		rep_con
+ck_rev:
+	moveql		#11,%d0		|need to zero 12 lwords
+rep_con:
+	clrl		(%a7)
+loop1:
+	clrl		-(%a7)		|clear and dec a7
+	dbra		%d0,loop1
+	moveb		VER_TMP(%a6),(%a7) |format a busy frame
+	moveb		#BUSY_SIZE-4,1(%a7)
+	movel		USER_FPSR(%a6),FPSR_SHADOW(%a6)
+	orl		#sx_mask,E_BYTE(%a6)
+	moveml		USER_DA(%a6),%d0-%d1/%a0-%a1
+	fmovemx	USER_FP0(%a6),%fp0-%fp3
+	fmoveml	USER_FPCR(%a6),%fpcr/%fpsr/%fpiar
+	frestore	(%a7)+
+	unlk		%a6
+	bral		real_snan
+|
+| Exit snan handler by expanding the unimp frame into a busy frame
+|
+end_snan:
+	bclrb		#E1,E_BYTE(%a6)
+
+	moveb		(%a7),VER_TMP(%a6)
+	cmpib		#VER_40,(%a7)	|test for orig unimp frame
+	bnes		ck_rev2
+	moveql		#13,%d0		|need to zero 14 lwords
+	bras		rep_con2
+ck_rev2:
+	moveql		#11,%d0		|need to zero 12 lwords
+rep_con2:
+	clrl		(%a7)
+loop2:
+	clrl		-(%a7)		|clear and dec a7
+	dbra		%d0,loop2
+	moveb		VER_TMP(%a6),(%a7) |format a busy frame
+	moveb		#BUSY_SIZE-4,1(%a7) |write busy size
+	movel		USER_FPSR(%a6),FPSR_SHADOW(%a6)
+	orl		#sx_mask,E_BYTE(%a6)
+	moveml		USER_DA(%a6),%d0-%d1/%a0-%a1
+	fmovemx	USER_FP0(%a6),%fp0-%fp3
+	fmoveml	USER_FPCR(%a6),%fpcr/%fpsr/%fpiar
+	frestore	(%a7)+
+	unlk		%a6
+	bral		fpsp_done
+
+|
+| Move_out 
+|
+move_out:
+	movel		EXC_EA(%a6),%a0	|get <ea> from exc frame
+
+	bfextu		CMDREG1B(%a6){#3:#3},%d0 |move rx field to d0{2:0}
+	cmpil		#0,%d0		|check for long
+	beqs		sto_long	|branch if move_out long
+	
+	cmpil		#4,%d0		|check for word
+	beqs		sto_word	|branch if move_out word
+	
+	cmpil		#6,%d0		|check for byte
+	beqs		sto_byte	|branch if move_out byte
+	
+|
+| Not byte, word or long
+|
+	rts
+|	
+| Get the 32 most significant bits of etemp mantissa
+|
+sto_long:
+	movel		ETEMP_HI(%a6),%d1
+	movel		#4,%d0		|load byte count
+|
+| Set signalling nan bit
+|
+	bsetl		#30,%d1			
+|
+| Store to the users destination address
+|
+	tstl		%a0		|check if <ea> is 0
+	beqs		wrt_dn		|destination is a data register
+	
+	movel		%d1,-(%a7)	|move the snan onto the stack
+	movel		%a0,%a1		|load dest addr into a1
+	movel		%a7,%a0		|load src addr of snan into a0
+	bsrl		mem_write	|write snan to user memory
+	movel		(%a7)+,%d1	|clear off stack
+	rts
+|
+| Get the 16 most significant bits of etemp mantissa
+|
+sto_word:
+	movel		ETEMP_HI(%a6),%d1
+	movel		#2,%d0		|load byte count
+|
+| Set signalling nan bit
+|
+	bsetl		#30,%d1			
+|
+| Store to the users destination address
+|
+	tstl		%a0		|check if <ea> is 0
+	beqs		wrt_dn		|destination is a data register
+
+	movel		%d1,-(%a7)	|move the snan onto the stack
+	movel		%a0,%a1		|load dest addr into a1
+	movel		%a7,%a0		|point to low word
+	bsrl		mem_write	|write snan to user memory
+	movel		(%a7)+,%d1	|clear off stack
+	rts
+|
+| Get the 8 most significant bits of etemp mantissa
+|
+sto_byte:
+	movel		ETEMP_HI(%a6),%d1
+	movel		#1,%d0		|load byte count
+|
+| Set signalling nan bit
+|
+	bsetl		#30,%d1			
+|
+| Store to the users destination address
+|
+	tstl		%a0		|check if <ea> is 0
+	beqs		wrt_dn		|destination is a data register
+	movel		%d1,-(%a7)	|move the snan onto the stack
+	movel		%a0,%a1		|load dest addr into a1
+	movel		%a7,%a0		|point to source byte
+	bsrl		mem_write	|write snan to user memory
+	movel		(%a7)+,%d1	|clear off stack
+	rts
+
+|
+|	wrt_dn --- write to a data register
+|
+|	We get here with D1 containing the data to write and D0 the
+|	number of bytes to write: 1=byte,2=word,4=long.
+|
+wrt_dn:
+	movel		%d1,L_SCR1(%a6)	|data
+	movel		%d0,-(%a7)	|size
+	bsrl		get_fline	|returns fline word in d0
+	movel		%d0,%d1
+	andil		#0x7,%d1		|d1 now holds register number
+	movel		(%sp)+,%d0	|get original size
+	cmpil		#4,%d0
+	beqs		wrt_long
+	cmpil		#2,%d0
+	bnes		wrt_byte
+wrt_word:
+	orl		#0x8,%d1
+	bral		reg_dest
+wrt_long:
+	orl		#0x10,%d1
+	bral		reg_dest
+wrt_byte:
+	bral		reg_dest
+|
+| Check if it is a src nan or dst nan
+|
+not_out:
+	movel		DTAG(%a6),%d0	
+	bfextu		%d0{#0:#3},%d0	|isolate dtag in lsbs
+
+	cmpib		#3,%d0		|check for nan in destination
+	bnes		issrc		|destination nan has priority
+dst_nan:
+	btstb		#6,FPTEMP_HI(%a6) |check if dest nan is an snan
+	bnes		issrc		|no, so check source for snan
+	movew		FPTEMP_EX(%a6),%d0
+	bras		cont
+issrc:
+	movew		ETEMP_EX(%a6),%d0
+cont:
+	btstl		#15,%d0		|test for sign of snan
+	beqs		clr_neg
+	bsetb		#neg_bit,FPSR_CC(%a6)
+	bra		report_snan
+clr_neg:
+	bclrb		#neg_bit,FPSR_CC(%a6)
+	bra		report_snan
+
+	|end
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/fpsp040/x_store.S linux/arch/m68k/fpsp040/x_store.S
--- v1.3.93/linux/arch/m68k/fpsp040/x_store.S	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/fpsp040/x_store.S	Sat Feb 24 22:58:45 1996
@@ -0,0 +1,256 @@
+|
+|	x_store.sa 3.2 1/24/91
+|
+|	store --- store operand to memory or register
+|
+|	Used by underflow and overflow handlers.
+|
+|	a6 = points to fp value to be stored.
+|
+
+|		Copyright (C) Motorola, Inc. 1990
+|			All Rights Reserved
+|
+|	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA 
+|	The copyright notice above does not evidence any  
+|	actual or intended publication of such source code.
+
+X_STORE:	|idnt    2,1 | Motorola 040 Floating Point Software Package
+
+	|section	8
+
+fpreg_mask:
+	.byte	0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01
+
+	.include "fpsp.h"
+
+	|xref	mem_write
+	|xref	get_fline
+	|xref	g_opcls
+	|xref	g_dfmtou
+	|xref	reg_dest
+
+	.global	dest_ext
+	.global	dest_dbl
+	.global	dest_sgl
+
+	.global	store
+store:
+	btstb	#E3,E_BYTE(%a6)
+	beqs	E1_sto
+E3_sto:
+	movel	CMDREG3B(%a6),%d0
+	bfextu	%d0{#6:#3},%d0		|isolate dest. reg from cmdreg3b
+sto_fp:
+	lea	fpreg_mask,%a1
+	moveb	(%a1,%d0.w),%d0		|convert reg# to dynamic register mask
+	tstb	LOCAL_SGN(%a0)
+	beqs	is_pos
+	bsetb	#sign_bit,LOCAL_EX(%a0)
+is_pos:
+	fmovemx (%a0),%d0		|move to correct register
+|
+|	if fp0-fp3 is being modified, we must put a copy
+|	in the USER_FPn variable on the stack because all exception
+|	handlers restore fp0-fp3 from there.
+|
+	cmpb	#0x80,%d0		
+	bnes	not_fp0
+	fmovemx %fp0-%fp0,USER_FP0(%a6)
+	rts
+not_fp0:
+	cmpb	#0x40,%d0
+	bnes	not_fp1
+	fmovemx %fp1-%fp1,USER_FP1(%a6)
+	rts
+not_fp1:
+	cmpb	#0x20,%d0
+	bnes	not_fp2
+	fmovemx %fp2-%fp2,USER_FP2(%a6)
+	rts
+not_fp2:
+	cmpb	#0x10,%d0
+	bnes	not_fp3
+	fmovemx %fp3-%fp3,USER_FP3(%a6)
+	rts
+not_fp3:
+	rts
+
+E1_sto:
+	bsrl	g_opcls		|returns opclass in d0
+	cmpib	#3,%d0
+	beq	opc011		|branch if opclass 3
+	movel	CMDREG1B(%a6),%d0
+	bfextu	%d0{#6:#3},%d0	|extract destination register
+	bras	sto_fp
+
+opc011:
+	bsrl	g_dfmtou	|returns dest format in d0
+|				;ext=00, sgl=01, dbl=10
+	movel	%a0,%a1		|save source addr in a1
+	movel	EXC_EA(%a6),%a0	|get the address
+	cmpil	#0,%d0		|if dest format is extended
+	beq	dest_ext	|then branch
+	cmpil	#1,%d0		|if dest format is single
+	beqs	dest_sgl	|then branch
+|
+|	fall through to dest_dbl
+|
+
+|
+|	dest_dbl --- write double precision value to user space
+|
+|Input
+|	a0 -> destination address
+|	a1 -> source in extended precision
+|Output
+|	a0 -> destroyed
+|	a1 -> destroyed
+|	d0 -> 0
+|
+|Changes extended precision to double precision.
+| Note: no attempt is made to round the extended value to double.
+|	dbl_sign = ext_sign
+|	dbl_exp = ext_exp - $3fff(ext bias) + $7ff(dbl bias)
+|	get rid of ext integer bit
+|	dbl_mant = ext_mant{62:12}
+|
+|	    	---------------   ---------------    ---------------
+|  extended ->  |s|    exp    |   |1| ms mant   |    | ls mant     |
+|	    	---------------   ---------------    ---------------
+|	   	 95	    64    63 62	      32      31     11	  0
+|				     |			     |
+|				     |			     |
+|				     |			     |
+|		 	             v   		     v
+|	    		      ---------------   ---------------
+|  double   ->  	      |s|exp| mant  |   |  mant       |
+|	    		      ---------------   ---------------
+|	   	 	      63     51   32   31	       0
+|
+dest_dbl:
+	clrl	%d0		|clear d0
+	movew	LOCAL_EX(%a1),%d0	|get exponent
+	subw	#0x3fff,%d0	|subtract extended precision bias
+	cmpw	#0x4000,%d0	|check if inf
+	beqs	inf		|if so, special case
+	addw	#0x3ff,%d0	|add double precision bias
+	swap	%d0		|d0 now in upper word
+	lsll	#4,%d0		|d0 now in proper place for dbl prec exp
+	tstb	LOCAL_SGN(%a1)	
+	beqs	get_mant	|if postive, go process mantissa
+	bsetl	#31,%d0		|if negative, put in sign information
+|				; before continuing
+	bras	get_mant	|go process mantissa
+inf:
+	movel	#0x7ff00000,%d0	|load dbl inf exponent
+	clrl	LOCAL_HI(%a1)	|clear msb
+	tstb	LOCAL_SGN(%a1)
+	beqs	dbl_inf		|if positive, go ahead and write it
+	bsetl	#31,%d0		|if negative put in sign information
+dbl_inf:
+	movel	%d0,LOCAL_EX(%a1)	|put the new exp back on the stack
+	bras	dbl_wrt
+get_mant:
+	movel	LOCAL_HI(%a1),%d1	|get ms mantissa
+	bfextu	%d1{#1:#20},%d1	|get upper 20 bits of ms
+	orl	%d1,%d0		|put these bits in ms word of double
+	movel	%d0,LOCAL_EX(%a1)	|put the new exp back on the stack
+	movel	LOCAL_HI(%a1),%d1	|get ms mantissa
+	movel	#21,%d0		|load shift count
+	lsll	%d0,%d1		|put lower 11 bits in upper bits
+	movel	%d1,LOCAL_HI(%a1)	|build lower lword in memory
+	movel	LOCAL_LO(%a1),%d1	|get ls mantissa
+	bfextu	%d1{#0:#21},%d0	|get ls 21 bits of double
+	orl	%d0,LOCAL_HI(%a1)	|put them in double result
+dbl_wrt:
+	movel	#0x8,%d0		|byte count for double precision number
+	exg	%a0,%a1		|a0=supervisor source, a1=user dest
+	bsrl	mem_write	|move the number to the user's memory
+	rts
+|
+|	dest_sgl --- write single precision value to user space
+|
+|Input
+|	a0 -> destination address
+|	a1 -> source in extended precision
+|
+|Output
+|	a0 -> destroyed
+|	a1 -> destroyed
+|	d0 -> 0
+|
+|Changes extended precision to single precision.
+|	sgl_sign = ext_sign
+|	sgl_exp = ext_exp - $3fff(ext bias) + $7f(sgl bias)
+|	get rid of ext integer bit
+|	sgl_mant = ext_mant{62:12}
+|
+|	    	---------------   ---------------    ---------------
+|  extended ->  |s|    exp    |   |1| ms mant   |    | ls mant     |
+|	    	---------------   ---------------    ---------------
+|	   	 95	    64    63 62	   40 32      31     12	  0
+|				     |	   |
+|				     |	   |
+|				     |	   |
+|		 	             v     v
+|	    		      ---------------
+|  single   ->  	      |s|exp| mant  |
+|	    		      ---------------
+|	   	 	      31     22     0
+|
+dest_sgl:
+	clrl	%d0
+	movew	LOCAL_EX(%a1),%d0	|get exponent
+	subw	#0x3fff,%d0	|subtract extended precision bias
+	cmpw	#0x4000,%d0	|check if inf
+	beqs	sinf		|if so, special case
+	addw	#0x7f,%d0		|add single precision bias
+	swap	%d0		|put exp in upper word of d0
+	lsll	#7,%d0		|shift it into single exp bits
+	tstb	LOCAL_SGN(%a1)	
+	beqs	get_sman	|if positive, continue
+	bsetl	#31,%d0		|if negative, put in sign first
+	bras	get_sman	|get mantissa
+sinf:
+	movel	#0x7f800000,%d0	|load single inf exp to d0
+	tstb	LOCAL_SGN(%a1)
+	beqs	sgl_wrt		|if positive, continue
+	bsetl	#31,%d0		|if negative, put in sign info
+	bras	sgl_wrt
+
+get_sman:
+	movel	LOCAL_HI(%a1),%d1	|get ms mantissa
+	bfextu	%d1{#1:#23},%d1	|get upper 23 bits of ms
+	orl	%d1,%d0		|put these bits in ms word of single
+
+sgl_wrt:
+	movel	%d0,L_SCR1(%a6)	|put the new exp back on the stack
+	movel	#0x4,%d0		|byte count for single precision number
+	tstl	%a0		|users destination address
+	beqs	sgl_Dn		|destination is a data register
+	exg	%a0,%a1		|a0=supervisor source, a1=user dest
+	leal	L_SCR1(%a6),%a0	|point a0 to data
+	bsrl	mem_write	|move the number to the user's memory
+	rts
+sgl_Dn:
+	bsrl	get_fline	|returns fline word in d0
+	andw	#0x7,%d0		|isolate register number
+	movel	%d0,%d1		|d1 has size:reg formatted for reg_dest
+	orl	#0x10,%d1		|reg_dest wants size added to reg#
+	bral	reg_dest	|size is X, rts in reg_dest will
+|				;return to caller of dest_sgl
+	
+dest_ext:
+	tstb	LOCAL_SGN(%a1)	|put back sign into exponent word
+	beqs	dstx_cont
+	bsetb	#sign_bit,LOCAL_EX(%a1)
+dstx_cont:
+	clrb	LOCAL_SGN(%a1)	|clear out the sign byte
+
+	movel	#0x0c,%d0		|byte count for extended number
+	exg	%a0,%a1		|a0=supervisor source, a1=user dest
+	bsrl	mem_write	|move the number to the user's memory
+	rts
+
+	|end
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/fpsp040/x_unfl.S linux/arch/m68k/fpsp040/x_unfl.S
--- v1.3.93/linux/arch/m68k/fpsp040/x_unfl.S	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/fpsp040/x_unfl.S	Sat Feb 24 22:58:45 1996
@@ -0,0 +1,269 @@
+|
+|	x_unfl.sa 3.4 7/1/91
+|
+|	fpsp_unfl --- FPSP handler for underflow exception
+|
+| Trap disabled results
+|	For 881/2 compatibility, sw must denormalize the intermediate 
+| result, then store the result.  Denormalization is accomplished 
+| by taking the intermediate result (which is always normalized) and 
+| shifting the mantissa right while incrementing the exponent until 
+| it is equal to the denormalized exponent for the destination 
+| format.  After denormalizatoin, the result is rounded to the 
+| destination format.
+|		
+| Trap enabled results
+| 	All trap disabled code applies.	In addition the exceptional 
+| operand needs to made available to the user with a bias of $6000 
+| added to the exponent.
+|
+
+|		Copyright (C) Motorola, Inc. 1990
+|			All Rights Reserved
+|
+|	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA 
+|	The copyright notice above does not evidence any  
+|	actual or intended publication of such source code.
+
+X_UNFL:	|idnt    2,1 | Motorola 040 Floating Point Software Package
+
+	|section	8
+
+	.include "fpsp.h"
+
+	|xref	denorm
+	|xref	round
+	|xref	store
+	|xref	g_rndpr
+	|xref	g_opcls
+	|xref	g_dfmtou
+	|xref	real_unfl
+	|xref	real_inex
+	|xref	fpsp_done
+	|xref	b1238_fix
+
+	.global	fpsp_unfl
+fpsp_unfl:
+	link		%a6,#-LOCAL_SIZE
+	fsave		-(%a7)
+	moveml		%d0-%d1/%a0-%a1,USER_DA(%a6)
+	fmovemx	%fp0-%fp3,USER_FP0(%a6)
+	fmoveml	%fpcr/%fpsr/%fpiar,USER_FPCR(%a6)
+
+|
+	bsrl		unf_res	|denormalize, round & store interm op
+|
+| If underflow exceptions are not enabled, check for inexact
+| exception
+|
+	btstb		#unfl_bit,FPCR_ENABLE(%a6)
+	beqs		ck_inex
+
+	btstb		#E3,E_BYTE(%a6)
+	beqs		no_e3_1
+|
+| Clear dirty bit on dest resister in the frame before branching
+| to b1238_fix.
+|
+	bfextu		CMDREG3B(%a6){#6:#3},%d0	|get dest reg no
+	bclrb		%d0,FPR_DIRTY_BITS(%a6)	|clr dest dirty bit
+	bsrl		b1238_fix		|test for bug1238 case
+	movel		USER_FPSR(%a6),FPSR_SHADOW(%a6)
+	orl		#sx_mask,E_BYTE(%a6)
+no_e3_1:
+	moveml		USER_DA(%a6),%d0-%d1/%a0-%a1
+	fmovemx	USER_FP0(%a6),%fp0-%fp3
+	fmoveml	USER_FPCR(%a6),%fpcr/%fpsr/%fpiar
+	frestore	(%a7)+
+	unlk		%a6
+	bral		real_unfl
+|
+| It is possible to have either inex2 or inex1 exceptions with the
+| unfl.  If the inex enable bit is set in the FPCR, and either
+| inex2 or inex1 occured, we must clean up and branch to the
+| real inex handler.
+|
+ck_inex:
+	moveb		FPCR_ENABLE(%a6),%d0
+	andb		FPSR_EXCEPT(%a6),%d0
+	andib		#0x3,%d0
+	beqs		unfl_done
+
+|
+| Inexact enabled and reported, and we must take an inexact exception
+|	
+take_inex:
+	btstb		#E3,E_BYTE(%a6)
+	beqs		no_e3_2
+|
+| Clear dirty bit on dest resister in the frame before branching
+| to b1238_fix.
+|
+	bfextu		CMDREG3B(%a6){#6:#3},%d0	|get dest reg no
+	bclrb		%d0,FPR_DIRTY_BITS(%a6)	|clr dest dirty bit
+	bsrl		b1238_fix		|test for bug1238 case
+	movel		USER_FPSR(%a6),FPSR_SHADOW(%a6)
+	orl		#sx_mask,E_BYTE(%a6)
+no_e3_2:
+	moveb		#INEX_VEC,EXC_VEC+1(%a6)
+	moveml         USER_DA(%a6),%d0-%d1/%a0-%a1
+	fmovemx        USER_FP0(%a6),%fp0-%fp3
+	fmoveml        USER_FPCR(%a6),%fpcr/%fpsr/%fpiar
+	frestore        (%a7)+
+	unlk            %a6
+	bral		real_inex
+
+unfl_done:
+	bclrb		#E3,E_BYTE(%a6)
+	beqs		e1_set		|if set then branch
+|
+| Clear dirty bit on dest resister in the frame before branching
+| to b1238_fix.
+|
+	bfextu		CMDREG3B(%a6){#6:#3},%d0		|get dest reg no
+	bclrb		%d0,FPR_DIRTY_BITS(%a6)	|clr dest dirty bit
+	bsrl		b1238_fix		|test for bug1238 case
+	movel		USER_FPSR(%a6),FPSR_SHADOW(%a6)
+	orl		#sx_mask,E_BYTE(%a6)
+	moveml		USER_DA(%a6),%d0-%d1/%a0-%a1
+	fmovemx	USER_FP0(%a6),%fp0-%fp3
+	fmoveml	USER_FPCR(%a6),%fpcr/%fpsr/%fpiar
+	frestore	(%a7)+
+	unlk		%a6
+	bral		fpsp_done
+e1_set:
+	moveml		USER_DA(%a6),%d0-%d1/%a0-%a1
+	fmovemx	USER_FP0(%a6),%fp0-%fp3
+	fmoveml	USER_FPCR(%a6),%fpcr/%fpsr/%fpiar
+	unlk		%a6
+	bral		fpsp_done
+|
+|	unf_res --- underflow result calculation
+|
+unf_res:
+	bsrl		g_rndpr		|returns RND_PREC in d0 0=ext,
+|					;1=sgl, 2=dbl
+|					;we need the RND_PREC in the
+|					;upper word for round
+	movew		#0,-(%a7)	
+	movew		%d0,-(%a7)	|copy RND_PREC to stack
+|
+|
+| If the exception bit set is E3, the exceptional operand from the
+| fpu is in WBTEMP; else it is in FPTEMP.
+|
+	btstb		#E3,E_BYTE(%a6)
+	beqs		unf_E1
+unf_E3:
+	lea		WBTEMP(%a6),%a0	|a0 now points to operand
+|
+| Test for fsgldiv and fsglmul.  If the inst was one of these, then
+| force the precision to extended for the denorm routine.  Use
+| the user's precision for the round routine.
+|
+	movew		CMDREG3B(%a6),%d1	|check for fsgldiv or fsglmul
+	andiw		#0x7f,%d1
+	cmpiw		#0x30,%d1		|check for sgldiv
+	beqs		unf_sgl
+	cmpiw		#0x33,%d1		|check for sglmul
+	bnes		unf_cont	|if not, use fpcr prec in round
+unf_sgl:
+	clrl		%d0
+	movew		#0x1,(%a7)	|override g_rndpr precision
+|					;force single
+	bras		unf_cont
+unf_E1:
+	lea		FPTEMP(%a6),%a0	|a0 now points to operand
+unf_cont:
+	bclrb		#sign_bit,LOCAL_EX(%a0)	|clear sign bit
+	sne		LOCAL_SGN(%a0)		|store sign
+
+	bsrl		denorm		|returns denorm, a0 points to it
+|
+| WARNING:
+|				;d0 has guard,round sticky bit
+|				;make sure that it is not corrupted
+|				;before it reaches the round subroutine
+|				;also ensure that a0 isn't corrupted
+
+|
+| Set up d1 for round subroutine d1 contains the PREC/MODE
+| information respectively on upper/lower register halves.
+|
+	bfextu		FPCR_MODE(%a6){#2:#2},%d1	|get mode from FPCR
+|						;mode in lower d1
+	addl		(%a7)+,%d1		|merge PREC/MODE
+|
+| WARNING: a0 and d0 are assumed to be intact between the denorm and
+| round subroutines. All code between these two subroutines
+| must not corrupt a0 and d0.
+|
+|
+| Perform Round	
+|	Input:		a0 points to input operand
+|			d0{31:29} has guard, round, sticky
+|			d1{01:00} has rounding mode
+|			d1{17:16} has rounding precision
+|	Output:		a0 points to rounded operand
+|
+
+	bsrl		round		|returns rounded denorm at (a0)
+|
+| Differentiate between store to memory vs. store to register
+|
+unf_store:
+	bsrl		g_opcls		|returns opclass in d0{2:0}
+	cmpib		#0x3,%d0
+	bnes		not_opc011
+|
+| At this point, a store to memory is pending
+|
+opc011:
+	bsrl		g_dfmtou
+	tstb		%d0
+	beqs		ext_opc011	|If extended, do not subtract
+| 				;If destination format is sgl/dbl, 
+	tstb		LOCAL_HI(%a0)	|If rounded result is normal,don't
+|					;subtract
+	bmis		ext_opc011
+	subqw		#1,LOCAL_EX(%a0)	|account for denorm bias vs.
+|				;normalized bias
+|				;          normalized   denormalized
+|				;single       $7f           $7e
+|				;double       $3ff          $3fe
+|
+ext_opc011:
+	bsrl		store		|stores to memory
+	bras		unf_done	|finish up
+
+|
+| At this point, a store to a float register is pending
+|
+not_opc011:
+	bsrl		store	|stores to float register
+|				;a0 is not corrupted on a store to a
+|				;float register.
+|
+| Set the condition codes according to result
+|
+	tstl		LOCAL_HI(%a0)	|check upper mantissa
+	bnes		ck_sgn
+	tstl		LOCAL_LO(%a0)	|check lower mantissa
+	bnes		ck_sgn
+	bsetb		#z_bit,FPSR_CC(%a6) |set condition codes if zero
+ck_sgn:
+	btstb 		#sign_bit,LOCAL_EX(%a0)	|check the sign bit
+	beqs		unf_done
+	bsetb		#neg_bit,FPSR_CC(%a6)
+
+|
+| Finish.  
+|
+unf_done:
+	btstb		#inex2_bit,FPSR_EXCEPT(%a6)
+	beqs		no_aunfl
+	bsetb		#aunfl_bit,FPSR_AEXCEPT(%a6)
+no_aunfl:
+	rts
+
+	|end
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/fpsp040/x_unimp.S linux/arch/m68k/fpsp040/x_unimp.S
--- v1.3.93/linux/arch/m68k/fpsp040/x_unimp.S	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/fpsp040/x_unimp.S	Sat Feb 24 22:58:45 1996
@@ -0,0 +1,77 @@
+|
+|	x_unimp.sa 3.3 7/1/91
+|
+|	fpsp_unimp --- FPSP handler for unimplemented instruction	
+|	exception.
+|
+| Invoked when the user program encounters a floating-point
+| op-code that hardware does not support.  Trap vector# 11
+| (See table 8-1 MC68030 User's Manual).
+|
+| 
+| Note: An fsave for an unimplemented inst. will create a short
+| fsave stack.
+|
+|  Input: 1. Six word stack frame for unimplemented inst, four word
+|            for illegal
+|            (See table 8-7 MC68030 User's Manual).
+|         2. Unimp (short) fsave state frame created here by fsave
+|            instruction.
+|
+|
+|		Copyright (C) Motorola, Inc. 1990
+|			All Rights Reserved
+|
+|	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA 
+|	The copyright notice above does not evidence any  
+|	actual or intended publication of such source code.
+
+X_UNIMP:	|idnt    2,1 | Motorola 040 Floating Point Software Package
+
+	|section	8
+
+	.include "fpsp.h"
+
+	|xref	get_op
+	|xref	do_func
+	|xref	sto_res
+	|xref	gen_except
+	|xref	fpsp_fmt_error
+
+	.global	fpsp_unimp
+	.global	uni_2
+fpsp_unimp:
+	link		%a6,#-LOCAL_SIZE
+	fsave		-(%a7)
+uni_2:
+	moveml		%d0-%d1/%a0-%a1,USER_DA(%a6)
+	fmovemx	%fp0-%fp3,USER_FP0(%a6)
+	fmoveml	%fpcr/%fpsr/%fpiar,USER_FPCR(%a6)
+	moveb		(%a7),%d0		|test for valid version num
+	andib		#0xf0,%d0		|test for $4x
+	cmpib		#VER_4,%d0	|must be $4x or exit
+	bnel		fpsp_fmt_error
+|
+|	Temporary D25B Fix
+|	The following lines are used to ensure that the FPSR
+|	exception byte and condition codes are clear before proceeding
+|
+	movel		USER_FPSR(%a6),%d0
+	andl		#0xFF00FF,%d0	|clear all but accrued exceptions
+	movel		%d0,USER_FPSR(%a6)
+	fmovel		#0,%FPSR |clear all user bits
+	fmovel		#0,%FPCR	|clear all user exceptions for FPSP
+
+	clrb		UFLG_TMP(%a6)	|clr flag for unsupp data
+
+	bsrl		get_op		|go get operand(s)
+	clrb		STORE_FLG(%a6)
+	bsrl		do_func		|do the function
+	fsave		-(%a7)		|capture possible exc state
+	tstb		STORE_FLG(%a6)
+	bnes		no_store	|if STORE_FLG is set, no store
+	bsrl		sto_res		|store the result in user space
+no_store:
+	bral		gen_except	|post any exceptions and return
+
+	|end
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/fpsp040/x_unsupp.S linux/arch/m68k/fpsp040/x_unsupp.S
--- v1.3.93/linux/arch/m68k/fpsp040/x_unsupp.S	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/fpsp040/x_unsupp.S	Sat Feb 24 22:58:45 1996
@@ -0,0 +1,83 @@
+|
+|	x_unsupp.sa 3.3 7/1/91
+|
+|	fpsp_unsupp --- FPSP handler for unsupported data type exception
+|
+| Trap vector #55	(See table 8-1 Mc68030 User's manual).	
+| Invoked when the user program encounters a data format (packed) that
+| hardware does not support or a data type (denormalized numbers or un-
+| normalized numbers).
+| Normalizes denorms and unnorms, unpacks packed numbers then stores 
+| them back into the machine to let the 040 finish the operation.  
+|
+| Unsupp calls two routines:
+| 	1. get_op -  gets the operand(s)
+| 	2. res_func - restore the function back into the 040 or
+| 			if fmove.p fpm,<ea> then pack source (fpm)
+| 			and store in users memory <ea>.
+|
+|  Input: Long fsave stack frame
+|
+|
+
+|		Copyright (C) Motorola, Inc. 1990
+|			All Rights Reserved
+|
+|	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA 
+|	The copyright notice above does not evidence any  
+|	actual or intended publication of such source code.
+
+X_UNSUPP:	|idnt    2,1 | Motorola 040 Floating Point Software Package
+
+	|section	8
+
+	.include "fpsp.h"
+
+	|xref	get_op
+	|xref	res_func
+	|xref	gen_except
+	|xref	fpsp_fmt_error
+
+	.global	fpsp_unsupp
+fpsp_unsupp:
+|
+	link		%a6,#-LOCAL_SIZE
+	fsave		-(%a7)
+	moveml		%d0-%d1/%a0-%a1,USER_DA(%a6)
+	fmovemx	%fp0-%fp3,USER_FP0(%a6)
+	fmoveml	%fpcr/%fpsr/%fpiar,USER_FPCR(%a6)
+
+
+	moveb		(%a7),VER_TMP(%a6) |save version number
+	moveb		(%a7),%d0		|test for valid version num
+	andib		#0xf0,%d0		|test for $4x
+	cmpib		#VER_4,%d0	|must be $4x or exit
+	bnel		fpsp_fmt_error
+
+	fmovel		#0,%FPSR		|clear all user status bits
+	fmovel		#0,%FPCR		|clear all user control bits
+|
+|	The following lines are used to ensure that the FPSR
+|	exception byte and condition codes are clear before proceeding,
+|	except in the case of fmove, which leaves the cc's intact.
+|
+unsupp_con:
+	movel		USER_FPSR(%a6),%d1
+	btst		#5,CMDREG1B(%a6)	|looking for fmove out
+	bne		fmove_con
+	andl		#0xFF00FF,%d1	|clear all but aexcs and qbyte
+	bras		end_fix
+fmove_con:
+	andl		#0x0FFF40FF,%d1	|clear all but cc's, snan bit, aexcs, and qbyte
+end_fix:
+	movel		%d1,USER_FPSR(%a6)
+
+	st		UFLG_TMP(%a6)	|set flag for unsupp data
+
+	bsrl		get_op		|everything okay, go get operand(s)
+	bsrl		res_func	|fix up stack frame so can restore it
+	clrl		-(%a7)
+	moveb		VER_TMP(%a6),(%a7) |move idle fmt word to top of stack
+	bral		gen_except
+|
+	|end
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/ifpsp060/CHANGES linux/arch/m68k/ifpsp060/CHANGES
--- v1.3.93/linux/arch/m68k/ifpsp060/CHANGES	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/ifpsp060/CHANGES	Mon Jan  8 22:08:12 1996
@@ -0,0 +1,120 @@
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+MOTOROLA MICROPROCESSOR & MEMORY TECHNOLOGY GROUP
+M68000 Hi-Performance Microprocessor Division
+M68060 Software Package
+Production Release P1.00 -- October 10, 1994
+
+M68060 Software Package Copyright © 1993, 1994 Motorola Inc.  All rights reserved.
+ 
+THE SOFTWARE is provided on an "AS IS" basis and without warranty.
+To the maximum extent permitted by applicable law,
+MOTOROLA DISCLAIMS ALL WARRANTIES WHETHER EXPRESS OR IMPLIED, 
+INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+and any warranty against infringement with regard to the SOFTWARE
+(INCLUDING ANY MODIFIED VERSIONS THEREOF) and any accompanying written materials.
+
+To the maximum extent permitted by applicable law,
+IN NO EVENT SHALL MOTOROLA BE LIABLE FOR ANY DAMAGES WHATSOEVER
+(INCLUDING WITHOUT LIMITATION, DAMAGES FOR LOSS OF BUSINESS PROFITS,
+BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION, OR OTHER PECUNIARY LOSS)
+ARISING OF THE USE OR INABILITY TO USE THE SOFTWARE.
+Motorola assumes no responsibility for the maintenance and support of the SOFTWARE.
+
+You are hereby granted a copyright license to use, modify, and distribute the SOFTWARE
+so long as this entire notice is retained without alteration in any modified and/or
+redistributed versions, and that such modified versions are clearly identified as such.
+No licenses are granted by implication, estoppel or otherwise under any patents
+or trademarks of Motorola, Inc.
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+CHANGES SINCE LAST RELEASE:
+---------------------------
+
+1) "movep" emulation where data was being read from memory
+was reading the intermediate bytes. Emulation now only 
+reads the required bytes.
+
+2) "flogn", "flog2", and "flog10" of "1" was setting the
+Inexact FPSR bit. Emulation now does not set Inexact for
+this case.
+
+3) For an opclass three FP instruction where the effective addressing
+mode was pre-decrement or post-increment and the address register
+was A0 or A1, the address register was not being updated as a result
+of the operation. This has been corrected.
+
+4) Beta B.2 version had the following erratum:
+
+	Scenario:
+	---------
+	If {i,d}mem_{read,write}_{byte,word,long}() returns
+	a failing value to the 68060SP, the package ignores
+	this return value and continues with program execution
+	as if it never received a failing value.
+
+	Effect:
+	-------
+	For example, if a user executed "fsin.x ADDR,fp0" where
+	ADDR should cause a "segmentation violation", the memory read
+	requested by the package should return a failing value
+	to the package. Since the package currently ignores this 
+	return value, the user program will continue to the
+	next instruction, and the result created in fp0 will be
+	undefined.
+
+	Fix:
+	----
+	This has been fixed in the current release.
+
+	Notes:
+	------
+	Upon receiving a non-zero (failing) return value from
+	a {i,d}mem_{read,write}_{byte,word,long}() "call-out",
+	the package creates a 16-byte access error stack frame
+	from the current exception stack frame and exits
+	through the "call-out" _real_access(). This is the process
+	as described in the MC68060 User's Manual.
+
+	For instruction read access errors, the info stacked is:
+		SR 	= SR at time of exception
+		PC 	= PC of instruction being emulated
+		VOFF	= $4008 (stack frame format type)
+		ADDRESS	= PC of instruction being emulated
+		FSLW	= FAULT STATUS LONGWORD
+
+	The valid FSLW bits are:
+		bit 27 		= 1	(misaligned bit)
+		bit 24 		= 1	(read)
+		bit 23 		= 0	(write)
+		bit 22:21	= 10	(SIZE = word)
+		bit 20:19	= 00	(TT)
+		bit 18:16	= x10	(TM; x = 1 for supervisor mode)
+		bit 15		= 1	(IO)
+		bit 0		= 1	(Software Emulation Error)
+
+	all other bits are EQUAL TO ZERO and can be set by the _real_access()
+	"call-out" stub by the user as appropriate. The MC68060 User's Manual
+	stated that ONLY "bit 0" would be set. The 060SP attempts to set a few
+	other bits.
+
+	For data read/write access errors, the info stacked is:
+		SR 	= SR at time of exception
+		PC 	= PC of instruction being emulated
+		VOFF	= $4008 (stack frame format type)
+		ADDRESS	= Address of source or destination operand
+		FSLW	= FAULT STATUS LONGWORD
+
+	The valid FSLW bits are:
+		bit 27 		= 0	(misaligned bit)
+		bit 24 		= x	(read; 1 if read, 0 if write)
+		bit 23		= x	(write; 1 if write, 0 if read)
+		bit 22:21	= xx	(SIZE; see MC68060 User's Manual)
+		bit 20:19	= 00	(TT)
+		bit 18:16	= x01	(TM; x = 1 for supervisor mode)
+		bit 15		= 0	(IO)
+		bit 0		= 1	(Software Emulation Error)
+
+	all other bits are EQUAL TO ZERO and can be set by the _real_access()
+	"call-out" stub by the user as appropriate. The MC68060 User's Manual
+	stated that ONLY "bit 0" would be set. The 060SP attempts to set a few
+	other bits.
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/ifpsp060/MISC linux/arch/m68k/ifpsp060/MISC
--- v1.3.93/linux/arch/m68k/ifpsp060/MISC	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/ifpsp060/MISC	Mon Jan  8 22:08:12 1996
@@ -0,0 +1,201 @@
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+MOTOROLA MICROPROCESSOR & MEMORY TECHNOLOGY GROUP
+M68000 Hi-Performance Microprocessor Division
+M68060 Software Package
+Production Release P1.00 -- October 10, 1994
+
+M68060 Software Package Copyright © 1993, 1994 Motorola Inc.  All rights reserved.
+ 
+THE SOFTWARE is provided on an "AS IS" basis and without warranty.
+To the maximum extent permitted by applicable law,
+MOTOROLA DISCLAIMS ALL WARRANTIES WHETHER EXPRESS OR IMPLIED, 
+INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+and any warranty against infringement with regard to the SOFTWARE
+(INCLUDING ANY MODIFIED VERSIONS THEREOF) and any accompanying written materials.
+
+To the maximum extent permitted by applicable law,
+IN NO EVENT SHALL MOTOROLA BE LIABLE FOR ANY DAMAGES WHATSOEVER
+(INCLUDING WITHOUT LIMITATION, DAMAGES FOR LOSS OF BUSINESS PROFITS,
+BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION, OR OTHER PECUNIARY LOSS)
+ARISING OF THE USE OR INABILITY TO USE THE SOFTWARE.
+Motorola assumes no responsibility for the maintenance and support of the SOFTWARE.
+
+You are hereby granted a copyright license to use, modify, and distribute the SOFTWARE
+so long as this entire notice is retained without alteration in any modified and/or
+redistributed versions, and that such modified versions are clearly identified as such.
+No licenses are granted by implication, estoppel or otherwise under any patents
+or trademarks of Motorola, Inc.
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+RELEASE FILE VERSIONS:
+-----------------------
+
+fpsp.sa
+----------
+freal.s     : 2.4
+hdr.fpu     : 2.4
+x_fovfl.s   : 2.16
+x_funfl.s   : 2.19
+x_funsupp.s : 2.27
+x_effadd.s  : 2.21
+x_foperr.s  : 2.9
+x_fsnan.s   : 2.12
+x_finex.s   : 2.14
+x_fdz.s     : 2.5
+x_fline.s   : 2.5
+x_funimp.s  : 2.27
+fsin.s      : 2.6
+ftan.s      : 2.6
+fatan.s     : 2.3
+fasin.s     : 2.3
+facos.s     : 2.5
+fetox.s     : 2.4
+fgetem.s    : 2.5
+fcosh.s     : 2.4
+fsinh.s     : 2.5
+ftanh.s     : 2.3
+flogn.s     : 2.6
+fatanh.s    : 2.4
+flog2.s     : 2.4
+ftwotox.s   : 2.4
+fmovecr.s   : 2.5
+fscale.s    : 2.5
+frem_mod.s  : 2.6
+fkern.s     : 2.6
+fkern2.s    : 2.5
+fgen_except.s: 2.7
+foptbl.s    : 2.3
+fmul.s      : 2.5
+fin.s       : 2.4
+fdiv.s      : 2.5
+fneg.s      : 2.4
+ftst.s      : 2.3
+fint.s      : 2.3
+fintrz.s    : 2.3
+fabs.s      : 2.4
+fcmp.s      : 2.4
+fsglmul.s   : 2.5
+fsgldiv.s   : 2.8
+fadd.s      : 2.6
+fsub.s      : 2.6
+fsqrt.s     : 2.4
+fmisc.s     : 2.3
+fdbcc.s     : 2.8
+ftrapcc.s   : 2.5
+fscc.s      : 2.6
+fmovm.s     : 2.15
+fctrl.s     : 2.6
+fcalc_ea.s  : 2.7
+fmem.s      : 2.9
+fout.s      : 2.9
+ireg.s      : 2.6
+fdenorm.s   : 2.3
+fround.s    : 2.4
+fnorm.s     : 2.3
+foptag_set.s: 2.4
+fresult.s   : 2.3
+fpack.s     : 2.6
+fdecbin.s   : 2.4
+fbindec.s   : 2.5
+fbinstr.s   : 2.3
+faccess.s   : 2.3
+
+pfpsp.sa
+----------
+freal.s     : 2.4
+hdr.fpu     : 2.4
+x_fovfl.s   : 2.16
+x_funfl.s   : 2.19
+x_funsupp.s : 2.27
+x_effadd.s  : 2.21
+x_foperr.s  : 2.9
+x_fsnan.s   : 2.12
+x_finex.s   : 2.14
+x_fdz.s     : 2.5
+x_fline2.s  : 2.3
+fcalc_ea.s  : 2.7
+foptbl2.s   : 2.4
+fmovm.s     : 2.15
+fctrl.s     : 2.6
+fmisc.s     : 2.3
+fdenorm.s   : 2.3
+fround.s    : 2.4
+fnorm.s     : 2.3
+foptag_set.s: 2.4
+fresult.s   : 2.3
+fout.s      : 2.9
+fmul.s      : 2.5
+fin.s       : 2.4
+fdiv.s      : 2.5
+fneg.s      : 2.4
+ftst.s      : 2.3
+fint.s      : 2.3
+fintrz.s    : 2.3
+fabs.s      : 2.4
+fcmp.s      : 2.4
+fsglmul.s   : 2.5
+fsgldiv.s   : 2.8
+fadd.s      : 2.6
+fsub.s      : 2.6
+fsqrt.s     : 2.4
+ireg.s      : 2.6
+fpack.s     : 2.6
+fdecbin.s   : 2.4
+fbindec.s   : 2.5
+fbinstr.s   : 2.3
+faccess.s   : 2.3
+
+fplsp.sa
+----------
+lfptop.s    : 2.3
+hdr.fpu     : 2.4
+fsin.s      : 2.6
+ftan.s      : 2.6
+fatan.s     : 2.3
+fasin.s     : 2.3
+facos.s     : 2.5
+fetox.s     : 2.4
+fgetem.s    : 2.5
+fcosh.s     : 2.4
+fsinh.s     : 2.5
+ftanh.s     : 2.3
+flogn.s     : 2.6
+fatanh.s    : 2.4
+flog2.s     : 2.4
+ftwotox.s   : 2.4
+fscale.s    : 2.5
+frem_mod.s  : 2.6
+l_support.s : 2.15
+fnorm.s     : 2.3
+
+isp.sa
+----------
+ireal.s     : 2.4
+hdr.int     : 2.4
+x_uieh.s    : 2.13
+icalc_ea.s  : 2.11
+imovep.s    : 2.8
+ichk2cmp2.s : 2.6
+idiv64.s    : 2.10
+imul64.s    : 
+icas2.s     : 2.11
+icas.s      : 2.12
+icas2_core.s: 2.6
+icas_core.s : 2.6
+
+ilsp.sa
+----------
+litop.s     : 2.2
+l_idiv64.s  : 2.8
+l_imul64.s  : 2.6
+l_ichk2cmp2.s: 2.5
+
+ex. files
+----------
+wrk/fskeleton.s: 2.2
+wrk/iskeleton.s: 2.2
+wrk/os.s    : 2.1
+
+tests
+----------
+itest.s     : 2.2
+ftest.s     : 2.1
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/ifpsp060/Makefile linux/arch/m68k/ifpsp060/Makefile
--- v1.3.93/linux/arch/m68k/ifpsp060/Makefile	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/ifpsp060/Makefile	Sat Feb 24 14:51:12 1996
@@ -0,0 +1,28 @@
+# Makefile for 680x0 Linux 68060 integer/floating point support package
+#
+# This file is subject to the terms and conditions of the GNU General Public
+# License.  See the file "README.legal" in the main directory of this archive
+# for more details.
+
+#.c.s:
+#	$(CC) $(CFLAGS) -S $<
+#.c.o:
+#	$(CC) $(CFLAGS) -c $<
+#.s.o:
+#	$(AS) -o $*.o $<
+.S.o:
+	$(AS) -o $*.o $<
+#	$(CC) -D__ASSEMBLY__ -traditional -c -o $*.o $<
+
+OS_TARGET := ifpsp.o
+
+OS_OBJS	  := fskeleton.o iskeleton.o os.o
+
+all:	$(OS_TARGET)
+
+include $(TOPDIR)/Rules.make
+
+$(OS_OBJS):
+
+$(OS_TARGET): $(OS_OBJS)
+	$(LD) -x -r -o $(OS_TARGET) $(OS_OBJS)
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/ifpsp060/README linux/arch/m68k/ifpsp060/README
--- v1.3.93/linux/arch/m68k/ifpsp060/README	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/ifpsp060/README	Mon Jan  8 22:08:13 1996
@@ -0,0 +1,71 @@
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+MOTOROLA MICROPROCESSOR & MEMORY TECHNOLOGY GROUP
+M68000 Hi-Performance Microprocessor Division
+M68060 Software Package
+Production Release P1.00 -- October 10, 1994
+
+M68060 Software Package Copyright © 1993, 1994 Motorola Inc.  All rights reserved.
+ 
+THE SOFTWARE is provided on an "AS IS" basis and without warranty.
+To the maximum extent permitted by applicable law,
+MOTOROLA DISCLAIMS ALL WARRANTIES WHETHER EXPRESS OR IMPLIED, 
+INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+and any warranty against infringement with regard to the SOFTWARE
+(INCLUDING ANY MODIFIED VERSIONS THEREOF) and any accompanying written materials.
+
+To the maximum extent permitted by applicable law,
+IN NO EVENT SHALL MOTOROLA BE LIABLE FOR ANY DAMAGES WHATSOEVER
+(INCLUDING WITHOUT LIMITATION, DAMAGES FOR LOSS OF BUSINESS PROFITS,
+BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION, OR OTHER PECUNIARY LOSS)
+ARISING OF THE USE OR INABILITY TO USE THE SOFTWARE.
+Motorola assumes no responsibility for the maintenance and support of the SOFTWARE.
+
+You are hereby granted a copyright license to use, modify, and distribute the SOFTWARE
+so long as this entire notice is retained without alteration in any modified and/or
+redistributed versions, and that such modified versions are clearly identified as such.
+No licenses are granted by implication, estoppel or otherwise under any patents
+or trademarks of Motorola, Inc.
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Files in this directory:
+-------------------------
+
+fpsp.sa		Full FP Kernel Module - hex image
+fpsp.s		Full FP Kernel Module - source code
+fpsp.doc	Full FP Kernel Module - on-line documentation
+
+pfpsp.sa	Partial FP Kernel Module - hex image
+pfpsp.s		Partial FP Kernel Module - source code
+
+fplsp.sa	FP Library Module - hex image
+fplsp.s		FP Library Module - source code
+fplsp.doc	FP Library Module - on-line documentation
+
+isp.sa		Integer Unimplemented Kernel Module - hex image
+isp.s		Integer Unimplemented Kernel Module - source code
+isp.doc		Integer Unimplemented Kernel Module - on-line doc
+
+ilsp.sa		Integer Unimplemented Library Module - hex image
+ilsp.s		Integer Unimplemented Library Module - source code
+ilsp.doc	Integer Unimplemented Library Module - on-line doc
+
+fskeleton.s	Sample Call-outs needed by fpsp.sa and pfpsp.sa
+
+iskeleton.s	Sample Call-outs needed by isp.sa
+
+os.s		Sample Call-outs needed by fpsp.sa, pfpsp.sa, and isp.sa
+
+ftest.sa	Simple test program to test that {p}fpsp.sa
+		was connected properly; hex image
+ftest.s		above test; source code
+
+itest.sa	Simple test program to test that isp.sa was
+		connected properly; hex image
+itest.s		above test; source code
+
+test.doc	on-line documentation for {i,f}test.sa
+
+README		This file
+
+ERRATA		Known errata for this release
+
+MISC		Release file version numbers
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/ifpsp060/TEST.DOC linux/arch/m68k/ifpsp060/TEST.DOC
--- v1.3.93/linux/arch/m68k/ifpsp060/TEST.DOC	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/ifpsp060/TEST.DOC	Mon Jan  8 22:08:13 1996
@@ -0,0 +1,208 @@
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+MOTOROLA MICROPROCESSOR & MEMORY TECHNOLOGY GROUP
+M68000 Hi-Performance Microprocessor Division
+M68060 Software Package
+Production Release P1.00 -- October 10, 1994
+
+M68060 Software Package Copyright © 1993, 1994 Motorola Inc.  All rights reserved.
+ 
+THE SOFTWARE is provided on an "AS IS" basis and without warranty.
+To the maximum extent permitted by applicable law,
+MOTOROLA DISCLAIMS ALL WARRANTIES WHETHER EXPRESS OR IMPLIED, 
+INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+and any warranty against infringement with regard to the SOFTWARE
+(INCLUDING ANY MODIFIED VERSIONS THEREOF) and any accompanying written materials.
+
+To the maximum extent permitted by applicable law,
+IN NO EVENT SHALL MOTOROLA BE LIABLE FOR ANY DAMAGES WHATSOEVER
+(INCLUDING WITHOUT LIMITATION, DAMAGES FOR LOSS OF BUSINESS PROFITS,
+BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION, OR OTHER PECUNIARY LOSS)
+ARISING OF THE USE OR INABILITY TO USE THE SOFTWARE.
+Motorola assumes no responsibility for the maintenance and support of the SOFTWARE.
+
+You are hereby granted a copyright license to use, modify, and distribute the SOFTWARE
+so long as this entire notice is retained without alteration in any modified and/or
+redistributed versions, and that such modified versions are clearly identified as such.
+No licenses are granted by implication, estoppel or otherwise under any patents
+or trademarks of Motorola, Inc.
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+68060 SOFTWARE PACKAGE (Kernel version) SIMPLE TESTS
+-----------------------------------------------------
+
+The files itest.sa and ftest.sa contain simple tests to check
+the state of the 68060ISP and 68060FPSP once they have been installed.
+
+Release file format:
+--------------------
+The release files itest.sa and ftest.sa are essentially
+hexadecimal images of the actual tests. This format is the
+ONLY format that will be supported. The hex images were created
+by assembling the source code and then converting the resulting
+binary output images into ASCII text files. The hexadecimal
+numbers are listed using the Motorola Assembly syntax assembler
+directive "dc.l" (define constant longword). The files can be
+converted to other assembly syntaxes by using any word processor
+with a global search and replace function.
+
+To assist in assembling and linking these modules with other modules,
+the instaler should add symbolic labels to the top of the files.
+This will allow the calling routines to access the entry points
+of these packages.
+
+The source code itest.s and ftest.s have been included but only
+for documentation purposes.
+
+Release file structure:
+-----------------------
+
+(top of module)
+	----------------- 
+	|		| - 128 byte-sized section
+   (1)  |   Call-Out	| - 4 bytes per entry (user fills these in)
+	|		|
+	-----------------
+	|		| - 8 bytes per entry
+   (2)  | Entry Point	| - user does "bsr" or "jsr" to this address
+	|		|
+	-----------------
+	|		| - code section
+   (3)  ~		~
+	|		|
+	-----------------
+(bottom of module)
+
+The first section of this module is the "Call-out" section. This section
+is NOT INCLUDED in {i,f}test.sa (an example "Call-out" section is provided at
+the end of this file). The purpose of this section is to allow the test
+routines to reference external printing functions that must be provided 
+by the host operating system. This section MUST be exactly 128 bytes in 
+size. There are 32 fields, each 4 bytes in size. Each field corresponds
+to a function required by the test packages (these functions and their
+location are listed in "68060{ISP,FPSP}-TEST call-outs" below). Each field
+entry should contain the address of the corresponding function RELATIVE to
+the starting address of the "call-out" section. The "Call-out" section must
+sit adjacent to the {i,f}test.sa image in memory. Since itest.sa and ftest.sa
+are individual tests, they each require their own "Call-out" sections.
+
+The second section, the "Entry-point" section, is used by external routines
+to access the test routines. Since the {i,f}test.sa hex files contain
+no symbol names, this section contains function entry points that are fixed
+with respect to the top of the package. The currently defined entry-points
+are listed in section "68060{ISP,FPSP}-TEST entry points" below. A calling
+routine would simply execute a "bsr" or "jsr" that jumped to the selected
+function entry-point.
+
+For example, to run the 060ISP test, write a program that includes the
+itest.sa data and execute something similar to:
+
+	bsr	_060ISP_TEST+128+0
+
+(_060ISP_TEST is the starting address of the "Call-out" section; the "Call-out"
+section is 128 bytes long; and the 68060ISP test entry point is located
+0 bytes from the top of the "Entry-point" section.)
+
+The third section is the code section. After entering through an "Entry-point",
+the entry code jumps to the appropriate test code within the code section.
+
+68060ISP-TEST Call-outs:
+------------------------
+0x0: _print_string()
+0x4: _print_number()
+
+68060FPSP-TEST Call-outs:
+-------------------------
+0x0: _print_string()
+0x4: _print_number()
+
+The test packages call _print_string() and _print_number()
+as subroutines and expect the main program to print a string
+or a number to a file or to the screen.
+In "C"-like fashion, the test program calls:
+
+	print_string("Test passed");
+
+		or
+
+	print_number(20);
+
+For _print_string(), the test programs pass a longword address
+of the string on the stack. For _print_number(), the test programs pass
+a longword number to be printed.
+
+For debugging purposes, after the main program performs a "print"
+for a test package, it should flush the output so that it's not
+buffered. In this way, if the test program crashes, at least the previous
+statements printed will be seen.
+
+68060ISP-TEST Entry-points:
+---------------------------
+0x0: integer test
+
+68060FPSP-TEST Entry-points:
+----------------------------
+0x00: main fp test
+0x08: FP unimplemented test
+0x10: FP enabled snan/operr/ovfl/unfl/dz/inex
+
+The floating-point unit test has 3 entry points which will require
+3 different calls to the package if each of the three following tests
+is desired:
+
+main fp test: tests (1) unimp effective address exception
+		    (2) unsupported data type exceptions
+		    (3) non-maskable overflow/underflow exceptions
+
+FP unimplemented: tests FP unimplemented exception. this one is 
+		  separate from the previous tests for systems that don't
+		  want FP unimplemented instructions.
+
+FP enabled: tests enabled snan/operr/ovfl/unfl/dz/inex.
+	    basically, it enables each of these exceptions and forces
+	    each using an implemented FP instruction. this process
+	    exercizes _fpsp_{snan,operr,ovfl,unfl,dz,inex}() and
+	    _real_{snan,operr,ovfl,unfl,dz,inex}(). the test expects
+	    _real_XXXX() to do nothing except clear the exception
+	    and "rte". if a system's _real_XXXX() handler creates an
+	    alternate result, the test will print "failed" but this
+	    is acceptable.
+
+Miscellaneous:
+--------------
+Again, itest.sa and ftest.sa are simple tests and do not thoroughly
+test all 68060SP connections. For example, they do not test connections
+to _real_access(), _real_trace(), _real_trap(), etc. because these
+will be system-implemented several different ways and the test packages
+must remain system independent.
+
+Example test package set-up:
+----------------------------
+_print_str:
+	.			# provided by system
+	rts
+
+_print_num:
+	.			# provided by system
+	rts
+
+	.
+	.
+	bsr	_060FPSP_TEST+128+0
+	.
+	.
+	rts
+
+# beginning of "Call-out" section; provided by integrator.
+# MUST be 128 bytes long.
+_060FPSP_TEST:
+	long	_print_str - _060FPSP_TEST	
+	long	_print_num - _060FPSP_TEST
+	space	120
+
+# ftest.sa starts here; start of "Entry-point" section.
+	long	0x60ff0000, 0x00002346
+	long	0x60ff0000, 0x00018766
+	long	0x60ff0000, 0x00023338
+	long	0x24377299, 0xab2643ea
+		.
+		.
+		.
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/ifpsp060/fplsp.doc linux/arch/m68k/ifpsp060/fplsp.doc
--- v1.3.93/linux/arch/m68k/ifpsp060/fplsp.doc	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/ifpsp060/fplsp.doc	Mon Jan  8 22:08:13 1996
@@ -0,0 +1,231 @@
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+MOTOROLA MICROPROCESSOR & MEMORY TECHNOLOGY GROUP
+M68000 Hi-Performance Microprocessor Division
+M68060 Software Package
+Production Release P1.00 -- October 10, 1994
+
+M68060 Software Package Copyright © 1993, 1994 Motorola Inc.  All rights reserved.
+ 
+THE SOFTWARE is provided on an "AS IS" basis and without warranty.
+To the maximum extent permitted by applicable law,
+MOTOROLA DISCLAIMS ALL WARRANTIES WHETHER EXPRESS OR IMPLIED, 
+INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+and any warranty against infringement with regard to the SOFTWARE
+(INCLUDING ANY MODIFIED VERSIONS THEREOF) and any accompanying written materials.
+
+To the maximum extent permitted by applicable law,
+IN NO EVENT SHALL MOTOROLA BE LIABLE FOR ANY DAMAGES WHATSOEVER
+(INCLUDING WITHOUT LIMITATION, DAMAGES FOR LOSS OF BUSINESS PROFITS,
+BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION, OR OTHER PECUNIARY LOSS)
+ARISING OF THE USE OR INABILITY TO USE THE SOFTWARE.
+Motorola assumes no responsibility for the maintenance and support of the SOFTWARE.
+
+You are hereby granted a copyright license to use, modify, and distribute the SOFTWARE
+so long as this entire notice is retained without alteration in any modified and/or
+redistributed versions, and that such modified versions are clearly identified as such.
+No licenses are granted by implication, estoppel or otherwise under any patents
+or trademarks of Motorola, Inc.
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+68060 FLOATING-POINT SOFTWARE PACKAGE (Library version)
+--------------------------------------------------------
+
+The file fplsp.sa contains the "Library version" of the
+68060SP Floating-Point Software Package. The routines
+included in this module can be used to emulate the
+FP instructions not implemented in 68060 hardware. These
+instructions normally take exception vector #11 
+"FP Unimplemented Instruction".
+
+By re-compiling a program that uses these instructions, and
+making subroutine calls in place of the unimplemented
+instructions, a program can avoid the overhead associated
+with taking the exception.
+
+Release file format:
+--------------------
+The file fplsp.sa is essentially a hexadecimal image of the
+release package. This is the ONLY format which will be supported.
+The hex image was created by assembling the source code and
+then converting the resulting binary output image into an
+ASCII text file. The hexadecimal numbers are listed
+using the Motorola Assembly Syntax assembler directive "dc.l"
+(define constant longword). The file can be converted to other
+assembly syntaxes by using any word processor with a global
+search and replace function.
+
+To assist in assembling and linking this module with other modules,
+the installer should add a symbolic label to the top of the file.
+This will allow calling routines to access the entry points
+of this package.
+
+The source code fplsp.s has also been included but only for
+documentation purposes.
+
+Release file structure:
+-----------------------
+The file fplsp.sa contains an "Entry-Point" section and a
+code section. The FPLSP has no "Call-Out" section. The first section
+is the "Entry-Point" section. In order to access a function in the
+package, a program must "bsr" or "jsr" to the location listed
+below in "68060FPLSP entry points" that corresponds to the desired
+function. A branch instruction located at the selected entry point
+within the package will then enter the correct emulation code routine.
+
+The entry point addresses at the beginning of the package will remain
+fixed so that a program calling the routines will not have to be
+re-compiled with every new 68060FPLSP release.
+
+There are 3 entry-points for each instruction type: single precision,
+double precision, and extended precision.
+
+As an example, the "fsin" library instruction can be passed an
+extended precision operand if program executes:
+
+# fsin.x fp0
+
+	fmovm.x	&0x01,-(%sp)	# pass operand on stack
+	bsr.l	_060FPLSP_TOP+0x1a8 # branch to fsin routine
+	add.l	&0xc,%sp	# clear operand from stack
+
+Upon return, fp0 holds the correct result. The FPSR is
+set correctly. The FPCR is unchanged. The FPIAR is undefined.
+
+Another example. This time, a dyadic operation:
+
+# frem.s %fp1,%fp0
+
+	fmov.s	%fp1,-(%sp)	# pass src operand
+	fmov.s	%fp0,-(%sp)	# pass dst operand
+	bsr.l	_060FPLSP_TOP+0x168 # branch to frem routine
+	addq.l	&0x8,%sp	# clear operands from stack
+
+Again, the result is returned in fp0. Note that BOTH operands
+are passed in single precision format.
+
+Exception reporting:
+--------------------
+The package takes exceptions according to the FPCR value upon subroutine
+entry. If an exception should be reported, then the package forces
+this exception using implemented floating-point instructions.
+For example, if the instruction being emulated should cause a
+floating-point Operand Error exception, then the library routine
+executes an FMUL of a zero and an infinity to force the OPERR
+exception. Although the FPIAR will be undefined for the enabled
+Operand Error exception handler, the user will at least be able
+to record that the event occurred.
+
+Miscellaneous:
+--------------
+The package does not attempt to correctly emulate instructions
+with Signalling NAN inputs. Use of SNANs should be avoided with
+this package.
+
+The fabs/fadd/fdiv/fint/fintrz/fmul/fneg/fsqrt/fsub entry points
+are provided for the convenience of older compilers that make
+subroutine calls for all fp instructions. The code does NOT emulate
+the instruction but rather simply executes it.
+
+68060FPLSP entry points:
+------------------------
+_060FPLSP_TOP:
+0x000:	_060LSP__facoss_
+0x008:	_060LSP__facosd_
+0x010:	_060LSP__facosx_
+0x018:	_060LSP__fasins_
+0x020:	_060LSP__fasind_
+0x028:	_060LSP__fasinx_
+0x030:	_060LSP__fatans_
+0x038:	_060LSP__fatand_
+0x040:	_060LSP__fatanx_
+0x048:	_060LSP__fatanhs_
+0x050:	_060LSP__fatanhd_
+0x058:	_060LSP__fatanhx_
+0x060:	_060LSP__fcoss_
+0x068:	_060LSP__fcosd_
+0x070:	_060LSP__fcosx_
+0x078:	_060LSP__fcoshs_
+0x080:	_060LSP__fcoshd_
+0x088:	_060LSP__fcoshx_
+0x090:	_060LSP__fetoxs_
+0x098:	_060LSP__fetoxd_
+0x0a0:	_060LSP__fetoxx_
+0x0a8:	_060LSP__fetoxm1s_
+0x0b0:	_060LSP__fetoxm1d_
+0x0b8:	_060LSP__fetoxm1x_
+0x0c0:	_060LSP__fgetexps_
+0x0c8:	_060LSP__fgetexpd_
+0x0d0:	_060LSP__fgetexpx_
+0x0d8:	_060LSP__fgetmans_
+0x0e0:	_060LSP__fgetmand_
+0x0e8:	_060LSP__fgetmanx_
+0x0f0:	_060LSP__flog10s_
+0x0f8:	_060LSP__flog10d_
+0x100:	_060LSP__flog10x_
+0x108:	_060LSP__flog2s_
+0x110:	_060LSP__flog2d_
+0x118:	_060LSP__flog2x_
+0x120:	_060LSP__flogns_
+0x128:	_060LSP__flognd_
+0x130:	_060LSP__flognx_
+0x138:	_060LSP__flognp1s_
+0x140:	_060LSP__flognp1d_
+0x148:	_060LSP__flognp1x_
+0x150:	_060LSP__fmods_
+0x158:	_060LSP__fmodd_
+0x160:	_060LSP__fmodx_
+0x168:	_060LSP__frems_
+0x170:	_060LSP__fremd_
+0x178:	_060LSP__fremx_
+0x180:	_060LSP__fscales_
+0x188:	_060LSP__fscaled_
+0x190:	_060LSP__fscalex_
+0x198:	_060LSP__fsins_
+0x1a0:	_060LSP__fsind_
+0x1a8:	_060LSP__fsinx_
+0x1b0:	_060LSP__fsincoss_
+0x1b8:	_060LSP__fsincosd_
+0x1c0:	_060LSP__fsincosx_
+0x1c8:	_060LSP__fsinhs_
+0x1d0:	_060LSP__fsinhd_
+0x1d8:	_060LSP__fsinhx_
+0x1e0:	_060LSP__ftans_
+0x1e8:	_060LSP__ftand_
+0x1f0:	_060LSP__ftanx_
+0x1f8:	_060LSP__ftanhs_
+0x200:	_060LSP__ftanhd_
+0x208:	_060LSP__ftanhx_
+0x210:	_060LSP__ftentoxs_
+0x218:	_060LSP__ftentoxd_
+0x220:	_060LSP__ftentoxx_
+0x228:	_060LSP__ftwotoxs_
+0x230:	_060LSP__ftwotoxd_
+0x238:	_060LSP__ftwotoxx_
+
+0x240:	_060LSP__fabss_
+0x248:	_060LSP__fabsd_
+0x250:	_060LSP__fabsx_
+0x258:	_060LSP__fadds_
+0x260:	_060LSP__faddd_
+0x268:	_060LSP__faddx_
+0x270:	_060LSP__fdivs_
+0x278:	_060LSP__fdivd_
+0x280:	_060LSP__fdivx_
+0x288:	_060LSP__fints_
+0x290:	_060LSP__fintd_
+0x298:	_060LSP__fintx_
+0x2a0:	_060LSP__fintrzs_
+0x2a8:	_060LSP__fintrzd_
+0x2b0:	_060LSP__fintrzx_
+0x2b8:	_060LSP__fmuls_
+0x2c0:	_060LSP__fmuld_
+0x2c8:	_060LSP__fmulx_
+0x2d0:	_060LSP__fnegs_
+0x2d8:	_060LSP__fnegd_
+0x2e0:	_060LSP__fnegx_
+0x2e8:	_060LSP__fsqrts_
+0x2f0:	_060LSP__fsqrtd_
+0x2f8:	_060LSP__fsqrtx_
+0x300:	_060LSP__fsubs_
+0x308:	_060LSP__fsubd_
+0x310:	_060LSP__fsubx_
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/ifpsp060/fplsp.sa linux/arch/m68k/ifpsp060/fplsp.sa
--- v1.3.93/linux/arch/m68k/ifpsp060/fplsp.sa	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/ifpsp060/fplsp.sa	Mon Jan  8 22:08:14 1996
@@ -0,0 +1,1946 @@
+	dc.l	$60ff0000,$238e0000,$60ff0000,$24200000
+	dc.l	$60ff0000,$24b60000,$60ff0000,$11060000
+	dc.l	$60ff0000,$11980000,$60ff0000,$122e0000
+	dc.l	$60ff0000,$0f160000,$60ff0000,$0fa80000
+	dc.l	$60ff0000,$103e0000,$60ff0000,$12ae0000
+	dc.l	$60ff0000,$13400000,$60ff0000,$13d60000
+	dc.l	$60ff0000,$05ae0000,$60ff0000,$06400000
+	dc.l	$60ff0000,$06d60000,$60ff0000,$213e0000
+	dc.l	$60ff0000,$21d00000,$60ff0000,$22660000
+	dc.l	$60ff0000,$16160000,$60ff0000,$16a80000
+	dc.l	$60ff0000,$173e0000,$60ff0000,$0aee0000
+	dc.l	$60ff0000,$0b800000,$60ff0000,$0c160000
+	dc.l	$60ff0000,$24a60000,$60ff0000,$25380000
+	dc.l	$60ff0000,$25ce0000,$60ff0000,$26660000
+	dc.l	$60ff0000,$26f80000,$60ff0000,$278e0000
+	dc.l	$60ff0000,$1d160000,$60ff0000,$1da80000
+	dc.l	$60ff0000,$1e3e0000,$60ff0000,$1ed60000
+	dc.l	$60ff0000,$1f680000,$60ff0000,$1ffe0000
+	dc.l	$60ff0000,$1b0e0000,$60ff0000,$1ba00000
+	dc.l	$60ff0000,$1c360000,$60ff0000,$08860000
+	dc.l	$60ff0000,$09180000,$60ff0000,$09ae0000
+	dc.l	$60ff0000,$2bf00000,$60ff0000,$2ca40000
+	dc.l	$60ff0000,$2d580000,$60ff0000,$29980000
+	dc.l	$60ff0000,$2a4c0000,$60ff0000,$2b000000
+	dc.l	$60ff0000,$2e000000,$60ff0000,$2eb40000
+	dc.l	$60ff0000,$2f680000,$60ff0000,$029e0000
+	dc.l	$60ff0000,$03300000,$60ff0000,$03c60000
+	dc.l	$60ff0000,$27660000,$60ff0000,$27fe0000
+	dc.l	$60ff0000,$289a0000,$60ff0000,$061e0000
+	dc.l	$60ff0000,$06b00000,$60ff0000,$07460000
+	dc.l	$60ff0000,$12ee0000,$60ff0000,$13800000
+	dc.l	$60ff0000,$14160000,$60ff0000,$0b760000
+	dc.l	$60ff0000,$0c080000,$60ff0000,$0c9e0000
+	dc.l	$60ff0000,$18460000,$60ff0000,$18d80000
+	dc.l	$60ff0000,$196e0000,$60ff0000,$16560000
+	dc.l	$60ff0000,$16e80000,$60ff0000,$177e0000
+	dc.l	$60ff0000,$72fe0000,$60ff0000,$72fe0000
+	dc.l	$60ff0000,$72fe0000,$60ff0000,$71be0000
+	dc.l	$60ff0000,$71d40000,$60ff0000,$71ea0000
+	dc.l	$60ff0000,$72840000,$60ff0000,$729a0000
+	dc.l	$60ff0000,$72b00000,$60ff0000,$72fe0000
+	dc.l	$60ff0000,$72fe0000,$60ff0000,$72fe0000
+	dc.l	$60ff0000,$72fe0000,$60ff0000,$72fe0000
+	dc.l	$60ff0000,$72fe0000,$60ff0000,$71f20000
+	dc.l	$60ff0000,$72080000,$60ff0000,$721e0000
+	dc.l	$60ff0000,$72860000,$60ff0000,$72860000
+	dc.l	$60ff0000,$72860000,$60ff0000,$72860000
+	dc.l	$60ff0000,$72860000,$60ff0000,$72860000
+	dc.l	$60ff0000,$71600000,$60ff0000,$71760000
+	dc.l	$60ff0000,$718c0000,$51fc51fc,$51fc51fc
+	dc.l	$51fc51fc,$51fc51fc,$51fc51fc,$51fc51fc
+	dc.l	$51fc51fc,$51fc51fc,$51fc51fc,$51fc51fc
+	dc.l	$51fc51fc,$51fc51fc,$51fc51fc,$51fc51fc
+	dc.l	$51fc51fc,$51fc51fc,$51fc51fc,$51fc51fc
+	dc.l	$51fc51fc,$51fc51fc,$51fc51fc,$51fc51fc
+	dc.l	$51fc51fc,$51fc51fc,$51fc51fc,$51fc51fc
+	dc.l	$51fc51fc,$51fc51fc,$51fc51fc,$51fc51fc
+	dc.l	$51fc51fc,$51fc51fc,$51fc51fc,$51fc51fc
+	dc.l	$51fc51fc,$51fc51fc,$51fc51fc,$51fc51fc
+	dc.l	$51fc51fc,$51fc51fc,$51fc51fc,$51fc51fc
+	dc.l	$51fc51fc,$51fc51fc,$51fc51fc,$51fc51fc
+	dc.l	$51fc51fc,$51fc51fc,$51fc51fc,$51fc51fc
+	dc.l	$51fc51fc,$51fc51fc,$51fc51fc,$51fc51fc
+	dc.l	$51fc51fc,$51fc51fc,$51fc51fc,$51fc51fc
+	dc.l	$40c62d38,$d3d64634,$3d6f90ae,$b1e75cc7
+	dc.l	$40000000,$c90fdaa2,$2168c235,$00000000
+	dc.l	$3fff0000,$c90fdaa2,$2168c235,$00000000
+	dc.l	$3fe45f30,$6dc9c883,$4e56ff40,$48ee0303
+	dc.l	$ff9cf22e,$b800ff60,$f22ef0c0,$ffdcf23c
+	dc.l	$90000000,$0000f22e,$44000008,$f22e6800
+	dc.l	$ff6c41ee,$ff6c61ff,$00006c76,$1d40ff4e
+	dc.l	$120002ae,$00ff00ff,$ff644280,$102eff63
+	dc.l	$4a016608,$61ff0000,$2ddc6030,$0c010001
+	dc.l	$660861ff,$00007124,$60220c01,$00026608
+	dc.l	$61ff0000,$6d226014,$0c010003,$660861ff
+	dc.l	$00006f4c,$600661ff,$00002f8e,$4cee0303
+	dc.l	$ff9cf22e,$9800ff60,$f22ed040,$ffe84e5e
+	dc.l	$4e754e56,$ff4048ee,$0303ff9c,$f22eb800
+	dc.l	$ff60f22e,$f0c0ffdc,$f23c9000,$00000000
+	dc.l	$f22e5400,$0008f22e,$6800ff6c,$41eeff6c
+	dc.l	$61ff0000,$6bdc1d40,$ff4e1200,$02ae00ff
+	dc.l	$00ffff64,$4280102e,$ff631d41,$ff4e4a01
+	dc.l	$660861ff,$00002d3e,$60300c01,$00016608
+	dc.l	$61ff0000,$70866022,$0c010002,$660861ff
+	dc.l	$00006c84,$60140c01,$00036608,$61ff0000
+	dc.l	$6eae6006,$61ff0000,$2ef04cee,$0303ff9c
+	dc.l	$f22e9800,$ff60f22e,$d040ffe8,$4e5e4e75
+	dc.l	$4e56ff40,$48ee0303,$ff9cf22e,$b800ff60
+	dc.l	$f22ef0c0,$ffdcf23c,$90000000,$000041ee
+	dc.l	$ff6c216e,$00080000,$216e000c,$0004216e
+	dc.l	$00100008,$61ff0000,$6b381d40,$ff4e1200
+	dc.l	$02ae00ff,$00ffff64,$4280102e,$ff634a01
+	dc.l	$660861ff,$00002c9e,$60300c01,$00016608
+	dc.l	$61ff0000,$6fe66022,$0c010002,$660861ff
+	dc.l	$00006be4,$60140c01,$00036608,$61ff0000
+	dc.l	$6e0e6006,$61ff0000,$2e504cee,$0303ff9c
+	dc.l	$f22e9800,$ff60f22e,$d040ffe8,$4e5e4e75
+	dc.l	$4e56ff40,$48ee0303,$ff9cf22e,$b800ff60
+	dc.l	$f22ef0c0,$ffdcf23c,$90000000,$0000f22e
+	dc.l	$44000008,$f22e6800,$ff6c41ee,$ff6c61ff
+	dc.l	$00006a9e,$1d40ff4e,$120002ae,$00ff00ff
+	dc.l	$ff644280,$102eff63,$4a016608,$61ff0000
+	dc.l	$2c0e6030,$0c010001,$660861ff,$00006fc8
+	dc.l	$60220c01,$00026608,$61ff0000,$6b4a6014
+	dc.l	$0c010003,$660861ff,$00006d74,$600661ff
+	dc.l	$00002dbc,$4cee0303,$ff9cf22e,$9800ff60
+	dc.l	$f22ed040,$ffe84e5e,$4e754e56,$ff4048ee
+	dc.l	$0303ff9c,$f22eb800,$ff60f22e,$f0c0ffdc
+	dc.l	$f23c9000,$00000000,$f22e5400,$0008f22e
+	dc.l	$6800ff6c,$41eeff6c,$61ff0000,$6a041d40
+	dc.l	$ff4e1200,$02ae00ff,$00ffff64,$4280102e
+	dc.l	$ff631d41,$ff4e4a01,$660861ff,$00002b70
+	dc.l	$60300c01,$00016608,$61ff0000,$6f2a6022
+	dc.l	$0c010002,$660861ff,$00006aac,$60140c01
+	dc.l	$00036608,$61ff0000,$6cd66006,$61ff0000
+	dc.l	$2d1e4cee,$0303ff9c,$f22e9800,$ff60f22e
+	dc.l	$d040ffe8,$4e5e4e75,$4e56ff40,$48ee0303
+	dc.l	$ff9cf22e,$b800ff60,$f22ef0c0,$ffdcf23c
+	dc.l	$90000000,$000041ee,$ff6c216e,$00080000
+	dc.l	$216e000c,$0004216e,$00100008,$61ff0000
+	dc.l	$69601d40,$ff4e1200,$02ae00ff,$00ffff64
+	dc.l	$4280102e,$ff634a01,$660861ff,$00002ad0
+	dc.l	$60300c01,$00016608,$61ff0000,$6e8a6022
+	dc.l	$0c010002,$660861ff,$00006a0c,$60140c01
+	dc.l	$00036608,$61ff0000,$6c366006,$61ff0000
+	dc.l	$2c7e4cee,$0303ff9c,$f22e9800,$ff60f22e
+	dc.l	$d040ffe8,$4e5e4e75,$4e56ff40,$48ee0303
+	dc.l	$ff9cf22e,$b800ff60,$f22ef0c0,$ffdcf23c
+	dc.l	$90000000,$0000f22e,$44000008,$f22e6800
+	dc.l	$ff6c41ee,$ff6c61ff,$000068c6,$1d40ff4e
+	dc.l	$120002ae,$00ff00ff,$ff644280,$102eff63
+	dc.l	$4a016608,$61ff0000,$4e686030,$0c010001
+	dc.l	$660861ff,$00006d74,$60220c01,$00026608
+	dc.l	$61ff0000,$6d946014,$0c010003,$660861ff
+	dc.l	$00006b9c,$600661ff,$00004f14,$4cee0303
+	dc.l	$ff9cf22e,$9800ff60,$f22ed040,$ffe84e5e
+	dc.l	$4e754e56,$ff4048ee,$0303ff9c,$f22eb800
+	dc.l	$ff60f22e,$f0c0ffdc,$f23c9000,$00000000
+	dc.l	$f22e5400,$0008f22e,$6800ff6c,$41eeff6c
+	dc.l	$61ff0000,$682c1d40,$ff4e1200,$02ae00ff
+	dc.l	$00ffff64,$4280102e,$ff631d41,$ff4e4a01
+	dc.l	$660861ff,$00004dca,$60300c01,$00016608
+	dc.l	$61ff0000,$6cd66022,$0c010002,$660861ff
+	dc.l	$00006cf6,$60140c01,$00036608,$61ff0000
+	dc.l	$6afe6006,$61ff0000,$4e764cee,$0303ff9c
+	dc.l	$f22e9800,$ff60f22e,$d040ffe8,$4e5e4e75
+	dc.l	$4e56ff40,$48ee0303,$ff9cf22e,$b800ff60
+	dc.l	$f22ef0c0,$ffdcf23c,$90000000,$000041ee
+	dc.l	$ff6c216e,$00080000,$216e000c,$0004216e
+	dc.l	$00100008,$61ff0000,$67881d40,$ff4e1200
+	dc.l	$02ae00ff,$00ffff64,$4280102e,$ff634a01
+	dc.l	$660861ff,$00004d2a,$60300c01,$00016608
+	dc.l	$61ff0000,$6c366022,$0c010002,$660861ff
+	dc.l	$00006c56,$60140c01,$00036608,$61ff0000
+	dc.l	$6a5e6006,$61ff0000,$4dd64cee,$0303ff9c
+	dc.l	$f22e9800,$ff60f22e,$d040ffe8,$4e5e4e75
+	dc.l	$4e56ff40,$48ee0303,$ff9cf22e,$b800ff60
+	dc.l	$f22ef0c0,$ffdcf23c,$90000000,$0000f22e
+	dc.l	$44000008,$f22e6800,$ff6c41ee,$ff6c61ff
+	dc.l	$000066ee,$1d40ff4e,$120002ae,$00ff00ff
+	dc.l	$ff644280,$102eff63,$4a016608,$61ff0000
+	dc.l	$59b26030,$0c010001,$660861ff,$00006b9c
+	dc.l	$60220c01,$00026608,$61ff0000,$6bf26014
+	dc.l	$0c010003,$660861ff,$000069c4,$600661ff
+	dc.l	$00005ad4,$4cee0303,$ff9cf22e,$9800ff60
+	dc.l	$f22ed040,$ffe84e5e,$4e754e56,$ff4048ee
+	dc.l	$0303ff9c,$f22eb800,$ff60f22e,$f0c0ffdc
+	dc.l	$f23c9000,$00000000,$f22e5400,$0008f22e
+	dc.l	$6800ff6c,$41eeff6c,$61ff0000,$66541d40
+	dc.l	$ff4e1200,$02ae00ff,$00ffff64,$4280102e
+	dc.l	$ff631d41,$ff4e4a01,$660861ff,$00005914
+	dc.l	$60300c01,$00016608,$61ff0000,$6afe6022
+	dc.l	$0c010002,$660861ff,$00006b54,$60140c01
+	dc.l	$00036608,$61ff0000,$69266006,$61ff0000
+	dc.l	$5a364cee,$0303ff9c,$f22e9800,$ff60f22e
+	dc.l	$d040ffe8,$4e5e4e75,$4e56ff40,$48ee0303
+	dc.l	$ff9cf22e,$b800ff60,$f22ef0c0,$ffdcf23c
+	dc.l	$90000000,$000041ee,$ff6c216e,$00080000
+	dc.l	$216e000c,$0004216e,$00100008,$61ff0000
+	dc.l	$65b01d40,$ff4e1200,$02ae00ff,$00ffff64
+	dc.l	$4280102e,$ff634a01,$660861ff,$00005874
+	dc.l	$60300c01,$00016608,$61ff0000,$6a5e6022
+	dc.l	$0c010002,$660861ff,$00006ab4,$60140c01
+	dc.l	$00036608,$61ff0000,$68866006,$61ff0000
+	dc.l	$59964cee,$0303ff9c,$f22e9800,$ff60f22e
+	dc.l	$d040ffe8,$4e5e4e75,$4e56ff40,$48ee0303
+	dc.l	$ff9cf22e,$b800ff60,$f22ef0c0,$ffdcf23c
+	dc.l	$90000000,$0000f22e,$44000008,$f22e6800
+	dc.l	$ff6c41ee,$ff6c61ff,$00006516,$1d40ff4e
+	dc.l	$120002ae,$00ff00ff,$ff644280,$102eff63
+	dc.l	$4a016608,$61ff0000,$46c46030,$0c010001
+	dc.l	$660861ff,$000069c4,$60220c01,$00026608
+	dc.l	$61ff0000,$6a246014,$0c010003,$660861ff
+	dc.l	$000067ec,$600661ff,$00004948,$4cee0303
+	dc.l	$ff9cf22e,$9800ff60,$f22ed040,$ffe84e5e
+	dc.l	$4e754e56,$ff4048ee,$0303ff9c,$f22eb800
+	dc.l	$ff60f22e,$f0c0ffdc,$f23c9000,$00000000
+	dc.l	$f22e5400,$0008f22e,$6800ff6c,$41eeff6c
+	dc.l	$61ff0000,$647c1d40,$ff4e1200,$02ae00ff
+	dc.l	$00ffff64,$4280102e,$ff631d41,$ff4e4a01
+	dc.l	$660861ff,$00004626,$60300c01,$00016608
+	dc.l	$61ff0000,$69266022,$0c010002,$660861ff
+	dc.l	$00006986,$60140c01,$00036608,$61ff0000
+	dc.l	$674e6006,$61ff0000,$48aa4cee,$0303ff9c
+	dc.l	$f22e9800,$ff60f22e,$d040ffe8,$4e5e4e75
+	dc.l	$4e56ff40,$48ee0303,$ff9cf22e,$b800ff60
+	dc.l	$f22ef0c0,$ffdcf23c,$90000000,$000041ee
+	dc.l	$ff6c216e,$00080000,$216e000c,$0004216e
+	dc.l	$00100008,$61ff0000,$63d81d40,$ff4e1200
+	dc.l	$02ae00ff,$00ffff64,$4280102e,$ff634a01
+	dc.l	$660861ff,$00004586,$60300c01,$00016608
+	dc.l	$61ff0000,$68866022,$0c010002,$660861ff
+	dc.l	$000068e6,$60140c01,$00036608,$61ff0000
+	dc.l	$66ae6006,$61ff0000,$480a4cee,$0303ff9c
+	dc.l	$f22e9800,$ff60f22e,$d040ffe8,$4e5e4e75
+	dc.l	$4e56ff40,$48ee0303,$ff9cf22e,$b800ff60
+	dc.l	$f22ef0c0,$ffdcf23c,$90000000,$0000f22e
+	dc.l	$44000008,$f22e6800,$ff6c41ee,$ff6c61ff
+	dc.l	$0000633e,$1d40ff4e,$120002ae,$00ff00ff
+	dc.l	$ff644280,$102eff63,$4a016608,$61ff0000
+	dc.l	$49c46030,$0c010001,$660861ff,$000067ec
+	dc.l	$60220c01,$00026608,$61ff0000,$68546014
+	dc.l	$0c010003,$660861ff,$00006614,$600661ff
+	dc.l	$00004afa,$4cee0303,$ff9cf22e,$9800ff60
+	dc.l	$f22ed040,$ffe84e5e,$4e754e56,$ff4048ee
+	dc.l	$0303ff9c,$f22eb800,$ff60f22e,$f0c0ffdc
+	dc.l	$f23c9000,$00000000,$f22e5400,$0008f22e
+	dc.l	$6800ff6c,$41eeff6c,$61ff0000,$62a41d40
+	dc.l	$ff4e1200,$02ae00ff,$00ffff64,$4280102e
+	dc.l	$ff631d41,$ff4e4a01,$660861ff,$00004926
+	dc.l	$60300c01,$00016608,$61ff0000,$674e6022
+	dc.l	$0c010002,$660861ff,$000067b6,$60140c01
+	dc.l	$00036608,$61ff0000,$65766006,$61ff0000
+	dc.l	$4a5c4cee,$0303ff9c,$f22e9800,$ff60f22e
+	dc.l	$d040ffe8,$4e5e4e75,$4e56ff40,$48ee0303
+	dc.l	$ff9cf22e,$b800ff60,$f22ef0c0,$ffdcf23c
+	dc.l	$90000000,$000041ee,$ff6c216e,$00080000
+	dc.l	$216e000c,$0004216e,$00100008,$61ff0000
+	dc.l	$62001d40,$ff4e1200,$02ae00ff,$00ffff64
+	dc.l	$4280102e,$ff634a01,$660861ff,$00004886
+	dc.l	$60300c01,$00016608,$61ff0000,$66ae6022
+	dc.l	$0c010002,$660861ff,$00006716,$60140c01
+	dc.l	$00036608,$61ff0000,$64d66006,$61ff0000
+	dc.l	$49bc4cee,$0303ff9c,$f22e9800,$ff60f22e
+	dc.l	$d040ffe8,$4e5e4e75,$4e56ff40,$48ee0303
+	dc.l	$ff9cf22e,$b800ff60,$f22ef0c0,$ffdcf23c
+	dc.l	$90000000,$0000f22e,$44000008,$f22e6800
+	dc.l	$ff6c41ee,$ff6c61ff,$00006166,$1d40ff4e
+	dc.l	$120002ae,$00ff00ff,$ff644280,$102eff63
+	dc.l	$4a016608,$61ff0000,$391c6030,$0c010001
+	dc.l	$660861ff,$00006614,$60220c01,$00026608
+	dc.l	$61ff0000,$66b86014,$0c010003,$660861ff
+	dc.l	$0000643c,$600661ff,$00003b28,$4cee0303
+	dc.l	$ff9cf22e,$9800ff60,$f22ed040,$ffe84e5e
+	dc.l	$4e754e56,$ff4048ee,$0303ff9c,$f22eb800
+	dc.l	$ff60f22e,$f0c0ffdc,$f23c9000,$00000000
+	dc.l	$f22e5400,$0008f22e,$6800ff6c,$41eeff6c
+	dc.l	$61ff0000,$60cc1d40,$ff4e1200,$02ae00ff
+	dc.l	$00ffff64,$4280102e,$ff631d41,$ff4e4a01
+	dc.l	$660861ff,$0000387e,$60300c01,$00016608
+	dc.l	$61ff0000,$65766022,$0c010002,$660861ff
+	dc.l	$0000661a,$60140c01,$00036608,$61ff0000
+	dc.l	$639e6006,$61ff0000,$3a8a4cee,$0303ff9c
+	dc.l	$f22e9800,$ff60f22e,$d040ffe8,$4e5e4e75
+	dc.l	$4e56ff40,$48ee0303,$ff9cf22e,$b800ff60
+	dc.l	$f22ef0c0,$ffdcf23c,$90000000,$000041ee
+	dc.l	$ff6c216e,$00080000,$216e000c,$0004216e
+	dc.l	$00100008,$61ff0000,$60281d40,$ff4e1200
+	dc.l	$02ae00ff,$00ffff64,$4280102e,$ff634a01
+	dc.l	$660861ff,$000037de,$60300c01,$00016608
+	dc.l	$61ff0000,$64d66022,$0c010002,$660861ff
+	dc.l	$0000657a,$60140c01,$00036608,$61ff0000
+	dc.l	$62fe6006,$61ff0000,$39ea4cee,$0303ff9c
+	dc.l	$f22e9800,$ff60f22e,$d040ffe8,$4e5e4e75
+	dc.l	$4e56ff40,$48ee0303,$ff9cf22e,$b800ff60
+	dc.l	$f22ef0c0,$ffdcf23c,$90000000,$0000f22e
+	dc.l	$44000008,$f22e6800,$ff6c41ee,$ff6c61ff
+	dc.l	$00005f8e,$1d40ff4e,$120002ae,$00ff00ff
+	dc.l	$ff644280,$102eff63,$4a016608,$61ff0000
+	dc.l	$39886030,$0c010001,$660861ff,$0000643c
+	dc.l	$60220c01,$00026608,$61ff0000,$603a6014
+	dc.l	$0c010003,$660861ff,$00006264,$600661ff
+	dc.l	$00003a04,$4cee0303,$ff9cf22e,$9800ff60
+	dc.l	$f22ed040,$ffe84e5e,$4e754e56,$ff4048ee
+	dc.l	$0303ff9c,$f22eb800,$ff60f22e,$f0c0ffdc
+	dc.l	$f23c9000,$00000000,$f22e5400,$0008f22e
+	dc.l	$6800ff6c,$41eeff6c,$61ff0000,$5ef41d40
+	dc.l	$ff4e1200,$02ae00ff,$00ffff64,$4280102e
+	dc.l	$ff631d41,$ff4e4a01,$660861ff,$000038ea
+	dc.l	$60300c01,$00016608,$61ff0000,$639e6022
+	dc.l	$0c010002,$660861ff,$00005f9c,$60140c01
+	dc.l	$00036608,$61ff0000,$61c66006,$61ff0000
+	dc.l	$39664cee,$0303ff9c,$f22e9800,$ff60f22e
+	dc.l	$d040ffe8,$4e5e4e75,$4e56ff40,$48ee0303
+	dc.l	$ff9cf22e,$b800ff60,$f22ef0c0,$ffdcf23c
+	dc.l	$90000000,$000041ee,$ff6c216e,$00080000
+	dc.l	$216e000c,$0004216e,$00100008,$61ff0000
+	dc.l	$5e501d40,$ff4e1200,$02ae00ff,$00ffff64
+	dc.l	$4280102e,$ff634a01,$660861ff,$0000384a
+	dc.l	$60300c01,$00016608,$61ff0000,$62fe6022
+	dc.l	$0c010002,$660861ff,$00005efc,$60140c01
+	dc.l	$00036608,$61ff0000,$61266006,$61ff0000
+	dc.l	$38c64cee,$0303ff9c,$f22e9800,$ff60f22e
+	dc.l	$d040ffe8,$4e5e4e75,$4e56ff40,$48ee0303
+	dc.l	$ff9cf22e,$b800ff60,$f22ef0c0,$ffdcf23c
+	dc.l	$90000000,$0000f22e,$44000008,$f22e6800
+	dc.l	$ff6c41ee,$ff6c61ff,$00005db6,$1d40ff4e
+	dc.l	$120002ae,$00ff00ff,$ff644280,$102eff63
+	dc.l	$4a016608,$61ff0000,$51d46030,$0c010001
+	dc.l	$660861ff,$00006264,$60220c01,$00026608
+	dc.l	$61ff0000,$5e626014,$0c010003,$660861ff
+	dc.l	$0000608c,$600661ff,$00005224,$4cee0303
+	dc.l	$ff9cf22e,$9800ff60,$f22ed040,$ffe84e5e
+	dc.l	$4e754e56,$ff4048ee,$0303ff9c,$f22eb800
+	dc.l	$ff60f22e,$f0c0ffdc,$f23c9000,$00000000
+	dc.l	$f22e5400,$0008f22e,$6800ff6c,$41eeff6c
+	dc.l	$61ff0000,$5d1c1d40,$ff4e1200,$02ae00ff
+	dc.l	$00ffff64,$4280102e,$ff631d41,$ff4e4a01
+	dc.l	$660861ff,$00005136,$60300c01,$00016608
+	dc.l	$61ff0000,$61c66022,$0c010002,$660861ff
+	dc.l	$00005dc4,$60140c01,$00036608,$61ff0000
+	dc.l	$5fee6006,$61ff0000,$51864cee,$0303ff9c
+	dc.l	$f22e9800,$ff60f22e,$d040ffe8,$4e5e4e75
+	dc.l	$4e56ff40,$48ee0303,$ff9cf22e,$b800ff60
+	dc.l	$f22ef0c0,$ffdcf23c,$90000000,$000041ee
+	dc.l	$ff6c216e,$00080000,$216e000c,$0004216e
+	dc.l	$00100008,$61ff0000,$5c781d40,$ff4e1200
+	dc.l	$02ae00ff,$00ffff64,$4280102e,$ff634a01
+	dc.l	$660861ff,$00005096,$60300c01,$00016608
+	dc.l	$61ff0000,$61266022,$0c010002,$660861ff
+	dc.l	$00005d24,$60140c01,$00036608,$61ff0000
+	dc.l	$5f4e6006,$61ff0000,$50e64cee,$0303ff9c
+	dc.l	$f22e9800,$ff60f22e,$d040ffe8,$4e5e4e75
+	dc.l	$4e56ff40,$48ee0303,$ff9cf22e,$b800ff60
+	dc.l	$f22ef0c0,$ffdcf23c,$90000000,$0000f22e
+	dc.l	$44000008,$f22e6800,$ff6c41ee,$ff6c61ff
+	dc.l	$00005bde,$1d40ff4e,$120002ae,$00ff00ff
+	dc.l	$ff644280,$102eff63,$4a016608,$61ff0000
+	dc.l	$28066030,$0c010001,$660861ff,$0000608c
+	dc.l	$60220c01,$00026608,$61ff0000,$5c8a6014
+	dc.l	$0c010003,$660861ff,$00005eb4,$600661ff
+	dc.l	$00002938,$4cee0303,$ff9cf22e,$9800ff60
+	dc.l	$f22ed040,$ffe84e5e,$4e754e56,$ff4048ee
+	dc.l	$0303ff9c,$f22eb800,$ff60f22e,$f0c0ffdc
+	dc.l	$f23c9000,$00000000,$f22e5400,$0008f22e
+	dc.l	$6800ff6c,$41eeff6c,$61ff0000,$5b441d40
+	dc.l	$ff4e1200,$02ae00ff,$00ffff64,$4280102e
+	dc.l	$ff631d41,$ff4e4a01,$660861ff,$00002768
+	dc.l	$60300c01,$00016608,$61ff0000,$5fee6022
+	dc.l	$0c010002,$660861ff,$00005bec,$60140c01
+	dc.l	$00036608,$61ff0000,$5e166006,$61ff0000
+	dc.l	$289a4cee,$0303ff9c,$f22e9800,$ff60f22e
+	dc.l	$d040ffe8,$4e5e4e75,$4e56ff40,$48ee0303
+	dc.l	$ff9cf22e,$b800ff60,$f22ef0c0,$ffdcf23c
+	dc.l	$90000000,$000041ee,$ff6c216e,$00080000
+	dc.l	$216e000c,$0004216e,$00100008,$61ff0000
+	dc.l	$5aa01d40,$ff4e1200,$02ae00ff,$00ffff64
+	dc.l	$4280102e,$ff634a01,$660861ff,$000026c8
+	dc.l	$60300c01,$00016608,$61ff0000,$5f4e6022
+	dc.l	$0c010002,$660861ff,$00005b4c,$60140c01
+	dc.l	$00036608,$61ff0000,$5d766006,$61ff0000
+	dc.l	$27fa4cee,$0303ff9c,$f22e9800,$ff60f22e
+	dc.l	$d040ffe8,$4e5e4e75,$4e56ff40,$48ee0303
+	dc.l	$ff9cf22e,$b800ff60,$f22ef0c0,$ffdcf23c
+	dc.l	$90000000,$0000f22e,$44000008,$f22e6800
+	dc.l	$ff6c41ee,$ff6c61ff,$00005a06,$1d40ff4e
+	dc.l	$120002ae,$00ff00ff,$ff644280,$102eff63
+	dc.l	$4a016608,$61ff0000,$39e46030,$0c010001
+	dc.l	$660861ff,$00005f30,$60220c01,$00026608
+	dc.l	$61ff0000,$5f026014,$0c010003,$660861ff
+	dc.l	$00005cdc,$600661ff,$00003b5e,$4cee0303
+	dc.l	$ff9cf22e,$9800ff60,$f22ed040,$ffe84e5e
+	dc.l	$4e754e56,$ff4048ee,$0303ff9c,$f22eb800
+	dc.l	$ff60f22e,$f0c0ffdc,$f23c9000,$00000000
+	dc.l	$f22e5400,$0008f22e,$6800ff6c,$41eeff6c
+	dc.l	$61ff0000,$596c1d40,$ff4e1200,$02ae00ff
+	dc.l	$00ffff64,$4280102e,$ff631d41,$ff4e4a01
+	dc.l	$660861ff,$00003946,$60300c01,$00016608
+	dc.l	$61ff0000,$5e926022,$0c010002,$660861ff
+	dc.l	$00005e64,$60140c01,$00036608,$61ff0000
+	dc.l	$5c3e6006,$61ff0000,$3ac04cee,$0303ff9c
+	dc.l	$f22e9800,$ff60f22e,$d040ffe8,$4e5e4e75
+	dc.l	$4e56ff40,$48ee0303,$ff9cf22e,$b800ff60
+	dc.l	$f22ef0c0,$ffdcf23c,$90000000,$000041ee
+	dc.l	$ff6c216e,$00080000,$216e000c,$0004216e
+	dc.l	$00100008,$61ff0000,$58c81d40,$ff4e1200
+	dc.l	$02ae00ff,$00ffff64,$4280102e,$ff634a01
+	dc.l	$660861ff,$000038a6,$60300c01,$00016608
+	dc.l	$61ff0000,$5df26022,$0c010002,$660861ff
+	dc.l	$00005dc4,$60140c01,$00036608,$61ff0000
+	dc.l	$5b9e6006,$61ff0000,$3a204cee,$0303ff9c
+	dc.l	$f22e9800,$ff60f22e,$d040ffe8,$4e5e4e75
+	dc.l	$4e56ff40,$48ee0303,$ff9cf22e,$b800ff60
+	dc.l	$f22ef0c0,$ffdcf23c,$90000000,$0000f22e
+	dc.l	$44000008,$f22e6800,$ff6c41ee,$ff6c61ff
+	dc.l	$0000582e,$1d40ff4e,$120002ae,$00ff00ff
+	dc.l	$ff644280,$102eff63,$4a016608,$61ff0000
+	dc.l	$522e6030,$0c010001,$660861ff,$00005d58
+	dc.l	$60220c01,$00026608,$61ff0000,$5d2a6014
+	dc.l	$0c010003,$660861ff,$00005b04,$600661ff
+	dc.l	$000052d6,$4cee0303,$ff9cf22e,$9800ff60
+	dc.l	$f22ed040,$ffe84e5e,$4e754e56,$ff4048ee
+	dc.l	$0303ff9c,$f22eb800,$ff60f22e,$f0c0ffdc
+	dc.l	$f23c9000,$00000000,$f22e5400,$0008f22e
+	dc.l	$6800ff6c,$41eeff6c,$61ff0000,$57941d40
+	dc.l	$ff4e1200,$02ae00ff,$00ffff64,$4280102e
+	dc.l	$ff631d41,$ff4e4a01,$660861ff,$00005190
+	dc.l	$60300c01,$00016608,$61ff0000,$5cba6022
+	dc.l	$0c010002,$660861ff,$00005c8c,$60140c01
+	dc.l	$00036608,$61ff0000,$5a666006,$61ff0000
+	dc.l	$52384cee,$0303ff9c,$f22e9800,$ff60f22e
+	dc.l	$d040ffe8,$4e5e4e75,$4e56ff40,$48ee0303
+	dc.l	$ff9cf22e,$b800ff60,$f22ef0c0,$ffdcf23c
+	dc.l	$90000000,$000041ee,$ff6c216e,$00080000
+	dc.l	$216e000c,$0004216e,$00100008,$61ff0000
+	dc.l	$56f01d40,$ff4e1200,$02ae00ff,$00ffff64
+	dc.l	$4280102e,$ff634a01,$660861ff,$000050f0
+	dc.l	$60300c01,$00016608,$61ff0000,$5c1a6022
+	dc.l	$0c010002,$660861ff,$00005bec,$60140c01
+	dc.l	$00036608,$61ff0000,$59c66006,$61ff0000
+	dc.l	$51984cee,$0303ff9c,$f22e9800,$ff60f22e
+	dc.l	$d040ffe8,$4e5e4e75,$4e56ff40,$48ee0303
+	dc.l	$ff9cf22e,$b800ff60,$f22ef0c0,$ffdcf23c
+	dc.l	$90000000,$0000f22e,$44000008,$f22e6800
+	dc.l	$ff6c41ee,$ff6c61ff,$00005656,$1d40ff4e
+	dc.l	$120002ae,$00ff00ff,$ff644280,$102eff63
+	dc.l	$4a016608,$61ff0000,$514e6030,$0c010001
+	dc.l	$660861ff,$00005b80,$60220c01,$00026608
+	dc.l	$61ff0000,$5b526014,$0c010003,$660861ff
+	dc.l	$0000592c,$600661ff,$0000524c,$4cee0303
+	dc.l	$ff9cf22e,$9800ff60,$f22ed040,$ffe84e5e
+	dc.l	$4e754e56,$ff4048ee,$0303ff9c,$f22eb800
+	dc.l	$ff60f22e,$f0c0ffdc,$f23c9000,$00000000
+	dc.l	$f22e5400,$0008f22e,$6800ff6c,$41eeff6c
+	dc.l	$61ff0000,$55bc1d40,$ff4e1200,$02ae00ff
+	dc.l	$00ffff64,$4280102e,$ff631d41,$ff4e4a01
+	dc.l	$660861ff,$000050b0,$60300c01,$00016608
+	dc.l	$61ff0000,$5ae26022,$0c010002,$660861ff
+	dc.l	$00005ab4,$60140c01,$00036608,$61ff0000
+	dc.l	$588e6006,$61ff0000,$51ae4cee,$0303ff9c
+	dc.l	$f22e9800,$ff60f22e,$d040ffe8,$4e5e4e75
+	dc.l	$4e56ff40,$48ee0303,$ff9cf22e,$b800ff60
+	dc.l	$f22ef0c0,$ffdcf23c,$90000000,$000041ee
+	dc.l	$ff6c216e,$00080000,$216e000c,$0004216e
+	dc.l	$00100008,$61ff0000,$55181d40,$ff4e1200
+	dc.l	$02ae00ff,$00ffff64,$4280102e,$ff634a01
+	dc.l	$660861ff,$00005010,$60300c01,$00016608
+	dc.l	$61ff0000,$5a426022,$0c010002,$660861ff
+	dc.l	$00005a14,$60140c01,$00036608,$61ff0000
+	dc.l	$57ee6006,$61ff0000,$510e4cee,$0303ff9c
+	dc.l	$f22e9800,$ff60f22e,$d040ffe8,$4e5e4e75
+	dc.l	$4e56ff40,$48ee0303,$ff9cf22e,$b800ff60
+	dc.l	$f22ef0c0,$ffdcf23c,$90000000,$0000f22e
+	dc.l	$44000008,$f22e6800,$ff6c41ee,$ff6c61ff
+	dc.l	$0000547e,$1d40ff4e,$120002ae,$00ff00ff
+	dc.l	$ff644280,$102eff63,$4a016608,$61ff0000
+	dc.l	$45026030,$0c010001,$660861ff,$000054c8
+	dc.l	$60220c01,$00026608,$61ff0000,$59826014
+	dc.l	$0c010003,$660861ff,$00005754,$600661ff
+	dc.l	$00004682,$4cee0303,$ff9cf22e,$9800ff60
+	dc.l	$f22ed040,$ffe84e5e,$4e754e56,$ff4048ee
+	dc.l	$0303ff9c,$f22eb800,$ff60f22e,$f0c0ffdc
+	dc.l	$f23c9000,$00000000,$f22e5400,$0008f22e
+	dc.l	$6800ff6c,$41eeff6c,$61ff0000,$53e41d40
+	dc.l	$ff4e1200,$02ae00ff,$00ffff64,$4280102e
+	dc.l	$ff631d41,$ff4e4a01,$660861ff,$00004464
+	dc.l	$60300c01,$00016608,$61ff0000,$542a6022
+	dc.l	$0c010002,$660861ff,$000058e4,$60140c01
+	dc.l	$00036608,$61ff0000,$56b66006,$61ff0000
+	dc.l	$45e44cee,$0303ff9c,$f22e9800,$ff60f22e
+	dc.l	$d040ffe8,$4e5e4e75,$4e56ff40,$48ee0303
+	dc.l	$ff9cf22e,$b800ff60,$f22ef0c0,$ffdcf23c
+	dc.l	$90000000,$000041ee,$ff6c216e,$00080000
+	dc.l	$216e000c,$0004216e,$00100008,$61ff0000
+	dc.l	$53401d40,$ff4e1200,$02ae00ff,$00ffff64
+	dc.l	$4280102e,$ff634a01,$660861ff,$000043c4
+	dc.l	$60300c01,$00016608,$61ff0000,$538a6022
+	dc.l	$0c010002,$660861ff,$00005844,$60140c01
+	dc.l	$00036608,$61ff0000,$56166006,$61ff0000
+	dc.l	$45444cee,$0303ff9c,$f22e9800,$ff60f22e
+	dc.l	$d040ffe8,$4e5e4e75,$4e56ff40,$48ee0303
+	dc.l	$ff9cf22e,$b800ff60,$f22ef0c0,$ffdcf23c
+	dc.l	$90000000,$0000f22e,$44000008,$f22e6800
+	dc.l	$ff6c41ee,$ff6c61ff,$000052a6,$1d40ff4e
+	dc.l	$120002ae,$00ff00ff,$ff644280,$102eff63
+	dc.l	$4a016608,$61ff0000,$476c6030,$0c010001
+	dc.l	$660861ff,$000052f0,$60220c01,$00026608
+	dc.l	$61ff0000,$57aa6014,$0c010003,$660861ff
+	dc.l	$0000557c,$600661ff,$0000476a,$4cee0303
+	dc.l	$ff9cf22e,$9800ff60,$f22ed040,$ffe84e5e
+	dc.l	$4e754e56,$ff4048ee,$0303ff9c,$f22eb800
+	dc.l	$ff60f22e,$f0c0ffdc,$f23c9000,$00000000
+	dc.l	$f22e5400,$0008f22e,$6800ff6c,$41eeff6c
+	dc.l	$61ff0000,$520c1d40,$ff4e1200,$02ae00ff
+	dc.l	$00ffff64,$4280102e,$ff631d41,$ff4e4a01
+	dc.l	$660861ff,$000046ce,$60300c01,$00016608
+	dc.l	$61ff0000,$52526022,$0c010002,$660861ff
+	dc.l	$0000570c,$60140c01,$00036608,$61ff0000
+	dc.l	$54de6006,$61ff0000,$46cc4cee,$0303ff9c
+	dc.l	$f22e9800,$ff60f22e,$d040ffe8,$4e5e4e75
+	dc.l	$4e56ff40,$48ee0303,$ff9cf22e,$b800ff60
+	dc.l	$f22ef0c0,$ffdcf23c,$90000000,$000041ee
+	dc.l	$ff6c216e,$00080000,$216e000c,$0004216e
+	dc.l	$00100008,$61ff0000,$51681d40,$ff4e1200
+	dc.l	$02ae00ff,$00ffff64,$4280102e,$ff634a01
+	dc.l	$660861ff,$0000462e,$60300c01,$00016608
+	dc.l	$61ff0000,$51b26022,$0c010002,$660861ff
+	dc.l	$0000566c,$60140c01,$00036608,$61ff0000
+	dc.l	$543e6006,$61ff0000,$462c4cee,$0303ff9c
+	dc.l	$f22e9800,$ff60f22e,$d040ffe8,$4e5e4e75
+	dc.l	$4e56ff40,$48ee0303,$ff9cf22e,$b800ff60
+	dc.l	$f22ef0c0,$ffdcf23c,$90000000,$0000f22e
+	dc.l	$44000008,$f22e6800,$ff6c41ee,$ff6c61ff
+	dc.l	$000050ce,$1d40ff4e,$120002ae,$00ff00ff
+	dc.l	$ff644280,$102eff63,$4a016608,$61ff0000
+	dc.l	$45e46030,$0c010001,$660861ff,$00005118
+	dc.l	$60220c01,$00026608,$61ff0000,$55d26014
+	dc.l	$0c010003,$660861ff,$000053a4,$600661ff
+	dc.l	$0000460c,$4cee0303,$ff9cf22e,$9800ff60
+	dc.l	$f22ed040,$ffe84e5e,$4e754e56,$ff4048ee
+	dc.l	$0303ff9c,$f22eb800,$ff60f22e,$f0c0ffdc
+	dc.l	$f23c9000,$00000000,$f22e5400,$0008f22e
+	dc.l	$6800ff6c,$41eeff6c,$61ff0000,$50341d40
+	dc.l	$ff4e1200,$02ae00ff,$00ffff64,$4280102e
+	dc.l	$ff631d41,$ff4e4a01,$660861ff,$00004546
+	dc.l	$60300c01,$00016608,$61ff0000,$507a6022
+	dc.l	$0c010002,$660861ff,$00005534,$60140c01
+	dc.l	$00036608,$61ff0000,$53066006,$61ff0000
+	dc.l	$456e4cee,$0303ff9c,$f22e9800,$ff60f22e
+	dc.l	$d040ffe8,$4e5e4e75,$4e56ff40,$48ee0303
+	dc.l	$ff9cf22e,$b800ff60,$f22ef0c0,$ffdcf23c
+	dc.l	$90000000,$000041ee,$ff6c216e,$00080000
+	dc.l	$216e000c,$0004216e,$00100008,$61ff0000
+	dc.l	$4f901d40,$ff4e1200,$02ae00ff,$00ffff64
+	dc.l	$4280102e,$ff634a01,$660861ff,$000044a6
+	dc.l	$60300c01,$00016608,$61ff0000,$4fda6022
+	dc.l	$0c010002,$660861ff,$00005494,$60140c01
+	dc.l	$00036608,$61ff0000,$52666006,$61ff0000
+	dc.l	$44ce4cee,$0303ff9c,$f22e9800,$ff60f22e
+	dc.l	$d040ffe8,$4e5e4e75,$4e56ff40,$48ee0303
+	dc.l	$ff9cf22e,$b800ff60,$f22ef0c0,$ffdcf23c
+	dc.l	$90000000,$0000f22e,$44000008,$f22e6800
+	dc.l	$ff6c41ee,$ff6c61ff,$00004ef6,$1d40ff4e
+	dc.l	$120002ae,$00ff00ff,$ff644280,$102eff63
+	dc.l	$4a016608,$61ff0000,$33da6030,$0c010001
+	dc.l	$660861ff,$00005420,$60220c01,$00026608
+	dc.l	$61ff0000,$53ca6014,$0c010003,$660861ff
+	dc.l	$000051cc,$600661ff,$0000344c,$4cee0303
+	dc.l	$ff9cf22e,$9800ff60,$f22ed040,$ffe84e5e
+	dc.l	$4e754e56,$ff4048ee,$0303ff9c,$f22eb800
+	dc.l	$ff60f22e,$f0c0ffdc,$f23c9000,$00000000
+	dc.l	$f22e5400,$0008f22e,$6800ff6c,$41eeff6c
+	dc.l	$61ff0000,$4e5c1d40,$ff4e1200,$02ae00ff
+	dc.l	$00ffff64,$4280102e,$ff631d41,$ff4e4a01
+	dc.l	$660861ff,$0000333c,$60300c01,$00016608
+	dc.l	$61ff0000,$53826022,$0c010002,$660861ff
+	dc.l	$0000532c,$60140c01,$00036608,$61ff0000
+	dc.l	$512e6006,$61ff0000,$33ae4cee,$0303ff9c
+	dc.l	$f22e9800,$ff60f22e,$d040ffe8,$4e5e4e75
+	dc.l	$4e56ff40,$48ee0303,$ff9cf22e,$b800ff60
+	dc.l	$f22ef0c0,$ffdcf23c,$90000000,$000041ee
+	dc.l	$ff6c216e,$00080000,$216e000c,$0004216e
+	dc.l	$00100008,$61ff0000,$4db81d40,$ff4e1200
+	dc.l	$02ae00ff,$00ffff64,$4280102e,$ff634a01
+	dc.l	$660861ff,$0000329c,$60300c01,$00016608
+	dc.l	$61ff0000,$52e26022,$0c010002,$660861ff
+	dc.l	$0000528c,$60140c01,$00036608,$61ff0000
+	dc.l	$508e6006,$61ff0000,$330e4cee,$0303ff9c
+	dc.l	$f22e9800,$ff60f22e,$d040ffe8,$4e5e4e75
+	dc.l	$4e56ff40,$48ee0303,$ff9cf22e,$b800ff60
+	dc.l	$f22ef0c0,$ffdcf23c,$90000000,$0000f22e
+	dc.l	$44000008,$f22e6800,$ff6c41ee,$ff6c61ff
+	dc.l	$00004d1e,$1d40ff4e,$120002ae,$00ff00ff
+	dc.l	$ff644280,$102eff63,$4a016608,$61ff0000
+	dc.l	$27cc6030,$0c010001,$660861ff,$00005284
+	dc.l	$60220c01,$00026608,$61ff0000,$4dca6014
+	dc.l	$0c010003,$660861ff,$00004ff4,$600661ff
+	dc.l	$0000282a,$4cee0303,$ff9cf22e,$9800ff60
+	dc.l	$f22ed040,$ffe84e5e,$4e754e56,$ff4048ee
+	dc.l	$0303ff9c,$f22eb800,$ff60f22e,$f0c0ffdc
+	dc.l	$f23c9000,$00000000,$f22e5400,$0008f22e
+	dc.l	$6800ff6c,$41eeff6c,$61ff0000,$4c841d40
+	dc.l	$ff4e1200,$02ae00ff,$00ffff64,$4280102e
+	dc.l	$ff631d41,$ff4e4a01,$660861ff,$0000272e
+	dc.l	$60300c01,$00016608,$61ff0000,$51e66022
+	dc.l	$0c010002,$660861ff,$00004d2c,$60140c01
+	dc.l	$00036608,$61ff0000,$4f566006,$61ff0000
+	dc.l	$278c4cee,$0303ff9c,$f22e9800,$ff60f22e
+	dc.l	$d040ffe8,$4e5e4e75,$4e56ff40,$48ee0303
+	dc.l	$ff9cf22e,$b800ff60,$f22ef0c0,$ffdcf23c
+	dc.l	$90000000,$000041ee,$ff6c216e,$00080000
+	dc.l	$216e000c,$0004216e,$00100008,$61ff0000
+	dc.l	$4be01d40,$ff4e1200,$02ae00ff,$00ffff64
+	dc.l	$4280102e,$ff634a01,$660861ff,$0000268e
+	dc.l	$60300c01,$00016608,$61ff0000,$51466022
+	dc.l	$0c010002,$660861ff,$00004c8c,$60140c01
+	dc.l	$00036608,$61ff0000,$4eb66006,$61ff0000
+	dc.l	$26ec4cee,$0303ff9c,$f22e9800,$ff60f22e
+	dc.l	$d040ffe8,$4e5e4e75,$4e56ff40,$48ee0303
+	dc.l	$ff9cf22e,$b800ff60,$f22ef0c0,$ffdcf23c
+	dc.l	$90000000,$0000f22e,$44000008,$f22e6800
+	dc.l	$ff6c41ee,$ff6c61ff,$00004b46,$1d40ff4e
+	dc.l	$120002ae,$00ff00ff,$ff644280,$102eff63
+	dc.l	$4a016608,$61ff0000,$2fb06030,$0c010001
+	dc.l	$660861ff,$00004ff4,$60220c01,$00026608
+	dc.l	$61ff0000,$4bf26014,$0c010003,$660861ff
+	dc.l	$00004e1c,$600661ff,$00002f9a,$4cee0303
+	dc.l	$ff9cf22e,$9800ff60,$f22ed040,$ffe84e5e
+	dc.l	$4e754e56,$ff4048ee,$0303ff9c,$f22eb800
+	dc.l	$ff60f22e,$f0c0ffdc,$f23c9000,$00000000
+	dc.l	$f22e5400,$0008f22e,$6800ff6c,$41eeff6c
+	dc.l	$61ff0000,$4aac1d40,$ff4e1200,$02ae00ff
+	dc.l	$00ffff64,$4280102e,$ff631d41,$ff4e4a01
+	dc.l	$660861ff,$00002f12,$60300c01,$00016608
+	dc.l	$61ff0000,$4f566022,$0c010002,$660861ff
+	dc.l	$00004b54,$60140c01,$00036608,$61ff0000
+	dc.l	$4d7e6006,$61ff0000,$2efc4cee,$0303ff9c
+	dc.l	$f22e9800,$ff60f22e,$d040ffe8,$4e5e4e75
+	dc.l	$4e56ff40,$48ee0303,$ff9cf22e,$b800ff60
+	dc.l	$f22ef0c0,$ffdcf23c,$90000000,$000041ee
+	dc.l	$ff6c216e,$00080000,$216e000c,$0004216e
+	dc.l	$00100008,$61ff0000,$4a081d40,$ff4e1200
+	dc.l	$02ae00ff,$00ffff64,$4280102e,$ff634a01
+	dc.l	$660861ff,$00002e72,$60300c01,$00016608
+	dc.l	$61ff0000,$4eb66022,$0c010002,$660861ff
+	dc.l	$00004ab4,$60140c01,$00036608,$61ff0000
+	dc.l	$4cde6006,$61ff0000,$2e5c4cee,$0303ff9c
+	dc.l	$f22e9800,$ff60f22e,$d040ffe8,$4e5e4e75
+	dc.l	$4e56ff40,$48ee0303,$ff9cf22e,$b800ff60
+	dc.l	$f22ef0c0,$ffdcf23c,$90000000,$0000f22e
+	dc.l	$44000008,$f22e6800,$ff6c41ee,$ff6c61ff
+	dc.l	$0000496e,$1d40ff4e,$120002ae,$00ff00ff
+	dc.l	$ff644280,$102eff63,$4a016608,$61ff0000
+	dc.l	$2e0c6030,$0c010001,$660861ff,$00004e1c
+	dc.l	$60220c01,$00026608,$61ff0000,$4a1a6014
+	dc.l	$0c010003,$660861ff,$00004c44,$600661ff
+	dc.l	$00002e08,$4cee0303,$ff9cf22e,$9800ff60
+	dc.l	$f22ed040,$ffe84e5e,$4e754e56,$ff4048ee
+	dc.l	$0303ff9c,$f22eb800,$ff60f22e,$f0c0ffdc
+	dc.l	$f23c9000,$00000000,$f22e5400,$0008f22e
+	dc.l	$6800ff6c,$41eeff6c,$61ff0000,$48d41d40
+	dc.l	$ff4e1200,$02ae00ff,$00ffff64,$4280102e
+	dc.l	$ff631d41,$ff4e4a01,$660861ff,$00002d6e
+	dc.l	$60300c01,$00016608,$61ff0000,$4d7e6022
+	dc.l	$0c010002,$660861ff,$0000497c,$60140c01
+	dc.l	$00036608,$61ff0000,$4ba66006,$61ff0000
+	dc.l	$2d6a4cee,$0303ff9c,$f22e9800,$ff60f22e
+	dc.l	$d040ffe8,$4e5e4e75,$4e56ff40,$48ee0303
+	dc.l	$ff9cf22e,$b800ff60,$f22ef0c0,$ffdcf23c
+	dc.l	$90000000,$000041ee,$ff6c216e,$00080000
+	dc.l	$216e000c,$0004216e,$00100008,$61ff0000
+	dc.l	$48301d40,$ff4e1200,$02ae00ff,$00ffff64
+	dc.l	$4280102e,$ff634a01,$660861ff,$00002cce
+	dc.l	$60300c01,$00016608,$61ff0000,$4cde6022
+	dc.l	$0c010002,$660861ff,$000048dc,$60140c01
+	dc.l	$00036608,$61ff0000,$4b066006,$61ff0000
+	dc.l	$2cca4cee,$0303ff9c,$f22e9800,$ff60f22e
+	dc.l	$d040ffe8,$4e5e4e75,$4e56ff40,$48ee0303
+	dc.l	$ff9cf22e,$b800ff60,$f22ef0c0,$ffdcf23c
+	dc.l	$90000000,$0000f22e,$44000008,$f22e6800
+	dc.l	$ff6c41ee,$ff6c61ff,$00004796,$1d40ff4e
+	dc.l	$120002ae,$00ff00ff,$ff644280,$102eff63
+	dc.l	$4a016608,$61ff0000,$0af46030,$0c010001
+	dc.l	$660861ff,$00004d18,$60220c01,$00026608
+	dc.l	$61ff0000,$4d386014,$0c010003,$660861ff
+	dc.l	$00004d34,$600661ff,$00000d58,$4cee0303
+	dc.l	$ff9cf22e,$9800ff60,$f227e003,$f21fd040
+	dc.l	$f21fd080,$4e5e4e75,$4e56ff40,$48ee0303
+	dc.l	$ff9cf22e,$b800ff60,$f22ef0c0,$ffdcf23c
+	dc.l	$90000000,$0000f22e,$54000008,$f22e6800
+	dc.l	$ff6c41ee,$ff6c61ff,$000046f6,$1d40ff4e
+	dc.l	$120002ae,$00ff00ff,$ff644280,$102eff63
+	dc.l	$1d41ff4e,$4a016608,$61ff0000,$0a506030
+	dc.l	$0c010001,$660861ff,$00004c74,$60220c01
+	dc.l	$00026608,$61ff0000,$4c946014,$0c010003
+	dc.l	$660861ff,$00004c90,$600661ff,$00000cb4
+	dc.l	$4cee0303,$ff9cf22e,$9800ff60,$f227e003
+	dc.l	$f21fd040,$f21fd080,$4e5e4e75,$4e56ff40
+	dc.l	$48ee0303,$ff9cf22e,$b800ff60,$f22ef0c0
+	dc.l	$ffdcf23c,$90000000,$000041ee,$ff6c216e
+	dc.l	$00080000,$216e000c,$0004216e,$00100008
+	dc.l	$61ff0000,$464c1d40,$ff4e1200,$02ae00ff
+	dc.l	$00ffff64,$4280102e,$ff634a01,$660861ff
+	dc.l	$000009aa,$60300c01,$00016608,$61ff0000
+	dc.l	$4bce6022,$0c010002,$660861ff,$00004bee
+	dc.l	$60140c01,$00036608,$61ff0000,$4bea6006
+	dc.l	$61ff0000,$0c0e4cee,$0303ff9c,$f22e9800
+	dc.l	$ff60f227,$e003f21f,$d040f21f,$d0804e5e
+	dc.l	$4e754e56,$ff4048ee,$0303ff9c,$f22eb800
+	dc.l	$ff60f22e,$f0c0ffdc,$f23c9000,$00000000
+	dc.l	$f22e4400,$0008f22e,$6800ff78,$41eeff78
+	dc.l	$61ff0000,$45ac1d40,$ff4ff22e,$4400000c
+	dc.l	$f22e6800,$ff6c41ee,$ff6c61ff,$00004592
+	dc.l	$1d40ff4e,$220002ae,$00ff00ff,$ff644280
+	dc.l	$102eff63,$41eeff6c,$43eeff78,$4a016608
+	dc.l	$61ff0000,$4c466030,$0c010001,$660861ff
+	dc.l	$00004c64,$60220c01,$00026608,$61ff0000
+	dc.l	$4c846014,$0c010003,$660861ff,$00004d16
+	dc.l	$600661ff,$00004c14,$4cee0303,$ff9cf22e
+	dc.l	$9800ff60,$f22ed040,$ffe84e5e,$4e754e56
+	dc.l	$ff4048ee,$0303ff9c,$f22eb800,$ff60f22e
+	dc.l	$f0c0ffdc,$f23c9000,$00000000,$f22e5400
+	dc.l	$0008f22e,$6800ff78,$41eeff78,$61ff0000
+	dc.l	$44f01d40,$ff4ff22e,$54000010,$f22e6800
+	dc.l	$ff6c41ee,$ff6c61ff,$000044d6,$1d40ff4e
+	dc.l	$220002ae,$00ff00ff,$ff644280,$102eff63
+	dc.l	$41eeff6c,$43eeff78,$4a016608,$61ff0000
+	dc.l	$4b8a6030,$0c010001,$660861ff,$00004ba8
+	dc.l	$60220c01,$00026608,$61ff0000,$4bc86014
+	dc.l	$0c010003,$660861ff,$00004c5a,$600661ff
+	dc.l	$00004b58,$4cee0303,$ff9cf22e,$9800ff60
+	dc.l	$f22ed040,$ffe84e5e,$4e754e56,$ff4048ee
+	dc.l	$0303ff9c,$f22eb800,$ff60f22e,$f0c0ffdc
+	dc.l	$f23c9000,$00000000,$41eeff78,$216e0008
+	dc.l	$0000216e,$000c0004,$216e0010,$000861ff
+	dc.l	$0000442e,$1d40ff4f,$41eeff6c,$216e0014
+	dc.l	$0000216e,$00180004,$216e001c,$000861ff
+	dc.l	$0000440e,$1d40ff4e,$220002ae,$00ff00ff
+	dc.l	$ff644280,$102eff63,$41eeff6c,$43eeff78
+	dc.l	$4a016608,$61ff0000,$4ac26030,$0c010001
+	dc.l	$660861ff,$00004ae0,$60220c01,$00026608
+	dc.l	$61ff0000,$4b006014,$0c010003,$660861ff
+	dc.l	$00004b92,$600661ff,$00004a90,$4cee0303
+	dc.l	$ff9cf22e,$9800ff60,$f22ed040,$ffe84e5e
+	dc.l	$4e754e56,$ff4048ee,$0303ff9c,$f22eb800
+	dc.l	$ff60f22e,$f0c0ffdc,$f23c9000,$00000000
+	dc.l	$f22e4400,$0008f22e,$6800ff78,$41eeff78
+	dc.l	$61ff0000,$436c1d40,$ff4ff22e,$4400000c
+	dc.l	$f22e6800,$ff6c41ee,$ff6c61ff,$00004352
+	dc.l	$1d40ff4e,$220002ae,$00ff00ff,$ff644280
+	dc.l	$102eff63,$41eeff6c,$43eeff78,$4a016608
+	dc.l	$61ff0000,$491c6030,$0c010001,$660861ff
+	dc.l	$0000493a,$60220c01,$00026608,$61ff0000
+	dc.l	$495a6014,$0c010003,$660861ff,$00004ad6
+	dc.l	$600661ff,$000048ea,$4cee0303,$ff9cf22e
+	dc.l	$9800ff60,$f22ed040,$ffe84e5e,$4e754e56
+	dc.l	$ff4048ee,$0303ff9c,$f22eb800,$ff60f22e
+	dc.l	$f0c0ffdc,$f23c9000,$00000000,$f22e5400
+	dc.l	$0008f22e,$6800ff78,$41eeff78,$61ff0000
+	dc.l	$42b01d40,$ff4ff22e,$54000010,$f22e6800
+	dc.l	$ff6c41ee,$ff6c61ff,$00004296,$1d40ff4e
+	dc.l	$220002ae,$00ff00ff,$ff644280,$102eff63
+	dc.l	$41eeff6c,$43eeff78,$4a016608,$61ff0000
+	dc.l	$48606030,$0c010001,$660861ff,$0000487e
+	dc.l	$60220c01,$00026608,$61ff0000,$489e6014
+	dc.l	$0c010003,$660861ff,$00004a1a,$600661ff
+	dc.l	$0000482e,$4cee0303,$ff9cf22e,$9800ff60
+	dc.l	$f22ed040,$ffe84e5e,$4e754e56,$ff4048ee
+	dc.l	$0303ff9c,$f22eb800,$ff60f22e,$f0c0ffdc
+	dc.l	$f23c9000,$00000000,$41eeff78,$216e0008
+	dc.l	$0000216e,$000c0004,$216e0010,$000861ff
+	dc.l	$000041ee,$1d40ff4f,$41eeff6c,$216e0014
+	dc.l	$0000216e,$00180004,$216e001c,$000861ff
+	dc.l	$000041ce,$1d40ff4e,$220002ae,$00ff00ff
+	dc.l	$ff644280,$102eff63,$41eeff6c,$43eeff78
+	dc.l	$4a016608,$61ff0000,$47986030,$0c010001
+	dc.l	$660861ff,$000047b6,$60220c01,$00026608
+	dc.l	$61ff0000,$47d66014,$0c010003,$660861ff
+	dc.l	$00004952,$600661ff,$00004766,$4cee0303
+	dc.l	$ff9cf22e,$9800ff60,$f22ed040,$ffe84e5e
+	dc.l	$4e754e56,$ff4048ee,$0303ff9c,$f22eb800
+	dc.l	$ff60f22e,$f0c0ffdc,$f23c9000,$00000000
+	dc.l	$f22e4400,$0008f22e,$6800ff78,$41eeff78
+	dc.l	$61ff0000,$412c1d40,$ff4ff22e,$4400000c
+	dc.l	$f22e6800,$ff6c41ee,$ff6c61ff,$00004112
+	dc.l	$1d40ff4e,$220002ae,$00ff00ff,$ff644280
+	dc.l	$102eff63,$41eeff6c,$43eeff78,$4a016608
+	dc.l	$61ff0000,$484a6030,$0c010001,$660861ff
+	dc.l	$0000486a,$60220c01,$00026608,$61ff0000
+	dc.l	$488a6014,$0c010003,$660861ff,$00004896
+	dc.l	$600661ff,$00004818,$4cee0303,$ff9cf22e
+	dc.l	$9800ff60,$f22ed040,$ffe84e5e,$4e754e56
+	dc.l	$ff4048ee,$0303ff9c,$f22eb800,$ff60f22e
+	dc.l	$f0c0ffdc,$f23c9000,$00000000,$f22e5400
+	dc.l	$0008f22e,$6800ff78,$41eeff78,$61ff0000
+	dc.l	$40701d40,$ff4ff22e,$54000010,$f22e6800
+	dc.l	$ff6c41ee,$ff6c61ff,$00004056,$1d40ff4e
+	dc.l	$220002ae,$00ff00ff,$ff644280,$102eff63
+	dc.l	$41eeff6c,$43eeff78,$4a016608,$61ff0000
+	dc.l	$478e6030,$0c010001,$660861ff,$000047ae
+	dc.l	$60220c01,$00026608,$61ff0000,$47ce6014
+	dc.l	$0c010003,$660861ff,$000047da,$600661ff
+	dc.l	$0000475c,$4cee0303,$ff9cf22e,$9800ff60
+	dc.l	$f22ed040,$ffe84e5e,$4e754e56,$ff4048ee
+	dc.l	$0303ff9c,$f22eb800,$ff60f22e,$f0c0ffdc
+	dc.l	$f23c9000,$00000000,$41eeff78,$216e0008
+	dc.l	$0000216e,$000c0004,$216e0010,$000861ff
+	dc.l	$00003fae,$1d40ff4f,$41eeff6c,$216e0014
+	dc.l	$0000216e,$00180004,$216e001c,$000861ff
+	dc.l	$00003f8e,$1d40ff4e,$220002ae,$00ff00ff
+	dc.l	$ff644280,$102eff63,$41eeff6c,$43eeff78
+	dc.l	$4a016608,$61ff0000,$46c66030,$0c010001
+	dc.l	$660861ff,$000046e6,$60220c01,$00026608
+	dc.l	$61ff0000,$47066014,$0c010003,$660861ff
+	dc.l	$00004712,$600661ff,$00004694,$4cee0303
+	dc.l	$ff9cf22e,$9800ff60,$f22ed040,$ffe84e5e
+	dc.l	$4e75bd6a,$aa77ccc9,$94f53de6,$12097aae
+	dc.l	$8da1be5a,$e6452a11,$8ae43ec7,$1de3a534
+	dc.l	$1531bf2a,$01a01a01,$8b590000,$00000000
+	dc.l	$00003ff8,$00008888,$88888888,$59af0000
+	dc.l	$0000bffc,$0000aaaa,$aaaaaaaa,$aa990000
+	dc.l	$00003d2a,$c4d0d601,$1ee3bda9,$396f9f45
+	dc.l	$ac193e21,$eed90612,$c972be92,$7e4fb79d
+	dc.l	$9fcf3efa,$01a01a01,$d4230000,$00000000
+	dc.l	$0000bff5,$0000b60b,$60b60b61,$d4380000
+	dc.l	$00003ffa,$0000aaaa,$aaaaaaaa,$ab5ebf00
+	dc.l	$00002d7c,$00000000,$ff5c6008,$2d7c0000
+	dc.l	$0001ff5c,$f2104800,$f22e6800,$ff842210
+	dc.l	$32280004,$02817fff,$ffff0c81,$3fd78000
+	dc.l	$6c046000,$01780c81,$4004bc7e,$6d046000
+	dc.l	$0468f200,$0080f23a,$54a3d186,$43fb0170
+	dc.l	$00000866,$f22e6080,$ff58222e,$ff58e981
+	dc.l	$d3c1f219,$4828f211,$4428222e,$ff58d2ae
+	dc.l	$ff5ce299,$0c810000,$00006d00,$0088f227
+	dc.l	$e00cf22e,$6800ff84,$f2000023,$f23a5580
+	dc.l	$fed2f23a,$5500fed4,$f2000080,$f20004a3
+	dc.l	$e2990281,$80000000,$b3aeff84,$f20005a3
+	dc.l	$f2000523,$f23a55a2,$febaf23a,$5522febc
+	dc.l	$f20005a3,$f2000523,$f23a55a2,$feb6f23a
+	dc.l	$4922fec0,$f2000ca3,$f2000123,$f23a48a2
+	dc.l	$fec2f22e,$4823ff84,$f20008a2,$f2000423
+	dc.l	$f21fd030,$f2009000,$f22e4822,$ff8460ff
+	dc.l	$00004006,$f227e00c,$f2000023,$f23a5500
+	dc.l	$fea2f23a,$5580fea4,$f2000080,$f20004a3
+	dc.l	$f22e6800,$ff84e299,$02818000,$0000f200
+	dc.l	$0523b3ae,$ff840281,$80000000,$f20005a3
+	dc.l	$00813f80,$00002d41,$ff54f23a,$5522fe74
+	dc.l	$f23a55a2,$fe76f200,$0523f200,$05a3f23a
+	dc.l	$5522fe70,$f23a49a2,$fe7af200,$0523f200
+	dc.l	$0ca3f23a,$4922fe7c,$f23a44a2,$fe82f200
+	dc.l	$0823f200,$0422f22e,$4823ff84,$f21fd030
+	dc.l	$f2009000,$f22e4422,$ff5460ff,$00003f6a
+	dc.l	$0c813fff,$80006eff,$00000300,$222eff5c
+	dc.l	$0c810000,$00006e14,$f2009000,$123c0003
+	dc.l	$f22e4800,$ff8460ff,$00003f36,$f23c4400
+	dc.l	$3f800000,$f2009000,$f23c4422,$80800000
+	dc.l	$60ff0000,$3f2c60ff,$00003f64,$f23c4400
+	dc.l	$3f800000,$60ff0000,$3f182d7c,$00000004
+	dc.l	$ff5cf210,$4800f22e,$6800ff84,$22103228
+	dc.l	$00040281,$7fffffff,$0c813fd7,$80006c04
+	dc.l	$60000240,$0c814004,$bc7e6d04,$6000027a
+	dc.l	$f2000080,$f23a54a3,$cf9843fb,$01700000
+	dc.l	$0678f22e,$6080ff58,$222eff58,$e981d3c1
+	dc.l	$f2194828,$f2114428,$222eff58,$e2990c81
+	dc.l	$00000000,$6c000106,$f227e004,$f22e6800
+	dc.l	$ff84f200,$0023f23a,$5480fce8,$f23a5500
+	dc.l	$fd32f200,$00a3f200,$01232f02,$2401e29a
+	dc.l	$02828000,$0000b382,$02828000,$0000f23a
+	dc.l	$54a2fcc8,$f23a5522,$fd12f200,$00a3b5ae
+	dc.l	$ff84241f,$f2000123,$e2990281,$80000000
+	dc.l	$2d7c3f80,$0000ff54,$b3aeff54,$f23a54a2
+	dc.l	$fca2f23a,$5522fcec,$f20000a3,$f2000123
+	dc.l	$f22e6800,$ff90f23a,$54a2fc90,$b3aeff90
+	dc.l	$f23a5522,$fcd6f200,$00a3f200,$0123f23a
+	dc.l	$54a2fc80,$f23a5522,$fccaf200,$00a3f200
+	dc.l	$0123f23a,$48a2fc7c,$f23a4922,$fcc6f200
+	dc.l	$00a3f200,$0123f23a,$48a2fc78,$f23a4922
+	dc.l	$fcc2f200,$00a3f200,$0823f22e,$48a3ff84
+	dc.l	$f23a4422,$fcbaf22e,$4823ff90,$f21fd020
+	dc.l	$f2009000,$f22e48a2,$ff8461ff,$00003e22
+	dc.l	$f22e4422,$ff5460ff,$00003d9e,$f227e004
+	dc.l	$f22e6800,$ff84f200,$0023f23a,$5480fc34
+	dc.l	$f23a5500,$fbdef200,$00a3f22e,$6800ff90
+	dc.l	$f2000123,$e2990281,$80000000,$f23a54a2
+	dc.l	$fc1af23a,$5522fbc4,$b3aeff84,$b3aeff90
+	dc.l	$f20000a3,$00813f80,$00002d41,$ff54f200
+	dc.l	$0123f23a,$54a2fbfc,$f23a5522,$fba6f200
+	dc.l	$00a3f200,$0123f23a,$54a2fbf0,$f23a5522
+	dc.l	$fb9af200,$00a3f200,$0123f23a,$54a2fbe4
+	dc.l	$f23a5522,$fb8ef200,$00a3f200,$0123f23a
+	dc.l	$48a2fbe0,$f23a4922,$fb8af200,$00a3f200
+	dc.l	$0123f23a,$48a2fbdc,$f23a4922,$fb86f200
+	dc.l	$00a3f200,$0823f23a,$44a2fbd4,$f22e4823
+	dc.l	$ff84f22e,$48a3ff90,$f21fd020,$f2009000
+	dc.l	$f22e44a2,$ff5461ff,$00003d36,$f22e4822
+	dc.l	$ff8460ff,$00003cb2,$0c813fff,$80006e00
+	dc.l	$0048f23c,$44803f80,$0000f200,$9000f23c
+	dc.l	$44a80080,$000061ff,$00003d06,$f200b000
+	dc.l	$123c0003,$f22e4800,$ff8460ff,$00003c72
+	dc.l	$2f00f23c,$44803f80,$000061ff,$00003ce2
+	dc.l	$201f60ff,$00003ca8,$f227e03c,$2f02f23c
+	dc.l	$44800000,$00000c81,$7ffeffff,$66523d7c
+	dc.l	$7ffeff84,$2d7cc90f,$daa2ff88,$42aeff8c
+	dc.l	$3d7c7fdc,$ff902d7c,$85a308d3,$ff9442ae
+	dc.l	$ff98f200,$003af294,$000e002e,$0080ff84
+	dc.l	$002e0080,$ff90f22e,$4822ff84,$f2000080
+	dc.l	$f22e4822,$ff90f200,$00a8f22e,$48a2ff90
+	dc.l	$f22e6800,$ff84322e,$ff842241,$02810000
+	dc.l	$7fff0481,$00003fff,$0c810000,$001c6f0e
+	dc.l	$04810000,$001b1d7c,$0000ff58,$60084281
+	dc.l	$1d7c0001,$ff58243c,$00003ffe,$94812d7c
+	dc.l	$a2f9836e,$ff882d7c,$4e44152a,$ff8c3d42
+	dc.l	$ff84f200,$0100f22e,$4923ff84,$24094842
+	dc.l	$02828000,$00000082,$5f000000,$2d42ff54
+	dc.l	$f22e4522,$ff54f22e,$4528ff54,$24010682
+	dc.l	$00003fff,$3d42ff84,$2d7cc90f,$daa2ff88
+	dc.l	$42aeff8c,$06810000,$3fdd3d41,$ff902d7c
+	dc.l	$85a308d3,$ff9442ae,$ff98122e,$ff58f200
+	dc.l	$0a00f22e,$4a23ff84,$f2000a80,$f22e4aa3
+	dc.l	$ff90f200,$1180f200,$15a2f200,$0e28f200
+	dc.l	$0c28f200,$1622f200,$0180f200,$10a8f200
+	dc.l	$04220c01,$00006e00,$000ef200,$01a8f200
+	dc.l	$0ca26000,$ff0cf22e,$6100ff58,$241ff21f
+	dc.l	$d03c222e,$ff5c0c81,$00000004,$6d00fa4c
+	dc.l	$6000fc36,$3ea0b759,$f50f8688,$bef2baa5
+	dc.l	$a8924f04,$bf346f59,$b39ba65f,$00000000
+	dc.l	$00000000,$3ff60000,$e073d3fc,$199c4a00
+	dc.l	$00000000,$3ff90000,$d23cd684,$15d95fa1
+	dc.l	$00000000,$bffc0000,$8895a6c5,$fb423bca
+	dc.l	$00000000,$bffd0000,$eef57e0d,$a84bc8ce
+	dc.l	$00000000,$3ffc0000,$a2f9836e,$4e44152a
+	dc.l	$00000000,$40010000,$c90fdaa2,$00000000
+	dc.l	$00000000,$3fdf0000,$85a308d4,$00000000
+	dc.l	$00000000,$c0040000,$c90fdaa2,$2168c235
+	dc.l	$21800000,$c0040000,$c2c75bcd,$105d7c23
+	dc.l	$a0d00000,$c0040000,$bc7edcf7,$ff523611
+	dc.l	$a1e80000,$c0040000,$b6365e22,$ee46f000
+	dc.l	$21480000,$c0040000,$afeddf4d,$dd3ba9ee
+	dc.l	$a1200000,$c0040000,$a9a56078,$cc3063dd
+	dc.l	$21fc0000,$c0040000,$a35ce1a3,$bb251dcb
+	dc.l	$21100000,$c0040000,$9d1462ce,$aa19d7b9
+	dc.l	$a1580000,$c0040000,$96cbe3f9,$990e91a8
+	dc.l	$21e00000,$c0040000,$90836524,$88034b96
+	dc.l	$20b00000,$c0040000,$8a3ae64f,$76f80584
+	dc.l	$a1880000,$c0040000,$83f2677a,$65ecbf73
+	dc.l	$21c40000,$c0030000,$fb53d14a,$a9c2f2c2
+	dc.l	$20000000,$c0030000,$eec2d3a0,$87ac669f
+	dc.l	$21380000,$c0030000,$e231d5f6,$6595da7b
+	dc.l	$a1300000,$c0030000,$d5a0d84c,$437f4e58
+	dc.l	$9fc00000,$c0030000,$c90fdaa2,$2168c235
+	dc.l	$21000000,$c0030000,$bc7edcf7,$ff523611
+	dc.l	$a1680000,$c0030000,$afeddf4d,$dd3ba9ee
+	dc.l	$a0a00000,$c0030000,$a35ce1a3,$bb251dcb
+	dc.l	$20900000,$c0030000,$96cbe3f9,$990e91a8
+	dc.l	$21600000,$c0030000,$8a3ae64f,$76f80584
+	dc.l	$a1080000,$c0020000,$fb53d14a,$a9c2f2c2
+	dc.l	$1f800000,$c0020000,$e231d5f6,$6595da7b
+	dc.l	$a0b00000,$c0020000,$c90fdaa2,$2168c235
+	dc.l	$20800000,$c0020000,$afeddf4d,$dd3ba9ee
+	dc.l	$a0200000,$c0020000,$96cbe3f9,$990e91a8
+	dc.l	$20e00000,$c0010000,$fb53d14a,$a9c2f2c2
+	dc.l	$1f000000,$c0010000,$c90fdaa2,$2168c235
+	dc.l	$20000000,$c0010000,$96cbe3f9,$990e91a8
+	dc.l	$20600000,$c0000000,$c90fdaa2,$2168c235
+	dc.l	$1f800000,$bfff0000,$c90fdaa2,$2168c235
+	dc.l	$1f000000,$00000000,$00000000,$00000000
+	dc.l	$00000000,$3fff0000,$c90fdaa2,$2168c235
+	dc.l	$9f000000,$40000000,$c90fdaa2,$2168c235
+	dc.l	$9f800000,$40010000,$96cbe3f9,$990e91a8
+	dc.l	$a0600000,$40010000,$c90fdaa2,$2168c235
+	dc.l	$a0000000,$40010000,$fb53d14a,$a9c2f2c2
+	dc.l	$9f000000,$40020000,$96cbe3f9,$990e91a8
+	dc.l	$a0e00000,$40020000,$afeddf4d,$dd3ba9ee
+	dc.l	$20200000,$40020000,$c90fdaa2,$2168c235
+	dc.l	$a0800000,$40020000,$e231d5f6,$6595da7b
+	dc.l	$20b00000,$40020000,$fb53d14a,$a9c2f2c2
+	dc.l	$9f800000,$40030000,$8a3ae64f,$76f80584
+	dc.l	$21080000,$40030000,$96cbe3f9,$990e91a8
+	dc.l	$a1600000,$40030000,$a35ce1a3,$bb251dcb
+	dc.l	$a0900000,$40030000,$afeddf4d,$dd3ba9ee
+	dc.l	$20a00000,$40030000,$bc7edcf7,$ff523611
+	dc.l	$21680000,$40030000,$c90fdaa2,$2168c235
+	dc.l	$a1000000,$40030000,$d5a0d84c,$437f4e58
+	dc.l	$1fc00000,$40030000,$e231d5f6,$6595da7b
+	dc.l	$21300000,$40030000,$eec2d3a0,$87ac669f
+	dc.l	$a1380000,$40030000,$fb53d14a,$a9c2f2c2
+	dc.l	$a0000000,$40040000,$83f2677a,$65ecbf73
+	dc.l	$a1c40000,$40040000,$8a3ae64f,$76f80584
+	dc.l	$21880000,$40040000,$90836524,$88034b96
+	dc.l	$a0b00000,$40040000,$96cbe3f9,$990e91a8
+	dc.l	$a1e00000,$40040000,$9d1462ce,$aa19d7b9
+	dc.l	$21580000,$40040000,$a35ce1a3,$bb251dcb
+	dc.l	$a1100000,$40040000,$a9a56078,$cc3063dd
+	dc.l	$a1fc0000,$40040000,$afeddf4d,$dd3ba9ee
+	dc.l	$21200000,$40040000,$b6365e22,$ee46f000
+	dc.l	$a1480000,$40040000,$bc7edcf7,$ff523611
+	dc.l	$21e80000,$40040000,$c2c75bcd,$105d7c23
+	dc.l	$20d00000,$40040000,$c90fdaa2,$2168c235
+	dc.l	$a1800000,$f2104800,$22103228,$00040281
+	dc.l	$7fffffff,$0c813fd7,$80006c04,$60000134
+	dc.l	$0c814004,$bc7e6d04,$60000144,$f2000080
+	dc.l	$f23a54a3,$c6dc43fa,$fdbcf201,$6080e981
+	dc.l	$d3c1f219,$4828f211,$4428ea99,$02818000
+	dc.l	$0000f227,$e00c0c81,$00000000,$6d000072
+	dc.l	$f2000080,$f20004a3,$f23a5580,$faf8f23a
+	dc.l	$5500fafa,$f20005a3,$f2000523,$f23a55a2
+	dc.l	$faf4f23a,$4922fafe,$f20005a3,$f2000523
+	dc.l	$f23a49a2,$fb00f23a,$4922fb0a,$f20005a3
+	dc.l	$f2000523,$f23a49a2,$fb0cf200,$0123f200
+	dc.l	$0ca3f200,$0822f23c,$44a23f80,$0000f21f
+	dc.l	$d030f200,$9000f200,$042060ff,$0000357a
+	dc.l	$f2000080,$f2000023,$f23a5580,$fa88f23a
+	dc.l	$5500fa8a,$f20001a3,$f2000123,$f23a55a2
+	dc.l	$fa84f23a,$4922fa8e,$f20001a3,$f2000123
+	dc.l	$f23a49a2,$fa90f23a,$4922fa9a,$f20001a3
+	dc.l	$f2000123,$f23a49a2,$fa9cf200,$0523f200
+	dc.l	$0c23f200,$08a2f23c,$44223f80,$0000f21f
+	dc.l	$d030f227,$68800a97,$80000000,$f2009000
+	dc.l	$f21f4820,$60ff0000,$35000c81,$3fff8000
+	dc.l	$6e1cf227,$6800f200,$9000123c,$0003f21f
+	dc.l	$480060ff,$000034da,$60ff0000,$3522f227
+	dc.l	$e03c2f02,$f23c4480,$00000000,$0c817ffe
+	dc.l	$ffff6652,$3d7c7ffe,$ff842d7c,$c90fdaa2
+	dc.l	$ff8842ae,$ff8c3d7c,$7fdcff90,$2d7c85a3
+	dc.l	$08d3ff94,$42aeff98,$f200003a,$f294000e
+	dc.l	$002e0080,$ff84002e,$0080ff90,$f22e4822
+	dc.l	$ff84f200,$0080f22e,$4822ff90,$f20000a8
+	dc.l	$f22e48a2,$ff90f22e,$6800ff84,$322eff84
+	dc.l	$22410281,$00007fff,$04810000,$3fff0c81
+	dc.l	$0000001c,$6f0e0481,$0000001b,$1d7c0000
+	dc.l	$ff586008,$42811d7c,$0001ff58,$243c0000
+	dc.l	$3ffe9481,$2d7ca2f9,$836eff88,$2d7c4e44
+	dc.l	$152aff8c,$3d42ff84,$f2000100,$f22e4923
+	dc.l	$ff842409,$48420282,$80000000,$00825f00
+	dc.l	$00002d42,$ff54f22e,$4522ff54,$f22e4528
+	dc.l	$ff542401,$06820000,$3fff3d42,$ff842d7c
+	dc.l	$c90fdaa2,$ff8842ae,$ff8c0681,$00003fdd
+	dc.l	$3d41ff90,$2d7c85a3,$08d3ff94,$42aeff98
+	dc.l	$122eff58,$f2000a00,$f22e4a23,$ff84f200
+	dc.l	$0a80f22e,$4aa3ff90,$f2001180,$f20015a2
+	dc.l	$f2000e28,$f2000c28,$f2001622,$f2000180
+	dc.l	$f20010a8,$f2000422,$0c010000,$6e00000e
+	dc.l	$f20001a8,$f2000ca2,$6000ff0c,$f22e6100
+	dc.l	$ff54241f,$f21fd03c,$222eff54,$e2996000
+	dc.l	$fd72bff6,$687e3149,$87d84002,$ac6934a2
+	dc.l	$6db3bfc2,$476f4e1d,$a28e3fb3,$44447f87
+	dc.l	$6989bfb7,$44ee7faf,$45db3fbc,$71c64694
+	dc.l	$0220bfc2,$49249218,$72f93fc9,$99999999
+	dc.l	$8fa9bfd5,$55555555,$5555bfb7,$0bf39853
+	dc.l	$9e6a3fbc,$7187962d,$1d7dbfc2,$49248271
+	dc.l	$07b83fc9,$99999996,$263ebfd5,$55555555
+	dc.l	$55363fff,$0000c90f,$daa22168,$c2350000
+	dc.l	$0000bfff,$0000c90f,$daa22168,$c2350000
+	dc.l	$00000001,$00008000,$00000000,$00000000
+	dc.l	$00008001,$00008000,$00000000,$00000000
+	dc.l	$00003ffb,$000083d1,$52c5060b,$7a510000
+	dc.l	$00003ffb,$00008bc8,$54456549,$8b8b0000
+	dc.l	$00003ffb,$000093be,$40601762,$6b0d0000
+	dc.l	$00003ffb,$00009bb3,$078d35ae,$c2020000
+	dc.l	$00003ffb,$0000a3a6,$9a525ddc,$e7de0000
+	dc.l	$00003ffb,$0000ab98,$e9436276,$56190000
+	dc.l	$00003ffb,$0000b389,$e502f9c5,$98620000
+	dc.l	$00003ffb,$0000bb79,$7e436b09,$e6fb0000
+	dc.l	$00003ffb,$0000c367,$a5c739e5,$f4460000
+	dc.l	$00003ffb,$0000cb54,$4c61cff7,$d5c60000
+	dc.l	$00003ffb,$0000d33f,$62f82488,$533e0000
+	dc.l	$00003ffb,$0000db28,$da816240,$4c770000
+	dc.l	$00003ffb,$0000e310,$a4078ad3,$4f180000
+	dc.l	$00003ffb,$0000eaf6,$b0a8188e,$e1eb0000
+	dc.l	$00003ffb,$0000f2da,$f1949dbe,$79d50000
+	dc.l	$00003ffb,$0000fabd,$581361d4,$7e3e0000
+	dc.l	$00003ffc,$00008346,$ac210959,$ecc40000
+	dc.l	$00003ffc,$00008b23,$2a083042,$82d80000
+	dc.l	$00003ffc,$000092fb,$70b8d29a,$e2f90000
+	dc.l	$00003ffc,$00009acf,$476f5ccd,$1cb40000
+	dc.l	$00003ffc,$0000a29e,$76304954,$f23f0000
+	dc.l	$00003ffc,$0000aa68,$c5d08ab8,$52300000
+	dc.l	$00003ffc,$0000b22d,$fffd9d53,$9f830000
+	dc.l	$00003ffc,$0000b9ed,$ef453e90,$0ea50000
+	dc.l	$00003ffc,$0000c1a8,$5f1cc75e,$3ea50000
+	dc.l	$00003ffc,$0000c95d,$1be82813,$8de60000
+	dc.l	$00003ffc,$0000d10b,$f300840d,$2de40000
+	dc.l	$00003ffc,$0000d8b4,$b2ba6bc0,$5e7a0000
+	dc.l	$00003ffc,$0000e057,$2a6bb423,$35f60000
+	dc.l	$00003ffc,$0000e7f3,$2a70ea9c,$aa8f0000
+	dc.l	$00003ffc,$0000ef88,$843264ec,$efaa0000
+	dc.l	$00003ffc,$0000f717,$0a28ecc0,$66660000
+	dc.l	$00003ffd,$0000812f,$d288332d,$ad320000
+	dc.l	$00003ffd,$000088a8,$d1b1218e,$4d640000
+	dc.l	$00003ffd,$00009012,$ab3f23e4,$aee80000
+	dc.l	$00003ffd,$0000976c,$c3d411e7,$f1b90000
+	dc.l	$00003ffd,$00009eb6,$89493889,$a2270000
+	dc.l	$00003ffd,$0000a5ef,$72c34487,$361b0000
+	dc.l	$00003ffd,$0000ad17,$00baf07a,$72270000
+	dc.l	$00003ffd,$0000b42c,$bcfafd37,$efb70000
+	dc.l	$00003ffd,$0000bb30,$3a940ba8,$0f890000
+	dc.l	$00003ffd,$0000c221,$15c6fcae,$bbaf0000
+	dc.l	$00003ffd,$0000c8fe,$f3e68633,$12210000
+	dc.l	$00003ffd,$0000cfc9,$8330b400,$0c700000
+	dc.l	$00003ffd,$0000d680,$7aa1102c,$5bf90000
+	dc.l	$00003ffd,$0000dd23,$99bc3125,$2aa30000
+	dc.l	$00003ffd,$0000e3b2,$a8556b8f,$c5170000
+	dc.l	$00003ffd,$0000ea2d,$764f6431,$59890000
+	dc.l	$00003ffd,$0000f3bf,$5bf8bad1,$a21d0000
+	dc.l	$00003ffe,$0000801c,$e39e0d20,$5c9a0000
+	dc.l	$00003ffe,$00008630,$a2dada1e,$d0660000
+	dc.l	$00003ffe,$00008c1a,$d445f3e0,$9b8c0000
+	dc.l	$00003ffe,$000091db,$8f1664f3,$50e20000
+	dc.l	$00003ffe,$00009773,$1420365e,$538c0000
+	dc.l	$00003ffe,$00009ce1,$c8e6a0b8,$cdba0000
+	dc.l	$00003ffe,$0000a228,$32dbcada,$ae090000
+	dc.l	$00003ffe,$0000a746,$f2ddb760,$22940000
+	dc.l	$00003ffe,$0000ac3e,$c0fb997d,$d6a20000
+	dc.l	$00003ffe,$0000b110,$688aebdc,$6f6a0000
+	dc.l	$00003ffe,$0000b5bc,$c49059ec,$c4b00000
+	dc.l	$00003ffe,$0000ba44,$bc7dd470,$782f0000
+	dc.l	$00003ffe,$0000bea9,$4144fd04,$9aac0000
+	dc.l	$00003ffe,$0000c2eb,$4abb6616,$28b60000
+	dc.l	$00003ffe,$0000c70b,$d54ce602,$ee140000
+	dc.l	$00003ffe,$0000cd00,$0549adec,$71590000
+	dc.l	$00003ffe,$0000d484,$57d2d8ea,$4ea30000
+	dc.l	$00003ffe,$0000db94,$8da712de,$ce3b0000
+	dc.l	$00003ffe,$0000e238,$55f969e8,$096a0000
+	dc.l	$00003ffe,$0000e877,$1129c435,$32590000
+	dc.l	$00003ffe,$0000ee57,$c16e0d37,$9c0d0000
+	dc.l	$00003ffe,$0000f3e1,$0211a87c,$37790000
+	dc.l	$00003ffe,$0000f919,$039d758b,$8d410000
+	dc.l	$00003ffe,$0000fe05,$8b8f6493,$5fb30000
+	dc.l	$00003fff,$00008155,$fb497b68,$5d040000
+	dc.l	$00003fff,$00008388,$9e3549d1,$08e10000
+	dc.l	$00003fff,$0000859c,$fa76511d,$724b0000
+	dc.l	$00003fff,$00008795,$2ecfff81,$31e70000
+	dc.l	$00003fff,$00008973,$2fd19557,$641b0000
+	dc.l	$00003fff,$00008b38,$cad10193,$2a350000
+	dc.l	$00003fff,$00008ce7,$a8d8301e,$e6b50000
+	dc.l	$00003fff,$00008f46,$a39e2eae,$52810000
+	dc.l	$00003fff,$0000922d,$a7d79188,$84870000
+	dc.l	$00003fff,$000094d1,$9fcbdedf,$52410000
+	dc.l	$00003fff,$0000973a,$b94419d2,$a08b0000
+	dc.l	$00003fff,$0000996f,$f00e08e1,$0b960000
+	dc.l	$00003fff,$00009b77,$3f951232,$1da70000
+	dc.l	$00003fff,$00009d55,$cc320f93,$56240000
+	dc.l	$00003fff,$00009f10,$0575006c,$c5710000
+	dc.l	$00003fff,$0000a0a9,$c290d97c,$c06c0000
+	dc.l	$00003fff,$0000a226,$59ebebc0,$630a0000
+	dc.l	$00003fff,$0000a388,$b4aff6ef,$0ec90000
+	dc.l	$00003fff,$0000a4d3,$5f1061d2,$92c40000
+	dc.l	$00003fff,$0000a608,$95dcfbe3,$187e0000
+	dc.l	$00003fff,$0000a72a,$51dc7367,$beac0000
+	dc.l	$00003fff,$0000a83a,$51530956,$168f0000
+	dc.l	$00003fff,$0000a93a,$20077539,$546e0000
+	dc.l	$00003fff,$0000aa9e,$7245023b,$26050000
+	dc.l	$00003fff,$0000ac4c,$84ba6fe4,$d58f0000
+	dc.l	$00003fff,$0000adce,$4a4a606b,$97120000
+	dc.l	$00003fff,$0000af2a,$2dcd8d26,$3c9c0000
+	dc.l	$00003fff,$0000b065,$6f81f222,$65c70000
+	dc.l	$00003fff,$0000b184,$65150f71,$496a0000
+	dc.l	$00003fff,$0000b28a,$aa156f9a,$da350000
+	dc.l	$00003fff,$0000b37b,$44ff3766,$b8950000
+	dc.l	$00003fff,$0000b458,$c3dce963,$04330000
+	dc.l	$00003fff,$0000b525,$529d5622,$46bd0000
+	dc.l	$00003fff,$0000b5e2,$cca95f9d,$88cc0000
+	dc.l	$00003fff,$0000b692,$cada7aca,$1ada0000
+	dc.l	$00003fff,$0000b736,$aea7a692,$58380000
+	dc.l	$00003fff,$0000b7cf,$ab287e9f,$7b360000
+	dc.l	$00003fff,$0000b85e,$cc66cb21,$98350000
+	dc.l	$00003fff,$0000b8e4,$fd5a20a5,$93da0000
+	dc.l	$00003fff,$0000b99f,$41f64aff,$9bb50000
+	dc.l	$00003fff,$0000ba7f,$1e17842b,$be7b0000
+	dc.l	$00003fff,$0000bb47,$12857637,$e17d0000
+	dc.l	$00003fff,$0000bbfa,$be8a4788,$df6f0000
+	dc.l	$00003fff,$0000bc9d,$0fad2b68,$9d790000
+	dc.l	$00003fff,$0000bd30,$6a39471e,$cd860000
+	dc.l	$00003fff,$0000bdb6,$c731856a,$f18a0000
+	dc.l	$00003fff,$0000be31,$cac502e8,$0d700000
+	dc.l	$00003fff,$0000bea2,$d55ce331,$94e20000
+	dc.l	$00003fff,$0000bf0b,$10b7c031,$28f00000
+	dc.l	$00003fff,$0000bf6b,$7a18dacb,$778d0000
+	dc.l	$00003fff,$0000bfc4,$ea4663fa,$18f60000
+	dc.l	$00003fff,$0000c018,$1bde8b89,$a4540000
+	dc.l	$00003fff,$0000c065,$b066cfbf,$64390000
+	dc.l	$00003fff,$0000c0ae,$345f5634,$0ae60000
+	dc.l	$00003fff,$0000c0f2,$22919cb9,$e6a70000
+	dc.l	$0000f210,$48002210,$32280004,$f22e6800
+	dc.l	$ff840281,$7fffffff,$0c813ffb,$80006c04
+	dc.l	$600000d0,$0c814002,$ffff6f04,$6000014c
+	dc.l	$02aef800,$0000ff88,$00ae0400,$0000ff88
+	dc.l	$2d7c0000,$0000ff8c,$f2000080,$f22e48a3
+	dc.l	$ff84f22e,$4828ff84,$f23c44a2,$3f800000
+	dc.l	$f2000420,$2f022401,$02810000,$78000282
+	dc.l	$7fff0000,$04823ffb,$0000e282,$d282ee81
+	dc.l	$43faf780,$d3c12d59,$ff902d59,$ff942d59
+	dc.l	$ff98222e,$ff840281,$80000000,$83aeff90
+	dc.l	$241ff227,$e004f200,$0080f200,$04a3f23a
+	dc.l	$5500f6a0,$f2000522,$f2000523,$f20000a3
+	dc.l	$f23a5522,$f696f23a,$54a3f698,$f20008a3
+	dc.l	$f2000422,$f21fd020,$f2009000,$f22e4822
+	dc.l	$ff9060ff,$000029d2,$0c813fff,$80006e00
+	dc.l	$008a0c81,$3fd78000,$6d00006c,$f227e00c
+	dc.l	$f2000023,$f2000080,$f20004a3,$f23a5500
+	dc.l	$f65af23a,$5580f65c,$f2000523,$f20005a3
+	dc.l	$f23a5522,$f656f23a,$55a2f658,$f2000523
+	dc.l	$f2000ca3,$f23a5522,$f652f23a,$54a2f654
+	dc.l	$f2000123,$f22e4823,$ff84f200,$08a2f200
+	dc.l	$0423f21f,$d030f200,$9000f22e,$4822ff84
+	dc.l	$60ff0000,$2954f200,$9000123c,$0003f22e
+	dc.l	$4800ff84,$60ff0000,$29380c81,$40638000
+	dc.l	$6e00008e,$f227e00c,$f23c4480,$bf800000
+	dc.l	$f20000a0,$f2000400,$f2000023,$f22e6880
+	dc.l	$ff84f200,$0080f200,$04a3f23a,$5580f5ec
+	dc.l	$f23a5500,$f5eef200,$05a3f200,$0523f23a
+	dc.l	$55a2f5e8,$f23a5522,$f5eaf200,$0ca3f200
+	dc.l	$0123f23a,$54a2f5e4,$f22e4823,$ff84f200
+	dc.l	$08a2f200,$0423f22e,$4822ff84,$f21fd030
+	dc.l	$f2009000,$4a106a0c,$f23a4822,$f5d660ff
+	dc.l	$000028c6,$f23a4822,$f5ba60ff,$000028b2
+	dc.l	$4a106a16,$f23a4800,$f5baf200,$9000f23a
+	dc.l	$4822f5c0,$60ff0000,$28a0f23a,$4800f594
+	dc.l	$f2009000,$f23a4822,$f5ba60ff,$00002882
+	dc.l	$60ff0000,$28baf210,$48002210,$32280004
+	dc.l	$02817fff,$ffff0c81,$3fff8000,$6c4e0c81
+	dc.l	$3fd78000,$6d00007c,$f23c4480,$3f800000
+	dc.l	$f20000a8,$f227e004,$f23c4500,$3f800000
+	dc.l	$f2000122,$f20008a3,$f21fd020,$f2000484
+	dc.l	$f2000420,$f227e001,$41d761ff,$fffffd66
+	dc.l	$dffc0000,$000c60ff,$0000280e,$f2000018
+	dc.l	$f23c4438,$3f800000,$f2d20000,$265af23a
+	dc.l	$4800b8ae,$22100281,$80000000,$00813f80
+	dc.l	$00002f01,$f2009000,$f21f4423,$60ff0000
+	dc.l	$27d8f200,$9000123c,$0003f210,$480060ff
+	dc.l	$000027be,$60ff0000,$2806f210,$48002210
+	dc.l	$32280004,$02817fff,$ffff0c81,$3fff8000
+	dc.l	$6c44f23c,$44803f80,$0000f200,$00a2f200
+	dc.l	$001af23c,$44223f80,$0000f200,$0420f200
+	dc.l	$00042f00,$4280f227,$e00141d7,$61ffffff
+	dc.l	$fcc4dffc,$0000000c,$f21f9000,$f2000022
+	dc.l	$60ff0000,$276cf200,$0018f23c,$44383f80
+	dc.l	$0000f2d2,$000025b0,$4a106a18,$f23a4800
+	dc.l	$b7f0f200,$9000f23c,$44220080,$000060ff
+	dc.l	$0000273e,$60ff0000,$2988f200,$9000f23a
+	dc.l	$4800b7de,$60ff0000,$27283fdc,$000082e3
+	dc.l	$08654361,$c4c60000,$00003fa5,$55555555
+	dc.l	$4cc13fc5,$55555555,$4a543f81,$11111117
+	dc.l	$43853fa5,$55555555,$4f5a3fc5,$55555555
+	dc.l	$55550000,$00000000,$00003ec7,$1de3a577
+	dc.l	$46823efa,$01a019d7,$cb683f2a,$01a01a01
+	dc.l	$9df33f56,$c16c16c1,$70e23f81,$11111111
+	dc.l	$11113fa5,$55555555,$55553ffc,$0000aaaa
+	dc.l	$aaaaaaaa,$aaab0000,$000048b0,$00000000
+	dc.l	$00003730,$00000000,$00003fff,$00008000
+	dc.l	$00000000,$00000000,$00003fff,$00008164
+	dc.l	$d1f3bc03,$07749f84,$1a9b3fff,$000082cd
+	dc.l	$8698ac2b,$a1d89fc1,$d5b93fff,$0000843a
+	dc.l	$28c3acde,$4048a072,$83693fff,$000085aa
+	dc.l	$c367cc48,$7b141fc5,$c95c3fff,$0000871f
+	dc.l	$61969e8d,$10101ee8,$5c9f3fff,$00008898
+	dc.l	$0e8092da,$85289fa2,$07293fff,$00008a14
+	dc.l	$d575496e,$fd9ca07b,$f9af3fff,$00008b95
+	dc.l	$c1e3ea8b,$d6e8a002,$0dcf3fff,$00008d1a
+	dc.l	$df5b7e5b,$a9e4205a,$63da3fff,$00008ea4
+	dc.l	$398b45cd,$53c01eb7,$00513fff,$00009031
+	dc.l	$dc431466,$b1dc1f6e,$b0293fff,$000091c3
+	dc.l	$d373ab11,$c338a078,$14943fff,$0000935a
+	dc.l	$2b2f13e6,$e92c9eb3,$19b03fff,$000094f4
+	dc.l	$efa8fef7,$09602017,$457d3fff,$00009694
+	dc.l	$2d372018,$5a001f11,$d5373fff,$00009837
+	dc.l	$f0518db8,$a9709fb9,$52dd3fff,$000099e0
+	dc.l	$459320b7,$fa641fe4,$30873fff,$00009b8d
+	dc.l	$39b9d54e,$55381fa2,$a8183fff,$00009d3e
+	dc.l	$d9a72cff,$b7501fde,$494d3fff,$00009ef5
+	dc.l	$326091a1,$11ac2050,$48903fff,$0000a0b0
+	dc.l	$510fb971,$4fc4a073,$691c3fff,$0000a270
+	dc.l	$43030c49,$68181f9b,$7a053fff,$0000a435
+	dc.l	$15ae09e6,$80a0a079,$71263fff,$0000a5fe
+	dc.l	$d6a9b151,$38eca071,$a1403fff,$0000a7cd
+	dc.l	$93b4e965,$3568204f,$62da3fff,$0000a9a1
+	dc.l	$5ab4ea7c,$0ef81f28,$3c4a3fff,$0000ab7a
+	dc.l	$39b5a93e,$d3389f9a,$7fdc3fff,$0000ad58
+	dc.l	$3eea42a1,$4ac8a05b,$3fac3fff,$0000af3b
+	dc.l	$78ad690a,$43741fdf,$26103fff,$0000b123
+	dc.l	$f581d2ac,$25909f70,$5f903fff,$0000b311
+	dc.l	$c412a911,$2488201f,$678a3fff,$0000b504
+	dc.l	$f333f9de,$64841f32,$fb133fff,$0000b6fd
+	dc.l	$91e328d1,$77902003,$8b303fff,$0000b8fb
+	dc.l	$af4762fb,$9ee8200d,$c3cc3fff,$0000baff
+	dc.l	$5ab2133e,$45fc9f8b,$2ae63fff,$0000bd08
+	dc.l	$a39f580c,$36c0a02b,$bf703fff,$0000bf17
+	dc.l	$99b67a73,$1084a00b,$f5183fff,$0000c12c
+	dc.l	$4cca6670,$9458a041,$dd413fff,$0000c346
+	dc.l	$ccda2497,$64089fdf,$137b3fff,$0000c567
+	dc.l	$2a115506,$dadc201f,$15683fff,$0000c78d
+	dc.l	$74c8abb9,$b15c1fc1,$3a2e3fff,$0000c9b9
+	dc.l	$bd866e2f,$27a4a03f,$8f033fff,$0000cbec
+	dc.l	$14fef272,$7c5c1ff4,$907d3fff,$0000ce24
+	dc.l	$8c151f84,$80e49e6e,$53e43fff,$0000d063
+	dc.l	$33daef2b,$25941fd6,$d45c3fff,$0000d2a8
+	dc.l	$1d91f12a,$e45ca076,$edb93fff,$0000d4f3
+	dc.l	$5aabcfed,$fa209fa6,$de213fff,$0000d744
+	dc.l	$fccad69d,$6af41ee6,$9a2f3fff,$0000d99d
+	dc.l	$15c278af,$d7b4207f,$439f3fff,$0000dbfb
+	dc.l	$b797daf2,$3754201e,$c2073fff,$0000de60
+	dc.l	$f4825e0e,$91249e8b,$e1753fff,$0000e0cc
+	dc.l	$deec2a94,$e1102003,$2c4b3fff,$0000e33f
+	dc.l	$8972be8a,$5a502004,$dff53fff,$0000e5b9
+	dc.l	$06e77c83,$48a81e72,$f47a3fff,$0000e839
+	dc.l	$6a503c4b,$dc681f72,$2f223fff,$0000eac0
+	dc.l	$c6e7dd24,$3930a017,$e9453fff,$0000ed4f
+	dc.l	$301ed994,$2b841f40,$1a5b3fff,$0000efe4
+	dc.l	$b99bdcda,$f5cc9fb9,$a9e33fff,$0000f281
+	dc.l	$773c59ff,$b1382074,$4c053fff,$0000f525
+	dc.l	$7d152486,$cc2c1f77,$3a193fff,$0000f7d0
+	dc.l	$df730ad1,$3bb81ffe,$90d53fff,$0000fa83
+	dc.l	$b2db722a,$033ca041,$ed223fff,$0000fd3e
+	dc.l	$0c0cf486,$c1741f85,$3f3a2210,$02817fff
+	dc.l	$00000c81,$3fbe0000,$6c0660ff,$00000108
+	dc.l	$32280004,$0c81400c,$b1676d06,$60ff0000
+	dc.l	$010cf210,$4800f200,$0080f23c,$442342b8
+	dc.l	$aa3bf227,$e00c2d7c,$00000000,$ff58f201
+	dc.l	$600043fa,$fbb6f201,$40002d41,$ff540281
+	dc.l	$0000003f,$e989d3c1,$222eff54,$ec810641
+	dc.l	$3fff3d7a,$fb06ff54,$f2000100,$f23c4423
+	dc.l	$bc317218,$f23a4923,$faf2f200,$0422f200
+	dc.l	$0822f200,$0080f200,$04a3f23c,$45003ab6
+	dc.l	$0b70f200,$0523f200,$0580f23c,$45a33c08
+	dc.l	$8895f23a,$5522fad4,$f23a55a2,$fad6f200
+	dc.l	$05233d41,$ff842d7c,$80000000,$ff8842ae
+	dc.l	$ff8cf200,$05a3f23c,$45223f00,$0000f200
+	dc.l	$01a3f200,$0523f200,$0c22f219,$4880f200
+	dc.l	$0822f200,$0423f21f,$d030f211,$4422f200
+	dc.l	$0422222e,$ff584a81,$6706f22e,$4823ff90
+	dc.l	$f2009000,$123c0000,$f22e4823,$ff8460ff
+	dc.l	$0000216e,$f210d080,$f2009000,$f23c4422
+	dc.l	$3f800000,$60ff0000,$21680c81,$400cb27c
+	dc.l	$6e66f210,$4800f200,$0080f23c,$442342b8
+	dc.l	$aa3bf227,$e00c2d7c,$00000001,$ff58f201
+	dc.l	$600043fa,$faa6f201,$40002d41,$ff540281
+	dc.l	$0000003f,$e989d3c1,$222eff54,$ec812d41
+	dc.l	$ff54e281,$93aeff54,$06413fff,$3d41ff90
+	dc.l	$2d7c8000,$0000ff94,$42aeff98,$222eff54
+	dc.l	$06413fff,$6000fed2,$4a106bff,$00001fbc
+	dc.l	$60ff0000,$20ae2f10,$02978000,$00000097
+	dc.l	$00800000,$f23c4400,$3f800000,$f2009000
+	dc.l	$f21f4422,$60ff0000,$20c82210,$02817fff
+	dc.l	$00000c81,$3ffd0000,$6c0660ff,$0000015e
+	dc.l	$32280004,$0c814004,$c2156f06,$60ff0000
+	dc.l	$026cf210,$4800f200,$0080f23c,$442342b8
+	dc.l	$aa3bf227,$e00cf201,$600043fa,$f9eef201
+	dc.l	$40002d41,$ff540281,$0000003f,$e989d3c1
+	dc.l	$222eff54,$ec812d41,$ff54f200,$0100f23c
+	dc.l	$4423bc31,$7218f23a,$4923f930,$f2000422
+	dc.l	$f2000822,$06413fff,$f2000080,$f20004a3
+	dc.l	$f23c4500,$3950097b,$f2000523,$f2000580
+	dc.l	$f23c45a3,$3ab60b6a,$f23a5522,$f91ef23a
+	dc.l	$55a2f920,$3d41ff84,$2d7c8000,$0000ff88
+	dc.l	$42aeff8c,$f2000523,$222eff54,$4441f200
+	dc.l	$05a30641,$3ffff23a,$5522f900,$f23c45a2
+	dc.l	$3f000000,$f2000523,$00418000,$3d41ff90
+	dc.l	$2d7c8000,$0000ff94,$42aeff98,$f2000ca3
+	dc.l	$f2000123,$f2000422,$f2000822,$f21fd030
+	dc.l	$f2114823,$222eff54,$0c810000,$003f6f1a
+	dc.l	$f2294480,$000cf22e,$48a2ff90,$f2000422
+	dc.l	$f2114822,$60ff0000,$00340c81,$fffffffd
+	dc.l	$6c16f229,$4422000c,$f2114822,$f22e4822
+	dc.l	$ff9060ff,$00000016,$f2194880,$f2114422
+	dc.l	$f22e48a2,$ff90f200,$0422f200,$9000f22e
+	dc.l	$4823ff84,$60ff0000,$1f500c81,$3fbe0000
+	dc.l	$6c6c0c81,$00330000,$6d2c2d7c,$80010000
+	dc.l	$ff842d7c,$80000000,$ff8842ae,$ff8cf210
+	dc.l	$4800f200,$9000123c,$0002f22e,$4822ff84
+	dc.l	$60ff0000,$1f0cf210,$4800f23a,$5423f86c
+	dc.l	$2d7c8001,$0000ff84,$2d7c8000,$0000ff88
+	dc.l	$42aeff8c,$f22e4822,$ff84f200,$9000123c
+	dc.l	$0000f23a,$5423f84c,$60ff0000,$1ed4f210
+	dc.l	$4800f200,$0023f227,$e00cf23c,$44802f30
+	dc.l	$caa8f200,$00a3f23c,$4500310f,$8290f23c
+	dc.l	$44a232d7,$3220f200,$0123f200,$00a3f23c
+	dc.l	$45223493,$f281f23a,$54a2f7c0,$f2000123
+	dc.l	$f20000a3,$f23a5522,$f7baf23a,$54a2f7bc
+	dc.l	$f2000123,$f20000a3,$f23a5522,$f7b6f23a
+	dc.l	$54a2f7b8,$f2000123,$f20000a3,$f23a5522
+	dc.l	$f7b2f23a,$48a2f7b4,$f2000123,$f20000a3
+	dc.l	$f2000123,$f21048a3,$f23c4423,$3f000000
+	dc.l	$f20008a2,$f21fd030,$f2000422,$f2009000
+	dc.l	$f2104822,$60ff0000,$1e302210,$0c810000
+	dc.l	$00006e00,$fbacf23c,$4400bf80,$0000f200
+	dc.l	$9000f23c,$44220080,$000060ff,$00001e1a
+	dc.l	$60ff0000,$1e4a3028,$00000880,$000f0440
+	dc.l	$3ffff200,$50006d02,$4e751d7c,$0008ff64
+	dc.l	$4e7561ff,$00002342,$44400440,$3ffff200
+	dc.l	$50001d7c,$0008ff64,$4e753028,$00000040
+	dc.l	$7fff0880,$000e2d68,$0004ff88,$2d680008
+	dc.l	$ff8c3d40,$ff84f22e,$4800ff84,$6b024e75
+	dc.l	$1d7c0008,$ff644e75,$61ff0000,$22fc60ca
+	dc.l	$7ffb0000,$80000000,$00000000,$00000000
+	dc.l	$f2104800,$22103228,$00040281,$7fffffff
+	dc.l	$0c81400c,$b1676e42,$f2000018,$2f004280
+	dc.l	$f227e001,$41d761ff,$fffffad2,$dffc0000
+	dc.l	$000cf23c,$44233f00,$0000201f,$f23c4480
+	dc.l	$3e800000,$f20000a0,$f2009000,$123c0002
+	dc.l	$f2000422,$60ff0000,$1d280c81,$400cb2b3
+	dc.l	$6e3cf200,$0018f23a,$5428adb6,$f23a5428
+	dc.l	$adb82f00,$4280f227,$e00141d7,$61ffffff
+	dc.l	$fa7cdffc,$0000000c,$201ff200,$9000123c
+	dc.l	$0000f23a,$4823ff5a,$60ff0000,$1ce460ff
+	dc.l	$00001cb0,$f23c4400,$3f800000,$f2009000
+	dc.l	$f23c4422,$00800000,$60ff0000,$1cd4f210
+	dc.l	$48002210,$32280004,$22410281,$7fffffff
+	dc.l	$0c81400c,$b1676e62,$f2000018,$48e78040
+	dc.l	$f227e001,$41d74280,$61ffffff,$fbe0dffc
+	dc.l	$0000000c,$f23c9000,$00000000,$4cdf0201
+	dc.l	$f2000080,$f23c44a2,$3f800000,$f2276800
+	dc.l	$f2000420,$22090281,$80000000,$00813f00
+	dc.l	$0000f21f,$48222f01,$f2009000,$123c0000
+	dc.l	$f21f4423,$60ff0000,$1c480c81,$400cb2b3
+	dc.l	$6eff0000,$1bc2f200,$0018f23a,$5428acd2
+	dc.l	$2f3c0000,$00002f3c,$80000000,$22090281
+	dc.l	$80000000,$00817ffb,$00002f01,$f23a5428
+	dc.l	$acb82f00,$4280f227,$e00141d7,$61ffffff
+	dc.l	$f97cdffc,$0000000c,$201ff200,$9000123c
+	dc.l	$0000f21f,$482360ff,$00001be6,$60ff0000
+	dc.l	$1c2ef210,$4800f22e,$6800ff84,$22103228
+	dc.l	$00042d41,$ff840281,$7fffffff,$0c813fd7
+	dc.l	$80006d00,$00740c81,$3fffddce,$6e00006a
+	dc.l	$222eff84,$2d41ff5c,$02817fff,$00000681
+	dc.l	$00010000,$2d41ff84,$02ae8000,$0000ff5c
+	dc.l	$f22e4800,$ff842f00,$4280f227,$e00141d7
+	dc.l	$61ffffff,$fac8dffc,$0000000c,$201ff200
+	dc.l	$0080f23c,$44a24000,$0000222e,$ff5cf22e
+	dc.l	$6880ff84,$b3aeff84,$f2009000,$f22e4820
+	dc.l	$ff8460ff,$00001b52,$0c813fff,$80006d00
+	dc.l	$00880c81,$40048aa1,$6e000092,$222eff84
+	dc.l	$2d41ff5c,$02817fff,$00000681,$00010000
+	dc.l	$2d41ff84,$02ae8000,$0000ff5c,$222eff5c
+	dc.l	$f22e4800,$ff842f00,$4280f227,$e00141d7
+	dc.l	$61ffffff,$f878dffc,$0000000c,$201f222e
+	dc.l	$ff5cf23c,$44223f80,$00000a81,$c0000000
+	dc.l	$f2014480,$f20000a0,$222eff5c,$00813f80
+	dc.l	$0000f201,$4400f200,$9000123c,$0002f200
+	dc.l	$042260ff,$00001ac2,$f2009000,$123c0003
+	dc.l	$f22e4800,$ff8460ff,$00001aa6,$222eff84
+	dc.l	$02818000,$00000081,$3f800000,$f2014400
+	dc.l	$02818000,$00000a81,$80800000,$f2009000
+	dc.l	$f2014422,$60ff0000,$1a8060ff,$00001ac0
+	dc.l	$3ffe0000,$b17217f7,$d1cf79ac,$00000000
+	dc.l	$3f800000,$00000000,$7f800000,$bf800000
+	dc.l	$3fc2499a,$b5e4040b,$bfc555b5,$848cb7db
+	dc.l	$3fc99999,$987d8730,$bfcfffff,$ff6f7e97
+	dc.l	$3fd55555,$555555a4,$bfe00000,$00000008
+	dc.l	$3f175496,$add7dad6,$3f3c71c2,$fe80c7e0
+	dc.l	$3f624924,$928bccff,$3f899999,$999995ec
+	dc.l	$3fb55555,$55555555,$40000000,$00000000
+	dc.l	$3f990000,$80000000,$00000000,$00000000
+	dc.l	$3ffe0000,$fe03f80f,$e03f80fe,$00000000
+	dc.l	$3ff70000,$ff015358,$833c47e2,$00000000
+	dc.l	$3ffe0000,$fa232cf2,$52138ac0,$00000000
+	dc.l	$3ff90000,$bdc8d83e,$ad88d549,$00000000
+	dc.l	$3ffe0000,$f6603d98,$0f6603da,$00000000
+	dc.l	$3ffa0000,$9cf43dcf,$f5eafd48,$00000000
+	dc.l	$3ffe0000,$f2b9d648,$0f2b9d65,$00000000
+	dc.l	$3ffa0000,$da16eb88,$cb8df614,$00000000
+	dc.l	$3ffe0000,$ef2eb71f,$c4345238,$00000000
+	dc.l	$3ffb0000,$8b29b775,$1bd70743,$00000000
+	dc.l	$3ffe0000,$ebbdb2a5,$c1619c8c,$00000000
+	dc.l	$3ffb0000,$a8d839f8,$30c1fb49,$00000000
+	dc.l	$3ffe0000,$e865ac7b,$7603a197,$00000000
+	dc.l	$3ffb0000,$c61a2eb1,$8cd907ad,$00000000
+	dc.l	$3ffe0000,$e525982a,$f70c880e,$00000000
+	dc.l	$3ffb0000,$e2f2a47a,$de3a18af,$00000000
+	dc.l	$3ffe0000,$e1fc780e,$1fc780e2,$00000000
+	dc.l	$3ffb0000,$ff64898e,$df55d551,$00000000
+	dc.l	$3ffe0000,$dee95c4c,$a037ba57,$00000000
+	dc.l	$3ffc0000,$8db956a9,$7b3d0148,$00000000
+	dc.l	$3ffe0000,$dbeb61ee,$d19c5958,$00000000
+	dc.l	$3ffc0000,$9b8fe100,$f47ba1de,$00000000
+	dc.l	$3ffe0000,$d901b203,$6406c80e,$00000000
+	dc.l	$3ffc0000,$a9372f1d,$0da1bd17,$00000000
+	dc.l	$3ffe0000,$d62b80d6,$2b80d62c,$00000000
+	dc.l	$3ffc0000,$b6b07f38,$ce90e46b,$00000000
+	dc.l	$3ffe0000,$d3680d36,$80d3680d,$00000000
+	dc.l	$3ffc0000,$c3fd0329,$06488481,$00000000
+	dc.l	$3ffe0000,$d0b69fcb,$d2580d0b,$00000000
+	dc.l	$3ffc0000,$d11de0ff,$15ab18ca,$00000000
+	dc.l	$3ffe0000,$ce168a77,$25080ce1,$00000000
+	dc.l	$3ffc0000,$de1433a1,$6c66b150,$00000000
+	dc.l	$3ffe0000,$cb8727c0,$65c393e0,$00000000
+	dc.l	$3ffc0000,$eae10b5a,$7ddc8add,$00000000
+	dc.l	$3ffe0000,$c907da4e,$871146ad,$00000000
+	dc.l	$3ffc0000,$f7856e5e,$e2c9b291,$00000000
+	dc.l	$3ffe0000,$c6980c69,$80c6980c,$00000000
+	dc.l	$3ffd0000,$82012ca5,$a68206d7,$00000000
+	dc.l	$3ffe0000,$c4372f85,$5d824ca6,$00000000
+	dc.l	$3ffd0000,$882c5fcd,$7256a8c5,$00000000
+	dc.l	$3ffe0000,$c1e4bbd5,$95f6e947,$00000000
+	dc.l	$3ffd0000,$8e44c60b,$4ccfd7de,$00000000
+	dc.l	$3ffe0000,$bfa02fe8,$0bfa02ff,$00000000
+	dc.l	$3ffd0000,$944ad09e,$f4351af6,$00000000
+	dc.l	$3ffe0000,$bd691047,$07661aa3,$00000000
+	dc.l	$3ffd0000,$9a3eecd4,$c3eaa6b2,$00000000
+	dc.l	$3ffe0000,$bb3ee721,$a54d880c,$00000000
+	dc.l	$3ffd0000,$a0218434,$353f1de8,$00000000
+	dc.l	$3ffe0000,$b92143fa,$36f5e02e,$00000000
+	dc.l	$3ffd0000,$a5f2fcab,$bbc506da,$00000000
+	dc.l	$3ffe0000,$b70fbb5a,$19be3659,$00000000
+	dc.l	$3ffd0000,$abb3b8ba,$2ad362a5,$00000000
+	dc.l	$3ffe0000,$b509e68a,$9b94821f,$00000000
+	dc.l	$3ffd0000,$b1641795,$ce3ca97b,$00000000
+	dc.l	$3ffe0000,$b30f6352,$8917c80b,$00000000
+	dc.l	$3ffd0000,$b7047551,$5d0f1c61,$00000000
+	dc.l	$3ffe0000,$b11fd3b8,$0b11fd3c,$00000000
+	dc.l	$3ffd0000,$bc952afe,$ea3d13e1,$00000000
+	dc.l	$3ffe0000,$af3addc6,$80af3ade,$00000000
+	dc.l	$3ffd0000,$c2168ed0,$f458ba4a,$00000000
+	dc.l	$3ffe0000,$ad602b58,$0ad602b6,$00000000
+	dc.l	$3ffd0000,$c788f439,$b3163bf1,$00000000
+	dc.l	$3ffe0000,$ab8f69e2,$8359cd11,$00000000
+	dc.l	$3ffd0000,$ccecac08,$bf04565d,$00000000
+	dc.l	$3ffe0000,$a9c84a47,$a07f5638,$00000000
+	dc.l	$3ffd0000,$d2420487,$2dd85160,$00000000
+	dc.l	$3ffe0000,$a80a80a8,$0a80a80b,$00000000
+	dc.l	$3ffd0000,$d7894992,$3bc3588a,$00000000
+	dc.l	$3ffe0000,$a655c439,$2d7b73a8,$00000000
+	dc.l	$3ffd0000,$dcc2c4b4,$9887dacc,$00000000
+	dc.l	$3ffe0000,$a4a9cf1d,$96833751,$00000000
+	dc.l	$3ffd0000,$e1eebd3e,$6d6a6b9e,$00000000
+	dc.l	$3ffe0000,$a3065e3f,$ae7cd0e0,$00000000
+	dc.l	$3ffd0000,$e70d785c,$2f9f5bdc,$00000000
+	dc.l	$3ffe0000,$a16b312e,$a8fc377d,$00000000
+	dc.l	$3ffd0000,$ec1f392c,$5179f283,$00000000
+	dc.l	$3ffe0000,$9fd809fd,$809fd80a,$00000000
+	dc.l	$3ffd0000,$f12440d3,$e36130e6,$00000000
+	dc.l	$3ffe0000,$9e4cad23,$dd5f3a20,$00000000
+	dc.l	$3ffd0000,$f61cce92,$346600bb,$00000000
+	dc.l	$3ffe0000,$9cc8e160,$c3fb19b9,$00000000
+	dc.l	$3ffd0000,$fb091fd3,$8145630a,$00000000
+	dc.l	$3ffe0000,$9b4c6f9e,$f03a3caa,$00000000
+	dc.l	$3ffd0000,$ffe97042,$bfa4c2ad,$00000000
+	dc.l	$3ffe0000,$99d722da,$bde58f06,$00000000
+	dc.l	$3ffe0000,$825efced,$49369330,$00000000
+	dc.l	$3ffe0000,$9868c809,$868c8098,$00000000
+	dc.l	$3ffe0000,$84c37a7a,$b9a905c9,$00000000
+	dc.l	$3ffe0000,$97012e02,$5c04b809,$00000000
+	dc.l	$3ffe0000,$87224c2e,$8e645fb7,$00000000
+	dc.l	$3ffe0000,$95a02568,$095a0257,$00000000
+	dc.l	$3ffe0000,$897b8cac,$9f7de298,$00000000
+	dc.l	$3ffe0000,$94458094,$45809446,$00000000
+	dc.l	$3ffe0000,$8bcf55de,$c4cd05fe,$00000000
+	dc.l	$3ffe0000,$92f11384,$0497889c,$00000000
+	dc.l	$3ffe0000,$8e1dc0fb,$89e125e5,$00000000
+	dc.l	$3ffe0000,$91a2b3c4,$d5e6f809,$00000000
+	dc.l	$3ffe0000,$9066e68c,$955b6c9b,$00000000
+	dc.l	$3ffe0000,$905a3863,$3e06c43b,$00000000
+	dc.l	$3ffe0000,$92aade74,$c7be59e0,$00000000
+	dc.l	$3ffe0000,$8f1779d9,$fdc3a219,$00000000
+	dc.l	$3ffe0000,$94e9bff6,$15845643,$00000000
+	dc.l	$3ffe0000,$8dda5202,$37694809,$00000000
+	dc.l	$3ffe0000,$9723a1b7,$20134203,$00000000
+	dc.l	$3ffe0000,$8ca29c04,$6514e023,$00000000
+	dc.l	$3ffe0000,$995899c8,$90eb8990,$00000000
+	dc.l	$3ffe0000,$8b70344a,$139bc75a,$00000000
+	dc.l	$3ffe0000,$9b88bdaa,$3a3dae2f,$00000000
+	dc.l	$3ffe0000,$8a42f870,$5669db46,$00000000
+	dc.l	$3ffe0000,$9db4224f,$ffe1157c,$00000000
+	dc.l	$3ffe0000,$891ac73a,$e9819b50,$00000000
+	dc.l	$3ffe0000,$9fdadc26,$8b7a12da,$00000000
+	dc.l	$3ffe0000,$87f78087,$f78087f8,$00000000
+	dc.l	$3ffe0000,$a1fcff17,$ce733bd4,$00000000
+	dc.l	$3ffe0000,$86d90544,$7a34acc6,$00000000
+	dc.l	$3ffe0000,$a41a9e8f,$5446fb9f,$00000000
+	dc.l	$3ffe0000,$85bf3761,$2cee3c9b,$00000000
+	dc.l	$3ffe0000,$a633cd7e,$6771cd8b,$00000000
+	dc.l	$3ffe0000,$84a9f9c8,$084a9f9d,$00000000
+	dc.l	$3ffe0000,$a8489e60,$0b435a5e,$00000000
+	dc.l	$3ffe0000,$83993052,$3fbe3368,$00000000
+	dc.l	$3ffe0000,$aa59233c,$cca4bd49,$00000000
+	dc.l	$3ffe0000,$828cbfbe,$b9a020a3,$00000000
+	dc.l	$3ffe0000,$ac656dae,$6bcc4985,$00000000
+	dc.l	$3ffe0000,$81848da8,$faf0d277,$00000000
+	dc.l	$3ffe0000,$ae6d8ee3,$60bb2468,$00000000
+	dc.l	$3ffe0000,$80808080,$80808081,$00000000
+	dc.l	$3ffe0000,$b07197a2,$3c46c654,$00000000
+	dc.l	$f2104800,$2d7c0000,$0000ff54,$22103228
+	dc.l	$00042d50,$ff842d68,$0004ff88,$2d680008
+	dc.l	$ff8c0c81,$00000000,$6d000182,$0c813ffe
+	dc.l	$f07d6d0a,$0c813fff,$88416f00,$00e2e081
+	dc.l	$e0810481,$00003fff,$d2aeff54,$41faf7b2
+	dc.l	$f2014080,$2d7c3fff,$0000ff84,$2d6eff88
+	dc.l	$ff9402ae,$fe000000,$ff9400ae,$01000000
+	dc.l	$ff94222e,$ff940281,$7e000000,$e081e081
+	dc.l	$e881d1c1,$f22e4800,$ff842d7c,$3fff0000
+	dc.l	$ff9042ae,$ff98f22e,$4828ff90,$f227e00c
+	dc.l	$f2104823,$f23a48a3,$f6c8f200,$0100f200
+	dc.l	$0923f22e,$6880ff84,$f2000980,$f2000880
+	dc.l	$f23a54a3,$f6ccf23a,$5523f6ce,$f23a54a2
+	dc.l	$f6d0f23a,$5522f6d2,$f2000ca3,$f2000d23
+	dc.l	$f23a54a2,$f6ccf23a,$5522f6ce,$f2000ca3
+	dc.l	$d1fc0000,$0010f200,$0d23f200,$00a3f200
+	dc.l	$0822f210,$48a2f21f,$d030f200,$0422f200
+	dc.l	$9000f22e,$4822ff84,$60ff0000,$10ccf23c
+	dc.l	$58380001,$f2c10000,$1318f200,$0080f23a
+	dc.l	$44a8f64e,$f23a4422,$f648f200,$04a2f200
+	dc.l	$00a0f227,$e00cf200,$0400f200,$0023f22e
+	dc.l	$6880ff84,$f2000080,$f20004a3,$f23a5580
+	dc.l	$f660f23a,$5500f662,$f20005a3,$f2000523
+	dc.l	$f23a55a2,$f65cf23a,$5522f65e,$f2000ca3
+	dc.l	$f2000123,$f23a54a2,$f658f22e,$4823ff84
+	dc.l	$f20008a2,$f21fd030,$f2000423,$f2009000
+	dc.l	$f22e4822,$ff8460ff,$0000103e,$60ff0000
+	dc.l	$0e962d7c,$ffffff9c,$ff5448e7,$3f002610
+	dc.l	$28280004,$2a280008,$42824a84,$66342805
+	dc.l	$42857420,$4286edc4,$6000edac,$d4862d43
+	dc.l	$ff842d44,$ff882d45,$ff8c4482,$2d42ff54
+	dc.l	$f22e4800,$ff844cdf,$00fc41ee,$ff846000
+	dc.l	$fe0c4286,$edc46000,$2406edac,$2e05edad
+	dc.l	$44860686,$00000020,$ecaf8887,$2d43ff84
+	dc.l	$2d44ff88,$2d45ff8c,$44822d42,$ff54f22e
+	dc.l	$4800ff84,$4cdf00fc,$41eeff84,$6000fdce
+	dc.l	$f2104800,$f2000018,$f23a4838,$f5a4f292
+	dc.l	$0014f200,$9000123c,$0003f210,$480060ff
+	dc.l	$00000f7e,$f2104800,$2d7c0000,$0000ff54
+	dc.l	$f2000080,$f23a4422,$f508f22e,$6800ff84
+	dc.l	$3d6eff88,$ff86222e,$ff840c81,$00000000
+	dc.l	$6f0000da,$0c813ffe,$80006d00,$fda20c81
+	dc.l	$3fffc000,$6e00fd98,$0c813ffe,$f07d6d00
+	dc.l	$001a0c81,$3fff8841,$6e000010,$f20004a2
+	dc.l	$f23a4422,$f4bc6000,$fe762d6e,$ff88ff94
+	dc.l	$02aefe00,$0000ff94,$00ae0100,$0000ff94
+	dc.l	$0c813fff,$80006c44,$f23a4400,$f4fc2d7c
+	dc.l	$3fff0000,$ff9042ae,$ff98f22e,$4828ff90
+	dc.l	$222eff94,$02817e00,$0000e081,$e081e881
+	dc.l	$f20004a2,$f227e00c,$f2000422,$41faf4e2
+	dc.l	$d1c1f23a,$4480f466,$6000fd76,$f23a4400
+	dc.l	$f4502d7c,$3fff0000,$ff9042ae,$ff98f22e
+	dc.l	$4828ff90,$222eff94,$02817e00,$0000e081
+	dc.l	$e081e881,$f2000422,$f227e00c,$41faf4a2
+	dc.l	$d1c1f23a,$4480f41e,$6000fd36,$0c810000
+	dc.l	$00006d10,$f23a4400,$f414f200,$900060ff
+	dc.l	$00000c4e,$f23a4400,$f3fcf200,$900060ff
+	dc.l	$00000cb4,$60ff0000,$0e962210,$32280004
+	dc.l	$02817fff,$ffff0c81,$3fff8000,$6c56f210
+	dc.l	$4818f200,$0080f200,$049af200,$0022f23c
+	dc.l	$44a23f80,$0000f200,$04202210,$02818000
+	dc.l	$00000081,$3f000000,$2f012f00,$4280f227
+	dc.l	$e00141d7,$61ffffff,$fe5adffc,$0000000c
+	dc.l	$201ff200,$9000123c,$0000f21f,$442360ff
+	dc.l	$00000dde,$f2104818,$f23c4438,$3f800000
+	dc.l	$f2d20000,$0c3260ff,$00000bb6,$60ff0000
+	dc.l	$0e0e3ffd,$0000de5b,$d8a93728,$71950000
+	dc.l	$00003fff,$0000b8aa,$3b295c17,$f0bc0000
+	dc.l	$0000f23c,$58000001,$f2104838,$f2c10000
+	dc.l	$0ff02210,$6d000090,$2f004280,$61ffffff
+	dc.l	$fba2f21f,$9000f23a,$4823ffb8,$60ff0000
+	dc.l	$0d782210,$6d000070,$2f004280,$61ffffff
+	dc.l	$fd34f21f,$9000f23a,$4823ff98,$60ff0000
+	dc.l	$0d682210,$6d000050,$22280008,$662e2228
+	dc.l	$00040281,$7fffffff,$66223210,$02810000
+	dc.l	$7fff0481,$00003fff,$67ff0000,$0f84f200
+	dc.l	$9000f201,$400060ff,$00000d1e,$2f004280
+	dc.l	$61ffffff,$fb2ef21f,$9000f23a,$4823ff54
+	dc.l	$60ff0000,$0d0460ff,$00000b5c,$22106d00
+	dc.l	$fff62f00,$428061ff,$fffffcba,$f21f9000
+	dc.l	$f23a4823,$ff2e60ff,$00000cee,$406a934f
+	dc.l	$0979a371,$3f734413,$509f8000,$bfcd0000
+	dc.l	$c0219dc1,$da994fd2,$00000000,$40000000
+	dc.l	$935d8ddd,$aaa8ac17,$00000000,$3ffe0000
+	dc.l	$b17217f7,$d1cf79ac,$00000000,$3f56c16d
+	dc.l	$6f7bd0b2,$3f811112,$302c712c,$3fa55555
+	dc.l	$55554cc1,$3fc55555,$55554a54,$3fe00000
+	dc.l	$00000000,$00000000,$00000000,$3fff0000
+	dc.l	$80000000,$00000000,$3f738000,$3fff0000
+	dc.l	$8164d1f3,$bc030773,$3fbef7ca,$3fff0000
+	dc.l	$82cd8698,$ac2ba1d7,$3fbdf8a9,$3fff0000
+	dc.l	$843a28c3,$acde4046,$3fbcd7c9,$3fff0000
+	dc.l	$85aac367,$cc487b15,$bfbde8da,$3fff0000
+	dc.l	$871f6196,$9e8d1010,$3fbde85c,$3fff0000
+	dc.l	$88980e80,$92da8527,$3fbebbf1,$3fff0000
+	dc.l	$8a14d575,$496efd9a,$3fbb80ca,$3fff0000
+	dc.l	$8b95c1e3,$ea8bd6e7,$bfba8373,$3fff0000
+	dc.l	$8d1adf5b,$7e5ba9e6,$bfbe9670,$3fff0000
+	dc.l	$8ea4398b,$45cd53c0,$3fbdb700,$3fff0000
+	dc.l	$9031dc43,$1466b1dc,$3fbeeeb0,$3fff0000
+	dc.l	$91c3d373,$ab11c336,$3fbbfd6d,$3fff0000
+	dc.l	$935a2b2f,$13e6e92c,$bfbdb319,$3fff0000
+	dc.l	$94f4efa8,$fef70961,$3fbdba2b,$3fff0000
+	dc.l	$96942d37,$20185a00,$3fbe91d5,$3fff0000
+	dc.l	$9837f051,$8db8a96f,$3fbe8d5a,$3fff0000
+	dc.l	$99e04593,$20b7fa65,$bfbcde7b,$3fff0000
+	dc.l	$9b8d39b9,$d54e5539,$bfbebaaf,$3fff0000
+	dc.l	$9d3ed9a7,$2cffb751,$bfbd86da,$3fff0000
+	dc.l	$9ef53260,$91a111ae,$bfbebedd,$3fff0000
+	dc.l	$a0b0510f,$b9714fc2,$3fbcc96e,$3fff0000
+	dc.l	$a2704303,$0c496819,$bfbec90b,$3fff0000
+	dc.l	$a43515ae,$09e6809e,$3fbbd1db,$3fff0000
+	dc.l	$a5fed6a9,$b15138ea,$3fbce5eb,$3fff0000
+	dc.l	$a7cd93b4,$e965356a,$bfbec274,$3fff0000
+	dc.l	$a9a15ab4,$ea7c0ef8,$3fbea83c,$3fff0000
+	dc.l	$ab7a39b5,$a93ed337,$3fbecb00,$3fff0000
+	dc.l	$ad583eea,$42a14ac6,$3fbe9301,$3fff0000
+	dc.l	$af3b78ad,$690a4375,$bfbd8367,$3fff0000
+	dc.l	$b123f581,$d2ac2590,$bfbef05f,$3fff0000
+	dc.l	$b311c412,$a9112489,$3fbdfb3c,$3fff0000
+	dc.l	$b504f333,$f9de6484,$3fbeb2fb,$3fff0000
+	dc.l	$b6fd91e3,$28d17791,$3fbae2cb,$3fff0000
+	dc.l	$b8fbaf47,$62fb9ee9,$3fbcdc3c,$3fff0000
+	dc.l	$baff5ab2,$133e45fb,$3fbee9aa,$3fff0000
+	dc.l	$bd08a39f,$580c36bf,$bfbeaefd,$3fff0000
+	dc.l	$bf1799b6,$7a731083,$bfbcbf51,$3fff0000
+	dc.l	$c12c4cca,$66709456,$3fbef88a,$3fff0000
+	dc.l	$c346ccda,$24976407,$3fbd83b2,$3fff0000
+	dc.l	$c5672a11,$5506dadd,$3fbdf8ab,$3fff0000
+	dc.l	$c78d74c8,$abb9b15d,$bfbdfb17,$3fff0000
+	dc.l	$c9b9bd86,$6e2f27a3,$bfbefe3c,$3fff0000
+	dc.l	$cbec14fe,$f2727c5d,$bfbbb6f8,$3fff0000
+	dc.l	$ce248c15,$1f8480e4,$bfbcee53,$3fff0000
+	dc.l	$d06333da,$ef2b2595,$bfbda4ae,$3fff0000
+	dc.l	$d2a81d91,$f12ae45a,$3fbc9124,$3fff0000
+	dc.l	$d4f35aab,$cfedfa1f,$3fbeb243,$3fff0000
+	dc.l	$d744fcca,$d69d6af4,$3fbde69a,$3fff0000
+	dc.l	$d99d15c2,$78afd7b6,$bfb8bc61,$3fff0000
+	dc.l	$dbfbb797,$daf23755,$3fbdf610,$3fff0000
+	dc.l	$de60f482,$5e0e9124,$bfbd8be1,$3fff0000
+	dc.l	$e0ccdeec,$2a94e111,$3fbacb12,$3fff0000
+	dc.l	$e33f8972,$be8a5a51,$3fbb9bfe,$3fff0000
+	dc.l	$e5b906e7,$7c8348a8,$3fbcf2f4,$3fff0000
+	dc.l	$e8396a50,$3c4bdc68,$3fbef22f,$3fff0000
+	dc.l	$eac0c6e7,$dd24392f,$bfbdbf4a,$3fff0000
+	dc.l	$ed4f301e,$d9942b84,$3fbec01a,$3fff0000
+	dc.l	$efe4b99b,$dcdaf5cb,$3fbe8cac,$3fff0000
+	dc.l	$f281773c,$59ffb13a,$bfbcbb3f,$3fff0000
+	dc.l	$f5257d15,$2486cc2c,$3fbef73a,$3fff0000
+	dc.l	$f7d0df73,$0ad13bb9,$bfb8b795,$3fff0000
+	dc.l	$fa83b2db,$722a033a,$3fbef84b,$3fff0000
+	dc.l	$fd3e0c0c,$f486c175,$bfbef581,$f210d080
+	dc.l	$22103228,$0004f22e,$6800ff84,$02817fff
+	dc.l	$ffff0c81,$3fb98000,$6c046000,$00880c81
+	dc.l	$400d80c0,$6f046000,$007cf200,$0080f23c
+	dc.l	$44a34280,$0000f22e,$6080ff54,$2f0243fa
+	dc.l	$fbbcf22e,$4080ff54,$222eff54,$24010281
+	dc.l	$0000003f,$e981d3c1,$ec822202,$e2819481
+	dc.l	$06820000,$3ffff227,$e00cf23c,$44a33c80
+	dc.l	$00002d59,$ff842d59,$ff882d59,$ff8c3d59
+	dc.l	$ff90f200,$04283d59,$ff94426e,$ff9642ae
+	dc.l	$ff98d36e,$ff84f23a,$4823fb22,$d36eff90
+	dc.l	$60000100,$0c813fff,$80006e12,$f2009000
+	dc.l	$f23c4422,$3f800000,$60ff0000,$07b4222e
+	dc.l	$ff840c81,$00000000,$6d0660ff,$00000764
+	dc.l	$60ff0000,$0666f200,$9000f23c,$44003f80
+	dc.l	$00002210,$00810080,$0001f201,$442260ff
+	dc.l	$0000077e,$f210d080,$22103228,$0004f22e
+	dc.l	$6800ff84,$02817fff,$ffff0c81,$3fb98000
+	dc.l	$6c046000,$ff900c81,$400b9b07,$6f046000
+	dc.l	$ff84f200,$0080f23a,$54a3fa62,$f22e6080
+	dc.l	$ff542f02,$43fafac6,$f22e4080,$ff54222e
+	dc.l	$ff542401,$02810000,$003fe981,$d3c1ec82
+	dc.l	$2202e281,$94810682,$00003fff,$f227e00c
+	dc.l	$f2000500,$f23a54a3,$fa2c2d59,$ff84f23a
+	dc.l	$4923fa2a,$2d59ff88,$2d59ff8c,$f2000428
+	dc.l	$3d59ff90,$f2000828,$3d59ff94,$426eff96
+	dc.l	$42aeff98,$f23a4823,$fa14d36e,$ff84d36e
+	dc.l	$ff90f200,$0080f200,$04a3f23a,$5500fa1e
+	dc.l	$f23a5580,$fa20f200,$0523f200,$05a3f23a
+	dc.l	$5522fa1a,$f23a55a2,$fa1cf200,$0523f200
+	dc.l	$05a3f23a,$5522fa16,$f20001a3,$f2000523
+	dc.l	$f2000c22,$f2000822,$f21fd030,$f22e4823
+	dc.l	$ff84f22e,$4822ff90,$f22e4822,$ff84f200
+	dc.l	$90003d42,$ff84241f,$2d7c8000,$0000ff88
+	dc.l	$42aeff8c,$123c0000,$f22e4823,$ff8460ff
+	dc.l	$0000063e,$f2009000,$f23c4400,$3f800000
+	dc.l	$22100081,$00800001,$f2014422,$60ff0000
+	dc.l	$06302f00,$32290000,$5beeff54,$02810000
+	dc.l	$7fff3028,$00000240,$7fff0c40,$3fff6d00
+	dc.l	$00c00c40,$400c6e00,$00a4f228,$48030000
+	dc.l	$f2006000,$f23c8800,$00000000,$4a290004
+	dc.l	$6b5e2f00,$3d690000,$ff842d69,$0004ff88
+	dc.l	$2d690008,$ff8c41ee,$ff8461ff,$00000b2a
+	dc.l	$4480d09f,$f22ed080,$ff840c40,$c0016c36
+	dc.l	$f21f9000,$223c8000,$00000480,$ffffc001
+	dc.l	$44800c00,$00206c0a,$e0a942a7,$2f0142a7
+	dc.l	$60280400,$0020e0a9,$2f0142a7,$42a7601a
+	dc.l	$f229d080,$0000f21f,$90000640,$3fff4840
+	dc.l	$42a72f3c,$80000000,$2f00f200,$b000123c
+	dc.l	$0000f21f,$482360ff,$0000054c,$201fc149
+	dc.l	$4a290000,$6bff0000,$041c60ff,$00000464
+	dc.l	$4a290004,$6a16201f,$f2009000,$123c0003
+	dc.l	$f2294800,$000060ff,$0000051c,$201f2049
+	dc.l	$60ff0000,$05860001,$00008000,$00000000
+	dc.l	$00000000,$0000422e,$ff652f00,$422eff5c
+	dc.l	$600c422e,$ff652f00,$1d7c0001,$ff5c48e7
+	dc.l	$3f003628,$00003d43,$ff580283,$00007fff
+	dc.l	$28280004,$2a280008,$4a83663c,$263c0000
+	dc.l	$3ffe4a84,$66162805,$42850483,$00000020
+	dc.l	$4286edc4,$6000edac,$96866022,$4286edc4
+	dc.l	$60009686,$edac2e05,$edad4486,$06860000
+	dc.l	$0020ecaf,$88876006,$06830000,$3ffe3029
+	dc.l	$00003d40,$ff5a322e,$ff58b181,$02810000
+	dc.l	$80003d41,$ff5e0280,$00007fff,$22290004
+	dc.l	$24290008,$4a80663c,$203c0000,$3ffe4a81
+	dc.l	$66162202,$42820480,$00000020,$4286edc1
+	dc.l	$6000eda9,$90866022,$4286edc1,$60009086
+	dc.l	$eda92e02,$edaa4486,$06860000,$0020ecaf
+	dc.l	$82876006,$06800000,$3ffe2d43,$ff542f00
+	dc.l	$90834286,$4283227c,$00000000,$4a806c06
+	dc.l	$201f6000,$006a588f,$4a866e0e,$b2846608
+	dc.l	$b4856604,$60000136,$65089485,$93844286
+	dc.l	$52834a80,$670ed683,$d482e391,$55c65289
+	dc.l	$538060d4,$202eff54,$4a816616,$22024282
+	dc.l	$04800000,$00204286,$edc16000,$eda99086
+	dc.l	$601c4286,$edc16000,$6b149086,$eda92e02
+	dc.l	$edaa4486,$06860000,$0020ecaf,$82870c80
+	dc.l	$000041fe,$6c2a3d40,$ff902d41,$ff942d42
+	dc.l	$ff982c2e,$ff543d46,$ff842d44,$ff882d45
+	dc.l	$ff8cf22e,$4800ff90,$1d7c0001,$ff5d6036
+	dc.l	$2d41ff94,$2d42ff98,$04800000,$3ffe3d40
+	dc.l	$ff902c2e,$ff540486,$00003ffe,$2d46ff54
+	dc.l	$f22e4800,$ff903d46,$ff842d44,$ff882d45
+	dc.l	$ff8c422e,$ff5d4a2e,$ff5c6722,$2c2eff54
+	dc.l	$5386b086,$6d186e0e,$b2846608,$b4856604
+	dc.l	$6000007a,$6508f22e,$4828ff84,$52833c2e
+	dc.l	$ff5a6c04,$f200001a,$42863c2e,$ff5e7e08
+	dc.l	$eeae0283,$0000007f,$86861d43,$ff654cdf
+	dc.l	$00fc201f,$f2009000,$4a2eff5d,$6710123c
+	dc.l	$0000f23a,$4823fdc0,$60ff0000,$02ca123c
+	dc.l	$0003f200,$000060ff,$000002bc,$52830c80
+	dc.l	$00000008,$6c04e1ab,$60024283,$f23c4400
+	dc.l	$00000000,$422eff5d,$6000ff94,$2c030286
+	dc.l	$00000001,$4a866700,$ff865283,$3c2eff5a
+	dc.l	$0a860000,$80003d46,$ff5a6000,$ff723028
+	dc.l	$00000240,$7fff0c40,$7fff6738,$08280007
+	dc.l	$00046706,$103c0000,$4e754a40,$66184aa8
+	dc.l	$0004660c,$4aa80008,$6606103c,$00014e75
+	dc.l	$103c0004,$4e7561ff,$000007f6,$4e75103c
+	dc.l	$00064e75,$4aa80008,$66122028,$00040280
+	dc.l	$7fffffff,$6606103c,$00024e75,$103c0003
+	dc.l	$4e757fff,$0000ffff,$ffffffff,$ffff4a28
+	dc.l	$00006a38,$00ae0a00,$0410ff64,$082e0002
+	dc.l	$ff62660a,$f23c4400,$ff800000,$4e75f22e
+	dc.l	$d080ffdc,$f22e9000,$ff60f23c,$4480bf80
+	dc.l	$0000f23c,$44a00000,$00004e75,$00ae0200
+	dc.l	$0410ff64,$082e0002,$ff62660a,$f23c4400
+	dc.l	$7f800000,$4e75f22e,$d080ffdc,$f22e9000
+	dc.l	$ff60f23c,$44803f80,$0000f23c,$44a00000
+	dc.l	$00004e75,$00ae0100,$2080ff64,$082e0005
+	dc.l	$ff626608,$f23ad080,$ff6a4e75,$f22ed080
+	dc.l	$ffdcf22e,$9000ff60,$f227e004,$f23c4500
+	dc.l	$7f800000,$f23c4523,$00000000,$f21fd020
+	dc.l	$4e757ffe,$0000ffff,$ffffffff,$fffffffe
+	dc.l	$0000ffff,$ffffffff,$ffff0000,$00008000
+	dc.l	$00000000,$00008000,$00008000,$00000000
+	dc.l	$00004a28,$00006a26,$00ae0800,$0a28ff64
+	dc.l	$f22e9000,$ff60f23a,$d080ffdc,$f23a4823
+	dc.l	$ffcaf200,$a800e198,$1d40ff64,$4e75006e
+	dc.l	$0a28ff66,$f22e9000,$ff60f23a,$d080ffac
+	dc.l	$f2000023,$f200a800,$e1981d40,$ff644e75
+	dc.l	$00ae0000,$1048ff64,$12000201,$00c06700
+	dc.l	$005a3d68,$0000ff84,$2d680004,$ff882d68
+	dc.l	$0008ff8c,$41eeff84,$48e7c080,$61ff0000
+	dc.l	$06184cdf,$01030c01,$00406610,$4aa80008
+	dc.l	$66184a28,$00076612,$60000020,$22280008
+	dc.l	$02810000,$07ff6700,$001200ae,$00000200
+	dc.l	$ff646006,$006e1248,$ff664a28,$00006a22
+	dc.l	$f22e9000,$ff60f23a,$d080ff14,$f23a4823
+	dc.l	$ff02f200,$a800e198,$00000000,$1d40ff64
+	dc.l	$4e75f22e,$9000ff60,$f23ad080,$fee6f23a
+	dc.l	$4823fee0,$f200a800,$e1981d40,$ff644e75
+	dc.l	$006e1248,$ff66f22e,$9000ff60,$f23ad080
+	dc.l	$fec2f23a,$4823febc,$f200a800,$e1981d40
+	dc.l	$ff644e75,$f200a800,$81aeff64,$6020f200
+	dc.l	$a80081ae,$ff64f294,$000ef281,$0032006e
+	dc.l	$0208ff66,$600800ae,$08000208,$ff64082e
+	dc.l	$0001ff62,$66024e75,$f22e9000,$ff60f23c
+	dc.l	$44803f80,$0000f23a,$48a2fe80,$4e751d7c
+	dc.l	$0004ff64,$006e0208,$ff664e75,$f22e9000
+	dc.l	$ff60f228,$48000000,$f200a800,$00800000
+	dc.l	$0a2881ae,$ff644e75,$f22e9000,$ff60f228
+	dc.l	$48000000,$f200a800,$81aeff64,$4e754e75
+	dc.l	$f2294800,$00004a29,$00006b08,$1d7c0001
+	dc.l	$ff644e75,$1d7c0009,$ff644e75,$f2284800
+	dc.l	$00004a28,$00006b08,$1d7c0001,$ff644e75
+	dc.l	$1d7c0009,$ff644e75,$f227b000,$f23c9000
+	dc.l	$00000000,$f22f4400,$0008f21f,$9000f22f
+	dc.l	$44220008,$4e75f227,$b000f23c,$90000000
+	dc.l	$0000f22f,$54000008,$f21f9000,$f22f5422
+	dc.l	$000c4e75,$f22fd080,$0004f22f,$48220010
+	dc.l	$4e75f227,$b000f23c,$90000000,$0000f22f
+	dc.l	$44000008,$f21f9000,$f22f4428,$00084e75
+	dc.l	$f227b000,$f23c9000,$00000000,$f22f5400
+	dc.l	$0008f21f,$9000f22f,$5428000c,$4e75f22f
+	dc.l	$d0800004,$f22f4828,$00104e75,$f227b000
+	dc.l	$f23c9000,$00000000,$f22f4400,$0008f21f
+	dc.l	$9000f22f,$44230008,$4e75f227,$b000f23c
+	dc.l	$90000000,$0000f22f,$54000008,$f21f9000
+	dc.l	$f22f5423,$000c4e75,$f22fd080,$0004f22f
+	dc.l	$48230010,$4e75f227,$b000f23c,$90000000
+	dc.l	$0000f22f,$44000008,$f21f9000,$f22f4420
+	dc.l	$00084e75,$f227b000,$f23c9000,$00000000
+	dc.l	$f22f5400,$0008f21f,$9000f22f,$5420000c
+	dc.l	$4e75f22f,$d0800004,$f22f4820,$00104e75
+	dc.l	$f22f4418,$00044e75,$f22f5418,$00044e75
+	dc.l	$f22f4818,$00044e75,$f22f441a,$00044e75
+	dc.l	$f22f541a,$00044e75,$f22f481a,$00044e75
+	dc.l	$f22f4404,$00044e75,$f22f5404,$00044e75
+	dc.l	$f22f4804,$00044e75,$f22f4401,$00044e75
+	dc.l	$f22f5401,$00044e75,$f22f4801,$00044e75
+	dc.l	$f22f4403,$00044e75,$f22f5403,$00044e75
+	dc.l	$f22f4803,$00044e75,$4a280000,$6b10f23c
+	dc.l	$44000000,$00001d7c,$0004ff64,$4e75f23c
+	dc.l	$44008000,$00001d7c,$000cff64,$4e754a29
+	dc.l	$00006bea,$60d84a28,$00006b10,$f23c4400
+	dc.l	$7f800000,$1d7c0002,$ff644e75,$f23c4400
+	dc.l	$ff800000,$1d7c000a,$ff644e75,$4a290000
+	dc.l	$6bea60d8,$4a280000,$6ba460d0,$4a280000
+	dc.l	$6b00fba2,$60c64a28,$00006b16,$60be4a28
+	dc.l	$00006b0e,$f23c4400,$3f800000,$422eff64
+	dc.l	$4e75f23c,$4400bf80,$00001d7c,$0008ff64
+	dc.l	$4e753fff,$0000c90f,$daa22168,$c235bfff
+	dc.l	$0000c90f,$daa22168,$c2354a28,$00006b0e
+	dc.l	$f2009000,$f23a4800,$ffda6000,$fcf2f200
+	dc.l	$9000f23a,$4800ffd8,$6000fcec,$f23c4480
+	dc.l	$3f800000,$4a280000,$6a10f23c,$44008000
+	dc.l	$00001d7c,$000cff64,$4e75f23c,$44000000
+	dc.l	$00001d7c,$0004ff64,$4e75f23a,$4880fa84
+	dc.l	$6000fb02,$f2284880,$00006000,$fd30122e
+	dc.l	$ff4f67ff,$fffff782,$0c010001,$67000078
+	dc.l	$0c010002,$67ffffff,$fade0c01,$000467ff
+	dc.l	$fffff766,$60ffffff,$fcea122e,$ff4f67ff
+	dc.l	$fffffac4,$0c010001,$67ffffff,$faba0c01
+	dc.l	$000267ff,$fffffab0,$0c010004,$67ffffff
+	dc.l	$faa660ff,$fffffcbc,$122eff4f,$67ff0000
+	dc.l	$00440c01,$000167ff,$0000001e,$0c010002
+	dc.l	$67ffffff,$fa820c01,$000467ff,$00000026
+	dc.l	$60ffffff,$fc8e1228,$00001029,$0000b101
+	dc.l	$02010080,$1d41ff65,$4a006a00,$fe526000
+	dc.l	$fe5e422e,$ff652f00,$12280000,$10290000
+	dc.l	$b1010201,$00801d41,$ff650c2e,$0004ff4f
+	dc.l	$660c41e9,$0000201f,$60ffffff,$fc2ef21f
+	dc.l	$9000f229,$48000000,$4a290000,$6b024e75
+	dc.l	$1d7c0008,$ff644e75,$122eff4f,$67ffffff
+	dc.l	$f6a40c01,$00016700,$ff8e0c01,$000267ff
+	dc.l	$fffff9f4,$0c010004,$67ffffff,$f68860ff
+	dc.l	$fffffc00,$122eff4f,$67ffffff,$f9da0c01
+	dc.l	$000167ff,$fffff9d0,$0c010002,$67ffffff
+	dc.l	$f9c60c01,$000467ff,$fffff9bc,$60ffffff
+	dc.l	$fbd2122e,$ff4f6700,$ff5a0c01,$00016700
+	dc.l	$ff360c01,$000267ff,$fffff99c,$0c010004
+	dc.l	$67ffffff,$ff4060ff,$fffffba8,$122eff4f
+	dc.l	$67ffffff,$f5000c01,$000167ff,$fffffd92
+	dc.l	$0c010002,$67ffffff,$fdb60c01,$000467ff
+	dc.l	$fffff4e2,$60ffffff,$fb7a122e,$ff4f67ff
+	dc.l	$fffff4d2,$0c010001,$67ffffff,$fd640c01
+	dc.l	$000267ff,$fffffd88,$0c010004,$67ffffff
+	dc.l	$f4b460ff,$fffffb4c,$122eff4f,$67ffffff
+	dc.l	$f9260c01,$000367ff,$fffffb38,$60ffffff
+	dc.l	$f916122e,$ff4f0c01,$000367ff,$fffffb24
+	dc.l	$60ffffff,$fb3a2f02,$2f032028,$00042228
+	dc.l	$0008edc0,$2000671a,$e5a8e9c1,$30228083
+	dc.l	$e5a92140,$00042141,$00082002,$261f241f
+	dc.l	$4e75edc1,$2000e5a9,$06820000,$00202141
+	dc.l	$000442a8,$00082002,$261f241f,$4e75ede8
+	dc.l	$00000004,$660eede8,$00000008,$67000074
+	dc.l	$06400020,$42813228,$00000241,$7fffb041
+	dc.l	$6e1c9240,$30280000,$02408000,$82403141
+	dc.l	$000061ff,$ffffff82,$103c0000,$4e750c01
+	dc.l	$00206e20,$e9e80840,$00042140,$00042028
+	dc.l	$0008e3a8,$21400008,$02688000,$0000103c
+	dc.l	$00044e75,$04410020,$20280008,$e3a82140
+	dc.l	$000442a8,$00080268,$80000000,$103c0004
+	dc.l	$4e750268,$80000000,$103c0001,$4e7551fc
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/ifpsp060/fpsp.doc linux/arch/m68k/ifpsp060/fpsp.doc
--- v1.3.93/linux/arch/m68k/ifpsp060/fpsp.doc	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/ifpsp060/fpsp.doc	Mon Jan  8 22:08:15 1996
@@ -0,0 +1,295 @@
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+MOTOROLA MICROPROCESSOR & MEMORY TECHNOLOGY GROUP
+M68000 Hi-Performance Microprocessor Division
+M68060 Software Package
+Production Release P1.00 -- October 10, 1994
+
+M68060 Software Package Copyright © 1993, 1994 Motorola Inc.  All rights reserved.
+ 
+THE SOFTWARE is provided on an "AS IS" basis and without warranty.
+To the maximum extent permitted by applicable law,
+MOTOROLA DISCLAIMS ALL WARRANTIES WHETHER EXPRESS OR IMPLIED, 
+INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+and any warranty against infringement with regard to the SOFTWARE
+(INCLUDING ANY MODIFIED VERSIONS THEREOF) and any accompanying written materials.
+
+To the maximum extent permitted by applicable law,
+IN NO EVENT SHALL MOTOROLA BE LIABLE FOR ANY DAMAGES WHATSOEVER
+(INCLUDING WITHOUT LIMITATION, DAMAGES FOR LOSS OF BUSINESS PROFITS,
+BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION, OR OTHER PECUNIARY LOSS)
+ARISING OF THE USE OR INABILITY TO USE THE SOFTWARE.
+Motorola assumes no responsibility for the maintenance and support of the SOFTWARE.
+
+You are hereby granted a copyright license to use, modify, and distribute the SOFTWARE
+so long as this entire notice is retained without alteration in any modified and/or
+redistributed versions, and that such modified versions are clearly identified as such.
+No licenses are granted by implication, estoppel or otherwise under any patents
+or trademarks of Motorola, Inc.
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+68060 FLOATING-POINT SOFTWARE PACKAGE (Kernel version)
+-------------------------------------------------------
+
+The file fpsp.sa contains the 68060 Floating-Point Software
+Package. This package is essentially a set of exception handlers
+that can be integrated into an operating system. 
+These exception handlers emulate Unimplemented FP instructions,
+instructions using unimplemented data types, and instructions
+using unimplemented addressing modes. In addition, this package
+includes exception handlers to provide full IEEE-754 compliant
+exception handling.
+
+Release file format:
+--------------------
+The file fpsp.sa is essentially a hexadecimal image of the
+release package. This is the ONLY format which will be supported.
+The hex image was created by assembling the source code and
+then converting the resulting binary output image into an
+ASCII text file. The hexadecimal numbers are listed
+using the Motorola Assembly Syntax assembler directive "dc.l"
+(define constant longword). The file can be converted to other
+assembly syntaxes by using any word processor with a global
+search and replace function.
+
+To assist in assembling and linking this module with other modules,
+the installer should add a symbolic label to the top of the file.
+This will allow calling routines to access the entry points
+of this package.
+
+The source code fpsp.s has also been included but only for
+documentation purposes.
+
+Release file structure:
+-----------------------
+
+(top of module)
+	----------------- 
+	|		| - 128 byte-sized section
+   (1)  |   Call-Out	| - 4 bytes per entry (user fills these in)
+	|		| - example routines in fskeleton.s
+	-----------------
+	|		| - 8 bytes per entry
+   (2)  | Entry Point	| - user does "bra" or "jmp" to this address
+	|		| 
+	-----------------
+	|		| - code section
+   (3)  ~		~
+	|		|
+	-----------------
+(bottom of module)
+
+The first section of this module is the "Call-out" section. This section
+is NOT INCLUDED in fpsp.sa (an example "Call-out" section is provided at
+the end of the file fskeleton.s). The purpose of this section is to allow 
+the FPSP routines to reference external functions that must be provided 
+by the host operating system. This section MUST be exactly 128 bytes in 
+size. There are 32 fields, each 4 bytes in size. Each field corresponds
+to a function required by the FPSP (these functions and their location are
+listed in "68060FPSP call-outs" below). Each field entry should contain
+the address of the corresponding function RELATIVE to the starting address
+of the "call-out" section. The "Call-out" section must sit adjacent to the 
+fpsp.sa image in memory.
+
+The second section, the "Entry-point" section, is used by external routines
+to access the functions within the FPSP. Since the fpsp.sa hex file contains
+no symbol names, this section contains function entry points that are fixed
+with respect to the top of the package. The currently defined entry-points
+are listed in section "68060 FPSP entry points" below. A calling routine
+would simply execute a "bra" or "jmp" that jumped to the selected function
+entry-point.
+
+For example, if the 68060 hardware took a "Line-F Emulator" exception 
+(vector #11), the operating system should execute something similar to:
+
+	bra	_060FPSP_TOP+128+48
+
+(_060FPSP_TOP is the starting address of the "Call-out" section; the "Call-out"
+section is 128 bytes long; and the F-Line FPSP handler entry point is located
+48 bytes from the top of the "Entry-point" section.)
+
+The third section is the code section. After entering through an "Entry-point",
+the entry code jumps to the appropriate emulation code within the code section.
+
+68060FPSP call-outs: (details in fskeleton.s)
+--------------------
+0x000:	_060_real_bsun
+0x004:	_060_real_snan
+0x008:	_060_real_operr
+0x00c:	_060_real_ovfl
+0x010:	_060_real_unfl
+0x014:	_060_real_dz
+0x018:	_060_real_inex
+0x01c:	_060_real_fline
+0x020:	_060_real_fpu_disabled
+0x024:	_060_real_trap
+0x028:	_060_real_trace
+0x02c:	_060_real_access
+0x030:	_060_fpsp_done
+
+0x034:	(Motorola reserved)
+0x038:	(Motorola reserved)
+0x03c:	(Motorola reserved)
+
+0x040:	_060_imem_read
+0x044:	_060_dmem_read
+0x048:	_060_dmem_write
+0x04c:	_060_imem_read_word
+0x050:	_060_imem_read_long
+0x054:	_060_dmem_read_byte
+0x058:	_060_dmem_read_word
+0x05c:	_060_dmem_read_long
+0x060:	_060_dmem_write_byte
+0x064:	_060_dmem_write_word
+0x068:	_060_dmem_write_long
+
+0x06c:	(Motorola reserved)
+0x070:	(Motorola reserved)
+0x074:	(Motorola reserved)
+0x078:	(Motorola reserved)
+0x07c:	(Motorola reserved)
+
+68060FPSP entry points:
+-----------------------
+0x000:	_060_fpsp_snan
+0x008:	_060_fpsp_operr
+0x010:	_060_fpsp_ovfl
+0x018:	_060_fpsp_unfl
+0x020:	_060_fpsp_dz
+0x028:	_060_fpsp_inex
+0x030:	_060_fpsp_fline
+0x038:	_060_fpsp_unsupp
+0x040:	_060_fpsp_effadd
+
+
+
+Miscellaneous:
+--------------
+
+_060_fpsp_snan:
+----------------
+- documented in 3.5 of 060SP spec.
+- Basic flow:
+	exception taken ---> enter _060_fpsp_snan --|
+						    |
+            always exits through _060_real_snan <----
+
+_060_fpsp_operr:
+----------------
+- documented in 3.5 of 060SP spec.
+- Basic flow:
+	exception taken ---> enter _060_fpsp_operr --|
+						     |
+           always exits through _060_real_operr <-----
+
+_060_fpsp_dz:
+----------------
+- documented in 3.7 of 060SP spec.
+- Basic flow:
+	exception taken ---> enter _060_fpsp_dz   --|
+						    |
+            always exits through _060_real_dz   <----
+
+_060_fpsp_inex:
+----------------
+- documented in 3.6 of 060SP spec.
+- Basic flow:
+	exception taken ---> enter _060_fpsp_inex --|
+						    |
+            always exits through _060_real_inex <----
+
+
+_060_fpsp_ovfl:
+----------------
+- documented in 3.4 of 060SP spec.
+- Basic flow:
+	exception taken ---> enter _060_fpsp_ovfl --|
+						    |
+            may exit through _060_real_inex     <---|
+						 or |
+            may exit through _060_real_ovfl     <---|
+						 or |
+            may exit through _060_fpsp_done     <---|
+
+_060_fpsp_unfl:
+----------------
+- documented in 3.4 of 060SP spec.
+- Basic flow:
+	exception taken ---> enter _060_fpsp_unfl --|
+						    |
+            may exit through _060_real_inex     <---|
+						 or |
+            may exit through _060_real_unfl     <---|
+						 or |
+            may exit through _060_fpsp_done     <---|
+
+
+_060_fpsp_fline:
+-----------------
+- not fully documented in 060SP spec.
+- Basic flow:
+	exception taken ---> enter _060_fpsp_fline --|
+						     |
+            -------------------------------------------
+            |               |                     |
+            v               v                     v
+   (unimplemented   (fpu disabled)       (possible F-line illegal)
+     stack frame)           |                     v
+            |               v               special case "fmovecr"?
+            |         exit through                    |
+            |     _060_real_fpu_disabled        -------------
+            |                                   |           |
+            |               ^                   v           v
+            |               |                 (yes)        (no)
+            |               |                   v           v
+            |               |             fpu disabled?   exit through
+            |               |                   |         _060_real_fline
+            v               |             -------------
+            |               |             |           |
+            |               |             v           v
+            |               |-----------(yes)        (no)
+            |                                         |
+            |----<------------------------------------|
+            |
+            |
+            |----> may exit through _060_real_trace
+            |
+            |----> may exit through _060_real_trap
+            |
+            |----> may exit thorugh _060_real_bsun
+            |
+            |----> may exit through _060_fpsp_done
+
+
+_060_fpsp_unsupp:
+------------------
+- documented in 3.1 of 060SP spec.
+- Basic flow:
+	exception taken ---> enter _060_fpsp_unsupp --|
+						      |
+						      |
+            may exit through _060_real_snan      <----|
+						  or  |
+            may exit through _060_real_operr     <----|
+						  or  |
+            may exit through _060_real_ovfl      <----|
+						  or  |
+            may exit through _060_real_unfl      <----|
+						  or  |
+            may exit through _060_real_inex      <----|
+						  or  |
+            may exit through _060_real_trace     <----|
+						  or  |
+            may exit through _060_fpsp_done      <----|
+
+
+_060_fpsp_effadd:
+------------------
+- documented in 3.3 of 060 spec.
+- Basic flow:
+	exception taken ---> enter _060_fpsp_effadd --|
+						      |
+						      |
+            may exit through _060_real_trace     <----|
+						  or  |
+     may exit through _060_real_fpu_disabled     <----|
+						  or  |
+            may exit through _060_fpsp_done      <----|
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/ifpsp060/fpsp.sa linux/arch/m68k/ifpsp060/fpsp.sa
--- v1.3.93/linux/arch/m68k/ifpsp060/fpsp.sa	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/ifpsp060/fpsp.sa	Mon Jan  8 22:08:16 1996
@@ -0,0 +1,3401 @@
+	.long	0x60ff0000,0x17400000,0x60ff0000,0x15f40000
+	.long	0x60ff0000,0x02b60000,0x60ff0000,0x04700000
+	.long	0x60ff0000,0x1b100000,0x60ff0000,0x19aa0000
+	.long	0x60ff0000,0x1b5a0000,0x60ff0000,0x062e0000
+	.long	0x60ff0000,0x102c0000,0x51fc51fc,0x51fc51fc
+	.long	0x51fc51fc,0x51fc51fc,0x51fc51fc,0x51fc51fc
+	.long	0x51fc51fc,0x51fc51fc,0x51fc51fc,0x51fc51fc
+	.long	0x51fc51fc,0x51fc51fc,0x51fc51fc,0x51fc51fc
+	.long	0x2f00203a,0xff2c487b,0x0930ffff,0xfef8202f
+	.long	0x00044e74,0x00042f00,0x203afef2,0x487b0930
+	.long	0xfffffee2,0x202f0004,0x4e740004,0x2f00203a
+	.long	0xfee0487b,0x0930ffff,0xfecc202f,0x00044e74
+	.long	0x00042f00,0x203afed2,0x487b0930,0xfffffeb6
+	.long	0x202f0004,0x4e740004,0x2f00203a,0xfea4487b
+	.long	0x0930ffff,0xfea0202f,0x00044e74,0x00042f00
+	.long	0x203afe96,0x487b0930,0xfffffe8a,0x202f0004
+	.long	0x4e740004,0x2f00203a,0xfe7c487b,0x0930ffff
+	.long	0xfe74202f,0x00044e74,0x00042f00,0x203afe76
+	.long	0x487b0930,0xfffffe5e,0x202f0004,0x4e740004
+	.long	0x2f00203a,0xfe68487b,0x0930ffff,0xfe48202f
+	.long	0x00044e74,0x00042f00,0x203afe56,0x487b0930
+	.long	0xfffffe32,0x202f0004,0x4e740004,0x2f00203a
+	.long	0xfe44487b,0x0930ffff,0xfe1c202f,0x00044e74
+	.long	0x00042f00,0x203afe32,0x487b0930,0xfffffe06
+	.long	0x202f0004,0x4e740004,0x2f00203a,0xfe20487b
+	.long	0x0930ffff,0xfdf0202f,0x00044e74,0x00042f00
+	.long	0x203afe1e,0x487b0930,0xfffffdda,0x202f0004
+	.long	0x4e740004,0x2f00203a,0xfe0c487b,0x0930ffff
+	.long	0xfdc4202f,0x00044e74,0x00042f00,0x203afdfa
+	.long	0x487b0930,0xfffffdae,0x202f0004,0x4e740004
+	.long	0x2f00203a,0xfde8487b,0x0930ffff,0xfd98202f
+	.long	0x00044e74,0x00042f00,0x203afdd6,0x487b0930
+	.long	0xfffffd82,0x202f0004,0x4e740004,0x2f00203a
+	.long	0xfdc4487b,0x0930ffff,0xfd6c202f,0x00044e74
+	.long	0x00042f00,0x203afdb2,0x487b0930,0xfffffd56
+	.long	0x202f0004,0x4e740004,0x2f00203a,0xfda0487b
+	.long	0x0930ffff,0xfd40202f,0x00044e74,0x00042f00
+	.long	0x203afd8e,0x487b0930,0xfffffd2a,0x202f0004
+	.long	0x4e740004,0x2f00203a,0xfd7c487b,0x0930ffff
+	.long	0xfd14202f,0x00044e74,0x00042f00,0x203afd6a
+	.long	0x487b0930,0xfffffcfe,0x202f0004,0x4e740004
+	.long	0x40c62d38,0xd3d64634,0x3d6f90ae,0xb1e75cc7
+	.long	0x40000000,0xc90fdaa2,0x2168c235,0x00000000
+	.long	0x3fff0000,0xc90fdaa2,0x2168c235,0x00000000
+	.long	0x3fe45f30,0x6dc9c883,0x4e56ff40,0xf32eff6c
+	.long	0x48ee0303,0xff9cf22e,0xbc00ff60,0xf22ef0c0
+	.long	0xffdc2d6e,0xff68ff44,0x206eff44,0x58aeff44
+	.long	0x61ffffff,0xff042d40,0xff40082e,0x0005ff42
+	.long	0x66000116,0x41eeff6c,0x61ff0000,0x051c41ee
+	.long	0xff6c61ff,0x0000c1dc,0x1d40ff4e,0x082e0005
+	.long	0xff436726,0xe9ee0183,0xff4261ff,0x0000bd22
+	.long	0x41eeff78,0x61ff0000,0xc1ba0c00,0x00066606
+	.long	0x61ff0000,0xc11e1d40,0xff4f4280,0x102eff63
+	.long	0x122eff43,0x0241007f,0x02ae00ff,0x01ffff64
+	.long	0xf23c9000,0x00000000,0xf23c8800,0x00000000
+	.long	0x41eeff6c,0x43eeff78,0x223b1530,0x00007112
+	.long	0x4ebb1930,0x0000710a,0xe9ee0183,0xff4261ff
+	.long	0x0000bd4e,0x082e0004,0xff626622,0x082e0001
+	.long	0xff626644,0xf22ed0c0,0xffdcf22e,0x9c00ff60
+	.long	0x4cee0303,0xff9c4e5e,0x60ffffff,0xfcc6f22e
+	.long	0xf040ff6c,0x3d7ce005,0xff6ef22e,0xd0c0ffdc
+	.long	0xf22e9c00,0xff604cee,0x0303ff9c,0xf36eff6c
+	.long	0x4e5e60ff,0xfffffcb2,0xf22ef040,0xff6c1d7c
+	.long	0x00c4000b,0x3d7ce001,0xff6ef22e,0xd0c0ffdc
+	.long	0xf22e9c00,0xff604cee,0x0303ff9c,0xf36eff6c
+	.long	0x4e5e60ff,0xfffffcae,0x1d7c0000,0xff4e4280
+	.long	0x102eff63,0x02aeffff,0x00ffff64,0xf23c9000
+	.long	0x00000000,0xf23c8800,0x00000000,0x41eeff6c
+	.long	0x61ff0000,0xb2ce082e,0x0004ff62,0x6600ff70
+	.long	0x082e0001,0xff626600,0xff90f22e,0xd0c0ffdc
+	.long	0xf22e9c00,0xff604cee,0x0303ff9c,0x4e5e0817
+	.long	0x000767ff,0xfffffc0c,0xf22fa400,0x00083f7c
+	.long	0x20240006,0x60ffffff,0xfcec4e56,0xff40f32e
+	.long	0xff6c48ee,0x0303ff9c,0xf22ebc00,0xff60f22e
+	.long	0xf0c0ffdc,0x2d6eff68,0xff44206e,0xff4458ae
+	.long	0xff4461ff,0xfffffd42,0x2d40ff40,0x082e0005
+	.long	0xff426600,0x013241ee,0xff6c61ff,0x0000035a
+	.long	0x41eeff6c,0x61ff0000,0xc01a1d40,0xff4e082e
+	.long	0x0005ff43,0x672e082e,0x0004ff43,0x6626e9ee
+	.long	0x0183ff42,0x61ff0000,0xbb5841ee,0xff7861ff
+	.long	0x0000bff0,0x0c000006,0x660661ff,0x0000bf54
+	.long	0x1d40ff4f,0x4280102e,0xff63122e,0xff430241
+	.long	0x007f02ae,0x00ff01ff,0xff64f23c,0x90000000
+	.long	0x0000f23c,0x88000000,0x000041ee,0xff6c43ee
+	.long	0xff78223b,0x15300000,0x6f484ebb,0x19300000
+	.long	0x6f40e9ee,0x0183ff42,0x61ff0000,0xbb84082e
+	.long	0x0003ff62,0x6622082e,0x0001ff62,0x664ef22e
+	.long	0xd0c0ffdc,0xf22e9c00,0xff604cee,0x0303ff9c
+	.long	0x4e5e60ff,0xfffffafc,0x082e0003,0xff666700
+	.long	0xffd6f22e,0xf040ff6c,0x3d7ce003,0xff6ef22e
+	.long	0xd0c0ffdc,0xf22e9c00,0xff604cee,0x0303ff9c
+	.long	0xf36eff6c,0x4e5e60ff,0xfffffaf4,0x082e0001
+	.long	0xff666700,0xffaaf22e,0xf040ff6c,0x1d7c00c4
+	.long	0x000b3d7c,0xe001ff6e,0xf22ed0c0,0xffdcf22e
+	.long	0x9c00ff60,0x4cee0303,0xff9cf36e,0xff6c4e5e
+	.long	0x60ffffff,0xfad01d7c,0x0000ff4e,0x4280102e
+	.long	0xff6302ae,0xffff00ff,0xff64f23c,0x90000000
+	.long	0x0000f23c,0x88000000,0x000041ee,0xff6c61ff
+	.long	0x0000b0f0,0x082e0003,0xff626600,0xff66082e
+	.long	0x0001ff62,0x6600ff90,0xf22ed0c0,0xffdcf22e
+	.long	0x9c00ff60,0x4cee0303,0xff9c4e5e,0x08170007
+	.long	0x67ffffff,0xfa2ef22f,0xa4000008,0x3f7c2024
+	.long	0x000660ff,0xfffffb0e,0x4e56ff40,0xf32eff6c
+	.long	0x48ee0303,0xff9cf22e,0xbc00ff60,0xf22ef0c0
+	.long	0xffdc082e,0x00050004,0x66084e68,0x2d48ffd8
+	.long	0x600841ee,0x00102d48,0xffd82d6e,0xff68ff44
+	.long	0x206eff44,0x58aeff44,0x61ffffff,0xfb4c2d40
+	.long	0xff40422e,0xff4a082e,0x0005ff42,0x66000208
+	.long	0xe9ee0006,0xff420c00,0x00136700,0x049e02ae
+	.long	0x00ff00ff,0xff64f23c,0x90000000,0x0000f23c
+	.long	0x88000000,0x000041ee,0xff6c61ff,0x0000013a
+	.long	0x41eeff6c,0x61ff0000,0xbdfa0c00,0x00066606
+	.long	0x61ff0000,0xbd5e1d40,0xff4ee9ee,0x0183ff42
+	.long	0x082e0005,0xff436728,0x0c2e003a,0xff436720
+	.long	0x61ff0000,0xb92c41ee,0xff7861ff,0x0000bdc4
+	.long	0x0c000006,0x660661ff,0x0000bd28,0x1d40ff4f
+	.long	0x4280102e,0xff63e9ee,0x1047ff43,0x41eeff6c
+	.long	0x43eeff78,0x223b1d30,0x00006d36,0x4ebb1930
+	.long	0x00006d2e,0x102eff62,0x6634102e,0xff430200
+	.long	0x00380c00,0x0038670c,0xe9ee0183,0xff4261ff
+	.long	0x0000b95e,0xf22ed0c0,0xffdcf22e,0x9c00ff60
+	.long	0x4cee0303,0xff9c4e5e,0x60ffffff,0xf8e6c02e
+	.long	0xff66edc0,0x06086614,0x082e0004,0xff6667ba
+	.long	0x082e0001,0xff6267b2,0x60000066,0x04800000
+	.long	0x00180c00,0x00066614,0x082e0003,0xff666600
+	.long	0x004a082e,0x0004ff66,0x66000046,0x2f0061ff
+	.long	0x000007e0,0x201f3d7b,0x0222ff6e,0xf22ed0c0
+	.long	0xffdcf22e,0x9c00ff60,0x4cee0303,0xff9cf36e
+	.long	0xff6c4e5e,0x60ffffff,0xf87ae000,0xe006e004
+	.long	0xe005e003,0xe002e001,0xe001303c,0x000460bc
+	.long	0x303c0003,0x60b6e9ee,0x0006ff42,0x0c000011
+	.long	0x67080c00,0x00156750,0x4e753028,0x00000240
+	.long	0x7fff0c40,0x3f806708,0x0c40407f,0x672c4e75
+	.long	0x02a87fff,0xffff0004,0x671861ff,0x0000bbbc
+	.long	0x44400640,0x3f810268,0x80000000,0x81680000
+	.long	0x4e750268,0x80000000,0x4e750228,0x007f0004
+	.long	0x00687fff,0x00004e75,0x30280000,0x02407fff
+	.long	0x0c403c00,0x67080c40,0x43ff67de,0x4e7502a8
+	.long	0x7fffffff,0x00046606,0x4aa80008,0x67c461ff
+	.long	0x0000bb68,0x44400640,0x3c010268,0x80000000
+	.long	0x81680000,0x4e75e9ee,0x00c3ff42,0x0c000003
+	.long	0x670004a2,0x0c000007,0x6700049a,0x02aeffff
+	.long	0x00ffff64,0xf23c9000,0x00000000,0xf23c8800
+	.long	0x00000000,0x302eff6c,0x02407fff,0x671041ee
+	.long	0xff6c61ff,0x0000bb5c,0x1d40ff4e,0x60061d7c
+	.long	0x0004ff4e,0x4280102e,0xff6341ee,0xff6c2d56
+	.long	0xffd461ff,0x0000adec,0x102eff62,0x66000086
+	.long	0x2caeffd4,0x082e0005,0x00046626,0x206effd8
+	.long	0x4e60f22e,0xd0c0ffdc,0xf22e9c00,0xff604cee
+	.long	0x0303ff9c,0x4e5e0817,0x0007667a,0x60ffffff
+	.long	0xf7220c2e,0x0008ff4a,0x66d8f22e,0xf080ff6c
+	.long	0xf22ed0c0,0xffdcf22e,0x9c00ff60,0x4cee0303
+	.long	0xff9c2c56,0x2f6f00c4,0x00b82f6f,0x00c800bc
+	.long	0x2f6f002c,0x00c42f6f,0x003000c8,0x2f6f0034
+	.long	0x00ccdffc,0x000000b8,0x08170007,0x662860ff
+	.long	0xfffff6d0,0xc02eff66,0xedc00608,0x662a082e
+	.long	0x0004ff66,0x6700ff6a,0x082e0001,0xff626700
+	.long	0xff606000,0x01663f7c,0x20240006,0xf22fa400
+	.long	0x000860ff,0xfffff78e,0x04800000,0x0018303b
+	.long	0x020a4efb,0x00064afc,0x00080000,0x0000003a
+	.long	0x00640094,0x00000140,0x0000f22e,0xd0c0ffdc
+	.long	0xf22e9c00,0xff604cee,0x0303ff9c,0x3d7c30d8
+	.long	0x000a3d7c,0xe006ff6e,0xf36eff6c,0x4e5e60ff
+	.long	0xfffff6d4,0xf22ed0c0,0xffdcf22e,0x9c00ff60
+	.long	0x4cee0303,0xff9c3d7c,0x30d0000a,0x3d7ce004
+	.long	0xff6ef36e,0xff6c4e5e,0x60ffffff,0xf694f22e
+	.long	0xf040ff6c,0xf22ed0c0,0xffdcf22e,0x9c00ff60
+	.long	0x4cee0303,0xff9c3d7c,0x30d4000a,0x3d7ce005
+	.long	0xff6ef36e,0xff6c4e5e,0x60ffffff,0xf60c2cae
+	.long	0xffd4082e,0x00050004,0x66000038,0x206effd8
+	.long	0x4e60f22e,0xf040ff6c,0xf22ed0c0,0xffdcf22e
+	.long	0x9c00ff60,0x4cee0303,0xff9c3d7c,0x30cc000a
+	.long	0x3d7ce003,0xff6ef36e,0xff6c4e5e,0x60ffffff
+	.long	0xf5de0c2e,0x0008ff4a,0x66c8f22e,0xf080ff6c
+	.long	0xf22ef040,0xff78f22e,0xd0c0ffdc,0xf22e9c00
+	.long	0xff604cee,0x0303ff9c,0x3d7c30cc,0x000a3d7c
+	.long	0xe003ff7a,0xf36eff78,0x2c562f6f,0x00c400b8
+	.long	0x2f6f00c8,0x00bc2f6f,0x00cc00c0,0x2f6f002c
+	.long	0x00c42f6f,0x003000c8,0x2f6f0034,0x00ccdffc
+	.long	0x000000b8,0x60ffffff,0xf576f22e,0xf040ff6c
+	.long	0xf22ed0c0,0xffdcf22e,0x9c00ff60,0x4cee0303
+	.long	0xff9c3d7c,0x30c4000a,0x3d7ce001,0xff6ef36e
+	.long	0xff6c4e5e,0x60ffffff,0xf55c02ae,0x00ff00ff
+	.long	0xff64f23c,0x90000000,0x0000f23c,0x88000000
+	.long	0x000061ff,0x0000bdba,0x41eeff6c,0x61ff0000
+	.long	0xb9621d40,0xff4ee9ee,0x0183ff42,0x082e0005
+	.long	0xff436728,0x0c2e003a,0xff436720,0x61ff0000
+	.long	0xb4a041ee,0xff7861ff,0x0000b938,0x0c000006
+	.long	0x660661ff,0x0000b89c,0x1d40ff4f,0x4280102e
+	.long	0xff63e9ee,0x1047ff43,0x41eeff6c,0x43eeff78
+	.long	0x223b1d30,0x000068aa,0x4ebb1930,0x000068a2
+	.long	0x102eff62,0x6600008a,0x102eff43,0x02000038
+	.long	0x0c000038,0x670ce9ee,0x0183ff42,0x61ff0000
+	.long	0xb4d0082e,0x00050004,0x6600002a,0x206effd8
+	.long	0x4e60f22e,0xd0c0ffdc,0xf22e9c00,0xff604cee
+	.long	0x0303ff9c,0x4e5e0817,0x00076600,0x012660ff
+	.long	0xfffff440,0x082e0002,0xff4a67d6,0xf22ed0c0
+	.long	0xffdcf22e,0x9c00ff60,0x4cee0303,0xff9c4e5e
+	.long	0x2f6f0004,0x00102f6f,0x0000000c,0xdffc0000
+	.long	0x000c0817,0x00076600,0x00ea60ff,0xfffff404
+	.long	0xc02eff66,0xedc00608,0x6618082e,0x0004ff66
+	.long	0x6700ff66,0x082e0001,0xff626700,0xff5c6000
+	.long	0x006e0480,0x00000018,0x0c000006,0x6d14082e
+	.long	0x0003ff66,0x66000060,0x082e0004,0xff666600
+	.long	0x004e082e,0x00050004,0x66000054,0x206effd8
+	.long	0x4e603d7b,0x022aff6e,0xf22ed0c0,0xffdcf22e
+	.long	0x9c00ff60,0x4cee0303,0xff9cf36e,0xff6c4e5e
+	.long	0x08170007,0x6600006c,0x60ffffff,0xf386e000
+	.long	0xe006e004,0xe005e003,0xe002e001,0xe001303c
+	.long	0x00036000,0xffae303c,0x00046000,0xffa6082e
+	.long	0x0002ff4a,0x67ac3d7b,0x02d6ff6e,0xf22ed0c0
+	.long	0xffdcf22e,0x9c00ff60,0x4cee0303,0xff9cf36e
+	.long	0xff6c4e5e,0x2f6f0004,0x00102f6f,0x0000000c
+	.long	0xdffc0000,0x000c0817,0x00076606,0x60ffffff
+	.long	0xf3223f7c,0x20240006,0xf22fa400,0x000860ff
+	.long	0xfffff402,0x02aeffff,0x00ffff64,0xf23c9000
+	.long	0x00000000,0xf23c8800,0x00000000,0xe9ee0183
+	.long	0xff4261ff,0x0000b22a,0x41eeff6c,0x61ff0000
+	.long	0xb7520c00,0x00066606,0x61ff0000,0xb6b61d40
+	.long	0xff4e4280,0x102eff63,0x41eeff6c,0x2d56ffd4
+	.long	0x61ff0000,0xa94e102e,0xff626600,0x00842cae
+	.long	0xffd4082e,0x00050004,0x6628206e,0xffd84e60
+	.long	0xf22ed0c0,0xffdcf22e,0x9c00ff60,0x4cee0303
+	.long	0xff9c4e5e,0x08170007,0x6600ff68,0x60ffffff
+	.long	0xf282082e,0x0003ff4a,0x67d6f22e,0xd0c0ffdc
+	.long	0xf22e9c00,0xff604cee,0x0303ff9c,0x2c562f6f
+	.long	0x00c400b8,0x2f6f00c8,0x00bc2f6f,0x003800c4
+	.long	0x2f6f003c,0x00c82f6f,0x004000cc,0xdffc0000
+	.long	0x00b80817,0x00076600,0xff1a60ff,0xfffff234
+	.long	0xc02eff66,0xedc00608,0x6700ff74,0x2caeffd4
+	.long	0x0c00001a,0x6e0000e8,0x67000072,0x082e0005
+	.long	0x0004660a,0x206effd8,0x4e606000,0xfb8e0c2e
+	.long	0x0008ff4a,0x6600fb84,0xf22ed0c0,0xffdcf22e
+	.long	0x9c00ff60,0x4cee0303,0xff9c3d7c,0x30d8000a
+	.long	0x3d7ce006,0xff6ef36e,0xff6c2c56,0x2f6f00c4
+	.long	0x00b82f6f,0x00c800bc,0x2f6f00cc,0x00c02f6f
+	.long	0x003800c4,0x2f6f003c,0x00c82f6f,0x004000cc
+	.long	0xdffc0000,0x00b860ff,0xfffff22c,0x082e0005
+	.long	0x00046600,0x000c206e,0xffd84e60,0x6000fb46
+	.long	0x0c2e0008,0xff4a6600,0xfb3cf22e,0xd0c0ffdc
+	.long	0xf22e9c00,0xff604cee,0x0303ff9c,0x3d7c30d0
+	.long	0x000a3d7c,0xe004ff6e,0xf36eff6c,0x2c562f6f
+	.long	0x00c400b8,0x2f6f00c8,0x00bc2f6f,0x00cc00c0
+	.long	0x2f6f0038,0x00c42f6f,0x003c00c8,0x2f6f0040
+	.long	0x00ccdffc,0x000000b8,0x60ffffff,0xf1a4082e
+	.long	0x00050004,0x6600000c,0x206effd8,0x4e606000
+	.long	0xfbda0c2e,0x0008ff4a,0x6600fbd0,0xf22ed0c0
+	.long	0xffdcf22e,0x9c00ff60,0x4cee0303,0xff9c3d7c
+	.long	0x30c4000a,0x3d7ce001,0xff6ef36e,0xff6c2c56
+	.long	0x2f6f00c4,0x00b82f6f,0x00c800bc,0x2f6f00cc
+	.long	0x00c02f6f,0x003800c4,0x2f6f003c,0x00c82f6f
+	.long	0x004000cc,0xdffc0000,0x00b860ff,0xfffff106
+	.long	0xe9ee00c3,0xff420c00,0x00016708,0x0c000005
+	.long	0x67344e75,0x302eff6c,0x02407fff,0x67260c40
+	.long	0x3f806e20,0x44400640,0x3f81222e,0xff70e0a9
+	.long	0x08c1001f,0x2d41ff70,0x026e8000,0xff6c006e
+	.long	0x3f80ff6c,0x4e75302e,0xff6c0240,0x7fff673a
+	.long	0x0c403c00,0x6e344a2e,0xff6c5bee,0xff6e3d40
+	.long	0xff6c4280,0x41eeff6c,0x323c3c01,0x61ff0000
+	.long	0xb156303c,0x3c004a2e,0xff6e6704,0x08c0000f
+	.long	0x08ee0007,0xff703d40,0xff6c4e75,0x082e0005
+	.long	0x000467ff,0xfffff176,0x2d680000,0xff782d68
+	.long	0x0004ff7c,0x2d680008,0xff804281,0x4e752f00
+	.long	0x4e7a0808,0x08000001,0x66000460,0x201f4e56
+	.long	0xff4048ee,0x0303ff9c,0xf22ebc00,0xff60f22e
+	.long	0xf0c0ffdc,0x2d6e0006,0xff44206e,0xff4458ae
+	.long	0xff4461ff,0xfffff152,0x2d40ff40,0x4a406b00
+	.long	0x020e02ae,0x00ff00ff,0xff640800,0x000a6618
+	.long	0x206eff44,0x43eeff6c,0x700c61ff,0xfffff0d2
+	.long	0x4a816600,0x04926048,0x206eff44,0x43eeff6c
+	.long	0x700c61ff,0xfffff0ba,0x4a816600,0x047ae9ee
+	.long	0x004fff6c,0x0c407fff,0x6726102e,0xff6f0200
+	.long	0x000f660c,0x4aaeff70,0x66064aae,0xff746710
+	.long	0x41eeff6c,0x61ff0000,0xb88cf22e,0xf080ff6c
+	.long	0x06ae0000,0x000cff44,0x41eeff6c,0x61ff0000
+	.long	0xb3c21d40,0xff4e0c00,0x0006660a,0x61ff0000
+	.long	0xb3221d40,0xff4e422e,0xff53082e,0x0005ff43
+	.long	0x6748082e,0x0004ff43,0x662ce9ee,0x0183ff42
+	.long	0x61ff0000,0xaeec41ee,0xff7861ff,0x0000b384
+	.long	0x1d40ff4f,0x0c000006,0x662061ff,0x0000b2e4
+	.long	0x1d40ff4f,0x6014082e,0x0003ff43,0x670c50ee
+	.long	0xff53082e,0x0001ff43,0x67c04280,0x102eff63
+	.long	0x122eff43,0x0241007f,0xf23c9000,0x00000000
+	.long	0xf23c8800,0x00000000,0x41eeff6c,0x43eeff78
+	.long	0x223b1530,0x000062ca,0x4ebb1930,0x000062c2
+	.long	0x102eff62,0x66404a2e,0xff53660c,0xe9ee0183
+	.long	0xff4261ff,0x0000aefa,0x2d6e0006,0xff682d6e
+	.long	0xff440006,0xf22ed0c0,0xffdcf22e,0x9c00ff60
+	.long	0x4cee0303,0xff9c4e5e,0x08170007,0x66000096
+	.long	0x60ffffff,0xee6ec02e,0xff66edc0,0x06086612
+	.long	0x082e0004,0xff6667ae,0x082e0001,0xff6267ac
+	.long	0x60340480,0x00000018,0x0c000006,0x6610082e
+	.long	0x0004ff66,0x6620082e,0x0003ff66,0x66203d7b
+	.long	0x0206ff6e,0x601ee002,0xe006e004,0xe005e003
+	.long	0xe002e001,0xe0013d7c,0xe005ff6e,0x60063d7c
+	.long	0xe003ff6e,0x2d6e0006,0xff682d6e,0xff440006
+	.long	0xf22ed0c0,0xffdcf22e,0x9c00ff60,0x4cee0303
+	.long	0xff9cf36e,0xff6c4e5e,0x08170007,0x660660ff
+	.long	0xffffede0,0x2f173f6f,0x00080004,0x3f7c2024
+	.long	0x0006f22f,0xa4000008,0x60ffffff,0xeeb80800
+	.long	0x000e6700,0x01c2082e,0x00050004,0x66164e68
+	.long	0x2d48ffd8,0x61ff0000,0x9564206e,0xffd84e60
+	.long	0x600001aa,0x422eff4a,0x41ee000c,0x2d48ffd8
+	.long	0x61ff0000,0x95480c2e,0x0008ff4a,0x67000086
+	.long	0x0c2e0004,0xff4a6600,0x0184082e,0x00070004
+	.long	0x66363dae,0x00040804,0x2daeff44,0x08063dbc
+	.long	0x00f0080a,0x41f60804,0x2d480004,0xf22ed0c0
+	.long	0xffdcf22e,0x9c00ff60,0x4cee0303,0xff9c4e5e
+	.long	0x2e5f60ff,0xffffed3c,0x3dae0004,0x08002dae
+	.long	0xff440802,0x3dbc2024,0x08062dae,0x00060808
+	.long	0x41f60800,0x2d480004,0xf22ed0c0,0xffdcf22e
+	.long	0x9c00ff60,0x4cee0303,0xff9c4e5e,0x2e5f60ff
+	.long	0xffffedf2,0x1d41000a,0x1d40000b,0xf22ed0c0
+	.long	0xffdcf22e,0x9c00ff60,0x4cee0303,0xff9c2f16
+	.long	0x2f002f01,0x2f2eff44,0x4280102e,0x000b4480
+	.long	0x082e0007,0x0004671c,0x3dae0004,0x08002dae
+	.long	0x00060808,0x2d9f0802,0x3dbc2024,0x08064876
+	.long	0x08006014,0x3dae0004,0x08042d9f,0x08063dbc
+	.long	0x00f0080a,0x48760804,0x4281122e,0x000a4a01
+	.long	0x6a0cf236,0xf080080c,0x06800000,0x000ce309
+	.long	0x6a0cf236,0xf040080c,0x06800000,0x000ce309
+	.long	0x6a0cf236,0xf020080c,0x06800000,0x000ce309
+	.long	0x6a0cf236,0xf010080c,0x06800000,0x000ce309
+	.long	0x6a0cf236,0xf008080c,0x06800000,0x000ce309
+	.long	0x6a0cf236,0xf004080c,0x06800000,0x000ce309
+	.long	0x6a0cf236,0xf002080c,0x06800000,0x000ce309
+	.long	0x6a06f236,0xf001080c,0x222f0004,0x202f0008
+	.long	0x2c6f000c,0x2e5f0817,0x000767ff,0xffffec04
+	.long	0x60ffffff,0xecf061ff,0x00009bda,0xf22ed0c0
+	.long	0xffdcf22e,0x9c00ff60,0x4cee0303,0xff9c082e
+	.long	0x00070004,0x660e2d6e,0xff440006,0x4e5e60ff
+	.long	0xffffebd0,0x2c563f6f,0x00c400c0,0x2f6f00c6
+	.long	0x00c82f6f,0x000400c2,0x3f7c2024,0x00c6dffc
+	.long	0x000000c0,0x60ffffff,0xec9c201f,0x4e56ff40
+	.long	0x48ee0303,0xff9c2d6e,0x0006ff44,0x206eff44
+	.long	0x58aeff44,0x61ffffff,0xed002d40,0xff404a40
+	.long	0x6b047010,0x60260800,0x000e6610,0xe9c014c3
+	.long	0x700c0c01,0x00076614,0x58806010,0x428061ff
+	.long	0x0000967c,0x202eff44,0x90ae0006,0x3d40000a
+	.long	0x4cee0303,0xff9c4e5e,0x518f2f00,0x3f6f000c
+	.long	0x00042f6f,0x000e0006,0x4280302f,0x00122f6f
+	.long	0x00060010,0xd1af0006,0x3f7c402c,0x000a201f
+	.long	0x60ffffff,0xebe44e7a,0x08080800,0x0001660c
+	.long	0xf22e9c00,0xff60f22e,0xd0c0ffdc,0x4cee0303
+	.long	0xff9c4e5e,0x514f2eaf,0x00083f6f,0x000c0004
+	.long	0x3f7c4008,0x00062f6f,0x00020008,0x2f7c0942
+	.long	0x8001000c,0x08170005,0x670608ef,0x0002000d
+	.long	0x60ffffff,0xebd64fee,0xff404e7a,0x18080801
+	.long	0x0001660c,0xf22ed0c0,0xffdcf22f,0x9c000020
+	.long	0x2c562f6f,0x00c400bc,0x3f6f00c8,0x00c03f7c
+	.long	0x400800c2,0x2f4800c4,0x3f4000c8,0x3f7c0001
+	.long	0x00ca4cef,0x0303005c,0xdefc00bc,0x60a64e56
+	.long	0xff40f32e,0xff6c48ee,0x0303ff9c,0xf22ebc00
+	.long	0xff60f22e,0xf0c0ffdc,0x2d6eff68,0xff44206e
+	.long	0xff4458ae,0xff4461ff,0xffffebce,0x2d40ff40
+	.long	0x0800000d,0x662841ee,0xff6c61ff,0xfffff1ea
+	.long	0xf22ed0c0,0xffdcf22e,0x9c00ff60,0x4cee0303
+	.long	0xff9cf36e,0xff6c4e5e,0x60ffffff,0xea94322e
+	.long	0xff6c0241,0x7fff0c41,0x7fff661a,0x4aaeff74
+	.long	0x660c222e,0xff700281,0x7fffffff,0x67082d6e
+	.long	0xff70ff54,0x6012223c,0x7fffffff,0x4a2eff6c
+	.long	0x6a025281,0x2d41ff54,0xe9c004c3,0x122eff41
+	.long	0x307b0206,0x4efb8802,0x006c0000,0x0000ff98
+	.long	0x003e0000,0x00100000,0x102eff54,0x0c010007
+	.long	0x6f16206e,0x000c61ff,0xffffeb86,0x4a8166ff
+	.long	0x0000bca8,0x6000ff6a,0x02410007,0x61ff0000
+	.long	0xa8046000,0xff5c302e,0xff540c01,0x00076f16
+	.long	0x206e000c,0x61ffffff,0xeb6e4a81,0x66ff0000
+	.long	0xbc886000,0xff3c0241,0x000761ff,0x0000a79a
+	.long	0x6000ff2e,0x202eff54,0x0c010007,0x6f16206e
+	.long	0x000c61ff,0xffffeb56,0x4a8166ff,0x0000bc68
+	.long	0x6000ff0e,0x02410007,0x61ff0000,0xa7306000
+	.long	0xff004e56,0xff40f32e,0xff6c48ee,0x0303ff9c
+	.long	0xf22ebc00,0xff60f22e,0xf0c0ffdc,0x2d6eff68
+	.long	0xff44206e,0xff4458ae,0xff4461ff,0xffffea8a
+	.long	0x2d40ff40,0x0800000d,0x6600002a,0x41eeff6c
+	.long	0x61ffffff,0xf0a4f22e,0xd0c0ffdc,0xf22e9c00
+	.long	0xff604cee,0x0303ff9c,0xf36eff6c,0x4e5e60ff
+	.long	0xffffe964,0xe9c004c3,0x122eff41,0x307b0206
+	.long	0x4efb8802,0x007400a6,0x015a0000,0x00420104
+	.long	0x00100000,0x102eff70,0x08c00006,0x0c010007
+	.long	0x6f16206e,0x000c61ff,0xffffea76,0x4a8166ff
+	.long	0x0000bb98,0x6000ffa0,0x02410007,0x61ff0000
+	.long	0xa6f46000,0xff92302e,0xff7008c0,0x000e0c01
+	.long	0x00076f16,0x206e000c,0x61ffffff,0xea5a4a81
+	.long	0x66ff0000,0xbb746000,0xff6e0241,0x000761ff
+	.long	0x0000a686,0x6000ff60,0x202eff70,0x08c0001e
+	.long	0x0c010007,0x6f16206e,0x000c61ff,0xffffea3e
+	.long	0x4a8166ff,0x0000bb50,0x6000ff3c,0x02410007
+	.long	0x61ff0000,0xa6186000,0xff2e0c01,0x00076f2e
+	.long	0x202eff6c,0x02808000,0x00000080,0x7fc00000
+	.long	0x222eff70,0xe0898081,0x206e000c,0x61ffffff
+	.long	0xe9fc4a81,0x66ff0000,0xbb0e6000,0xfefa202e
+	.long	0xff6c0280,0x80000000,0x00807fc0,0x00002f01
+	.long	0x222eff70,0xe0898081,0x221f0241,0x000761ff
+	.long	0x0000a5ba,0x6000fed0,0x202eff6c,0x02808000
+	.long	0x00000080,0x7ff80000,0x222eff70,0x2d40ff84
+	.long	0x700be0a9,0x83aeff84,0x222eff70,0x02810000
+	.long	0x07ffe0b9,0x2d41ff88,0x222eff74,0xe0a983ae
+	.long	0xff8841ee,0xff84226e,0x000c7008,0x61ffffff
+	.long	0xe8cc4a81,0x66ff0000,0xba9c6000,0xfe7a422e
+	.long	0xff4a3d6e,0xff6cff84,0x426eff86,0x202eff70
+	.long	0x08c0001e,0x2d40ff88,0x2d6eff74,0xff8c082e
+	.long	0x00050004,0x66384e68,0x2d48ffd8,0x2d56ffd4
+	.long	0x61ff0000,0x98922248,0x2d48000c,0x206effd8
+	.long	0x4e602cae,0xffd441ee,0xff84700c,0x61ffffff
+	.long	0xe86c4a81,0x66ff0000,0xba4a6000,0xfe1a2d56
+	.long	0xffd461ff,0x00009860,0x22482d48,0x000c2cae
+	.long	0xffd40c2e,0x0008ff4a,0x66ccf22e,0xd0c0ffdc
+	.long	0xf22e9c00,0xff604cee,0x0303ff9c,0xf36eff6c
+	.long	0x2c6effd4,0x2f6f00c4,0x00b82f6f,0x00c800bc
+	.long	0x2f6f00cc,0x00c02f6f,0x004400c4,0x2f6f0048
+	.long	0x00c82f6f,0x004c00cc,0xdffc0000,0x00b860ff
+	.long	0xffffe734,0x4e56ff40,0xf32eff6c,0x48ee0303
+	.long	0xff9cf22e,0xbc00ff60,0xf22ef0c0,0xffdc2d6e
+	.long	0xff68ff44,0x206eff44,0x58aeff44,0x61ffffff
+	.long	0xe7f82d40,0xff400800,0x000d6600,0x0106e9c0
+	.long	0x04c36622,0x0c6e401e,0xff6c661a,0xf23c9000
+	.long	0x00000000,0xf22e4000,0xff70f22e,0x6800ff6c
+	.long	0x3d7ce001,0xff6e41ee,0xff6c61ff,0xffffedea
+	.long	0x02ae00ff,0x01ffff64,0xf23c9000,0x00000000
+	.long	0xf23c8800,0x00000000,0xe9ee1006,0xff420c01
+	.long	0x00176700,0x009641ee,0xff6c61ff,0x0000aa84
+	.long	0x1d40ff4e,0x082e0005,0xff43672e,0x082e0004
+	.long	0xff436626,0xe9ee0183,0xff4261ff,0x0000a5c2
+	.long	0x41eeff78,0x61ff0000,0xaa5a0c00,0x00066606
+	.long	0x61ff0000,0xa9be1d40,0xff4f4280,0x102eff63
+	.long	0x122eff43,0x0241007f,0x41eeff6c,0x43eeff78
+	.long	0x223b1530,0x000059ca,0x4ebb1930,0x000059c2
+	.long	0xe9ee0183,0xff4261ff,0x0000a606,0xf22ed0c0
+	.long	0xffdcf22e,0x9c00ff60,0x4cee0303,0xff9cf36e
+	.long	0xff6c4e5e,0x60ffffff,0xe5cc4280,0x102eff63
+	.long	0x122eff43,0x02810000,0x007f61ff,0x000043ce
+	.long	0x60be1d7c,0x0000ff4e,0x4280102e,0xff6302ae
+	.long	0xffff00ff,0xff6441ee,0xff6c61ff,0x00009be4
+	.long	0x60aa4e56,0xff40f32e,0xff6c48ee,0x0303ff9c
+	.long	0xf22ebc00,0xff60f22e,0xf0c0ffdc,0x2d6eff68
+	.long	0xff44206e,0xff4458ae,0xff4461ff,0xffffe69a
+	.long	0x2d40ff40,0x41eeff6c,0x61ffffff,0xecbcf22e
+	.long	0xd0c0ffdc,0xf22e9c00,0xff604cee,0x0303ff9c
+	.long	0xf36eff6c,0x4e5e60ff,0xffffe592,0x0c6f202c
+	.long	0x000667ff,0x000000aa,0x0c6f402c,0x000667ff
+	.long	0xffffe5a6,0x4e56ff40,0x48ee0303,0xff9c2d6e
+	.long	0x0006ff44,0x206eff44,0x58aeff44,0x61ffffff
+	.long	0xe638e9c0,0x100a0c41,0x03c86664,0xe9c01406
+	.long	0x0c010017,0x665a4e7a,0x08080800,0x0001672a
+	.long	0x4cee0303,0xff9c4e5e,0x518f3eaf,0x00082f6f
+	.long	0x000a0002,0x3f7c402c,0x00062f6f,0x0002000c
+	.long	0x58af0002,0x60ffffff,0xe5404cee,0x0303ff9c
+	.long	0x4e5ef22f,0x84000002,0x58af0002,0x2f172f6f
+	.long	0x00080004,0x1f7c0020,0x000660ff,0x00000012
+	.long	0x4cee0303,0xff9c4e5e,0x60ffffff,0xe4f64e56
+	.long	0xff4048ee,0x0303ff9c,0xf22ebc00,0xff60f22e
+	.long	0xf0c0ffdc,0x082e0005,0x00046608,0x4e682d48
+	.long	0xffd8600c,0x41ee0010,0x2d48ffd8,0x2d48ffd4
+	.long	0x2d6eff68,0xff44206e,0xff4458ae,0xff4461ff
+	.long	0xffffe576,0x2d40ff40,0xf23c9000,0x00000000
+	.long	0xf23c8800,0x00000000,0x422eff4a,0x08000016
+	.long	0x66000182,0x422eff53,0x02ae00ff,0x00ffff64
+	.long	0xe9c01406,0x0c010017,0x670000be,0x61ff0000
+	.long	0x95fc4280,0x102eff63,0x122eff43,0x0241003f
+	.long	0xe749822e,0xff4e43ee,0xff7841ee,0xff6c323b
+	.long	0x132002b2,0x4ebb1120,0x02ac102e,0xff626600
+	.long	0x00a2e9ee,0x0183ff42,0x61ff0000,0xa3e4f22e
+	.long	0xd0c0ffdc,0xf22e9c00,0xff604cee,0x0303ff9c
+	.long	0x0c2e0004,0xff4a672a,0x0c2e0008,0xff4a6722
+	.long	0x4e5e0817,0x000767ff,0xffffe358,0xf327f22f
+	.long	0xa4000014,0xf35f3f7c,0x20240006,0x60ffffff
+	.long	0xe434082e,0x00050004,0x660c2f08,0x206effd8
+	.long	0x4e60205f,0x60ca2f00,0x202effd8,0x90aeffd4
+	.long	0x2dae0008,0x08082dae,0x00040804,0x3d400004
+	.long	0x201f4e5e,0xded760aa,0x4280102e,0xff63122e
+	.long	0xff430281,0x0000007f,0x61ff0000,0x41506000
+	.long	0xff5ac02e,0xff66edc0,0x06086616,0x082e0004
+	.long	0xff666700,0xff4e082e,0x0001ff62,0x6700ff44
+	.long	0x603e0480,0x00000018,0x0c000006,0x6610082e
+	.long	0x0004ff66,0x662a082e,0x0003ff66,0x66302f00
+	.long	0x61ffffff,0xf1ee201f,0x3d7b0206,0xff6e602a
+	.long	0xe002e006,0xe004e005,0xe003e002,0xe001e001
+	.long	0x61ffffff,0xf1ce3d7c,0xe005ff6e,0x600c61ff
+	.long	0xfffff1c0,0x3d7ce003,0xff6ef22e,0xd0c0ffdc
+	.long	0xf22e9c00,0xff604cee,0x0303ff9c,0xf36eff6c
+	.long	0x6000feee,0xe9c01283,0x0c010001,0x67000056
+	.long	0x0c010007,0x66000078,0xe9c01343,0x0c010002
+	.long	0x6d00006c,0x61ff0000,0x82780c2e,0x0002ff4a
+	.long	0x670000d2,0x0c2e0001,0xff4a6600,0x01002d6e
+	.long	0xff68000c,0x3d7c201c,0x000af22e,0xd0c0ffdc
+	.long	0xf22e9c00,0xff604cee,0x0303ff9c,0x4e5e60ff
+	.long	0xffffe2dc,0x206eff44,0x54aeff44,0x61ffffff
+	.long	0xe3524a81,0x6600047c,0x48c061ff,0x00007e60
+	.long	0x0c2e0002,0xff4a6700,0x007c6000,0x00b061ff
+	.long	0x00008562,0x0c2e0002,0xff4a6700,0x0068082e
+	.long	0x00050004,0x660a206e,0xffd84e60,0x6000008e
+	.long	0x0c2e0008,0xff4a6600,0x0084f22e,0xd0c0ffdc
+	.long	0xf22e9c00,0xff604cee,0x0303ff9c,0x4e5e0817
+	.long	0x00076612,0x558f2eaf,0x00022f6f,0x00060004
+	.long	0x60ffffff,0xe17e558f,0x2eaf0002,0x3f6f0006
+	.long	0x00043f7c,0x20240006,0xf22fa400,0x000860ff
+	.long	0xffffe252,0x3d7c00c0,0x000e2d6e,0xff68000a
+	.long	0x3d6e0004,0x00083d7c,0xe000ff6e,0xf22ed0c0
+	.long	0xffdcf22e,0x9c00ff60,0x4cee0303,0xff9cf36e
+	.long	0xff6c4e5e,0x588f60ff,0xffffe180,0xf22ed0c0
+	.long	0xffdcf22e,0x9c00ff60,0x4cee0303,0xff9c4e5e
+	.long	0x08170007,0x660660ff,0xffffe108,0xf22fa400
+	.long	0x00081f7c,0x00240007,0x60ffffff,0xe1e84afc
+	.long	0x01c00000,0x00000000,0x00000000,0x00000000
+	.long	0x00000000,0x00000000,0x00000000,0x00000000
+	.long	0x000028a4,0x4b1e4b4c,0x4f4c2982,0x4f3c0000
+	.long	0x00000000,0x00000000,0x00000000,0x00000000
+	.long	0x00000000,0x00000000,0x00000000,0x00000000
+	.long	0x00000000,0x00000000,0x00000000,0x00000000
+	.long	0x000035c6,0x4b1e4b82,0x4f4c371a,0x4f3c0000
+	.long	0x00000000,0x00000000,0x00000000,0x00000000
+	.long	0x000024b0,0x4b1e4b8c,0x4f4c2766,0x4f3c0000
+	.long	0x00002988,0x4b1e4b94,0x4f4c2af0,0x4f3c0000
+	.long	0x00001ab8,0x4b1e4bd0,0x4f4c1cf6,0x4f3c0000
+	.long	0x00000000,0x00000000,0x00000000,0x00000000
+	.long	0x00001cfc,0x4b1e4744,0x4f4c1daa,0x4f3c0000
+	.long	0x00003720,0x4b1e4744,0x4f4c37a2,0x4f3c0000
+	.long	0x00000468,0x4b1e4744,0x4f4c064c,0x4f3c0000
+	.long	0x00000f2a,0x4b1e4744,0x4f4c108e,0x4f3c0000
+	.long	0x000022e0,0x4b9a4b7a,0x4f4c248c,0x4f3c0000
+	.long	0x00003d02,0x4b9a4b7a,0x4f4c3ddc,0x4f3c0000
+	.long	0x00003dfa,0x4b9a4b7a,0x4f4c3f2a,0x4f3c0000
+	.long	0x00000000,0x00000000,0x00000000,0x00000000
+	.long	0x00003386,0x47324b82,0x4f4c3538,0x4f3c0000
+	.long	0x000037c8,0x47324b82,0x4f4c37f8,0x4f3c0000
+	.long	0x00003818,0x47324b82,0x4f4c3872,0x4f3c0000
+	.long	0x00000000,0x00000000,0x00000000,0x00000000
+	.long	0x00000000,0x00000000,0x00000000,0x00000000
+	.long	0x000027e6,0x4b9a4b52,0x4f4c288a,0x4f3c0000
+	.long	0x00000000,0x00000000,0x00000000,0x00000000
+	.long	0x00000000,0x00000000,0x00000000,0x00000000
+	.long	0x00001db0,0x4bd64744,0x4f4c1e40,0x4f3c0000
+	.long	0x00000472,0x4b9a4744,0x4f4c0652,0x4f3c0000
+	.long	0x0000276c,0x4b1e4744,0x4f4c2788,0x4f3c0000
+	.long	0x000027a0,0x4b1e4744,0x4f4c27ce,0x4f3c0000
+	.long	0x00000000,0x00000000,0x00000000,0x00000000
+	.long	0x00004ca4,0x4cda4d12,0x4ee24ca4,0x4ef40000
+	.long	0x00000000,0x00000000,0x00000000,0x00000000
+	.long	0x00000000,0x00000000,0x00000000,0x00000000
+	.long	0x00000000,0x00000000,0x00000000,0x00000000
+	.long	0x00004dac,0x4de24e1a,0x4ee24dac,0x4ef40000
+	.long	0x00004e4e,0x4e864ebe,0x4ee24e4e,0x4ef40000
+	.long	0x00000000,0x00000000,0x00000000,0x00000000
+	.long	0x00000000,0x00000000,0x00000000,0x00000000
+	.long	0x00000000,0x00000000,0x00000000,0x00000000
+	.long	0x00000000,0x00000000,0x00000000,0x00000000
+	.long	0x00000000,0x00000000,0x00000000,0x00000000
+	.long	0x00000000,0x00000000,0x00000000,0x00000000
+	.long	0x00000000,0x00000000,0x00000000,0x00000000
+	.long	0x00000000,0x00000000,0x00000000,0x00000000
+	.long	0x00000000,0x00000000,0x00000000,0x00000000
+	.long	0x00000660,0x4bf24c20,0x4c3008f6,0x4c400000
+	.long	0x00000660,0x4bf24c20,0x4c3008f6,0x4c400000
+	.long	0x00000660,0x4bf24c20,0x4c3008f6,0x4c400000
+	.long	0x00000660,0x4bf24c20,0x4c3008f6,0x4c400000
+	.long	0x00000660,0x4bf24c20,0x4c3008f6,0x4c400000
+	.long	0x00000660,0x4bf24c20,0x4c3008f6,0x4c400000
+	.long	0x00000660,0x4bf24c20,0x4c3008f6,0x4c400000
+	.long	0x00000660,0x4bf24c20,0x4c3008f6,0x4c400000
+	.long	0x00004cee,0x0303ff9c,0xf22e9c00,0xff60f22e
+	.long	0xd0c0ffdc,0x2d6eff68,0x00064e5e,0x2f173f6f
+	.long	0x00080004,0x3f7c4008,0x00062f6f,0x00020008
+	.long	0x2f7c0942,0x8001000c,0x08170005,0x670608ef
+	.long	0x0002000d,0x60ffffff,0xde32bd6a,0xaa77ccc9
+	.long	0x94f53de6,0x12097aae,0x8da1be5a,0xe6452a11
+	.long	0x8ae43ec7,0x1de3a534,0x1531bf2a,0x01a01a01
+	.long	0x8b590000,0x00000000,0x00003ff8,0x00008888
+	.long	0x88888888,0x59af0000,0x0000bffc,0x0000aaaa
+	.long	0xaaaaaaaa,0xaa990000,0x00003d2a,0xc4d0d601
+	.long	0x1ee3bda9,0x396f9f45,0xac193e21,0xeed90612
+	.long	0xc972be92,0x7e4fb79d,0x9fcf3efa,0x01a01a01
+	.long	0xd4230000,0x00000000,0x0000bff5,0x0000b60b
+	.long	0x60b60b61,0xd4380000,0x00003ffa,0x0000aaaa
+	.long	0xaaaaaaaa,0xab5ebf00,0x00002d7c,0x00000000
+	.long	0xff5c6008,0x2d7c0000,0x0001ff5c,0xf2104800
+	.long	0xf22e6800,0xff842210,0x32280004,0x02817fff
+	.long	0xffff0c81,0x3fd78000,0x6c046000,0x01780c81
+	.long	0x4004bc7e,0x6d046000,0x0468f200,0x0080f23a
+	.long	0x54a3de7e,0x43fb0170,0x00000866,0xf22e6080
+	.long	0xff58222e,0xff58e981,0xd3c1f219,0x4828f211
+	.long	0x4428222e,0xff58d2ae,0xff5ce299,0x0c810000
+	.long	0x00006d00,0x0088f227,0xe00cf22e,0x6800ff84
+	.long	0xf2000023,0xf23a5580,0xfed2f23a,0x5500fed4
+	.long	0xf2000080,0xf20004a3,0xe2990281,0x80000000
+	.long	0xb3aeff84,0xf20005a3,0xf2000523,0xf23a55a2
+	.long	0xfebaf23a,0x5522febc,0xf20005a3,0xf2000523
+	.long	0xf23a55a2,0xfeb6f23a,0x4922fec0,0xf2000ca3
+	.long	0xf2000123,0xf23a48a2,0xfec2f22e,0x4823ff84
+	.long	0xf20008a2,0xf2000423,0xf21fd030,0xf2009000
+	.long	0xf22e4822,0xff8460ff,0x00004364,0xf227e00c
+	.long	0xf2000023,0xf23a5500,0xfea2f23a,0x5580fea4
+	.long	0xf2000080,0xf20004a3,0xf22e6800,0xff84e299
+	.long	0x02818000,0x0000f200,0x0523b3ae,0xff840281
+	.long	0x80000000,0xf20005a3,0x00813f80,0x00002d41
+	.long	0xff54f23a,0x5522fe74,0xf23a55a2,0xfe76f200
+	.long	0x0523f200,0x05a3f23a,0x5522fe70,0xf23a49a2
+	.long	0xfe7af200,0x0523f200,0x0ca3f23a,0x4922fe7c
+	.long	0xf23a44a2,0xfe82f200,0x0823f200,0x0422f22e
+	.long	0x4823ff84,0xf21fd030,0xf2009000,0xf22e4422
+	.long	0xff5460ff,0x000042c8,0x0c813fff,0x80006eff
+	.long	0x00000300,0x222eff5c,0x0c810000,0x00006e14
+	.long	0xf2009000,0x123c0003,0xf22e4800,0xff8460ff
+	.long	0x0000428e,0xf23c4400,0x3f800000,0xf2009000
+	.long	0xf23c4422,0x80800000,0x60ff0000,0x428a60ff
+	.long	0x00004110,0xf23c4400,0x3f800000,0x60ff0000
+	.long	0x42762d7c,0x00000004,0xff5cf210,0x4800f22e
+	.long	0x6800ff84,0x22103228,0x00040281,0x7fffffff
+	.long	0x0c813fd7,0x80006c04,0x60000240,0x0c814004
+	.long	0xbc7e6d04,0x6000027a,0xf2000080,0xf23a54a3
+	.long	0xdc9043fb,0x01700000,0x0678f22e,0x6080ff58
+	.long	0x222eff58,0xe981d3c1,0xf2194828,0xf2114428
+	.long	0x222eff58,0xe2990c81,0x00000000,0x6c000106
+	.long	0xf227e004,0xf22e6800,0xff84f200,0x0023f23a
+	.long	0x5480fce8,0xf23a5500,0xfd32f200,0x00a3f200
+	.long	0x01232f02,0x2401e29a,0x02828000,0x0000b382
+	.long	0x02828000,0x0000f23a,0x54a2fcc8,0xf23a5522
+	.long	0xfd12f200,0x00a3b5ae,0xff84241f,0xf2000123
+	.long	0xe2990281,0x80000000,0x2d7c3f80,0x0000ff54
+	.long	0xb3aeff54,0xf23a54a2,0xfca2f23a,0x5522fcec
+	.long	0xf20000a3,0xf2000123,0xf22e6800,0xff90f23a
+	.long	0x54a2fc90,0xb3aeff90,0xf23a5522,0xfcd6f200
+	.long	0x00a3f200,0x0123f23a,0x54a2fc80,0xf23a5522
+	.long	0xfccaf200,0x00a3f200,0x0123f23a,0x48a2fc7c
+	.long	0xf23a4922,0xfcc6f200,0x00a3f200,0x0123f23a
+	.long	0x48a2fc78,0xf23a4922,0xfcc2f200,0x00a3f200
+	.long	0x0823f22e,0x48a3ff84,0xf23a4422,0xfcbaf22e
+	.long	0x4823ff90,0xf21fd020,0xf2009000,0xf22e48a2
+	.long	0xff8461ff,0x0000448e,0xf22e4422,0xff5460ff
+	.long	0x000040fc,0xf227e004,0xf22e6800,0xff84f200
+	.long	0x0023f23a,0x5480fc34,0xf23a5500,0xfbdef200
+	.long	0x00a3f22e,0x6800ff90,0xf2000123,0xe2990281
+	.long	0x80000000,0xf23a54a2,0xfc1af23a,0x5522fbc4
+	.long	0xb3aeff84,0xb3aeff90,0xf20000a3,0x00813f80
+	.long	0x00002d41,0xff54f200,0x0123f23a,0x54a2fbfc
+	.long	0xf23a5522,0xfba6f200,0x00a3f200,0x0123f23a
+	.long	0x54a2fbf0,0xf23a5522,0xfb9af200,0x00a3f200
+	.long	0x0123f23a,0x54a2fbe4,0xf23a5522,0xfb8ef200
+	.long	0x00a3f200,0x0123f23a,0x48a2fbe0,0xf23a4922
+	.long	0xfb8af200,0x00a3f200,0x0123f23a,0x48a2fbdc
+	.long	0xf23a4922,0xfb86f200,0x00a3f200,0x0823f23a
+	.long	0x44a2fbd4,0xf22e4823,0xff84f22e,0x48a3ff90
+	.long	0xf21fd020,0xf2009000,0xf22e44a2,0xff5461ff
+	.long	0x000043a2,0xf22e4822,0xff8460ff,0x00004010
+	.long	0x0c813fff,0x80006e00,0x0048f23c,0x44803f80
+	.long	0x0000f200,0x9000f23c,0x44a80080,0x000061ff
+	.long	0x00004372,0xf200b000,0x123c0003,0xf22e4800
+	.long	0xff8460ff,0x00003fca,0x2f00f23c,0x44803f80
+	.long	0x000061ff,0x0000434e,0x201f60ff,0x00003e54
+	.long	0xf227e03c,0x2f02f23c,0x44800000,0x00000c81
+	.long	0x7ffeffff,0x66523d7c,0x7ffeff84,0x2d7cc90f
+	.long	0xdaa2ff88,0x42aeff8c,0x3d7c7fdc,0xff902d7c
+	.long	0x85a308d3,0xff9442ae,0xff98f200,0x003af294
+	.long	0x000e002e,0x0080ff84,0x002e0080,0xff90f22e
+	.long	0x4822ff84,0xf2000080,0xf22e4822,0xff90f200
+	.long	0x00a8f22e,0x48a2ff90,0xf22e6800,0xff84322e
+	.long	0xff842241,0x02810000,0x7fff0481,0x00003fff
+	.long	0x0c810000,0x001c6f0e,0x04810000,0x001b1d7c
+	.long	0x0000ff58,0x60084281,0x1d7c0001,0xff58243c
+	.long	0x00003ffe,0x94812d7c,0xa2f9836e,0xff882d7c
+	.long	0x4e44152a,0xff8c3d42,0xff84f200,0x0100f22e
+	.long	0x4923ff84,0x24094842,0x02828000,0x00000082
+	.long	0x5f000000,0x2d42ff54,0xf22e4522,0xff54f22e
+	.long	0x4528ff54,0x24010682,0x00003fff,0x3d42ff84
+	.long	0x2d7cc90f,0xdaa2ff88,0x42aeff8c,0x06810000
+	.long	0x3fdd3d41,0xff902d7c,0x85a308d3,0xff9442ae
+	.long	0xff98122e,0xff58f200,0x0a00f22e,0x4a23ff84
+	.long	0xf2000a80,0xf22e4aa3,0xff90f200,0x1180f200
+	.long	0x15a2f200,0x0e28f200,0x0c28f200,0x1622f200
+	.long	0x0180f200,0x10a8f200,0x04220c01,0x00006e00
+	.long	0x000ef200,0x01a8f200,0x0ca26000,0xff0cf22e
+	.long	0x6100ff58,0x241ff21f,0xd03c222e,0xff5c0c81
+	.long	0x00000004,0x6d00fa4c,0x6000fc36,0x3ea0b759
+	.long	0xf50f8688,0xbef2baa5,0xa8924f04,0xbf346f59
+	.long	0xb39ba65f,0x00000000,0x00000000,0x3ff60000
+	.long	0xe073d3fc,0x199c4a00,0x00000000,0x3ff90000
+	.long	0xd23cd684,0x15d95fa1,0x00000000,0xbffc0000
+	.long	0x8895a6c5,0xfb423bca,0x00000000,0xbffd0000
+	.long	0xeef57e0d,0xa84bc8ce,0x00000000,0x3ffc0000
+	.long	0xa2f9836e,0x4e44152a,0x00000000,0x40010000
+	.long	0xc90fdaa2,0x00000000,0x00000000,0x3fdf0000
+	.long	0x85a308d4,0x00000000,0x00000000,0xc0040000
+	.long	0xc90fdaa2,0x2168c235,0x21800000,0xc0040000
+	.long	0xc2c75bcd,0x105d7c23,0xa0d00000,0xc0040000
+	.long	0xbc7edcf7,0xff523611,0xa1e80000,0xc0040000
+	.long	0xb6365e22,0xee46f000,0x21480000,0xc0040000
+	.long	0xafeddf4d,0xdd3ba9ee,0xa1200000,0xc0040000
+	.long	0xa9a56078,0xcc3063dd,0x21fc0000,0xc0040000
+	.long	0xa35ce1a3,0xbb251dcb,0x21100000,0xc0040000
+	.long	0x9d1462ce,0xaa19d7b9,0xa1580000,0xc0040000
+	.long	0x96cbe3f9,0x990e91a8,0x21e00000,0xc0040000
+	.long	0x90836524,0x88034b96,0x20b00000,0xc0040000
+	.long	0x8a3ae64f,0x76f80584,0xa1880000,0xc0040000
+	.long	0x83f2677a,0x65ecbf73,0x21c40000,0xc0030000
+	.long	0xfb53d14a,0xa9c2f2c2,0x20000000,0xc0030000
+	.long	0xeec2d3a0,0x87ac669f,0x21380000,0xc0030000
+	.long	0xe231d5f6,0x6595da7b,0xa1300000,0xc0030000
+	.long	0xd5a0d84c,0x437f4e58,0x9fc00000,0xc0030000
+	.long	0xc90fdaa2,0x2168c235,0x21000000,0xc0030000
+	.long	0xbc7edcf7,0xff523611,0xa1680000,0xc0030000
+	.long	0xafeddf4d,0xdd3ba9ee,0xa0a00000,0xc0030000
+	.long	0xa35ce1a3,0xbb251dcb,0x20900000,0xc0030000
+	.long	0x96cbe3f9,0x990e91a8,0x21600000,0xc0030000
+	.long	0x8a3ae64f,0x76f80584,0xa1080000,0xc0020000
+	.long	0xfb53d14a,0xa9c2f2c2,0x1f800000,0xc0020000
+	.long	0xe231d5f6,0x6595da7b,0xa0b00000,0xc0020000
+	.long	0xc90fdaa2,0x2168c235,0x20800000,0xc0020000
+	.long	0xafeddf4d,0xdd3ba9ee,0xa0200000,0xc0020000
+	.long	0x96cbe3f9,0x990e91a8,0x20e00000,0xc0010000
+	.long	0xfb53d14a,0xa9c2f2c2,0x1f000000,0xc0010000
+	.long	0xc90fdaa2,0x2168c235,0x20000000,0xc0010000
+	.long	0x96cbe3f9,0x990e91a8,0x20600000,0xc0000000
+	.long	0xc90fdaa2,0x2168c235,0x1f800000,0xbfff0000
+	.long	0xc90fdaa2,0x2168c235,0x1f000000,0x00000000
+	.long	0x00000000,0x00000000,0x00000000,0x3fff0000
+	.long	0xc90fdaa2,0x2168c235,0x9f000000,0x40000000
+	.long	0xc90fdaa2,0x2168c235,0x9f800000,0x40010000
+	.long	0x96cbe3f9,0x990e91a8,0xa0600000,0x40010000
+	.long	0xc90fdaa2,0x2168c235,0xa0000000,0x40010000
+	.long	0xfb53d14a,0xa9c2f2c2,0x9f000000,0x40020000
+	.long	0x96cbe3f9,0x990e91a8,0xa0e00000,0x40020000
+	.long	0xafeddf4d,0xdd3ba9ee,0x20200000,0x40020000
+	.long	0xc90fdaa2,0x2168c235,0xa0800000,0x40020000
+	.long	0xe231d5f6,0x6595da7b,0x20b00000,0x40020000
+	.long	0xfb53d14a,0xa9c2f2c2,0x9f800000,0x40030000
+	.long	0x8a3ae64f,0x76f80584,0x21080000,0x40030000
+	.long	0x96cbe3f9,0x990e91a8,0xa1600000,0x40030000
+	.long	0xa35ce1a3,0xbb251dcb,0xa0900000,0x40030000
+	.long	0xafeddf4d,0xdd3ba9ee,0x20a00000,0x40030000
+	.long	0xbc7edcf7,0xff523611,0x21680000,0x40030000
+	.long	0xc90fdaa2,0x2168c235,0xa1000000,0x40030000
+	.long	0xd5a0d84c,0x437f4e58,0x1fc00000,0x40030000
+	.long	0xe231d5f6,0x6595da7b,0x21300000,0x40030000
+	.long	0xeec2d3a0,0x87ac669f,0xa1380000,0x40030000
+	.long	0xfb53d14a,0xa9c2f2c2,0xa0000000,0x40040000
+	.long	0x83f2677a,0x65ecbf73,0xa1c40000,0x40040000
+	.long	0x8a3ae64f,0x76f80584,0x21880000,0x40040000
+	.long	0x90836524,0x88034b96,0xa0b00000,0x40040000
+	.long	0x96cbe3f9,0x990e91a8,0xa1e00000,0x40040000
+	.long	0x9d1462ce,0xaa19d7b9,0x21580000,0x40040000
+	.long	0xa35ce1a3,0xbb251dcb,0xa1100000,0x40040000
+	.long	0xa9a56078,0xcc3063dd,0xa1fc0000,0x40040000
+	.long	0xafeddf4d,0xdd3ba9ee,0x21200000,0x40040000
+	.long	0xb6365e22,0xee46f000,0xa1480000,0x40040000
+	.long	0xbc7edcf7,0xff523611,0x21e80000,0x40040000
+	.long	0xc2c75bcd,0x105d7c23,0x20d00000,0x40040000
+	.long	0xc90fdaa2,0x2168c235,0xa1800000,0xf2104800
+	.long	0x22103228,0x00040281,0x7fffffff,0x0c813fd7
+	.long	0x80006c04,0x60000134,0x0c814004,0xbc7e6d04
+	.long	0x60000144,0xf2000080,0xf23a54a3,0xd3d443fa
+	.long	0xfdbcf201,0x6080e981,0xd3c1f219,0x4828f211
+	.long	0x4428ea99,0x02818000,0x0000f227,0xe00c0c81
+	.long	0x00000000,0x6d000072,0xf2000080,0xf20004a3
+	.long	0xf23a5580,0xfaf8f23a,0x5500fafa,0xf20005a3
+	.long	0xf2000523,0xf23a55a2,0xfaf4f23a,0x4922fafe
+	.long	0xf20005a3,0xf2000523,0xf23a49a2,0xfb00f23a
+	.long	0x4922fb0a,0xf20005a3,0xf2000523,0xf23a49a2
+	.long	0xfb0cf200,0x0123f200,0x0ca3f200,0x0822f23c
+	.long	0x44a23f80,0x0000f21f,0xd030f200,0x9000f200
+	.long	0x042060ff,0x000038d8,0xf2000080,0xf2000023
+	.long	0xf23a5580,0xfa88f23a,0x5500fa8a,0xf20001a3
+	.long	0xf2000123,0xf23a55a2,0xfa84f23a,0x4922fa8e
+	.long	0xf20001a3,0xf2000123,0xf23a49a2,0xfa90f23a
+	.long	0x4922fa9a,0xf20001a3,0xf2000123,0xf23a49a2
+	.long	0xfa9cf200,0x0523f200,0x0c23f200,0x08a2f23c
+	.long	0x44223f80,0x0000f21f,0xd030f227,0x68800a97
+	.long	0x80000000,0xf2009000,0xf21f4820,0x60ff0000
+	.long	0x385e0c81,0x3fff8000,0x6e1cf227,0x6800f200
+	.long	0x9000123c,0x0003f21f,0x480060ff,0x00003832
+	.long	0x60ff0000,0x36cef227,0xe03c2f02,0xf23c4480
+	.long	0x00000000,0x0c817ffe,0xffff6652,0x3d7c7ffe
+	.long	0xff842d7c,0xc90fdaa2,0xff8842ae,0xff8c3d7c
+	.long	0x7fdcff90,0x2d7c85a3,0x08d3ff94,0x42aeff98
+	.long	0xf200003a,0xf294000e,0x002e0080,0xff84002e
+	.long	0x0080ff90,0xf22e4822,0xff84f200,0x0080f22e
+	.long	0x4822ff90,0xf20000a8,0xf22e48a2,0xff90f22e
+	.long	0x6800ff84,0x322eff84,0x22410281,0x00007fff
+	.long	0x04810000,0x3fff0c81,0x0000001c,0x6f0e0481
+	.long	0x0000001b,0x1d7c0000,0xff586008,0x42811d7c
+	.long	0x0001ff58,0x243c0000,0x3ffe9481,0x2d7ca2f9
+	.long	0x836eff88,0x2d7c4e44,0x152aff8c,0x3d42ff84
+	.long	0xf2000100,0xf22e4923,0xff842409,0x48420282
+	.long	0x80000000,0x00825f00,0x00002d42,0xff54f22e
+	.long	0x4522ff54,0xf22e4528,0xff542401,0x06820000
+	.long	0x3fff3d42,0xff842d7c,0xc90fdaa2,0xff8842ae
+	.long	0xff8c0681,0x00003fdd,0x3d41ff90,0x2d7c85a3
+	.long	0x08d3ff94,0x42aeff98,0x122eff58,0xf2000a00
+	.long	0xf22e4a23,0xff84f200,0x0a80f22e,0x4aa3ff90
+	.long	0xf2001180,0xf20015a2,0xf2000e28,0xf2000c28
+	.long	0xf2001622,0xf2000180,0xf20010a8,0xf2000422
+	.long	0x0c010000,0x6e00000e,0xf20001a8,0xf2000ca2
+	.long	0x6000ff0c,0xf22e6100,0xff54241f,0xf21fd03c
+	.long	0x222eff54,0xe2996000,0xfd72bff6,0x687e3149
+	.long	0x87d84002,0xac6934a2,0x6db3bfc2,0x476f4e1d
+	.long	0xa28e3fb3,0x44447f87,0x6989bfb7,0x44ee7faf
+	.long	0x45db3fbc,0x71c64694,0x0220bfc2,0x49249218
+	.long	0x72f93fc9,0x99999999,0x8fa9bfd5,0x55555555
+	.long	0x5555bfb7,0x0bf39853,0x9e6a3fbc,0x7187962d
+	.long	0x1d7dbfc2,0x49248271,0x07b83fc9,0x99999996
+	.long	0x263ebfd5,0x55555555,0x55363fff,0x0000c90f
+	.long	0xdaa22168,0xc2350000,0x0000bfff,0x0000c90f
+	.long	0xdaa22168,0xc2350000,0x00000001,0x00008000
+	.long	0x00000000,0x00000000,0x00008001,0x00008000
+	.long	0x00000000,0x00000000,0x00003ffb,0x000083d1
+	.long	0x52c5060b,0x7a510000,0x00003ffb,0x00008bc8
+	.long	0x54456549,0x8b8b0000,0x00003ffb,0x000093be
+	.long	0x40601762,0x6b0d0000,0x00003ffb,0x00009bb3
+	.long	0x078d35ae,0xc2020000,0x00003ffb,0x0000a3a6
+	.long	0x9a525ddc,0xe7de0000,0x00003ffb,0x0000ab98
+	.long	0xe9436276,0x56190000,0x00003ffb,0x0000b389
+	.long	0xe502f9c5,0x98620000,0x00003ffb,0x0000bb79
+	.long	0x7e436b09,0xe6fb0000,0x00003ffb,0x0000c367
+	.long	0xa5c739e5,0xf4460000,0x00003ffb,0x0000cb54
+	.long	0x4c61cff7,0xd5c60000,0x00003ffb,0x0000d33f
+	.long	0x62f82488,0x533e0000,0x00003ffb,0x0000db28
+	.long	0xda816240,0x4c770000,0x00003ffb,0x0000e310
+	.long	0xa4078ad3,0x4f180000,0x00003ffb,0x0000eaf6
+	.long	0xb0a8188e,0xe1eb0000,0x00003ffb,0x0000f2da
+	.long	0xf1949dbe,0x79d50000,0x00003ffb,0x0000fabd
+	.long	0x581361d4,0x7e3e0000,0x00003ffc,0x00008346
+	.long	0xac210959,0xecc40000,0x00003ffc,0x00008b23
+	.long	0x2a083042,0x82d80000,0x00003ffc,0x000092fb
+	.long	0x70b8d29a,0xe2f90000,0x00003ffc,0x00009acf
+	.long	0x476f5ccd,0x1cb40000,0x00003ffc,0x0000a29e
+	.long	0x76304954,0xf23f0000,0x00003ffc,0x0000aa68
+	.long	0xc5d08ab8,0x52300000,0x00003ffc,0x0000b22d
+	.long	0xfffd9d53,0x9f830000,0x00003ffc,0x0000b9ed
+	.long	0xef453e90,0x0ea50000,0x00003ffc,0x0000c1a8
+	.long	0x5f1cc75e,0x3ea50000,0x00003ffc,0x0000c95d
+	.long	0x1be82813,0x8de60000,0x00003ffc,0x0000d10b
+	.long	0xf300840d,0x2de40000,0x00003ffc,0x0000d8b4
+	.long	0xb2ba6bc0,0x5e7a0000,0x00003ffc,0x0000e057
+	.long	0x2a6bb423,0x35f60000,0x00003ffc,0x0000e7f3
+	.long	0x2a70ea9c,0xaa8f0000,0x00003ffc,0x0000ef88
+	.long	0x843264ec,0xefaa0000,0x00003ffc,0x0000f717
+	.long	0x0a28ecc0,0x66660000,0x00003ffd,0x0000812f
+	.long	0xd288332d,0xad320000,0x00003ffd,0x000088a8
+	.long	0xd1b1218e,0x4d640000,0x00003ffd,0x00009012
+	.long	0xab3f23e4,0xaee80000,0x00003ffd,0x0000976c
+	.long	0xc3d411e7,0xf1b90000,0x00003ffd,0x00009eb6
+	.long	0x89493889,0xa2270000,0x00003ffd,0x0000a5ef
+	.long	0x72c34487,0x361b0000,0x00003ffd,0x0000ad17
+	.long	0x00baf07a,0x72270000,0x00003ffd,0x0000b42c
+	.long	0xbcfafd37,0xefb70000,0x00003ffd,0x0000bb30
+	.long	0x3a940ba8,0x0f890000,0x00003ffd,0x0000c221
+	.long	0x15c6fcae,0xbbaf0000,0x00003ffd,0x0000c8fe
+	.long	0xf3e68633,0x12210000,0x00003ffd,0x0000cfc9
+	.long	0x8330b400,0x0c700000,0x00003ffd,0x0000d680
+	.long	0x7aa1102c,0x5bf90000,0x00003ffd,0x0000dd23
+	.long	0x99bc3125,0x2aa30000,0x00003ffd,0x0000e3b2
+	.long	0xa8556b8f,0xc5170000,0x00003ffd,0x0000ea2d
+	.long	0x764f6431,0x59890000,0x00003ffd,0x0000f3bf
+	.long	0x5bf8bad1,0xa21d0000,0x00003ffe,0x0000801c
+	.long	0xe39e0d20,0x5c9a0000,0x00003ffe,0x00008630
+	.long	0xa2dada1e,0xd0660000,0x00003ffe,0x00008c1a
+	.long	0xd445f3e0,0x9b8c0000,0x00003ffe,0x000091db
+	.long	0x8f1664f3,0x50e20000,0x00003ffe,0x00009773
+	.long	0x1420365e,0x538c0000,0x00003ffe,0x00009ce1
+	.long	0xc8e6a0b8,0xcdba0000,0x00003ffe,0x0000a228
+	.long	0x32dbcada,0xae090000,0x00003ffe,0x0000a746
+	.long	0xf2ddb760,0x22940000,0x00003ffe,0x0000ac3e
+	.long	0xc0fb997d,0xd6a20000,0x00003ffe,0x0000b110
+	.long	0x688aebdc,0x6f6a0000,0x00003ffe,0x0000b5bc
+	.long	0xc49059ec,0xc4b00000,0x00003ffe,0x0000ba44
+	.long	0xbc7dd470,0x782f0000,0x00003ffe,0x0000bea9
+	.long	0x4144fd04,0x9aac0000,0x00003ffe,0x0000c2eb
+	.long	0x4abb6616,0x28b60000,0x00003ffe,0x0000c70b
+	.long	0xd54ce602,0xee140000,0x00003ffe,0x0000cd00
+	.long	0x0549adec,0x71590000,0x00003ffe,0x0000d484
+	.long	0x57d2d8ea,0x4ea30000,0x00003ffe,0x0000db94
+	.long	0x8da712de,0xce3b0000,0x00003ffe,0x0000e238
+	.long	0x55f969e8,0x096a0000,0x00003ffe,0x0000e877
+	.long	0x1129c435,0x32590000,0x00003ffe,0x0000ee57
+	.long	0xc16e0d37,0x9c0d0000,0x00003ffe,0x0000f3e1
+	.long	0x0211a87c,0x37790000,0x00003ffe,0x0000f919
+	.long	0x039d758b,0x8d410000,0x00003ffe,0x0000fe05
+	.long	0x8b8f6493,0x5fb30000,0x00003fff,0x00008155
+	.long	0xfb497b68,0x5d040000,0x00003fff,0x00008388
+	.long	0x9e3549d1,0x08e10000,0x00003fff,0x0000859c
+	.long	0xfa76511d,0x724b0000,0x00003fff,0x00008795
+	.long	0x2ecfff81,0x31e70000,0x00003fff,0x00008973
+	.long	0x2fd19557,0x641b0000,0x00003fff,0x00008b38
+	.long	0xcad10193,0x2a350000,0x00003fff,0x00008ce7
+	.long	0xa8d8301e,0xe6b50000,0x00003fff,0x00008f46
+	.long	0xa39e2eae,0x52810000,0x00003fff,0x0000922d
+	.long	0xa7d79188,0x84870000,0x00003fff,0x000094d1
+	.long	0x9fcbdedf,0x52410000,0x00003fff,0x0000973a
+	.long	0xb94419d2,0xa08b0000,0x00003fff,0x0000996f
+	.long	0xf00e08e1,0x0b960000,0x00003fff,0x00009b77
+	.long	0x3f951232,0x1da70000,0x00003fff,0x00009d55
+	.long	0xcc320f93,0x56240000,0x00003fff,0x00009f10
+	.long	0x0575006c,0xc5710000,0x00003fff,0x0000a0a9
+	.long	0xc290d97c,0xc06c0000,0x00003fff,0x0000a226
+	.long	0x59ebebc0,0x630a0000,0x00003fff,0x0000a388
+	.long	0xb4aff6ef,0x0ec90000,0x00003fff,0x0000a4d3
+	.long	0x5f1061d2,0x92c40000,0x00003fff,0x0000a608
+	.long	0x95dcfbe3,0x187e0000,0x00003fff,0x0000a72a
+	.long	0x51dc7367,0xbeac0000,0x00003fff,0x0000a83a
+	.long	0x51530956,0x168f0000,0x00003fff,0x0000a93a
+	.long	0x20077539,0x546e0000,0x00003fff,0x0000aa9e
+	.long	0x7245023b,0x26050000,0x00003fff,0x0000ac4c
+	.long	0x84ba6fe4,0xd58f0000,0x00003fff,0x0000adce
+	.long	0x4a4a606b,0x97120000,0x00003fff,0x0000af2a
+	.long	0x2dcd8d26,0x3c9c0000,0x00003fff,0x0000b065
+	.long	0x6f81f222,0x65c70000,0x00003fff,0x0000b184
+	.long	0x65150f71,0x496a0000,0x00003fff,0x0000b28a
+	.long	0xaa156f9a,0xda350000,0x00003fff,0x0000b37b
+	.long	0x44ff3766,0xb8950000,0x00003fff,0x0000b458
+	.long	0xc3dce963,0x04330000,0x00003fff,0x0000b525
+	.long	0x529d5622,0x46bd0000,0x00003fff,0x0000b5e2
+	.long	0xcca95f9d,0x88cc0000,0x00003fff,0x0000b692
+	.long	0xcada7aca,0x1ada0000,0x00003fff,0x0000b736
+	.long	0xaea7a692,0x58380000,0x00003fff,0x0000b7cf
+	.long	0xab287e9f,0x7b360000,0x00003fff,0x0000b85e
+	.long	0xcc66cb21,0x98350000,0x00003fff,0x0000b8e4
+	.long	0xfd5a20a5,0x93da0000,0x00003fff,0x0000b99f
+	.long	0x41f64aff,0x9bb50000,0x00003fff,0x0000ba7f
+	.long	0x1e17842b,0xbe7b0000,0x00003fff,0x0000bb47
+	.long	0x12857637,0xe17d0000,0x00003fff,0x0000bbfa
+	.long	0xbe8a4788,0xdf6f0000,0x00003fff,0x0000bc9d
+	.long	0x0fad2b68,0x9d790000,0x00003fff,0x0000bd30
+	.long	0x6a39471e,0xcd860000,0x00003fff,0x0000bdb6
+	.long	0xc731856a,0xf18a0000,0x00003fff,0x0000be31
+	.long	0xcac502e8,0x0d700000,0x00003fff,0x0000bea2
+	.long	0xd55ce331,0x94e20000,0x00003fff,0x0000bf0b
+	.long	0x10b7c031,0x28f00000,0x00003fff,0x0000bf6b
+	.long	0x7a18dacb,0x778d0000,0x00003fff,0x0000bfc4
+	.long	0xea4663fa,0x18f60000,0x00003fff,0x0000c018
+	.long	0x1bde8b89,0xa4540000,0x00003fff,0x0000c065
+	.long	0xb066cfbf,0x64390000,0x00003fff,0x0000c0ae
+	.long	0x345f5634,0x0ae60000,0x00003fff,0x0000c0f2
+	.long	0x22919cb9,0xe6a70000,0x0000f210,0x48002210
+	.long	0x32280004,0xf22e6800,0xff840281,0x7fffffff
+	.long	0x0c813ffb,0x80006c04,0x600000d0,0x0c814002
+	.long	0xffff6f04,0x6000014c,0x02aef800,0x0000ff88
+	.long	0x00ae0400,0x0000ff88,0x2d7c0000,0x0000ff8c
+	.long	0xf2000080,0xf22e48a3,0xff84f22e,0x4828ff84
+	.long	0xf23c44a2,0x3f800000,0xf2000420,0x2f022401
+	.long	0x02810000,0x78000282,0x7fff0000,0x04823ffb
+	.long	0x0000e282,0xd282ee81,0x43faf780,0xd3c12d59
+	.long	0xff902d59,0xff942d59,0xff98222e,0xff840281
+	.long	0x80000000,0x83aeff90,0x241ff227,0xe004f200
+	.long	0x0080f200,0x04a3f23a,0x5500f6a0,0xf2000522
+	.long	0xf2000523,0xf20000a3,0xf23a5522,0xf696f23a
+	.long	0x54a3f698,0xf20008a3,0xf2000422,0xf21fd020
+	.long	0xf2009000,0xf22e4822,0xff9060ff,0x00002d30
+	.long	0x0c813fff,0x80006e00,0x008a0c81,0x3fd78000
+	.long	0x6d00006c,0xf227e00c,0xf2000023,0xf2000080
+	.long	0xf20004a3,0xf23a5500,0xf65af23a,0x5580f65c
+	.long	0xf2000523,0xf20005a3,0xf23a5522,0xf656f23a
+	.long	0x55a2f658,0xf2000523,0xf2000ca3,0xf23a5522
+	.long	0xf652f23a,0x54a2f654,0xf2000123,0xf22e4823
+	.long	0xff84f200,0x08a2f200,0x0423f21f,0xd030f200
+	.long	0x9000f22e,0x4822ff84,0x60ff0000,0x2cb2f200
+	.long	0x9000123c,0x0003f22e,0x4800ff84,0x60ff0000
+	.long	0x2c900c81,0x40638000,0x6e00008e,0xf227e00c
+	.long	0xf23c4480,0xbf800000,0xf20000a0,0xf2000400
+	.long	0xf2000023,0xf22e6880,0xff84f200,0x0080f200
+	.long	0x04a3f23a,0x5580f5ec,0xf23a5500,0xf5eef200
+	.long	0x05a3f200,0x0523f23a,0x55a2f5e8,0xf23a5522
+	.long	0xf5eaf200,0x0ca3f200,0x0123f23a,0x54a2f5e4
+	.long	0xf22e4823,0xff84f200,0x08a2f200,0x0423f22e
+	.long	0x4822ff84,0xf21fd030,0xf2009000,0x4a106a0c
+	.long	0xf23a4822,0xf5d660ff,0x00002c24,0xf23a4822
+	.long	0xf5ba60ff,0x00002c10,0x4a106a16,0xf23a4800
+	.long	0xf5baf200,0x9000f23a,0x4822f5c0,0x60ff0000
+	.long	0x2bfef23a,0x4800f594,0xf2009000,0xf23a4822
+	.long	0xf5ba60ff,0x00002be0,0x60ff0000,0x2a66f210
+	.long	0x48002210,0x32280004,0x02817fff,0xffff0c81
+	.long	0x3fff8000,0x6c4e0c81,0x3fd78000,0x6d00007c
+	.long	0xf23c4480,0x3f800000,0xf20000a8,0xf227e004
+	.long	0xf23c4500,0x3f800000,0xf2000122,0xf20008a3
+	.long	0xf21fd020,0xf2000484,0xf2000420,0xf227e001
+	.long	0x41d761ff,0xfffffd66,0xdffc0000,0x000c60ff
+	.long	0x00002b6c,0xf2000018,0xf23c4438,0x3f800000
+	.long	0xf2d20000,0x29d4f23a,0x4800c5a6,0x22100281
+	.long	0x80000000,0x00813f80,0x00002f01,0xf2009000
+	.long	0xf21f4423,0x60ff0000,0x2b36f200,0x9000123c
+	.long	0x0003f210,0x480060ff,0x00002b16,0x60ff0000
+	.long	0x29b2f210,0x48002210,0x32280004,0x02817fff
+	.long	0xffff0c81,0x3fff8000,0x6c44f23c,0x44803f80
+	.long	0x0000f200,0x00a2f200,0x001af23c,0x44223f80
+	.long	0x0000f200,0x0420f200,0x00042f00,0x4280f227
+	.long	0xe00141d7,0x61ffffff,0xfcc4dffc,0x0000000c
+	.long	0xf21f9000,0xf2000022,0x60ff0000,0x2acaf200
+	.long	0x0018f23c,0x44383f80,0x0000f2d2,0x0000292a
+	.long	0x4a106a18,0xf23a4800,0xc4e8f200,0x9000f23c
+	.long	0x44220080,0x000060ff,0x00002a9c,0x60ff0000
+	.long	0x2ce8f200,0x9000f23a,0x4800c4d6,0x60ff0000
+	.long	0x2a863fdc,0x000082e3,0x08654361,0xc4c60000
+	.long	0x00003fa5,0x55555555,0x4cc13fc5,0x55555555
+	.long	0x4a543f81,0x11111117,0x43853fa5,0x55555555
+	.long	0x4f5a3fc5,0x55555555,0x55550000,0x00000000
+	.long	0x00003ec7,0x1de3a577,0x46823efa,0x01a019d7
+	.long	0xcb683f2a,0x01a01a01,0x9df33f56,0xc16c16c1
+	.long	0x70e23f81,0x11111111,0x11113fa5,0x55555555
+	.long	0x55553ffc,0x0000aaaa,0xaaaaaaaa,0xaaab0000
+	.long	0x000048b0,0x00000000,0x00003730,0x00000000
+	.long	0x00003fff,0x00008000,0x00000000,0x00000000
+	.long	0x00003fff,0x00008164,0xd1f3bc03,0x07749f84
+	.long	0x1a9b3fff,0x000082cd,0x8698ac2b,0xa1d89fc1
+	.long	0xd5b93fff,0x0000843a,0x28c3acde,0x4048a072
+	.long	0x83693fff,0x000085aa,0xc367cc48,0x7b141fc5
+	.long	0xc95c3fff,0x0000871f,0x61969e8d,0x10101ee8
+	.long	0x5c9f3fff,0x00008898,0x0e8092da,0x85289fa2
+	.long	0x07293fff,0x00008a14,0xd575496e,0xfd9ca07b
+	.long	0xf9af3fff,0x00008b95,0xc1e3ea8b,0xd6e8a002
+	.long	0x0dcf3fff,0x00008d1a,0xdf5b7e5b,0xa9e4205a
+	.long	0x63da3fff,0x00008ea4,0x398b45cd,0x53c01eb7
+	.long	0x00513fff,0x00009031,0xdc431466,0xb1dc1f6e
+	.long	0xb0293fff,0x000091c3,0xd373ab11,0xc338a078
+	.long	0x14943fff,0x0000935a,0x2b2f13e6,0xe92c9eb3
+	.long	0x19b03fff,0x000094f4,0xefa8fef7,0x09602017
+	.long	0x457d3fff,0x00009694,0x2d372018,0x5a001f11
+	.long	0xd5373fff,0x00009837,0xf0518db8,0xa9709fb9
+	.long	0x52dd3fff,0x000099e0,0x459320b7,0xfa641fe4
+	.long	0x30873fff,0x00009b8d,0x39b9d54e,0x55381fa2
+	.long	0xa8183fff,0x00009d3e,0xd9a72cff,0xb7501fde
+	.long	0x494d3fff,0x00009ef5,0x326091a1,0x11ac2050
+	.long	0x48903fff,0x0000a0b0,0x510fb971,0x4fc4a073
+	.long	0x691c3fff,0x0000a270,0x43030c49,0x68181f9b
+	.long	0x7a053fff,0x0000a435,0x15ae09e6,0x80a0a079
+	.long	0x71263fff,0x0000a5fe,0xd6a9b151,0x38eca071
+	.long	0xa1403fff,0x0000a7cd,0x93b4e965,0x3568204f
+	.long	0x62da3fff,0x0000a9a1,0x5ab4ea7c,0x0ef81f28
+	.long	0x3c4a3fff,0x0000ab7a,0x39b5a93e,0xd3389f9a
+	.long	0x7fdc3fff,0x0000ad58,0x3eea42a1,0x4ac8a05b
+	.long	0x3fac3fff,0x0000af3b,0x78ad690a,0x43741fdf
+	.long	0x26103fff,0x0000b123,0xf581d2ac,0x25909f70
+	.long	0x5f903fff,0x0000b311,0xc412a911,0x2488201f
+	.long	0x678a3fff,0x0000b504,0xf333f9de,0x64841f32
+	.long	0xfb133fff,0x0000b6fd,0x91e328d1,0x77902003
+	.long	0x8b303fff,0x0000b8fb,0xaf4762fb,0x9ee8200d
+	.long	0xc3cc3fff,0x0000baff,0x5ab2133e,0x45fc9f8b
+	.long	0x2ae63fff,0x0000bd08,0xa39f580c,0x36c0a02b
+	.long	0xbf703fff,0x0000bf17,0x99b67a73,0x1084a00b
+	.long	0xf5183fff,0x0000c12c,0x4cca6670,0x9458a041
+	.long	0xdd413fff,0x0000c346,0xccda2497,0x64089fdf
+	.long	0x137b3fff,0x0000c567,0x2a115506,0xdadc201f
+	.long	0x15683fff,0x0000c78d,0x74c8abb9,0xb15c1fc1
+	.long	0x3a2e3fff,0x0000c9b9,0xbd866e2f,0x27a4a03f
+	.long	0x8f033fff,0x0000cbec,0x14fef272,0x7c5c1ff4
+	.long	0x907d3fff,0x0000ce24,0x8c151f84,0x80e49e6e
+	.long	0x53e43fff,0x0000d063,0x33daef2b,0x25941fd6
+	.long	0xd45c3fff,0x0000d2a8,0x1d91f12a,0xe45ca076
+	.long	0xedb93fff,0x0000d4f3,0x5aabcfed,0xfa209fa6
+	.long	0xde213fff,0x0000d744,0xfccad69d,0x6af41ee6
+	.long	0x9a2f3fff,0x0000d99d,0x15c278af,0xd7b4207f
+	.long	0x439f3fff,0x0000dbfb,0xb797daf2,0x3754201e
+	.long	0xc2073fff,0x0000de60,0xf4825e0e,0x91249e8b
+	.long	0xe1753fff,0x0000e0cc,0xdeec2a94,0xe1102003
+	.long	0x2c4b3fff,0x0000e33f,0x8972be8a,0x5a502004
+	.long	0xdff53fff,0x0000e5b9,0x06e77c83,0x48a81e72
+	.long	0xf47a3fff,0x0000e839,0x6a503c4b,0xdc681f72
+	.long	0x2f223fff,0x0000eac0,0xc6e7dd24,0x3930a017
+	.long	0xe9453fff,0x0000ed4f,0x301ed994,0x2b841f40
+	.long	0x1a5b3fff,0x0000efe4,0xb99bdcda,0xf5cc9fb9
+	.long	0xa9e33fff,0x0000f281,0x773c59ff,0xb1382074
+	.long	0x4c053fff,0x0000f525,0x7d152486,0xcc2c1f77
+	.long	0x3a193fff,0x0000f7d0,0xdf730ad1,0x3bb81ffe
+	.long	0x90d53fff,0x0000fa83,0xb2db722a,0x033ca041
+	.long	0xed223fff,0x0000fd3e,0x0c0cf486,0xc1741f85
+	.long	0x3f3a2210,0x02817fff,0x00000c81,0x3fbe0000
+	.long	0x6c0660ff,0x00000108,0x32280004,0x0c81400c
+	.long	0xb1676d06,0x60ff0000,0x010cf210,0x4800f200
+	.long	0x0080f23c,0x442342b8,0xaa3bf227,0xe00c2d7c
+	.long	0x00000000,0xff58f201,0x600043fa,0xfbb6f201
+	.long	0x40002d41,0xff540281,0x0000003f,0xe989d3c1
+	.long	0x222eff54,0xec810641,0x3fff3d7a,0xfb06ff54
+	.long	0xf2000100,0xf23c4423,0xbc317218,0xf23a4923
+	.long	0xfaf2f200,0x0422f200,0x0822f200,0x0080f200
+	.long	0x04a3f23c,0x45003ab6,0x0b70f200,0x0523f200
+	.long	0x0580f23c,0x45a33c08,0x8895f23a,0x5522fad4
+	.long	0xf23a55a2,0xfad6f200,0x05233d41,0xff842d7c
+	.long	0x80000000,0xff8842ae,0xff8cf200,0x05a3f23c
+	.long	0x45223f00,0x0000f200,0x01a3f200,0x0523f200
+	.long	0x0c22f219,0x4880f200,0x0822f200,0x0423f21f
+	.long	0xd030f211,0x4422f200,0x0422222e,0xff584a81
+	.long	0x6706f22e,0x4823ff90,0xf2009000,0x123c0000
+	.long	0xf22e4823,0xff8460ff,0x000024c6,0xf210d080
+	.long	0xf2009000,0xf23c4422,0x3f800000,0x60ff0000
+	.long	0x24c60c81,0x400cb27c,0x6e66f210,0x4800f200
+	.long	0x0080f23c,0x442342b8,0xaa3bf227,0xe00c2d7c
+	.long	0x00000001,0xff58f201,0x600043fa,0xfaa6f201
+	.long	0x40002d41,0xff540281,0x0000003f,0xe989d3c1
+	.long	0x222eff54,0xec812d41,0xff54e281,0x93aeff54
+	.long	0x06413fff,0x3d41ff90,0x2d7c8000,0x0000ff94
+	.long	0x42aeff98,0x222eff54,0x06413fff,0x6000fed2
+	.long	0x4a106bff,0x00002370,0x60ff0000,0x24122f10
+	.long	0x02978000,0x00000097,0x00800000,0xf23c4400
+	.long	0x3f800000,0xf2009000,0xf21f4422,0x60ff0000
+	.long	0x24262210,0x02817fff,0x00000c81,0x3ffd0000
+	.long	0x6c0660ff,0x0000015e,0x32280004,0x0c814004
+	.long	0xc2156f06,0x60ff0000,0x026cf210,0x4800f200
+	.long	0x0080f23c,0x442342b8,0xaa3bf227,0xe00cf201
+	.long	0x600043fa,0xf9eef201,0x40002d41,0xff540281
+	.long	0x0000003f,0xe989d3c1,0x222eff54,0xec812d41
+	.long	0xff54f200,0x0100f23c,0x4423bc31,0x7218f23a
+	.long	0x4923f930,0xf2000422,0xf2000822,0x06413fff
+	.long	0xf2000080,0xf20004a3,0xf23c4500,0x3950097b
+	.long	0xf2000523,0xf2000580,0xf23c45a3,0x3ab60b6a
+	.long	0xf23a5522,0xf91ef23a,0x55a2f920,0x3d41ff84
+	.long	0x2d7c8000,0x0000ff88,0x42aeff8c,0xf2000523
+	.long	0x222eff54,0x4441f200,0x05a30641,0x3ffff23a
+	.long	0x5522f900,0xf23c45a2,0x3f000000,0xf2000523
+	.long	0x00418000,0x3d41ff90,0x2d7c8000,0x0000ff94
+	.long	0x42aeff98,0xf2000ca3,0xf2000123,0xf2000422
+	.long	0xf2000822,0xf21fd030,0xf2114823,0x222eff54
+	.long	0x0c810000,0x003f6f1a,0xf2294480,0x000cf22e
+	.long	0x48a2ff90,0xf2000422,0xf2114822,0x60ff0000
+	.long	0x00340c81,0xfffffffd,0x6c16f229,0x4422000c
+	.long	0xf2114822,0xf22e4822,0xff9060ff,0x00000016
+	.long	0xf2194880,0xf2114422,0xf22e48a2,0xff90f200
+	.long	0x0422f200,0x9000f22e,0x4823ff84,0x60ff0000
+	.long	0x22ae0c81,0x3fbe0000,0x6c6c0c81,0x00330000
+	.long	0x6d2c2d7c,0x80010000,0xff842d7c,0x80000000
+	.long	0xff8842ae,0xff8cf210,0x4800f200,0x9000123c
+	.long	0x0002f22e,0x4822ff84,0x60ff0000,0x2264f210
+	.long	0x4800f23a,0x5423f86c,0x2d7c8001,0x0000ff84
+	.long	0x2d7c8000,0x0000ff88,0x42aeff8c,0xf22e4822
+	.long	0xff84f200,0x9000123c,0x0000f23a,0x5423f84c
+	.long	0x60ff0000,0x222cf210,0x4800f200,0x0023f227
+	.long	0xe00cf23c,0x44802f30,0xcaa8f200,0x00a3f23c
+	.long	0x4500310f,0x8290f23c,0x44a232d7,0x3220f200
+	.long	0x0123f200,0x00a3f23c,0x45223493,0xf281f23a
+	.long	0x54a2f7c0,0xf2000123,0xf20000a3,0xf23a5522
+	.long	0xf7baf23a,0x54a2f7bc,0xf2000123,0xf20000a3
+	.long	0xf23a5522,0xf7b6f23a,0x54a2f7b8,0xf2000123
+	.long	0xf20000a3,0xf23a5522,0xf7b2f23a,0x48a2f7b4
+	.long	0xf2000123,0xf20000a3,0xf2000123,0xf21048a3
+	.long	0xf23c4423,0x3f000000,0xf20008a2,0xf21fd030
+	.long	0xf2000422,0xf2009000,0xf2104822,0x60ff0000
+	.long	0x218e2210,0x0c810000,0x00006e00,0xfbacf23c
+	.long	0x4400bf80,0x0000f200,0x9000f23c,0x44220080
+	.long	0x000060ff,0x00002178,0x60ff0000,0x1ff63028
+	.long	0x00000880,0x000f0440,0x3ffff200,0x50006d02
+	.long	0x4e751d7c,0x0008ff64,0x4e7561ff,0x00007cfc
+	.long	0x44400440,0x3ffff200,0x50001d7c,0x0008ff64
+	.long	0x4e753028,0x00000040,0x7fff0880,0x000e2d68
+	.long	0x0004ff88,0x2d680008,0xff8c3d40,0xff84f22e
+	.long	0x4800ff84,0x6b024e75,0x1d7c0008,0xff644e75
+	.long	0x61ff0000,0x7cb660ca,0x7ffb0000,0x80000000
+	.long	0x00000000,0x00000000,0xf2104800,0x22103228
+	.long	0x00040281,0x7fffffff,0x0c81400c,0xb1676e42
+	.long	0xf2000018,0x2f004280,0xf227e001,0x41d761ff
+	.long	0xfffffad2,0xdffc0000,0x000cf23c,0x44233f00
+	.long	0x0000201f,0xf23c4480,0x3e800000,0xf20000a0
+	.long	0xf2009000,0x123c0002,0xf2000422,0x60ff0000
+	.long	0x20800c81,0x400cb2b3,0x6e3cf200,0x0018f23a
+	.long	0x5428baae,0xf23a5428,0xbab02f00,0x4280f227
+	.long	0xe00141d7,0x61ffffff,0xfa7cdffc,0x0000000c
+	.long	0x201ff200,0x9000123c,0x0000f23a,0x4823ff5a
+	.long	0x60ff0000,0x203c60ff,0x00002014,0xf23c4400
+	.long	0x3f800000,0xf2009000,0xf23c4422,0x00800000
+	.long	0x60ff0000,0x2032f210,0x48002210,0x32280004
+	.long	0x22410281,0x7fffffff,0x0c81400c,0xb1676e62
+	.long	0xf2000018,0x48e78040,0xf227e001,0x41d74280
+	.long	0x61ffffff,0xfbe0dffc,0x0000000c,0xf23c9000
+	.long	0x00000000,0x4cdf0201,0xf2000080,0xf23c44a2
+	.long	0x3f800000,0xf2276800,0xf2000420,0x22090281
+	.long	0x80000000,0x00813f00,0x0000f21f,0x48222f01
+	.long	0xf2009000,0x123c0000,0xf21f4423,0x60ff0000
+	.long	0x1fa00c81,0x400cb2b3,0x6eff0000,0x1f4cf200
+	.long	0x0018f23a,0x5428b9ca,0x2f3c0000,0x00002f3c
+	.long	0x80000000,0x22090281,0x80000000,0x00817ffb
+	.long	0x00002f01,0xf23a5428,0xb9b02f00,0x4280f227
+	.long	0xe00141d7,0x61ffffff,0xf97cdffc,0x0000000c
+	.long	0x201ff200,0x9000123c,0x0000f21f,0x482360ff
+	.long	0x00001f3e,0x60ff0000,0x1ddaf210,0x4800f22e
+	.long	0x6800ff84,0x22103228,0x00042d41,0xff840281
+	.long	0x7fffffff,0x0c813fd7,0x80006d00,0x00740c81
+	.long	0x3fffddce,0x6e00006a,0x222eff84,0x2d41ff5c
+	.long	0x02817fff,0x00000681,0x00010000,0x2d41ff84
+	.long	0x02ae8000,0x0000ff5c,0xf22e4800,0xff842f00
+	.long	0x4280f227,0xe00141d7,0x61ffffff,0xfac8dffc
+	.long	0x0000000c,0x201ff200,0x0080f23c,0x44a24000
+	.long	0x0000222e,0xff5cf22e,0x6880ff84,0xb3aeff84
+	.long	0xf2009000,0xf22e4820,0xff8460ff,0x00001eb0
+	.long	0x0c813fff,0x80006d00,0x00880c81,0x40048aa1
+	.long	0x6e000092,0x222eff84,0x2d41ff5c,0x02817fff
+	.long	0x00000681,0x00010000,0x2d41ff84,0x02ae8000
+	.long	0x0000ff5c,0x222eff5c,0xf22e4800,0xff842f00
+	.long	0x4280f227,0xe00141d7,0x61ffffff,0xf878dffc
+	.long	0x0000000c,0x201f222e,0xff5cf23c,0x44223f80
+	.long	0x00000a81,0xc0000000,0xf2014480,0xf20000a0
+	.long	0x222eff5c,0x00813f80,0x0000f201,0x4400f200
+	.long	0x9000123c,0x0002f200,0x042260ff,0x00001e20
+	.long	0xf2009000,0x123c0003,0xf22e4800,0xff8460ff
+	.long	0x00001dfe,0x222eff84,0x02818000,0x00000081
+	.long	0x3f800000,0xf2014400,0x02818000,0x00000a81
+	.long	0x80800000,0xf2009000,0xf2014422,0x60ff0000
+	.long	0x1dde60ff,0x00001c6c,0x3ffe0000,0xb17217f7
+	.long	0xd1cf79ac,0x00000000,0x3f800000,0x00000000
+	.long	0x7f800000,0xbf800000,0x3fc2499a,0xb5e4040b
+	.long	0xbfc555b5,0x848cb7db,0x3fc99999,0x987d8730
+	.long	0xbfcfffff,0xff6f7e97,0x3fd55555,0x555555a4
+	.long	0xbfe00000,0x00000008,0x3f175496,0xadd7dad6
+	.long	0x3f3c71c2,0xfe80c7e0,0x3f624924,0x928bccff
+	.long	0x3f899999,0x999995ec,0x3fb55555,0x55555555
+	.long	0x40000000,0x00000000,0x3f990000,0x80000000
+	.long	0x00000000,0x00000000,0x3ffe0000,0xfe03f80f
+	.long	0xe03f80fe,0x00000000,0x3ff70000,0xff015358
+	.long	0x833c47e2,0x00000000,0x3ffe0000,0xfa232cf2
+	.long	0x52138ac0,0x00000000,0x3ff90000,0xbdc8d83e
+	.long	0xad88d549,0x00000000,0x3ffe0000,0xf6603d98
+	.long	0x0f6603da,0x00000000,0x3ffa0000,0x9cf43dcf
+	.long	0xf5eafd48,0x00000000,0x3ffe0000,0xf2b9d648
+	.long	0x0f2b9d65,0x00000000,0x3ffa0000,0xda16eb88
+	.long	0xcb8df614,0x00000000,0x3ffe0000,0xef2eb71f
+	.long	0xc4345238,0x00000000,0x3ffb0000,0x8b29b775
+	.long	0x1bd70743,0x00000000,0x3ffe0000,0xebbdb2a5
+	.long	0xc1619c8c,0x00000000,0x3ffb0000,0xa8d839f8
+	.long	0x30c1fb49,0x00000000,0x3ffe0000,0xe865ac7b
+	.long	0x7603a197,0x00000000,0x3ffb0000,0xc61a2eb1
+	.long	0x8cd907ad,0x00000000,0x3ffe0000,0xe525982a
+	.long	0xf70c880e,0x00000000,0x3ffb0000,0xe2f2a47a
+	.long	0xde3a18af,0x00000000,0x3ffe0000,0xe1fc780e
+	.long	0x1fc780e2,0x00000000,0x3ffb0000,0xff64898e
+	.long	0xdf55d551,0x00000000,0x3ffe0000,0xdee95c4c
+	.long	0xa037ba57,0x00000000,0x3ffc0000,0x8db956a9
+	.long	0x7b3d0148,0x00000000,0x3ffe0000,0xdbeb61ee
+	.long	0xd19c5958,0x00000000,0x3ffc0000,0x9b8fe100
+	.long	0xf47ba1de,0x00000000,0x3ffe0000,0xd901b203
+	.long	0x6406c80e,0x00000000,0x3ffc0000,0xa9372f1d
+	.long	0x0da1bd17,0x00000000,0x3ffe0000,0xd62b80d6
+	.long	0x2b80d62c,0x00000000,0x3ffc0000,0xb6b07f38
+	.long	0xce90e46b,0x00000000,0x3ffe0000,0xd3680d36
+	.long	0x80d3680d,0x00000000,0x3ffc0000,0xc3fd0329
+	.long	0x06488481,0x00000000,0x3ffe0000,0xd0b69fcb
+	.long	0xd2580d0b,0x00000000,0x3ffc0000,0xd11de0ff
+	.long	0x15ab18ca,0x00000000,0x3ffe0000,0xce168a77
+	.long	0x25080ce1,0x00000000,0x3ffc0000,0xde1433a1
+	.long	0x6c66b150,0x00000000,0x3ffe0000,0xcb8727c0
+	.long	0x65c393e0,0x00000000,0x3ffc0000,0xeae10b5a
+	.long	0x7ddc8add,0x00000000,0x3ffe0000,0xc907da4e
+	.long	0x871146ad,0x00000000,0x3ffc0000,0xf7856e5e
+	.long	0xe2c9b291,0x00000000,0x3ffe0000,0xc6980c69
+	.long	0x80c6980c,0x00000000,0x3ffd0000,0x82012ca5
+	.long	0xa68206d7,0x00000000,0x3ffe0000,0xc4372f85
+	.long	0x5d824ca6,0x00000000,0x3ffd0000,0x882c5fcd
+	.long	0x7256a8c5,0x00000000,0x3ffe0000,0xc1e4bbd5
+	.long	0x95f6e947,0x00000000,0x3ffd0000,0x8e44c60b
+	.long	0x4ccfd7de,0x00000000,0x3ffe0000,0xbfa02fe8
+	.long	0x0bfa02ff,0x00000000,0x3ffd0000,0x944ad09e
+	.long	0xf4351af6,0x00000000,0x3ffe0000,0xbd691047
+	.long	0x07661aa3,0x00000000,0x3ffd0000,0x9a3eecd4
+	.long	0xc3eaa6b2,0x00000000,0x3ffe0000,0xbb3ee721
+	.long	0xa54d880c,0x00000000,0x3ffd0000,0xa0218434
+	.long	0x353f1de8,0x00000000,0x3ffe0000,0xb92143fa
+	.long	0x36f5e02e,0x00000000,0x3ffd0000,0xa5f2fcab
+	.long	0xbbc506da,0x00000000,0x3ffe0000,0xb70fbb5a
+	.long	0x19be3659,0x00000000,0x3ffd0000,0xabb3b8ba
+	.long	0x2ad362a5,0x00000000,0x3ffe0000,0xb509e68a
+	.long	0x9b94821f,0x00000000,0x3ffd0000,0xb1641795
+	.long	0xce3ca97b,0x00000000,0x3ffe0000,0xb30f6352
+	.long	0x8917c80b,0x00000000,0x3ffd0000,0xb7047551
+	.long	0x5d0f1c61,0x00000000,0x3ffe0000,0xb11fd3b8
+	.long	0x0b11fd3c,0x00000000,0x3ffd0000,0xbc952afe
+	.long	0xea3d13e1,0x00000000,0x3ffe0000,0xaf3addc6
+	.long	0x80af3ade,0x00000000,0x3ffd0000,0xc2168ed0
+	.long	0xf458ba4a,0x00000000,0x3ffe0000,0xad602b58
+	.long	0x0ad602b6,0x00000000,0x3ffd0000,0xc788f439
+	.long	0xb3163bf1,0x00000000,0x3ffe0000,0xab8f69e2
+	.long	0x8359cd11,0x00000000,0x3ffd0000,0xccecac08
+	.long	0xbf04565d,0x00000000,0x3ffe0000,0xa9c84a47
+	.long	0xa07f5638,0x00000000,0x3ffd0000,0xd2420487
+	.long	0x2dd85160,0x00000000,0x3ffe0000,0xa80a80a8
+	.long	0x0a80a80b,0x00000000,0x3ffd0000,0xd7894992
+	.long	0x3bc3588a,0x00000000,0x3ffe0000,0xa655c439
+	.long	0x2d7b73a8,0x00000000,0x3ffd0000,0xdcc2c4b4
+	.long	0x9887dacc,0x00000000,0x3ffe0000,0xa4a9cf1d
+	.long	0x96833751,0x00000000,0x3ffd0000,0xe1eebd3e
+	.long	0x6d6a6b9e,0x00000000,0x3ffe0000,0xa3065e3f
+	.long	0xae7cd0e0,0x00000000,0x3ffd0000,0xe70d785c
+	.long	0x2f9f5bdc,0x00000000,0x3ffe0000,0xa16b312e
+	.long	0xa8fc377d,0x00000000,0x3ffd0000,0xec1f392c
+	.long	0x5179f283,0x00000000,0x3ffe0000,0x9fd809fd
+	.long	0x809fd80a,0x00000000,0x3ffd0000,0xf12440d3
+	.long	0xe36130e6,0x00000000,0x3ffe0000,0x9e4cad23
+	.long	0xdd5f3a20,0x00000000,0x3ffd0000,0xf61cce92
+	.long	0x346600bb,0x00000000,0x3ffe0000,0x9cc8e160
+	.long	0xc3fb19b9,0x00000000,0x3ffd0000,0xfb091fd3
+	.long	0x8145630a,0x00000000,0x3ffe0000,0x9b4c6f9e
+	.long	0xf03a3caa,0x00000000,0x3ffd0000,0xffe97042
+	.long	0xbfa4c2ad,0x00000000,0x3ffe0000,0x99d722da
+	.long	0xbde58f06,0x00000000,0x3ffe0000,0x825efced
+	.long	0x49369330,0x00000000,0x3ffe0000,0x9868c809
+	.long	0x868c8098,0x00000000,0x3ffe0000,0x84c37a7a
+	.long	0xb9a905c9,0x00000000,0x3ffe0000,0x97012e02
+	.long	0x5c04b809,0x00000000,0x3ffe0000,0x87224c2e
+	.long	0x8e645fb7,0x00000000,0x3ffe0000,0x95a02568
+	.long	0x095a0257,0x00000000,0x3ffe0000,0x897b8cac
+	.long	0x9f7de298,0x00000000,0x3ffe0000,0x94458094
+	.long	0x45809446,0x00000000,0x3ffe0000,0x8bcf55de
+	.long	0xc4cd05fe,0x00000000,0x3ffe0000,0x92f11384
+	.long	0x0497889c,0x00000000,0x3ffe0000,0x8e1dc0fb
+	.long	0x89e125e5,0x00000000,0x3ffe0000,0x91a2b3c4
+	.long	0xd5e6f809,0x00000000,0x3ffe0000,0x9066e68c
+	.long	0x955b6c9b,0x00000000,0x3ffe0000,0x905a3863
+	.long	0x3e06c43b,0x00000000,0x3ffe0000,0x92aade74
+	.long	0xc7be59e0,0x00000000,0x3ffe0000,0x8f1779d9
+	.long	0xfdc3a219,0x00000000,0x3ffe0000,0x94e9bff6
+	.long	0x15845643,0x00000000,0x3ffe0000,0x8dda5202
+	.long	0x37694809,0x00000000,0x3ffe0000,0x9723a1b7
+	.long	0x20134203,0x00000000,0x3ffe0000,0x8ca29c04
+	.long	0x6514e023,0x00000000,0x3ffe0000,0x995899c8
+	.long	0x90eb8990,0x00000000,0x3ffe0000,0x8b70344a
+	.long	0x139bc75a,0x00000000,0x3ffe0000,0x9b88bdaa
+	.long	0x3a3dae2f,0x00000000,0x3ffe0000,0x8a42f870
+	.long	0x5669db46,0x00000000,0x3ffe0000,0x9db4224f
+	.long	0xffe1157c,0x00000000,0x3ffe0000,0x891ac73a
+	.long	0xe9819b50,0x00000000,0x3ffe0000,0x9fdadc26
+	.long	0x8b7a12da,0x00000000,0x3ffe0000,0x87f78087
+	.long	0xf78087f8,0x00000000,0x3ffe0000,0xa1fcff17
+	.long	0xce733bd4,0x00000000,0x3ffe0000,0x86d90544
+	.long	0x7a34acc6,0x00000000,0x3ffe0000,0xa41a9e8f
+	.long	0x5446fb9f,0x00000000,0x3ffe0000,0x85bf3761
+	.long	0x2cee3c9b,0x00000000,0x3ffe0000,0xa633cd7e
+	.long	0x6771cd8b,0x00000000,0x3ffe0000,0x84a9f9c8
+	.long	0x084a9f9d,0x00000000,0x3ffe0000,0xa8489e60
+	.long	0x0b435a5e,0x00000000,0x3ffe0000,0x83993052
+	.long	0x3fbe3368,0x00000000,0x3ffe0000,0xaa59233c
+	.long	0xcca4bd49,0x00000000,0x3ffe0000,0x828cbfbe
+	.long	0xb9a020a3,0x00000000,0x3ffe0000,0xac656dae
+	.long	0x6bcc4985,0x00000000,0x3ffe0000,0x81848da8
+	.long	0xfaf0d277,0x00000000,0x3ffe0000,0xae6d8ee3
+	.long	0x60bb2468,0x00000000,0x3ffe0000,0x80808080
+	.long	0x80808081,0x00000000,0x3ffe0000,0xb07197a2
+	.long	0x3c46c654,0x00000000,0xf2104800,0x2d7c0000
+	.long	0x0000ff54,0x22103228,0x00042d50,0xff842d68
+	.long	0x0004ff88,0x2d680008,0xff8c0c81,0x00000000
+	.long	0x6d000182,0x0c813ffe,0xf07d6d0a,0x0c813fff
+	.long	0x88416f00,0x00e2e081,0xe0810481,0x00003fff
+	.long	0xd2aeff54,0x41faf7b2,0xf2014080,0x2d7c3fff
+	.long	0x0000ff84,0x2d6eff88,0xff9402ae,0xfe000000
+	.long	0xff9400ae,0x01000000,0xff94222e,0xff940281
+	.long	0x7e000000,0xe081e081,0xe881d1c1,0xf22e4800
+	.long	0xff842d7c,0x3fff0000,0xff9042ae,0xff98f22e
+	.long	0x4828ff90,0xf227e00c,0xf2104823,0xf23a48a3
+	.long	0xf6c8f200,0x0100f200,0x0923f22e,0x6880ff84
+	.long	0xf2000980,0xf2000880,0xf23a54a3,0xf6ccf23a
+	.long	0x5523f6ce,0xf23a54a2,0xf6d0f23a,0x5522f6d2
+	.long	0xf2000ca3,0xf2000d23,0xf23a54a2,0xf6ccf23a
+	.long	0x5522f6ce,0xf2000ca3,0xd1fc0000,0x0010f200
+	.long	0x0d23f200,0x00a3f200,0x0822f210,0x48a2f21f
+	.long	0xd030f200,0x0422f200,0x9000f22e,0x4822ff84
+	.long	0x60ff0000,0x142af23c,0x58380001,0xf2c10000
+	.long	0x1678f200,0x0080f23a,0x44a8f64e,0xf23a4422
+	.long	0xf648f200,0x04a2f200,0x00a0f227,0xe00cf200
+	.long	0x0400f200,0x0023f22e,0x6880ff84,0xf2000080
+	.long	0xf20004a3,0xf23a5580,0xf660f23a,0x5500f662
+	.long	0xf20005a3,0xf2000523,0xf23a55a2,0xf65cf23a
+	.long	0x5522f65e,0xf2000ca3,0xf2000123,0xf23a54a2
+	.long	0xf658f22e,0x4823ff84,0xf20008a2,0xf21fd030
+	.long	0xf2000423,0xf2009000,0xf22e4822,0xff8460ff
+	.long	0x0000139c,0x60ff0000,0x12102d7c,0xffffff9c
+	.long	0xff5448e7,0x3f002610,0x28280004,0x2a280008
+	.long	0x42824a84,0x66342805,0x42857420,0x4286edc4
+	.long	0x6000edac,0xd4862d43,0xff842d44,0xff882d45
+	.long	0xff8c4482,0x2d42ff54,0xf22e4800,0xff844cdf
+	.long	0x00fc41ee,0xff846000,0xfe0c4286,0xedc46000
+	.long	0x2406edac,0x2e05edad,0x44860686,0x00000020
+	.long	0xecaf8887,0x2d43ff84,0x2d44ff88,0x2d45ff8c
+	.long	0x44822d42,0xff54f22e,0x4800ff84,0x4cdf00fc
+	.long	0x41eeff84,0x6000fdce,0xf2104800,0xf2000018
+	.long	0xf23a4838,0xf5a4f292,0x0014f200,0x9000123c
+	.long	0x0003f210,0x480060ff,0x000012d6,0xf2104800
+	.long	0x2d7c0000,0x0000ff54,0xf2000080,0xf23a4422
+	.long	0xf508f22e,0x6800ff84,0x3d6eff88,0xff86222e
+	.long	0xff840c81,0x00000000,0x6f0000da,0x0c813ffe
+	.long	0x80006d00,0xfda20c81,0x3fffc000,0x6e00fd98
+	.long	0x0c813ffe,0xf07d6d00,0x001a0c81,0x3fff8841
+	.long	0x6e000010,0xf20004a2,0xf23a4422,0xf4bc6000
+	.long	0xfe762d6e,0xff88ff94,0x02aefe00,0x0000ff94
+	.long	0x00ae0100,0x0000ff94,0x0c813fff,0x80006c44
+	.long	0xf23a4400,0xf4fc2d7c,0x3fff0000,0xff9042ae
+	.long	0xff98f22e,0x4828ff90,0x222eff94,0x02817e00
+	.long	0x0000e081,0xe081e881,0xf20004a2,0xf227e00c
+	.long	0xf2000422,0x41faf4e2,0xd1c1f23a,0x4480f466
+	.long	0x6000fd76,0xf23a4400,0xf4502d7c,0x3fff0000
+	.long	0xff9042ae,0xff98f22e,0x4828ff90,0x222eff94
+	.long	0x02817e00,0x0000e081,0xe081e881,0xf2000422
+	.long	0xf227e00c,0x41faf4a2,0xd1c1f23a,0x4480f41e
+	.long	0x6000fd36,0x0c810000,0x00006d10,0xf23a4400
+	.long	0xf414f200,0x900060ff,0x00001014,0xf23a4400
+	.long	0xf3fcf200,0x900060ff,0x0000102e,0x60ff0000
+	.long	0x10422210,0x32280004,0x02817fff,0xffff0c81
+	.long	0x3fff8000,0x6c56f210,0x4818f200,0x0080f200
+	.long	0x049af200,0x0022f23c,0x44a23f80,0x0000f200
+	.long	0x04202210,0x02818000,0x00000081,0x3f000000
+	.long	0x2f012f00,0x4280f227,0xe00141d7,0x61ffffff
+	.long	0xfe5adffc,0x0000000c,0x201ff200,0x9000123c
+	.long	0x0000f21f,0x442360ff,0x00001136,0xf2104818
+	.long	0xf23c4438,0x3f800000,0xf2d20000,0x0fac60ff
+	.long	0x00000f7c,0x60ff0000,0x0fba3ffd,0x0000de5b
+	.long	0xd8a93728,0x71950000,0x00003fff,0x0000b8aa
+	.long	0x3b295c17,0xf0bc0000,0x0000f23c,0x58000001
+	.long	0xf2104838,0xf2c10000,0x13502210,0x6d000090
+	.long	0x2f004280,0x61ffffff,0xfba2f21f,0x9000f23a
+	.long	0x4823ffb8,0x60ff0000,0x10d62210,0x6d000070
+	.long	0x2f004280,0x61ffffff,0xfd34f21f,0x9000f23a
+	.long	0x4823ff98,0x60ff0000,0x10c62210,0x6d000050
+	.long	0x22280008,0x662e2228,0x00040281,0x7fffffff
+	.long	0x66223210,0x02810000,0x7fff0481,0x00003fff
+	.long	0x67ff0000,0x12e4f200,0x9000f201,0x400060ff
+	.long	0x0000107c,0x2f004280,0x61ffffff,0xfb2ef21f
+	.long	0x9000f23a,0x4823ff54,0x60ff0000,0x106260ff
+	.long	0x00000ed6,0x22106d00,0xfff62f00,0x428061ff
+	.long	0xfffffcba,0xf21f9000,0xf23a4823,0xff2e60ff
+	.long	0x0000104c,0x406a934f,0x0979a371,0x3f734413
+	.long	0x509f8000,0xbfcd0000,0xc0219dc1,0xda994fd2
+	.long	0x00000000,0x40000000,0x935d8ddd,0xaaa8ac17
+	.long	0x00000000,0x3ffe0000,0xb17217f7,0xd1cf79ac
+	.long	0x00000000,0x3f56c16d,0x6f7bd0b2,0x3f811112
+	.long	0x302c712c,0x3fa55555,0x55554cc1,0x3fc55555
+	.long	0x55554a54,0x3fe00000,0x00000000,0x00000000
+	.long	0x00000000,0x3fff0000,0x80000000,0x00000000
+	.long	0x3f738000,0x3fff0000,0x8164d1f3,0xbc030773
+	.long	0x3fbef7ca,0x3fff0000,0x82cd8698,0xac2ba1d7
+	.long	0x3fbdf8a9,0x3fff0000,0x843a28c3,0xacde4046
+	.long	0x3fbcd7c9,0x3fff0000,0x85aac367,0xcc487b15
+	.long	0xbfbde8da,0x3fff0000,0x871f6196,0x9e8d1010
+	.long	0x3fbde85c,0x3fff0000,0x88980e80,0x92da8527
+	.long	0x3fbebbf1,0x3fff0000,0x8a14d575,0x496efd9a
+	.long	0x3fbb80ca,0x3fff0000,0x8b95c1e3,0xea8bd6e7
+	.long	0xbfba8373,0x3fff0000,0x8d1adf5b,0x7e5ba9e6
+	.long	0xbfbe9670,0x3fff0000,0x8ea4398b,0x45cd53c0
+	.long	0x3fbdb700,0x3fff0000,0x9031dc43,0x1466b1dc
+	.long	0x3fbeeeb0,0x3fff0000,0x91c3d373,0xab11c336
+	.long	0x3fbbfd6d,0x3fff0000,0x935a2b2f,0x13e6e92c
+	.long	0xbfbdb319,0x3fff0000,0x94f4efa8,0xfef70961
+	.long	0x3fbdba2b,0x3fff0000,0x96942d37,0x20185a00
+	.long	0x3fbe91d5,0x3fff0000,0x9837f051,0x8db8a96f
+	.long	0x3fbe8d5a,0x3fff0000,0x99e04593,0x20b7fa65
+	.long	0xbfbcde7b,0x3fff0000,0x9b8d39b9,0xd54e5539
+	.long	0xbfbebaaf,0x3fff0000,0x9d3ed9a7,0x2cffb751
+	.long	0xbfbd86da,0x3fff0000,0x9ef53260,0x91a111ae
+	.long	0xbfbebedd,0x3fff0000,0xa0b0510f,0xb9714fc2
+	.long	0x3fbcc96e,0x3fff0000,0xa2704303,0x0c496819
+	.long	0xbfbec90b,0x3fff0000,0xa43515ae,0x09e6809e
+	.long	0x3fbbd1db,0x3fff0000,0xa5fed6a9,0xb15138ea
+	.long	0x3fbce5eb,0x3fff0000,0xa7cd93b4,0xe965356a
+	.long	0xbfbec274,0x3fff0000,0xa9a15ab4,0xea7c0ef8
+	.long	0x3fbea83c,0x3fff0000,0xab7a39b5,0xa93ed337
+	.long	0x3fbecb00,0x3fff0000,0xad583eea,0x42a14ac6
+	.long	0x3fbe9301,0x3fff0000,0xaf3b78ad,0x690a4375
+	.long	0xbfbd8367,0x3fff0000,0xb123f581,0xd2ac2590
+	.long	0xbfbef05f,0x3fff0000,0xb311c412,0xa9112489
+	.long	0x3fbdfb3c,0x3fff0000,0xb504f333,0xf9de6484
+	.long	0x3fbeb2fb,0x3fff0000,0xb6fd91e3,0x28d17791
+	.long	0x3fbae2cb,0x3fff0000,0xb8fbaf47,0x62fb9ee9
+	.long	0x3fbcdc3c,0x3fff0000,0xbaff5ab2,0x133e45fb
+	.long	0x3fbee9aa,0x3fff0000,0xbd08a39f,0x580c36bf
+	.long	0xbfbeaefd,0x3fff0000,0xbf1799b6,0x7a731083
+	.long	0xbfbcbf51,0x3fff0000,0xc12c4cca,0x66709456
+	.long	0x3fbef88a,0x3fff0000,0xc346ccda,0x24976407
+	.long	0x3fbd83b2,0x3fff0000,0xc5672a11,0x5506dadd
+	.long	0x3fbdf8ab,0x3fff0000,0xc78d74c8,0xabb9b15d
+	.long	0xbfbdfb17,0x3fff0000,0xc9b9bd86,0x6e2f27a3
+	.long	0xbfbefe3c,0x3fff0000,0xcbec14fe,0xf2727c5d
+	.long	0xbfbbb6f8,0x3fff0000,0xce248c15,0x1f8480e4
+	.long	0xbfbcee53,0x3fff0000,0xd06333da,0xef2b2595
+	.long	0xbfbda4ae,0x3fff0000,0xd2a81d91,0xf12ae45a
+	.long	0x3fbc9124,0x3fff0000,0xd4f35aab,0xcfedfa1f
+	.long	0x3fbeb243,0x3fff0000,0xd744fcca,0xd69d6af4
+	.long	0x3fbde69a,0x3fff0000,0xd99d15c2,0x78afd7b6
+	.long	0xbfb8bc61,0x3fff0000,0xdbfbb797,0xdaf23755
+	.long	0x3fbdf610,0x3fff0000,0xde60f482,0x5e0e9124
+	.long	0xbfbd8be1,0x3fff0000,0xe0ccdeec,0x2a94e111
+	.long	0x3fbacb12,0x3fff0000,0xe33f8972,0xbe8a5a51
+	.long	0x3fbb9bfe,0x3fff0000,0xe5b906e7,0x7c8348a8
+	.long	0x3fbcf2f4,0x3fff0000,0xe8396a50,0x3c4bdc68
+	.long	0x3fbef22f,0x3fff0000,0xeac0c6e7,0xdd24392f
+	.long	0xbfbdbf4a,0x3fff0000,0xed4f301e,0xd9942b84
+	.long	0x3fbec01a,0x3fff0000,0xefe4b99b,0xdcdaf5cb
+	.long	0x3fbe8cac,0x3fff0000,0xf281773c,0x59ffb13a
+	.long	0xbfbcbb3f,0x3fff0000,0xf5257d15,0x2486cc2c
+	.long	0x3fbef73a,0x3fff0000,0xf7d0df73,0x0ad13bb9
+	.long	0xbfb8b795,0x3fff0000,0xfa83b2db,0x722a033a
+	.long	0x3fbef84b,0x3fff0000,0xfd3e0c0c,0xf486c175
+	.long	0xbfbef581,0xf210d080,0x22103228,0x0004f22e
+	.long	0x6800ff84,0x02817fff,0xffff0c81,0x3fb98000
+	.long	0x6c046000,0x00880c81,0x400d80c0,0x6f046000
+	.long	0x007cf200,0x0080f23c,0x44a34280,0x0000f22e
+	.long	0x6080ff54,0x2f0243fa,0xfbbcf22e,0x4080ff54
+	.long	0x222eff54,0x24010281,0x0000003f,0xe981d3c1
+	.long	0xec822202,0xe2819481,0x06820000,0x3ffff227
+	.long	0xe00cf23c,0x44a33c80,0x00002d59,0xff842d59
+	.long	0xff882d59,0xff8c3d59,0xff90f200,0x04283d59
+	.long	0xff94426e,0xff9642ae,0xff98d36e,0xff84f23a
+	.long	0x4823fb22,0xd36eff90,0x60000100,0x0c813fff
+	.long	0x80006e12,0xf2009000,0xf23c4422,0x3f800000
+	.long	0x60ff0000,0x0b12222e,0xff840c81,0x00000000
+	.long	0x6d0660ff,0x00000ac8,0x60ff0000,0x0a1af200
+	.long	0x9000f23c,0x44003f80,0x00002210,0x00810080
+	.long	0x0001f201,0x442260ff,0x00000adc,0xf210d080
+	.long	0x22103228,0x0004f22e,0x6800ff84,0x02817fff
+	.long	0xffff0c81,0x3fb98000,0x6c046000,0xff900c81
+	.long	0x400b9b07,0x6f046000,0xff84f200,0x0080f23a
+	.long	0x54a3fa62,0xf22e6080,0xff542f02,0x43fafac6
+	.long	0xf22e4080,0xff54222e,0xff542401,0x02810000
+	.long	0x003fe981,0xd3c1ec82,0x2202e281,0x94810682
+	.long	0x00003fff,0xf227e00c,0xf2000500,0xf23a54a3
+	.long	0xfa2c2d59,0xff84f23a,0x4923fa2a,0x2d59ff88
+	.long	0x2d59ff8c,0xf2000428,0x3d59ff90,0xf2000828
+	.long	0x3d59ff94,0x426eff96,0x42aeff98,0xf23a4823
+	.long	0xfa14d36e,0xff84d36e,0xff90f200,0x0080f200
+	.long	0x04a3f23a,0x5500fa1e,0xf23a5580,0xfa20f200
+	.long	0x0523f200,0x05a3f23a,0x5522fa1a,0xf23a55a2
+	.long	0xfa1cf200,0x0523f200,0x05a3f23a,0x5522fa16
+	.long	0xf20001a3,0xf2000523,0xf2000c22,0xf2000822
+	.long	0xf21fd030,0xf22e4823,0xff84f22e,0x4822ff90
+	.long	0xf22e4822,0xff84f200,0x90003d42,0xff84241f
+	.long	0x2d7c8000,0x0000ff88,0x42aeff8c,0x123c0000
+	.long	0xf22e4823,0xff8460ff,0x00000996,0xf2009000
+	.long	0xf23c4400,0x3f800000,0x22100081,0x00800001
+	.long	0xf2014422,0x60ff0000,0x098e2f01,0xe8082200
+	.long	0x02410003,0x0240000c,0x48403001,0x221f4a01
+	.long	0x671e0c01,0x000a6f12,0x0c01000e,0x6f3c0c01
+	.long	0x002f6f06,0x0c01003f,0x6f6260ff,0x00000baa
+	.long	0x4a00660c,0x41fb0170,0x000000d6,0x60000086
+	.long	0x0c000003,0x670a41fb,0x01700000,0x00d06074
+	.long	0x41fb0170,0x000000d2,0x606a0401,0x000b4a00
+	.long	0x661041fb,0x01700000,0x00cc0c01,0x00026f54
+	.long	0x605a0c00,0x0003670a,0x41fb0170,0x000000f2
+	.long	0x60e841fb,0x01700000,0x012460de,0x04010030
+	.long	0x4a006616,0x41fb0170,0x0000014e,0x0c010001
+	.long	0x6f220c01,0x00076f24,0x601a0c00,0x0003670a
+	.long	0x41fb0170,0x000001f2,0x60e241fb,0x01700000
+	.long	0x02a860d8,0x00ae0000,0x0208ff64,0xc2fc000c
+	.long	0x48404a00,0x6608f230,0xd0801000,0x4e754840
+	.long	0x3d701000,0xff902d70,0x1004ff94,0x2d701008
+	.long	0xff982200,0x428041ee,0xff904268,0x000261ff
+	.long	0x000062c6,0xf210d080,0x4e7551fc,0x40000000
+	.long	0xc90fdaa2,0x2168c235,0x40000000,0xc90fdaa2
+	.long	0x2168c234,0x40000000,0xc90fdaa2,0x2168c235
+	.long	0x3ffd0000,0x9a209a84,0xfbcff798,0x40000000
+	.long	0xadf85458,0xa2bb4a9a,0x3fff0000,0xb8aa3b29
+	.long	0x5c17f0bc,0x3ffd0000,0xde5bd8a9,0x37287195
+	.long	0x00000000,0x00000000,0x00000000,0x3ffd0000
+	.long	0x9a209a84,0xfbcff798,0x40000000,0xadf85458
+	.long	0xa2bb4a9a,0x3fff0000,0xb8aa3b29,0x5c17f0bb
+	.long	0x3ffd0000,0xde5bd8a9,0x37287195,0x00000000
+	.long	0x00000000,0x00000000,0x3ffd0000,0x9a209a84
+	.long	0xfbcff799,0x40000000,0xadf85458,0xa2bb4a9b
+	.long	0x3fff0000,0xb8aa3b29,0x5c17f0bc,0x3ffd0000
+	.long	0xde5bd8a9,0x37287195,0x00000000,0x00000000
+	.long	0x00000000,0x3ffe0000,0xb17217f7,0xd1cf79ac
+	.long	0x40000000,0x935d8ddd,0xaaa8ac17,0x3fff0000
+	.long	0x80000000,0x00000000,0x40020000,0xa0000000
+	.long	0x00000000,0x40050000,0xc8000000,0x00000000
+	.long	0x400c0000,0x9c400000,0x00000000,0x40190000
+	.long	0xbebc2000,0x00000000,0x40340000,0x8e1bc9bf
+	.long	0x04000000,0x40690000,0x9dc5ada8,0x2b70b59e
+	.long	0x40d30000,0xc2781f49,0xffcfa6d5,0x41a80000
+	.long	0x93ba47c9,0x80e98ce0,0x43510000,0xaa7eebfb
+	.long	0x9df9de8e,0x46a30000,0xe319a0ae,0xa60e91c7
+	.long	0x4d480000,0xc9767586,0x81750c17,0x5a920000
+	.long	0x9e8b3b5d,0xc53d5de5,0x75250000,0xc4605202
+	.long	0x8a20979b,0x3ffe0000,0xb17217f7,0xd1cf79ab
+	.long	0x40000000,0x935d8ddd,0xaaa8ac16,0x3fff0000
+	.long	0x80000000,0x00000000,0x40020000,0xa0000000
+	.long	0x00000000,0x40050000,0xc8000000,0x00000000
+	.long	0x400c0000,0x9c400000,0x00000000,0x40190000
+	.long	0xbebc2000,0x00000000,0x40340000,0x8e1bc9bf
+	.long	0x04000000,0x40690000,0x9dc5ada8,0x2b70b59d
+	.long	0x40d30000,0xc2781f49,0xffcfa6d5,0x41a80000
+	.long	0x93ba47c9,0x80e98cdf,0x43510000,0xaa7eebfb
+	.long	0x9df9de8d,0x46a30000,0xe319a0ae,0xa60e91c6
+	.long	0x4d480000,0xc9767586,0x81750c17,0x5a920000
+	.long	0x9e8b3b5d,0xc53d5de4,0x75250000,0xc4605202
+	.long	0x8a20979a,0x3ffe0000,0xb17217f7,0xd1cf79ac
+	.long	0x40000000,0x935d8ddd,0xaaa8ac17,0x3fff0000
+	.long	0x80000000,0x00000000,0x40020000,0xa0000000
+	.long	0x00000000,0x40050000,0xc8000000,0x00000000
+	.long	0x400c0000,0x9c400000,0x00000000,0x40190000
+	.long	0xbebc2000,0x00000000,0x40340000,0x8e1bc9bf
+	.long	0x04000000,0x40690000,0x9dc5ada8,0x2b70b59e
+	.long	0x40d30000,0xc2781f49,0xffcfa6d6,0x41a80000
+	.long	0x93ba47c9,0x80e98ce0,0x43510000,0xaa7eebfb
+	.long	0x9df9de8e,0x46a30000,0xe319a0ae,0xa60e91c7
+	.long	0x4d480000,0xc9767586,0x81750c18,0x5a920000
+	.long	0x9e8b3b5d,0xc53d5de5,0x75250000,0xc4605202
+	.long	0x8a20979b,0x2f003229,0x00005bee,0xff540281
+	.long	0x00007fff,0x30280000,0x02407fff,0x0c403fff
+	.long	0x6d0000c0,0x0c40400c,0x6e0000a4,0xf2284803
+	.long	0x0000f200,0x6000f23c,0x88000000,0x00004a29
+	.long	0x00046b5e,0x2f003d69,0x0000ff84,0x2d690004
+	.long	0xff882d69,0x0008ff8c,0x41eeff84,0x61ff0000
+	.long	0x60ba4480,0xd09ff22e,0xd080ff84,0x0c40c001
+	.long	0x6c36f21f,0x9000223c,0x80000000,0x0480ffff
+	.long	0xc0014480,0x0c000020,0x6c0ae0a9,0x42a72f01
+	.long	0x42a76028,0x04000020,0xe0a92f01,0x42a742a7
+	.long	0x601af229,0xd0800000,0xf21f9000,0x06403fff
+	.long	0x484042a7,0x2f3c8000,0x00002f00,0xf200b000
+	.long	0x123c0000,0xf21f4823,0x60ff0000,0x04ce201f
+	.long	0xc1494a29,0x00006bff,0x0000038c,0x60ff0000
+	.long	0x03c44a29,0x00046a16,0x201ff200,0x9000123c
+	.long	0x0003f229,0x48000000,0x60ff0000,0x049e201f
+	.long	0x204960ff,0x000002e2,0x00010000,0x80000000
+	.long	0x00000000,0x00000000,0x422eff65,0x2f00422e
+	.long	0xff5c600c,0x422eff65,0x2f001d7c,0x0001ff5c
+	.long	0x48e73f00,0x36280000,0x3d43ff58,0x02830000
+	.long	0x7fff2828,0x00042a28,0x00084a83,0x663c263c
+	.long	0x00003ffe,0x4a846616,0x28054285,0x04830000
+	.long	0x00204286,0xedc46000,0xedac9686,0x60224286
+	.long	0xedc46000,0x9686edac,0x2e05edad,0x44860686
+	.long	0x00000020,0xecaf8887,0x60060683,0x00003ffe
+	.long	0x30290000,0x3d40ff5a,0x322eff58,0xb1810281
+	.long	0x00008000,0x3d41ff5e,0x02800000,0x7fff2229
+	.long	0x00042429,0x00084a80,0x663c203c,0x00003ffe
+	.long	0x4a816616,0x22024282,0x04800000,0x00204286
+	.long	0xedc16000,0xeda99086,0x60224286,0xedc16000
+	.long	0x9086eda9,0x2e02edaa,0x44860686,0x00000020
+	.long	0xecaf8287,0x60060680,0x00003ffe,0x2d43ff54
+	.long	0x2f009083,0x42864283,0x227c0000,0x00004a80
+	.long	0x6c06201f,0x6000006a,0x588f4a86,0x6e0eb284
+	.long	0x6608b485,0x66046000,0x01366508,0x94859384
+	.long	0x42865283,0x4a80670e,0xd683d482,0xe39155c6
+	.long	0x52895380,0x60d4202e,0xff544a81,0x66162202
+	.long	0x42820480,0x00000020,0x4286edc1,0x6000eda9
+	.long	0x9086601c,0x4286edc1,0x60006b14,0x9086eda9
+	.long	0x2e02edaa,0x44860686,0x00000020,0xecaf8287
+	.long	0x0c800000,0x41fe6c2a,0x3d40ff90,0x2d41ff94
+	.long	0x2d42ff98,0x2c2eff54,0x3d46ff84,0x2d44ff88
+	.long	0x2d45ff8c,0xf22e4800,0xff901d7c,0x0001ff5d
+	.long	0x60362d41,0xff942d42,0xff980480,0x00003ffe
+	.long	0x3d40ff90,0x2c2eff54,0x04860000,0x3ffe2d46
+	.long	0xff54f22e,0x4800ff90,0x3d46ff84,0x2d44ff88
+	.long	0x2d45ff8c,0x422eff5d,0x4a2eff5c,0x67222c2e
+	.long	0xff545386,0xb0866d18,0x6e0eb284,0x6608b485
+	.long	0x66046000,0x007a6508,0xf22e4828,0xff845283
+	.long	0x3c2eff5a,0x6c04f200,0x001a4286,0x3c2eff5e
+	.long	0x7e08eeae,0x02830000,0x007f8686,0x1d43ff65
+	.long	0x4cdf00fc,0x201ff200,0x90004a2e,0xff5d6710
+	.long	0x123c0000,0xf23a4823,0xfdc060ff,0x0000024c
+	.long	0x123c0003,0xf2000000,0x60ff0000,0x023e5283
+	.long	0x0c800000,0x00086c04,0xe1ab6002,0x4283f23c
+	.long	0x44000000,0x0000422e,0xff5d6000,0xff942c03
+	.long	0x02860000,0x00014a86,0x6700ff86,0x52833c2e
+	.long	0xff5a0a86,0x00008000,0x3d46ff5a,0x6000ff72
+	.long	0x7fff0000,0xffffffff,0xffffffff,0x4a280000
+	.long	0x6b12f23c,0x44007f80,0x000000ae,0x02000410
+	.long	0xff644e75,0xf23c4400,0xff800000,0x00ae0a00
+	.long	0x0410ff64,0x4e7500ae,0x01002080,0xff64f23a
+	.long	0xd080ffbe,0x4e7500ae,0x00000800,0xff646008
+	.long	0x00ae0000,0x0a28ff64,0x22482200,0x020100c0
+	.long	0x660e4a28,0x00006a18,0x08ee0003,0xff646010
+	.long	0x2f094a28,0x00005bc1,0x61ff0000,0x0196225f
+	.long	0xf210d080,0x102eff62,0x0200000a,0x66024e75
+	.long	0x3d690000,0xff842d69,0x0004ff88,0x2d690008
+	.long	0xff8c41ee,0xff8461ff,0x00005cd0,0x06800000
+	.long	0x6000026e,0x8000ff84,0x816eff84,0xf22ed040
+	.long	0xff844e75,0x00ae0000,0x0a28ff64,0x4a105bc1
+	.long	0x61ff0000,0x013ef210,0xd080f23c,0x44800000
+	.long	0x00004e75,0x00ae0000,0x0a28ff64,0x51c161ff
+	.long	0x00000120,0xf210d080,0xf23c4480,0x00000000
+	.long	0x4e7500ae,0x00001048,0xff641200,0x020100c0
+	.long	0x675c4a28,0x00046b24,0x3d680000,0xff842d68
+	.long	0x0004ff88,0x2d680008,0xff8c41ee,0xff8448e7
+	.long	0xc08061ff,0x00005c44,0x4cdf0103,0x0c010040
+	.long	0x660e4aa8,0x00086614,0x4a280007,0x660e601e
+	.long	0x22280008,0x02810000,0x07ff6712,0x00ae0000
+	.long	0x0200ff64,0x600800ae,0x00001248,0xff644a28
+	.long	0x00005bc1,0x61ff0000,0x5f261d40,0xff64f210
+	.long	0xd080f23c,0x44800000,0x00004e75,0x00ae0000
+	.long	0x1248ff64,0x51c161ff,0x00005f04,0x1d40ff64
+	.long	0xf210d080,0xf23c4480,0x00000000,0x4e75f327
+	.long	0x4a2f0002,0x6b2edffc,0x0000000c,0xf294000e
+	.long	0xf2810014,0x006e0208,0xff664e75,0x00ae0800
+	.long	0x0208ff64,0x4e751d7c,0x0004ff64,0x006e0208
+	.long	0xff664e75,0x006e0208,0xff6661ff,0x00000bae
+	.long	0xdffc0000,0x000c4e75,0xf3274a2f,0x00026bea
+	.long	0xdffc0000,0x000cf200,0xa80081ae,0xff644e75
+	.long	0x00ae0000,0x0a28ff64,0x02410010,0xe8080200
+	.long	0x000f8001,0x2200e309,0x1d7b000a,0xff6441fb
+	.long	0x16204e75,0x04040400,0x04040400,0x04040400
+	.long	0x00000000,0x0c0c080c,0x0c0c080c,0x0c0c080c
+	.long	0x00000000,0x00000000,0x00000000,0x00000000
+	.long	0x00000000,0x00000000,0x00000000,0x00000000
+	.long	0x00000000,0x00000000,0x00000000,0x00000000
+	.long	0x00000000,0x00000000,0x00000001,0x00000000
+	.long	0x3f810000,0x00000000,0x00000000,0x00000000
+	.long	0x3f810000,0x00000000,0x00000000,0x00000000
+	.long	0x3f810000,0x00000000,0x00000000,0x00000000
+	.long	0x3f810000,0x00000100,0x00000000,0x00000000
+	.long	0x3c010000,0x00000000,0x00000000,0x00000000
+	.long	0x3c010000,0x00000000,0x00000000,0x00000000
+	.long	0x3c010000,0x00000000,0x00000000,0x00000000
+	.long	0x3c010000,0x00000000,0x00000800,0x00000000
+	.long	0x00000000,0x00000000,0x00000000,0x00000000
+	.long	0x00000000,0x00000000,0x00000000,0x00000000
+	.long	0x00000000,0x00000000,0x00000000,0x00000000
+	.long	0x00000000,0x00000000,0x00000000,0x00000000
+	.long	0x80000000,0x00000000,0x00000000,0x00000000
+	.long	0x80000000,0x00000000,0x00000000,0x00000000
+	.long	0x80000000,0x00000000,0x00000001,0x00000000
+	.long	0x80000000,0x00000000,0x00000000,0x00000000
+	.long	0xbf810000,0x00000000,0x00000000,0x00000000
+	.long	0xbf810000,0x00000000,0x00000000,0x00000000
+	.long	0xbf810000,0x00000100,0x00000000,0x00000000
+	.long	0xbf810000,0x00000000,0x00000000,0x00000000
+	.long	0xbc010000,0x00000000,0x00000000,0x00000000
+	.long	0xbc010000,0x00000000,0x00000000,0x00000000
+	.long	0xbc010000,0x00000000,0x00000800,0x00000000
+	.long	0xbc010000,0x00000000,0x00000000,0x00000000
+	.long	0x4a280000,0x6b10f23c,0x44000000,0x00001d7c
+	.long	0x0004ff64,0x4e75f23c,0x44008000,0x00001d7c
+	.long	0x000cff64,0x4e754a29,0x00006bea,0x60d84a28
+	.long	0x00006b10,0xf23c4400,0x7f800000,0x1d7c0002
+	.long	0xff644e75,0xf23c4400,0xff800000,0x1d7c000a
+	.long	0xff644e75,0x4a290000,0x6bea60d8,0x4a280000
+	.long	0x6ba460d0,0x4a280000,0x6b00fbbc,0x60c64a28
+	.long	0x00006b16,0x60be4a28,0x00006b0e,0xf23c4400
+	.long	0x3f800000,0x422eff64,0x4e75f23c,0x4400bf80
+	.long	0x00001d7c,0x0008ff64,0x4e753fff,0x0000c90f
+	.long	0xdaa22168,0xc235bfff,0x0000c90f,0xdaa22168
+	.long	0xc2354a28,0x00006b0e,0xf2009000,0xf23a4800
+	.long	0xffda6000,0xfcf0f200,0x9000f23a,0x4800ffd8
+	.long	0x6000fcea,0xf23c4480,0x3f800000,0x4a280000
+	.long	0x6a10f23c,0x44008000,0x00001d7c,0x000cff64
+	.long	0x6040f23c,0x44000000,0x00001d7c,0x0004ff64
+	.long	0x6030f23a,0x4880faea,0x61ff0000,0x00286000
+	.long	0xfb16f228,0x48800000,0x61ff0000,0x00186000
+	.long	0x030ef228,0x48800000,0x61ff0000,0x00086000
+	.long	0x02ee102e,0xff430240,0x0007303b,0x02064efb
+	.long	0x00020010,0x00180020,0x0026002c,0x00320038
+	.long	0x003ef22e,0xf040ffdc,0x4e75f22e,0xf040ffe8
+	.long	0x4e75f200,0x05004e75,0xf2000580,0x4e75f200
+	.long	0x06004e75,0xf2000680,0x4e75f200,0x07004e75
+	.long	0xf2000780,0x4e75122e,0xff4f67ff,0xfffff7dc
+	.long	0x0c010001,0x67000096,0x0c010002,0x67ffffff
+	.long	0xfa880c01,0x000467ff,0xfffff7c0,0x0c010005
+	.long	0x67ff0000,0x024060ff,0x0000024a,0x122eff4f
+	.long	0x67ffffff,0xfa640c01,0x000167ff,0xfffffa5a
+	.long	0x0c010002,0x67ffffff,0xfa500c01,0x000467ff
+	.long	0xfffffa46,0x0c010003,0x67ff0000,0x021860ff
+	.long	0x00000202,0x122eff4f,0x67ff0000,0x004e0c01
+	.long	0x000167ff,0x00000028,0x0c010002,0x67ffffff
+	.long	0xfa180c01,0x000467ff,0x00000030,0x0c010003
+	.long	0x67ff0000,0x01e060ff,0x000001ca,0x12280000
+	.long	0x10290000,0xb1010201,0x00801d41,0xff654a00
+	.long	0x6a00fdc4,0x6000fdd0,0x422eff65,0x2f001228
+	.long	0x00001029,0x0000b101,0x02010080,0x1d41ff65
+	.long	0x0c2e0004,0xff4f660c,0x41e90000,0x201f60ff
+	.long	0xfffff9c6,0xf21f9000,0xf2294800,0x00004a29
+	.long	0x00006b02,0x4e751d7c,0x0008ff64,0x4e75122e
+	.long	0xff4f67ff,0xfffff6e0,0x0c010001,0x6700ff8e
+	.long	0x0c010002,0x67ffffff,0xf9800c01,0x000467ff
+	.long	0xfffff6c4,0x0c010003,0x67ff0000,0x014860ff
+	.long	0x00000132,0x122eff4f,0x67ffffff,0xf95c0c01
+	.long	0x000167ff,0xfffff952,0x0c010002,0x67ffffff
+	.long	0xf9480c01,0x000467ff,0xfffff93e,0x0c010003
+	.long	0x67ff0000,0x011060ff,0x000000fa,0x122eff4f
+	.long	0x6700ff46,0x0c010001,0x6700ff22,0x0c010002
+	.long	0x67ffffff,0xf9140c01,0x000467ff,0xffffff2c
+	.long	0x0c010003,0x67ff0000,0x00dc60ff,0x000000c6
+	.long	0x122eff4f,0x67ffffff,0xf51e0c01,0x000167ff
+	.long	0xfffffce6,0x0c010002,0x67ffffff,0xfd0a0c01
+	.long	0x000467ff,0xfffff500,0x0c010003,0x67ff0000
+	.long	0x00a460ff,0x0000008e,0x122eff4f,0x67ffffff
+	.long	0xf4e60c01,0x000167ff,0xfffffcae,0x0c010002
+	.long	0x67ffffff,0xfcd20c01,0x000467ff,0xfffff4c8
+	.long	0x0c010003,0x67ff0000,0x006c60ff,0x00000056
+	.long	0x122eff4f,0x67ffffff,0xf8800c01,0x000367ff
+	.long	0x00000052,0x0c010005,0x67ff0000,0x003860ff
+	.long	0xfffff866,0x122eff4f,0x0c010003,0x67340c01
+	.long	0x0005671e,0x6058122e,0xff4f0c01,0x00036708
+	.long	0x0c010005,0x670c6036,0x00ae0100,0x4080ff64
+	.long	0x6010f229,0x48000000,0xf200a800,0x81aeff64
+	.long	0x4e75f229,0x48000000,0x4a290000,0x6b081d7c
+	.long	0x0001ff64,0x4e751d7c,0x0009ff64,0x4e75f228
+	.long	0x48000000,0xf200a800,0x81aeff64,0x4e75f228
+	.long	0x48000000,0x4a280000,0x6bdc1d7c,0x0001ff64
+	.long	0x4e751d7c,0x0009ff64,0x4e75122e,0xff4e67ff
+	.long	0xffffd936,0x0c010001,0x67ffffff,0xfba60c01
+	.long	0x000267ff,0xfffffbca,0x0c010004,0x67ffffff
+	.long	0xd9f60c01,0x000367ff,0xffffffb6,0x60ffffff
+	.long	0xffa0122e,0xff4e67ff,0xffffe620,0x0c010001
+	.long	0x67ffffff,0xfb6e0c01,0x000267ff,0xfffffbc8
+	.long	0x0c010004,0x67ffffff,0xe7560c01,0x000367ff
+	.long	0xffffff7e,0x60ffffff,0xff68122e,0xff4e67ff
+	.long	0xffffd4d2,0x0c010001,0x67ffffff,0xfb360c01
+	.long	0x000267ff,0xfffffb9a,0x0c010004,0x67ffffff
+	.long	0xd76a0c01,0x000367ff,0xffffff46,0x60ffffff
+	.long	0xff30122e,0xff4e67ff,0xffffd972,0x0c010001
+	.long	0x67ffffff,0xfafe0c01,0x000267ff,0xfffffb6a
+	.long	0x0c010004,0x67ffffff,0xdabc0c01,0x000367ff
+	.long	0xffffff0e,0x60ffffff,0xfef8122e,0xff4e67ff
+	.long	0xffffca6a,0x0c010001,0x67ffffff,0xfac60c01
+	.long	0x000267ff,0xfffffb6e,0x0c010004,0x67ffffff
+	.long	0xcc8a0c01,0x000367ff,0xfffffed6,0x60ffffff
+	.long	0xfec0122e,0xff4e67ff,0xffffcc76,0x0c010001
+	.long	0x67ffffff,0xfa8e0c01,0x000267ff,0xfffff6aa
+	.long	0x0c010004,0x67ffffff,0xcd060c01,0x000367ff
+	.long	0xfffffe9e,0x60ffffff,0xfe88122e,0xff4e67ff
+	.long	0xffffe662,0x0c010001,0x67ffffff,0xfa560c01
+	.long	0x000267ff,0xfffff672,0x0c010004,0x67ffffff
+	.long	0xe6c60c01,0x000367ff,0xfffffe66,0x60ffffff
+	.long	0xfe50122e,0xff4e67ff,0xffffb372,0x0c010001
+	.long	0x67ffffff,0xfa1e0c01,0x000267ff,0xfffff63a
+	.long	0x0c010004,0x67ffffff,0xb5380c01,0x000367ff
+	.long	0xfffffe2e,0x60ffffff,0xfe18122e,0xff4e67ff
+	.long	0xffffbdfc,0x0c010001,0x67ffffff,0xf9e60c01
+	.long	0x000267ff,0xfffff602,0x0c010004,0x67ffffff
+	.long	0xbf420c01,0x000367ff,0xfffffdf6,0x60ffffff
+	.long	0xfde0122e,0xff4e67ff,0xffffd17a,0x0c010001
+	.long	0x67ffffff,0xfa2a0c01,0x000267ff,0xfffffa00
+	.long	0x0c010004,0x67ffffff,0xd3080c01,0x000367ff
+	.long	0xfffffdbe,0x60ffffff,0xfda8122e,0xff4e67ff
+	.long	0xffffeb64,0x0c010001,0x67ffffff,0xf9f20c01
+	.long	0x000267ff,0xfffff9c8,0x0c010004,0x67ffffff
+	.long	0xec200c01,0x000367ff,0xfffffd86,0x60ffffff
+	.long	0xfd70122e,0xff4e67ff,0xffffec24,0x0c010001
+	.long	0x67ffffff,0xf9ba0c01,0x000267ff,0xfffff990
+	.long	0x0c010004,0x67ffffff,0xed360c01,0x000367ff
+	.long	0xfffffd4e,0x60ffffff,0xfd38122e,0xff4e67ff
+	.long	0xffffe178,0x0c010001,0x67ffffff,0xf51a0c01
+	.long	0x000267ff,0xfffff960,0x0c010004,0x67ffffff
+	.long	0xe30c0c01,0x000367ff,0xfffffd16,0x60ffffff
+	.long	0xfd00122e,0xff4e67ff,0xffffe582,0x0c010001
+	.long	0x67ffffff,0xf4e20c01,0x000267ff,0xfffff928
+	.long	0x0c010004,0x67ffffff,0xe5940c01,0x000367ff
+	.long	0xfffffcde,0x60ffffff,0xfcc8122e,0xff4e67ff
+	.long	0xffffe59a,0x0c010001,0x67ffffff,0xf4aa0c01
+	.long	0x000267ff,0xfffff8f0,0x0c010004,0x67ffffff
+	.long	0xe5d60c01,0x000367ff,0xfffffca6,0x60ffffff
+	.long	0xfc90122e,0xff4e67ff,0xffffd530,0x0c010001
+	.long	0x67ffffff,0xf8da0c01,0x000267ff,0xfffff888
+	.long	0x0c010004,0x67ffffff,0xd5b60c01,0x000367ff
+	.long	0xfffffc6e,0x60ffffff,0xfc58122e,0xff4e67ff
+	.long	0xffffcac2,0x0c010001,0x67ffffff,0xf8de0c01
+	.long	0x000267ff,0xfffff442,0x0c010004,0x67ffffff
+	.long	0xcb340c01,0x000367ff,0xfffffc36,0x60ffffff
+	.long	0xfc20122e,0xff4e67ff,0xffffb14c,0x0c010001
+	.long	0x67ffffff,0xf86a0c01,0x000267ff,0xfffff40a
+	.long	0x0c010004,0x67ffffff,0xb30e0c01,0x000367ff
+	.long	0xfffffbfe,0x60ffffff,0xfbe8122e,0xff4e67ff
+	.long	0xffffd40e,0x0c010001,0x67ffffff,0xf7b60c01
+	.long	0x000267ff,0xfffff3d2,0x0c010004,0x67ffffff
+	.long	0xd40c0c01,0x000367ff,0xfffffbc6,0x60ffffff
+	.long	0xfbb0122e,0xff4e67ff,0xffffd40a,0x0c010001
+	.long	0x67ffffff,0xf77e0c01,0x000267ff,0xfffff39a
+	.long	0x0c010004,0x67ffffff,0xd41a0c01,0x000367ff
+	.long	0xfffffb8e,0x60ffffff,0xfb78122e,0xff4e67ff
+	.long	0xffffb292,0x0c010001,0x67ffffff,0xf81a0c01
+	.long	0x000267ff,0xfffff83e,0x0c010004,0x67ffffff
+	.long	0xb50a0c01,0x000367ff,0xfffff83a,0x60ffffff
+	.long	0xf844122e,0xff4e67ff,0xfffff89e,0x0c010001
+	.long	0x67ffffff,0xf8ca0c01,0x000267ff,0xfffff8f8
+	.long	0x0c010004,0x67ffffff,0xf8800c01,0x000367ff
+	.long	0xfffffab4,0x60ffffff,0xfac0122e,0xff4e67ff
+	.long	0xfffff96e,0x0c010001,0x67ffffff,0xf99a0c01
+	.long	0x000267ff,0xfffff9c8,0x0c010004,0x67ffffff
+	.long	0xf9500c01,0x000367ff,0xfffffa7c,0x60ffffff
+	.long	0xfa88122e,0xff4e67ff,0xfffff9d8,0x0c010001
+	.long	0x67ffffff,0xfa060c01,0x000267ff,0xfffffa34
+	.long	0x0c010004,0x67ffffff,0xf9ba0c01,0x000367ff
+	.long	0xfffffa44,0x60ffffff,0xfa500c2f,0x00070003
+	.long	0x673e1d7c,0x0000ff4e,0x1d7c0000,0xff4ff22e
+	.long	0xf080ff78,0x41ef0004,0x43eeff78,0x0c010003
+	.long	0x67160c01,0x00026708,0x61ff0000,0x02004e75
+	.long	0x61ff0000,0x1b9e4e75,0x61ff0000,0x05e44e75
+	.long	0x1d7c0004,0xff4e60c0,0x4afc006d,0x000005d2
+	.long	0x00000fc8,0xfffffa6e,0x0000106c,0x00002314
+	.long	0x00000000,0xfffffaa6,0x00000000,0xfffffade
+	.long	0xfffffb16,0xfffffb4e,0x00000000,0xfffffb86
+	.long	0xfffffbbe,0xfffffbf6,0xfffffc2e,0xfffffc66
+	.long	0xfffffc9e,0xfffffcd6,0x00000000,0xfffffd0e
+	.long	0xfffffd46,0xfffffd7e,0x00000000,0x00001112
+	.long	0xfffffdb6,0x00000ca8,0x00000000,0xfffffdee
+	.long	0xfffffe26,0xfffffe5e,0xfffffe96,0x0000089e
+	.long	0xffffff06,0x00001b84,0x000001de,0x00001854
+	.long	0xffffff3e,0xffffff76,0x00001512,0x00001f4c
+	.long	0x00000000,0x00000000,0x00000000,0x00000000
+	.long	0x00000000,0x00000000,0x00000000,0xfffffece
+	.long	0xfffffece,0xfffffece,0xfffffece,0xfffffece
+	.long	0xfffffece,0xfffffece,0xfffffece,0x000013b0
+	.long	0x00000000,0x00000f56,0x00000000,0x00000000
+	.long	0x00000000,0x00000000,0x00000000,0x000005c0
+	.long	0x00002302,0x00000000,0x00000000,0x000005ca
+	.long	0x0000230c,0x00000000,0x00000000,0x00000000
+	.long	0x00000000,0x00000000,0x00000000,0x00000000
+	.long	0x00000000,0x00000000,0x00000000,0x00000000
+	.long	0x00000000,0x00000000,0x00000000,0x00000000
+	.long	0x00000000,0x00000000,0x00000000,0x00001100
+	.long	0x00000000,0x00000c96,0x00000000,0x0000110a
+	.long	0x00000000,0x00000ca0,0x00000000,0x0000088c
+	.long	0x00000000,0x00001b72,0x000001cc,0x00000896
+	.long	0x00000000,0x00001b7c,0x000001d6,0x00001f3a
+	.long	0x00000000,0x00000000,0x00000000,0x00001f44
+	.long	0xffffc001,0xffffff81,0xfffffc01,0x00004000
+	.long	0x0000007f,0x000003ff,0x02000030,0x00000040
+	.long	0x60080200,0x00300000,0x00802d40,0xff5c4241
+	.long	0x122eff4f,0xe709822e,0xff4e6600,0x02e43d69
+	.long	0x0000ff90,0x2d690004,0xff942d69,0x0008ff98
+	.long	0x3d680000,0xff842d68,0x0004ff88,0x2d680008
+	.long	0xff8c61ff,0x000024ce,0x2f0061ff,0x00002572
+	.long	0xd197322e,0xff5eec09,0x201fb0bb,0x14846700
+	.long	0x011e6d00,0x0062b0bb,0x14846700,0x021a6e00
+	.long	0x014af22e,0xd080ff90,0xf22e9000,0xff5cf23c
+	.long	0x88000000,0x0000f22e,0x4823ff84,0xf201a800
+	.long	0xf23c9000,0x00000000,0x83aeff64,0xf22ef080
+	.long	0xff842f02,0x322eff84,0x24010281,0x00007fff
+	.long	0x02428000,0x92808242,0x3d41ff84,0x241ff22e
+	.long	0xd080ff84,0x4e75f22e,0xd080ff90,0xf22e9000
+	.long	0xff5cf23c,0x88000000,0x0000f22e,0x4823ff84
+	.long	0xf201a800,0xf23c9000,0x00000000,0x83aeff64
+	.long	0x00ae0000,0x1048ff64,0x122eff62,0x02010013
+	.long	0x661c082e,0x0003ff64,0x56c1202e,0xff5c61ff
+	.long	0x00004fcc,0x812eff64,0xf210d080,0x4e75222e
+	.long	0xff5c0201,0x00c06634,0xf22ef080,0xff842f02
+	.long	0x322eff84,0x34010281,0x00007fff,0x92800481
+	.long	0x00006000,0x02417fff,0x02428000,0x82423d41
+	.long	0xff84241f,0xf22ed040,0xff8460a6,0xf22ed080
+	.long	0xff90222e,0xff5c0201,0x0030f201,0x9000f22e
+	.long	0x4823ff84,0xf23c9000,0x00000000,0x60aaf22e
+	.long	0xd080ff90,0xf22e9000,0xff5cf23c,0x88000000
+	.long	0x0000f22e,0x4823ff84,0xf201a800,0xf23c9000
+	.long	0x00000000,0x83aeff64,0xf2000098,0xf23c58b8
+	.long	0x0002f293,0xff3c6000,0xfee408ee,0x0003ff66
+	.long	0xf22ed080,0xff90f23c,0x90000000,0x0010f23c
+	.long	0x88000000,0x0000f22e,0x4823ff84,0xf201a800
+	.long	0xf23c9000,0x00000000,0x83aeff64,0x122eff62
+	.long	0x0201000b,0x6620f22e,0xf080ff84,0x41eeff84
+	.long	0x222eff5c,0x61ff0000,0x4dd8812e,0xff64f22e
+	.long	0xd080ff84,0x4e75f22e,0xd040ff90,0x222eff5c
+	.long	0x020100c0,0x6652f22e,0x9000ff5c,0xf23c8800
+	.long	0x00000000,0xf22e48a3,0xff84f23c,0x90000000
+	.long	0x0000f22e,0xf040ff84,0x2f02322e,0xff842401
+	.long	0x02810000,0x7fff0242,0x80009280,0x06810000
+	.long	0x60000241,0x7fff8242,0x3d41ff84,0x241ff22e
+	.long	0xd040ff84,0x6000ff80,0x222eff5c,0x02010030
+	.long	0xf2019000,0x60a6f22e,0xd080ff90,0xf22e9000
+	.long	0xff5cf23c,0x88000000,0x0000f22e,0x4823ff84
+	.long	0xf201a800,0xf23c9000,0x00000000,0x83aeff64
+	.long	0xf2000098,0xf23c58b8,0x0002f292,0xfde0f294
+	.long	0xfefaf22e,0xd040ff90,0x222eff5c,0x020100c0
+	.long	0x00010010,0xf2019000,0xf23c8800,0x00000000
+	.long	0xf22e48a3,0xff84f23c,0x90000000,0x0000f200
+	.long	0x0498f23c,0x58b80002,0xf293fda2,0x6000febc
+	.long	0x323b120a,0x4efb1006,0x4afc0030,0xfd120072
+	.long	0x00cc006c,0xfd120066,0x00000000,0x00720072
+	.long	0x0060006c,0x00720066,0x00000000,0x009e0060
+	.long	0x009e006c,0x009e0066,0x00000000,0x006c006c
+	.long	0x006c006c,0x006c0066,0x00000000,0xfd120072
+	.long	0x00cc006c,0xfd120066,0x00000000,0x00660066
+	.long	0x00660066,0x00660066,0x00000000,0x60ff0000
+	.long	0x230e60ff,0x00002284,0x60ff0000,0x227e1028
+	.long	0x00001229,0x0000b101,0x6a10f23c,0x44008000
+	.long	0x00001d7c,0x000cff64,0x4e75f23c,0x44000000
+	.long	0x00001d7c,0x0004ff64,0x4e75f229,0xd0800000
+	.long	0x10280000,0x12290000,0xb1016a10,0xf2000018
+	.long	0xf200001a,0x1d7c000a,0xff644e75,0xf2000018
+	.long	0x1d7c0002,0xff644e75,0xf228d080,0x00001028
+	.long	0x00001229,0x0000b101,0x6ae260d0,0x02000030
+	.long	0x00000040,0x60080200,0x00300000,0x00802d40
+	.long	0xff5c122e,0xff4e6600,0x02620200,0x00c06600
+	.long	0x007c4a28,0x00006a06,0x08ee0003,0xff64f228
+	.long	0xd0800000,0x4e750200,0x00c06600,0x006008ee
+	.long	0x0003ff66,0x4a280000,0x6a0608ee,0x0003ff64
+	.long	0xf228d080,0x0000082e,0x0003ff62,0x66024e75
+	.long	0x3d680000,0xff842d68,0x0004ff88,0x2d680008
+	.long	0xff8c41ee,0xff8461ff,0x00004950,0x44400640
+	.long	0x6000322e,0xff840241,0x80000240,0x7fff8041
+	.long	0x3d40ff84,0xf22ed040,0xff844e75,0x0c000040
+	.long	0x667e3d68,0x0000ff84,0x2d680004,0xff882d68
+	.long	0x0008ff8c,0x61ff0000,0x206c0c80,0x0000007f
+	.long	0x6c000092,0x0c80ffff,0xff816700,0x01786d00
+	.long	0x00f4f23c,0x88000000,0x0000f22e,0x9000ff5c
+	.long	0xf22e4800,0xff84f201,0xa800f23c,0x90000000
+	.long	0x000083ae,0xff642f02,0xf22ef080,0xff84322e
+	.long	0xff843401,0x02810000,0x7fff9280,0x02428000
+	.long	0x84413d42,0xff84241f,0xf22ed080,0xff844e75
+	.long	0x3d680000,0xff842d68,0x0004ff88,0x2d680008
+	.long	0xff8c61ff,0x00001fee,0x0c800000,0x03ff6c00
+	.long	0x00140c80,0xfffffc01,0x670000fa,0x6d000076
+	.long	0x6000ff80,0x08ee0003,0xff664a2e,0xff846a06
+	.long	0x08ee0003,0xff64122e,0xff620201,0x000b661a
+	.long	0x41eeff84,0x222eff5c,0x61ff0000,0x4a74812e
+	.long	0xff64f22e,0xd080ff84,0x4e752d6e,0xff88ff94
+	.long	0x2d6eff8c,0xff98322e,0xff842f02,0x34010281
+	.long	0x00007fff,0x92800242,0x80000681,0x00006000
+	.long	0x02417fff,0x84413d42,0xff90f22e,0xd040ff90
+	.long	0x241f60ac,0xf23c8800,0x00000000,0xf22e9000
+	.long	0xff5cf22e,0x4800ff84,0xf23c9000,0x00000000
+	.long	0xf201a800,0x83aeff64,0x00ae0000,0x1048ff64
+	.long	0x122eff62,0x02010013,0x661c082e,0x0003ff64
+	.long	0x56c1202e,0xff5c61ff,0x00004ae4,0x812eff64
+	.long	0xf210d080,0x4e752f02,0x322eff84,0x24010281
+	.long	0x00007fff,0x02428000,0x92800481,0x00006000
+	.long	0x02417fff,0x82423d41,0xff84241f,0xf22ed040
+	.long	0xff8460b6,0xf23c8800,0x00000000,0xf22e9000
+	.long	0xff5cf22e,0x4800ff84,0xf201a800,0xf23c9000
+	.long	0x00000000,0x83aeff64,0xf2000098,0xf23c58b8
+	.long	0x0002f293,0xff746000,0xfe7e0c01,0x00046700
+	.long	0xfdb60c01,0x000567ff,0x00001f98,0x0c010003
+	.long	0x67ff0000,0x1fa2f228,0x48000000,0xf200a800
+	.long	0xe1981d40,0xff644e75,0x51fc51fc,0x51fc51fc
+	.long	0x00003fff,0x0000007e,0x000003fe,0xffffc001
+	.long	0xffffff81,0xfffffc01,0x02000030,0x00000040
+	.long	0x60080200,0x00300000,0x00802d40,0xff5c4241
+	.long	0x122eff4f,0xe709822e,0xff4e6600,0x02d63d69
+	.long	0x0000ff90,0x2d690004,0xff942d69,0x0008ff98
+	.long	0x3d680000,0xff842d68,0x0004ff88,0x2d680008
+	.long	0xff8c61ff,0x00001e0e,0x2f0061ff,0x00001eb2
+	.long	0x4497d197,0x322eff5e,0xec09201f,0xb0bb148e
+	.long	0x6f000074,0xb0bb1520,0xff7a6700,0x020c6e00
+	.long	0x013cf22e,0xd080ff90,0xf22e9000,0xff5cf23c
+	.long	0x88000000,0x0000f22e,0x4820ff84,0xf201a800
+	.long	0xf23c9000,0x00000000,0x83aeff64,0xf22ef080
+	.long	0xff842f02,0x322eff84,0x24010281,0x00007fff
+	.long	0x02428000,0x92808242,0x3d41ff84,0x241ff22e
+	.long	0xd080ff84,0x4e750000,0x7fff0000,0x407f0000
+	.long	0x43ff201f,0x60c62f00,0xf22ed080,0xff90f22e
+	.long	0x9000ff5c,0xf23c8800,0x00000000,0xf22e4820
+	.long	0xff84f200,0xa800f23c,0x90000000,0x000081ae
+	.long	0xff64f227,0xe0013017,0xdffc0000,0x000c0280
+	.long	0x00007fff,0x9097b0bb,0x14ae6db6,0x201f00ae
+	.long	0x00001048,0xff64122e,0xff620201,0x0013661c
+	.long	0x082e0003,0xff6456c1,0x202eff5c,0x61ff0000
+	.long	0x48de812e,0xff64f210,0xd0804e75,0x222eff5c
+	.long	0x020100c0,0x6634f22e,0xf080ff84,0x2f02322e
+	.long	0xff843401,0x02810000,0x7fff9280,0x04810000
+	.long	0x60000241,0x7fff0242,0x80008242,0x3d41ff84
+	.long	0x241ff22e,0xd040ff84,0x60a6f22e,0xd080ff90
+	.long	0x222eff5c,0x02010030,0xf2019000,0xf22e4820
+	.long	0xff84f23c,0x90000000,0x000060aa,0x08ee0003
+	.long	0xff66f22e,0xd080ff90,0xf23c9000,0x00000010
+	.long	0xf23c8800,0x00000000,0xf22e4820,0xff84f201
+	.long	0xa800f23c,0x90000000,0x000083ae,0xff64122e
+	.long	0xff620201,0x000b6620,0xf22ef080,0xff8441ee
+	.long	0xff84222e,0xff5c61ff,0x00004726,0x812eff64
+	.long	0xf22ed080,0xff844e75,0xf22ed040,0xff90222e
+	.long	0xff5c0201,0x00c06652,0xf22e9000,0xff5cf23c
+	.long	0x88000000,0x0000f22e,0x48a0ff84,0xf23c9000
+	.long	0x00000000,0xf22ef040,0xff842f02,0x322eff84
+	.long	0x24010281,0x00007fff,0x02428000,0x92800681
+	.long	0x00006000,0x02417fff,0x82423d41,0xff84241f
+	.long	0xf22ed040,0xff846000,0xff80222e,0xff5c0201
+	.long	0x0030f201,0x900060a6,0xf22ed080,0xff90f22e
+	.long	0x9000ff5c,0xf23c8800,0x00000000,0xf22e4820
+	.long	0xff84f201,0xa800f23c,0x90000000,0x000083ae
+	.long	0xff64f200,0x0098f23c,0x58b80001,0xf292fdee
+	.long	0xf294fefa,0xf22ed040,0xff90222e,0xff5c0201
+	.long	0x00c00001,0x0010f201,0x9000f23c,0x88000000
+	.long	0x0000f22e,0x48a0ff84,0xf23c9000,0x00000000
+	.long	0xf2000498,0xf23c58b8,0x0001f293,0xfdb06000
+	.long	0xfebc323b,0x120a4efb,0x10064afc,0x0030fd20
+	.long	0x009e0072,0x0060fd20,0x00660000,0x00000072
+	.long	0x006c0072,0x00600072,0x00660000,0x000000d0
+	.long	0x00d0006c,0x006000d0,0x00660000,0x00000060
+	.long	0x00600060,0x00600060,0x00660000,0x0000fd20
+	.long	0x009e0072,0x0060fd20,0x00660000,0x00000066
+	.long	0x00660066,0x00660066,0x00660000,0x000060ff
+	.long	0x00001bd8,0x60ff0000,0x1bd260ff,0x00001c50
+	.long	0x10280000,0x12290000,0xb1016a10,0xf23c4400
+	.long	0x80000000,0x1d7c000c,0xff644e75,0xf23c4400
+	.long	0x00000000,0x1d7c0004,0xff644e75,0x006e0410
+	.long	0xff661028,0x00001229,0x0000b101,0x6a10f23c
+	.long	0x4400ff80,0x00001d7c,0x000aff64,0x4e75f23c
+	.long	0x44007f80,0x00001d7c,0x0002ff64,0x4e751029
+	.long	0x00001228,0x0000b101,0x6a16f229,0xd0800000
+	.long	0xf2000018,0xf200001a,0x1d7c000a,0xff644e75
+	.long	0xf229d080,0x0000f200,0x00181d7c,0x0002ff64
+	.long	0x4e750200,0x00300000,0x00406008,0x02000030
+	.long	0x00000080,0x2d40ff5c,0x122eff4e,0x66000276
+	.long	0x020000c0,0x66000090,0x2d680004,0xff882d68
+	.long	0x0008ff8c,0x30280000,0x0a408000,0x6a061d7c
+	.long	0x0008ff64,0x3d40ff84,0xf22ed080,0xff844e75
+	.long	0x020000c0,0x666008ee,0x0003ff66,0x2d680004
+	.long	0xff882d68,0x0008ff8c,0x30280000,0x0a408000
+	.long	0x6a061d7c,0x0008ff64,0x3d40ff84,0xf22ed080
+	.long	0xff84082e,0x0003ff62,0x66024e75,0x41eeff84
+	.long	0x61ff0000,0x42664440,0x06406000,0x322eff84
+	.long	0x02418000,0x02407fff,0x80413d40,0xff84f22e
+	.long	0xd040ff84,0x4e750c00,0x0040667e,0x3d680000
+	.long	0xff842d68,0x0004ff88,0x2d680008,0xff8c61ff
+	.long	0x00001982,0x0c800000,0x007f6c00,0x00900c80
+	.long	0xffffff81,0x67000178,0x6d0000f4,0xf23c8800
+	.long	0x00000000,0xf22e9000,0xff5cf22e,0x481aff84
+	.long	0xf201a800,0xf23c9000,0x00000000,0x83aeff64
+	.long	0x2f02f22e,0xf080ff84,0x322eff84,0x34010281
+	.long	0x00007fff,0x92800242,0x80008441,0x3d42ff84
+	.long	0x241ff22e,0xd080ff84,0x4e753d68,0x0000ff84
+	.long	0x2d680004,0xff882d68,0x0008ff8c,0x61ff0000
+	.long	0x19040c80,0x000003ff,0x6c120c80,0xfffffc01
+	.long	0x670000fc,0x6d000078,0x6000ff82,0x08ee0003
+	.long	0xff660a2e,0x0080ff84,0x6a0608ee,0x0003ff64
+	.long	0x122eff62,0x0201000b,0x661a41ee,0xff84222e
+	.long	0xff5c61ff,0x0000438a,0x812eff64,0xf22ed080
+	.long	0xff844e75,0x2d6eff88,0xff942d6e,0xff8cff98
+	.long	0x322eff84,0x2f022401,0x02810000,0x7fff0242
+	.long	0x80009280,0x06810000,0x60000241,0x7fff8242
+	.long	0x3d41ff90,0xf22ed040,0xff90241f,0x60acf23c
+	.long	0x88000000,0x0000f22e,0x9000ff5c,0xf22e481a
+	.long	0xff84f23c,0x90000000,0x0000f201,0xa80083ae
+	.long	0xff6400ae,0x00001048,0xff64122e,0xff620201
+	.long	0x0013661c,0x082e0003,0xff6456c1,0x202eff5c
+	.long	0x61ff0000,0x43fa812e,0xff64f210,0xd0804e75
+	.long	0x2f02322e,0xff842401,0x02810000,0x7fff0242
+	.long	0x80009280,0x04810000,0x60000241,0x7fff8242
+	.long	0x3d41ff84,0xf22ed040,0xff84241f,0x60b6f23c
+	.long	0x88000000,0x0000f22e,0x9000ff5c,0xf22e481a
+	.long	0xff84f201,0xa800f23c,0x90000000,0x000083ae
+	.long	0xff64f200,0x0098f23c,0x58b80002,0xf293ff74
+	.long	0x6000fe7e,0x0c010004,0x6700fdb6,0x0c010005
+	.long	0x67ff0000,0x18ae0c01,0x000367ff,0x000018b8
+	.long	0xf228481a,0x0000f200,0xa800e198,0x1d40ff64
+	.long	0x4e75122e,0xff4e6610,0x4a280000,0x6b024e75
+	.long	0x1d7c0008,0xff644e75,0x0c010001,0x67400c01
+	.long	0x00026724,0x0c010005,0x67ff0000,0x18660c01
+	.long	0x000367ff,0x00001870,0x4a280000,0x6b024e75
+	.long	0x1d7c0008,0xff644e75,0x4a280000,0x6b081d7c
+	.long	0x0002ff64,0x4e751d7c,0x000aff64,0x4e754a28
+	.long	0x00006b08,0x1d7c0004,0xff644e75,0x1d7c000c
+	.long	0xff644e75,0x122eff4e,0x66280200,0x0030f200
+	.long	0x9000f23c,0x88000000,0x0000f228,0x48010000
+	.long	0xf23c9000,0x00000000,0xf200a800,0x81aeff64
+	.long	0x4e750c01,0x0001672e,0x0c010002,0x674e0c01
+	.long	0x00046710,0x0c010005,0x67ff0000,0x17d660ff
+	.long	0x000017e4,0x3d680000,0xff841d7c,0x0080ff88
+	.long	0x41eeff84,0x60a44a28,0x00006b10,0xf23c4400
+	.long	0x00000000,0x1d7c0004,0xff644e75,0xf23c4400
+	.long	0x80000000,0x1d7c000c,0xff644e75,0xf228d080
+	.long	0x00004a28,0x00006b08,0x1d7c0002,0xff644e75
+	.long	0x1d7c000a,0xff644e75,0x122eff4e,0x6618f23c
+	.long	0x88000000,0x0000f228,0x48030000,0xf200a800
+	.long	0x81aeff64,0x4e750c01,0x0001672e,0x0c010002
+	.long	0x674e0c01,0x00046710,0x0c010005,0x67ff0000
+	.long	0x174260ff,0x00001750,0x3d680000,0xff841d7c
+	.long	0x0080ff88,0x41eeff84,0x60b44a28,0x00006b10
+	.long	0xf23c4400,0x00000000,0x1d7c0004,0xff644e75
+	.long	0xf23c4400,0x80000000,0x1d7c000c,0xff644e75
+	.long	0xf228d080,0x00004a28,0x00006b08,0x1d7c0002
+	.long	0xff644e75,0x1d7c000a,0xff644e75,0x02000030
+	.long	0x00000040,0x60080200,0x00300000,0x00802d40
+	.long	0xff5c122e,0xff4e6600,0x025c0200,0x00c0667e
+	.long	0x2d680004,0xff882d68,0x0008ff8c,0x32280000
+	.long	0x0881000f,0x3d41ff84,0xf22ed080,0xff844e75
+	.long	0x020000c0,0x665808ee,0x0003ff66,0x2d680004
+	.long	0xff882d68,0x0008ff8c,0x30280000,0x0880000f
+	.long	0x3d40ff84,0xf22ed080,0xff84082e,0x0003ff62
+	.long	0x66024e75,0x41eeff84,0x61ff0000,0x3e0e4440
+	.long	0x06406000,0x322eff84,0x02418000,0x02407fff
+	.long	0x80413d40,0xff84f22e,0xd040ff84,0x4e750c00
+	.long	0x0040667e,0x3d680000,0xff842d68,0x0004ff88
+	.long	0x2d680008,0xff8c61ff,0x0000152a,0x0c800000
+	.long	0x007f6c00,0x00900c80,0xffffff81,0x67000170
+	.long	0x6d0000ec,0xf23c8800,0x00000000,0xf22e9000
+	.long	0xff5cf22e,0x4818ff84,0xf201a800,0xf23c9000
+	.long	0x00000000,0x83aeff64,0x2f02f22e,0xf080ff84
+	.long	0x322eff84,0x24010281,0x00007fff,0x92800242
+	.long	0x80008441,0x3d42ff84,0x241ff22e,0xd080ff84
+	.long	0x4e753d68,0x0000ff84,0x2d680004,0xff882d68
+	.long	0x0008ff8c,0x61ff0000,0x14ac0c80,0x000003ff
+	.long	0x6c120c80,0xfffffc01,0x670000f4,0x6d000070
+	.long	0x6000ff82,0x08ee0003,0xff6608ae,0x0007ff84
+	.long	0x122eff62,0x0201000b,0x661a41ee,0xff84222e
+	.long	0xff5c61ff,0x00003f3a,0x812eff64,0xf22ed080
+	.long	0xff844e75,0x2d6eff88,0xff942d6e,0xff8cff98
+	.long	0x322eff84,0x2f022401,0x02810000,0x7fff0242
+	.long	0x80009280,0x06810000,0x60000241,0x7fff8242
+	.long	0x3d41ff90,0xf22ed040,0xff90241f,0x60acf23c
+	.long	0x88000000,0x0000f22e,0x9000ff5c,0xf22e4818
+	.long	0xff84f23c,0x90000000,0x0000f201,0xa80083ae
+	.long	0xff6400ae,0x00001048,0xff64122e,0xff620201
+	.long	0x0013661c,0x082e0003,0xff6456c1,0x202eff5c
+	.long	0x61ff0000,0x3faa812e,0xff64f210,0xd0804e75
+	.long	0x2f02322e,0xff842401,0x02810000,0x7fff0242
+	.long	0x80009280,0x04810000,0x60000241,0x7fff8242
+	.long	0x3d41ff84,0xf22ed040,0xff84241f,0x60b6f23c
+	.long	0x88000000,0x0000f22e,0x9000ff5c,0xf22e4818
+	.long	0xff84f201,0xa800f23c,0x90000000,0x000083ae
+	.long	0xff64f200,0x0098f23c,0x58b80002,0xf293ff74
+	.long	0x6000fe86,0x0c010004,0x6700fdc6,0x0c010005
+	.long	0x67ff0000,0x145e0c01,0x000367ff,0x00001468
+	.long	0xf2284818,0x00000c01,0x00026708,0x1d7c0004
+	.long	0xff644e75,0x1d7c0002,0xff644e75,0x4241122e
+	.long	0xff4fe709,0x822eff4e,0x6618f229,0xd0800000
+	.long	0xf2284838,0x0000f200,0xa800e198,0x1d40ff64
+	.long	0x4e75323b,0x120a4efb,0x10064afc,0x0030ffdc
+	.long	0xffdcffdc,0x006000f8,0x006e0000,0x0000ffdc
+	.long	0xffdcffdc,0x0060007c,0x006e0000,0x0000ffdc
+	.long	0xffdcffdc,0x0060007c,0x006e0000,0x00000060
+	.long	0x00600060,0x00600060,0x006e0000,0x00000114
+	.long	0x009c009c,0x006000bc,0x006e0000,0x0000006e
+	.long	0x006e006e,0x006e006e,0x006e0000,0x000061ff
+	.long	0x00001388,0x022e00f7,0xff644e75,0x61ff0000
+	.long	0x137a022e,0x00f7ff64,0x4e753d68,0x0000ff84
+	.long	0x20280004,0x08c0001f,0x2d40ff88,0x2d680008
+	.long	0xff8c41ee,0xff846000,0xff422d69,0x0000ff84
+	.long	0x20290004,0x08c0001f,0x2d40ff88,0x2d690008
+	.long	0xff8c43ee,0xff846000,0xff223d69,0x0000ff90
+	.long	0x3d680000,0xff842029,0x000408c0,0x001f2d40
+	.long	0xff942028,0x000408c0,0x001f2d40,0xff882d69
+	.long	0x0008ff98,0x2d680008,0xff8c43ee,0xff9041ee
+	.long	0xff846000,0xfee61028,0x00001229,0x0000b101
+	.long	0x6b00ff78,0x4a006b02,0x4e751d7c,0x0008ff64
+	.long	0x4e751028,0x00001229,0x0000b101,0x6b00ff7c
+	.long	0x4a006a02,0x4e751d7c,0x0008ff64,0x4e752d40
+	.long	0xff5c4241,0x122eff4f,0xe709822e,0xff4e6600
+	.long	0x02a03d69,0x0000ff90,0x2d690004,0xff942d69
+	.long	0x0008ff98,0x3d680000,0xff842d68,0x0004ff88
+	.long	0x2d680008,0xff8c61ff,0x0000119a,0x2f0061ff
+	.long	0x0000123e,0xd09f0c80,0xffffc001,0x670000f8
+	.long	0x6d000064,0x0c800000,0x40006700,0x01da6e00
+	.long	0x0122f22e,0xd080ff90,0xf22e9000,0xff5cf23c
+	.long	0x88000000,0x0000f22e,0x4827ff84,0xf201a800
+	.long	0xf23c9000,0x00000000,0x83aeff64,0xf22ef080
+	.long	0xff842f02,0x322eff84,0x24010281,0x00007fff
+	.long	0x02428000,0x92808242,0x3d41ff84,0x241ff22e
+	.long	0xd080ff84,0x4e75f22e,0xd080ff90,0xf22e9000
+	.long	0xff5cf23c,0x88000000,0x0000f22e,0x4827ff84
+	.long	0xf201a800,0xf23c9000,0x00000000,0x83aeff64
+	.long	0x00ae0000,0x1048ff64,0x122eff62,0x02010013
+	.long	0x6620082e,0x0003ff64,0x56c1202e,0xff5c0200
+	.long	0x003061ff,0x00003c98,0x812eff64,0xf210d080
+	.long	0x4e75f22e,0xf080ff84,0x2f02322e,0xff842401
+	.long	0x02810000,0x7fff9280,0x04810000,0x60000241
+	.long	0x7fff0242,0x80008242,0x3d41ff84,0x241ff22e
+	.long	0xd040ff84,0x60acf22e,0xd080ff90,0xf22e9000
+	.long	0xff5cf23c,0x88000000,0x0000f22e,0x4827ff84
+	.long	0xf201a800,0xf23c9000,0x00000000,0x83aeff64
+	.long	0xf2000098,0xf23c58b8,0x0002f293,0xff646000
+	.long	0xff0c08ee,0x0003ff66,0xf22ed080,0xff90f23c
+	.long	0x90000000,0x0010f23c,0x88000000,0x0000f22e
+	.long	0x4827ff84,0xf201a800,0xf23c9000,0x00000000
+	.long	0x83aeff64,0x122eff62,0x0201000b,0x6620f22e
+	.long	0xf080ff84,0x41eeff84,0x222eff5c,0x61ff0000
+	.long	0x3b56812e,0xff64f22e,0xd080ff84,0x4e75f22e
+	.long	0xd040ff90,0xf22e9000,0xff5cf23c,0x88000000
+	.long	0x0000f22e,0x48a7ff84,0xf23c9000,0x00000000
+	.long	0xf22ef040,0xff842f02,0x322eff84,0x24010281
+	.long	0x00007fff,0x02428000,0x92800681,0x00006000
+	.long	0x02417fff,0x82423d41,0xff84241f,0xf22ed040
+	.long	0xff846000,0xff8af22e,0xd080ff90,0xf22e9000
+	.long	0xff5cf23c,0x88000000,0x0000f22e,0x4827ff84
+	.long	0xf201a800,0xf23c9000,0x00000000,0x83aeff64
+	.long	0xf2000098,0xf23c58b8,0x0002f292,0xfe20f294
+	.long	0xff12f22e,0xd040ff90,0x222eff5c,0x020100c0
+	.long	0x00010010,0xf2019000,0xf23c8800,0x00000000
+	.long	0xf22e48a7,0xff84f23c,0x90000000,0x0000f200
+	.long	0x0498f23c,0x58b80002,0xf293fde2,0x6000fed4
+	.long	0x323b120a,0x4efb1006,0x4afc0030,0xfd560072
+	.long	0x0078006c,0xfd560066,0x00000000,0x00720072
+	.long	0x0060006c,0x00720066,0x00000000,0x007e0060
+	.long	0x007e006c,0x007e0066,0x00000000,0x006c006c
+	.long	0x006c006c,0x006c0066,0x00000000,0xfd560072
+	.long	0x0078006c,0xfd560066,0x00000000,0x00660066
+	.long	0x00660066,0x00660066,0x00000000,0x60ff0000
+	.long	0x101e60ff,0x00000f94,0x60ff0000,0x0f8e60ff
+	.long	0xffffed0e,0x60ffffff,0xed6260ff,0xffffed2e
+	.long	0x2d40ff5c,0x4241122e,0xff4fe709,0x822eff4e
+	.long	0x6600027c,0x3d690000,0xff902d69,0x0004ff94
+	.long	0x2d690008,0xff983d68,0x0000ff84,0x2d680004
+	.long	0xff882d68,0x0008ff8c,0x61ff0000,0x0e582f00
+	.long	0x61ff0000,0x0efc4497,0xd197322e,0xff5eec09
+	.long	0x201f0c80,0xffffc001,0x6f000064,0x0c800000
+	.long	0x3fff6700,0x01b66e00,0x0100f22e,0xd080ff90
+	.long	0xf22e9000,0xff5cf23c,0x88000000,0x0000f22e
+	.long	0x4824ff84,0xf201a800,0xf23c9000,0x00000000
+	.long	0x83aeff64,0xf22ef080,0xff842f02,0x322eff84
+	.long	0x24010281,0x00007fff,0x02428000,0x92808242
+	.long	0x3d41ff84,0x241ff22e,0xd080ff84,0x4e75f22e
+	.long	0xd080ff90,0xf22e9000,0xff5cf23c,0x88000000
+	.long	0x0000f22e,0x4824ff84,0xf201a800,0xf23c9000
+	.long	0x00000000,0x83aeff64,0xf227e001,0x3217dffc
+	.long	0x0000000c,0x02810000,0x7fff9280,0x0c810000
+	.long	0x7fff6d90,0x006e1048,0xff66122e,0xff620201
+	.long	0x00136620,0x082e0003,0xff6456c1,0x202eff5c
+	.long	0x02000030,0x61ff0000,0x3936812e,0xff64f210
+	.long	0xd0804e75,0xf22ef080,0xff842f02,0x322eff84
+	.long	0x24010281,0x00007fff,0x02428000,0x92800481
+	.long	0x00006000,0x02417fff,0x82423d41,0xff84241f
+	.long	0xf22ed040,0xff8460ac,0x08ee0003,0xff66f22e
+	.long	0xd080ff90,0xf23c9000,0x00000010,0xf23c8800
+	.long	0x00000000,0xf22e4824,0xff84f201,0xa800f23c
+	.long	0x90000000,0x000083ae,0xff64122e,0xff620201
+	.long	0x000b6620,0xf22ef080,0xff8441ee,0xff84222e
+	.long	0xff5c61ff,0x00003830,0x812eff64,0xf22ed080
+	.long	0xff844e75,0xf22ed040,0xff90f22e,0x9000ff5c
+	.long	0xf23c8800,0x00000000,0xf22e48a4,0xff84f23c
+	.long	0x90000000,0x0000f22e,0xf040ff84,0x2f02322e
+	.long	0xff842401,0x02810000,0x7fff0242,0x80009280
+	.long	0x06810000,0x60000241,0x7fff8242,0x3d41ff84
+	.long	0x241ff22e,0xd040ff84,0x608af22e,0xd080ff90
+	.long	0xf22e9000,0xff5cf23c,0x88000000,0x0000f22e
+	.long	0x4824ff84,0xf201a800,0xf23c9000,0x00000000
+	.long	0x83aeff64,0xf2000098,0xf23c58b8,0x0001f292
+	.long	0xfe44f294,0xff14f22e,0xd040ff90,0x42810001
+	.long	0x0010f201,0x9000f23c,0x88000000,0x0000f22e
+	.long	0x48a4ff84,0xf23c9000,0x00000000,0xf2000498
+	.long	0xf23c58b8,0x0001f293,0xfe0c6000,0xfedc323b
+	.long	0x120a4efb,0x10064afc,0x0030fd7a,0x00720078
+	.long	0x0060fd7a,0x00660000,0x00000078,0x006c0078
+	.long	0x00600078,0x00660000,0x0000007e,0x007e006c
+	.long	0x0060007e,0x00660000,0x00000060,0x00600060
+	.long	0x00600060,0x00660000,0x0000fd7a,0x00720078
+	.long	0x0060fd7a,0x00660000,0x00000066,0x00660066
+	.long	0x00660066,0x00660000,0x000060ff,0x00000c7c
+	.long	0x60ff0000,0x0c7660ff,0x00000cf4,0x60ffffff
+	.long	0xf0ce60ff,0xfffff09c,0x60ffffff,0xf0f40200
+	.long	0x00300000,0x00406008,0x02000030,0x00000080
+	.long	0x2d40ff5c,0x4241122e,0xff4fe709,0x822eff4e
+	.long	0x6600024c,0x61ff0000,0x0a5cf22e,0xd080ff90
+	.long	0xf23c8800,0x00000000,0xf22e9000,0xff5cf22e
+	.long	0x4822ff84,0xf23c9000,0x00000000,0xf201a800
+	.long	0x83aeff64,0xf281003c,0x2f02f227,0xe001322e
+	.long	0xff5eec09,0x34170282,0x00007fff,0x9480b4bb
+	.long	0x14246c38,0xb4bb142a,0x6d0000b8,0x67000184
+	.long	0x32170241,0x80008242,0x3e81f21f,0xd080241f
+	.long	0x4e754e75,0x00007fff,0x0000407f,0x000043ff
+	.long	0x00000000,0x00003f81,0x00003c01,0x00ae0000
+	.long	0x1048ff64,0x122eff62,0x02010013,0x6624dffc
+	.long	0x0000000c,0x082e0003,0xff6456c1,0x202eff5c
+	.long	0x61ff0000,0x366a812e,0xff64f210,0xd080241f
+	.long	0x4e75122e,0xff5c0201,0x00c0661a,0x32170241
+	.long	0x80000482,0x00006000,0x02427fff,0x82423e81
+	.long	0xf21fd040,0x60bef22e,0xd080ff90,0x222eff5c
+	.long	0x02010030,0xf2019000,0xf22e4822,0xff84f23c
+	.long	0x90000000,0x0000dffc,0x0000000c,0xf227e001
+	.long	0x60ba08ee,0x0003ff66,0xdffc0000,0x000cf22e
+	.long	0xd080ff90,0xf23c9000,0x00000010,0xf23c8800
+	.long	0x00000000,0xf22e4822,0xff84f23c,0x90000000
+	.long	0x0000f201,0xa80083ae,0xff64122e,0xff620201
+	.long	0x000b6622,0xf22ef080,0xff8441ee,0xff84222e
+	.long	0xff5c61ff,0x000034ba,0x812eff64,0xf22ed080
+	.long	0xff84241f,0x4e75f22e,0xd040ff90,0x222eff5c
+	.long	0x020100c0,0x664ef22e,0x9000ff5c,0xf23c8800
+	.long	0x00000000,0xf22e48a2,0xff84f23c,0x90000000
+	.long	0x0000f22e,0xf040ff84,0x322eff84,0x24010281
+	.long	0x00007fff,0x02428000,0x92800681,0x00006000
+	.long	0x02417fff,0x82423d41,0xff84f22e,0xd040ff84
+	.long	0x6000ff82,0x222eff5c,0x02010030,0xf2019000
+	.long	0x60aa222e,0xff5c0201,0x00c06700,0xfe74222f
+	.long	0x00040c81,0x80000000,0x6600fe66,0x4aaf0008
+	.long	0x6600fe5e,0x082e0001,0xff666700,0xfe54f22e
+	.long	0xd040ff90,0x222eff5c,0x020100c0,0x00010010
+	.long	0xf2019000,0xf23c8800,0x00000000,0xf22e48a2
+	.long	0xff84f23c,0x90000000,0x0000f200,0x0018f200
+	.long	0x0498f200,0x0438f292,0xfeca6000,0xfe14323b
+	.long	0x120a4efb,0x10064afc,0x0030fdaa,0x00e4011c
+	.long	0x0060fdaa,0x00660000,0x000000bc,0x006c011c
+	.long	0x006000bc,0x00660000,0x00000130,0x0130010c
+	.long	0x00600130,0x00660000,0x00000060,0x00600060
+	.long	0x00600060,0x00660000,0x0000fdaa,0x00e4011c
+	.long	0x0060fdaa,0x00660000,0x00000066,0x00660066
+	.long	0x00660066,0x00660000,0x000060ff,0x0000097c
+	.long	0x60ff0000,0x09761028,0x00001229,0x0000b101
+	.long	0x6b000016,0x4a006b2e,0xf23c4400,0x00000000
+	.long	0x1d7c0004,0xff644e75,0x122eff5f,0x02010030
+	.long	0x0c010020,0x6710f23c,0x44000000,0x00001d7c
+	.long	0x0004ff64,0x4e75f23c,0x44008000,0x00001d7c
+	.long	0x000cff64,0x4e753d68,0x0000ff84,0x2d680004
+	.long	0xff882d68,0x0008ff8c,0x61ff0000,0x0828426e
+	.long	0xff9042ae,0xff9442ae,0xff986000,0xfcce3d69
+	.long	0x0000ff90,0x2d690004,0xff942d69,0x0008ff98
+	.long	0x61ff0000,0x08ac426e,0xff8442ae,0xff8842ae
+	.long	0xff8c6000,0xfca61028,0x00001229,0x0000b300
+	.long	0x6bff0000,0x094af228,0xd0800000,0x4a280000
+	.long	0x6a1c1d7c,0x000aff64,0x4e75f229,0xd0800000
+	.long	0x4a290000,0x6a081d7c,0x000aff64,0x4e751d7c
+	.long	0x0002ff64,0x4e750200,0x00300000,0x00406008
+	.long	0x02000030,0x00000080,0x2d40ff5c,0x4241122e
+	.long	0xff4fe709,0x822eff4e,0x6600024c,0x61ff0000
+	.long	0x0694f22e,0xd080ff90,0xf23c8800,0x00000000
+	.long	0xf22e9000,0xff5cf22e,0x4828ff84,0xf23c9000
+	.long	0x00000000,0xf201a800,0x83aeff64,0xf281003c
+	.long	0x2f02f227,0xe001322e,0xff5eec09,0x34170282
+	.long	0x00007fff,0x9480b4bb,0x14246c38,0xb4bb142a
+	.long	0x6d0000b8,0x67000184,0x32170241,0x80008242
+	.long	0x3e81f21f,0xd080241f,0x4e754e75,0x00007fff
+	.long	0x0000407f,0x000043ff,0x00000000,0x00003f81
+	.long	0x00003c01,0x00ae0000,0x1048ff64,0x122eff62
+	.long	0x02010013,0x6624dffc,0x0000000c,0x082e0003
+	.long	0xff6456c1,0x202eff5c,0x61ff0000,0x32a2812e
+	.long	0xff64f210,0xd080241f,0x4e75122e,0xff5c0201
+	.long	0x00c0661a,0x32170241,0x80000482,0x00006000
+	.long	0x02427fff,0x82423e81,0xf21fd040,0x60bef22e
+	.long	0xd080ff90,0x222eff5c,0x02010030,0xf2019000
+	.long	0xf22e4828,0xff84f23c,0x90000000,0x0000dffc
+	.long	0x0000000c,0xf227e001,0x60ba08ee,0x0003ff66
+	.long	0xdffc0000,0x000cf22e,0xd080ff90,0xf23c9000
+	.long	0x00000010,0xf23c8800,0x00000000,0xf22e4828
+	.long	0xff84f23c,0x90000000,0x0000f201,0xa80083ae
+	.long	0xff64122e,0xff620201,0x000b6622,0xf22ef080
+	.long	0xff8441ee,0xff84222e,0xff5c61ff,0x000030f2
+	.long	0x812eff64,0xf22ed080,0xff84241f,0x4e75f22e
+	.long	0xd040ff90,0x222eff5c,0x020100c0,0x664ef22e
+	.long	0x9000ff5c,0xf23c8800,0x00000000,0xf22e48a8
+	.long	0xff84f23c,0x90000000,0x0000f22e,0xf040ff84
+	.long	0x322eff84,0x24010281,0x00007fff,0x02428000
+	.long	0x92800681,0x00006000,0x02417fff,0x82423d41
+	.long	0xff84f22e,0xd040ff84,0x6000ff82,0x222eff5c
+	.long	0x02010030,0xf2019000,0x60aa222e,0xff5c0201
+	.long	0x00c06700,0xfe74222f,0x00040c81,0x80000000
+	.long	0x6600fe66,0x4aaf0008,0x6600fe5e,0x082e0001
+	.long	0xff666700,0xfe54f22e,0xd040ff90,0x222eff5c
+	.long	0x020100c0,0x00010010,0xf2019000,0xf23c8800
+	.long	0x00000000,0xf22e48a8,0xff84f23c,0x90000000
+	.long	0x0000f200,0x0018f200,0x0498f200,0x0438f292
+	.long	0xfeca6000,0xfe14323b,0x120a4efb,0x10064afc
+	.long	0x0030fdaa,0x00e2011a,0x0060fdaa,0x00660000
+	.long	0x000000ba,0x006c011a,0x006000ba,0x00660000
+	.long	0x00000130,0x0130010a,0x00600130,0x00660000
+	.long	0x00000060,0x00600060,0x00600060,0x00660000
+	.long	0x0000fdaa,0x00e2011a,0x0060fdaa,0x00660000
+	.long	0x00000066,0x00660066,0x00660066,0x00660000
+	.long	0x000060ff,0x000005b4,0x60ff0000,0x05ae1028
+	.long	0x00001229,0x0000b300,0x6a144a00,0x6b2ef23c
+	.long	0x44000000,0x00001d7c,0x0004ff64,0x4e75122e
+	.long	0xff5f0201,0x00300c01,0x00206710,0xf23c4400
+	.long	0x00000000,0x1d7c0004,0xff644e75,0xf23c4400
+	.long	0x80000000,0x1d7c000c,0xff644e75,0x3d680000
+	.long	0xff842d68,0x0004ff88,0x2d680008,0xff8c61ff
+	.long	0x00000462,0x426eff90,0x42aeff94,0x42aeff98
+	.long	0x6000fcd0,0x3d690000,0xff902d69,0x0004ff94
+	.long	0x2d690008,0xff9861ff,0x000004e6,0x426eff84
+	.long	0x42aeff88,0x42aeff8c,0x6000fca8,0x10280000
+	.long	0x12290000,0xb3006aff,0x00000584,0xf228d080
+	.long	0x0000f200,0x001af293,0x001e1d7c,0x000aff64
+	.long	0x4e75f229,0xd0800000,0x4a290000,0x6a081d7c
+	.long	0x000aff64,0x4e751d7c,0x0002ff64,0x4e750200
+	.long	0x00300000,0x00406008,0x02000030,0x00000080
+	.long	0x2d40ff5c,0x4241122e,0xff4e6600,0x02744a28
+	.long	0x00006bff,0x00000528,0x020000c0,0x6648f22e
+	.long	0x9000ff5c,0xf23c8800,0x00000000,0xf2104804
+	.long	0xf201a800,0x83aeff64,0x4e754a28,0x00006bff
+	.long	0x000004fc,0x020000c0,0x661c3d68,0x0000ff84
+	.long	0x2d680004,0xff882d68,0x0008ff8c,0x61ff0000
+	.long	0x03ae6000,0x003e0c00,0x00406600,0x00843d68
+	.long	0x0000ff84,0x2d680004,0xff882d68,0x0008ff8c
+	.long	0x61ff0000,0x038a0c80,0x0000007e,0x67000098
+	.long	0x6e00009e,0x0c80ffff,0xff806700,0x01a46d00
+	.long	0x0120f23c,0x88000000,0x0000f22e,0x9000ff5c
+	.long	0xf22e4804,0xff84f201,0xa800f23c,0x90000000
+	.long	0x000083ae,0xff642f02,0xf22ef080,0xff84322e
+	.long	0xff842401,0x02810000,0x7fff9280,0x02428000
+	.long	0x84413d42,0xff84241f,0xf22ed080,0xff844e75
+	.long	0x3d680000,0xff842d68,0x0004ff88,0x2d680008
+	.long	0xff8c61ff,0x00000308,0x0c800000,0x03fe6700
+	.long	0x00166e1c,0x0c80ffff,0xfc006700,0x01246d00
+	.long	0x00a06000,0xff7e082e,0x0000ff85,0x6600ff74
+	.long	0x08ee0003,0xff66f23c,0x90000000,0x0010f23c
+	.long	0x88000000,0x0000f22e,0x4804ff84,0xf201a800
+	.long	0xf23c9000,0x00000000,0x83aeff64,0x122eff62
+	.long	0x0201000b,0x6620f22e,0xf080ff84,0x41eeff84
+	.long	0x222eff5c,0x61ff0000,0x2d28812e,0xff64f22e
+	.long	0xd080ff84,0x4e752d6e,0xff88ff94,0x2d6eff8c
+	.long	0xff98322e,0xff842f02,0x24010281,0x00007fff
+	.long	0x02428000,0x92800681,0x00006000,0x02417fff
+	.long	0x82423d41,0xff90f22e,0xd040ff90,0x241f60a6
+	.long	0xf23c8800,0x00000000,0xf22e9000,0xff5cf22e
+	.long	0x4804ff84,0xf23c9000,0x00000000,0xf201a800
+	.long	0x83aeff64,0x00ae0000,0x1048ff64,0x122eff62
+	.long	0x02010013,0x661c082e,0x0003ff64,0x56c1202e
+	.long	0xff5c61ff,0x00002d98,0x812eff64,0xf210d080
+	.long	0x4e752f02,0x322eff84,0x24010281,0x00007fff
+	.long	0x02428000,0x92800481,0x00006000,0x02417fff
+	.long	0x82423d41,0xff84f22e,0xd040ff84,0x241f60b6
+	.long	0x082e0000,0xff856600,0xff78f23c,0x88000000
+	.long	0x0000f22e,0x9000ff5c,0xf22e4804,0xff84f201
+	.long	0xa800f23c,0x90000000,0x000083ae,0xff64f200
+	.long	0x0080f23c,0x58b80001,0xf293ff6a,0x6000fe48
+	.long	0x0c010004,0x6700fdb4,0x0c010001,0x67160c01
+	.long	0x00026736,0x0c010005,0x67ff0000,0x023660ff
+	.long	0x00000244,0x4a280000,0x6b10f23c,0x44000000
+	.long	0x00001d7c,0x0004ff64,0x4e75f23c,0x44008000
+	.long	0x00001d7c,0x000cff64,0x4e754a28,0x00006bff
+	.long	0x0000026c,0xf228d080,0x00001d7c,0x0002ff64
+	.long	0x4e752d68,0x0004ff88,0x2d690004,0xff942d68
+	.long	0x0008ff8c,0x2d690008,0xff983028,0x00003229
+	.long	0x00003d40,0xff843d41,0xff900240,0x7fff0241
+	.long	0x7fff3d40,0xff543d41,0xff56b041,0x6cff0000
+	.long	0x005c61ff,0x0000015a,0x2f000c2e,0x0004ff4e
+	.long	0x661041ee,0xff8461ff,0x00002940,0x44403d40
+	.long	0xff54302e,0xff560440,0x0042b06e,0xff546c1a
+	.long	0x302eff54,0xd06f0002,0x322eff84,0x02418000
+	.long	0x80413d40,0xff84201f,0x4e75026e,0x8000ff84
+	.long	0x08ee0000,0xff85201f,0x4e7561ff,0x00000056
+	.long	0x2f000c2e,0x0004ff4f,0x661041ee,0xff9061ff
+	.long	0x000028e8,0x44403d40,0xff56302e,0xff540440
+	.long	0x0042b06e,0xff566c1a,0x302eff56,0xd06f0002
+	.long	0x322eff90,0x02418000,0x80413d40,0xff90201f
+	.long	0x4e75026e,0x8000ff90,0x08ee0000,0xff91201f
+	.long	0x4e75322e,0xff843001,0x02810000,0x7fff0240
+	.long	0x80000040,0x3fff3d40,0xff840c2e,0x0004ff4e
+	.long	0x670a203c,0x00003fff,0x90814e75,0x41eeff84
+	.long	0x61ff0000,0x28764480,0x220060e6,0x0c2e0004
+	.long	0xff4e673a,0x322eff84,0x02810000,0x7fff026e
+	.long	0x8000ff84,0x08010000,0x6712006e,0x3fffff84
+	.long	0x203c0000,0x3fff9081,0xe2804e75,0x006e3ffe
+	.long	0xff84203c,0x00003ffe,0x9081e280,0x4e7541ee
+	.long	0xff8461ff,0x00002824,0x08000000,0x6710006e
+	.long	0x3fffff84,0x06800000,0x3fffe280,0x4e75006e
+	.long	0x3ffeff84,0x06800000,0x3ffee280,0x4e75322e
+	.long	0xff903001,0x02810000,0x7fff0240,0x80000040
+	.long	0x3fff3d40,0xff900c2e,0x0004ff4f,0x670a203c
+	.long	0x00003fff,0x90814e75,0x41eeff90,0x61ff0000
+	.long	0x27ca4480,0x220060e6,0x0c2e0005,0xff4f6732
+	.long	0x0c2e0003,0xff4f673e,0x0c2e0003,0xff4e6714
+	.long	0x08ee0006,0xff7000ae,0x01004080,0xff6441ee
+	.long	0xff6c6042,0x00ae0100,0x0000ff64,0x41eeff6c
+	.long	0x603400ae,0x01004080,0xff6408ee,0x0006ff7c
+	.long	0x41eeff78,0x602041ee,0xff780c2e,0x0005ff4e
+	.long	0x66ff0000,0x000c00ae,0x00004080,0xff6400ae
+	.long	0x01000000,0xff640828,0x00070000,0x670800ae
+	.long	0x08000000,0xff64f210,0xd0804e75,0x00ae0100
+	.long	0x2080ff64,0xf23bd080,0x01700000,0x00084e75
+	.long	0x7fff0000,0xffffffff,0xffffffff,0x2d40ff54
+	.long	0x302eff42,0x4281122e,0xff64e099,0xf2018800
+	.long	0x323b0206,0x4efb1002,0x02340040,0x02f8030c
+	.long	0x03200334,0x0348035c,0x03660352,0x033e032a
+	.long	0x03160302,0x004a0238,0x023a0276,0x0054009e
+	.long	0x0102014c,0x01b201fc,0x021801d8,0x018c0128
+	.long	0x00de007a,0x02b6025a,0xf2810006,0x6000032a
+	.long	0x4e75f28e,0x00066000,0x03204e75,0xf2920022
+	.long	0x082e0000,0xff646700,0x031000ae,0x00008080
+	.long	0xff64082e,0x0007ff62,0x6600032c,0x600002fa
+	.long	0x4e75f29d,0x00066000,0x02f0082e,0x0000ff64
+	.long	0x671200ae,0x00008080,0xff64082e,0x0007ff62
+	.long	0x66000304,0x4e75f293,0x0022082e,0x0000ff64
+	.long	0x670002c6,0x00ae0000,0x8080ff64,0x082e0007
+	.long	0xff626600,0x02e26000,0x02b0082e,0x0000ff64
+	.long	0x671200ae,0x00008080,0xff64082e,0x0007ff62
+	.long	0x660002c4,0x4e75f29c,0x00066000,0x028c082e
+	.long	0x0000ff64,0x671200ae,0x00008080,0xff64082e
+	.long	0x0007ff62,0x660002a0,0x4e75f294,0x0022082e
+	.long	0x0000ff64,0x67000262,0x00ae0000,0x8080ff64
+	.long	0x082e0007,0xff626600,0x027e6000,0x024c4e75
+	.long	0xf29b0006,0x60000242,0x082e0000,0xff646712
+	.long	0x00ae0000,0x8080ff64,0x082e0007,0xff626600
+	.long	0x02564e75,0xf2950022,0x082e0000,0xff646700
+	.long	0x021800ae,0x00008080,0xff64082e,0x0007ff62
+	.long	0x66000234,0x60000202,0x082e0000,0xff646712
+	.long	0x00ae0000,0x8080ff64,0x082e0007,0xff626600
+	.long	0x02164e75,0xf29a0006,0x600001de,0x082e0000
+	.long	0xff646700,0x001400ae,0x00008080,0xff64082e
+	.long	0x0007ff62,0x660001f0,0x4e75f296,0x0022082e
+	.long	0x0000ff64,0x670001b2,0x00ae0000,0x8080ff64
+	.long	0x082e0007,0xff626600,0x01ce6000,0x019c4e75
+	.long	0xf2990006,0x60000192,0x082e0000,0xff646712
+	.long	0x00ae0000,0x8080ff64,0x082e0007,0xff626600
+	.long	0x01a64e75,0xf2970018,0x00ae0000,0x8080ff64
+	.long	0x082e0007,0xff626600,0x018e6000,0x015c4e75
+	.long	0xf2980006,0x60000152,0x00ae0000,0x8080ff64
+	.long	0x082e0007,0xff626600,0x016e4e75,0x6000013a
+	.long	0x4e75082e,0x0000ff64,0x6700012e,0x00ae0000
+	.long	0x8080ff64,0x082e0007,0xff626600,0x014a6000
+	.long	0x0118082e,0x0000ff64,0x671200ae,0x00008080
+	.long	0xff64082e,0x0007ff62,0x6600012c,0x4e75f291
+	.long	0x0022082e,0x0000ff64,0x670000ee,0x00ae0000
+	.long	0x8080ff64,0x082e0007,0xff626600,0x010a6000
+	.long	0x00d8082e,0x0000ff64,0x671200ae,0x00008080
+	.long	0xff64082e,0x0007ff62,0x660000ec,0x4e75f29e
+	.long	0x0022082e,0x0000ff64,0x670000ae,0x00ae0000
+	.long	0x8080ff64,0x082e0007,0xff626600,0x00ca6000
+	.long	0x0098082e,0x0000ff64,0x67000014,0x00ae0000
+	.long	0x8080ff64,0x082e0007,0xff626600,0x00aa4e75
+	.long	0xf2820006,0x60000072,0x4e75f28d,0x00066000
+	.long	0x00684e75,0xf2830006,0x6000005e,0x4e75f28c
+	.long	0x00066000,0x00544e75,0xf2840006,0x6000004a
+	.long	0x4e75f28b,0x00066000,0x00404e75,0xf2850006
+	.long	0x60000036,0x4e75f28a,0x00066000,0x002c4e75
+	.long	0xf2860006,0x60000022,0x4e75f289,0x00066000
+	.long	0x00184e75,0xf2870006,0x6000000e,0x4e75f288
+	.long	0x00066000,0x00044e75,0x122eff41,0x02410007
+	.long	0x61ff0000,0x1d665340,0x61ff0000,0x1dd00c40
+	.long	0xffff6602,0x4e75202e,0xff54d0ae,0xff685880
+	.long	0x2d400006,0x4e751d7c,0x0002ff4a,0x4e75302e
+	.long	0xff424281,0x122eff64,0xe099f201,0x8800323b
+	.long	0x02064efb,0x1002021e,0x004002e4,0x02f002fc
+	.long	0x03080314,0x03200326,0x031a030e,0x030202f6
+	.long	0x02ea0046,0x02200224,0x0260004c,0x009200f8
+	.long	0x013e01a4,0x01ea0202,0x01c4017e,0x011800d2
+	.long	0x006c02a2,0x0240f281,0x02ea4e75,0xf28e02e4
+	.long	0x4e75f292,0x02de082e,0x0000ff64,0x671200ae
+	.long	0x00008080,0xff64082e,0x0007ff62,0x660002cc
+	.long	0x4e75f29d,0x00044e75,0x082e0000,0xff646700
+	.long	0x02b200ae,0x00008080,0xff64082e,0x0007ff62
+	.long	0x660002a8,0x6000029c,0xf293001e,0x082e0000
+	.long	0xff646712,0x00ae0000,0x8080ff64,0x082e0007
+	.long	0xff626600,0x02864e75,0x082e0000,0xff646700
+	.long	0x027200ae,0x00008080,0xff64082e,0x0007ff62
+	.long	0x66000268,0x6000025c,0xf29c0004,0x4e75082e
+	.long	0x0000ff64,0x6700024c,0x00ae0000,0x8080ff64
+	.long	0x082e0007,0xff626600,0x02426000,0x0236f294
+	.long	0x0232082e,0x0000ff64,0x671200ae,0x00008080
+	.long	0xff64082e,0x0007ff62,0x66000220,0x4e75f29b
+	.long	0x00044e75,0x082e0000,0xff646700,0x020600ae
+	.long	0x00008080,0xff64082e,0x0007ff62,0x660001fc
+	.long	0x600001f0,0xf295001e,0x082e0000,0xff646712
+	.long	0x00ae0000,0x8080ff64,0x082e0007,0xff626600
+	.long	0x01da4e75,0x082e0000,0xff646700,0x01c600ae
+	.long	0x00008080,0xff64082e,0x0007ff62,0x660001bc
+	.long	0x600001b0,0xf29a0004,0x4e75082e,0x0000ff64
+	.long	0x670001a0,0x00ae0000,0x8080ff64,0x082e0007
+	.long	0xff626600,0x01966000,0x018af296,0x0186082e
+	.long	0x0000ff64,0x671200ae,0x00008080,0xff64082e
+	.long	0x0007ff62,0x66000174,0x4e75f299,0x00044e75
+	.long	0x082e0000,0xff646700,0x015a00ae,0x00008080
+	.long	0xff64082e,0x0007ff62,0x66000150,0x60000144
+	.long	0xf2970140,0x00ae0000,0x8080ff64,0x082e0007
+	.long	0xff626600,0x01364e75,0xf2980004,0x4e7500ae
+	.long	0x00008080,0xff64082e,0x0007ff62,0x6600011c
+	.long	0x60000110,0x4e756000,0x010a082e,0x0000ff64
+	.long	0x671200ae,0x00008080,0xff64082e,0x0007ff62
+	.long	0x660000f8,0x4e75082e,0x0000ff64,0x670000e4
+	.long	0x00ae0000,0x8080ff64,0x082e0007,0xff626600
+	.long	0x00da6000,0x00cef291,0x0020082e,0x0000ff64
+	.long	0x67000014,0x00ae0000,0x8080ff64,0x082e0007
+	.long	0xff626600,0x00b64e75,0x082e0000,0xff646700
+	.long	0x00a200ae,0x00008080,0xff64082e,0x0007ff62
+	.long	0x66000098,0x6000008c,0xf29e0020,0x082e0000
+	.long	0xff646700,0x001400ae,0x00008080,0xff64082e
+	.long	0x0007ff62,0x66000074,0x4e75082e,0x0000ff64
+	.long	0x67000060,0x00ae0000,0x8080ff64,0x082e0007
+	.long	0xff626600,0x00566000,0x004af282,0x00464e75
+	.long	0xf28d0040,0x4e75f283,0x003a4e75,0xf28c0034
+	.long	0x4e75f284,0x002e4e75,0xf28b0028,0x4e75f285
+	.long	0x00224e75,0xf28a001c,0x4e75f286,0x00164e75
+	.long	0xf2890010,0x4e75f287,0x000a4e75,0xf2880004
+	.long	0x4e751d7c,0x0001ff4a,0x4e751d7c,0x0002ff4a
+	.long	0x4e75302e,0xff424281,0x122eff64,0xe099f201
+	.long	0x8800323b,0x02064efb,0x10020208,0x004002ac
+	.long	0x02cc02ec,0x030c032c,0x034c035c,0x033c031c
+	.long	0x02fc02dc,0x02bc0050,0x020e0214,0x02440060
+	.long	0x00a400fa,0x013e0194,0x01d801f0,0x01b60172
+	.long	0x011c00d8,0x00820278,0x022cf281,0x00084200
+	.long	0x6000032e,0x50c06000,0x0328f28e,0x00084200
+	.long	0x6000031e,0x50c06000,0x0318f292,0x001a4200
+	.long	0x082e0000,0xff646700,0x030800ae,0x00008080
+	.long	0xff646000,0x02f250c0,0x600002f6,0xf29d0008
+	.long	0x42006000,0x02ec50c0,0x082e0000,0xff646700
+	.long	0x02e000ae,0x00008080,0xff646000,0x02caf293
+	.long	0x001a4200,0x082e0000,0xff646700,0x02c400ae
+	.long	0x00008080,0xff646000,0x02ae50c0,0x082e0000
+	.long	0xff646700,0x02ac00ae,0x00008080,0xff646000
+	.long	0x0296f29c,0x00084200,0x60000296,0x50c0082e
+	.long	0x0000ff64,0x6700028a,0x00ae0000,0x8080ff64
+	.long	0x60000274,0xf294001a,0x4200082e,0x0000ff64
+	.long	0x6700026e,0x00ae0000,0x8080ff64,0x60000258
+	.long	0x50c06000,0x025cf29b,0x00084200,0x60000252
+	.long	0x50c0082e,0x0000ff64,0x67000246,0x00ae0000
+	.long	0x8080ff64,0x60000230,0xf295001a,0x4200082e
+	.long	0x0000ff64,0x6700022a,0x00ae0000,0x8080ff64
+	.long	0x60000214,0x50c0082e,0x0000ff64,0x67000212
+	.long	0x00ae0000,0x8080ff64,0x600001fc,0xf29a0008
+	.long	0x42006000,0x01fc50c0,0x082e0000,0xff646700
+	.long	0x01f000ae,0x00008080,0xff646000,0x01daf296
+	.long	0x001a4200,0x082e0000,0xff646700,0x01d400ae
+	.long	0x00008080,0xff646000,0x01be50c0,0x600001c2
+	.long	0xf2990008,0x42006000,0x01b850c0,0x082e0000
+	.long	0xff646700,0x01ac00ae,0x00008080,0xff646000
+	.long	0x0196f297,0x00104200,0x00ae0000,0x8080ff64
+	.long	0x60000184,0x50c06000,0x0188f298,0x00084200
+	.long	0x6000017e,0x50c000ae,0x00008080,0xff646000
+	.long	0x01664200,0x6000016a,0x50c06000,0x01644200
+	.long	0x082e0000,0xff646700,0x015800ae,0x00008080
+	.long	0xff646000,0x014250c0,0x082e0000,0xff646700
+	.long	0x014000ae,0x00008080,0xff646000,0x012af291
+	.long	0x001a4200,0x082e0000,0xff646700,0x012400ae
+	.long	0x00008080,0xff646000,0x010e50c0,0x082e0000
+	.long	0xff646700,0x010c00ae,0x00008080,0xff646000
+	.long	0x00f6f29e,0x001a4200,0x082e0000,0xff646700
+	.long	0x00f000ae,0x00008080,0xff646000,0x00da50c0
+	.long	0x082e0000,0xff646700,0x00d800ae,0x00008080
+	.long	0xff646000,0x00c2f282,0x00084200,0x600000c2
+	.long	0x50c06000,0x00bcf28d,0x00084200,0x600000b2
+	.long	0x50c06000,0x00acf283,0x00084200,0x600000a2
+	.long	0x50c06000,0x009cf28c,0x00084200,0x60000092
+	.long	0x50c06000,0x008cf284,0x00084200,0x60000082
+	.long	0x50c06000,0x007cf28b,0x00084200,0x60000072
+	.long	0x50c06000,0x006cf285,0x00084200,0x60000062
+	.long	0x50c06000,0x005cf28a,0x00084200,0x60000052
+	.long	0x50c06000,0x004cf286,0x00084200,0x60000042
+	.long	0x50c06000,0x003cf289,0x00084200,0x60000032
+	.long	0x50c06000,0x002cf287,0x00084200,0x60000022
+	.long	0x50c06000,0x001cf288,0x00084200,0x60000012
+	.long	0x50c06000,0x000c082e,0x0007ff62,0x66000088
+	.long	0x2040122e,0xff412001,0x02010038,0x66102200
+	.long	0x02410007,0x200861ff,0x0000172a,0x4e750c01
+	.long	0x0018671a,0x0c010020,0x67382008,0x206e000c
+	.long	0x61ffffff,0x5a7c4a81,0x66000054,0x4e752008
+	.long	0x206e000c,0x61ffffff,0x5a684a81,0x66000040
+	.long	0x122eff41,0x02410007,0x700161ff,0x00001722
+	.long	0x4e752008,0x206e000c,0x61ffffff,0x5a444a81
+	.long	0x6600001c,0x122eff41,0x02410007,0x700161ff
+	.long	0x0000174e,0x4e751d7c,0x0002ff4a,0x4e753d7c
+	.long	0x00a1000a,0x60ff0000,0x2b86122e,0xff430241
+	.long	0x0070e809,0x61ff0000,0x15b20280,0x000000ff
+	.long	0x2f00103b,0x09200148,0x2f0061ff,0x00000340
+	.long	0x201f221f,0x67000134,0x082e0005,0xff426700
+	.long	0x00b8082e,0x0004ff42,0x6600001a,0x123b1120
+	.long	0x021e082e,0x00050004,0x670a0c2e,0x0008ff4a
+	.long	0x66024e75,0x22489fc0,0x41d74a01,0x6a0c20ee
+	.long	0xffdc20ee,0xffe020ee,0xffe4e309,0x6a0c20ee
+	.long	0xffe820ee,0xffec20ee,0xfff0e309,0x6a0af210
+	.long	0xf020d1fc,0x0000000c,0xe3096a0a,0xf210f010
+	.long	0xd1fc0000,0x000ce309,0x6a0af210,0xf008d1fc
+	.long	0x0000000c,0xe3096a0a,0xf210f004,0xd1fc0000
+	.long	0x000ce309,0x6a0af210,0xf002d1fc,0x0000000c
+	.long	0xe3096a0a,0xf210f001,0xd1fc0000,0x000c2d49
+	.long	0xff5441d7,0x2f0061ff,0xffff58b2,0x201fdfc0
+	.long	0x4a816600,0x071e4e75,0x2d48ff54,0x9fc043d7
+	.long	0x2f012f00,0x61ffffff,0x587e201f,0x4a816600
+	.long	0x070e221f,0x41d74a01,0x6a0c2d58,0xffdc2d58
+	.long	0xffe02d58,0xffe4e309,0x6a0c2d58,0xffe82d58
+	.long	0xffec2d58,0xfff0e309,0x6a04f218,0xd020e309
+	.long	0x6a04f218,0xd010e309,0x6a04f218,0xd008e309
+	.long	0x6a04f218,0xd004e309,0x6a04f218,0xd002e309
+	.long	0x6a04f218,0xd001dfc0,0x4e754e75,0x000c0c18
+	.long	0x0c181824,0x0c181824,0x18242430,0x0c181824
+	.long	0x18242430,0x18242430,0x2430303c,0x0c181824
+	.long	0x18242430,0x18242430,0x2430303c,0x18242430
+	.long	0x2430303c,0x2430303c,0x303c3c48,0x0c181824
+	.long	0x18242430,0x18242430,0x2430303c,0x18242430
+	.long	0x2430303c,0x2430303c,0x303c3c48,0x18242430
+	.long	0x2430303c,0x2430303c,0x303c3c48,0x2430303c
+	.long	0x303c3c48,0x303c3c48,0x3c484854,0x0c181824
+	.long	0x18242430,0x18242430,0x2430303c,0x18242430
+	.long	0x2430303c,0x2430303c,0x303c3c48,0x18242430
+	.long	0x2430303c,0x2430303c,0x303c3c48,0x2430303c
+	.long	0x303c3c48,0x303c3c48,0x3c484854,0x18242430
+	.long	0x2430303c,0x2430303c,0x303c3c48,0x2430303c
+	.long	0x303c3c48,0x303c3c48,0x3c484854,0x2430303c
+	.long	0x303c3c48,0x303c3c48,0x3c484854,0x303c3c48
+	.long	0x3c484854,0x3c484854,0x48545460,0x008040c0
+	.long	0x20a060e0,0x109050d0,0x30b070f0,0x088848c8
+	.long	0x28a868e8,0x189858d8,0x38b878f8,0x048444c4
+	.long	0x24a464e4,0x149454d4,0x34b474f4,0x0c8c4ccc
+	.long	0x2cac6cec,0x1c9c5cdc,0x3cbc7cfc,0x028242c2
+	.long	0x22a262e2,0x129252d2,0x32b272f2,0x0a8a4aca
+	.long	0x2aaa6aea,0x1a9a5ada,0x3aba7afa,0x068646c6
+	.long	0x26a666e6,0x169656d6,0x36b676f6,0x0e8e4ece
+	.long	0x2eae6eee,0x1e9e5ede,0x3ebe7efe,0x018141c1
+	.long	0x21a161e1,0x119151d1,0x31b171f1,0x098949c9
+	.long	0x29a969e9,0x199959d9,0x39b979f9,0x058545c5
+	.long	0x25a565e5,0x159555d5,0x35b575f5,0x0d8d4dcd
+	.long	0x2dad6ded,0x1d9d5ddd,0x3dbd7dfd,0x038343c3
+	.long	0x23a363e3,0x139353d3,0x33b373f3,0x0b8b4bcb
+	.long	0x2bab6beb,0x1b9b5bdb,0x3bbb7bfb,0x078747c7
+	.long	0x27a767e7,0x179757d7,0x37b777f7,0x0f8f4fcf
+	.long	0x2faf6fef,0x1f9f5fdf,0x3fbf7fff,0x2040302e
+	.long	0xff403200,0x0240003f,0x02810000,0x0007303b
+	.long	0x020a4efb,0x00064afc,0x00400000,0x00000000
+	.long	0x00000000,0x00000000,0x00000000,0x00000000
+	.long	0x00000000,0x00000000,0x00000080,0x0086008c
+	.long	0x00900094,0x0098009c,0x00a000a6,0x00b600c6
+	.long	0x00d200de,0x00ea00f6,0x01020118,0x01260134
+	.long	0x013e0148,0x0152015c,0x0166017a,0x019801b6
+	.long	0x01d201ee,0x020a0226,0x02420260,0x02600260
+	.long	0x02600260,0x02600260,0x026002c0,0x02da02f4
+	.long	0x03140000,0x00000000,0x0000206e,0xffa44e75
+	.long	0x206effa8,0x4e75204a,0x4e75204b,0x4e75204c
+	.long	0x4e75204d,0x4e752056,0x4e75206e,0xffd84e75
+	.long	0x202effa4,0x2200d288,0x2d41ffa4,0x20404e75
+	.long	0x202effa8,0x2200d288,0x2d41ffa8,0x20404e75
+	.long	0x200a2200,0xd2882441,0x20404e75,0x200b2200
+	.long	0xd2882641,0x20404e75,0x200c2200,0xd2882841
+	.long	0x20404e75,0x200d2200,0xd2882a41,0x20404e75
+	.long	0x20162200,0xd2882c81,0x20404e75,0x1d7c0004
+	.long	0xff4a202e,0xffd82200,0xd2882d41,0xffd82040
+	.long	0x4e75202e,0xffa49088,0x2d40ffa4,0x20404e75
+	.long	0x202effa8,0x90882d40,0xffa82040,0x4e75200a
+	.long	0x90882440,0x20404e75,0x200b9088,0x26402040
+	.long	0x4e75200c,0x90882840,0x20404e75,0x200d9088
+	.long	0x2a402040,0x4e752016,0x90882c80,0x20404e75
+	.long	0x1d7c0008,0xff4a202e,0xffd89088,0x2d40ffd8
+	.long	0x20404e75,0x206eff44,0x54aeff44,0x61ffffff
+	.long	0x54a24a81,0x66ffffff,0x68203040,0xd1eeffa4
+	.long	0x4e75206e,0xff4454ae,0xff4461ff,0xffff5484
+	.long	0x4a8166ff,0xffff6802,0x3040d1ee,0xffa84e75
+	.long	0x206eff44,0x54aeff44,0x61ffffff,0x54664a81
+	.long	0x66ffffff,0x67e43040,0xd1ca4e75,0x206eff44
+	.long	0x54aeff44,0x61ffffff,0x544a4a81,0x66ffffff
+	.long	0x67c83040,0xd1cb4e75,0x206eff44,0x54aeff44
+	.long	0x61ffffff,0x542e4a81,0x66ffffff,0x67ac3040
+	.long	0xd1cc4e75,0x206eff44,0x54aeff44,0x61ffffff
+	.long	0x54124a81,0x66ffffff,0x67903040,0xd1cd4e75
+	.long	0x206eff44,0x54aeff44,0x61ffffff,0x53f64a81
+	.long	0x66ffffff,0x67743040,0xd1d64e75,0x206eff44
+	.long	0x54aeff44,0x61ffffff,0x53da4a81,0x66ffffff
+	.long	0x67583040,0xd1eeffd8,0x4e755081,0x61ff0000
+	.long	0x0fda2f00,0x206eff44,0x54aeff44,0x61ffffff
+	.long	0x53b24a81,0x66ffffff,0x6730205f,0x08000008
+	.long	0x660000e6,0x2d40ff54,0x2200e959,0x0241000f
+	.long	0x61ff0000,0x0fa62f02,0x242eff54,0x0802000b
+	.long	0x660248c0,0x2202ef59,0x02810000,0x0003e3a8
+	.long	0x49c2d082,0xd1c0241f,0x4e75206e,0xff4454ae
+	.long	0xff4461ff,0xffff535c,0x4a8166ff,0xffff66da
+	.long	0x30404e75,0x206eff44,0x58aeff44,0x61ffffff
+	.long	0x53584a81,0x66ffffff,0x66c02040,0x4e75206e
+	.long	0xff4454ae,0xff4461ff,0xffff5328,0x4a8166ff
+	.long	0xffff66a6,0x3040d1ee,0xff445588,0x4e75206e
+	.long	0xff4454ae,0xff4461ff,0xffff5308,0x4a8166ff
+	.long	0xffff6686,0x206eff44,0x55880800,0x00086600
+	.long	0x00382d40,0xff542200,0xe9590241,0x000f61ff
+	.long	0x00000ef8,0x2f02242e,0xff540802,0x000b6602
+	.long	0x48c02202,0xef590281,0x00000003,0xe3a849c2
+	.long	0xd082d1c0,0x241f4e75,0x08000006,0x670c48e7
+	.long	0x3c002a00,0x26084282,0x60282d40,0xff54e9c0
+	.long	0x140461ff,0x00000eb4,0x48e73c00,0x24002a2e
+	.long	0xff542608,0x0805000b,0x660248c2,0xe9c50542
+	.long	0xe1aa0805,0x00076702,0x4283e9c5,0x06820c00
+	.long	0x00026d34,0x6718206e,0xff4458ae,0xff4461ff
+	.long	0xffff5276,0x4a8166ff,0x000000b0,0x6018206e
+	.long	0xff4454ae,0xff4461ff,0xffff5248,0x4a8166ff
+	.long	0x00000098,0x48c0d680,0xe9c50782,0x6700006e
+	.long	0x0c000002,0x6d346718,0x206eff44,0x58aeff44
+	.long	0x61ffffff,0x52344a81,0x66ff0000,0x006e601c
+	.long	0x206eff44,0x54aeff44,0x61ffffff,0x52064a81
+	.long	0x66ff0000,0x005648c0,0x60024280,0x28000805
+	.long	0x00026714,0x204361ff,0xffff5240,0x4a816600
+	.long	0x0028d082,0xd0846018,0xd6822043,0x61ffffff
+	.long	0x522a4a81,0x66000012,0xd0846004,0xd6822003
+	.long	0x20404cdf,0x003c4e75,0x20434cdf,0x003c303c
+	.long	0x010160ff,0xffff6582,0x4cdf003c,0x60ffffff
+	.long	0x652861ff,0x000023c6,0x303c00e1,0x600a61ff
+	.long	0x000023ba,0x303c0161,0x206eff54,0x60ffffff
+	.long	0x6558102e,0xff420c00,0x009c6700,0x00b20c00
+	.long	0x00986700,0x00740c00,0x00946736,0x206eff44
+	.long	0x58aeff44,0x61ffffff,0x51704a81,0x66ffffff
+	.long	0x64d82d40,0xff64206e,0xff4458ae,0xff4461ff
+	.long	0xffff5156,0x4a8166ff,0xffff64be,0x2d40ff68
+	.long	0x4e75206e,0xff4458ae,0xff4461ff,0xffff513a
+	.long	0x4a8166ff,0xffff64a2,0x2d40ff60,0x206eff44
+	.long	0x58aeff44,0x61ffffff,0x51204a81,0x66ffffff
+	.long	0x64882d40,0xff684e75,0x206eff44,0x58aeff44
+	.long	0x61ffffff,0x51044a81,0x66ffffff,0x646c2d40
+	.long	0xff60206e,0xff4458ae,0xff4461ff,0xffff50ea
+	.long	0x4a8166ff,0xffff6452,0x2d40ff64,0x4e75206e
+	.long	0xff4458ae,0xff4461ff,0xffff50ce,0x4a8166ff
+	.long	0xffff6436,0x2d40ff60,0x206eff44,0x58aeff44
+	.long	0x61ffffff,0x50b44a81,0x66ffffff,0x641c2d40
+	.long	0xff64206e,0xff4458ae,0xff4461ff,0xffff509a
+	.long	0x4a8166ff,0xffff6402,0x2d40ff68,0x4e752040
+	.long	0x102eff41,0x22000240,0x00380281,0x00000007
+	.long	0x0c000018,0x67240c00,0x0020672c,0x80410c00
+	.long	0x003c6706,0x206e000c,0x4e751d7c,0x0080ff4a
+	.long	0x41f60162,0xff680004,0x4e752008,0x61ff0000
+	.long	0x0d70206e,0x000c4e75,0x200861ff,0x00000db2
+	.long	0x206e000c,0x0c00000c,0x67024e75,0x51882d48
+	.long	0x000c4e75,0x102eff41,0x22000240,0x00380281
+	.long	0x00000007,0x0c000018,0x670e0c00,0x00206700
+	.long	0x0076206e,0x000c4e75,0x323b120e,0x206e000c
+	.long	0x4efb1006,0x4afc0008,0x0010001a,0x0024002c
+	.long	0x0034003c,0x0044004e,0x06ae0000,0x000cffa4
+	.long	0x4e7506ae,0x0000000c,0xffa84e75,0xd5fc0000
+	.long	0x000c4e75,0xd7fc0000,0x000c4e75,0xd9fc0000
+	.long	0x000c4e75,0xdbfc0000,0x000c4e75,0x06ae0000
+	.long	0x000cffd4,0x4e751d7c,0x0004ff4a,0x06ae0000
+	.long	0x000cffd8,0x4e75323b,0x1214206e,0x000c5188
+	.long	0x51ae000c,0x4efb1006,0x4afc0008,0x00100016
+	.long	0x001c0020,0x00240028,0x002c0032,0x2d48ffa4
+	.long	0x4e752d48,0xffa84e75,0x24484e75,0x26484e75
+	.long	0x28484e75,0x2a484e75,0x2d48ffd4,0x4e752d48
+	.long	0xffd81d7c,0x0008ff4a,0x4e75082e,0x0006ff42
+	.long	0x6664102e,0xff430800,0x0005672c,0x08000004
+	.long	0x670a0240,0x007f0c40,0x0038661c,0xe9ee0183
+	.long	0xff4261ff,0x00000d6a,0x61ff0000,0x12060c00
+	.long	0x00066722,0x1d40ff4f,0xe9ee00c3,0xff4261ff
+	.long	0x00000cbe,0x61ff0000,0x11ea0c00,0x0006670e
+	.long	0x1d40ff4e,0x4e7561ff,0x00001148,0x60d661ff
+	.long	0x00001140,0x60ea302e,0xff420800,0x0005672c
+	.long	0x08000004,0x670a0240,0x007f0c40,0x0038661c
+	.long	0xe9ee0183,0xff4261ff,0x00000d06,0x61ff0000
+	.long	0x11a20c00,0x00066726,0x1d40ff4f,0xe9ee00c3
+	.long	0xff42e9ee,0x1283ff40,0x660000be,0x422eff4e
+	.long	0xe9ee1343,0xff40303b,0x02124efb,0x000e61ff
+	.long	0x000010e0,0x60d24afc,0x00080010,0x006a0000
+	.long	0x0000002e,0x0000004c,0x000061ff,0x00000a5c
+	.long	0xf2004000,0xf22ef080,0xff6cf281,0x00044e75
+	.long	0x1d7c0001,0xff4e4e75,0x61ff0000,0x0a3ef200
+	.long	0x5000f22e,0xf080ff6c,0xf2810004,0x4e751d7c
+	.long	0x0001ff4e,0x4e7561ff,0x00000a20,0xf2005800
+	.long	0xf22ef080,0xff6cf281,0x00044e75,0x1d7c0001
+	.long	0xff4e4e75,0x61ff0000,0x0a022d40,0xff5441ee
+	.long	0xff5461ff,0x000011de,0x1d40ff4e,0x0c000005
+	.long	0x670001a4,0x0c000004,0x6700015e,0xf2104400
+	.long	0xf22ef080,0xff6c4e75,0x422eff4e,0x303b020a
+	.long	0x4efb0006,0x4afc0008,0x001000e2,0x027202b0
+	.long	0x005601a0,0x009c0000,0x700461ff,0xfffffd22
+	.long	0x0c2e0080,0xff4a6726,0x61ffffff,0x4dde4a81
+	.long	0x66ff0000,0x1eecf200,0x4000f22e,0xf080ff6c
+	.long	0xf2810004,0x4e751d7c,0x0001ff4e,0x4e7561ff
+	.long	0xffff4d76,0x4a8166ff,0xffff6e8a,0x60d87002
+	.long	0x61ffffff,0xfcdc0c2e,0x0080ff4a,0x672661ff
+	.long	0xffff4d82,0x4a8166ff,0x00001e98,0xf2005000
+	.long	0xf22ef080,0xff6cf281,0x00044e75,0x1d7c0001
+	.long	0xff4e4e75,0x61ffffff,0x4d1a4a81,0x66ffffff
+	.long	0x6e4460d8,0x700161ff,0xfffffc96,0x0c2e0080
+	.long	0xff4a6726,0x61ffffff,0x4d264a81,0x66ff0000
+	.long	0x1e42f200,0x5800f22e,0xf080ff6c,0xf2810004
+	.long	0x4e751d7c,0x0001ff4e,0x4e7561ff,0xffff4cd4
+	.long	0x4a8166ff,0xffff6dfe,0x60d87004,0x61ffffff
+	.long	0xfc500c2e,0x0080ff4a,0x673e61ff,0xffff4d0c
+	.long	0x2d40ff54,0x4a8166ff,0x00001e16,0x41eeff54
+	.long	0x61ff0000,0x10a01d40,0xff4e0c00,0x00046700
+	.long	0x00280c00,0x00056700,0x005ef22e,0x4400ff54
+	.long	0xf22ef080,0xff6c4e75,0x61ffffff,0x4c8c4a81
+	.long	0x66ffffff,0x6da060c4,0x426eff6c,0xe9d00257
+	.long	0xe1882d40,0xff7042ae,0xff74426e,0xff6c0810
+	.long	0x00076706,0x08ee0007,0xff6c41ee,0xff6c61ff
+	.long	0x00000e78,0x323c3f81,0x9240836e,0xff6c1d7c
+	.long	0x0000ff4e,0x4e753d7c,0x7fffff6c,0xe9d00257
+	.long	0xe1882d40,0xff7042ae,0xff740810,0x00076706
+	.long	0x08ee0007,0xff6c4e75,0x700861ff,0xfffffb92
+	.long	0x0c2e0080,0xff4a6740,0x43eeff54,0x700861ff
+	.long	0xffff4bc4,0x4a8166ff,0x00001d64,0x41eeff54
+	.long	0x61ff0000,0x0f701d40,0xff4e0c00,0x00046700
+	.long	0x002e0c00,0x00056700,0x0068f22e,0x5400ff54
+	.long	0xf22ef080,0xff6c4e75,0x43eeff54,0x700861ff
+	.long	0xffff4b6e,0x4a8166ff,0xffff6cda,0x60be426e
+	.long	0xff6ce9d0,0x031f2d40,0xff70e9e8,0x02d50004
+	.long	0x720be3a8,0x2d40ff74,0x08100007,0x670608ee
+	.long	0x0007ff6c,0x41eeff6c,0x61ff0000,0x0dae323c
+	.long	0x3c019240,0x836eff6c,0x1d7c0000,0xff4e4e75
+	.long	0x3d7c7fff,0xff6ce9d0,0x031f2d40,0xff70e9e8
+	.long	0x02d50004,0x720be3a8,0x2d40ff74,0x08100007
+	.long	0x670608ee,0x0007ff6c,0x4e75700c,0x61ffffff
+	.long	0xfac043ee,0xff6c700c,0x61ffffff,0x4afa4a81
+	.long	0x66ff0000,0x1ca841ee,0xff6c61ff,0x00000e24
+	.long	0x0c000006,0x67061d40,0xff4e4e75,0x61ff0000
+	.long	0x0d821d40,0xff4e4e75,0x61ff0000,0x125441ee
+	.long	0xff6c61ff,0x00000dfc,0x0c000006,0x67061d40
+	.long	0xff4e4e75,0x61ff0000,0x0d5a1d40,0xff4e4e75
+	.long	0xe9ee10c3,0xff42327b,0x120a4efb,0x98064afc
+	.long	0x000800e0,0x01e00148,0x06200078,0x041a0010
+	.long	0x06204a2e,0xff4e664c,0xf228d080,0x0000f200
+	.long	0x9000f200,0x7800f23c,0x90000000,0x0000f201
+	.long	0xa800836e,0xff66122e,0xff410201,0x00386714
+	.long	0x206e000c,0x61ffffff,0x4ae84a81,0x66ff0000
+	.long	0x1c0a4e75,0x122eff41,0x02410007,0x61ff0000
+	.long	0x07644e75,0x22280000,0x02818000,0x00000081
+	.long	0x00800000,0xf2014400,0x60a44a2e,0xff4e664c
+	.long	0xf228d080,0x0000f200,0x9000f200,0x7000f23c
+	.long	0x90000000,0x0000f201,0xa800836e,0xff66122e
+	.long	0xff410201,0x00386714,0x206e000c,0x61ffffff
+	.long	0x4a964a81,0x66ff0000,0x1bb04e75,0x122eff41
+	.long	0x02410007,0x61ff0000,0x06c04e75,0x22280000
+	.long	0x02818000,0x00000081,0x00800000,0xf2014400
+	.long	0x60a44a2e,0xff4e664c,0xf228d080,0x0000f200
+	.long	0x9000f200,0x6000f23c,0x90000000,0x0000f201
+	.long	0xa800836e,0xff66122e,0xff410201,0x00386714
+	.long	0x206e000c,0x61ffffff,0x4a444a81,0x66ff0000
+	.long	0x1b564e75,0x122eff41,0x02410007,0x61ff0000
+	.long	0x061c4e75,0x22280000,0x02818000,0x00000081
+	.long	0x00800000,0xf2014400,0x60a43d68,0x0000ff84
+	.long	0x426eff86,0x2d680004,0xff882d68,0x0008ff8c
+	.long	0xf228d080,0x000061ff,0xfffff94c,0x224841ee
+	.long	0xff84700c,0x0c2e0008,0xff4a6726,0x61ffffff
+	.long	0x492c4a81,0x66000052,0x4a2eff4e,0x66024e75
+	.long	0x08ee0003,0xff66102e,0xff620200,0x000a6616
+	.long	0x4e7561ff,0xffff5788,0x4a816600,0x002c4a2e
+	.long	0xff4e66dc,0x4e7541ee,0xff8461ff,0x00000b3c
+	.long	0x44400240,0x7fff026e,0x8000ff84,0x816eff84
+	.long	0xf22ed040,0xff844e75,0x2caeffd4,0x60ff0000
+	.long	0x1ab20200,0x00300000,0x00402d40,0xff5c3028
+	.long	0x00000240,0x7fff0c40,0x407e6e00,0x00e66700
+	.long	0x01520c40,0x3f816d00,0x0058f228,0xd0800000
+	.long	0xf22e9000,0xff5cf23c,0x88000000,0x0000f200
+	.long	0x6400f23c,0x90000000,0x0000f201,0xa800836e
+	.long	0xff66122e,0xff410201,0x00386714,0x206e000c
+	.long	0x61ffffff,0x49184a81,0x66ff0000,0x1a2a4e75
+	.long	0x122eff41,0x02410007,0x61ff0000,0x04f04e75
+	.long	0x08ee0003,0xff663d68,0x0000ff84,0x2d680004
+	.long	0xff882d68,0x0008ff8c,0x2f084280,0x0c2e0004
+	.long	0xff4e660a,0x41eeff84,0x61ff0000,0x0a6e41ee
+	.long	0xff84222e,0xff5c61ff,0x00000c86,0x41eeff84
+	.long	0x61ff0000,0x034c122e,0xff410201,0x00386714
+	.long	0x206e000c,0x61ffffff,0x48a44a81,0x66ff0000
+	.long	0x19b6600e,0x122eff41,0x02410007,0x61ff0000
+	.long	0x047c122e,0xff620201,0x000a6600,0x00b8588f
+	.long	0x4e754a28,0x0007660e,0x4aa80008,0x6608006e
+	.long	0x1048ff66,0x6006006e,0x1248ff66,0x2f084a28
+	.long	0x00005bc1,0x202eff5c,0x61ff0000,0x0d12f210
+	.long	0xd080f200,0x6400122e,0xff410201,0x00386714
+	.long	0x206e000c,0x61ffffff,0x48344a81,0x66ff0000
+	.long	0x1946600e,0x122eff41,0x02410007,0x61ff0000
+	.long	0x040c122e,0xff620201,0x000a6600,0x007c588f
+	.long	0x4e753228,0x00000241,0x80000041,0x3fff3d41
+	.long	0xff842d68,0x0004ff88,0x2d680008,0xff8cf22e
+	.long	0x9000ff5c,0xf22e4800,0xff84f23c,0x90000000
+	.long	0x0000f200,0x0018f23c,0x58380002,0xf294fe7c
+	.long	0x6000ff50,0x205f3d68,0x0000ff84,0x2d680004
+	.long	0xff882d68,0x0008ff8c,0x0c2e0004,0xff4e662c
+	.long	0x41eeff84,0x61ff0000,0x09424480,0x02407fff
+	.long	0xefee004f,0xff846014,0x205f3d68,0x0000ff84
+	.long	0x2d680004,0xff882d68,0x0008ff8c,0x08ae0007
+	.long	0xff8456ee,0xff8641ee,0xff84122e,0xff5fe809
+	.long	0x0241000c,0x4841122e,0xff5fe809,0x02410003
+	.long	0x428061ff,0x00000782,0x4a2eff86,0x670608ee
+	.long	0x0007ff84,0xf22ed040,0xff844e75,0x02000030
+	.long	0x00000080,0x2d40ff5c,0x30280000,0x02407fff
+	.long	0x0c4043fe,0x6e0000c8,0x67000120,0x0c403c01
+	.long	0x6d000046,0xf228d080,0x0000f22e,0x9000ff5c
+	.long	0xf23c8800,0x00000000,0xf22e7400,0xff54f23c
+	.long	0x90000000,0x0000f200,0xa800816e,0xff66226e
+	.long	0x000c41ee,0xff547008,0x61ffffff,0x46304a81
+	.long	0x66ff0000,0x18004e75,0x08ee0003,0xff663d68
+	.long	0x0000ff84,0x2d680004,0xff882d68,0x0008ff8c
+	.long	0x2f084280,0x0c2e0004,0xff4e660a,0x41eeff84
+	.long	0x61ff0000,0x084641ee,0xff84222e,0xff5c61ff
+	.long	0x00000a5e,0x41eeff84,0x61ff0000,0x00d22d40
+	.long	0xff542d41,0xff58226e,0x000c41ee,0xff547008
+	.long	0x61ffffff,0x45c84a81,0x66ff0000,0x1798122e
+	.long	0xff620201,0x000a6600,0xfe9c588f,0x4e753028
+	.long	0x000a0240,0x07ff6608,0x006e1048,0xff666006
+	.long	0x006e1248,0xff662f08,0x4a280000,0x5bc1202e
+	.long	0xff5c61ff,0x00000af8,0xf210d080,0xf22e7400
+	.long	0xff54226e,0x000c41ee,0xff547008,0x61ffffff
+	.long	0x456c4a81,0x66ff0000,0x173c122e,0xff620201
+	.long	0x000a6600,0xfe74588f,0x4e753228,0x00000241
+	.long	0x80000041,0x3fff3d41,0xff842d68,0x0004ff88
+	.long	0x2d680008,0xff8cf22e,0x9000ff5c,0xf22e4800
+	.long	0xff84f23c,0x90000000,0x0000f200,0x0018f23c
+	.long	0x58380002,0xf294feae,0x6000ff64,0x42803028
+	.long	0x00000440,0x3fff0640,0x03ff4a28,0x00046b02
+	.long	0x53404840,0xe9884a28,0x00006a04,0x08c0001f
+	.long	0x22280004,0xe9c11054,0x80812d40,0xff542228
+	.long	0x00047015,0xe1a92d41,0xff582228,0x0008e9c1
+	.long	0x0015222e,0xff588280,0x202eff54,0x4e754280
+	.long	0x30280000,0x04403fff,0x0640007f,0x4a280004
+	.long	0x6b025340,0x4840ef88,0x4a280000,0x6a0408c0
+	.long	0x001f2228,0x00040281,0x7fffff00,0xe0898081
+	.long	0x4e7561ff,0xfffff490,0x2f08102e,0xff4e6600
+	.long	0x0082082e,0x0004ff42,0x6712122e,0xff43e809
+	.long	0x02410007,0x61ff0000,0x00926004,0x102eff43
+	.long	0xebc00647,0x2f0041ee,0xff6c61ff,0x00000ed0
+	.long	0x02aecfff,0xf00fff84,0x201f4a2e,0xff876616
+	.long	0x4aaeff88,0x66104aae,0xff8c660a,0x4a806606
+	.long	0x026ef000,0xff8441ee,0xff84225f,0x700c0c2e
+	.long	0x0008ff4a,0x670e61ff,0xffff4412,0x4a816600
+	.long	0xfb384e75,0x61ffffff,0x52864a81,0x6600fb2a
+	.long	0x4e750c00,0x00046700,0xff7a41ee,0xff6c426e
+	.long	0xff6e0c00,0x00056702,0x60c0006e,0x4080ff66
+	.long	0x08ee0006,0xff7060b2,0x303b1206,0x4efb0002
+	.long	0x00200026,0x002c0030,0x00340038,0x003c0040
+	.long	0x0044004a,0x00500054,0x0058005c,0x00600064
+	.long	0x202eff9c,0x4e75202e,0xffa04e75,0x20024e75
+	.long	0x20034e75,0x20044e75,0x20054e75,0x20064e75
+	.long	0x20074e75,0x202effa4,0x4e75202e,0xffa84e75
+	.long	0x200a4e75,0x200b4e75,0x200c4e75,0x200d4e75
+	.long	0x20164e75,0x202effd8,0x4e75323b,0x12064efb
+	.long	0x10020010,0x0016001c,0x00200024,0x0028002c
+	.long	0x00302d40,0xff9c4e75,0x2d40ffa0,0x4e752400
+	.long	0x4e752600,0x4e752800,0x4e752a00,0x4e752c00
+	.long	0x4e752e00,0x4e75323b,0x12064efb,0x10020010
+	.long	0x0016001c,0x00200024,0x0028002c,0x00303d40
+	.long	0xff9e4e75,0x3d40ffa2,0x4e753400,0x4e753600
+	.long	0x4e753800,0x4e753a00,0x4e753c00,0x4e753e00
+	.long	0x4e75323b,0x12064efb,0x10020010,0x0016001c
+	.long	0x00200024,0x0028002c,0x00301d40,0xff9f4e75
+	.long	0x1d40ffa3,0x4e751400,0x4e751600,0x4e751800
+	.long	0x4e751a00,0x4e751c00,0x4e751e00,0x4e75323b
+	.long	0x12064efb,0x10020010,0x0016001c,0x00200024
+	.long	0x0028002c,0x0030d1ae,0xffa44e75,0xd1aeffa8
+	.long	0x4e75d5c0,0x4e75d7c0,0x4e75d9c0,0x4e75dbc0
+	.long	0x4e75d196,0x4e751d7c,0x0004ff4a,0x0c000001
+	.long	0x6706d1ae,0xffd84e75,0x54aeffd8,0x4e75323b
+	.long	0x12064efb,0x10020010,0x0016001c,0x00200024
+	.long	0x0028002c,0x003091ae,0xffa44e75,0x91aeffa8
+	.long	0x4e7595c0,0x4e7597c0,0x4e7599c0,0x4e759bc0
+	.long	0x4e759196,0x4e751d7c,0x0008ff4a,0x0c000001
+	.long	0x670691ae,0xffd84e75,0x55aeffd8,0x4e75303b
+	.long	0x02064efb,0x00020010,0x00280040,0x004c0058
+	.long	0x00640070,0x007c2d6e,0xffdcff6c,0x2d6effe0
+	.long	0xff702d6e,0xffe4ff74,0x41eeff6c,0x4e752d6e
+	.long	0xffe8ff6c,0x2d6effec,0xff702d6e,0xfff0ff74
+	.long	0x41eeff6c,0x4e75f22e,0xf020ff6c,0x41eeff6c
+	.long	0x4e75f22e,0xf010ff6c,0x41eeff6c,0x4e75f22e
+	.long	0xf008ff6c,0x41eeff6c,0x4e75f22e,0xf004ff6c
+	.long	0x41eeff6c,0x4e75f22e,0xf002ff6c,0x41eeff6c
+	.long	0x4e75f22e,0xf001ff6c,0x41eeff6c,0x4e75303b
+	.long	0x02064efb,0x00020010,0x00280040,0x004c0058
+	.long	0x00640070,0x007c2d6e,0xffdcff78,0x2d6effe0
+	.long	0xff7c2d6e,0xffe4ff80,0x41eeff78,0x4e752d6e
+	.long	0xffe8ff78,0x2d6effec,0xff7c2d6e,0xfff0ff80
+	.long	0x41eeff78,0x4e75f22e,0xf020ff78,0x41eeff78
+	.long	0x4e75f22e,0xf010ff78,0x41eeff78,0x4e75f22e
+	.long	0xf008ff78,0x41eeff78,0x4e75f22e,0xf004ff78
+	.long	0x41eeff78,0x4e75f22e,0xf002ff78,0x41eeff78
+	.long	0x4e75f22e,0xf001ff78,0x41eeff78,0x4e75303b
+	.long	0x02064efb,0x00020010,0x00180020,0x002a0034
+	.long	0x003e0048,0x0052f22e,0xf080ffdc,0x4e75f22e
+	.long	0xf080ffe8,0x4e75f227,0xe001f21f,0xd0204e75
+	.long	0xf227e001,0xf21fd010,0x4e75f227,0xe001f21f
+	.long	0xd0084e75,0xf227e001,0xf21fd004,0x4e75f227
+	.long	0xe001f21f,0xd0024e75,0xf227e001,0xf21fd001
+	.long	0x4e750000,0x3f813c01,0xe408323b,0x02f63001
+	.long	0x90680000,0x0c400042,0x6a164280,0x082e0001
+	.long	0xff666704,0x08c0001d,0x61ff0000,0x001a4e75
+	.long	0x203c2000,0x00003141,0x000042a8,0x000442a8
+	.long	0x00084e75,0x2d680008,0xff542d40,0xff582001
+	.long	0x92680000,0x6f100c41,0x00206d10,0x0c410040
+	.long	0x6d506000,0x009a202e,0xff584e75,0x2f023140
+	.long	0x00007020,0x90410c41,0x001d6d08,0x142eff58
+	.long	0x852eff57,0xe9e82020,0x0004e9e8,0x18000004
+	.long	0xe9ee0800,0xff542142,0x00042141,0x0008e8c0
+	.long	0x009e6704,0x08c0001d,0x0280e000,0x0000241f
+	.long	0x4e752f02,0x31400000,0x04410020,0x70209041
+	.long	0x142eff58,0x852eff57,0xe9e82020,0x0004e9e8
+	.long	0x18000004,0xe8c1009e,0x660ce8ee,0x081fff54
+	.long	0x66042001,0x60062001,0x08c0001d,0x42a80004
+	.long	0x21420008,0x0280e000,0x0000241f,0x4e753140
+	.long	0x00000c41,0x00416d12,0x672442a8,0x000442a8
+	.long	0x0008203c,0x20000000,0x4e752028,0x00042200
+	.long	0x0280c000,0x00000281,0x3fffffff,0x60122028
+	.long	0x00040280,0x80000000,0xe2880281,0x7fffffff
+	.long	0x66164aa8,0x00086610,0x4a2eff58,0x660a42a8
+	.long	0x000442a8,0x00084e75,0x08c0001d,0x42a80004
+	.long	0x42a80008,0x4e7561ff,0x00000110,0x4a806700
+	.long	0x00fa006e,0x0208ff66,0x327b1206,0x4efb9802
+	.long	0x004000ea,0x00240008,0x4a280002,0x6b0000dc
+	.long	0x70ff4841,0x0c010004,0x6700003e,0x6e000094
+	.long	0x60000064,0x4a280002,0x6a0000c0,0x70ff4841
+	.long	0x0c010004,0x67000022,0x6e000078,0x60000048
+	.long	0xe3806400,0x00a64841,0x0c010004,0x6700000a
+	.long	0x6e000060,0x60000030,0x06a80000,0x01000004
+	.long	0x640ce4e8,0x0004e4e8,0x00065268,0x00004a80
+	.long	0x66060268,0xfe000006,0x02a8ffff,0xff000004
+	.long	0x42a80008,0x4e7552a8,0x0008641a,0x52a80004
+	.long	0x6414e4e8,0x0004e4e8,0x0006e4e8,0x0008e4e8
+	.long	0x000a5268,0x00004a80,0x66060228,0x00fe000b
+	.long	0x4e7506a8,0x00000800,0x0008641a,0x52a80004
+	.long	0x6414e4e8,0x0004e4e8,0x0006e4e8,0x0008e4e8
+	.long	0x000a5268,0x00004a80,0x66060268,0xf000000a
+	.long	0x02a8ffff,0xf8000008,0x4e754841,0x0c010004
+	.long	0x6700ff86,0x6eea4e75,0x48414a01,0x66044841
+	.long	0x4e7548e7,0x30000c01,0x00046622,0xe9e83602
+	.long	0x0004741e,0xe5ab2428,0x00040282,0x0000003f
+	.long	0x66284aa8,0x00086622,0x4a80661e,0x6020e9e8
+	.long	0x35420008,0x741ee5ab,0x24280008,0x02820000
+	.long	0x01ff6606,0x4a806602,0x600408c3,0x001d2003
+	.long	0x4cdf000c,0x48414e75,0x2f022f03,0x20280004
+	.long	0x22280008,0xedc02000,0x671ae5a8,0xe9c13022
+	.long	0x8083e5a9,0x21400004,0x21410008,0x2002261f
+	.long	0x241f4e75,0xedc12000,0xe5a90682,0x00000020
+	.long	0x21410004,0x42a80008,0x2002261f,0x241f4e75
+	.long	0xede80000,0x0004660e,0xede80000,0x00086700
+	.long	0x00740640,0x00204281,0x32280000,0x02417fff
+	.long	0xb0416e1c,0x92403028,0x00000240,0x80008240
+	.long	0x31410000,0x61ffffff,0xff82103c,0x00004e75
+	.long	0x0c010020,0x6e20e9e8,0x08400004,0x21400004
+	.long	0x20280008,0xe3a82140,0x00080268,0x80000000
+	.long	0x103c0004,0x4e750441,0x00202028,0x0008e3a8
+	.long	0x21400004,0x42a80008,0x02688000,0x0000103c
+	.long	0x00044e75,0x02688000,0x0000103c,0x00014e75
+	.long	0x30280000,0x02407fff,0x0c407fff,0x67480828
+	.long	0x00070004,0x6706103c,0x00004e75,0x4a406618
+	.long	0x4aa80004,0x660c4aa8,0x00086606,0x103c0001
+	.long	0x4e75103c,0x00044e75,0x4aa80004,0x66124aa8
+	.long	0x0008660c,0x02688000,0x0000103c,0x00014e75
+	.long	0x103c0006,0x4e754aa8,0x00086612,0x20280004
+	.long	0x02807fff,0xffff6606,0x103c0002,0x4e750828
+	.long	0x00060004,0x6706103c,0x00034e75,0x103c0005
+	.long	0x4e752028,0x00002200,0x02807ff0,0x0000670e
+	.long	0x0c807ff0,0x00006728,0x103c0000,0x4e750281
+	.long	0x000fffff,0x66ff0000,0x00144aa8,0x000466ff
+	.long	0x0000000a,0x103c0001,0x4e75103c,0x00044e75
+	.long	0x0281000f,0xffff66ff,0x00000014,0x4aa80004
+	.long	0x66ff0000,0x000a103c,0x00024e75,0x08010013
+	.long	0x66ff0000,0x000a103c,0x00054e75,0x103c0003
+	.long	0x4e752028,0x00002200,0x02807f80,0x0000670e
+	.long	0x0c807f80,0x0000671e,0x103c0000,0x4e750281
+	.long	0x007fffff,0x66ff0000,0x000a103c,0x00014e75
+	.long	0x103c0004,0x4e750281,0x007fffff,0x66ff0000
+	.long	0x000a103c,0x00024e75,0x08010016,0x66ff0000
+	.long	0x000a103c,0x00054e75,0x103c0003,0x4e752f01
+	.long	0x08280007,0x000056e8,0x00023228,0x00000241
+	.long	0x7fff9240,0x31410000,0x2f08202f,0x00040240
+	.long	0x00c0e848,0x61ffffff,0xfae22057,0x322f0006
+	.long	0x024100c0,0xe8494841,0x322f0006,0x02410030
+	.long	0xe84961ff,0xfffffc22,0x205f08a8,0x00070000
+	.long	0x4a280002,0x670a08e8,0x00070000,0x42280002
+	.long	0x42804aa8,0x0004660a,0x4aa80008,0x660408c0
+	.long	0x0002082e,0x0001ff66,0x670608ee,0x0005ff67
+	.long	0x588f4e75,0x2f010828,0x00070000,0x56e80002
+	.long	0x32280000,0x02417fff,0x92403141,0x00002f08
+	.long	0x428061ff,0xfffffa64,0x2057323c,0x00044841
+	.long	0x322f0006,0x02410030,0xe84961ff,0xfffffbaa
+	.long	0x205f08a8,0x00070000,0x4a280002,0x670a08e8
+	.long	0x00070000,0x42280002,0x42804aa8,0x0004660a
+	.long	0x4aa80008,0x660408c0,0x0002082e,0x0001ff66
+	.long	0x670608ee,0x0005ff67,0x588f4e75,0x02410010
+	.long	0xe8088200,0x3001e309,0x600e0241,0x00108200
+	.long	0x48408200,0x3001e309,0x103b0008,0x41fb1620
+	.long	0x4e750200,0x00020200,0x00020200,0x00020000
+	.long	0x00000a08,0x0a080a08,0x0a080a08,0x0a087fff
+	.long	0x00000000,0x00000000,0x00000000,0x00007ffe
+	.long	0x0000ffff,0xffffffff,0xffff0000,0x00007ffe
+	.long	0x0000ffff,0xffffffff,0xffff0000,0x00007fff
+	.long	0x00000000,0x00000000,0x00000000,0x00007fff
+	.long	0x00000000,0x00000000,0x00000000,0x0000407e
+	.long	0x0000ffff,0xff000000,0x00000000,0x0000407e
+	.long	0x0000ffff,0xff000000,0x00000000,0x00007fff
+	.long	0x00000000,0x00000000,0x00000000,0x00007fff
+	.long	0x00000000,0x00000000,0x00000000,0x000043fe
+	.long	0x0000ffff,0xffffffff,0xf8000000,0x000043fe
+	.long	0x0000ffff,0xffffffff,0xf8000000,0x00007fff
+	.long	0x00000000,0x00000000,0x00000000,0x00000000
+	.long	0x00000000,0x00000000,0x00000000,0x00000000
+	.long	0x00000000,0x00000000,0x00000000,0x00000000
+	.long	0x00000000,0x00000000,0x00000000,0x00000000
+	.long	0x00000000,0x00000000,0x00000000,0x0000ffff
+	.long	0x00000000,0x00000000,0x00000000,0x0000fffe
+	.long	0x0000ffff,0xffffffff,0xffff0000,0x0000ffff
+	.long	0x00000000,0x00000000,0x00000000,0x0000fffe
+	.long	0x0000ffff,0xffffffff,0xffff0000,0x0000ffff
+	.long	0x00000000,0x00000000,0x00000000,0x0000c07e
+	.long	0x0000ffff,0xff000000,0x00000000,0x0000ffff
+	.long	0x00000000,0x00000000,0x00000000,0x0000c07e
+	.long	0x0000ffff,0xff000000,0x00000000,0x0000ffff
+	.long	0x00000000,0x00000000,0x00000000,0x0000c3fe
+	.long	0x0000ffff,0xffffffff,0xf8000000,0x0000ffff
+	.long	0x00000000,0x00000000,0x00000000,0x0000c3fe
+	.long	0x0000ffff,0xffffffff,0xf8000000,0x0000700c
+	.long	0x61ffffff,0xe82c43ee,0xff6c700c,0x61ffffff
+	.long	0x38664a81,0x66ff0000,0x0a14e9ee,0x004fff6c
+	.long	0x0c407fff,0x66024e75,0x102eff6f,0x0200000f
+	.long	0x660e4aae,0xff706608,0x4aaeff74,0x66024e75
+	.long	0x41eeff6c,0x61ff0000,0x001cf22e,0xf080ff6c
+	.long	0x4e750000,0x00000203,0x02030203,0x03020302
+	.long	0x02032d68,0x0000ff84,0x2d680004,0xff882d68
+	.long	0x0008ff8c,0x41eeff84,0x48e73c00,0xf227e001
+	.long	0x74027604,0x28104281,0x4c3c1001,0x0000000a
+	.long	0xe9c408c4,0xd2805803,0x51caffee,0x0804001e
+	.long	0x67024481,0x04810000,0x00106c0e,0x44810084
+	.long	0x40000000,0x00904000,0x00002f01,0x7201f23c
+	.long	0x44000000,0x0000e9d0,0x0704f200,0x58222830
+	.long	0x1c007600,0x7407f23c,0x44234120,0x0000e9c4
+	.long	0x08c4f200,0x58225803,0x51caffec,0x52810c81
+	.long	0x00000002,0x6fd80810,0x001f6704,0xf200001a
+	.long	0x22170c81,0x0000001b,0x6f0000e4,0x0810001e
+	.long	0x66744281,0x2810e9c4,0x07046624,0x52817a01
+	.long	0x28305c00,0x66085081,0x52852830,0x5c004283
+	.long	0x7407e9c4,0x08c46608,0x58835281,0x51cafff4
+	.long	0x20012217,0x92806c10,0x44812810,0x00844000
+	.long	0x00000090,0x40000000,0x43fb0170,0x00000666
+	.long	0x4283f23c,0x44803f80,0x00007403,0xe2806406
+	.long	0xf23148a3,0x38000683,0x0000000c,0x4a8066ec
+	.long	0xf2000423,0x60684281,0x7a022830,0x5c006608
+	.long	0x53855081,0x28305c00,0x761c7407,0xe9c408c4
+	.long	0x66085983,0x528151ca,0xfff42001,0x22179280
+	.long	0x6e104481,0x28100284,0xbfffffff,0x0290bfff
+	.long	0xffff43fb,0x01700000,0x05fc4283,0xf23c4480
+	.long	0x3f800000,0x7403e280,0x6406f231,0x48a33800
+	.long	0x06830000,0x000c4a80,0x66ecf200,0x0420262e
+	.long	0xff60e9c3,0x26822810,0xe582e9c4,0x0002d480
+	.long	0x43fafe50,0x10312800,0x4283efc3,0x0682f203
+	.long	0x9000e280,0x640a43fb,0x01700000,0x06446016
+	.long	0xe280640a,0x43fb0170,0x000006d2,0x600843fb
+	.long	0x01700000,0x05902001,0x6a084480,0x00904000
+	.long	0x00004283,0xf23c4480,0x3f800000,0xe2806406
+	.long	0xf23148a3,0x38000683,0x0000000c,0x4a8066ec
+	.long	0x0810001e,0x6706f200,0x04206004,0xf2000423
+	.long	0xf200a800,0x08800009,0x6706006e,0x0108ff66
+	.long	0x588ff21f,0xd0404cdf,0x003cf23c,0x90000000
+	.long	0x0000f23c,0x88000000,0x00004e75,0x3ffd0000
+	.long	0x9a209a84,0xfbcff798,0x00000000,0x3ffd0000
+	.long	0x9a209a84,0xfbcff799,0x00000000,0x3f800000
+	.long	0x00000000,0x00000000,0x00000000,0x40000000
+	.long	0x00000000,0x00000000,0x00000000,0x41200000
+	.long	0x00000000,0x00000000,0x00000000,0x459a2800
+	.long	0x00000000,0x00000000,0x00000000,0x00000000
+	.long	0x03030202,0x03020203,0x02030302,0x48e73f20
+	.long	0xf227e007,0xf23c9000,0x00000020,0x2d50ff58
+	.long	0x2e00422e,0xff500c2e,0x0004ff4e,0x66000030
+	.long	0x30100240,0x7fff2228,0x00042428,0x00085340
+	.long	0xe38ae391,0x4a816cf6,0x4a406e04,0x50eeff50
+	.long	0x02407fff,0x30802141,0x00042142,0x00082d50
+	.long	0xff902d68,0x0004ff94,0x2d680008,0xff9802ae
+	.long	0x7fffffff,0xff904a2e,0xff506708,0x2c3cffff
+	.long	0xecbb6038,0x302eff90,0x3d7c3fff,0xff90f22e
+	.long	0x4800ff90,0x04403fff,0xf2005022,0xf23a4428
+	.long	0xff1cf293,0x000ef23a,0x4823ff02,0xf2066000
+	.long	0x600af23a,0x4823fee6,0xf2066000,0xf23c8800
+	.long	0x00000000,0x42454a87,0x6f042807,0x60062806
+	.long	0x98875284,0x4a846f18,0x0c840000,0x00116f12
+	.long	0x78114a87,0x6f0c00ae,0x00002080,0xff646002
+	.long	0x78014a87,0x6e06be86,0x6d022c07,0x20065280
+	.long	0x90844845,0x42454242,0x4a806c14,0x52450c80
+	.long	0xffffecd4,0x6e080680,0x00000018,0x74184480
+	.long	0xf23a4480,0xfe98e9ee,0x1682ff60,0xe349d245
+	.long	0xe3494aae,0xff586c02,0x528145fa,0xfec01632
+	.long	0x1800e98b,0xf2039000,0xe88b4a03,0x660a43fb
+	.long	0x01700000,0x03706016,0xe20b640a,0x43fb0170
+	.long	0x000003fe,0x600843fb,0x01700000,0x04904283
+	.long	0xe2886406,0xf23148a3,0x38000683,0x0000000c
+	.long	0x4a8066ec,0xf23c8800,0x00000000,0xf23c9000
+	.long	0x00000010,0xf2104800,0xf2000018,0x4a456608
+	.long	0xf2000420,0x6000008e,0x4a2eff50,0x67000072
+	.long	0xf227e002,0x36170243,0x7fff0050,0x8000d650
+	.long	0x04433fff,0xd6690024,0x04433fff,0xd6690030
+	.long	0x04433fff,0x6b000048,0x02578000,0x87570250
+	.long	0x7fff2f28,0x00082f28,0x00042f3c,0x3fff0000
+	.long	0xf21fd080,0xf21f4823,0x2f29002c,0x2f290028
+	.long	0x2f3c3fff,0x00002f29,0x00382f29,0x00342f3c
+	.long	0x3fff0000,0xf21f4823,0xf21f4823,0x601660fe
+	.long	0x4a42670c,0xf2294823,0x0024f229,0x48230030
+	.long	0xf2000423,0xf200a800,0xf22e6800,0xff9045ee
+	.long	0xff900800,0x0009670e,0x00aa0000,0x00010008
+	.long	0xf22e4800,0xff902d6e,0xff60ff54,0x02ae0000
+	.long	0x0030ff60,0x48e7c0c0,0x2f2eff54,0x2f2eff58
+	.long	0x41eeff90,0xf2106800,0x4aaeff58,0x6c060090
+	.long	0x80000000,0x2f2eff64,0xf22e9000,0xff60f23c
+	.long	0x88000000,0x0000f22e,0x4801ff90,0xf200a800
+	.long	0x816eff66,0x1d57ff64,0x588f2d5f,0xff582d5f
+	.long	0xff544cdf,0x03032d6e,0xff58ff90,0x2d6eff54
+	.long	0xff604845,0x4a4566ff,0x00000086,0xf23a4500
+	.long	0xfcec2004,0x53804283,0xe2886406,0xf2314923
+	.long	0x38000683,0x0000000c,0x4a8066ec,0x4a2eff50
+	.long	0x670af200,0x001860ff,0x00000028,0xf2000018
+	.long	0xf2000838,0xf293001a,0x53863a3c,0x0001f23c
+	.long	0x90000000,0x0020f23a,0x4523fcc2,0x6000fda8
+	.long	0xf23a4523,0xfcb8f200,0x0838f294,0x005cf292
+	.long	0x000cf23a,0x4420fca6,0x5286604c,0x52863a3c
+	.long	0x0001f23c,0x90000000,0x00206000,0xfd7af23a
+	.long	0x4500fc6a,0x20044283,0xe2886406,0xf2314923
+	.long	0x38000683,0x0000000c,0x4a8066ec,0xf2000018
+	.long	0xf2000838,0xf28e0012,0xf23a4420,0xfc605286
+	.long	0x5284f23a,0x4523fc56,0xf23c9000,0x00000010
+	.long	0xf2000820,0x41eeff84,0xf2106800,0x24280004
+	.long	0x26280008,0x42a80004,0x42a80008,0x20104840
+	.long	0x67140480,0x00003ffd,0x4a806e0a,0x4480e28a
+	.long	0xe29351c8,0xfffa4a82,0x66044a83,0x67104281
+	.long	0x06830000,0x0080d581,0x0283ffff,0xff802004
+	.long	0x568861ff,0x000002b0,0x4a2eff50,0x6728f200
+	.long	0x003af281,0x000cf206,0x4000f200,0x0018602e
+	.long	0x4a876d08,0xf23a4400,0xfbe46022,0xf2064000
+	.long	0xf2000018,0x6018f200,0x003af28e,0x000af23a
+	.long	0x4400fb9a,0x6008f206,0x4000f200,0x0018f229
+	.long	0x48200018,0xf22e6800,0xff90242a,0x0004262a
+	.long	0x00083012,0x670e0440,0x3ffd4440,0xe28ae293
+	.long	0x51c8fffa,0x42810683,0x00000080,0xd5810283
+	.long	0xffffff80,0x700441ee,0xff5461ff,0x00000228
+	.long	0x202eff54,0x720ce2a8,0xefee010c,0xff84e2a8
+	.long	0xefee0404,0xff844a00,0x670800ae,0x00002080
+	.long	0xff644280,0x022e000f,0xff844aae,0xff586c02
+	.long	0x70024a86,0x6c025280,0xefee0002,0xff84f23c
+	.long	0x88000000,0x0000f21f,0xd0e04cdf,0x04fc4e75
+	.long	0x40020000,0xa0000000,0x00000000,0x40050000
+	.long	0xc8000000,0x00000000,0x400c0000,0x9c400000
+	.long	0x00000000,0x40190000,0xbebc2000,0x00000000
+	.long	0x40340000,0x8e1bc9bf,0x04000000,0x40690000
+	.long	0x9dc5ada8,0x2b70b59e,0x40d30000,0xc2781f49
+	.long	0xffcfa6d5,0x41a80000,0x93ba47c9,0x80e98ce0
+	.long	0x43510000,0xaa7eebfb,0x9df9de8e,0x46a30000
+	.long	0xe319a0ae,0xa60e91c7,0x4d480000,0xc9767586
+	.long	0x81750c17,0x5a920000,0x9e8b3b5d,0xc53d5de5
+	.long	0x75250000,0xc4605202,0x8a20979b,0x40020000
+	.long	0xa0000000,0x00000000,0x40050000,0xc8000000
+	.long	0x00000000,0x400c0000,0x9c400000,0x00000000
+	.long	0x40190000,0xbebc2000,0x00000000,0x40340000
+	.long	0x8e1bc9bf,0x04000000,0x40690000,0x9dc5ada8
+	.long	0x2b70b59e,0x40d30000,0xc2781f49,0xffcfa6d6
+	.long	0x41a80000,0x93ba47c9,0x80e98ce0,0x43510000
+	.long	0xaa7eebfb,0x9df9de8e,0x46a30000,0xe319a0ae
+	.long	0xa60e91c7,0x4d480000,0xc9767586,0x81750c18
+	.long	0x5a920000,0x9e8b3b5d,0xc53d5de5,0x75250000
+	.long	0xc4605202,0x8a20979b,0x40020000,0xa0000000
+	.long	0x00000000,0x40050000,0xc8000000,0x00000000
+	.long	0x400c0000,0x9c400000,0x00000000,0x40190000
+	.long	0xbebc2000,0x00000000,0x40340000,0x8e1bc9bf
+	.long	0x04000000,0x40690000,0x9dc5ada8,0x2b70b59d
+	.long	0x40d30000,0xc2781f49,0xffcfa6d5,0x41a80000
+	.long	0x93ba47c9,0x80e98cdf,0x43510000,0xaa7eebfb
+	.long	0x9df9de8d,0x46a30000,0xe319a0ae,0xa60e91c6
+	.long	0x4d480000,0xc9767586,0x81750c17,0x5a920000
+	.long	0x9e8b3b5d,0xc53d5de4,0x75250000,0xc4605202
+	.long	0x8a20979a,0x48e7ff00,0x7e015380,0x28022a03
+	.long	0xe9c21003,0xe782e9c3,0x6003e783,0x8486e385
+	.long	0xe3944846,0xd346d685,0x4e71d584,0x4e71d346
+	.long	0x48464a47,0x67124847,0xe947de41,0x10c74847
+	.long	0x424751c8,0xffc86012,0x48473e01,0x48475247
+	.long	0x51c8ffba,0x4847e94f,0x10c74cdf,0x00ff4e75
+	.long	0x70016100,0x00d63d7c,0x0121000a,0x6000007e
+	.long	0x70026100,0x00c63d7c,0x0141000a,0x606e7004
+	.long	0x610000b8,0x3d7c0101,0x000a6060,0x70086100
+	.long	0x00aa3d7c,0x0161000a,0x6052700c,0x6100009c
+	.long	0x3d7c0161,0x000a6044,0x70016100,0x008e3d7c
+	.long	0x00a1000a,0x60367002,0x61000080,0x3d7c00c1
+	.long	0x000a6028,0x70046100,0x00723d7c,0x0081000a
+	.long	0x601a7008,0x61000064,0x3d7c00e1,0x000a600c
+	.long	0x700c6100,0x00563d7c,0x00e1000a,0x2d6eff68
+	.long	0x0006f22e,0xd0c0ffdc,0xf22e9c00,0xff604cee
+	.long	0x0303ff9c,0x4e5e2f17,0x2f6f0008,0x00042f6f
+	.long	0x000c0008,0x2f7c0000,0x0001000c,0x3f6f0006
+	.long	0x000c3f7c,0x40080006,0x08170005,0x670608ef
+	.long	0x0002000d,0x60ffffff,0x2d82122e,0xff410201
+	.long	0x00380c01,0x00186700,0x000c0c01,0x00206700
+	.long	0x00604e75,0x122eff41,0x02410007,0x323b1206
+	.long	0x4efb1002,0x00100016,0x001c0020,0x00240028
+	.long	0x002c0030,0x91aeffa4,0x4e7591ae,0xffa84e75
+	.long	0x95c04e75,0x97c04e75,0x99c04e75,0x9bc04e75
+	.long	0x91964e75,0x0c2e0030,0x000a6612,0x082e0005
+	.long	0x0004660a,0x4e7a8800,0x91c04e7b,0x88004e75
+	.long	0x448060a0,0x00000000,0x00000000,0x00000000
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/ifpsp060/fskeleton.S linux/arch/m68k/ifpsp060/fskeleton.S
--- v1.3.93/linux/arch/m68k/ifpsp060/fskeleton.S	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/ifpsp060/fskeleton.S	Sun Feb 18 19:32:57 1996
@@ -0,0 +1,344 @@
+|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+|MOTOROLA MICROPROCESSOR & MEMORY TECHNOLOGY GROUP
+|M68000 Hi-Performance Microprocessor Division
+|M68060 Software Package
+|Production Release P1.00 -- October 10, 1994
+|
+|M68060 Software Package Copyright © 1993, 1994 Motorola Inc.  All rights reserved.
+| 
+|THE SOFTWARE is provided on an "AS IS" basis and without warranty.
+|To the maximum extent permitted by applicable law,
+|MOTOROLA DISCLAIMS ALL WARRANTIES WHETHER EXPRESS OR IMPLIED, 
+|INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+|and any warranty against infringement with regard to the SOFTWARE
+|(INCLUDING ANY MODIFIED VERSIONS THEREOF) and any accompanying written materials.
+|
+|To the maximum extent permitted by applicable law,
+|IN NO EVENT SHALL MOTOROLA BE LIABLE FOR ANY DAMAGES WHATSOEVER
+|(INCLUDING WITHOUT LIMITATION, DAMAGES FOR LOSS OF BUSINESS PROFITS,
+|BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION, OR OTHER PECUNIARY LOSS)
+|ARISING OF THE USE OR INABILITY TO USE THE SOFTWARE.
+|Motorola assumes no responsibility for the maintenance and support of the SOFTWARE.
+|
+|You are hereby granted a copyright license to use, modify, and distribute the SOFTWARE
+|so long as this entire notice is retained without alteration in any modified and/or
+|redistributed versions, and that such modified versions are clearly identified as such.
+|No licenses are granted by implication, estoppel or otherwise under any patents
+|or trademarks of Motorola, Inc.
+|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+| fskeleton.s
+|
+| This file contains:
+|	(1) example "Call-out"s
+|	(2) example package entry code
+|	(3) example "Call-out" table
+|
+
+
+|################################
+| (1) EXAMPLE CALL-OUTS		#
+|				#
+| _060_fpsp_done()		#
+| _060_real_ovfl()		#
+| _060_real_unfl()		#
+| _060_real_operr()		#
+| _060_real_snan()		#
+| _060_real_dz()		#
+| _060_real_inex()		#
+| _060_real_bsun()		#
+| _060_real_fline()		#
+| _060_real_fpu_disabled()	#
+| _060_real_trap()		#
+|################################
+
+|
+| _060_fpsp_done():
+|
+| This is the main exit point for the 68060 Floating-Point
+| Software Package. For a normal exit, all 060FPSP routines call this
+| routine. The operating system can do system dependent clean-up or
+| simply execute an "rte" as with the sample code below.
+|
+	.global		_060_fpsp_done
+_060_fpsp_done:
+	rte
+
+|
+| _060_real_ovfl():
+|
+| This is the exit point for the 060FPSP when an enabled overflow exception
+| is present. The routine below should point to the operating system handler 
+| for enabled overflow conditions. The exception stack frame is an overflow
+| stack frame. The FP state frame holds the EXCEPTIONAL OPERAND.
+|
+| The sample routine below simply clears the exception status bit and
+| does an "rte".
+|
+	.global		_060_real_ovfl
+_060_real_ovfl:
+	fsave		-(%sp)
+	move.w		#0x6000,0x2(%sp)
+	frestore	(%sp)+
+	rte
+
+|
+| _060_real_unfl():
+|
+| This is the exit point for the 060FPSP when an enabled underflow exception
+| is present. The routine below should point to the operating system handler 
+| for enabled underflow conditions. The exception stack frame is an underflow
+| stack frame. The FP state frame holds the EXCEPTIONAL OPERAND.
+|
+| The sample routine below simply clears the exception status bit and
+| does an "rte".
+|
+	.global		_060_real_unfl
+_060_real_unfl:
+	fsave		-(%sp)
+	move.w		#0x6000,0x2(%sp)
+	frestore	(%sp)+
+	rte
+
+|
+| _060_real_operr():
+|
+| This is the exit point for the 060FPSP when an enabled operand error exception
+| is present. The routine below should point to the operating system handler 
+| for enabled operand error exceptions. The exception stack frame is an operand error
+| stack frame. The FP state frame holds the source operand of the faulting
+| instruction.
+|
+| The sample routine below simply clears the exception status bit and
+| does an "rte".
+|
+	.global		_060_real_operr
+_060_real_operr:
+	fsave		-(%sp)
+	move.w		#0x6000,0x2(%sp)
+	frestore	(%sp)+
+	rte
+
+|
+| _060_real_snan():
+|
+| This is the exit point for the 060FPSP when an enabled signalling NaN exception
+| is present. The routine below should point to the operating system handler 
+| for enabled signalling NaN exceptions. The exception stack frame is a signalling NaN
+| stack frame. The FP state frame holds the source operand of the faulting
+| instruction.
+|
+| The sample routine below simply clears the exception status bit and
+| does an "rte".
+|
+	.global		_060_real_snan
+_060_real_snan:
+	fsave		-(%sp)
+	move.w		#0x6000,0x2(%sp)
+	frestore	(%sp)+
+	rte
+
+|
+| _060_real_dz():
+|
+| This is the exit point for the 060FPSP when an enabled divide-by-zero exception
+| is present. The routine below should point to the operating system handler 
+| for enabled divide-by-zero exceptions. The exception stack frame is a divide-by-zero
+| stack frame. The FP state frame holds the source operand of the faulting
+| instruction.
+|
+| The sample routine below simply clears the exception status bit and
+| does an "rte".
+|
+	.global		_060_real_dz
+_060_real_dz:
+	fsave		-(%sp)
+	move.w		#0x6000,0x2(%sp)
+	frestore	(%sp)+
+	rte
+
+|
+| _060_real_inex():
+|
+| This is the exit point for the 060FPSP when an enabled inexact exception
+| is present. The routine below should point to the operating system handler 
+| for enabled inexact exceptions. The exception stack frame is an inexact
+| stack frame. The FP state frame holds the source operand of the faulting
+| instruction.
+|
+| The sample routine below simply clears the exception status bit and
+| does an "rte".
+|
+	.global		_060_real_inex
+_060_real_inex:
+	fsave		-(%sp)
+	move.w		#0x6000,0x2(%sp)
+	frestore	(%sp)+
+	rte
+
+|
+| _060_real_bsun():
+|
+| This is the exit point for the 060FPSP when an enabled bsun exception
+| is present. The routine below should point to the operating system handler 
+| for enabled bsun exceptions. The exception stack frame is a bsun
+| stack frame.
+|
+| The sample routine below clears the exception status bit, clears the NaN
+| bit in the FPSR, and does an "rte". The instruction that caused the 
+| bsun will now be re-executed but with the NaN FPSR bit cleared.
+|
+	.global		_060_real_bsun
+_060_real_bsun:
+	fsave		-(%sp)
+
+	fmove.l		%fpsr,-(%sp)
+	andi.b		#0xfe,(%sp)
+	fmove.l		(%sp)+,%fpsr
+
+	add.l		#0xc,%sp
+	rte
+
+|
+| _060_real_fline():
+|
+| This is the exit point for the 060FPSP when an F-Line Illegal exception is 
+| encountered. Three different types of exceptions can enter the F-Line exception
+| vector number 11: FP Unimplemented Instructions, FP implemented instructions when
+| the FPU is disabled, and F-Line Illegal instructions. The 060FPSP module
+| _fpsp_fline() distinguishes between the three and acts appropriately. F-Line
+| Illegals branch here.
+| 
+	.global		_060_real_fline
+_060_real_fline:
+	bras		_060_real_fline
+
+|
+| _060_real_fpu_disabled():
+|
+| This is the exit point for the 060FPSP when an FPU disabled exception is 
+| encountered. Three different types of exceptions can enter the F-Line exception
+| vector number 11: FP Unimplemented Instructions, FP implemented instructions when
+| the FPU is disabled, and F-Line Illegal instructions. The 060FPSP module
+| _fpsp_fline() distinguishes between the three and acts appropriately. FPU disabled
+| exceptions branch here.
+|
+| The sample code below enables the FPU, sets the PC field in the exception stack
+| frame to the PC of the instruction causing the exception, and does an "rte".
+| The execution of the instruction then proceeds with an enabled floating-point
+| unit.
+|
+	.global		_060_real_fpu_disabled
+_060_real_fpu_disabled:
+	move.l		%d0,-(%sp)		| enabled the fpu
+	.long	0x4E7A0808
+	|movec		pcr,d0
+	bclr		#0x1,%d0
+	.long	0x4E7B0808
+	|movec		%d0,pcr
+	move.l		(%sp)+,%d0
+
+	move.l		0xc(%sp),0x2(%sp)	| set "Current PC"
+	rte
+
+|
+| _060_real_trap():
+|
+| This is the exit point for the 060FPSP when an emulated "ftrapcc" instruction
+| discovers that the trap condition is true and it should branch to the operating
+| system handler for the trap exception vector number 7.
+|
+| The sample code below simply executes an "rte".
+|
+	.global		_060_real_trap
+_060_real_trap:
+	rte
+
+|############################################################################
+
+|#################################
+| (2) EXAMPLE PACKAGE ENTRY CODE #
+|#################################
+
+	.global		_060_fpsp_snan
+_060_fpsp_snan:
+	bra.l		_FP_CALL_TOP+0x80+0x00
+
+	.global		_060_fpsp_operr
+_060_fpsp_operr:
+	bra.l		_FP_CALL_TOP+0x80+0x08
+
+	.global		_060_fpsp_ovfl
+_060_fpsp_ovfl:
+	bra.l		_FP_CALL_TOP+0x80+0x10
+
+	.global		_060_fpsp_unfl
+_060_fpsp_unfl:
+	bra.l		_FP_CALL_TOP+0x80+0x18
+
+	.global		_060_fpsp_dz
+_060_fpsp_dz:
+	bra.l		_FP_CALL_TOP+0x80+0x20
+
+	.global		_060_fpsp_inex
+_060_fpsp_inex:
+	bra.l		_FP_CALL_TOP+0x80+0x28
+
+	.global		_060_fpsp_fline
+_060_fpsp_fline:
+	bra.l		_FP_CALL_TOP+0x80+0x30
+
+	.global		_060_fpsp_unsupp
+_060_fpsp_unsupp:
+	bra.l		_FP_CALL_TOP+0x80+0x38
+
+	.global		_060_fpsp_effadd
+_060_fpsp_effadd:
+	bra.l		_FP_CALL_TOP+0x80+0x40
+
+|############################################################################
+
+|###############################
+| (3) EXAMPLE CALL-OUT SECTION #
+|###############################
+
+| The size of this section MUST be 128 bytes!!!
+
+	.global	_FP_CALL_TOP
+_FP_CALL_TOP:
+	.long	_060_real_bsun		- _FP_CALL_TOP
+	.long	_060_real_snan		- _FP_CALL_TOP
+	.long	_060_real_operr		- _FP_CALL_TOP
+	.long	_060_real_ovfl		- _FP_CALL_TOP
+	.long	_060_real_unfl		- _FP_CALL_TOP
+	.long	_060_real_dz		- _FP_CALL_TOP
+	.long	_060_real_inex		- _FP_CALL_TOP
+	.long	_060_real_fline		- _FP_CALL_TOP
+	.long	_060_real_fpu_disabled	- _FP_CALL_TOP
+	.long	_060_real_trap		- _FP_CALL_TOP
+	.long	_060_real_trace		- _FP_CALL_TOP
+	.long	_060_real_access	- _FP_CALL_TOP
+	.long	_060_fpsp_done		- _FP_CALL_TOP
+
+	.long	0x00000000, 0x00000000, 0x00000000
+
+	.long	_060_imem_read		- _FP_CALL_TOP
+	.long	_060_dmem_read		- _FP_CALL_TOP
+	.long	_060_dmem_write		- _FP_CALL_TOP
+	.long	_060_imem_read_word	- _FP_CALL_TOP
+	.long	_060_imem_read_long	- _FP_CALL_TOP
+	.long	_060_dmem_read_byte	- _FP_CALL_TOP
+	.long	_060_dmem_read_word	- _FP_CALL_TOP
+	.long	_060_dmem_read_long	- _FP_CALL_TOP
+	.long	_060_dmem_write_byte	- _FP_CALL_TOP
+	.long	_060_dmem_write_word	- _FP_CALL_TOP
+	.long	_060_dmem_write_long	- _FP_CALL_TOP
+
+	.long	0x00000000
+
+	.long	0x00000000, 0x00000000, 0x00000000, 0x00000000
+
+|############################################################################
+
+| 060 FPSP KERNEL PACKAGE NEEDS TO GO HERE!!!
+
+	.include "fpsp.sa"
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/ifpsp060/ftest.sa linux/arch/m68k/ifpsp060/ftest.sa
--- v1.3.93/linux/arch/m68k/ifpsp060/ftest.sa	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/ifpsp060/ftest.sa	Mon Jan  8 22:08:17 1996
@@ -0,0 +1,371 @@
+	dc.l	$60ff0000,$00d40000,$60ff0000,$016c0000
+	dc.l	$60ff0000,$01a80000,$54657374,$696e6720
+	dc.l	$36383036,$30204650,$53502073,$74617274
+	dc.l	$65643a0a,$00546573,$74696e67,$20363830
+	dc.l	$36302046,$50535020,$756e696d,$706c656d
+	dc.l	$656e7465,$6420696e,$73747275,$6374696f
+	dc.l	$6e207374,$61727465,$643a0a00,$54657374
+	dc.l	$696e6720,$36383036,$30204650,$53502065
+	dc.l	$78636570,$74696f6e,$20656e61,$626c6564
+	dc.l	$20737461,$72746564,$3a0a0070,$61737365
+	dc.l	$640a0020,$6661696c,$65640a00,$4a80660e
+	dc.l	$487affe9,$61ff0000,$1642588f,$4e752f01
+	dc.l	$61ff0000,$164c588f,$487affd9,$61ff0000
+	dc.l	$162a588f,$4e754e56,$fe8048e7,$3f3cf227
+	dc.l	$e0ff487a,$ff3461ff,$00001610,$588f42ae
+	dc.l	$fea0487b,$01700000,$058061ff,$000015fc
+	dc.l	$588f61ff,$00000588,$61ffffff,$ffa242ae
+	dc.l	$fea0487b,$01700000,$126c61ff,$000015dc
+	dc.l	$588f61ff,$00001280,$61ffffff,$ff8242ae
+	dc.l	$fea0487b,$01700000,$0b6461ff,$000015bc
+	dc.l	$61ff0000,$0b7261ff,$ffffff64,$42aefea0
+	dc.l	$487b0170,$00000de2,$61ff0000,$159e61ff
+	dc.l	$00000df0,$61ffffff,$ff464cdf,$3cfcf21f
+	dc.l	$d0ff4e5e,$4e754e56,$fe8048e7,$3f3cf227
+	dc.l	$e0ff487a,$feb161ff,$00001570,$588f42ae
+	dc.l	$fea0487b,$01700000,$00fe61ff,$0000155c
+	dc.l	$588f61ff,$00000110,$61ffffff,$ff024cdf
+	dc.l	$3cfcf21f,$d0ff4e5e,$4e754e56,$fe8048e7
+	dc.l	$3f3cf227,$e0ff487a,$fea461ff,$0000152c
+	dc.l	$588f42ae,$fea0487b,$01700000,$0f1461ff
+	dc.l	$00001518,$61ff0000,$0f1a61ff,$fffffec0
+	dc.l	$42aefea0,$487b0170,$00000fd2,$61ff0000
+	dc.l	$14fa61ff,$00000fd8,$61ffffff,$fea242ae
+	dc.l	$fea0487b,$01700000,$0b6061ff,$000014dc
+	dc.l	$61ff0000,$0b6a61ff,$fffffe84,$42aefea0
+	dc.l	$487b0170,$00000c22,$61ff0000,$14be61ff
+	dc.l	$00000c2c,$61ffffff,$fe6642ae,$fea0487b
+	dc.l	$01700000,$105661ff,$000014a0,$61ff0000
+	dc.l	$105a61ff,$fffffe48,$42aefea0,$487b0170
+	dc.l	$00000da2,$61ff0000,$148261ff,$00000da8
+	dc.l	$61ffffff,$fe2a4cdf,$3cfcf21f,$d0ff4e5e
+	dc.l	$4e750955,$6e696d70,$6c656d65,$6e746564
+	dc.l	$20465020,$696e7374,$72756374,$696f6e73
+	dc.l	$2e2e2e00,$52aefea0,$4cfb3fff,$01700000
+	dc.l	$1390f23b,$d0ff0170,$000013c6,$f23b9c00
+	dc.l	$01700000,$141c3d7c,$0000fea6,$48ee7fff
+	dc.l	$ff80f22e,$f0ffff20,$f22ebc00,$feb42d7c
+	dc.l	$40000000,$fe802d7c,$c90fdaa2,$fe842d7c
+	dc.l	$2168c235,$fe8844fc,$0000f22e,$480efe80
+	dc.l	$42eefea4,$48ee7fff,$ffc0f22e,$f0fffec0
+	dc.l	$f22ebc00,$fea82d7c,$bfbf0000,$ff202d7c
+	dc.l	$80000000,$ff242d7c,$00000000,$ff282d7c
+	dc.l	$08000208,$feb841fa,$ffc22d48,$febc61ff
+	dc.l	$00001288,$4a0066ff,$000012ae,$61ff0000
+	dc.l	$12b04a00,$66ff0000,$12a052ae,$fea04cfb
+	dc.l	$3fff0170,$000012da,$f23bd0ff,$01700000
+	dc.l	$1310f23b,$9c000170,$00001366,$3d7c0000
+	dc.l	$fea648ee,$7fffff80,$f22ef0ff,$ff20f22e
+	dc.l	$bc00feb4,$2d7c3ffe,$0000fe80,$2d7cc90f
+	dc.l	$daa2fe84,$2d7c2168,$c235fe88,$44fc0000
+	dc.l	$f22e480f,$fe8042ee,$fea448ee,$7fffffc0
+	dc.l	$f22ef0ff,$fec0f22e,$bc00fea8,$2d7c3fff
+	dc.l	$0000ff20,$2d7c8000,$0000ff24,$2d7c0000
+	dc.l	$0000ff28,$2d7c0000,$0208feb8,$41faffc2
+	dc.l	$2d48febc,$61ff0000,$11d24a00,$66ff0000
+	dc.l	$11f861ff,$000011fa,$4a0066ff,$000011ea
+	dc.l	$52aefea0,$4cfb3fff,$01700000,$1224f23b
+	dc.l	$d0ff0170,$0000125a,$f23b9c00,$01700000
+	dc.l	$12b03d7c,$0000fea6,$48ee7fff,$ff80f22e
+	dc.l	$f0ffff20,$f22ebc00,$feb444fc,$0000f200
+	dc.l	$5c3142ee,$fea448ee,$7fffffc0,$f22ef0ff
+	dc.l	$fec0f22e,$bc00fea8,$2d7c4000,$0000ff20
+	dc.l	$2d7c935d,$8dddff24,$2d7caaa8,$ac17ff28
+	dc.l	$2d7c0000,$0208feb8,$41faffc4,$2d48febc
+	dc.l	$61ff0000,$11364a00,$66ff0000,$115c61ff
+	dc.l	$0000115e,$4a0066ff,$0000114e,$52aefea0
+	dc.l	$4cfb3fff,$01700000,$1188f23b,$d0ff0170
+	dc.l	$000011be,$f23b9c00,$01700000,$1214f23c
+	dc.l	$88000f00,$00007e00,$3d7c0000,$fea648ee
+	dc.l	$7fffff80,$f22ef0ff,$ff20f22e,$bc00feb4
+	dc.l	$44fc0000,$f2470012,$42eefea4,$48ee7fff
+	dc.l	$ffc0f22e,$f0fffec0,$f22ebc00,$fea82d7c
+	dc.l	$0f008080,$feb841fa,$ffdc2d48,$febc61ff
+	dc.l	$000010a8,$4a0066ff,$000010ce,$61ff0000
+	dc.l	$10d04a00,$66ff0000,$10c052ae,$fea04cfb
+	dc.l	$3fff0170,$000010fa,$f23bd0ff,$01700000
+	dc.l	$1130f23b,$9c000170,$00001186,$f23c8800
+	dc.l	$0f000000,$7e023d7c,$0000fea6,$48ee7fff
+	dc.l	$ff80f22e,$f0ffff20,$f22ebc00,$feb444fc
+	dc.l	$0000f24f,$0012fffc,$42eefea4,$48ee7fff
+	dc.l	$ffc0f22e,$f0fffec0,$f22ebc00,$fea83d7c
+	dc.l	$ffffff9e,$2d7c0f00,$8080feb8,$41faffd4
+	dc.l	$2d48febc,$61ff0000,$10124a00,$66ff0000
+	dc.l	$103861ff,$0000103a,$4a0066ff,$0000102a
+	dc.l	$52aefea0,$4cfb3fff,$01700000,$1064f23b
+	dc.l	$d0ff0170,$0000109a,$f23b9c00,$01700000
+	dc.l	$10f0f23c,$88000f00,$00003d7c,$0000fea6
+	dc.l	$48ee7fff,$ff80f22e,$f0ffff20,$f22ebc00
+	dc.l	$feb444fc,$0000f27b,$0012abcd,$ef0142ee
+	dc.l	$fea448ee,$7fffffc0,$f22ef0ff,$fec0f22e
+	dc.l	$bc00fea8,$2d7c0f00,$8080feb8,$41faffd8
+	dc.l	$2d48febc,$61ff0000,$0f824a00,$66ff0000
+	dc.l	$0fa861ff,$00000faa,$4a0066ff,$00000f9a
+	dc.l	$42804e75,$09556e69,$6d706c65,$6d656e74
+	dc.l	$6564203c,$65613e2e,$2e2e0000,$52aefea0
+	dc.l	$4cfb3fff,$01700000,$0fb8f23b,$d0ff0170
+	dc.l	$00000fee,$f23b9c00,$01700000,$10443d7c
+	dc.l	$0000fea6,$48ee7fff,$ff80f22e,$f0ffff20
+	dc.l	$f22ebc00,$feb4f23c,$58000002,$44fc0000
+	dc.l	$f23c4823,$c0000000,$80000000,$00000000
+	dc.l	$42eefea4,$48ee7fff,$ffc0f22e,$f0fffec0
+	dc.l	$f22ebc00,$fea82d7c,$c0010000,$ff202d7c
+	dc.l	$80000000,$ff242d7c,$00000000,$ff282d7c
+	dc.l	$08000000,$feb841fa,$ffb82d48,$febc61ff
+	dc.l	$00000eb8,$4a0066ff,$00000ede,$61ff0000
+	dc.l	$0ee04a00,$66ff0000,$0ed052ae,$fea04cfb
+	dc.l	$3fff0170,$00000f0a,$f23bd0ff,$01700000
+	dc.l	$0f40f23b,$9c000170,$00000f96,$3d7c0000
+	dc.l	$fea648ee,$7fffff80,$f22ef0ff,$ff20f22e
+	dc.l	$bc00feb4,$44fc0000,$f23c4c18,$c1230001
+	dc.l	$23456789,$12345678,$42eefea4,$48ee7fff
+	dc.l	$ffc0f22e,$f0fffec0,$f22ebc00,$fea82d7c
+	dc.l	$3e660000,$ff202d7c,$d0ed23e8,$ff242d7c
+	dc.l	$d14035bc,$ff282d7c,$00000108,$feb841fa
+	dc.l	$ffb82d48,$febc61ff,$00000e10,$4a0066ff
+	dc.l	$00000e36,$61ff0000,$0e384a00,$66ff0000
+	dc.l	$0e2852ae,$fea04cfb,$3fff0170,$00000e62
+	dc.l	$f23bd0ff,$01700000,$0e98f23b,$9c000170
+	dc.l	$00000eee,$3d7c0000,$fea644fc,$000048ee
+	dc.l	$7fffff80,$f22ef0ff,$ff20f22e,$bc00feb4
+	dc.l	$f23c9800,$ffffffff,$ffffffff,$42eefea4
+	dc.l	$48ee7fff,$ffc0f22e,$f0fffec0,$f22ebc00
+	dc.l	$fea82d7c,$0000fff0,$feb42d7c,$0ffffff8
+	dc.l	$feb861ff,$00000d84,$4a0066ff,$00000daa
+	dc.l	$61ff0000,$0dac4a00,$66ff0000,$0d9c52ae
+	dc.l	$fea04cfb,$3fff0170,$00000dd6,$f23bd0ff
+	dc.l	$01700000,$0e0cf23b,$9c000170,$00000e62
+	dc.l	$3d7c0000,$fea644fc,$000048ee,$7fffff80
+	dc.l	$f22ef0ff,$ff20f22e,$bc00feb4,$f23c9400
+	dc.l	$ffffffff,$ffffffff,$42eefea4,$48ee7fff
+	dc.l	$ffc0f22e,$f0fffec0,$f22ebc00,$fea82d7c
+	dc.l	$0000fff0,$feb42d7c,$ffffffff,$febc61ff
+	dc.l	$00000cf8,$4a0066ff,$00000d1e,$61ff0000
+	dc.l	$0d204a00,$66ff0000,$0d1052ae,$fea04cfb
+	dc.l	$3fff0170,$00000d4a,$f23bd0ff,$01700000
+	dc.l	$0d80f23b,$9c000170,$00000dd6,$3d7c0000
+	dc.l	$fea644fc,$000048ee,$7fffff80,$f22ef0ff
+	dc.l	$ff20f22e,$bc00feb4,$f23c8c00,$ffffffff
+	dc.l	$ffffffff,$42eefea4,$48ee7fff,$ffc0f22e
+	dc.l	$f0fffec0,$f22ebc00,$fea82d7c,$0ffffff8
+	dc.l	$feb82d7c,$ffffffff,$febc61ff,$00000c6c
+	dc.l	$4a0066ff,$00000c92,$61ff0000,$0c944a00
+	dc.l	$66ff0000,$0c8452ae,$fea04cfb,$3fff0170
+	dc.l	$00000cbe,$f23bd0ff,$01700000,$0cf4f23b
+	dc.l	$9c000170,$00000d4a,$3d7c0000,$fea644fc
+	dc.l	$000048ee,$7fffff80,$f22ef0ff,$ff20f22e
+	dc.l	$bc00feb4,$f23c9c00,$ffffffff,$ffffffff
+	dc.l	$ffffffff,$42eefea4,$48ee7fff,$ffc0f22e
+	dc.l	$f0fffec0,$f22ebc00,$fea82d7c,$0000fff0
+	dc.l	$feb42d7c,$0ffffff8,$feb82d7c,$ffffffff
+	dc.l	$febc61ff,$00000bd4,$4a0066ff,$00000bfa
+	dc.l	$61ff0000,$0bfc4a00,$66ff0000,$0bec52ae
+	dc.l	$fea04cfb,$3fff0170,$00000c26,$f23bd0ff
+	dc.l	$01700000,$0c5cf23b,$9c000170,$00000cb2
+	dc.l	$f23c5800,$0001f23c,$58800002,$f23c5900
+	dc.l	$0003f23c,$59800004,$f23c5a00,$0005f23c
+	dc.l	$5a800006,$f23c5b00,$0007f23c,$5b800008
+	dc.l	$f23c8400,$00000000,$70aa3d7c,$0000fea6
+	dc.l	$48eeffff,$ff80f22e,$bc00feb4,$f22ef0ff
+	dc.l	$ff2044fc,$0000f227,$e80042ee,$fea4f22e
+	dc.l	$bc00fea8,$f23c4480,$7f800000,$f23c4580
+	dc.l	$7f800000,$f23c4680,$7f800000,$f23c4780
+	dc.l	$7f800000,$f21f4880,$f21f4980,$f21f4a80
+	dc.l	$f21f4b80,$48eeffff,$ffc0f22e,$f0fffec0
+	dc.l	$61ff0000,$0af64a00,$66ff0000,$0b1c61ff
+	dc.l	$00000b1e,$4a0066ff,$00000b0e,$52aefea0
+	dc.l	$4cfb3fff,$01700000,$0b48f23b,$d0ff0170
+	dc.l	$00000b7e,$f23b9c00,$01700000,$0bd4f23c
+	dc.l	$58000001,$f23c5880,$0002f23c,$59000003
+	dc.l	$f23c5980,$0004f23c,$5a000005,$f23c5a80
+	dc.l	$0006f23c,$5b000007,$f23c5b80,$0008f227
+	dc.l	$6b00f227,$6a00f227,$6900f227,$6800f22e
+	dc.l	$f0ffff20,$f23c4700,$7f800000,$f23c4600
+	dc.l	$7f800000,$f23c4500,$7f800000,$f23c4400
+	dc.l	$7f800000,$f23c8400,$00000000,$f23c8800
+	dc.l	$00000000,$70aa3d7c,$0000fea6,$48eeffff
+	dc.l	$ff80f22e,$bc00feb4,$44fc0000,$f21fd800
+	dc.l	$42eefea4,$f22ebc00,$fea848ee,$ffffffc0
+	dc.l	$f22ef0ff,$fec061ff,$00000a10,$4a0066ff
+	dc.l	$00000a36,$61ff0000,$0a384a00,$66ff0000
+	dc.l	$0a2852ae,$fea04cfb,$3fff0170,$00000a62
+	dc.l	$f23bd0ff,$01700000,$0a98f23b,$9c000170
+	dc.l	$00000aee,$f23c5800,$0001f23c,$58800002
+	dc.l	$f23c5900,$0003f23c,$59800004,$f23c5a00
+	dc.l	$0005f23c,$5a800006,$f23c5b00,$0007f23c
+	dc.l	$5b800008,$f23c8400,$00000000,$203cffff
+	dc.l	$ff003d7c,$0000fea6,$48eeffff,$ff80f22e
+	dc.l	$bc00feb4,$f22ef0ff,$ff2044fc,$0000f227
+	dc.l	$e80042ee,$fea4f22e,$bc00fea8,$48eeffff
+	dc.l	$ffc0f22e,$f0fffec0,$61ff0000,$095e4a00
+	dc.l	$66ff0000,$098461ff,$00000986,$4a0066ff
+	dc.l	$00000976,$42804e75,$094e6f6e,$2d6d6173
+	dc.l	$6b61626c,$65206f76,$6572666c,$6f772e2e
+	dc.l	$2e0051fc,$52aefea0,$4cfb3fff,$01700000
+	dc.l	$0990f23b,$d0ff0170,$000009c6,$f23b9c00
+	dc.l	$01700000,$0a1c3d7c,$0000fea6,$48ee7fff
+	dc.l	$ff80f22e,$f0ffff20,$f22ebc00,$feb4f23c
+	dc.l	$58000002,$2d7c7ffe,$0000fe80,$2d7c8000
+	dc.l	$0000fe84,$2d7c0000,$0000fe88,$44fc0000
+	dc.l	$f22e4823,$fe8042ee,$fea448ee,$7fffffc0
+	dc.l	$f22ef0ff,$fec0f22e,$bc00fea8,$2d7c7fff
+	dc.l	$0000ff20,$2d7c0000,$0000ff24,$2d7c0000
+	dc.l	$0000ff28,$2d7c0200,$1048feb8,$41faffc2
+	dc.l	$2d48febc,$61ff0000,$08824a00,$66ff0000
+	dc.l	$08a861ff,$000008aa,$4a0066ff,$0000089a
+	dc.l	$42804e75,$09456e61,$626c6564,$206f7665
+	dc.l	$72666c6f,$772e2e2e,$000051fc,$52aefea0
+	dc.l	$4cfb3fff,$01700000,$08b8f23b,$d0ff0170
+	dc.l	$000008ee,$f23b9c00,$01700000,$09443d7c
+	dc.l	$0000fea6,$48ee7fff,$ff80f22e,$f0ffff20
+	dc.l	$f23c9000,$00001000,$f22ebc00,$feb4f23c
+	dc.l	$58000002,$2d7c7ffe,$0000fe80,$2d7c8000
+	dc.l	$0000fe84,$2d7c0000,$0000fe88,$44fc0000
+	dc.l	$f22e4823,$fe8042ee,$fea448ee,$7fffffc0
+	dc.l	$f22ef0ff,$fec0f22e,$bc00fea8,$2d7c7fff
+	dc.l	$0000ff20,$2d7c0000,$0000ff24,$2d7c0000
+	dc.l	$0000ff28,$2d7c0200,$1048feb8,$41faffc2
+	dc.l	$2d48febc,$61ff0000,$07a24a00,$66ff0000
+	dc.l	$07c861ff,$000007ca,$4a0066ff,$000007ba
+	dc.l	$42804e75,$09456e61,$626c6564,$20756e64
+	dc.l	$6572666c,$6f772e2e,$2e0051fc,$52aefea0
+	dc.l	$4cfb3fff,$01700000,$07d8f23b,$d0ff0170
+	dc.l	$0000080e,$f23b9c00,$01700000,$08643d7c
+	dc.l	$0000fea6,$48ee7fff,$ff80f22e,$f0ffff20
+	dc.l	$f23c9000,$00000800,$f22ebc00,$feb42d7c
+	dc.l	$00000000,$fe802d7c,$80000000,$fe842d7c
+	dc.l	$00000000,$fe88f22e,$d080fe80,$44fc0000
+	dc.l	$f23c5820,$000242ee,$fea448ee,$7fffffc0
+	dc.l	$f22ef0ff,$fec0f22e,$bc00fea8,$2d7c0000
+	dc.l	$0000ff20,$2d7c4000,$0000ff24,$2d7c0000
+	dc.l	$0000ff28,$2d7c0000,$0800feb8,$41faffc2
+	dc.l	$2d48febc,$61ff0000,$06c24a00,$66ff0000
+	dc.l	$06e861ff,$000006ea,$4a0066ff,$000006da
+	dc.l	$42804e75,$094e6f6e,$2d6d6173,$6b61626c
+	dc.l	$6520756e,$64657266,$6c6f772e,$2e2e0000
+	dc.l	$52aefea0,$4cfb3fff,$01700000,$06f4f23b
+	dc.l	$d0ff0170,$0000072a,$f23b9c00,$01700000
+	dc.l	$07803d7c,$0000fea6,$48ee7fff,$ff80f22e
+	dc.l	$f0ffff20,$f22ebc00,$feb42d7c,$00000000
+	dc.l	$fe802d7c,$80000000,$fe842d7c,$00000000
+	dc.l	$fe88f22e,$d080fe80,$44fc0000,$f23c5820
+	dc.l	$000242ee,$fea448ee,$7fffffc0,$f22ef0ff
+	dc.l	$fec0f22e,$bc00fea8,$2d7c0000,$0000ff20
+	dc.l	$2d7c4000,$0000ff24,$2d7c0000,$0000ff28
+	dc.l	$2d7c0000,$0800feb8,$41faffc2,$2d48febc
+	dc.l	$61ff0000,$05e64a00,$66ff0000,$060c61ff
+	dc.l	$0000060e,$4a0066ff,$000005fe,$42804e75
+	dc.l	$09456e61,$626c6564,$20696e65,$78616374
+	dc.l	$2e2e2e00,$52aefea0,$4cfb3fff,$01700000
+	dc.l	$0620f23b,$d0ff0170,$00000656,$f23b9c00
+	dc.l	$01700000,$06ac3d7c,$0000fea6,$48ee7fff
+	dc.l	$ff80f22e,$f0ffff20,$f23c9000,$00000200
+	dc.l	$f22ebc00,$feb42d7c,$50000000,$fe802d7c
+	dc.l	$80000000,$fe842d7c,$00000000,$fe88f22e
+	dc.l	$d080fe80,$44fc0000,$f23c5822,$000242ee
+	dc.l	$fea448ee,$7fffffc0,$f22ef0ff,$fec0f22e
+	dc.l	$bc00fea8,$2d7c5000,$0000ff20,$2d7c8000
+	dc.l	$0000ff24,$2d7c0000,$0000ff28,$2d7c0000
+	dc.l	$0208feb8,$41faffc2,$2d48febc,$61ff0000
+	dc.l	$050a4a00,$66ff0000,$053061ff,$00000532
+	dc.l	$4a0066ff,$00000522,$42804e75,$09456e61
+	dc.l	$626c6564,$20534e41,$4e2e2e2e,$000051fc
+	dc.l	$52aefea0,$4cfb3fff,$01700000,$0544f23b
+	dc.l	$d0ff0170,$0000057a,$f23b9c00,$01700000
+	dc.l	$05d03d7c,$0000fea6,$48ee7fff,$ff80f22e
+	dc.l	$f0ffff20,$f23c9000,$00004000,$f22ebc00
+	dc.l	$feb42d7c,$ffff0000,$fe802d7c,$00000000
+	dc.l	$fe842d7c,$00000001,$fe88f22e,$d080fe80
+	dc.l	$44fc0000,$f23c5822,$000242ee,$fea448ee
+	dc.l	$7fffffc0,$f22ef0ff,$fec0f22e,$bc00fea8
+	dc.l	$2d7cffff,$0000ff20,$2d7c0000,$0000ff24
+	dc.l	$2d7c0000,$0001ff28,$2d7c0900,$4080feb8
+	dc.l	$41faffc2,$2d48febc,$61ff0000,$042e4a00
+	dc.l	$66ff0000,$045461ff,$00000456,$4a0066ff
+	dc.l	$00000446,$42804e75,$09456e61,$626c6564
+	dc.l	$204f5045,$52522e2e,$2e0051fc,$52aefea0
+	dc.l	$4cfb3fff,$01700000,$0468f23b,$d0ff0170
+	dc.l	$0000049e,$f23b9c00,$01700000,$04f43d7c
+	dc.l	$0000fea6,$48ee7fff,$ff80f22e,$f0ffff20
+	dc.l	$f23c9000,$00002000,$f22ebc00,$feb42d7c
+	dc.l	$ffff0000,$fe802d7c,$00000000,$fe842d7c
+	dc.l	$00000000,$fe88f22e,$d080fe80,$44fc0000
+	dc.l	$f23c4422,$7f800000,$42eefea4,$48ee7fff
+	dc.l	$ffc0f22e,$f0fffec0,$f22ebc00,$fea82d7c
+	dc.l	$ffff0000,$ff202d7c,$00000000,$ff242d7c
+	dc.l	$00000000,$ff282d7c,$01002080,$feb841fa
+	dc.l	$ffc02d48,$febc61ff,$00000350,$4a0066ff
+	dc.l	$00000376,$61ff0000,$03784a00,$66ff0000
+	dc.l	$03684280,$4e750945,$6e61626c,$65642044
+	dc.l	$5a2e2e2e,$000051fc,$52aefea0,$4cfb3fff
+	dc.l	$01700000,$038cf23b,$d0ff0170,$000003c2
+	dc.l	$f23b9c00,$01700000,$04183d7c,$0000fea6
+	dc.l	$48ee7fff,$ff80f22e,$f0ffff20,$f23c9000
+	dc.l	$00000400,$f22ebc00,$feb42d7c,$40000000
+	dc.l	$fe802d7c,$80000000,$fe842d7c,$00000000
+	dc.l	$fe88f22e,$d080fe80,$44fc0000,$f23c5820
+	dc.l	$000042ee,$fea448ee,$7fffffc0,$f22ef0ff
+	dc.l	$fec0f22e,$bc00fea8,$2d7c4000,$0000ff20
+	dc.l	$2d7c8000,$0000ff24,$2d7c0000,$0000ff28
+	dc.l	$2d7c0200,$0410feb8,$41faffc2,$2d48febc
+	dc.l	$61ff0000,$02764a00,$66ff0000,$029c61ff
+	dc.l	$0000029e,$4a0066ff,$0000028e,$42804e75
+	dc.l	$09556e69,$6d706c65,$6d656e74,$65642064
+	dc.l	$61746120,$74797065,$2f666f72,$6d61742e
+	dc.l	$2e2e0000,$52aefea0,$4cfb3fff,$01700000
+	dc.l	$02a0f23b,$d0ff0170,$000002d6,$f23b9c00
+	dc.l	$01700000,$032c3d7c,$0000fea6,$48ee7fff
+	dc.l	$ff80f22e,$f0ffff20,$f22ebc00,$feb42d7c
+	dc.l	$c03f0000,$fe802d7c,$00000000,$fe842d7c
+	dc.l	$00000001,$fe88f23c,$58000002,$44fc0000
+	dc.l	$f22e4823,$fe8042ee,$fea448ee,$7fffffc0
+	dc.l	$f22ef0ff,$fec0f22e,$bc00fea8,$2d7cc001
+	dc.l	$0000ff20,$2d7c8000,$0000ff24,$2d7c0000
+	dc.l	$0000ff28,$2d7c0800,$0000feb8,$41faffc2
+	dc.l	$2d48febc,$61ff0000,$01924a00,$66ff0000
+	dc.l	$01b861ff,$000001ba,$4a0066ff,$000001aa
+	dc.l	$52aefea0,$4cfb3fff,$01700000,$01e4f23b
+	dc.l	$d0ff0170,$0000021a,$f23b9c00,$01700000
+	dc.l	$02703d7c,$0000fea6,$48ee7fff,$ff80f22e
+	dc.l	$f0ffff20,$f22ebc00,$feb42d7c,$80000000
+	dc.l	$fe802d7c,$01000000,$fe842d7c,$00000000
+	dc.l	$fe88f23c,$40007fff,$ffff44fc,$0000f22e
+	dc.l	$4823fe80,$42eefea4,$48ee7fff,$ffc0f22e
+	dc.l	$f0fffec0,$f22ebc00,$fea82d7c,$80170000
+	dc.l	$ff202d7c,$fffffffe,$ff242d7c,$00000000
+	dc.l	$ff282d7c,$08000000,$feb841fa,$ffc22d48
+	dc.l	$febc61ff,$000000d4,$4a0066ff,$000000fa
+	dc.l	$61ff0000,$00fc4a00,$66ff0000,$00ec52ae
+	dc.l	$fea04cfb,$3fff0170,$00000126,$f23bd0ff
+	dc.l	$01700000,$015cf23b,$9c000170,$000001b2
+	dc.l	$3d7c0000,$fea648ee,$7fffff80,$f22ef0ff
+	dc.l	$ff20f22e,$bc00feb4,$2d7cc123,$0001fe80
+	dc.l	$2d7c2345,$6789fe84,$2d7c1234,$5678fe88
+	dc.l	$44fc0000,$f22e4c18,$fe8042ee,$fea448ee
+	dc.l	$7fffffc0,$f22ef0ff,$fec0f22e,$bc00fea8
+	dc.l	$2d7c3e66,$0000ff20,$2d7cd0ed,$23e8ff24
+	dc.l	$2d7cd140,$35bcff28,$2d7c0000,$0108feb8
+	dc.l	$41faffc2,$2d48febc,$61ff0000,$001e4a00
+	dc.l	$66ff0000,$004461ff,$00000046,$4a0066ff
+	dc.l	$00000036,$42804e75,$41eeff80,$43eeffc0
+	dc.l	$700eb189,$66ff0000,$001c51c8,$fff6302e
+	dc.l	$fea6322e,$fea4b041,$66ff0000,$00084280
+	dc.l	$4e757001,$4e75222e,$fea07001,$4e7541ee
+	dc.l	$ff2043ee,$fec07017,$b18966ff,$0000002c
+	dc.l	$51c8fff6,$41eefeb4,$43eefea8,$b18966ff
+	dc.l	$00000018,$b18966ff,$00000010,$b18966ff
+	dc.l	$00000008,$42804e75,$70014e75,$acacacac
+	dc.l	$acacacac,$acacacac,$acacacac,$acacacac
+	dc.l	$acacacac,$acacacac,$acacacac,$acacacac
+	dc.l	$acacacac,$acacacac,$acacacac,$acacacac
+	dc.l	$acacacac,$acacacac,$acacacac,$7fff0000
+	dc.l	$ffffffff,$ffffffff,$7fff0000,$ffffffff
+	dc.l	$ffffffff,$7fff0000,$ffffffff,$ffffffff
+	dc.l	$7fff0000,$ffffffff,$ffffffff,$7fff0000
+	dc.l	$ffffffff,$ffffffff,$7fff0000,$ffffffff
+	dc.l	$ffffffff,$7fff0000,$ffffffff,$ffffffff
+	dc.l	$7fff0000,$ffffffff,$ffffffff,$00000000
+	dc.l	$00000000,$00000000,$2f00203a,$e884487b
+	dc.l	$0930ffff,$e880202f,$00044e74,$00042f00
+	dc.l	$203ae872,$487b0930,$ffffe86a,$202f0004
+	dc.l	$4e740004,$00000000,$00000000,$00000000
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/ifpsp060/ilsp.doc linux/arch/m68k/ifpsp060/ilsp.doc
--- v1.3.93/linux/arch/m68k/ifpsp060/ilsp.doc	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/ifpsp060/ilsp.doc	Mon Jan  8 22:08:17 1996
@@ -0,0 +1,150 @@
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+MOTOROLA MICROPROCESSOR & MEMORY TECHNOLOGY GROUP
+M68000 Hi-Performance Microprocessor Division
+M68060 Software Package
+Production Release P1.00 -- October 10, 1994
+
+M68060 Software Package Copyright © 1993, 1994 Motorola Inc.  All rights reserved.
+ 
+THE SOFTWARE is provided on an "AS IS" basis and without warranty.
+To the maximum extent permitted by applicable law,
+MOTOROLA DISCLAIMS ALL WARRANTIES WHETHER EXPRESS OR IMPLIED, 
+INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+and any warranty against infringement with regard to the SOFTWARE
+(INCLUDING ANY MODIFIED VERSIONS THEREOF) and any accompanying written materials.
+
+To the maximum extent permitted by applicable law,
+IN NO EVENT SHALL MOTOROLA BE LIABLE FOR ANY DAMAGES WHATSOEVER
+(INCLUDING WITHOUT LIMITATION, DAMAGES FOR LOSS OF BUSINESS PROFITS,
+BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION, OR OTHER PECUNIARY LOSS)
+ARISING OF THE USE OR INABILITY TO USE THE SOFTWARE.
+Motorola assumes no responsibility for the maintenance and support of the SOFTWARE.
+
+You are hereby granted a copyright license to use, modify, and distribute the SOFTWARE
+so long as this entire notice is retained without alteration in any modified and/or
+redistributed versions, and that such modified versions are clearly identified as such.
+No licenses are granted by implication, estoppel or otherwise under any patents
+or trademarks of Motorola, Inc.
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+68060 INTEGER SOFTWARE PACKAGE (Library version)
+-------------------------------------------------
+
+The file ilsp.s contains the "Library version" of the
+68060 Integer Software Package. Routines included in this
+module can be used to emulate 64-bit divide and multiply,
+and the "cmp2" instruction. These instructions are not 
+implemented in hardware on the 68060 and normally take 
+exception vector #61 "Unimplemented Integer Instruction".
+
+By re-compiling a program that uses these instructions, and 
+making subroutine calls in place of the unimplemented
+instructions, a program can avoid the overhead associated with
+taking the exception.
+
+Release file format:
+--------------------
+The file ilsp.sa is essentially a hexadecimal image of the
+release package. This is the ONLY format which will be supported.
+The hex image was created by assembling the source code and
+then converting the resulting binary output image into an
+ASCII text file. The hexadecimal numbers are listed
+using the Motorola Assembly Syntax assembler directive "dc.l"
+(define constant longword). The file can be converted to other
+assembly syntaxes by using any word processor with a global
+search and replace function.
+
+To assist in assembling and linking this module with other modules,
+the installer should add a symbolic label to the top of the file.
+This will allow calling routines to access the entry points
+of this package.
+
+The source code ilsp.s has also been included but only for
+documentation purposes.
+
+Release file structure:
+-----------------------
+The file ilsp.sa contains an "Entry-Point" section and a 
+code section. The ILSP has no "Call-Out" section. The first section
+is the "Entry-Point" section. In order to access a function in the
+package, a program must "bsr" or "jsr" to the location listed
+below in "68060ILSP Entry Points" that corresponds to the desired
+function. A branch instruction located at the selected entry point
+within the package will then enter the correct emulation code routine.
+
+The entry point addresses at the beginning of the package will remain
+fixed so that a program calling the routines will not have to be
+re-compiled with every new 68060ILSP release.
+
+For example, to use a 64-bit multiply instruction,
+do a "bsr" or "jsr" to the entry point defined by
+the 060ILSP entry table. A compiler generated code sequence 
+for unsigned multiply could look like:
+
+# mulu.l <ea>,Dh:Dl
+# mulu.l _multiplier,%d1:%d0
+
+	subq.l	&0x8,%sp	# make room for result on stack
+	pea	(%sp)		# pass: result addr on stack
+	mov.l	%d0,-(%sp)	# pass: multiplicand on stack
+	mov.l	_multiplier,-(%sp) # pass: multiplier on stack
+	bsr.l	_060LISP_TOP+0x18 # branch to multiply routine
+	add.l	&0xc,%sp	# clear arguments from stack
+	mov.l	(%sp)+,%d1	# load result[63:32]
+	mov.l	(%sp)+,%d0	# load result[31:0]
+
+For a divide:
+
+# divu.l <ea>,Dr:Dq
+# divu.l _divisor,%d1:%d0
+
+	subq.l	&0x8,%sp	# make room for result on stack
+	pea	(%sp)		# pass: result addr on stack
+	mov.l	%d0,-(%sp)	# pass: dividend hi on stack
+	mov.l	%d1,-(%sp)	# pass: dividend hi on stack
+	mov.l	_divisor,-(%sp) # pass: divisor on stack
+	bsr.l	_060LISP_TOP+0x08 # branch to divide routine
+	add.l	&0xc,%sp	# clear arguments from stack
+	mov.l	(%sp)+,%d1	# load remainder
+	mov.l	(%sp)+,%d0	# load quotient
+
+The library routines also return the correct condition code 
+register value. If this is important, then the caller of the library
+routine must make sure that the value isn't lost while popping
+other items off of the stack.
+
+An example of using the "cmp2" instruction is as follows:
+
+# cmp2.l <ea>,Rn
+# cmp2.l _bounds,%d0
+
+	pea	_bounds		# pass ptr to bounds
+	mov.l	%d0,-(%sp)	# pass Rn
+	bsr.l	_060LSP_TOP_+0x48 # branch to "cmp2" routine
+	mov.w	%cc,_tmp	# save off condition codes
+	addq.l	&0x8,%sp	# clear arguments from stack
+
+Exception reporting:
+--------------------
+If the instruction being emulated is a divide and the source
+operand is a zero, then the library routine, as it's last
+instruction, executes an implemented divide using a zero
+source operand so that an "Integer Divide-by-Zero" exception
+will be taken. Although the exception stack frame will not
+point to the correct instruction, the user will at least be able
+to record that such an event occurred if desired.
+
+68060ILSP entry points:
+-----------------------
+_060ILSP_TOP:
+0x000:	_060LSP__idivs64_
+0x008:	_060LSP__idivu64_
+
+0x010:	_060LSP__imuls64_
+0x018:	_060LSP__imulu64_
+
+0x020:	_060LSP__cmp2_Ab_
+0x028:	_060LSP__cmp2_Aw_
+0x030:	_060LSP__cmp2_Al_
+0x038:	_060LSP__cmp2_Db_
+0x040:	_060LSP__cmp2_Dw_
+0x048:	_060LSP__cmp2_Dl_
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/ifpsp060/ilsp.sa linux/arch/m68k/ifpsp060/ilsp.sa
--- v1.3.93/linux/arch/m68k/ifpsp060/ilsp.sa	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/ifpsp060/ilsp.sa	Mon Jan  8 22:08:18 1996
@@ -0,0 +1,101 @@
+	dc.l	$60ff0000,$01fe0000,$60ff0000,$02080000
+	dc.l	$60ff0000,$04900000,$60ff0000,$04080000
+	dc.l	$60ff0000,$051e0000,$60ff0000,$053c0000
+	dc.l	$60ff0000,$055a0000,$60ff0000,$05740000
+	dc.l	$60ff0000,$05940000,$60ff0000,$05b40000
+	dc.l	$51fc51fc,$51fc51fc,$51fc51fc,$51fc51fc
+	dc.l	$51fc51fc,$51fc51fc,$51fc51fc,$51fc51fc
+	dc.l	$51fc51fc,$51fc51fc,$51fc51fc,$51fc51fc
+	dc.l	$51fc51fc,$51fc51fc,$51fc51fc,$51fc51fc
+	dc.l	$51fc51fc,$51fc51fc,$51fc51fc,$51fc51fc
+	dc.l	$51fc51fc,$51fc51fc,$51fc51fc,$51fc51fc
+	dc.l	$51fc51fc,$51fc51fc,$51fc51fc,$51fc51fc
+	dc.l	$51fc51fc,$51fc51fc,$51fc51fc,$51fc51fc
+	dc.l	$51fc51fc,$51fc51fc,$51fc51fc,$51fc51fc
+	dc.l	$51fc51fc,$51fc51fc,$51fc51fc,$51fc51fc
+	dc.l	$51fc51fc,$51fc51fc,$51fc51fc,$51fc51fc
+	dc.l	$51fc51fc,$51fc51fc,$51fc51fc,$51fc51fc
+	dc.l	$51fc51fc,$51fc51fc,$51fc51fc,$51fc51fc
+	dc.l	$51fc51fc,$51fc51fc,$51fc51fc,$51fc51fc
+	dc.l	$51fc51fc,$51fc51fc,$51fc51fc,$51fc51fc
+	dc.l	$51fc51fc,$51fc51fc,$51fc51fc,$51fc51fc
+	dc.l	$51fc51fc,$51fc51fc,$51fc51fc,$51fc51fc
+	dc.l	$51fc51fc,$51fc51fc,$51fc51fc,$51fc51fc
+	dc.l	$51fc51fc,$51fc51fc,$51fc51fc,$51fc51fc
+	dc.l	$51fc51fc,$51fc51fc,$51fc51fc,$51fc51fc
+	dc.l	$51fc51fc,$51fc51fc,$51fc51fc,$51fc51fc
+	dc.l	$51fc51fc,$51fc51fc,$51fc51fc,$51fc51fc
+	dc.l	$51fc51fc,$51fc51fc,$51fc51fc,$51fc51fc
+	dc.l	$51fc51fc,$51fc51fc,$51fc51fc,$51fc51fc
+	dc.l	$51fc51fc,$51fc51fc,$51fc51fc,$51fc51fc
+	dc.l	$51fc51fc,$51fc51fc,$51fc51fc,$51fc51fc
+	dc.l	$51fc51fc,$51fc51fc,$51fc51fc,$51fc51fc
+	dc.l	$4e56fff0,$48e73f00,$42eefff0,$50eeffff
+	dc.l	$60104e56,$fff048e7,$3f0042ee,$fff051ee
+	dc.l	$ffff2e2e,$00086700,$00ae2a2e,$000c2c2e
+	dc.l	$00104a2e,$ffff671a,$4a875dee,$fffe6a02
+	dc.l	$44874a85,$5deefffd,$6a0844fc,$00004086
+	dc.l	$40854a85,$66164a86,$67000046,$be866306
+	dc.l	$cb466000,$00124c47,$6005600a,$be85634c
+	dc.l	$61ff0000,$00864a2e,$ffff6724,$4a2efffd
+	dc.l	$67024485,$102efffe,$b12efffd,$670c0c86
+	dc.l	$80000000,$62264486,$60060806,$001f661c
+	dc.l	$026e0010,$fff044ee,$fff04a86,$48f60060
+	dc.l	$01610014,$4cdf00fc,$4e5e4e75,$2a2e000c
+	dc.l	$2c2e0010,$026e001c,$fff0006e,$0002fff0
+	dc.l	$44eefff0,$60d62dae,$000c0161,$00142dae
+	dc.l	$00100162,$00140004,$44eefff0,$4cdf00fc
+	dc.l	$4e5e80fc,$00004e75,$0c870000,$ffff621e
+	dc.l	$42814845,$48463a06,$8ac73205,$48463a06
+	dc.l	$8ac74841,$32054245,$48452c01,$4e7542ae
+	dc.l	$fff8422e,$fffc4281,$0807001f,$660e52ae
+	dc.l	$fff8e38f,$e38ee395,$6000ffee,$26072405
+	dc.l	$48424843,$b4436606,$323cffff,$600a2205
+	dc.l	$82c30281,$0000ffff,$2f064246,$48462607
+	dc.l	$2401c4c7,$4843c6c1,$28059883,$48443004
+	dc.l	$38064a40,$6600000a,$b4846304,$538160de
+	dc.l	$2f052c01,$48462a07,$61ff0000,$006a2405
+	dc.l	$26062a1f,$2c1f9c83,$9b8264ff,$0000001a
+	dc.l	$53814282,$26074843,$4243dc83,$db822607
+	dc.l	$42434843,$da834a2e,$fffc6616,$3d41fff4
+	dc.l	$42814845,$48463a06,$424650ee,$fffc6000
+	dc.l	$ff6c3d41,$fff63c05,$48464845,$2e2efff8
+	dc.l	$670a5387,$e28de296,$51cffffa,$2a062c2e
+	dc.l	$fff44e75,$24062606,$28054843,$4844ccc5
+	dc.l	$cac3c4c4,$c6c44284,$4846dc45,$d744dc42
+	dc.l	$d7444846,$42454242,$48454842,$da82da83
+	dc.l	$4e754e56,$fffc48e7,$380042ee,$fffc202e
+	dc.l	$00086700,$005a222e,$000c6700,$00522400
+	dc.l	$26002801,$48434844,$c0c1c2c3,$c4c4c6c4
+	dc.l	$42844840,$d041d784,$d042d784,$48404241
+	dc.l	$42424841,$4842d282,$d283382e,$fffc0204
+	dc.l	$00104a81,$6a040004,$000844c4,$c34048f6
+	dc.l	$00030161,$00104cdf,$001c4e5e,$4e754280
+	dc.l	$4281382e,$fffc0204,$00100004,$000444c4
+	dc.l	$60da4e56,$fffc48e7,$3c0042ee,$fffc202e
+	dc.l	$000867da,$222e000c,$67d44205,$4a806c06
+	dc.l	$44800005,$00014a81,$6c064481,$0a050001
+	dc.l	$24002600,$28014843,$4844c0c1,$c2c3c4c4
+	dc.l	$c6c44284,$4840d041,$d784d042,$d7844840
+	dc.l	$42414242,$48414842,$d282d283,$4a056708
+	dc.l	$46804681,$5280d384,$382efffc,$02040010
+	dc.l	$4a816a04,$00040008,$44c4c340,$48f60003
+	dc.l	$01610010,$4cdf003c,$4e5e4e75,$42804281
+	dc.l	$382efffc,$02040010,$00040004,$44c460da
+	dc.l	$4e56fffc,$48e73800,$42eefffc,$242e0008
+	dc.l	$10360161,$000c1236,$0162000c,$000149c0
+	dc.l	$49c16000,$00b84e56,$fffc48e7,$380042ee
+	dc.l	$fffc242e,$00083036,$0161000c,$32360162
+	dc.l	$000c0002,$48c048c1,$60000092,$4e56fffc
+	dc.l	$48e73800,$42eefffc,$242e0008,$20360161
+	dc.l	$000c2236,$0162000c,$00046000,$00704e56
+	dc.l	$fffc48e7,$380042ee,$fffc242e,$00081036
+	dc.l	$0161000c,$12360162,$000c0001,$49c049c1
+	dc.l	$49c26000,$00484e56,$fffc48e7,$380042ee
+	dc.l	$fffc242e,$00083036,$0161000c,$32360162
+	dc.l	$000c0002,$48c048c1,$48c26000,$00204e56
+	dc.l	$fffc48e7,$380042ee,$fffc242e,$00082036
+	dc.l	$0161000c,$22360162,$000c0004,$948042c3
+	dc.l	$02030004,$9280b282,$42c48604,$02030005
+	dc.l	$382efffc,$0204001a,$880344c4,$4cdf001c
+	dc.l	$4e5e4e75,$00000000,$00000000,$00000000
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/ifpsp060/iskeleton.S linux/arch/m68k/ifpsp060/iskeleton.S
--- v1.3.93/linux/arch/m68k/ifpsp060/iskeleton.S	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/ifpsp060/iskeleton.S	Sun Feb 18 19:33:27 1996
@@ -0,0 +1,282 @@
+|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+|MOTOROLA MICROPROCESSOR & MEMORY TECHNOLOGY GROUP
+|M68000 Hi-Performance Microprocessor Division
+|M68060 Software Package
+|Production Release P1.00 -- October 10, 1994
+|
+|M68060 Software Package Copyright © 1993, 1994 Motorola Inc.  All rights reserved.
+| 
+|THE SOFTWARE is provided on an "AS IS" basis and without warranty.
+|To the maximum extent permitted by applicable law,
+|MOTOROLA DISCLAIMS ALL WARRANTIES WHETHER EXPRESS OR IMPLIED, 
+|INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+|and any warranty against infringement with regard to the SOFTWARE
+|(INCLUDING ANY MODIFIED VERSIONS THEREOF) and any accompanying written materials.
+|
+|To the maximum extent permitted by applicable law,
+|IN NO EVENT SHALL MOTOROLA BE LIABLE FOR ANY DAMAGES WHATSOEVER
+|(INCLUDING WITHOUT LIMITATION, DAMAGES FOR LOSS OF BUSINESS PROFITS,
+|BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION, OR OTHER PECUNIARY LOSS)
+|ARISING OF THE USE OR INABILITY TO USE THE SOFTWARE.
+|Motorola assumes no responsibility for the maintenance and support of the SOFTWARE.
+|
+|You are hereby granted a copyright license to use, modify, and distribute the SOFTWARE
+|so long as this entire notice is retained without alteration in any modified and/or
+|redistributed versions, and that such modified versions are clearly identified as such.
+|No licenses are granted by implication, estoppel or otherwise under any patents
+|or trademarks of Motorola, Inc.
+|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+| iskeleton.s
+|
+| This file contains:
+|	(1) example "Call-out"s
+|	(2) example package entry code
+|	(3) example "Call-out" table
+|
+
+
+|################################
+| (1) EXAMPLE CALL-OUTS 	#
+|				#
+| _060_isp_done()		#
+| _060_real_chk()		#
+| _060_real_divbyzero()		#
+|				#
+| _060_real_cas()		#
+| _060_real_cas2()		#
+| _060_real_lock_page()		#
+| _060_real_unlock_page()	#
+|################################
+
+|
+| _060_isp_done():
+|
+| This is and example main exit point for the Unimplemented Integer
+| Instruction exception handler. For a normal exit, the 
+| _isp_unimp() branches to here so that the operating system
+| can do any clean-up desired. The stack frame is the
+| Unimplemented Integer Instruction stack frame with
+| the PC pointing to the instruction following the instruction
+| just emulated.
+| To simply continue execution at the next instruction, just
+| do an "rte".
+|
+	.global		_060_isp_done
+_060_isp_done:
+	rte
+
+|
+| _060_real_chk():
+|
+| This is an alternate exit point for the Unimplemented Integer
+| Instruction exception handler. If the instruction was a "chk2"
+| and the operand was out of bounds, then _isp_unimp() creates
+| a CHK exception stack frame from the Unimplemented Integer Instrcution
+| stack frame and branches to this routine.
+|
+	.global		_060_real_chk
+_060_real_chk:
+	tst.b		(%sp)			| is tracing enabled?
+	bpls		real_chk_end		| no
+
+|
+|	    CHK FRAME		   TRACE FRAME
+|	*****************	*****************
+|	*   Current PC	*	*   Current PC	*
+|	*****************	*****************
+|	* 0x2 *  0x018	*	* 0x2 *  0x024	*
+|	*****************	*****************
+|	*     Next	*	*     Next	*
+|	*      PC	*	*      PC	*
+|	*****************	*****************
+|	*      SR	*	*      SR	*
+|	*****************	*****************
+|
+	move.b		#0x24,0x7(%sp)		| set trace vecno
+	bral		_060_real_trace
+
+real_chk_end:
+	rte
+
+|
+| _060_real_divbyzero:
+|
+| This is an alternate exit point for the Unimplemented Integer 
+| Instruction exception handler isp_unimp(). If the instruction is a 64-bit
+| integer divide where the source operand is a zero, then the _isp_unimp() 
+| creates a Divide-by-zero exception stack frame from the Unimplemented
+| Integer Instruction stack frame and branches to this routine.
+|
+| Remember that a trace exception may be pending. The code below performs
+| no action associated with the "chk" exception. If tracing is enabled,
+| then it create a Trace exception stack frame from the "chk" exception
+| stack frame and branches to the _real_trace() entry point.
+| 
+	.global		_060_real_divbyzero
+_060_real_divbyzero:
+	tst.b		(%sp)			| is tracing enabled?
+	bpls		real_divbyzero_end	| no
+
+|
+|	 DIVBYZERO FRAME	   TRACE FRAME
+|	*****************	*****************
+|	*   Current PC	*	*   Current PC	*
+|	*****************	*****************
+|	* 0x2 *  0x014	*	* 0x2 *  0x024	*
+|	*****************	*****************
+|	*     Next	*	*     Next	*
+|	*      PC	*	*      PC	*
+|	*****************	*****************
+|	*      SR	*	*      SR	*
+|	*****************	*****************
+|
+	move.b		#0x24,0x7(%sp)		| set trace vecno
+	bral		_060_real_trace
+
+real_divbyzero_end:
+	rte
+
+|##########################
+
+|
+| _060_real_cas():
+|
+| Entry point for the selected cas emulation code implementation.
+| If the implementation provided by the 68060ISP is sufficient,
+| then this routine simply re-enters the package through _isp_cas.
+|
+	.global		_060_real_cas
+_060_real_cas:
+	bral		_I_CALL_TOP+0x80+0x08
+
+|
+| _060_real_cas2():
+|
+| Entry point for the selected cas2 emulation code implementation.
+| If the implementation provided by the 68060ISP is sufficient,
+| then this routine simply re-enters the package through _isp_cas2.
+|
+	.global		_060_real_cas2
+_060_real_cas2:
+	bral		_I_CALL_TOP+0x80+0x10
+
+|
+| _060_lock_page():
+|
+| Entry point for the operating system's routine to "lock" a page
+| from being paged out. This routine is needed by the cas/cas2
+| algorithms so that no page faults occur within the "core" code
+| region. Note: the routine must lock two pages if the operand 
+| spans two pages.
+| NOTE: THE ROUTINE SHOULD RETURN AN FSLW VALUE IN D0 ON FAILURE
+| SO THAT THE 060SP CAN CREATE A PROPER ACCESS ERROR FRAME.
+| Arguments:
+|	a0 = operand address
+|	d0 = `xxxxxxff -> supervisor; `xxxxxx00 -> user
+|	d1 = `xxxxxxff -> longword; `xxxxxx00 -> word
+| Expected outputs:
+|	d0 = 0 -> success; non-zero -> failure
+|
+	.global		_060_real_lock_page
+_060_real_lock_page:
+	clr.l		%d0
+	rts
+
+|
+| _060_unlock_page():
+|
+| Entry point for the operating system's routine to "unlock" a
+| page that has been "locked" previously with _real_lock_page.
+| Note: the routine must unlock two pages if the operand spans
+| two pages.
+| Arguments:
+| 	a0 = operand address
+|	d0 = `xxxxxxff -> supervisor; `xxxxxx00 -> user
+|	d1 = `xxxxxxff -> longword; `xxxxxx00 -> word
+|
+	.global		_060_real_unlock_page
+_060_real_unlock_page:
+	clr.l		%d0
+	rts
+
+|###########################################################################
+
+|#################################
+| (2) EXAMPLE PACKAGE ENTRY CODE #
+|#################################
+
+	.global		_060_isp_unimp
+_060_isp_unimp:
+	bral		_I_CALL_TOP+0x80+0x00
+
+	.global		_060_isp_cas
+_060_isp_cas:
+	bral		_I_CALL_TOP+0x80+0x08
+
+	.global		_060_isp_cas2
+_060_isp_cas2:
+	bral		_I_CALL_TOP+0x80+0x10
+
+	.global		_060_isp_cas_finish
+_060_isp_cas_finish:
+	bra.l		_I_CALL_TOP+0x80+0x18
+
+	.global		_060_isp_cas2_finish
+_060_isp_cas2_finish:
+	bral		_I_CALL_TOP+0x80+0x20
+
+	.global		_060_isp_cas_inrange
+_060_isp_cas_inrange:
+	bral		_I_CALL_TOP+0x80+0x28
+
+	.global		_060_isp_cas_terminate
+_060_isp_cas_terminate:
+	bral		_I_CALL_TOP+0x80+0x30
+
+	.global		_060_isp_cas_restart
+_060_isp_cas_restart:
+	bral		_I_CALL_TOP+0x80+0x38
+
+|###########################################################################
+
+|###############################
+| (3) EXAMPLE CALL-OUT SECTION #
+|###############################
+
+| The size of this section MUST be 128 bytes!!!
+
+	.global	_I_CALL_TOP
+_I_CALL_TOP:
+	.long	_060_real_chk		- _I_CALL_TOP
+	.long	_060_real_divbyzero	- _I_CALL_TOP
+	.long	_060_real_trace		- _I_CALL_TOP
+	.long	_060_real_access	- _I_CALL_TOP
+	.long	_060_isp_done		- _I_CALL_TOP
+
+	.long	_060_real_cas		- _I_CALL_TOP
+	.long	_060_real_cas2		- _I_CALL_TOP
+	.long	_060_real_lock_page	- _I_CALL_TOP
+	.long	_060_real_unlock_page	- _I_CALL_TOP
+
+	.long	0x00000000, 0x00000000, 0x00000000, 0x00000000
+	.long	0x00000000, 0x00000000, 0x00000000
+
+	.long	_060_imem_read		- _I_CALL_TOP
+	.long	_060_dmem_read		- _I_CALL_TOP
+	.long	_060_dmem_write		- _I_CALL_TOP
+	.long	_060_imem_read_word	- _I_CALL_TOP
+	.long	_060_imem_read_long	- _I_CALL_TOP
+	.long	_060_dmem_read_byte	- _I_CALL_TOP
+	.long	_060_dmem_read_word	- _I_CALL_TOP
+	.long	_060_dmem_read_long	- _I_CALL_TOP
+	.long	_060_dmem_write_byte	- _I_CALL_TOP
+	.long	_060_dmem_write_word	- _I_CALL_TOP
+	.long	_060_dmem_write_long	- _I_CALL_TOP
+
+	.long	0x00000000
+	.long	0x00000000, 0x00000000, 0x00000000, 0x00000000
+
+|###########################################################################
+
+| 060 INTEGER KERNEL PACKAGE MUST GO HERE!!!
+	.include "isp.sa"
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/ifpsp060/isp.doc linux/arch/m68k/ifpsp060/isp.doc
--- v1.3.93/linux/arch/m68k/ifpsp060/isp.doc	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/ifpsp060/isp.doc	Mon Jan  8 22:08:19 1996
@@ -0,0 +1,218 @@
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+MOTOROLA MICROPROCESSOR & MEMORY TECHNOLOGY GROUP
+M68000 Hi-Performance Microprocessor Division
+M68060 Software Package
+Production Release P1.00 -- October 10, 1994
+
+M68060 Software Package Copyright © 1993, 1994 Motorola Inc.  All rights reserved.
+ 
+THE SOFTWARE is provided on an "AS IS" basis and without warranty.
+To the maximum extent permitted by applicable law,
+MOTOROLA DISCLAIMS ALL WARRANTIES WHETHER EXPRESS OR IMPLIED, 
+INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+and any warranty against infringement with regard to the SOFTWARE
+(INCLUDING ANY MODIFIED VERSIONS THEREOF) and any accompanying written materials.
+
+To the maximum extent permitted by applicable law,
+IN NO EVENT SHALL MOTOROLA BE LIABLE FOR ANY DAMAGES WHATSOEVER
+(INCLUDING WITHOUT LIMITATION, DAMAGES FOR LOSS OF BUSINESS PROFITS,
+BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION, OR OTHER PECUNIARY LOSS)
+ARISING OF THE USE OR INABILITY TO USE THE SOFTWARE.
+Motorola assumes no responsibility for the maintenance and support of the SOFTWARE.
+
+You are hereby granted a copyright license to use, modify, and distribute the SOFTWARE
+so long as this entire notice is retained without alteration in any modified and/or
+redistributed versions, and that such modified versions are clearly identified as such.
+No licenses are granted by implication, estoppel or otherwise under any patents
+or trademarks of Motorola, Inc.
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+68060 INTEGER SOFTWARE PACKAGE (Kernel version)
+------------------------------------------------
+
+The file isp.sa contains the 68060 Integer Software Package.
+This package is essentially an exception handler that can be
+integrated into an operating system to handle the "Unimplemented
+Integer Instruction" exception vector #61.
+This exception is taken when any of the integer instructions
+not hardware implemented on the 68060 are encountered. The
+isp.sa provides full emulation support for these instructions.
+
+The unimplemented integer instructions are:
+	64-bit divide
+	64-bit multiply
+	movep
+	cmp2
+	chk2
+	cas (w/ a misaligned effective address)
+	cas2
+
+Release file format:
+--------------------
+The file isp.sa is essentially a hexadecimal image of the
+release package. This is the ONLY format which will be supported.
+The hex image was created by assembling the source code and
+then converting the resulting binary output image into an
+ASCII text file. The hexadecimal numbers are listed
+using the Motorola Assembly Syntax assembler directive "dc.l"
+(define constant longword). The file can be converted to other
+assembly syntaxes by using any word processor with a global
+search and replace function.
+
+To assist in assembling and linking this module with other modules,
+the installer should add a symbolic label to the top of the file.
+This will allow calling routines to access the entry points
+of this package.
+
+The source code isp.s has also been included but only for
+documentation purposes.
+
+Release file structure:
+-----------------------
+
+(top of module)
+	-----------------
+	|		| - 128 byte-sized section
+   (1)  |   Call-Out    | - 4 bytes per entry (user fills these in)
+	|		| - example routines in iskeleton.s
+	-----------------
+	|		| - 8 bytes per entry
+   (2)  | Entry Point   | - user does a "bra" or "jmp" to this address
+	|               | 
+	-----------------
+	|		| - code section
+   (3)  ~		~
+	|		|
+	-----------------
+(bottom of module)
+
+The first section of this module is the "Call-out" section. This section
+is NOT INCLUDED in isp.sa (an example "Call-out" section is provided at
+the end of the file iskeleton.s). The purpose of this section is to allow 
+the ISP routines to reference external functions that must be provided 
+by the host operating system. This section MUST be exactly 128 bytes in 
+size. There are 32 fields, each 4 bytes in size. Each field corresponds
+to a function required by the ISP (these functions and their location are
+listed in "68060ISP call-outs" below). Each field entry should contain
+the address of the corresponding function RELATIVE to the starting address
+of the "call-out" section. The "Call-out" section must sit adjacent to the 
+isp.sa image in memory.
+
+The second section, the "Entry-point" section, is used by external routines
+to access the functions within the ISP. Since the isp.sa hex file contains
+no symbol names, this section contains function entry points that are fixed
+with respect to the top of the package. The currently defined entry-points
+are listed in section "68060 ISP entry points" below. A calling routine
+would simply execute a "bra" or "jmp" that jumped to the selected function
+entry-point.
+
+For example, if the 68060 hardware took a "Unimplemented Integer Instruction"
+exception (vector #61), the operating system should execute something
+similar to:
+
+	bra	_060ISP_TOP+128+0
+
+(_060ISP_TOP is the starting address of the "Call-out" section; the "Call-out"
+section is 128 bytes long; and the Unimplemented Integer ISP handler entry 
+point is located 0 bytes from the top of the "Entry-point" section.)
+
+The third section is the code section. After entering through an "Entry-point",
+the entry code jumps to the appropriate emulation code within the code section.
+
+68060ISP call-outs: (details in iskeleton.s)
+--------------------
+0x000:	_060_real_chk
+0x004:	_060_real_divbyzero
+0x008:	_060_real_trace
+0x00c:	_060_real_access
+0x010:	_060_isp_done
+
+0x014:	_060_real_cas
+0x018:	_060_real_cas2
+0x01c:	_060_real_lock_page
+0x020:	_060_real_unlock_page
+
+0x024:	(Motorola reserved)
+0x028:	(Motorola reserved)
+0x02c:	(Motorola reserved)
+0x030:	(Motorola reserved)
+0x034:	(Motorola reserved)
+0x038:	(Motorola reserved)
+0x03c:	(Motorola reserved)
+
+0x040:	_060_imem_read
+0x044:	_060_dmem_read
+0x048:	_060_dmem_write
+0x04c:	_060_imem_read_word
+0x050:	_060_imem_read_long
+0x054:	_060_dmem_read_byte
+0x058:	_060_dmem_read_word
+0x05c:	_060_dmem_read_long
+0x060:	_060_dmem_write_byte
+0x064:	_060_dmem_write_word
+0x068:	_060_dmem_write_long
+
+0x06c:	(Motorola reserved)
+0x070:	(Motorola reserved)
+0x074:	(Motorola reserved)
+0x078:	(Motorola reserved)
+0x07c:	(Motorola reserved)
+
+68060ISP entry points:
+-----------------------
+0x000:	_060_isp_unimp
+
+0x008:	_060_isp_cas
+0x010:	_060_isp_cas2
+0x018:	_060_isp_cas_finish
+0x020:	_060_isp_cas2_finish
+0x028:	_060_isp_cas_inrange
+0x030:	_060_isp_cas_terminate
+0x038:	_060_isp_cas_restart
+
+Integrating cas/cas2:
+---------------------
+The instructions "cas2" and "cas" (when used with a misaligned effective
+address) take the Unimplemented Integer Instruction exception. When the
+060ISP is installed properly, these instructions will enter through the
+_060_isp_unimp() entry point of the ISP.
+
+After the 060ISP decodes the instruction type and fetches the appropriate
+data registers, and BEFORE the actual emulated transfers occur, the 
+package calls either the "Call-out" _060_real_cas() or _060_real_cas2().
+If the emulation code provided by the 060ISP is sufficient for the
+host system (see isp.s source code), then these "Call-out"s should be
+made, by the system integrator, to point directly back into the package
+through the "Entry-point"s _060_isp_cas() or _060_isp_cas2().
+
+One other necessary action by the integrator is to supply the routines
+_060_real_lock_page() and _060_real_unlock_page(). These functions are
+defined further in iskeleton.s and the 68060 Software Package Specification.
+
+If the "core" emulation routines of either "cas" or "cas2" perform some
+actions which are too system-specific, then the system integrator must
+supply new emulation code. This new emulation code should reside within
+the functions _060_real_cas() or _060_real_cas2(). When this new emulation
+code has completed, then it should re-enter the 060ISP package through the
+"Entry-point" _060_isp_cas_finish() or _060_isp_cas2_finish().
+To see what the register state is upon entering _060_real_cas() or
+_060_real_cas2() and what it should be upon return to the package through
+_060_isp_cas_finish() or _060_isp_cas2_finish(), please refer to the
+source code in isp.s.
+
+Miscellaneous:
+--------------
+
+_060_isp_unimp:
+----------------
+- documented in 2.2 in spec.
+- Basic flow:
+	exception taken ---> enter _060_isp_unimp   --|
+						      |
+						      |
+            may exit through _060_real_itrace    <----|
+						  or  |
+            may exit through _060_real_chk       <----|
+						  or  |
+            may exit through _060_real_divbyzero <----|
+						  or  |
+            may exit through _060_isp_done       <----|
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/ifpsp060/isp.sa linux/arch/m68k/ifpsp060/isp.sa
--- v1.3.93/linux/arch/m68k/ifpsp060/isp.sa	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/ifpsp060/isp.sa	Mon Jan  8 22:08:19 1996
@@ -0,0 +1,392 @@
+	.long	0x60ff0000,0x02360000,0x60ff0000,0x16260000
+	.long	0x60ff0000,0x12dc0000,0x60ff0000,0x11ea0000
+	.long	0x60ff0000,0x10de0000,0x60ff0000,0x12a40000
+	.long	0x60ff0000,0x12560000,0x60ff0000,0x122a0000
+	.long	0x51fc51fc,0x51fc51fc,0x51fc51fc,0x51fc51fc
+	.long	0x51fc51fc,0x51fc51fc,0x51fc51fc,0x51fc51fc
+	.long	0x51fc51fc,0x51fc51fc,0x51fc51fc,0x51fc51fc
+	.long	0x51fc51fc,0x51fc51fc,0x51fc51fc,0x51fc51fc
+	.long	0x2f00203a,0xfefc487b,0x0930ffff,0xfef8202f
+	.long	0x00044e74,0x00042f00,0x203afeea,0x487b0930
+	.long	0xfffffee2,0x202f0004,0x4e740004,0x2f00203a
+	.long	0xfed8487b,0x0930ffff,0xfecc202f,0x00044e74
+	.long	0x00042f00,0x203afec6,0x487b0930,0xfffffeb6
+	.long	0x202f0004,0x4e740004,0x2f00203a,0xfeb4487b
+	.long	0x0930ffff,0xfea0202f,0x00044e74,0x00042f00
+	.long	0x203afea2,0x487b0930,0xfffffe8a,0x202f0004
+	.long	0x4e740004,0x2f00203a,0xfe90487b,0x0930ffff
+	.long	0xfe74202f,0x00044e74,0x00042f00,0x203afe7e
+	.long	0x487b0930,0xfffffe5e,0x202f0004,0x4e740004
+	.long	0x2f00203a,0xfe6c487b,0x0930ffff,0xfe48202f
+	.long	0x00044e74,0x00042f00,0x203afe76,0x487b0930
+	.long	0xfffffe32,0x202f0004,0x4e740004,0x2f00203a
+	.long	0xfe64487b,0x0930ffff,0xfe1c202f,0x00044e74
+	.long	0x00042f00,0x203afe52,0x487b0930,0xfffffe06
+	.long	0x202f0004,0x4e740004,0x2f00203a,0xfe40487b
+	.long	0x0930ffff,0xfdf0202f,0x00044e74,0x00042f00
+	.long	0x203afe2e,0x487b0930,0xfffffdda,0x202f0004
+	.long	0x4e740004,0x2f00203a,0xfe1c487b,0x0930ffff
+	.long	0xfdc4202f,0x00044e74,0x00042f00,0x203afe0a
+	.long	0x487b0930,0xfffffdae,0x202f0004,0x4e740004
+	.long	0x2f00203a,0xfdf8487b,0x0930ffff,0xfd98202f
+	.long	0x00044e74,0x00042f00,0x203afde6,0x487b0930
+	.long	0xfffffd82,0x202f0004,0x4e740004,0x2f00203a
+	.long	0xfdd4487b,0x0930ffff,0xfd6c202f,0x00044e74
+	.long	0x00042f00,0x203afdc2,0x487b0930,0xfffffd56
+	.long	0x202f0004,0x4e740004,0x4e56ffa0,0x48ee3fff
+	.long	0xffc02d56,0xfff8082e,0x00050004,0x66084e68
+	.long	0x2d48fffc,0x600841ee,0x000c2d48,0xfffc422e
+	.long	0xffaa3d6e,0x0004ffa8,0x2d6e0006,0xffa4206e
+	.long	0xffa458ae,0xffa461ff,0xffffff26,0x2d40ffa0
+	.long	0x0800001e,0x67680800,0x00166628,0x61ff0000
+	.long	0x0cb0082e,0x00050004,0x670000ac,0x082e0002
+	.long	0xffaa6700,0x00a2082e,0x00070004,0x66000186
+	.long	0x600001b0,0x61ff0000,0x0a28082e,0x0002ffaa
+	.long	0x660e082e,0x0005ffaa,0x6600010a,0x60000078
+	.long	0x082e0005,0x000467ea,0x082e0005,0xffaa6600
+	.long	0x01264a2e,0x00046b00,0x014c6000,0x01760800
+	.long	0x0018670a,0x61ff0000,0x07ae6000,0x004a0800
+	.long	0x001b6730,0x48400c00,0x00fc670a,0x61ff0000
+	.long	0x0e926000,0x0032206e,0xffa454ae,0xffa461ff
+	.long	0xfffffe68,0x4a816600,0x019861ff,0x00000d20
+	.long	0x60000014,0x61ff0000,0x08c40c2e,0x0010ffaa
+	.long	0x66000004,0x605c1d6e,0xffa90005,0x082e0005
+	.long	0x00046606,0x206efffc,0x4e604cee,0x3fffffc0
+	.long	0x082e0007,0x00046612,0x2d6effa4,0x00062cae
+	.long	0xfff84e5e,0x60ffffff,0xfd622d6e,0xfff8fffc
+	.long	0x3d6e0004,0x00002d6e,0x00060008,0x2d6effa4
+	.long	0x00023d7c,0x20240006,0x598e4e5e,0x60ffffff
+	.long	0xfd0e1d6e,0xffa90005,0x4cee3fff,0xffc03cae
+	.long	0x00042d6e,0x00060008,0x2d6effa4,0x00023d7c
+	.long	0x20180006,0x2c6efff8,0xdffc0000,0x006060ff
+	.long	0xfffffcb0,0x1d6effa9,0x00054cee,0x3fffffc0
+	.long	0x3cae0004,0x2d6e0006,0x00082d6e,0xffa40002
+	.long	0x3d7c2014,0x00062c6e,0xfff8dffc,0x00000060
+	.long	0x60ffffff,0xfc941d6e,0xffa90005,0x4cee3fff
+	.long	0xffc02d6e,0x0006000c,0x3d7c2014,0x000a2d6e
+	.long	0xffa40006,0x2c6efff8,0xdffc0000,0x006460ff
+	.long	0xfffffc66,0x1d6effa9,0x00054cee,0x3fffffc0
+	.long	0x2d6e0006,0x000c3d7c,0x2024000a,0x2d6effa4
+	.long	0x00062c6e,0xfff8dffc,0x00000064,0x60ffffff
+	.long	0xfc4e1d6e,0xffa90005,0x4cee3fff,0xffc03d7c
+	.long	0x00f4000e,0x2d6effa4,0x000a3d6e,0x00040008
+	.long	0x2c6efff8,0xdffc0000,0x006860ff,0xfffffc4c
+	.long	0x2c882d40,0xfffc4fee,0xffc04cdf,0x7fff2f2f
+	.long	0x000c2f6f,0x00040010,0x2f6f000c,0x00042f6f
+	.long	0x0008000c,0x2f5f0004,0x3f7c4008,0x00066028
+	.long	0x4cee3fff,0xffc04e5e,0x514f2eaf,0x00083f6f
+	.long	0x000c0004,0x3f7c4008,0x00062f6f,0x00020008
+	.long	0x2f7c0942,0x8001000c,0x08170005,0x670608ef
+	.long	0x0002000d,0x60ffffff,0xfbcc0c2e,0x0040ffaa
+	.long	0x660c4280,0x102effab,0x2daeffac,0x0ce04e75
+	.long	0x2040302e,0xffa03200,0x0240003f,0x02810000
+	.long	0x0007303b,0x020a4efb,0x00064afc,0x00400000
+	.long	0x00000000,0x00000000,0x00000000,0x00000000
+	.long	0x00000000,0x00000000,0x00000000,0x00000080
+	.long	0x0086008c,0x00920098,0x009e00a4,0x00aa00b0
+	.long	0x00ce00ec,0x010a0128,0x01460164,0x01820196
+	.long	0x01b401d2,0x01f0020e,0x022c024a,0x0268027c
+	.long	0x029a02b8,0x02d602f4,0x03120330,0x034e036c
+	.long	0x036c036c,0x036c036c,0x036c036c,0x036c03d6
+	.long	0x03f0040a,0x042a03ca,0x00000000,0x0000206e
+	.long	0xffe04e75,0x206effe4,0x4e75206e,0xffe84e75
+	.long	0x206effec,0x4e75206e,0xfff04e75,0x206efff4
+	.long	0x4e75206e,0xfff84e75,0x206efffc,0x4e752008
+	.long	0x206effe0,0xd0882d40,0xffe02d48,0xffac1d7c
+	.long	0x0000ffab,0x1d7c0040,0xffaa4e75,0x2008206e
+	.long	0xffe4d088,0x2d40ffe4,0x2d48ffac,0x1d7c0001
+	.long	0xffab1d7c,0x0040ffaa,0x4e752008,0x206effe8
+	.long	0xd0882d40,0xffe82d48,0xffac1d7c,0x0002ffab
+	.long	0x1d7c0040,0xffaa4e75,0x2008206e,0xffecd088
+	.long	0x2d40ffec,0x2d48ffac,0x1d7c0003,0xffab1d7c
+	.long	0x0040ffaa,0x4e752008,0x206efff0,0xd0882d40
+	.long	0xfff02d48,0xffac1d7c,0x0004ffab,0x1d7c0040
+	.long	0xffaa4e75,0x2008206e,0xfff4d088,0x2d40fff4
+	.long	0x2d48ffac,0x1d7c0005,0xffab1d7c,0x0040ffaa
+	.long	0x4e752008,0x206efff8,0xd0882d40,0xfff82d48
+	.long	0xffac1d7c,0x0006ffab,0x1d7c0040,0xffaa4e75
+	.long	0x1d7c0004,0xffaa2008,0x206efffc,0xd0882d40
+	.long	0xfffc4e75,0x202effe0,0x2d40ffac,0x90882d40
+	.long	0xffe02040,0x1d7c0000,0xffab1d7c,0x0040ffaa
+	.long	0x4e75202e,0xffe42d40,0xffac9088,0x2d40ffe4
+	.long	0x20401d7c,0x0001ffab,0x1d7c0040,0xffaa4e75
+	.long	0x202effe8,0x2d40ffac,0x90882d40,0xffe82040
+	.long	0x1d7c0002,0xffab1d7c,0x0040ffaa,0x4e75202e
+	.long	0xffec2d40,0xffac9088,0x2d40ffec,0x20401d7c
+	.long	0x0003ffab,0x1d7c0040,0xffaa4e75,0x202efff0
+	.long	0x2d40ffac,0x90882d40,0xfff02040,0x1d7c0004
+	.long	0xffab1d7c,0x0040ffaa,0x4e75202e,0xfff42d40
+	.long	0xffac9088,0x2d40fff4,0x20401d7c,0x0005ffab
+	.long	0x1d7c0040,0xffaa4e75,0x202efff8,0x2d40ffac
+	.long	0x90882d40,0xfff82040,0x1d7c0006,0xffab1d7c
+	.long	0x0040ffaa,0x4e751d7c,0x0008ffaa,0x202efffc
+	.long	0x90882d40,0xfffc2040,0x4e75206e,0xffa454ae
+	.long	0xffa461ff,0xfffff9d4,0x4a8166ff,0xfffffd04
+	.long	0x3040d1ee,0xffe04e75,0x206effa4,0x54aeffa4
+	.long	0x61ffffff,0xf9b64a81,0x66ffffff,0xfce63040
+	.long	0xd1eeffe4,0x4e75206e,0xffa454ae,0xffa461ff
+	.long	0xfffff998,0x4a8166ff,0xfffffcc8,0x3040d1ee
+	.long	0xffe84e75,0x206effa4,0x54aeffa4,0x61ffffff
+	.long	0xf97a4a81,0x66ffffff,0xfcaa3040,0xd1eeffec
+	.long	0x4e75206e,0xffa454ae,0xffa461ff,0xfffff95c
+	.long	0x4a8166ff,0xfffffc8c,0x3040d1ee,0xfff04e75
+	.long	0x206effa4,0x54aeffa4,0x61ffffff,0xf93e4a81
+	.long	0x66ffffff,0xfc6e3040,0xd1eefff4,0x4e75206e
+	.long	0xffa454ae,0xffa461ff,0xfffff920,0x4a8166ff
+	.long	0xfffffc50,0x3040d1ee,0xfff84e75,0x206effa4
+	.long	0x54aeffa4,0x61ffffff,0xf9024a81,0x66ffffff
+	.long	0xfc323040,0xd1eefffc,0x4e752f01,0x206effa4
+	.long	0x54aeffa4,0x61ffffff,0xf8e24a81,0x66ffffff
+	.long	0xfc12221f,0x207614e0,0x08000008,0x670e48e7
+	.long	0x3c002a00,0x260860ff,0x000000ec,0x2f022200
+	.long	0xe9590241,0x000f2236,0x14c00800,0x000b6602
+	.long	0x48c12400,0xef5a0282,0x00000003,0xe5a949c0
+	.long	0xd081d1c0,0x241f4e75,0x1d7c0080,0xffaa206e
+	.long	0xffa44e75,0x206effa4,0x54aeffa4,0x61ffffff
+	.long	0xf87a4a81,0x66ffffff,0xfbaa3040,0x4e75206e
+	.long	0xffa458ae,0xffa461ff,0xfffff876,0x4a8166ff
+	.long	0xfffffb90,0x20404e75,0x206effa4,0x54aeffa4
+	.long	0x61ffffff,0xf8464a81,0x66ffffff,0xfb763040
+	.long	0xd1eeffa4,0x55884e75,0x206effa4,0x54aeffa4
+	.long	0x61ffffff,0xf8264a81,0x66ffffff,0xfb56206e
+	.long	0xffa45588,0x08000008,0x670e48e7,0x3c002a00
+	.long	0x260860ff,0x00000030,0x2f022200,0xe9590241
+	.long	0x000f2236,0x14c00800,0x000b6602,0x48c12400
+	.long	0xef5a0282,0x00000003,0xe5a949c0,0xd081d1c0
+	.long	0x241f4e75,0x08050006,0x67044282,0x6016e9c5
+	.long	0x24042436,0x24c00805,0x000b6602,0x48c2e9c5
+	.long	0x0542e1aa,0x08050007,0x67024283,0xe9c50682
+	.long	0x0c000002,0x6d346718,0x206effa4,0x58aeffa4
+	.long	0x61ffffff,0xf7ac4a81,0x66ffffff,0xfac66018
+	.long	0x206effa4,0x54aeffa4,0x61ffffff,0xf77e4a81
+	.long	0x66ffffff,0xfaae48c0,0xd680e9c5,0x07826700
+	.long	0x006a0c00,0x00026d34,0x6718206e,0xffa458ae
+	.long	0xffa461ff,0xfffff76a,0x4a8166ff,0xfffffa84
+	.long	0x601c206e,0xffa454ae,0xffa461ff,0xfffff73c
+	.long	0x4a8166ff,0xfffffa6c,0x48c06002,0x42802800
+	.long	0x08050002,0x67122043,0x61ffffff,0xf7764a81
+	.long	0x6624d082,0xd0846016,0xd6822043,0x61ffffff
+	.long	0xf7624a81,0x6610d084,0x6004d682,0x20032040
+	.long	0x4cdf003c,0x4e752043,0x203c0101,0x000160ff
+	.long	0xfffff9f0,0x322effa0,0x10010240,0x00072076
+	.long	0x04e0d0ee,0xffa20801,0x00076700,0x008c3001
+	.long	0xef580240,0x00072036,0x04c00801,0x00066752
+	.long	0x24002448,0xe19a2002,0x61ffffff,0xf71c4a81
+	.long	0x660000fc,0x544a204a,0xe19a2002,0x61ffffff
+	.long	0xf7084a81,0x660000e8,0x544a204a,0xe19a2002
+	.long	0x61ffffff,0xf6f44a81,0x660000d4,0x544a204a
+	.long	0xe19a2002,0x61ffffff,0xf6e04a81,0x660000c0
+	.long	0x4e752400,0x2448e048,0x61ffffff,0xf6cc4a81
+	.long	0x660000ac,0x544a204a,0x200261ff,0xfffff6ba
+	.long	0x4a816600,0x009a4e75,0x08010006,0x675c2448
+	.long	0x61ffffff,0xf6624a81,0x66000092,0x2400544a
+	.long	0x204a61ff,0xfffff650,0x4a816600,0x0080e14a
+	.long	0x1400544a,0x204a61ff,0xfffff63c,0x4a816600
+	.long	0x006ce18a,0x1400544a,0x204a61ff,0xfffff628
+	.long	0x4a816600,0x0058e18a,0x1400122e,0xffa0e209
+	.long	0x02410007,0x2d8214c0,0x4e752448,0x61ffffff
+	.long	0xf6064a81,0x66000036,0x2400544a,0x204a61ff
+	.long	0xfffff5f4,0x4a816600,0x0024e14a,0x1400122e
+	.long	0xffa0e209,0x02410007,0x3d8214c2,0x4e75204a
+	.long	0x203c00a1,0x000160ff,0xfffff8a8,0x204a203c
+	.long	0x01210001,0x60ffffff,0xf89a61ff,0xfffff914
+	.long	0x102effa2,0xe9180240,0x000f2436,0x04c00c2e
+	.long	0x0002ffa0,0x6d506728,0x244861ff,0xfffff5c4
+	.long	0x4a816600,0x009e2600,0x588a204a,0x61ffffff
+	.long	0xf5b24a81,0x6600008c,0x22002003,0x60000048
+	.long	0x244861ff,0xfffff59c,0x4a816600,0x00763200
+	.long	0x484048c0,0x48c1082e,0x0007ffa2,0x66000028
+	.long	0x48c26000,0x00222448,0x61ffffff,0xf5604a81
+	.long	0x6600005e,0x1200e048,0x49c049c1,0x082e0007
+	.long	0xffa26602,0x49c29480,0x42c30203,0x00049280
+	.long	0xb28242c4,0x86040203,0x0005382e,0xffa80204
+	.long	0x001a8803,0x3d44ffa8,0x082e0003,0xffa26602
+	.long	0x4e750804,0x00006602,0x4e751d7c,0x0010ffaa
+	.long	0x4e75204a,0x203c0101,0x000160ff,0xfffff7c4
+	.long	0x204a203c,0x01410001,0x60ffffff,0xf7b6102e
+	.long	0xffa10200,0x00386600,0x0208102e,0xffa10240
+	.long	0x00072e36,0x04c06700,0x00c0102e,0xffa3122e
+	.long	0xffa20240,0x0007e809,0x02410007,0x3d40ffb2
+	.long	0x3d41ffb4,0x2a3604c0,0x2c3614c0,0x082e0003
+	.long	0xffa2671a,0x4a875dee,0xffb06a02,0x44874a85
+	.long	0x5deeffb1,0x6a0844fc,0x00004086,0x40854a85
+	.long	0x66164a86,0x67000048,0xbe866306,0xcb466000
+	.long	0x00124c47,0x6005600a,0xbe85634e,0x61ff0000
+	.long	0x0068082e,0x0003ffa2,0x67244a2e,0xffb16702
+	.long	0x4485102e,0xffb0b12e,0xffb1670c,0x0c868000
+	.long	0x00006226,0x44866006,0x0806001f,0x661c44ee
+	.long	0xffa84a86,0x42eeffa8,0x302effb2,0x322effb4
+	.long	0x2d8504c0,0x2d8614c0,0x4e7508ee,0x0001ffa9
+	.long	0x08ae0000,0xffa94e75,0x022e001e,0xffa9002e
+	.long	0x0020ffaa,0x4e750c87,0x0000ffff,0x621e4281
+	.long	0x48454846,0x3a068ac7,0x32054846,0x3a068ac7
+	.long	0x48413205,0x42454845,0x2c014e75,0x42aeffbc
+	.long	0x422effb6,0x42810807,0x001f660e,0x52aeffbc
+	.long	0xe38fe38e,0xe3956000,0xffee2607,0x24054842
+	.long	0x4843b443,0x6606323c,0xffff600a,0x220582c3
+	.long	0x02810000,0xffff2f06,0x42464846,0x26072401
+	.long	0xc4c74843,0xc6c12805,0x98834844,0x30043806
+	.long	0x4a406600,0x000ab484,0x63045381,0x60de2f05
+	.long	0x2c014846,0x2a0761ff,0x0000006a,0x24052606
+	.long	0x2a1f2c1f,0x9c839b82,0x64ff0000,0x001a5381
+	.long	0x42822607,0x48434243,0xdc83db82,0x26074243
+	.long	0x4843da83,0x4a2effb6,0x66163d41,0xffb84281
+	.long	0x48454846,0x3a064246,0x50eeffb6,0x6000ff6c
+	.long	0x3d41ffba,0x3c054846,0x48452e2e,0xffbc670a
+	.long	0x5387e28d,0xe29651cf,0xfffa2a06,0x2c2effb8
+	.long	0x4e752406,0x26062805,0x48434844,0xccc5cac3
+	.long	0xc4c4c6c4,0x42844846,0xdc45d744,0xdc42d744
+	.long	0x48464245,0x42424845,0x4842da82,0xda834e75
+	.long	0x700461ff,0xfffff61c,0x0c2e0080,0xffaa6712
+	.long	0x244861ff,0xfffff2dc,0x4a81661e,0x2e006000
+	.long	0xfde658ae,0xffa461ff,0xfffff286,0x4a8166ff
+	.long	0xfffff5a0,0x2e006000,0xfdce61ff,0xfffff5ce
+	.long	0x204a203c,0x01010001,0x60ffffff,0xf556102e
+	.long	0xffa10c00,0x00076e00,0x00b40240,0x00072636
+	.long	0x04c0342e,0xffa24241,0x1202e95a,0x02420007
+	.long	0x283624c0,0x4a846700,0x00884a83,0x67000082
+	.long	0x422effb0,0x082e0003,0xffa26718,0x4a836c08
+	.long	0x4483002e,0x0001ffb0,0x4a846c08,0x44840a2e
+	.long	0x0001ffb0,0x2a032c03,0x2e044846,0x4847c6c4
+	.long	0xc8c6cac7,0xccc74287,0x4843d644,0xdd87d645
+	.long	0xdd874843,0x42444245,0x48444845,0xd885d886
+	.long	0x4a2effb0,0x67084683,0x46845283,0xd9872d83
+	.long	0x24c044fc,0x00002d84,0x14c042c7,0x02070008
+	.long	0x1c2effa9,0x02060010,0x8c071d46,0xffa94e75
+	.long	0x42b624c0,0x42b614c0,0x7e0460e4,0x700461ff
+	.long	0xfffff510,0x0c2e0080,0xffaa6714,0x244861ff
+	.long	0xfffff1d0,0x4a816600,0x00202600,0x6000ff34
+	.long	0x58aeffa4,0x61ffffff,0xf1784a81,0x66ffffff
+	.long	0xf4922600,0x6000ff1c,0x61ffffff,0xf4c0204a
+	.long	0x203c0101,0x000160ff,0xfffff448,0x2d40ffb4
+	.long	0x2200e958,0x0240000f,0x227604c0,0x2d49ffb0
+	.long	0x2001ec49,0x02410007,0x2a3614c0,0x02400007
+	.long	0x263604c0,0x3d40ffba,0x302effa2,0x2200e958
+	.long	0x0240000f,0x207604c0,0x2d48ffbc,0x2001ec49
+	.long	0x02410007,0x283614c0,0x02400007,0x243604c0
+	.long	0x3d40ffb8,0x082e0001,0xffa056c7,0x082e0005
+	.long	0x000456c6,0x24482649,0x22072006,0x61ffffff
+	.long	0xf05c204a,0x4a8066ff,0x000001c8,0x22072006
+	.long	0x204b61ff,0xfffff046,0x204b4a80,0x660a204a
+	.long	0x224b60ff,0xfffff020,0x2f002207,0x2006204a
+	.long	0x61ffffff,0xf03e201f,0x204b60ff,0x00000194
+	.long	0x082e0001,0xffa06648,0x44eeffa8,0xb0426602
+	.long	0xb24342ee,0xffa84a04,0x6610362e,0xffba3d81
+	.long	0x34c2342e,0xffb83d80,0x24c2082e,0x00050004
+	.long	0x56c22002,0x51c1206e,0xffbc61ff,0xffffeff4
+	.long	0x200251c1,0x206effb0,0x61ffffff,0xefe64e75
+	.long	0x44eeffa8,0xb0826602,0xb28342ee,0xffa84a04
+	.long	0x6610362e,0xffba2d81,0x34c0342e,0xffb82d80
+	.long	0x24c0082e,0x00050004,0x56c22002,0x50c1206e
+	.long	0xffbc61ff,0xffffefac,0x200250c1,0x206effb0
+	.long	0x61ffffff,0xef9e4e75,0x202effb4,0x6000feae
+	.long	0x082e0001,0xffa06610,0x700261ff,0xfffff364
+	.long	0x2d48ffb4,0x51c7600e,0x700461ff,0xfffff354
+	.long	0x2d48ffb4,0x50c7302e,0xffa22200,0xec480240
+	.long	0x00072436,0x04c00241,0x00072836,0x14c03d41
+	.long	0xffb8082e,0x00050004,0x56c62448,0x22072006
+	.long	0x61ffffff,0xef284a80,0x66000096,0x204a60ff
+	.long	0xffffeeee,0x082e0001,0xffa0662c,0x44eeffa8
+	.long	0xb04442ee,0xffa84a01,0x6608362e,0xffb83d80
+	.long	0x34c2206e,0xffb451c1,0x082e0005,0x000456c0
+	.long	0x61ffffff,0xeefe4e75,0x44eeffa8,0xb08442ee
+	.long	0xffa84a01,0x6608362e,0xffb82d80,0x34c0206e
+	.long	0xffb450c1,0x082e0005,0x000456c0,0x61ffffff
+	.long	0xeed24e75,0x4e7b6000,0x4e7b6001,0x0c2e00fc
+	.long	0xffa167ff,0xffffff24,0x206effb4,0x082e0001
+	.long	0xffa056c7,0x6000ff40,0x4e7b6000,0x4e7b6001
+	.long	0x24482f00,0x61ffffff,0xf264201f,0x588f518f
+	.long	0x518e721a,0x41ef0008,0x43ef0000,0x22d851c9
+	.long	0xfffc3d7c,0x4008000a,0x2d4a000c,0x2d400010
+	.long	0x4cee3fff,0xffc04e5e,0x60ffffff,0xedf84280
+	.long	0x43fb0170,0x000005ae,0xb3c86d0e,0x43fb0170
+	.long	0x00000010,0xb1c96d02,0x4e7570ff,0x4e754a06
+	.long	0x66047001,0x60027005,0x4a076700,0x01e42448
+	.long	0x26492848,0x2a49568c,0x568d220a,0x40c7007c
+	.long	0x07004e7a,0x60004e7b,0x00004e7b,0x0001f58a
+	.long	0xf58cf58b,0xf58df46a,0xf46cf46b,0xf46d2441
+	.long	0x56812841,0xf5caf5cc,0x247c8000,0x0000267c
+	.long	0xa0000000,0x287c0000,0x00002008,0x02000003
+	.long	0x671c0c00,0x00026700,0x00966000,0x010251fc
+	.long	0x4e7ba008,0x0e911000,0x0e900000,0x6002600e
+	.long	0xb082661c,0xb2836618,0x0e915800,0x6002600e
+	.long	0x4e7bb008,0x0e904800,0x4e7bc008,0x6034600e
+	.long	0x4e7bb008,0x0e900800,0x4e7bc008,0x6012600e
+	.long	0x4e714e71,0x4e714e71,0x4e714e71,0x4e7160b0
+	.long	0x4e7b6000,0x4e7b6001,0x46c751c4,0x60ffffff
+	.long	0xfd424e7b,0x60004e7b,0x600146c7,0x50c460ff
+	.long	0xfffffd30,0x51fc51fc,0x51fc51fc,0x51fc51fc
+	.long	0x4e7ba008,0x0e911000,0x0e900000,0x6002600e
+	.long	0xb082662c,0xb2836628,0x0e915800,0x6002600e
+	.long	0x48440e58,0x48004e7b,0xb0084844,0x6002600e
+	.long	0x0e504800,0x4e7bc008,0x6000ffa8,0x4e71600e
+	.long	0x48400e58,0x08004e7b,0xb0084840,0x6002600e
+	.long	0x0e500800,0x4e7bc008,0x6000ff76,0x4e71600e
+	.long	0x4e714e71,0x4e714e71,0x4e714e71,0x4e716090
+	.long	0x4e7ba008,0x0e911000,0x0e900000,0x6002600e
+	.long	0xb082663c,0xb2836638,0x0e915800,0x6002600e
+	.long	0xe19c0e18,0x48004844,0x0e584800,0x6002600e
+	.long	0xe19c4e7b,0xb0080e10,0x48006004,0x4e71600e
+	.long	0x4e7bc008,0x6000ff2c,0x4e714e71,0x4e71600e
+	.long	0xe1980e18,0x08004840,0x0e580800,0x6002600e
+	.long	0xe1984e7b,0xb0080e10,0x08006004,0x4e71600e
+	.long	0x4e7bc008,0x6000feea,0x4e714e71,0x4e71600c
+	.long	0x4e714e71,0x4e714e71,0x4e714e71,0x6000ff72
+	.long	0x24482649,0x28482a49,0x528c528d,0x220a40c7
+	.long	0x007c0700,0x4e7a6000,0x4e7b0000,0x4e7b0001
+	.long	0xf58af58c,0xf58bf58d,0xf46af46c,0xf46bf46d
+	.long	0x24415681,0x2841f5ca,0xf5cc247c,0x80000000
+	.long	0x267ca000,0x0000287c,0x00000000,0x20080800
+	.long	0x00006600,0x009a6016,0x51fc51fc,0x51fc51fc
+	.long	0x4e7ba008,0x0e511000,0x0e500000,0x6002600e
+	.long	0xb042661c,0xb2436618,0x0e515800,0x6002600e
+	.long	0x4e7bb008,0x0e504800,0x4e7bc008,0x6034600e
+	.long	0x4e7bb008,0x0e500800,0x4e7bc008,0x6012600e
+	.long	0x4e714e71,0x4e714e71,0x4e714e71,0x4e7160b0
+	.long	0x4e7b6000,0x4e7b6001,0x46c751c4,0x60ffffff
+	.long	0xfb624e7b,0x60004e7b,0x600146c7,0x50c460ff
+	.long	0xfffffb50,0x51fc51fc,0x51fc51fc,0x51fc51fc
+	.long	0x4e7ba008,0x0e511000,0x0e500000,0x6002600e
+	.long	0xb042662c,0xb2436628,0x0e515800,0x6002600e
+	.long	0xe09c0e18,0x48004e7b,0xb008e19c,0x6002600e
+	.long	0x0e104800,0x4e7bc008,0x6000ffa8,0x4e71600e
+	.long	0xe0980e18,0x08004e7b,0xb008e198,0x6002600e
+	.long	0x0e100800,0x4e7bc008,0x6000ff76,0x4e71600e
+	.long	0x4e714e71,0x4e714e71,0x4e714e71,0x4e716090
+	.long	0x4a066604,0x70016002,0x70054a07,0x660000c6
+	.long	0x22482448,0x528a2602,0xe04a40c7,0x007c0700
+	.long	0x4e7a6000,0x4e7b0000,0x4e7b0001,0xf589f58a
+	.long	0xf469f46a,0x227c8000,0x0000247c,0xa0000000
+	.long	0x267c0000,0x00006016,0x51fc51fc,0x51fc51fc
+	.long	0x4e7b9008,0x0e500000,0xb0446624,0x6002600e
+	.long	0x0e182800,0x4e7ba008,0x0e103800,0x6002600e
+	.long	0x4e7bb008,0x604c4e71,0x4e714e71,0x4e71600e
+	.long	0xe0980e18,0x08004e7b,0xa008e198,0x6002600e
+	.long	0x0e100800,0x4e7bb008,0x60164e71,0x4e71600e
+	.long	0x4e714e71,0x4e714e71,0x4e714e71,0x4e7160a0
+	.long	0x4e7b6000,0x4e7b6001,0x46c751c1,0x60ffffff
+	.long	0xfb164e7b,0x60004e7b,0x600146c7,0x50c160ff
+	.long	0xfffffb04,0x22482448,0x568a2208,0x08010000
+	.long	0x660000c2,0x26024842,0x40c7007c,0x07004e7a
+	.long	0x60004e7b,0x00004e7b,0x0001f589,0xf58af469
+	.long	0xf46a227c,0x80000000,0x247ca000,0x0000267c
+	.long	0x00000000,0x601851fc,0x51fc51fc,0x51fc51fc
+	.long	0x4e7b9008,0x0e900000,0xb0846624,0x6002600e
+	.long	0x0e582800,0x4e7ba008,0x0e503800,0x6002600e
+	.long	0x4e7bb008,0x604c4e71,0x4e714e71,0x4e71600e
+	.long	0x48400e58,0x08004840,0x4e7ba008,0x6002600e
+	.long	0x0e500800,0x4e7bb008,0x60164e71,0x4e71600e
+	.long	0x4e714e71,0x4e714e71,0x4e714e71,0x4e7160a0
+	.long	0x4e7b6000,0x4e7b6001,0x46c751c1,0x60ffffff
+	.long	0xfa464e7b,0x60004e7b,0x600146c7,0x50c160ff
+	.long	0xfffffa34,0x2a02e08a,0x26024842,0x40c7007c
+	.long	0x07004e7a,0x60004e7b,0x00004e7b,0x0001f589
+	.long	0xf58af469,0xf46a227c,0x80000000,0x247ca000
+	.long	0x0000267c,0x00000000,0x601451fc,0x51fc51fc
+	.long	0x4e7b9008,0x0e900000,0xb0846624,0x6002600e
+	.long	0x0e182800,0x0e583800,0x4e7ba008,0x6002600e
+	.long	0x0e105800,0x4e7bb008,0x6000ff88,0x4e71600e
+	.long	0xe1980e18,0x08004840,0x0e580800,0x6002600e
+	.long	0xe1984e7b,0xa0080e10,0x08006004,0x4e71600e
+	.long	0x4e7bb008,0x6000ff4a,0x4e714e71,0x4e71600e
+	.long	0x4e714e71,0x4e714e71,0x4e714e71,0x4e716090
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/ifpsp060/itest.sa linux/arch/m68k/ifpsp060/itest.sa
--- v1.3.93/linux/arch/m68k/ifpsp060/itest.sa	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/ifpsp060/itest.sa	Mon Jan  8 22:08:20 1996
@@ -0,0 +1,1281 @@
+	dc.l	$60ff0000,$005c5465,$7374696e,$67203638
+	dc.l	$30363020,$49535020,$73746172,$7465643a
+	dc.l	$0a007061,$73736564,$0a002066,$61696c65
+	dc.l	$640a0000,$4a80660e,$487affe8,$61ff0000
+	dc.l	$4f9a588f,$4e752f01,$61ff0000,$4fa4588f
+	dc.l	$487affd8,$61ff0000,$4f82588f,$4e754e56
+	dc.l	$ff6048e7,$3f3c487a,$ff9e61ff,$00004f6c
+	dc.l	$588f42ae,$ff78487b,$01700000,$00ea61ff
+	dc.l	$00004f58,$588f61ff,$000000f0,$61ffffff
+	dc.l	$ffa642ae,$ff78487b,$01700000,$0af661ff
+	dc.l	$00004f38,$588f61ff,$00000af8,$61ffffff
+	dc.l	$ff8642ae,$ff78487b,$01700000,$179c61ff
+	dc.l	$00004f18,$588f61ff,$0000179c,$61ffffff
+	dc.l	$ff6642ae,$ff78487b,$01700000,$038661ff
+	dc.l	$00004ef8,$588f61ff,$00000380,$61ffffff
+	dc.l	$ff4642ae,$ff78487b,$01700000,$202c61ff
+	dc.l	$00004ed8,$588f2d7c,$00000002,$ff7461ff
+	dc.l	$0000202c,$61ffffff,$ff1e42ae,$ff78487b
+	dc.l	$01700000,$0d7c61ff,$00004eb0,$588f61ff
+	dc.l	$00000d74,$61ffffff,$fefe42ae,$ff78487b
+	dc.l	$01700000,$0f8e61ff,$00004e90,$588f61ff
+	dc.l	$00000f88,$61ffffff,$fede4cdf,$3cfc4e5e
+	dc.l	$4e750936,$342d6269,$74206d75,$6c746970
+	dc.l	$6c792e2e,$2e0051fc,$52aeff78,$4cfb3fff
+	dc.l	$01700000,$4e184281,$243c9999,$9999263c
+	dc.l	$88888888,$3d7c0004,$ff7c44fc,$000048ee
+	dc.l	$7fffff80,$4c013402,$42eeff7e,$48ee7fff
+	dc.l	$ffc042ae,$ff8842ae,$ff8c61ff,$00004da6
+	dc.l	$4a0066ff,$00004dcc,$52aeff78,$4cfb3fff
+	dc.l	$01700000,$4dc8223c,$77777777,$243c9999
+	dc.l	$99997600,$3d7c0004,$ff7c44fc,$000048ee
+	dc.l	$7fffff80,$4c013402,$42eeff7e,$48ee7fff
+	dc.l	$ffc042ae,$ff8842ae,$ff8c61ff,$00004d56
+	dc.l	$4a0066ff,$00004d7c,$52aeff78,$4cfb3fff
+	dc.l	$01700000,$4d787210,$243c6666,$66663d7c
+	dc.l	$0000ff7c,$44fc0000,$48ee7fff,$ff804c01
+	dc.l	$240242ee,$ff7e48ee,$7fffffc0,$2d7c0000
+	dc.l	$0006ff88,$61ff0000,$4d0c4a00,$66ff0000
+	dc.l	$4d3252ae,$ff784cfb,$3fff0170,$00004d2e
+	dc.l	$223c5555,$55557400,$76033d7c,$0000ff7c
+	dc.l	$44fc0000,$48ee7fff,$ff804c01,$340242ee
+	dc.l	$ff7e48ee,$7fffffc0,$2d7c0000,$0000ff88
+	dc.l	$2d7cffff,$ffffff8c,$61ff0000,$4cb84a00
+	dc.l	$66ff0000,$4cde52ae,$ff784cfb,$3fff0170
+	dc.l	$00004cda,$223c4000,$00007400,$76043d7c
+	dc.l	$0000ff7c,$44fc0000,$48ee7fff,$ff804c01
+	dc.l	$340242ee,$ff7e48ee,$7fffffc0,$2d7c0000
+	dc.l	$0001ff88,$2d7c0000,$0000ff8c,$61ff0000
+	dc.l	$4c644a00,$66ff0000,$4c8a52ae,$ff784cfb
+	dc.l	$3fff0170,$00004c86,$72ff7400,$76ff3d7c
+	dc.l	$0008ff7c,$44fc0000,$48ee7fff,$ff804c01
+	dc.l	$340242ee,$ff7e48ee,$7fffffc0,$2d7cffff
+	dc.l	$fffeff88,$2d7c0000,$0001ff8c,$61ff0000
+	dc.l	$4c144a00,$66ff0000,$4c3a52ae,$ff784cfb
+	dc.l	$3fff0170,$00004c36,$223c8000,$00007400
+	dc.l	$76ff3d7c,$0000ff7c,$44fc0000,$48ee7fff
+	dc.l	$ff804c01,$3c0242ee,$ff7e48ee,$7fffffc0
+	dc.l	$2d7c0000,$0000ff88,$2d7c8000,$0000ff8c
+	dc.l	$61ff0000,$4bc04a00,$66ff0000,$4be652ae
+	dc.l	$ff784cfb,$3fff0170,$00004be2,$223c8000
+	dc.l	$00007400,$76013d7c,$0008ff7c,$44fc0000
+	dc.l	$48ee7fff,$ff804c01,$3c0242ee,$ff7e48ee
+	dc.l	$7fffffc0,$2d7cffff,$ffffff88,$2d7c8000
+	dc.l	$0000ff8c,$61ff0000,$4b6c4a00,$66ff0000
+	dc.l	$4b9252ae,$ff784cfb,$3fff0170,$00004b8e
+	dc.l	$72017400,$263c8000,$00003d7c,$0008ff7c
+	dc.l	$44fc0000,$48ee7fff,$ff804c01,$3c0242ee
+	dc.l	$ff7e48ee,$7fffffc0,$2d7cffff,$ffffff88
+	dc.l	$2d7c8000,$0000ff8c,$61ff0000,$4b184a00
+	dc.l	$66ff0000,$4b3e222e,$ff784280,$4e75096d
+	dc.l	$6f766570,$2e2e2e00,$52aeff78,$4cfb3fff
+	dc.l	$01700000,$4b2841ee,$ff60303c,$aaaa4228
+	dc.l	$00004228,$00023d7c,$001fff7c,$44fc001f
+	dc.l	$48ee7fff,$ff800188,$000042ee,$ff7e48ee
+	dc.l	$7fffffc0,$12280002,$e1491228,$0000b041
+	dc.l	$66ff0000,$4ade61ff,$00004aaa,$4a0066ff
+	dc.l	$00004ad0,$52aeff78,$4cfb3fff,$01700000
+	dc.l	$4acc41ee,$ff64303c,$aaaa42a8,$fffc4290
+	dc.l	$42a80004,$3d7c001f,$ff7c44fc,$001f48ee
+	dc.l	$7fffff80,$01880000,$42eeff7e,$48ee7fff
+	dc.l	$ffc04aa8,$fffc66ff,$00004a88,$4aa80004
+	dc.l	$66ff0000,$4a7e0c90,$aa00aa00,$66ff0000
+	dc.l	$4a7261ff,$00004a3e,$4a0066ff,$00004a64
+	dc.l	$52aeff78,$4cfb3fff,$01700000,$4a6041ee
+	dc.l	$ff60303c,$aaaa4228,$00004228,$00023d7c
+	dc.l	$0000ff7c,$44fc0000,$48ee7fff,$ff800188
+	dc.l	$000042ee,$ff7e48ee,$7fffffc0,$12280002
+	dc.l	$e1491228,$0000b041,$66ff0000,$4a1661ff
+	dc.l	$000049e2,$4a0066ff,$00004a08,$52aeff78
+	dc.l	$4cfb3fff,$01700000,$4a0441ee,$ff60117c
+	dc.l	$00aa0000,$117c00aa,$00023d7c,$001fff7c
+	dc.l	$44fc001f,$48ee7fff,$ff800108,$000042ee
+	dc.l	$ff7e48ee,$7fffffc0,$3d7caaaa,$ff82323c
+	dc.l	$aaaab041,$66ff0000,$49ba61ff,$00004986
+	dc.l	$4a0066ff,$000049ac,$52aeff78,$4cfb3fff
+	dc.l	$01700000,$49a841ee,$ff60203c,$aaaaaaaa
+	dc.l	$42280000,$42280002,$42280004,$42280006
+	dc.l	$3d7c001f,$ff7c44fc,$001f48ee,$7fffff80
+	dc.l	$01c80000,$42eeff7e,$48ee7fff,$ffc01228
+	dc.l	$0006e189,$12280004,$e1891228,$0002e189
+	dc.l	$12280000,$b08166ff,$00004948,$61ff0000
+	dc.l	$49144a00,$66ff0000,$493a52ae,$ff784cfb
+	dc.l	$3fff0170,$00004936,$41eeff64,$203caaaa
+	dc.l	$aaaa42a8,$fffc4290,$42a80004,$42a80008
+	dc.l	$3d7c001f,$ff7c44fc,$001f48ee,$7fffff80
+	dc.l	$01c80000,$42eeff7e,$48ee7fff,$ffc04aa8
+	dc.l	$fffc66ff,$000048ec,$4aa80008,$66ff0000
+	dc.l	$48e20c90,$aa00aa00,$66ff0000,$48d60ca8
+	dc.l	$aa00aa00,$000466ff,$000048c8,$61ff0000
+	dc.l	$48944a00,$66ff0000,$48ba52ae,$ff784cfb
+	dc.l	$3fff0170,$000048b6,$41eeff60,$117c00aa
+	dc.l	$0000117c,$00aa0002,$117c00aa,$0004117c
+	dc.l	$00aa0006,$3d7c001f,$ff7c44fc,$001f48ee
+	dc.l	$7fffff80,$01480000,$42eeff7e,$48ee7fff
+	dc.l	$ffc02d7c,$aaaaaaaa,$ff80223c,$aaaaaaaa
+	dc.l	$b08166ff,$0000485c,$61ff0000,$48284a00
+	dc.l	$66ff0000,$484e52ae,$ff784cfb,$3fff0170
+	dc.l	$0000484a,$41eeff60,$3e3caaaa,$42280000
+	dc.l	$42280002,$3d7c001f,$ff7c44fc,$001f48ee
+	dc.l	$7fffff80,$0f880000,$42eeff7e,$48ee7fff
+	dc.l	$ffc01228,$0002e149,$12280000,$be4166ff
+	dc.l	$00004800,$61ff0000,$47cc4a00,$66ff0000
+	dc.l	$47f252ae,$ff784cfb,$3fff0170,$000047ee
+	dc.l	$41eeff60,$117c00aa,$0000117c,$00aa0002
+	dc.l	$3d7c001f,$ff7c44fc,$001f48ee,$7fffff80
+	dc.l	$0f080000,$42eeff7e,$48ee7fff,$ffc03d7c
+	dc.l	$aaaaff9e,$323caaaa,$be4166ff,$000047a4
+	dc.l	$61ff0000,$47704a00,$66ff0000,$479652ae
+	dc.l	$ff784cfb,$3fff0170,$00004792,$41eeff60
+	dc.l	$303caaaa,$42280000,$42280002,$3d7c001f
+	dc.l	$ff7c44fc,$001f48ee,$7fffff80,$01880000
+	dc.l	$42eeff7e,$48ee7fff,$ffc01228,$0002e149
+	dc.l	$12280000,$b04166ff,$00004748,$61ff0000
+	dc.l	$47144a00,$66ff0000,$473a52ae,$ff784cfb
+	dc.l	$3fff0170,$00004736,$41eeff60,$303caaaa
+	dc.l	$42280008,$4228000a,$3d7c001f,$ff7c44fc
+	dc.l	$001f48ee,$7fffff80,$01880008,$42eeff7e
+	dc.l	$48ee7fff,$ffc01228,$000ae149,$12280008
+	dc.l	$b04166ff,$000046ec,$61ff0000,$46b84a00
+	dc.l	$66ff0000,$46de52ae,$ff784cfb,$3fff0170
+	dc.l	$000046da,$41eeff60,$117c00aa,$0008117c
+	dc.l	$00aa000a,$3d7c001f,$ff7c44fc,$001f48ee
+	dc.l	$7fffff80,$01080008,$42eeff7e,$48ee7fff
+	dc.l	$ffc03d7c,$aaaaff82,$323caaaa,$b04166ff
+	dc.l	$00004690,$61ff0000,$465c4a00,$66ff0000
+	dc.l	$468252ae,$ff784cfb,$3fff0170,$0000467e
+	dc.l	$41eeff60,$203caaaa,$aaaa4228,$00084228
+	dc.l	$000a4228,$000c4228,$000e3d7c,$001fff7c
+	dc.l	$44fc001f,$48ee7fff,$ff8001c8,$000842ee
+	dc.l	$ff7e48ee,$7fffffc0,$1228000e,$e1891228
+	dc.l	$000ce189,$1228000a,$e1891228,$0008b081
+	dc.l	$66ff0000,$461e61ff,$000045ea,$4a0066ff
+	dc.l	$00004610,$52aeff78,$4cfb3fff,$01700000
+	dc.l	$460c41ee,$ff60117c,$00aa0008,$117c00aa
+	dc.l	$000a117c,$00aa000c,$117c00aa,$000e3d7c
+	dc.l	$001fff7c,$44fc001f,$48ee7fff,$ff800148
+	dc.l	$000842ee,$ff7e48ee,$7fffffc0,$2d7caaaa
+	dc.l	$aaaaff80,$223caaaa,$aaaab081,$66ff0000
+	dc.l	$45b261ff,$0000457e,$4a0066ff,$000045a4
+	dc.l	$52aeff78,$4cfb3fff,$01700000,$45a041ee
+	dc.l	$ff68303c,$aaaa4228,$fff84228,$fffa3d7c
+	dc.l	$001fff7c,$44fc001f,$48ee7fff,$ff800188
+	dc.l	$fff842ee,$ff7e48ee,$7fffffc0,$1228fffa
+	dc.l	$e1491228,$fff8b041,$66ff0000,$455661ff
+	dc.l	$00004522,$4a0066ff,$00004548,$52aeff78
+	dc.l	$4cfb3fff,$01700000,$454441ee,$ff68117c
+	dc.l	$00aafff8,$117c00aa,$fffa3d7c,$001fff7c
+	dc.l	$44fc001f,$48ee7fff,$ff800108,$fff842ee
+	dc.l	$ff7e48ee,$7fffffc0,$3d7caaaa,$ff82323c
+	dc.l	$aaaab041,$66ff0000,$44fa61ff,$000044c6
+	dc.l	$4a0066ff,$000044ec,$52aeff78,$4cfb3fff
+	dc.l	$01700000,$44e841ee,$ff68203c,$aaaaaaaa
+	dc.l	$4228fff8,$4228fffa,$4228fffc,$42280000
+	dc.l	$3d7c001f,$ff7c44fc,$001f48ee,$7fffff80
+	dc.l	$01c8fff8,$42eeff7e,$48ee7fff,$ffc01228
+	dc.l	$fffee189,$1228fffc,$e1891228,$fffae189
+	dc.l	$1228fff8,$b08166ff,$00004488,$61ff0000
+	dc.l	$44544a00,$66ff0000,$447a52ae,$ff784cfb
+	dc.l	$3fff0170,$00004476,$41eeff68,$117c00aa
+	dc.l	$fff8117c,$00aafffa,$117c00aa,$fffc117c
+	dc.l	$00aa0000,$3d7c001f,$ff7c44fc,$001f48ee
+	dc.l	$7fffff80,$0148fff8,$42eeff7e,$48ee7fff
+	dc.l	$ffc02d7c,$aaaaaaaa,$ff80223c,$aaaaaaaa
+	dc.l	$b08166ff,$0000441c,$61ff0000,$43e84a00
+	dc.l	$66ff0000,$440e222e,$ff784280,$4e750936
+	dc.l	$342d6269,$74206469,$76696465,$2e2e2e00
+	dc.l	$52aeff78,$52aeff78,$4cfb3fff,$01700000
+	dc.l	$43ec7201,$74007600,$3d7c0014,$ff7c44fc
+	dc.l	$001f48ee,$7fffff80,$4c413402,$42eeff7e
+	dc.l	$48ee7fff,$ffc061ff,$0000438a,$4a0066ff
+	dc.l	$000043b0,$52aeff78,$4cfb3fff,$01700000
+	dc.l	$43ac223c,$44444444,$7400263c,$55555555
+	dc.l	$3d7c0010,$ff7c44fc,$001f48ee,$7fffff80
+	dc.l	$4c413402,$42eeff7e,$48ee7fff,$ffc02d7c
+	dc.l	$11111111,$ff882d7c,$00000001,$ff8c61ff
+	dc.l	$00004332,$4a0066ff,$00004358,$52aeff78
+	dc.l	$4cfb3fff,$01700000,$4354223c,$55555555
+	dc.l	$7400263c,$44444444,$3d7c0014,$ff7c44fc
+	dc.l	$001f48ee,$7fffff80,$4c413402,$42eeff7e
+	dc.l	$48ee7fff,$ffc02d7c,$44444444,$ff882d7c
+	dc.l	$00000000,$ff8c61ff,$000042da,$4a0066ff
+	dc.l	$00004300,$52aeff78,$4cfb3fff,$01700000
+	dc.l	$42fc223c,$11111111,$243c4444,$4444263c
+	dc.l	$44444444,$3d7c001e,$ff7c44fc,$001d48ee
+	dc.l	$7fffff80,$4c413402,$42eeff7e,$48ee7fff
+	dc.l	$ffc061ff,$0000428e,$4a0066ff,$000042b4
+	dc.l	$52aeff78,$4cfb3fff,$01700000,$42b072fe
+	dc.l	$74017602,$3d7c001e,$ff7c44fc,$001d48ee
+	dc.l	$7fffff80,$4c413c02,$42eeff7e,$48ee7fff
+	dc.l	$ffc061ff,$0000424e,$4a0066ff,$00004274
+	dc.l	$52aeff78,$4cfb3fff,$01700000,$427072fe
+	dc.l	$74017600,$3d7c0018,$ff7c44fc,$001d48ee
+	dc.l	$7fffff80,$4c413c02,$42eeff7e,$48ee7fff
+	dc.l	$ffc02d7c,$00000000,$ff882d7c,$80000000
+	dc.l	$ff8c61ff,$000041fe,$4a0066ff,$00004224
+	dc.l	$52aeff78,$4cfb3fff,$01700000,$42207202
+	dc.l	$74017600,$3d7c001e,$ff7c44fc,$001d48ee
+	dc.l	$7fffff80,$4c413c02,$42eeff7e,$48ee7fff
+	dc.l	$ffc061ff,$000041be,$4a0066ff,$000041e4
+	dc.l	$52aeff78,$4cfb3fff,$01700000,$41e072ff
+	dc.l	$74fe76ff,$3d7c0008,$ff7c44fc,$000048ee
+	dc.l	$7fffff80,$4c413402,$42eeff7e,$48ee7fff
+	dc.l	$ffc061ff,$0000417e,$4a0066ff,$000041a4
+	dc.l	$52aeff78,$4cfb3fff,$01700000,$41a072ff
+	dc.l	$74fe76ff,$3d7c0008,$ff7c44fc,$000048ee
+	dc.l	$7fffff80,$4c7c2402,$ffffffff,$42eeff7e
+	dc.l	$48ee7fff,$ffc02d7c,$ffffffff,$ff8861ff
+	dc.l	$00004132,$4a0066ff,$00004158,$52aeff78
+	dc.l	$4cfb3fff,$01700000,$4154223c,$0000ffff
+	dc.l	$7401263c,$55555555,$3d7c0000,$ff7c44fc
+	dc.l	$000048ee,$7fffff80,$4c413402,$42eeff7e
+	dc.l	$48ee7fff,$ffc02d7c,$0000aaab,$ff882d7c
+	dc.l	$00015556,$ff8c61ff,$000040da,$4a0066ff
+	dc.l	$00004100,$222eff78,$42804e75,$09636173
+	dc.l	$2e2e2e00,$52aeff78,$4cfb3fff,$01700000
+	dc.l	$40ec41ee,$ff6130bc,$aaaa323c,$aaaa343c
+	dc.l	$bbbb3d7c,$0014ff7c,$44fc0010,$48ee7fff
+	dc.l	$ff800cd0,$008142ee,$ff7e3610,$3d7cbbbb
+	dc.l	$ff8e48ee,$7fffffc0,$61ff0000,$40784a00
+	dc.l	$66ff0000,$409e52ae,$ff784cfb,$3fff0170
+	dc.l	$0000409a,$41eeff61,$30bceeee,$323caaaa
+	dc.l	$343cbbbb,$3d7c0000,$ff7c44fc,$000048ee
+	dc.l	$7fffff80,$0cd00081,$42eeff7e,$36103d7c
+	dc.l	$eeeeff86,$3d7ceeee,$ff8e48ee,$7fffffc0
+	dc.l	$61ff0000,$40204a00,$66ff0000,$404652ae
+	dc.l	$ff784cfb,$3fff0170,$00004042,$41eeff62
+	dc.l	$20bcaaaa,$aaaa223c,$aaaaaaaa,$243cbbbb
+	dc.l	$bbbb3d7c,$0004ff7c,$44fc0000,$48ee7fff
+	dc.l	$ff800ed0,$008142ee,$ff7e2610,$2d7cbbbb
+	dc.l	$bbbbff8c,$48ee7fff,$ffc061ff,$00003fc6
+	dc.l	$4a0066ff,$00003fec,$52aeff78,$4cfb3fff
+	dc.l	$01700000,$3fe841ee,$ff6220bc,$eeeeeeee
+	dc.l	$223caaaa,$aaaa243c,$bbbbbbbb,$3d7c0000
+	dc.l	$ff7c44fc,$000048ee,$7fffff80,$0ed00081
+	dc.l	$42eeff7e,$26102d7c,$eeeeeeee,$ff842d7c
+	dc.l	$eeeeeeee,$ff8c48ee,$7fffffc0,$61ff0000
+	dc.l	$3f644a00,$66ff0000,$3f8a52ae,$ff784cfb
+	dc.l	$3fff0170,$00003f86,$41eeff61,$20bcaaaa
+	dc.l	$aaaa223c,$aaaaaaaa,$243cbbbb,$bbbb3d7c
+	dc.l	$0004ff7c,$44fc0000,$48ee7fff,$ff800ed0
+	dc.l	$008142ee,$ff7e2610,$2d7cbbbb,$bbbbff8c
+	dc.l	$48ee7fff,$ffc061ff,$00003f0a,$4a0066ff
+	dc.l	$00003f30,$52aeff78,$4cfb3fff,$01700000
+	dc.l	$3f2c41ee,$ff6120bc,$7fffffff,$223c8000
+	dc.l	$0000243c,$bbbbbbbb,$3d7c001b,$ff7c44fc
+	dc.l	$001048ee,$7fffff80,$0ed00081,$42eeff7e
+	dc.l	$26102d7c,$7fffffff,$ff842d7c,$7fffffff
+	dc.l	$ff8c48ee,$7fffffc0,$61ff0000,$3ea84a00
+	dc.l	$66ff0000,$3ece222e,$ff784280,$4e750963
+	dc.l	$6173322e,$2e2e0000,$52aeff78,$4cfb3fff
+	dc.l	$01700000,$3eb841ee,$ff6043ee,$ff6420bc
+	dc.l	$aaaaaaaa,$22bcbbbb,$bbbb223c,$aaaaaaaa
+	dc.l	$243cbbbb,$bbbb263c,$cccccccc,$283cdddd
+	dc.l	$dddd3d7c,$0014ff7c,$44fc0010,$48ee7fff
+	dc.l	$ff800efc,$80c19102,$42eeff7e,$2a102c11
+	dc.l	$2d7ccccc,$ccccff94,$2d7cdddd,$ddddff98
+	dc.l	$48ee7fff,$ffc061ff,$00003e1a,$4a0066ff
+	dc.l	$00003e40,$52aeff78,$4cfb3fff,$01700000
+	dc.l	$3e3c41ee,$ff6143ee,$ff6520bc,$aaaaaaaa
+	dc.l	$22bcbbbb,$bbbb223c,$aaaaaaaa,$243cbbbb
+	dc.l	$bbbb263c,$cccccccc,$283cdddd,$dddd3d7c
+	dc.l	$0014ff7c,$44fc0010,$48ee7fff,$ff800efc
+	dc.l	$80c19102,$42eeff7e,$2a102c11,$2d7ccccc
+	dc.l	$ccccff94,$2d7cdddd,$ddddff98,$48ee7fff
+	dc.l	$ffc061ff,$00003d9e,$4a0066ff,$00003dc4
+	dc.l	$52aeff78,$4cfb3fff,$01700000,$3dc041ee
+	dc.l	$ff6243ee,$ff6620bc,$aaaaaaaa,$22bcbbbb
+	dc.l	$bbbb223c,$aaaaaaaa,$243cbbbb,$bbbb263c
+	dc.l	$cccccccc,$283cdddd,$dddd3d7c,$0014ff7c
+	dc.l	$44fc0010,$48ee7fff,$ff800efc,$80c19102
+	dc.l	$42eeff7e,$2a102c11,$2d7ccccc,$ccccff94
+	dc.l	$2d7cdddd,$ddddff98,$48ee7fff,$ffc061ff
+	dc.l	$00003d22,$4a0066ff,$00003d48,$52aeff78
+	dc.l	$4cfb3fff,$01700000,$3d4441ee,$ff6043ee
+	dc.l	$ff6420bc,$eeeeeeee,$22bcbbbb,$bbbb223c
+	dc.l	$aaaaaaaa,$243cbbbb,$bbbb263c,$cccccccc
+	dc.l	$283cdddd,$dddd3d7c,$0000ff7c,$44fc0000
+	dc.l	$48ee7fff,$ff800efc,$80c19102,$42eeff7e
+	dc.l	$2a102c11,$2d7ceeee,$eeeeff84,$2d7cbbbb
+	dc.l	$bbbbff88,$2d7ceeee,$eeeeff94,$2d7cbbbb
+	dc.l	$bbbbff98,$48ee7fff,$ffc061ff,$00003c96
+	dc.l	$4a0066ff,$00003cbc,$52aeff78,$4cfb3fff
+	dc.l	$01700000,$3cb841ee,$ff6143ee,$ff6520bc
+	dc.l	$eeeeeeee,$22bcbbbb,$bbbb223c,$aaaaaaaa
+	dc.l	$243cbbbb,$bbbb263c,$cccccccc,$283cdddd
+	dc.l	$dddd3d7c,$0000ff7c,$44fc0000,$48ee7fff
+	dc.l	$ff800efc,$80c19102,$42eeff7e,$2a102c11
+	dc.l	$2d7ceeee,$eeeeff84,$2d7cbbbb,$bbbbff88
+	dc.l	$2d7ceeee,$eeeeff94,$2d7cbbbb,$bbbbff98
+	dc.l	$48ee7fff,$ffc061ff,$00003c0a,$4a0066ff
+	dc.l	$00003c30,$52aeff78,$4cfb3fff,$01700000
+	dc.l	$3c2c41ee,$ff6243ee,$ff6620bc,$eeeeeeee
+	dc.l	$22bcbbbb,$bbbb223c,$aaaaaaaa,$243cbbbb
+	dc.l	$bbbb263c,$cccccccc,$283cdddd,$dddd3d7c
+	dc.l	$0000ff7c,$44fc0000,$48ee7fff,$ff800efc
+	dc.l	$80c19102,$42eeff7e,$2a102c11,$2d7ceeee
+	dc.l	$eeeeff84,$2d7cbbbb,$bbbbff88,$2d7ceeee
+	dc.l	$eeeeff94,$2d7cbbbb,$bbbbff98,$48ee7fff
+	dc.l	$ffc061ff,$00003b7e,$4a0066ff,$00003ba4
+	dc.l	$52aeff78,$4cfb3fff,$01700000,$3ba041ee
+	dc.l	$ff6043ee,$ff6420bc,$aaaaaaaa,$22bceeee
+	dc.l	$eeee223c,$aaaaaaaa,$243cbbbb,$bbbb263c
+	dc.l	$cccccccc,$283cdddd,$dddd3d7c,$0000ff7c
+	dc.l	$44fc0000,$48ee7fff,$ff800efc,$80c19102
+	dc.l	$42eeff7e,$2a102c11,$2d7caaaa,$aaaaff84
+	dc.l	$2d7ceeee,$eeeeff88,$2d7caaaa,$aaaaff94
+	dc.l	$2d7ceeee,$eeeeff98,$48ee7fff,$ffc061ff
+	dc.l	$00003af2,$4a0066ff,$00003b18,$52aeff78
+	dc.l	$4cfb3fff,$01700000,$3b1441ee,$ff6143ee
+	dc.l	$ff6520bc,$aaaaaaaa,$22bceeee,$eeee223c
+	dc.l	$aaaaaaaa,$243cbbbb,$bbbb263c,$cccccccc
+	dc.l	$283cdddd,$dddd3d7c,$0000ff7c,$44fc0000
+	dc.l	$48ee7fff,$ff800efc,$80c19102,$42eeff7e
+	dc.l	$2a102c11,$2d7caaaa,$aaaaff84,$2d7ceeee
+	dc.l	$eeeeff88,$2d7caaaa,$aaaaff94,$2d7ceeee
+	dc.l	$eeeeff98,$48ee7fff,$ffc061ff,$00003a66
+	dc.l	$4a0066ff,$00003a8c,$52aeff78,$4cfb3fff
+	dc.l	$01700000,$3a8841ee,$ff6243ee,$ff6620bc
+	dc.l	$aaaaaaaa,$22bc7fff,$ffff223c,$aaaaaaaa
+	dc.l	$243c8000,$0000263c,$cccccccc,$283cdddd
+	dc.l	$dddd3d7c,$000bff7c,$44fc0000,$48ee7fff
+	dc.l	$ff800efc,$80c19102,$42eeff7e,$2a102c11
+	dc.l	$2d7caaaa,$aaaaff84,$2d7c7fff,$ffffff88
+	dc.l	$2d7caaaa,$aaaaff94,$2d7c7fff,$ffffff98
+	dc.l	$48ee7fff,$ffc061ff,$000039da,$4a0066ff
+	dc.l	$00003a00,$52aeff78,$4cfb3fff,$01700000
+	dc.l	$39fc41ee,$ff6043ee,$ff6430bc,$aaaa32bc
+	dc.l	$bbbb323c,$aaaa343c,$bbbb363c,$cccc383c
+	dc.l	$dddd3d7c,$0014ff7c,$44fc0010,$48ee7fff
+	dc.l	$ff800cfc,$80c19102,$42eeff7e,$3a103c11
+	dc.l	$3d7ccccc,$ff963d7c,$ddddff9a,$48ee7fff
+	dc.l	$ffc061ff,$0000396e,$4a0066ff,$00003994
+	dc.l	$52aeff78,$4cfb3fff,$01700000,$399041ee
+	dc.l	$ff6143ee,$ff6530bc,$aaaa32bc,$bbbb323c
+	dc.l	$aaaa343c,$bbbb363c,$cccc383c,$dddd3d7c
+	dc.l	$0004ff7c,$44fc0000,$48ee7fff,$ff800cfc
+	dc.l	$80c19102,$42eeff7e,$3a103c11,$3d7ccccc
+	dc.l	$ff963d7c,$ddddff9a,$48ee7fff,$ffc061ff
+	dc.l	$00003902,$4a0066ff,$00003928,$52aeff78
+	dc.l	$4cfb3fff,$01700000,$392441ee,$ff6043ee
+	dc.l	$ff6430bc,$eeee32bc,$bbbb323c,$aaaa343c
+	dc.l	$bbbb363c,$cccc383c,$dddd3d7c,$0000ff7c
+	dc.l	$44fc0000,$48ee7fff,$ff800cfc,$80c19102
+	dc.l	$42eeff7e,$3a103c11,$3d7ceeee,$ff863d7c
+	dc.l	$bbbbff8a,$3d7ceeee,$ff963d7c,$bbbbff9a
+	dc.l	$48ee7fff,$ffc061ff,$0000388a,$4a0066ff
+	dc.l	$000038b0,$52aeff78,$4cfb3fff,$01700000
+	dc.l	$38ac41ee,$ff6143ee,$ff6530bc,$eeee32bc
+	dc.l	$bbbb323c,$aaaa343c,$bbbb363c,$cccc383c
+	dc.l	$dddd3d7c,$0000ff7c,$44fc0000,$48ee7fff
+	dc.l	$ff800cfc,$80c19102,$42eeff7e,$3a103c11
+	dc.l	$3d7ceeee,$ff863d7c,$bbbbff8a,$3d7ceeee
+	dc.l	$ff963d7c,$bbbbff9a,$48ee7fff,$ffc061ff
+	dc.l	$00003812,$4a0066ff,$00003838,$52aeff78
+	dc.l	$4cfb3fff,$01700000,$383441ee,$ff6043ee
+	dc.l	$ff6430bc,$aaaa32bc,$eeee323c,$aaaa343c
+	dc.l	$bbbb363c,$cccc383c,$dddd3d7c,$0000ff7c
+	dc.l	$44fc0000,$48ee7fff,$ff800cfc,$80c19102
+	dc.l	$42eeff7e,$3a103c11,$3d7caaaa,$ff863d7c
+	dc.l	$eeeeff8a,$3d7caaaa,$ff963d7c,$eeeeff9a
+	dc.l	$48ee7fff,$ffc061ff,$0000379a,$4a0066ff
+	dc.l	$000037c0,$52aeff78,$4cfb3fff,$01700000
+	dc.l	$37bc41ee,$ff6143ee,$ff6530bc,$aaaa32bc
+	dc.l	$7fff323c,$aaaa343c,$8000363c,$cccc383c
+	dc.l	$dddd3d7c,$001bff7c,$44fc0010,$48ee7fff
+	dc.l	$ff800cfc,$80c19102,$42eeff7e,$3a103c11
+	dc.l	$3d7caaaa,$ff863d7c,$7fffff8a,$3d7caaaa
+	dc.l	$ff963d7c,$7fffff9a,$48ee7fff,$ffc061ff
+	dc.l	$00003722,$4a0066ff,$00003748,$222eff78
+	dc.l	$42804e75,$09636d70,$322c6368,$6b322e2e
+	dc.l	$2e0051fc,$52aeff78,$4cfb3fff,$01700000
+	dc.l	$372c3d7c,$2040ff60,$223c1111,$11203d7c
+	dc.l	$0004ff7c,$44fc0000,$48ee7fff,$ff8000ee
+	dc.l	$1000ff60,$42eeff7e,$48ee7fff,$ffc061ff
+	dc.l	$000036c2,$4a0066ff,$000036e8,$52aeff78
+	dc.l	$4cfb3fff,$01700000,$36e43d7c,$2040ff60
+	dc.l	$227c0000,$00403d7c,$0004ff7c,$44fc0000
+	dc.l	$48ee7fff,$ff8000ee,$9000ff60,$42eeff7e
+	dc.l	$48ee7fff,$ffc061ff,$0000367a,$4a0066ff
+	dc.l	$000036a0,$52aeff78,$4cfb3fff,$01700000
+	dc.l	$369c3d7c,$2040ff60,$223c1111,$11303d7c
+	dc.l	$0000ff7c,$44fc0000,$48ee7fff,$ff8000ee
+	dc.l	$1800ff60,$42eeff7e,$48ee7fff,$ffc061ff
+	dc.l	$00003632,$4a0066ff,$00003658,$52aeff78
+	dc.l	$4cfb3fff,$01700000,$36543d7c,$2040ff60
+	dc.l	$227c0000,$00103d7c,$0001ff7c,$44fc0000
+	dc.l	$48ee7fff,$ff8000ee,$9000ff60,$42eeff7e
+	dc.l	$48ee7fff,$ffc061ff,$000035ea,$4a0066ff
+	dc.l	$00003610,$52aeff78,$4cfb3fff,$01700000
+	dc.l	$360c3d7c,$2040ff60,$223c1111,$11503d7c
+	dc.l	$0001ff7c,$44fc0000,$48ee7fff,$ff8000ee
+	dc.l	$1000ff60,$42eeff7e,$48ee7fff,$ffc061ff
+	dc.l	$000035a2,$4a0066ff,$000035c8,$52aeff78
+	dc.l	$4cfb3fff,$01700000,$35c43d7c,$2040ff60
+	dc.l	$227c0000,$00903d7c,$0001ff7c,$44fc0000
+	dc.l	$48ee7fff,$ff8000ee,$9000ff60,$42eeff7e
+	dc.l	$48ee7fff,$ffc061ff,$0000355a,$4a0066ff
+	dc.l	$00003580,$52aeff78,$4cfb3fff,$01700000
+	dc.l	$357c2d7c,$2000a000,$ff60223c,$11112000
+	dc.l	$3d7c0004,$ff7c44fc,$000048ee,$7fffff80
+	dc.l	$02ee1000,$ff6042ee,$ff7e48ee,$7fffffc0
+	dc.l	$61ff0000,$35104a00,$66ff0000,$353652ae
+	dc.l	$ff784cfb,$3fff0170,$00003532,$2d7c2000
+	dc.l	$a000ff60,$227cffff,$a0003d7c,$0004ff7c
+	dc.l	$44fc0000,$48ee7fff,$ff8002ee,$9000ff60
+	dc.l	$42eeff7e,$48ee7fff,$ffc061ff,$000034c6
+	dc.l	$4a0066ff,$000034ec,$52aeff78,$4cfb3fff
+	dc.l	$01700000,$34e82d7c,$2000a000,$ff60223c
+	dc.l	$11113000,$3d7c0000,$ff7c44fc,$000048ee
+	dc.l	$7fffff80,$02ee1800,$ff6042ee,$ff7e48ee
+	dc.l	$7fffffc0,$61ff0000,$347c4a00,$66ff0000
+	dc.l	$34a252ae,$ff784cfb,$3fff0170,$0000349e
+	dc.l	$2d7c2000,$a000ff60,$227cffff,$90003d7c
+	dc.l	$0000ff7c,$44fc0000,$48ee7fff,$ff8002ee
+	dc.l	$9000ff60,$42eeff7e,$48ee7fff,$ffc061ff
+	dc.l	$00003432,$4a0066ff,$00003458,$52aeff78
+	dc.l	$4cfb3fff,$01700000,$34542d7c,$2000a000
+	dc.l	$ff60223c,$11111000,$3d7c0001,$ff7c44fc
+	dc.l	$000048ee,$7fffff80,$02ee1000,$ff6042ee
+	dc.l	$ff7e48ee,$7fffffc0,$61ff0000,$33e84a00
+	dc.l	$66ff0000,$340e52ae,$ff784cfb,$3fff0170
+	dc.l	$0000340a,$2d7c2000,$a000ff60,$227cffff
+	dc.l	$b0003d7c,$0001ff7c,$44fc0000,$48ee7fff
+	dc.l	$ff8002ee,$9000ff60,$42eeff7e,$48ee7fff
+	dc.l	$ffc061ff,$0000339e,$4a0066ff,$000033c4
+	dc.l	$52aeff78,$4cfb3fff,$01700000,$33c02d7c
+	dc.l	$a0000000,$ff602d7c,$c0000000,$ff64223c
+	dc.l	$a0000000,$3d7c000c,$ff7c44fc,$000848ee
+	dc.l	$7fffff80,$04ee1000,$ff6042ee,$ff7e48ee
+	dc.l	$7fffffc0,$61ff0000,$334c4a00,$66ff0000
+	dc.l	$337252ae,$ff784cfb,$3fff0170,$0000336e
+	dc.l	$2d7ca000,$0000ff60,$2d7cc000,$0000ff64
+	dc.l	$227cc000,$00003d7c,$000cff7c,$44fc0008
+	dc.l	$48ee7fff,$ff8004ee,$9000ff60,$42eeff7e
+	dc.l	$48ee7fff,$ffc061ff,$000032fa,$4a0066ff
+	dc.l	$00003320,$52aeff78,$4cfb3fff,$01700000
+	dc.l	$331c2d7c,$a0000000,$ff602d7c,$c0000000
+	dc.l	$ff64223c,$b0000000,$3d7c0008,$ff7c44fc
+	dc.l	$000848ee,$7fffff80,$04ee1800,$ff6042ee
+	dc.l	$ff7e48ee,$7fffffc0,$61ff0000,$32a84a00
+	dc.l	$66ff0000,$32ce52ae,$ff784cfb,$3fff0170
+	dc.l	$000032ca,$2d7ca000,$0000ff60,$2d7cc000
+	dc.l	$0000ff64,$227c1000,$00003d7c,$0009ff7c
+	dc.l	$44fc0008,$48ee7fff,$ff8004ee,$9000ff60
+	dc.l	$42eeff7e,$48ee7fff,$ffc061ff,$00003256
+	dc.l	$4a0066ff,$0000327c,$52aeff78,$4cfb3fff
+	dc.l	$01700000,$32782d7c,$a0000000,$ff602d7c
+	dc.l	$c0000000,$ff64223c,$90000000,$3d7c0009
+	dc.l	$ff7c44fc,$000848ee,$7fffff80,$04ee1000
+	dc.l	$ff6042ee,$ff7e48ee,$7fffffc0,$61ff0000
+	dc.l	$32044a00,$66ff0000,$322a52ae,$ff784cfb
+	dc.l	$3fff0170,$00003226,$2d7ca000,$0000ff60
+	dc.l	$2d7cc000,$0000ff64,$227cd000,$00003d7c
+	dc.l	$0009ff7c,$44fc0008,$48ee7fff,$ff8004ee
+	dc.l	$9000ff60,$42eeff7e,$48ee7fff,$ffc061ff
+	dc.l	$000031b2,$4a0066ff,$000031d8,$52aeff78
+	dc.l	$4cfb3fff,$01700000,$31d43d7c,$a040ff60
+	dc.l	$223c1111,$11a03d7c,$0004ff7c,$44fc0000
+	dc.l	$48ee7fff,$ff8000ee,$1000ff60,$42eeff7e
+	dc.l	$48ee7fff,$ffc061ff,$0000316a,$4a0066ff
+	dc.l	$00003190,$52aeff78,$4cfb3fff,$01700000
+	dc.l	$318c3d7c,$a040ff60,$227c0000,$00403d7c
+	dc.l	$0004ff7c,$44fc0000,$48ee7fff,$ff8000ee
+	dc.l	$9800ff60,$42eeff7e,$48ee7fff,$ffc061ff
+	dc.l	$00003122,$4a0066ff,$00003148,$52aeff78
+	dc.l	$4cfb3fff,$01700000,$31443d7c,$a040ff60
+	dc.l	$223c1111,$11b03d7c,$0000ff7c,$44fc0000
+	dc.l	$48ee7fff,$ff8000ee,$1000ff60,$42eeff7e
+	dc.l	$48ee7fff,$ffc061ff,$000030da,$4a0066ff
+	dc.l	$00003100,$52aeff78,$4cfb3fff,$01700000
+	dc.l	$30fc3d7c,$a040ff60,$227c0000,$00103d7c
+	dc.l	$0000ff7c,$44fc0000,$48ee7fff,$ff8000ee
+	dc.l	$9000ff60,$42eeff7e,$48ee7fff,$ffc061ff
+	dc.l	$00003092,$4a0066ff,$000030b8,$52aeff78
+	dc.l	$4cfb3fff,$01700000,$30b43d7c,$a040ff60
+	dc.l	$223c1111,$11903d7c,$0001ff7c,$44fc0000
+	dc.l	$48ee7fff,$ff8000ee,$1000ff60,$42eeff7e
+	dc.l	$48ee7fff,$ffc061ff,$0000304a,$4a0066ff
+	dc.l	$00003070,$52aeff78,$4cfb3fff,$01700000
+	dc.l	$306c3d7c,$a040ff60,$227c0000,$00503d7c
+	dc.l	$0001ff7c,$44fc0000,$48ee7fff,$ff8000ee
+	dc.l	$9000ff60,$42eeff7e,$48ee7fff,$ffc061ff
+	dc.l	$00003002,$4a0066ff,$00003028,$52aeff78
+	dc.l	$4cfb3fff,$01700000,$30243d7c,$a0c0ff60
+	dc.l	$223c1111,$11a03d7c,$0004ff7c,$44fc0000
+	dc.l	$48ee7fff,$ff8000ee,$1000ff60,$42eeff7e
+	dc.l	$48ee7fff,$ffc061ff,$00002fba,$4a0066ff
+	dc.l	$00002fe0,$52aeff78,$4cfb3fff,$01700000
+	dc.l	$2fdc3d7c,$a0c0ff60,$227cffff,$ffc03d7c
+	dc.l	$0004ff7c,$44fc0000,$48ee7fff,$ff8000ee
+	dc.l	$9000ff60,$42eeff7e,$48ee7fff,$ffc061ff
+	dc.l	$00002f72,$4a0066ff,$00002f98,$52aeff78
+	dc.l	$4cfb3fff,$01700000,$2f943d7c,$a0c0ff60
+	dc.l	$223c1111,$11b03d7c,$0000ff7c,$44fc0000
+	dc.l	$48ee7fff,$ff8000ee,$1800ff60,$42eeff7e
+	dc.l	$48ee7fff,$ffc061ff,$00002f2a,$4a0066ff
+	dc.l	$00002f50,$52aeff78,$4cfb3fff,$01700000
+	dc.l	$2f4c3d7c,$a0c0ff60,$227c1111,$11903d7c
+	dc.l	$0001ff7c,$44fc0000,$48ee7fff,$ff8000ee
+	dc.l	$9000ff60,$42eeff7e,$48ee7fff,$ffc061ff
+	dc.l	$00002ee2,$4a0066ff,$00002f08,$52aeff78
+	dc.l	$4cfb3fff,$01700000,$2f043d7c,$a0c0ff60
+	dc.l	$223c1111,$11d03d7c,$0001ff7c,$44fc0000
+	dc.l	$48ee7fff,$ff8000ee,$1000ff60,$42eeff7e
+	dc.l	$48ee7fff,$ffc061ff,$00002e9a,$4a0066ff
+	dc.l	$00002ec0,$52aeff78,$4cfb3fff,$01700000
+	dc.l	$2ebc3d7c,$a0c0ff60,$227c0000,$00503d7c
+	dc.l	$001bff7c,$44fc001f,$48ee7fff,$ff8000ee
+	dc.l	$9000ff60,$42eeff7e,$48ee7fff,$ffc061ff
+	dc.l	$00002e52,$4a0066ff,$00002e78,$222eff78
+	dc.l	$42804e75,$09456666,$65637469,$76652061
+	dc.l	$64647265,$73736573,$2e2e2e00,$52aeff78
+	dc.l	$4cfb3fff,$01700000,$2e544282,$760241ee
+	dc.l	$ff743d7c,$0000ff7c,$44fc0000,$48eeffff
+	dc.l	$ff804c10,$340242ee,$ff7e48ee,$ffffffc0
+	dc.l	$2d7c0000,$0004ff8c,$61ff0000,$2de84a00
+	dc.l	$66ff0000,$2e0e52ae,$ff784cfb,$3fff0170
+	dc.l	$00002e0a,$42827602,$41eeff74,$3d7c0000
+	dc.l	$ff7c44fc,$000048ee,$ffffff80,$4c183402
+	dc.l	$42eeff7e,$48eeffff,$ffc02d7c,$00000004
+	dc.l	$ff8c41ee,$ff782d48,$ffa061ff,$00002d96
+	dc.l	$4a0066ff,$00002dbc,$52aeff78,$4cfb3fff
+	dc.l	$01700000,$2db84282,$760241ee,$ff783d7c
+	dc.l	$0000ff7c,$44fc0000,$48eeffff,$ff804c20
+	dc.l	$340242ee,$ff7e48ee,$ffffffc0,$2d7c0000
+	dc.l	$0004ff8c,$41eeff74,$2d48ffa0,$61ff0000
+	dc.l	$2d444a00,$66ff0000,$2d6a52ae,$ff784cfb
+	dc.l	$3fff0170,$00002d66,$42827602,$41ee0f74
+	dc.l	$3d7c0000,$ff7c44fc,$000048ee,$ffffff80
+	dc.l	$4c283402,$f00042ee,$ff7e48ee,$ffffffc0
+	dc.l	$2d7c0000,$0004ff8c,$61ff0000,$2cf84a00
+	dc.l	$66ff0000,$2d1e52ae,$ff784cfb,$3fff0170
+	dc.l	$00002d1a,$42827602,$41eeef74,$3d7c0000
+	dc.l	$ff7c44fc,$000048ee,$ffffff80,$4c283402
+	dc.l	$100042ee,$ff7e48ee,$ffffffc0,$2d7c0000
+	dc.l	$0004ff8c,$61ff0000,$2cac4a00,$66ff0000
+	dc.l	$2cd252ae,$ff7852ae,$ff7852ae,$ff784cfb
+	dc.l	$3fff0170,$00002cc6,$42827602,$3d7c0000
+	dc.l	$ff7c44fc,$000048ee,$ffffff80,$4c3c3402
+	dc.l	$00000002,$42eeff7e,$48eeffff,$ffc02d7c
+	dc.l	$00000004,$ff8c61ff,$00002c5a,$4a0066ff
+	dc.l	$00002c80,$52aeff78,$60040000,$00024cfb
+	dc.l	$3fff0170,$00002c76,$42827602,$3d7c0000
+	dc.l	$ff7c44fc,$000048ee,$ffffff80,$4c3a3402
+	dc.l	$ffda42ee,$ff7e48ee,$ffffffc0,$2d7c0000
+	dc.l	$0004ff8c,$61ff0000,$2c0c4a00,$66ff0000
+	dc.l	$2c3252ae,$ff784cfb,$3fff0170,$00002c2e
+	dc.l	$42827602,$43eeff78,$3d7c0000,$ff7c44fc
+	dc.l	$000048ee,$ffffff80,$4c213402,$42eeff7e
+	dc.l	$48eeffff,$ffc02d7c,$00000004,$ff8c41ee
+	dc.l	$ff742d48,$ffa461ff,$00002bba,$4a0066ff
+	dc.l	$00002be0,$52aeff78,$4cfb3fff,$01700000
+	dc.l	$2bdc4282,$760245ee,$ff783d7c,$0000ff7c
+	dc.l	$44fc0000,$48eeffff,$ff804c22,$340242ee
+	dc.l	$ff7e48ee,$ffffffc0,$2d7c0000,$0004ff8c
+	dc.l	$41eeff74,$2d48ffa8,$61ff0000,$2b684a00
+	dc.l	$66ff0000,$2b8e52ae,$ff784cfb,$3fff0170
+	dc.l	$00002b8a,$42827602,$47eeff78,$3d7c0000
+	dc.l	$ff7c44fc,$000048ee,$ffffff80,$4c233402
+	dc.l	$42eeff7e,$48eeffff,$ffc02d7c,$00000004
+	dc.l	$ff8c41ee,$ff742d48,$ffac61ff,$00002b16
+	dc.l	$4a0066ff,$00002b3c,$52aeff78,$4cfb3fff
+	dc.l	$01700000,$2b384282,$760249ee,$ff783d7c
+	dc.l	$0000ff7c,$44fc0000,$48eeffff,$ff804c24
+	dc.l	$340242ee,$ff7e48ee,$ffffffc0,$2d7c0000
+	dc.l	$0004ff8c,$41eeff74,$2d48ffb0,$61ff0000
+	dc.l	$2ac44a00,$66ff0000,$2aea52ae,$ff784cfb
+	dc.l	$3fff0170,$00002ae6,$42827602,$4beeff78
+	dc.l	$3d7c0000,$ff7c44fc,$000048ee,$ffffff80
+	dc.l	$4c253402,$42eeff7e,$48eeffff,$ffc02d7c
+	dc.l	$00000004,$ff8c41ee,$ff742d48,$ffb461ff
+	dc.l	$00002a72,$4a0066ff,$00002a98,$52aeff78
+	dc.l	$4cfb3fff,$01700000,$2a94224e,$42827602
+	dc.l	$4de9ff78,$337c0000,$ff7c44fc,$000048e9
+	dc.l	$ffffff80,$4c263402,$42e9ff7e,$48e9ffff
+	dc.l	$ffc0237c,$00000004,$ff8c41e9,$ff742348
+	dc.l	$ffb82c49,$61ff0000,$2a1c4a00,$66ff0000
+	dc.l	$2a4252ae,$ff784cfb,$3fff0170,$00002a3e
+	dc.l	$42827602,$204f4fee,$ff783d7c,$0000ff7c
+	dc.l	$44fc0000,$48eeffff,$ff804c27,$340242ee
+	dc.l	$ff7e48ee,$ffffffc0,$2d7c0000,$0004ff8c
+	dc.l	$43eeff74,$2d49ffbc,$2e4861ff,$000029c6
+	dc.l	$4a0066ff,$000029ec,$52aeff78,$4cfb3fff
+	dc.l	$01700000,$29e84282,$760241ee,$ff7478f0
+	dc.l	$3d7c0000,$ff7c44fc,$000048ee,$ffffff80
+	dc.l	$4c303402,$401042ee,$ff7e48ee,$ffffffc0
+	dc.l	$2d7c0000,$0004ff8c,$61ff0000,$29784a00
+	dc.l	$66ff0000,$299e52ae,$ff784cfb,$3fff0170
+	dc.l	$0000299a,$42827602,$41eeff74,$78f83d7c
+	dc.l	$0000ff7c,$44fc0000,$48eeffff,$ff804c30
+	dc.l	$34024210,$42eeff7e,$48eeffff,$ffc02d7c
+	dc.l	$00000004,$ff8c61ff,$0000292a,$4a0066ff
+	dc.l	$00002950,$52aeff78,$4cfb3fff,$01700000
+	dc.l	$294c4282,$760241ee,$ff7478fc,$3d7c0000
+	dc.l	$ff7c44fc,$000048ee,$ffffff80,$4c303402
+	dc.l	$441042ee,$ff7e48ee,$ffffffc0,$2d7c0000
+	dc.l	$0004ff8c,$61ff0000,$28dc4a00,$66ff0000
+	dc.l	$290252ae,$ff784cfb,$3fff0170,$000028fe
+	dc.l	$42827602,$41eeff74,$78fe3d7c,$0000ff7c
+	dc.l	$44fc0000,$48eeffff,$ff804c30,$34024610
+	dc.l	$42eeff7e,$48eeffff,$ffc02d7c,$00000004
+	dc.l	$ff8c61ff,$0000288e,$4a0066ff,$000028b4
+	dc.l	$52aeff78,$4cfb3fff,$01700000,$28b04282
+	dc.l	$760241ee,$ff7478f0,$3d7c0000,$ff7c44fc
+	dc.l	$000048ee,$ffffff80,$4c303402,$481042ee
+	dc.l	$ff7e48ee,$ffffffc0,$2d7c0000,$0004ff8c
+	dc.l	$61ff0000,$28404a00,$66ff0000,$286652ae
+	dc.l	$ff784cfb,$3fff0170,$00002862,$42827602
+	dc.l	$41eeff74,$78f83d7c,$0000ff7c,$44fc0000
+	dc.l	$48eeffff,$ff804c30,$34024a10,$42eeff7e
+	dc.l	$48eeffff,$ffc02d7c,$00000004,$ff8c61ff
+	dc.l	$000027f2,$4a0066ff,$00002818,$52aeff78
+	dc.l	$4cfb3fff,$01700000,$28144282,$760241ee
+	dc.l	$ff7478fc,$3d7c0000,$ff7c44fc,$000048ee
+	dc.l	$ffffff80,$4c303402,$4c1042ee,$ff7e48ee
+	dc.l	$ffffffc0,$2d7c0000,$0004ff8c,$61ff0000
+	dc.l	$27a44a00,$66ff0000,$27ca52ae,$ff784cfb
+	dc.l	$3fff0170,$000027c6,$42827602,$41eeff74
+	dc.l	$78fe3d7c,$0000ff7c,$44fc0000,$48eeffff
+	dc.l	$ff804c30,$34024e10,$42eeff7e,$48eeffff
+	dc.l	$ffc02d7c,$00000004,$ff8c61ff,$00002756
+	dc.l	$4a0066ff,$0000277c,$52aeff78,$4cfb3fff
+	dc.l	$01700000,$27784282,$760241ee,$ff74287c
+	dc.l	$fffffffe,$3d7c0000,$ff7c44fc,$000048ee
+	dc.l	$ffffff80,$4c303402,$ce1042ee,$ff7e48ee
+	dc.l	$ffffffc0,$2d7c0000,$0004ff8c,$61ff0000
+	dc.l	$27044a00,$66ff0000,$272a52ae,$ff784cfb
+	dc.l	$3fff0170,$00002726,$42827602,$41eeff74
+	dc.l	$287c0000,$00023d7c,$0000ff7c,$44fc0000
+	dc.l	$48eeffff,$ff804c30,$3402cef0,$42eeff7e
+	dc.l	$48eeffff,$ffc02d7c,$00000004,$ff8c61ff
+	dc.l	$000026b2,$4a0066ff,$000026d8,$52aeff78
+	dc.l	$4cfb3fff,$01700000,$26d44282,$760243ee
+	dc.l	$ff7478f0,$3d7c0000,$ff7c44fc,$000048ee
+	dc.l	$ffffff80,$4c313402,$401042ee,$ff7e48ee
+	dc.l	$ffffffc0,$2d7c0000,$0004ff8c,$61ff0000
+	dc.l	$26644a00,$66ff0000,$268a52ae,$ff784cfb
+	dc.l	$3fff0170,$00002686,$42827602,$45eeff74
+	dc.l	$78f03d7c,$0000ff7c,$44fc0000,$48eeffff
+	dc.l	$ff804c32,$34024010,$42eeff7e,$48eeffff
+	dc.l	$ffc02d7c,$00000004,$ff8c61ff,$00002616
+	dc.l	$4a0066ff,$0000263c,$52aeff78,$4cfb3fff
+	dc.l	$01700000,$26384282,$760247ee,$ff7478f0
+	dc.l	$3d7c0000,$ff7c44fc,$000048ee,$ffffff80
+	dc.l	$4c333402,$401042ee,$ff7e48ee,$ffffffc0
+	dc.l	$2d7c0000,$0004ff8c,$61ff0000,$25c84a00
+	dc.l	$66ff0000,$25ee52ae,$ff784cfb,$3fff0170
+	dc.l	$000025ea,$42827602,$49eeff74,$78f03d7c
+	dc.l	$0000ff7c,$44fc0000,$48eeffff,$ff804c34
+	dc.l	$34024010,$42eeff7e,$48eeffff,$ffc02d7c
+	dc.l	$00000004,$ff8c61ff,$0000257a,$4a0066ff
+	dc.l	$000025a0,$52aeff78,$4cfb3fff,$01700000
+	dc.l	$259c4282,$76024bee,$ff7478f0,$3d7c0000
+	dc.l	$ff7c44fc,$000048ee,$ffffff80,$4c353402
+	dc.l	$401042ee,$ff7e48ee,$ffffffc0,$2d7c0000
+	dc.l	$0004ff8c,$61ff0000,$252c4a00,$66ff0000
+	dc.l	$255252ae,$ff784cfb,$3fff0170,$0000254e
+	dc.l	$224e4282,$76024de9,$ff7478f0,$337c0000
+	dc.l	$ff7c44fc,$000048e9,$ffffff80,$4c363402
+	dc.l	$401042e9,$ff7e48e9,$ffffffc0,$237c0000
+	dc.l	$0004ff8c,$2c4961ff,$000024da,$4a0066ff
+	dc.l	$00002500,$52aeff78,$4cfb3fff,$01700000
+	dc.l	$24fc4282,$7602204f,$4feeff74,$78f03d7c
+	dc.l	$0000ff7c,$44fc0000,$48eeffff,$ff804c37
+	dc.l	$34024010,$42eeff7e,$48eeffff,$ffc02d7c
+	dc.l	$00000004,$ff8c2e48,$61ff0000,$24884a00
+	dc.l	$66ff0000,$24ae52ae,$ff784cfb,$3fff0170
+	dc.l	$000024aa,$42827602,$43eeff74,$3d7c0000
+	dc.l	$ff7c44fc,$000048ee,$ffffff80,$4c113402
+	dc.l	$42eeff7e,$48eeffff,$ffc02d7c,$00000004
+	dc.l	$ff8c61ff,$0000243e,$4a0066ff,$00002464
+	dc.l	$52aeff78,$4cfb3fff,$01700000,$24604282
+	dc.l	$760245ee,$ff743d7c,$0000ff7c,$44fc0000
+	dc.l	$48eeffff,$ff804c12,$340242ee,$ff7e48ee
+	dc.l	$ffffffc0,$2d7c0000,$0004ff8c,$61ff0000
+	dc.l	$23f44a00,$66ff0000,$241a52ae,$ff784cfb
+	dc.l	$3fff0170,$00002416,$42827602,$47eeff74
+	dc.l	$3d7c0000,$ff7c44fc,$000048ee,$ffffff80
+	dc.l	$4c133402,$42eeff7e,$48eeffff,$ffc02d7c
+	dc.l	$00000004,$ff8c61ff,$000023aa,$4a0066ff
+	dc.l	$000023d0,$52aeff78,$4cfb3fff,$01700000
+	dc.l	$23cc4282,$760249ee,$ff743d7c,$0000ff7c
+	dc.l	$44fc0000,$48eeffff,$ff804c14,$340242ee
+	dc.l	$ff7e48ee,$ffffffc0,$2d7c0000,$0004ff8c
+	dc.l	$61ff0000,$23604a00,$66ff0000,$238652ae
+	dc.l	$ff784cfb,$3fff0170,$00002382,$42827602
+	dc.l	$4beeff74,$3d7c0000,$ff7c44fc,$000048ee
+	dc.l	$ffffff80,$4c153402,$42eeff7e,$48eeffff
+	dc.l	$ffc02d7c,$00000004,$ff8c61ff,$00002316
+	dc.l	$4a0066ff,$0000233c,$52aeff78,$4cfb3fff
+	dc.l	$01700000,$2338224e,$42827602,$4de9ff74
+	dc.l	$337c0000,$ff7c44fc,$000048e9,$ffffff80
+	dc.l	$4c163402,$42e9ff7e,$48e9ffff,$ffc0237c
+	dc.l	$00000004,$ff8c2c49,$61ff0000,$22c84a00
+	dc.l	$66ff0000,$22ee52ae,$ff784cfb,$3fff0170
+	dc.l	$000022ea,$42827602,$204f4fee,$ff743d7c
+	dc.l	$0000ff7c,$44fc0000,$48eeffff,$ff804c17
+	dc.l	$340242ee,$ff7e48ee,$ffffffc0,$2d7c0000
+	dc.l	$0004ff8c,$2e4861ff,$0000227a,$4a0066ff
+	dc.l	$000022a0,$52aeff78,$4cfb3fff,$01700000
+	dc.l	$229c4282,$760243ee,$ff743d7c,$0000ff7c
+	dc.l	$44fc0000,$48eeffff,$ff804c19,$340242ee
+	dc.l	$ff7e48ee,$ffffffc0,$2d7c0000,$0004ff8c
+	dc.l	$41eeff78,$2d48ffa4,$61ff0000,$22284a00
+	dc.l	$66ff0000,$224e52ae,$ff784cfb,$3fff0170
+	dc.l	$0000224a,$42827602,$45eeff74,$3d7c0000
+	dc.l	$ff7c44fc,$000048ee,$ffffff80,$4c1a3402
+	dc.l	$42eeff7e,$48eeffff,$ffc02d7c,$00000004
+	dc.l	$ff8c41ee,$ff782d48,$ffa861ff,$000021d6
+	dc.l	$4a0066ff,$000021fc,$52aeff78,$4cfb3fff
+	dc.l	$01700000,$21f84282,$760247ee,$ff743d7c
+	dc.l	$0000ff7c,$44fc0000,$48eeffff,$ff804c1b
+	dc.l	$340242ee,$ff7e48ee,$ffffffc0,$2d7c0000
+	dc.l	$0004ff8c,$41eeff78,$2d48ffac,$61ff0000
+	dc.l	$21844a00,$66ff0000,$21aa52ae,$ff784cfb
+	dc.l	$3fff0170,$000021a6,$42827602,$49eeff74
+	dc.l	$3d7c0000,$ff7c44fc,$000048ee,$ffffff80
+	dc.l	$4c1c3402,$42eeff7e,$48eeffff,$ffc02d7c
+	dc.l	$00000004,$ff8c41ee,$ff782d48,$ffb061ff
+	dc.l	$00002132,$4a0066ff,$00002158,$52aeff78
+	dc.l	$4cfb3fff,$01700000,$21544282,$76024bee
+	dc.l	$ff743d7c,$0000ff7c,$44fc0000,$48eeffff
+	dc.l	$ff804c1d,$340242ee,$ff7e48ee,$ffffffc0
+	dc.l	$2d7c0000,$0004ff8c,$41eeff78,$2d48ffb4
+	dc.l	$61ff0000,$20e04a00,$66ff0000,$210652ae
+	dc.l	$ff784cfb,$3fff0170,$00002102,$224e4282
+	dc.l	$76024de9,$ff74337c,$0000ff7c,$44fc0000
+	dc.l	$48e9ffff,$ff804c1e,$340242e9,$ff7e48e9
+	dc.l	$ffffffc0,$237c0000,$0004ff8c,$41e9ff78
+	dc.l	$2348ffb8,$2c4961ff,$0000208a,$4a0066ff
+	dc.l	$000020b0,$52aeff78,$4cfb3fff,$01700000
+	dc.l	$20ac4282,$7602204f,$4feeff74,$3d7c0000
+	dc.l	$ff7c44fc,$000048ee,$ffffff80,$4c1f3402
+	dc.l	$42eeff7e,$48eeffff,$ffc02d7c,$00000004
+	dc.l	$ff8c43ee,$ff782d49,$ffbc2e48,$61ff0000
+	dc.l	$20344a00,$66ff0000,$205a52ae,$ff784cfb
+	dc.l	$3fff0170,$00002056,$42827602,$43eeef74
+	dc.l	$3d7c0000,$ff7c44fc,$000048ee,$ffffff80
+	dc.l	$4c293402,$100042ee,$ff7e48ee,$ffffffc0
+	dc.l	$2d7c0000,$0004ff8c,$61ff0000,$1fe84a00
+	dc.l	$66ff0000,$200e52ae,$ff784cfb,$3fff0170
+	dc.l	$0000200a,$42827602,$45eeef74,$3d7c0000
+	dc.l	$ff7c44fc,$000048ee,$ffffff80,$4c2a3402
+	dc.l	$100042ee,$ff7e48ee,$ffffffc0,$2d7c0000
+	dc.l	$0004ff8c,$61ff0000,$1f9c4a00,$66ff0000
+	dc.l	$1fc252ae,$ff784cfb,$3fff0170,$00001fbe
+	dc.l	$42827602,$47eeef74,$3d7c0000,$ff7c44fc
+	dc.l	$000048ee,$ffffff80,$4c2b3402,$100042ee
+	dc.l	$ff7e48ee,$ffffffc0,$2d7c0000,$0004ff8c
+	dc.l	$61ff0000,$1f504a00,$66ff0000,$1f7652ae
+	dc.l	$ff784cfb,$3fff0170,$00001f72,$42827602
+	dc.l	$49eeef74,$3d7c0000,$ff7c44fc,$000048ee
+	dc.l	$ffffff80,$4c2c3402,$100042ee,$ff7e48ee
+	dc.l	$ffffffc0,$2d7c0000,$0004ff8c,$61ff0000
+	dc.l	$1f044a00,$66ff0000,$1f2a52ae,$ff784cfb
+	dc.l	$3fff0170,$00001f26,$42827602,$4beeef74
+	dc.l	$3d7c0000,$ff7c44fc,$000048ee,$ffffff80
+	dc.l	$4c2d3402,$100042ee,$ff7e48ee,$ffffffc0
+	dc.l	$2d7c0000,$0004ff8c,$61ff0000,$1eb84a00
+	dc.l	$66ff0000,$1ede52ae,$ff784cfb,$3fff0170
+	dc.l	$00001eda,$224e4282,$76024de9,$ef74337c
+	dc.l	$0000ff7c,$44fc0000,$48e9ffff,$ff804c2e
+	dc.l	$34021000,$42e9ff7e,$48e9ffff,$ffc0237c
+	dc.l	$00000004,$ff8c2c49,$61ff0000,$1e684a00
+	dc.l	$66ff0000,$1e8e52ae,$ff784cfb,$3fff0170
+	dc.l	$00001e8a,$42827602,$204f4fee,$ef743d7c
+	dc.l	$0000ff7c,$44fc0000,$48eeffff,$ff804c2f
+	dc.l	$34021000,$42eeff7e,$48eeffff,$ffc02d7c
+	dc.l	$00000004,$ff8c2e48,$61ff0000,$1e184a00
+	dc.l	$66ff0000,$1e3e52ae,$ff784cfb,$3fff0170
+	dc.l	$00001e3a,$42827602,$41ee0f74,$3d7c0000
+	dc.l	$ff7c44fc,$000048ee,$ffffff80,$4c283402
+	dc.l	$f00042ee,$ff7e48ee,$ffffffc0,$2d7c0000
+	dc.l	$0004ff8c,$61ff0000,$1dcc4a00,$66ff0000
+	dc.l	$1df252ae,$ff786004,$00000002,$4cfb3fff
+	dc.l	$01700000,$1de84282,$76023d7c,$0000ff7c
+	dc.l	$44fc0000,$48eeffff,$ff804c3a,$3402ffda
+	dc.l	$42eeff7e,$48eeffff,$ffc02d7c,$00000004
+	dc.l	$ff8c61ff,$00001d7e,$4a0066ff,$00001da4
+	dc.l	$52aeff78,$4cfb3fff,$01700000,$1da04282
+	dc.l	$760247ee,$ff7478f0,$3d7c0000,$ff7c44fc
+	dc.l	$000048ee,$ffffff80,$4c333402,$401042ee
+	dc.l	$ff7e48ee,$ffffffc0,$2d7c0000,$0004ff8c
+	dc.l	$61ff0000,$1d304a00,$66ff0000,$1d5652ae
+	dc.l	$ff784cfb,$3fff0170,$00001d52,$42827602
+	dc.l	$47eeff74,$78f83d7c,$0000ff7c,$44fc0000
+	dc.l	$48eeffff,$ff804c33,$34024210,$42eeff7e
+	dc.l	$48eeffff,$ffc02d7c,$00000004,$ff8c61ff
+	dc.l	$00001ce2,$4a0066ff,$00001d08,$52aeff78
+	dc.l	$4cfb3fff,$01700000,$1d044282,$760247ee
+	dc.l	$ff7478fc,$3d7c0000,$ff7c44fc,$000048ee
+	dc.l	$ffffff80,$4c333402,$441042ee,$ff7e48ee
+	dc.l	$ffffffc0,$2d7c0000,$0004ff8c,$61ff0000
+	dc.l	$1c944a00,$66ff0000,$1cba52ae,$ff784cfb
+	dc.l	$3fff0170,$00001cb6,$42827602,$47eeff74
+	dc.l	$78fe3d7c,$0000ff7c,$44fc0000,$48eeffff
+	dc.l	$ff804c33,$34024610,$42eeff7e,$48eeffff
+	dc.l	$ffc02d7c,$00000004,$ff8c61ff,$00001c46
+	dc.l	$4a0066ff,$00001c6c,$52aeff78,$4cfb3fff
+	dc.l	$01700000,$1c684282,$760247ee,$ff7478f0
+	dc.l	$3d7c0000,$ff7c44fc,$000048ee,$ffffff80
+	dc.l	$4c333402,$481042ee,$ff7e48ee,$ffffffc0
+	dc.l	$2d7c0000,$0004ff8c,$61ff0000,$1bf84a00
+	dc.l	$66ff0000,$1c1e52ae,$ff784cfb,$3fff0170
+	dc.l	$00001c1a,$42827602,$47eeff74,$78f83d7c
+	dc.l	$0000ff7c,$44fc0000,$48eeffff,$ff804c33
+	dc.l	$34024a10,$42eeff7e,$48eeffff,$ffc02d7c
+	dc.l	$00000004,$ff8c61ff,$00001baa,$4a0066ff
+	dc.l	$00001bd0,$52aeff78,$4cfb3fff,$01700000
+	dc.l	$1bcc4282,$760247ee,$ff7478fc,$3d7c0000
+	dc.l	$ff7c44fc,$000048ee,$ffffff80,$4c333402
+	dc.l	$4c1042ee,$ff7e48ee,$ffffffc0,$2d7c0000
+	dc.l	$0004ff8c,$61ff0000,$1b5c4a00,$66ff0000
+	dc.l	$1b8252ae,$ff784cfb,$3fff0170,$00001b7e
+	dc.l	$42827602,$47eeff74,$78fe3d7c,$0000ff7c
+	dc.l	$44fc0000,$48eeffff,$ff804c33,$34024e10
+	dc.l	$42eeff7e,$48eeffff,$ffc02d7c,$00000004
+	dc.l	$ff8c61ff,$00001b0e,$4a0066ff,$00001b34
+	dc.l	$52aeff78,$4cfb3fff,$01700000,$1b304282
+	dc.l	$760247ee,$ff74287c,$00000002,$3d7c0000
+	dc.l	$ff7c44fc,$000048ee,$ffffff80,$4c333402
+	dc.l	$cef042ee,$ff7e48ee,$ffffffc0,$2d7c0000
+	dc.l	$0004ff8c,$61ff0000,$1abc4a00,$66ff0000
+	dc.l	$1ae252ae,$ff784cfb,$3fff0170,$00001ade
+	dc.l	$42827602,$47eeff74,$287c0000,$00023d7c
+	dc.l	$0000ff7c,$44fc0000,$48eeffff,$ff804c33
+	dc.l	$34020750,$42eeff7e,$48eeffff,$ffc02d7c
+	dc.l	$00000004,$ff8c61ff,$00001a6a,$4a0066ff
+	dc.l	$00001a90,$52aeff78,$4cfb3fff,$01700000
+	dc.l	$1a8c4282,$760247ee,$ff74284b,$d9fc0000
+	dc.l	$00103d7c,$0000ff7c,$44fc0000,$48eeffff
+	dc.l	$ff804c30,$3402c9a0,$fff042ee,$ff7e48ee
+	dc.l	$ffffffc0,$2d7c0000,$0004ff8c,$61ff0000
+	dc.l	$1a144a00,$66ff0000,$1a3a52ae,$ff784cfb
+	dc.l	$3fff0170,$00001a36,$42827602,$47eeff74
+	dc.l	$287c0000,$00023d7c,$0000ff7c,$44fc0000
+	dc.l	$48eeffff,$ff804c33,$3402cef0,$42eeff7e
+	dc.l	$48eeffff,$ffc02d7c,$00000004,$ff8c61ff
+	dc.l	$000019c2,$4a0066ff,$000019e8,$52aeff78
+	dc.l	$60040000,$00024cfb,$3fff0170,$000019de
+	dc.l	$42827602,$47eeff74,$78f03d7c,$0000ff7c
+	dc.l	$44fc0000,$48eeffff,$ff804c3b,$340240e4
+	dc.l	$42eeff7e,$48eeffff,$ffc02d7c,$00000004
+	dc.l	$ff8c61ff,$0000196e,$4a0066ff,$00001994
+	dc.l	$52aeff78,$60040000,$00024cfb,$3fff0170
+	dc.l	$0000198a,$42827602,$41eeff74,$78f83d7c
+	dc.l	$0000ff7c,$44fc0000,$48ee7fff,$ff804c3b
+	dc.l	$340242e4,$42eeff7e,$48ee7fff,$ffc02d7c
+	dc.l	$00000004,$ff8c61ff,$0000191a,$4a0066ff
+	dc.l	$00001940,$52aeff78,$60040000,$00024cfb
+	dc.l	$3fff0170,$00001936,$42827602,$41eeff74
+	dc.l	$78fc3d7c,$0000ff7c,$44fc0000,$48ee7fff
+	dc.l	$ff804c3b,$340244e4,$42eeff7e,$48ee7fff
+	dc.l	$ffc02d7c,$00000004,$ff8c61ff,$000018c6
+	dc.l	$4a0066ff,$000018ec,$52aeff78,$60040000
+	dc.l	$00024cfb,$3fff0170,$000018e2,$42827602
+	dc.l	$41eeff74,$78fe3d7c,$0000ff7c,$44fc0000
+	dc.l	$48ee7fff,$ff804c3b,$340246e4,$42eeff7e
+	dc.l	$48ee7fff,$ffc02d7c,$00000004,$ff8c61ff
+	dc.l	$00001872,$4a0066ff,$00001898,$52aeff78
+	dc.l	$60040000,$00024cfb,$3fff0170,$0000188e
+	dc.l	$42827602,$41eeff74,$78f03d7c,$0000ff7c
+	dc.l	$44fc0000,$48ee7fff,$ff804c3b,$340248e4
+	dc.l	$42eeff7e,$48ee7fff,$ffc02d7c,$00000004
+	dc.l	$ff8c61ff,$0000181e,$4a0066ff,$00001844
+	dc.l	$52aeff78,$60040000,$00024cfb,$3fff0170
+	dc.l	$0000183a,$42827602,$41eeff74,$78f83d7c
+	dc.l	$0000ff7c,$44fc0000,$48ee7fff,$ff804c3b
+	dc.l	$34024ae4,$42eeff7e,$48ee7fff,$ffc02d7c
+	dc.l	$00000004,$ff8c61ff,$000017ca,$4a0066ff
+	dc.l	$000017f0,$52aeff78,$60040000,$00024cfb
+	dc.l	$3fff0170,$000017e6,$42827602,$41eeff74
+	dc.l	$78fc3d7c,$0000ff7c,$44fc0000,$48ee7fff
+	dc.l	$ff804c3b,$34024ce4,$42eeff7e,$48ee7fff
+	dc.l	$ffc02d7c,$00000004,$ff8c61ff,$00001776
+	dc.l	$4a0066ff,$0000179c,$52aeff78,$60040000
+	dc.l	$00024cfb,$3fff0170,$00001792,$42827602
+	dc.l	$41eeff74,$78fe3d7c,$0000ff7c,$44fc0000
+	dc.l	$48ee7fff,$ff804c3b,$34024ee4,$42eeff7e
+	dc.l	$48ee7fff,$ffc02d7c,$00000004,$ff8c61ff
+	dc.l	$00001722,$4a0066ff,$00001748,$52aeff78
+	dc.l	$60040000,$00024cfb,$3fff0170,$0000173e
+	dc.l	$42827602,$47eeff74,$287cffff,$fffe3d7c
+	dc.l	$0000ff7c,$44fc0000,$48eeffff,$ff804c3b
+	dc.l	$3402cee0,$42eeff7e,$48eeffff,$ffc02d7c
+	dc.l	$00000004,$ff8c61ff,$000016ca,$4a0066ff
+	dc.l	$000016f0,$52aeff78,$60040000,$00024cfb
+	dc.l	$3fff0170,$000016e6,$42827602,$47eeff74
+	dc.l	$287c0000,$00023d7c,$0000ff7c,$44fc0000
+	dc.l	$48eeffff,$ff804c3b,$34020760,$ffd042ee
+	dc.l	$ff7e48ee,$ffffffc0,$2d7c0000,$0004ff8c
+	dc.l	$61ff0000,$16704a00,$66ff0000,$169652ae
+	dc.l	$ff7852ae,$ff784cfb,$3fff0170,$0000168e
+	dc.l	$42827602,$47f9ffff,$ff74287c,$00000002
+	dc.l	$3d7c0000,$ff7c44fc,$000048ee,$ffffff80
+	dc.l	$4c3b3402,$cf300000,$000a42ee,$ff7e48ee
+	dc.l	$ffffffc0,$2d7c0000,$0004ff8c,$60040000
+	dc.l	$000261ff,$0000160e,$4a0066ff,$00001634
+	dc.l	$52aeff78,$60040000,$00024cfb,$3fff0170
+	dc.l	$0000162a,$42827602,$43eeff74,$78f03d7c
+	dc.l	$0000ff7c,$44fc0000,$48eeffff,$ff804c3b
+	dc.l	$340240e4,$42eeff7e,$48eeffff,$ffc02d7c
+	dc.l	$00000004,$ff8c61ff,$000015ba,$4a0066ff
+	dc.l	$000015e0,$52aeff78,$60040000,$00024cfb
+	dc.l	$3fff0170,$000015d6,$42827602,$41eeff74
+	dc.l	$78f83d7c,$0000ff7c,$44fc0000,$48eeffff
+	dc.l	$ff804c3b,$340242e4,$42eeff7e,$48eeffff
+	dc.l	$ffc02d7c,$00000004,$ff8c61ff,$00001566
+	dc.l	$4a0066ff,$0000158c,$52aeff78,$60040000
+	dc.l	$00024cfb,$3fff0170,$00001582,$42827602
+	dc.l	$41eeff74,$78fc3d7c,$0000ff7c,$44fc0000
+	dc.l	$48eeffff,$ff804c3b,$340244e4,$42eeff7e
+	dc.l	$48eeffff,$ffc02d7c,$00000004,$ff8c61ff
+	dc.l	$00001512,$4a0066ff,$00001538,$52aeff78
+	dc.l	$60040000,$00024cfb,$3fff0170,$0000152e
+	dc.l	$42827602,$41eeff74,$78fe3d7c,$0000ff7c
+	dc.l	$44fc0000,$48eeffff,$ff804c3b,$340246e4
+	dc.l	$42eeff7e,$48eeffff,$ffc02d7c,$00000004
+	dc.l	$ff8c61ff,$000014be,$4a0066ff,$000014e4
+	dc.l	$52aeff78,$60040000,$00024cfb,$3fff0170
+	dc.l	$000014da,$42827602,$41eeff74,$78f03d7c
+	dc.l	$0000ff7c,$44fc0000,$48eeffff,$ff804c3b
+	dc.l	$340248e4,$42eeff7e,$48eeffff,$ffc02d7c
+	dc.l	$00000004,$ff8c61ff,$0000146a,$4a0066ff
+	dc.l	$00001490,$52aeff78,$60040000,$00024cfb
+	dc.l	$3fff0170,$00001486,$42827602,$41eeff74
+	dc.l	$78f83d7c,$0000ff7c,$44fc0000,$48eeffff
+	dc.l	$ff804c3b,$34024ae4,$42eeff7e,$48eeffff
+	dc.l	$ffc02d7c,$00000004,$ff8c61ff,$00001416
+	dc.l	$4a0066ff,$0000143c,$52aeff78,$60040000
+	dc.l	$00024cfb,$3fff0170,$00001432,$42827602
+	dc.l	$41eeff74,$78fc3d7c,$0000ff7c,$44fc0000
+	dc.l	$48eeffff,$ff804c3b,$34024ce4,$42eeff7e
+	dc.l	$48eeffff,$ffc02d7c,$00000004,$ff8c61ff
+	dc.l	$000013c2,$4a0066ff,$000013e8,$52aeff78
+	dc.l	$60040000,$00024cfb,$3fff0170,$000013de
+	dc.l	$42827602,$41eeff74,$78fe3d7c,$0000ff7c
+	dc.l	$44fc0000,$48eeffff,$ff804c3b,$34024ee4
+	dc.l	$42eeff7e,$48eeffff,$ffc02d7c,$00000004
+	dc.l	$ff8c61ff,$0000136e,$4a0066ff,$00001394
+	dc.l	$52aeff78,$4cfb3fff,$01700000,$13904282
+	dc.l	$760241ee,$ff7478fe,$3d7c0000,$ff7c44fc
+	dc.l	$000048ee,$ffffff80,$4c3b3402,$4e2642ee
+	dc.l	$ff7e48ee,$ffffffc0,$2d7c0000,$0004ff8c
+	dc.l	$60040000,$000261ff,$0000131a,$4a0066ff
+	dc.l	$00001340,$52aeff78,$4cfb3fff,$01700000
+	dc.l	$133c4282,$760247ee,$ef7449ee,$ff70288b
+	dc.l	$78f03d7c,$0000ff7c,$44fc0000,$48eeffff
+	dc.l	$ff804c34,$34024122,$00101000,$42eeff7e
+	dc.l	$48eeffff,$ffc02d7c,$00000004,$ff8c61ff
+	dc.l	$000012c2,$4a0066ff,$000012e8,$52aeff78
+	dc.l	$4cfb3fff,$01700000,$12e44282,$760247ee
+	dc.l	$ef7449ee,$ff70288b,$78f83d7c,$0000ff7c
+	dc.l	$44fc0000,$48eeffff,$ff804c34,$34024322
+	dc.l	$00101000,$42eeff7e,$48eeffff,$ffc02d7c
+	dc.l	$00000004,$ff8c61ff,$0000126a,$4a0066ff
+	dc.l	$00001290,$52aeff78,$4cfb3fff,$01700000
+	dc.l	$128c4282,$760247ee,$ef7449ee,$ff70288b
+	dc.l	$78fc3d7c,$0000ff7c,$44fc0000,$48eeffff
+	dc.l	$ff804c34,$34024522,$00101000,$42eeff7e
+	dc.l	$48eeffff,$ffc02d7c,$00000004,$ff8c61ff
+	dc.l	$00001212,$4a0066ff,$00001238,$52aeff78
+	dc.l	$4cfb3fff,$01700000,$12344282,$760247ee
+	dc.l	$ef7449ee,$ff70288b,$78fe3d7c,$0000ff7c
+	dc.l	$44fc0000,$48eeffff,$ff804c34,$34024722
+	dc.l	$00101000,$42eeff7e,$48eeffff,$ffc02d7c
+	dc.l	$00000004,$ff8c61ff,$000011ba,$4a0066ff
+	dc.l	$000011e0,$52aeff78,$4cfb3fff,$01700000
+	dc.l	$11dc4282,$760247ee,$ef7449ee,$ff70288b
+	dc.l	$78f03d7c,$0000ff7c,$44fc0000,$48eeffff
+	dc.l	$ff804c34,$34024922,$00101000,$42eeff7e
+	dc.l	$48eeffff,$ffc02d7c,$00000004,$ff8c61ff
+	dc.l	$00001162,$4a0066ff,$00001188,$52aeff78
+	dc.l	$4cfb3fff,$01700000,$11844282,$760247ee
+	dc.l	$ef7449ee,$ff70288b,$78f83d7c,$0000ff7c
+	dc.l	$44fc0000,$48eeffff,$ff804c34,$34024b22
+	dc.l	$00101000,$42eeff7e,$48eeffff,$ffc02d7c
+	dc.l	$00000004,$ff8c61ff,$0000110a,$4a0066ff
+	dc.l	$00001130,$52aeff78,$4cfb3fff,$01700000
+	dc.l	$112c4282,$760247ee,$ef7449ee,$ff70288b
+	dc.l	$78fc3d7c,$0000ff7c,$44fc0000,$48eeffff
+	dc.l	$ff804c34,$34024d22,$00101000,$42eeff7e
+	dc.l	$48eeffff,$ffc02d7c,$00000004,$ff8c61ff
+	dc.l	$000010b2,$4a0066ff,$000010d8,$52aeff78
+	dc.l	$4cfb3fff,$01700000,$10d44282,$760247ee
+	dc.l	$ef7449ee,$ff70288b,$78fe3d7c,$0000ff7c
+	dc.l	$44fc0000,$48eeffff,$ff804c34,$34024f22
+	dc.l	$00101000,$42eeff7e,$48eeffff,$ffc02d7c
+	dc.l	$00000004,$ff8c61ff,$0000105a,$4a0066ff
+	dc.l	$00001080,$52aeff78,$4cfb3fff,$01700000
+	dc.l	$107c4282,$760247ee,$ef7449ee,$ff70288b
+	dc.l	$78fe3d7c,$0000ff7c,$44fc0000,$48eeffff
+	dc.l	$ff804c34,$34024f33,$00000010,$00001000
+	dc.l	$42eeff7e,$48eeffff,$ffc02d7c,$00000004
+	dc.l	$ff8c61ff,$00000ffe,$4a0066ff,$00001024
+	dc.l	$52aeff78,$4cfb3fff,$01700000,$10204282
+	dc.l	$760247ee,$ef7449ee,$ff70288b,$78fe3d7c
+	dc.l	$0000ff7c,$44fc0000,$48eeffff,$ff804c34
+	dc.l	$34020753,$00001000,$42eeff7e,$48eeffff
+	dc.l	$ffc02d7c,$00000004,$ff8c61ff,$00000fa6
+	dc.l	$4a0066ff,$00000fcc,$52aeff78,$4cfb3fff
+	dc.l	$01700000,$0fc84282,$760247ee,$ef7449ee
+	dc.l	$ff70288b,$78fe3d7c,$0000ff7c,$44fc0000
+	dc.l	$48eeffff,$ff804c34,$34020753,$00001000
+	dc.l	$42eeff7e,$48eeffff,$ffc02d7c,$00000004
+	dc.l	$ff8c61ff,$00000f4e,$4a0066ff,$00000f74
+	dc.l	$52aeff78,$4cfb3fff,$01700000,$0f704282
+	dc.l	$760247ee,$ef7449ee,$ff70288b,$78f0d88c
+	dc.l	$3d7c0000,$ff7c44fc,$000048ee,$ffffff80
+	dc.l	$4c303402,$49b30000,$00100000,$100042ee
+	dc.l	$ff7e48ee,$ffffffc0,$2d7c0000,$0004ff8c
+	dc.l	$61ff0000,$0ef04a00,$66ff0000,$0f1652ae
+	dc.l	$ff7852ae,$ff784cfb,$3fff0170,$00000f0e
+	dc.l	$224e4282,$760247e9,$0f7449e9,$ff70288b
+	dc.l	$2c7cffff,$fffe337c,$0000ff7c,$44fc0000
+	dc.l	$48e9ffff,$ff804c34,$3402ef22,$0010f000
+	dc.l	$42e9ff7e,$48e9ffff,$ffc0237c,$00000004
+	dc.l	$ff8c2c49,$61ff0000,$0e8c4a00,$66ff0000
+	dc.l	$0eb252ae,$ff784cfb,$3fff0170,$00000eae
+	dc.l	$224e4282,$760247e9,$0f7449e9,$ff70288b
+	dc.l	$2c7c0000,$0002337c,$0000ff7c,$44fc0000
+	dc.l	$48e9ffff,$ff804c34,$3402ef22,$fff0f000
+	dc.l	$42e9ff7e,$48e9ffff,$ffc0237c,$00000004
+	dc.l	$ff8c2c49,$61ff0000,$0e2c4a00,$66ff0000
+	dc.l	$0e5252ae,$ff784cfb,$3fff0170,$00000e4e
+	dc.l	$42827602,$47eeff54,$49eeff70,$288b99fc
+	dc.l	$00000010,$78103d7c,$0000ff7c,$44fc0000
+	dc.l	$48eeffff,$ff804c34,$34024126,$00100010
+	dc.l	$42eeff7e,$48eeffff,$ffc02d7c,$00000004
+	dc.l	$ff8c61ff,$00000dce,$4a0066ff,$00000df4
+	dc.l	$52aeff78,$4cfb3fff,$01700000,$0df04282
+	dc.l	$760247ee,$ff5449ee,$ff70288b,$99fc0000
+	dc.l	$00107808,$3d7c0000,$ff7c44fc,$000048ee
+	dc.l	$ffffff80,$4c343402,$43260010,$001042ee
+	dc.l	$ff7e48ee,$ffffffc0,$2d7c0000,$0004ff8c
+	dc.l	$61ff0000,$0d704a00,$66ff0000,$0d9652ae
+	dc.l	$ff784cfb,$3fff0170,$00000d92,$42827602
+	dc.l	$47eeff54,$49eeff70,$288b99fc,$00000010
+	dc.l	$78043d7c,$0000ff7c,$44fc0000,$48eeffff
+	dc.l	$ff804c34,$34024526,$00100010,$42eeff7e
+	dc.l	$48eeffff,$ffc02d7c,$00000004,$ff8c61ff
+	dc.l	$00000d12,$4a0066ff,$00000d38,$52aeff78
+	dc.l	$4cfb3fff,$01700000,$0d344282,$760247ee
+	dc.l	$ff5449ee,$ff70288b,$99fc0000,$00107802
+	dc.l	$3d7c0000,$ff7c44fc,$000048ee,$ffffff80
+	dc.l	$4c343402,$47260010,$001042ee,$ff7e48ee
+	dc.l	$ffffffc0,$2d7c0000,$0004ff8c,$61ff0000
+	dc.l	$0cb44a00,$66ff0000,$0cda52ae,$ff784cfb
+	dc.l	$3fff0170,$00000cd6,$42827602,$47eeff54
+	dc.l	$49eeff70,$288b99fc,$00000010,$78103d7c
+	dc.l	$0000ff7c,$44fc0000,$48eeffff,$ff804c34
+	dc.l	$34024926,$00100010,$42eeff7e,$48eeffff
+	dc.l	$ffc02d7c,$00000004,$ff8c61ff,$00000c56
+	dc.l	$4a0066ff,$00000c7c,$52aeff78,$4cfb3fff
+	dc.l	$01700000,$0c784282,$760247ee,$ff5449ee
+	dc.l	$ff70288b,$99fc0000,$00107808,$3d7c0000
+	dc.l	$ff7c44fc,$000048ee,$ffffff80,$4c343402
+	dc.l	$43260010,$001042ee,$ff7e48ee,$ffffffc0
+	dc.l	$2d7c0000,$0004ff8c,$61ff0000,$0bf84a00
+	dc.l	$66ff0000,$0c1e52ae,$ff784cfb,$3fff0170
+	dc.l	$00000c1a,$42827602,$47eeff54,$49eeff70
+	dc.l	$288b99fc,$00000010,$78043d7c,$0000ff7c
+	dc.l	$44fc0000,$48eeffff,$ff804c34,$34024d26
+	dc.l	$00100010,$42eeff7e,$48eeffff,$ffc02d7c
+	dc.l	$00000004,$ff8c61ff,$00000b9a,$4a0066ff
+	dc.l	$00000bc0,$52aeff78,$4cfb3fff,$01700000
+	dc.l	$0bbc4282,$760247ee,$ff5449ee,$ff70288b
+	dc.l	$99fc0000,$00107802,$3d7c0000,$ff7c44fc
+	dc.l	$000048ee,$ffffff80,$4c343402,$4f260010
+	dc.l	$001042ee,$ff7e48ee,$ffffffc0,$2d7c0000
+	dc.l	$0004ff8c,$61ff0000,$0b3c4a00,$66ff0000
+	dc.l	$0b6252ae,$ff784cfb,$3fff0170,$00000b5e
+	dc.l	$42827602,$47eeff54,$49eeff70,$288b99fc
+	dc.l	$00000010,$78023d7c,$0000ff7c,$44fc0000
+	dc.l	$48eeffff,$ff804c34,$34024f37,$00000010
+	dc.l	$00000010,$42eeff7e,$48eeffff,$ffc02d7c
+	dc.l	$00000004,$ff8c61ff,$00000ada,$4a0066ff
+	dc.l	$00000b00,$52aeff78,$4cfb3fff,$01700000
+	dc.l	$0afc4282,$760247ee,$ff5449ee,$ff70288b
+	dc.l	$78023d7c,$0000ff7c,$44fc0000,$48eeffff
+	dc.l	$ff804c34,$34020753,$00000020,$42eeff7e
+	dc.l	$48eeffff,$ffc02d7c,$00000004,$ff8c61ff
+	dc.l	$00000a82,$4a0066ff,$00000aa8,$52aeff78
+	dc.l	$4cfb3fff,$01700000,$0aa4204f,$42827602
+	dc.l	$47eeff54,$4feeff70,$2e8b7820,$3d7c0000
+	dc.l	$ff7c44fc,$000048ee,$ffffff80,$4c373402
+	dc.l	$491542ee,$ff7e48ee,$ffffffc0,$2d7c0000
+	dc.l	$0004ff8c,$2e4861ff,$00000a2a,$4a0066ff
+	dc.l	$00000a50,$52aeff78,$52aeff78,$4cfb3fff
+	dc.l	$01700000,$0a48224e,$42827602,$47e9ff74
+	dc.l	$4de9ff70,$2c8bddfc,$00000010,$2a7cffff
+	dc.l	$fffe337c,$0000ff7c,$44fc0000,$48e9ffff
+	dc.l	$ff804c36,$3402df27,$fff00000,$001042e9
+	dc.l	$ff7e48e9,$ffffffc0,$237c0000,$0004ff8c
+	dc.l	$2c4961ff,$000009be,$4a0066ff,$000009e4
+	dc.l	$222eff78,$42804e75,$52aeff78,$4cfb3fff
+	dc.l	$01700000,$09d84282,$760247fa,$ef7449fa
+	dc.l	$ff70288b,$78f03d7c,$0000ff7c,$44fc0000
+	dc.l	$48eeffff,$ff804c3b,$34024122,$ff801000
+	dc.l	$42eeff7e,$48eeffff,$ffc02d7c,$00000004
+	dc.l	$ff8c61ff,$0000095e,$4a0066ff,$00000984
+	dc.l	$52aeff78,$4cfb3fff,$01700000,$09804282
+	dc.l	$760247fa,$ef7449fa,$ff70288b,$78f83d7c
+	dc.l	$0000ff7c,$44fc0000,$48eeffff,$ff804c3b
+	dc.l	$34024322,$ff801000,$42eeff7e,$48eeffff
+	dc.l	$ffc02d7c,$00000004,$ff8c61ff,$00000906
+	dc.l	$4a0066ff,$0000092c,$52aeff78,$4cfb3fff
+	dc.l	$01700000,$09284282,$760247fa,$ef7449fa
+	dc.l	$ff70288b,$78fc3d7c,$0000ff7c,$44fc0000
+	dc.l	$48eeffff,$ff804c3b,$34024522,$ff801000
+	dc.l	$42eeff7e,$48eeffff,$ffc02d7c,$00000004
+	dc.l	$ff8c61ff,$000008ae,$4a0066ff,$000008d4
+	dc.l	$52aeff78,$4cfb3fff,$01700000,$08d04282
+	dc.l	$760247fa,$ef7449fa,$ff70288b,$78fe3d7c
+	dc.l	$0000ff7c,$44fc0000,$48eeffff,$ff804c3b
+	dc.l	$34024722,$ff801000,$42eeff7e,$48eeffff
+	dc.l	$ffc02d7c,$00000004,$ff8c61ff,$00000856
+	dc.l	$4a0066ff,$0000087c,$52aeff78,$4cfb3fff
+	dc.l	$01700000,$08784282,$760247fa,$ef7449fa
+	dc.l	$ff70288b,$78f03d7c,$0000ff7c,$44fc0000
+	dc.l	$48eeffff,$ff804c3b,$34024922,$ff801000
+	dc.l	$42eeff7e,$48eeffff,$ffc02d7c,$00000004
+	dc.l	$ff8c61ff,$000007fe,$4a0066ff,$00000824
+	dc.l	$52aeff78,$4cfb3fff,$01700000,$08204282
+	dc.l	$760247fa,$ef7449fa,$ff70288b,$78f83d7c
+	dc.l	$0000ff7c,$44fc0000,$48eeffff,$ff804c3b
+	dc.l	$34024b22,$ff801000,$42eeff7e,$48eeffff
+	dc.l	$ffc02d7c,$00000004,$ff8c61ff,$000007a6
+	dc.l	$4a0066ff,$000007cc,$52aeff78,$4cfb3fff
+	dc.l	$01700000,$07c84282,$760247fa,$ef7449fa
+	dc.l	$ff70288b,$78fc3d7c,$0000ff7c,$44fc0000
+	dc.l	$48eeffff,$ff804c3b,$34024d22,$ff801000
+	dc.l	$42eeff7e,$48eeffff,$ffc02d7c,$00000004
+	dc.l	$ff8c61ff,$0000074e,$4a0066ff,$00000774
+	dc.l	$52aeff78,$4cfb3fff,$01700000,$07704282
+	dc.l	$760247fa,$ef7449fa,$ff70288b,$78fe3d7c
+	dc.l	$0000ff7c,$44fc0000,$48eeffff,$ff804c3b
+	dc.l	$34024f22,$ff801000,$42eeff7e,$48eeffff
+	dc.l	$ffc02d7c,$00000004,$ff8c61ff,$000006f6
+	dc.l	$4a0066ff,$0000071c,$52aeff78,$4cfb3fff
+	dc.l	$01700000,$07184282,$760247fa,$ef7449fa
+	dc.l	$ff70288b,$78fe3d7c,$0000ff7c,$44fc0000
+	dc.l	$48eeffff,$ff804c3b,$34024f33,$ffffff80
+	dc.l	$00001000,$42eeff7e,$48eeffff,$ffc02d7c
+	dc.l	$00000004,$ff8c61ff,$0000069a,$4a0066ff
+	dc.l	$000006c0,$52aeff78,$4cfb3fff,$01700000
+	dc.l	$06bc4282,$760247fa,$ef7449fa,$ff70288b
+	dc.l	$78fe3d7c,$0000ff7c,$44fc0000,$48eeffff
+	dc.l	$ff804c3b,$34020773,$ffffff70,$00001000
+	dc.l	$42eeff7e,$48eeffff,$ffc02d7c,$00000004
+	dc.l	$ff8c61ff,$0000063e,$4a0066ff,$00000664
+	dc.l	$52aeff78,$4cfb3fff,$01700000,$06604282
+	dc.l	$760247fa,$ef7449fa,$ff70288b,$280c3d7c
+	dc.l	$0000ff7c,$44fc0000,$48eeffff,$ff804c30
+	dc.l	$34024993,$00001000,$42eeff7e,$48eeffff
+	dc.l	$ffc02d7c,$00000004,$ff8c61ff,$000005e6
+	dc.l	$4a0066ff,$0000060c,$52aeff78,$4cfb3fff
+	dc.l	$01700000,$06084282,$760247fa,$ef7449fa
+	dc.l	$ff70288b,$78f0d88c,$3d7c0000,$ff7c44fc
+	dc.l	$000048ee,$ffffff80,$4c303402,$49b30000
+	dc.l	$00100000,$100042ee,$ff7e48ee,$ffffffc0
+	dc.l	$2d7c0000,$0004ff8c,$61ff0000,$05884a00
+	dc.l	$66ff0000,$05ae52ae,$ff784282,$760247fa
+	dc.l	$ff7449fa,$ff70288b,$78f03d7c,$0000ff7c
+	dc.l	$44fc0000,$48eeffff,$ff804c30,$340201f1
+	dc.l	$ffffff70,$42eeff7e,$48eeffff,$ffc02d7c
+	dc.l	$00000004,$ff8c61ff,$0000053a,$4a0066ff
+	dc.l	$00000560,$52aeff78,$4cfb3fff,$01700000
+	dc.l	$055c4282,$760247fa,$0f7449fa,$ff70288b
+	dc.l	$2c7c0000,$00023d7c,$0000ff7c,$44fc0000
+	dc.l	$48eeffff,$ff804c3b,$3402ef22,$ff60f000
+	dc.l	$42eeff7e,$48eeffff,$ffc02d7c,$00000004
+	dc.l	$ff8c61ff,$000004de,$4a0066ff,$00000504
+	dc.l	$52aeff78,$4cfb3fff,$01700000,$0500204f
+	dc.l	$42827602,$47fa0f74,$49faff70,$288b2e7c
+	dc.l	$00000002,$3d7c0000,$ff7c44fc,$000048ee
+	dc.l	$ffffff80,$4c3b3402,$ff22ff60,$f00042ee
+	dc.l	$ff7e48ee,$ffffffc0,$2d7c0000,$0004ff8c
+	dc.l	$2e4861ff,$0000047e,$4a0066ff,$000004a4
+	dc.l	$52aeff78,$4cfb3fff,$01700000,$04a04282
+	dc.l	$760247fa,$ff5449fa,$ff70288b,$99fc0000
+	dc.l	$00107810,$3d7c0000,$ff7c44fc,$000048ee
+	dc.l	$ffffff80,$4c3b3402,$4126ff70,$001042ee
+	dc.l	$ff7e48ee,$ffffffc0,$2d7c0000,$0004ff8c
+	dc.l	$61ff0000,$04204a00,$66ff0000,$044652ae
+	dc.l	$ff784cfb,$3fff0170,$00000442,$42827602
+	dc.l	$47faff54,$49faff70,$288b99fc,$00000010
+	dc.l	$78083d7c,$0000ff7c,$44fc0000,$48eeffff
+	dc.l	$ff804c3b,$34024326,$ff700010,$42eeff7e
+	dc.l	$48eeffff,$ffc02d7c,$00000004,$ff8c61ff
+	dc.l	$000003c2,$4a0066ff,$000003e8,$52aeff78
+	dc.l	$4cfb3fff,$01700000,$03e44282,$760247fa
+	dc.l	$ff5449fa,$ff70288b,$99fc0000,$00107804
+	dc.l	$3d7c0000,$ff7c44fc,$000048ee,$ffffff80
+	dc.l	$4c3b3402,$4526ff70,$001042ee,$ff7e48ee
+	dc.l	$ffffffc0,$2d7c0000,$0004ff8c,$61ff0000
+	dc.l	$03644a00,$66ff0000,$038a52ae,$ff784cfb
+	dc.l	$3fff0170,$00000386,$42827602,$47faff54
+	dc.l	$49faff70,$288b99fc,$00000010,$78023d7c
+	dc.l	$0000ff7c,$44fc0000,$48eeffff,$ff804c3b
+	dc.l	$34024726,$ff700010,$42eeff7e,$48eeffff
+	dc.l	$ffc02d7c,$00000004,$ff8c61ff,$00000306
+	dc.l	$4a0066ff,$0000032c,$52aeff78,$4cfb3fff
+	dc.l	$01700000,$03284282,$760247fa,$ff5449fa
+	dc.l	$ff70288b,$99fc0000,$00107810,$3d7c0000
+	dc.l	$ff7c44fc,$000048ee,$ffffff80,$4c3b3402
+	dc.l	$4926ff70,$001042ee,$ff7e48ee,$ffffffc0
+	dc.l	$2d7c0000,$0004ff8c,$61ff0000,$02a84a00
+	dc.l	$66ff0000,$02ce52ae,$ff784cfb,$3fff0170
+	dc.l	$000002ca,$42827602,$47faff54,$49faff70
+	dc.l	$288b99fc,$00000010,$78083d7c,$0000ff7c
+	dc.l	$44fc0000,$48eeffff,$ff804c3b,$34024326
+	dc.l	$ff700010,$42eeff7e,$48eeffff,$ffc02d7c
+	dc.l	$00000004,$ff8c61ff,$0000024a,$4a0066ff
+	dc.l	$00000270,$52aeff78,$4cfb3fff,$01700000
+	dc.l	$026c4282,$760247fa,$ff5449fa,$ff70288b
+	dc.l	$99fc0000,$00107804,$3d7c0000,$ff7c44fc
+	dc.l	$000048ee,$ffffff80,$4c3b3402,$4d26ff70
+	dc.l	$001042ee,$ff7e48ee,$ffffffc0,$2d7c0000
+	dc.l	$0004ff8c,$61ff0000,$01ec4a00,$66ff0000
+	dc.l	$021252ae,$ff784cfb,$3fff0170,$0000020e
+	dc.l	$42827602,$47faff54,$49faff70,$288b99fc
+	dc.l	$00000010,$78023d7c,$0000ff7c,$44fc0000
+	dc.l	$48eeffff,$ff804c3b,$34024f26,$ff700010
+	dc.l	$42eeff7e,$48eeffff,$ffc02d7c,$00000004
+	dc.l	$ff8c61ff,$0000018e,$4a0066ff,$000001b4
+	dc.l	$52aeff78,$4cfb3fff,$01700000,$01b04282
+	dc.l	$760247fa,$ff5449fa,$ff70288b,$99fc0000
+	dc.l	$00107802,$3d7c0000,$ff7c44fc,$000048ee
+	dc.l	$ffffff80,$4c3b3402,$4f37ffff,$ff700000
+	dc.l	$001042ee,$ff7e48ee,$ffffffc0,$2d7c0000
+	dc.l	$0004ff8c,$61ff0000,$012c4a00,$66ff0000
+	dc.l	$015252ae,$ff784cfb,$3fff0170,$0000014e
+	dc.l	$42827602,$47faff54,$49faff70,$288b7802
+	dc.l	$3d7c0000,$ff7c44fc,$000048ee,$ffffff80
+	dc.l	$4c3b3402,$0773ffff,$ff700000,$002042ee
+	dc.l	$ff7e48ee,$ffffffc0,$2d7c0000,$0004ff8c
+	dc.l	$61ff0000,$00d04a00,$66ff0000,$00f652ae
+	dc.l	$ff784cfb,$3fff0170,$000000f2,$42827602
+	dc.l	$47faff54,$49faff70,$288b7804,$3d7c0000
+	dc.l	$ff7c44fc,$000048ee,$ffffff80,$4c303402
+	dc.l	$4fb5ffff,$ff7042ee,$ff7e48ee,$ffffffc0
+	dc.l	$2d7c0000,$0004ff8c,$61ff0000,$00784a00
+	dc.l	$66ff0000,$009e52ae,$ff784cfb,$3fff0170
+	dc.l	$0000009a,$204f4282,$760247fa,$ff744dfa
+	dc.l	$ff702c8b,$ddfc0000,$00102e7c,$fffffffe
+	dc.l	$3d7c0000,$ff7c44fc,$000048ee,$ffffff80
+	dc.l	$4c3b3402,$ff27ff70,$00000010,$42eeff7e
+	dc.l	$48eeffff,$ffc02d7c,$00000004,$ff8c2e48
+	dc.l	$61ff0000,$00104a00,$66ff0000,$00364280
+	dc.l	$4e7541ee,$ff8043ee,$ffc0700e,$b18966ff
+	dc.l	$0000001c,$51c8fff6,$302eff7c,$322eff7e
+	dc.l	$b04166ff,$00000008,$42804e75,$70014e75
+	dc.l	$222eff78,$70014e75,$acacacac,$acacacac
+	dc.l	$acacacac,$acacacac,$acacacac,$acacacac
+	dc.l	$acacacac,$acacacac,$acacacac,$acacacac
+	dc.l	$acacacac,$acacacac,$acacacac,$acacacac
+	dc.l	$acacacac,$acacacac,$2f00203a,$afa4487b
+	dc.l	$0930ffff,$afa0202f,$00044e74,$00042f00
+	dc.l	$203aaf92,$487b0930,$ffffaf8a,$202f0004
+	dc.l	$4e740004,$00000000,$00000000,$00000000
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/ifpsp060/os.S linux/arch/m68k/ifpsp060/os.S
--- v1.3.93/linux/arch/m68k/ifpsp060/os.S	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/ifpsp060/os.S	Sun Feb 18 19:33:51 1996
@@ -0,0 +1,432 @@
+|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+|MOTOROLA MICROPROCESSOR & MEMORY TECHNOLOGY GROUP
+|M68000 Hi-Performance Microprocessor Division
+|M68060 Software Package
+|Production Release P1.00 -- October 10, 1994
+|
+|M68060 Software Package Copyright © 1993, 1994 Motorola Inc.  All rights reserved.
+| 
+|THE SOFTWARE is provided on an "AS IS" basis and without warranty.
+|To the maximum extent permitted by applicable law,
+|MOTOROLA DISCLAIMS ALL WARRANTIES WHETHER EXPRESS OR IMPLIED, 
+|INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+|and any warranty against infringement with regard to the SOFTWARE
+|(INCLUDING ANY MODIFIED VERSIONS THEREOF) and any accompanying written materials.
+|
+|To the maximum extent permitted by applicable law,
+|IN NO EVENT SHALL MOTOROLA BE LIABLE FOR ANY DAMAGES WHATSOEVER
+|(INCLUDING WITHOUT LIMITATION, DAMAGES FOR LOSS OF BUSINESS PROFITS,
+|BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION, OR OTHER PECUNIARY LOSS)
+|ARISING OF THE USE OR INABILITY TO USE THE SOFTWARE.
+|Motorola assumes no responsibility for the maintenance and support of the SOFTWARE.
+|
+|You are hereby granted a copyright license to use, modify, and distribute the SOFTWARE
+|so long as this entire notice is retained without alteration in any modified and/or
+|redistributed versions, and that such modified versions are clearly identified as such.
+|No licenses are granted by implication, estoppel or otherwise under any patents
+|or trademarks of Motorola, Inc.
+|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+| os.s
+|
+| This file contains:
+|	- example "Call-Out"s required by both the ISP and FPSP.
+|
+
+
+|################################
+| EXAMPLE CALL-OUTS 		#
+| 				#
+| _060_dmem_write()		#
+| _060_dmem_read()		#
+| _060_imem_read()		#
+| _060_dmem_read_byte()		#
+| _060_dmem_read_word()		#
+| _060_dmem_read_long()		#
+| _060_imem_read_word()		#
+| _060_imem_read_long()		#
+| _060_dmem_write_byte()	#
+| _060_dmem_write_word()	#
+| _060_dmem_write_long()	#
+|				#
+| _060_real_trace()		#
+| _060_real_access()		#
+|################################
+
+| 
+| Each IO routine checks to see if the memory write/read is to/from user
+| or supervisor application space. The examples below use simple "move"
+| instructions for supervisor mode applications and call _copyin()/_copyout()
+| for user mode applications.
+| When installing the 060SP, the _copyin()/_copyout() equivalents for a 
+| given operating system should be substituted.
+|
+| The addresses within the 060SP are guaranteed to be on the stack.
+| The result is that Unix processes are allowed to sleep as a consequence
+| of a page fault during a _copyout.
+|
+
+|
+| _060_dmem_write():
+|
+| Writes to data memory while in supervisor mode.
+|
+| INPUTS:
+|	a0 - supervisor source address	
+|	a1 - user destination address
+|	d0 - number of bytes to write	
+| 	0x4(%a6),bit5 - 1 = supervisor mode, 0 = user mode
+| OUTPUTS:
+|	d1 - 0 = success, !0 = failure
+|
+	.global		_060_dmem_write
+_060_dmem_write:
+	btst		#0x5,0x4(%a6)		| check for supervisor state
+	beqs		user_write
+super_write:
+	move.b		(%a0)+,(%a1)+		| copy 1 byte
+	subq.l		#0x1,%d0		| decr byte counter
+	bnes		super_write		| quit if ctr = 0
+	clr.l		%d1			| return success
+	rts
+user_write:
+	move.l		%d0,-(%sp)		| pass: counter
+	move.l		%a1,-(%sp)		| pass: user dst
+	move.l		%a0,-(%sp)		| pass: supervisor src
+	bsr.l		_copyout		| write byte to user mem
+	move.l		%d0,%d1			| return success
+	add.l		#0xc, %sp		| clear 3 lw params
+	rts
+
+|
+| _060_imem_read(), _060_dmem_read():
+|
+| Reads from data/instruction memory while in supervisor mode.
+|
+| INPUTS:
+|	a0 - user source address
+|	a1 - supervisor destination address
+|	d0 - number of bytes to read
+| 	0x4(%a6),bit5 - 1 = supervisor mode, 0 = user mode
+| OUTPUTS:
+|	d1 - 0 = success, !0 = failure
+|
+	.global 		_060_imem_read
+	.global		_060_dmem_read
+_060_imem_read:
+_060_dmem_read:
+	btst		#0x5,0x4(%a6)		| check for supervisor state
+	beqs		user_read
+super_read:
+	move.b		(%a0)+,(%a1)+		| copy 1 byte
+	subq.l		#0x1,%d0		| decr byte counter
+	bnes		super_read		| quit if ctr = 0
+	clr.l		%d1			| return success
+	rts
+user_read:
+	move.l		%d0,-(%sp)		| pass: counter
+	move.l		%a1,-(%sp)		| pass: super dst
+	move.l		%a0,-(%sp)		| pass: user src
+	bsr.l		_copyin			| read byte from user mem
+	move.l		%d0,%d1			| return success
+	add.l		#0xc,%sp		| clear 3 lw params
+	rts
+
+|
+| _060_dmem_read_byte():
+| 
+| Read a data byte from user memory.
+|
+| INPUTS:
+|	a0 - user source address
+| 	0x4(%a6),bit5 - 1 = supervisor mode, 0 = user mode
+| OUTPUTS:
+|	d0 - data byte in d0
+|	d1 - 0 = success, !0 = failure
+|
+	.global 		_060_dmem_read_byte
+_060_dmem_read_byte:
+	btst		#0x5,0x4(%a6)		| check for supervisor state
+	bnes		dmrbs			| supervisor
+dmrbu:	clr.l		-(%sp)			| clear space on stack for result
+	move.l		#0x1,-(%sp)		| pass: # bytes to copy
+	pea		0x7(%sp)		| pass: dst addr (stack)
+	move.l		%a0,-(%sp)		| pass: src addr (user mem)
+	bsr.l		_copyin			| "copy in" the data
+	move.l		%d0,%d1			| return success
+	add.l		#0xc,%sp		| delete params
+	move.l		(%sp)+,%d0		| put answer in d0
+	rts
+dmrbs:	clr.l		%d0			| clear whole longword
+	move.b		(%a0),%d0		| fetch super byte
+	clr.l		%d1			| return success
+	rts
+
+|
+| _060_dmem_read_word():
+| 
+| Read a data word from user memory.
+|
+| INPUTS:
+|	a0 - user source address
+| 	0x4(%a6),bit5 - 1 = supervisor mode, 0 = user mode
+| OUTPUTS:
+|	d0 - data word in d0
+|	d1 - 0 = success, !0 = failure
+|
+	.global 		_060_dmem_read_word
+_060_dmem_read_word:
+	btst		#0x5,0x4(%a6)		| check for supervisor state
+	bnes		dmrws			| supervisor
+dmrwu:	clr.l		-(%sp)			| clear space on stack for result
+	move.l		#0x2,-(%sp)		| pass: # bytes to copy
+	pea		0x6(%sp)		| pass: dst addr (stack)
+	move.l		%a0,-(%sp)		| pass: src addr (user mem)
+	bsr.l		_copyin			| "copy in" the data
+	move.l		%d0,%d1			| return success
+	add.l		#0xc,%sp		| delete params
+	move.l		(%sp)+,%d0		| put answer in d0
+	rts
+dmrws:	clr.l		%d0			| clear whole longword
+	move.w		(%a0), %d0		| fetch super word
+	clr.l		%d1			| return success
+	rts
+
+|
+| _060_dmem_read_long():
+| 
+
+|
+| INPUTS:
+|	a0 - user source address
+| 	0x4(%a6),bit5 - 1 = supervisor mode, 0 = user mode
+| OUTPUTS:
+|	d0 - data longword in d0
+|	d1 - 0 = success, !0 = failure
+|
+	.global 		_060_dmem_read_long
+_060_dmem_read_long:
+	btst		#0x5,0x4(%a6)		| check for supervisor state
+	bnes		dmrls			| supervisor
+dmrlu:	subq.l		#0x4,%sp		| clear space on stack for result
+	move.l		#0x4,-(%sp)		| pass: # bytes to copy
+	pea		0x4(%sp)		| pass: dst addr (stack)
+	move.l		%a0,-(%sp)		| pass: src addr (user mem)
+	bsr.l		_copyin			| "copy in" the data
+	move.l		%d0,%d1			| return success
+	add.l		#0xc,%sp		| delete params
+	move.l		(%sp)+,%d0		| put answer in d0
+	rts
+dmrls:	move.l		(%a0),%d0		| fetch super longword
+	clr.l		%d1			| return success
+	rts
+
+|
+| _060_dmem_write_byte():
+|
+| Write a data byte to user memory.
+|
+| INPUTS:
+|	a0 - user destination address
+| 	d0 - data byte in d0
+| 	0x4(%a6),bit5 - 1 = supervisor mode, 0 = user mode
+| OUTPUTS:
+|	d1 - 0 = success, !0 = failure
+|
+	.global 		_060_dmem_write_byte
+_060_dmem_write_byte:
+	btst		#0x5,0x4(%a6)		| check for supervisor state
+	bnes		dmwbs			| supervisor
+dmwbu:	move.l		%d0,-(%sp)		| put src on stack
+	move.l		#0x1,-(%sp)		| pass: # bytes to copy
+	move.l		%a0,-(%sp)		| pass: dst addr (user mem)
+	pea		0xb(%sp)		| pass: src addr (stack)
+	bsr.l		_copyout		| "copy out" the data
+	move.l		%d0,%d1			| return success
+	add.l		#0x10,%sp		| delete params + src
+	rts
+dmwbs:	move.b		%d0,(%a0)		| store super byte
+	clr.l		%d1			| return success
+	rts
+
+|
+| _060_dmem_write_word():
+|
+| Write a data word to user memory.
+|
+| INPUTS:
+|	a0 - user destination address
+| 	d0 - data word in d0
+| 	0x4(%a6),bit5 - 1 = supervisor mode, 0 = user mode
+| OUTPUTS:
+|	d1 - 0 = success, !0 = failure
+|
+	.global 		_060_dmem_write_word
+_060_dmem_write_word:
+	btst		#0x5,0x4(%a6)		| check for supervisor state
+	bnes		dmwws			| supervisor
+dmwwu:	move.l		%d0,-(%sp)		| put src on stack
+	move.l		#0x2,-(%sp)		| pass: # bytes to copy
+	move.l		%a0,-(%sp)		| pass: dst addr (user mem)
+	pea		0xa(%sp)		| pass: src addr (stack)
+	bsr.l		_copyout		| "copy out" the data
+	move.l		%d0,%d1			| return success
+	add.l		#0x10,%sp		| delete params + src
+	rts
+dmwws:	move.w		%d0,(%a0)		| store super word
+	clr.l		%d1			| return success
+	rts
+
+|
+| _060_dmem_write_long():
+|
+| Write a data longword to user memory.
+|
+| INPUTS:
+|	a0 - user destination address
+| 	d0 - data longword in d0
+| 	0x4(%a6),bit5 - 1 = supervisor mode, 0 = user mode
+| OUTPUTS:
+|	d1 - 0 = success, !0 = failure
+|
+	.global 		_060_dmem_write_long
+_060_dmem_write_long:
+	btst		#0x5,0x4(%a6)		| check for supervisor state
+	bnes		dmwls			| supervisor
+dmwlu:	move.l		%d0,-(%sp)		| put src on stack
+	move.l		#0x4,-(%sp)		| pass: # bytes to copy
+	move.l		%a0,-(%sp)		| pass: dst addr (user mem)
+	pea		0x8(%sp)		| pass: src addr (stack)
+	bsr.l		_copyout		| "copy out" the data
+	move.l		%d0,%d1			| return success
+	add.l		#0x10,%sp		| delete params + src
+	rts
+dmwls:	move.l		%d0,(%a0)		| store super longword
+	clr.l		%d1			| return success
+	rts
+
+|
+| _060_imem_read_word():
+| 
+| Read an instruction word from user memory.
+|
+| INPUTS:
+|	a0 - user source address
+| 	0x4(%a6),bit5 - 1 = supervisor mode, 0 = user mode
+| OUTPUTS:
+|	d0 - instruction word in d0
+|	d1 - 0 = success, !0 = failure
+|
+	.global 		_060_imem_read_word
+_060_imem_read_word:
+	btst		#0x5,0x4(%a6)		| check for supervisor state
+	bnes		imrws			| supervisor
+imrwu:	clr.l		-(%sp)			| clear space on stack for result
+	move.l		#0x2,-(%sp)		| pass: # bytes to copy
+	pea		0x6(%sp)		| pass: dst addr (stack)
+	move.l		%a0,-(%sp)		| pass: src addr (user mem)
+	bsr.l		_copyin			| "copy in" the data
+	move.l		%d0,%d1			| return success
+	add.l		#0xc,%sp		| delete params
+	move.l		(%sp)+,%d0		| put answer in d0
+	rts
+imrws:	move.w		(%a0),%d0		| fetch super word
+	clr.l		%d1			| return success
+	rts
+
+|
+| _060_imem_read_long():
+| 
+| Read an instruction longword from user memory.
+|
+| INPUTS:
+|	a0 - user source address
+| 	0x4(%a6),bit5 - 1 = supervisor mode, 0 = user mode
+| OUTPUTS:
+|	d0 - instruction longword in d0
+|	d1 - 0 = success, !0 = failure
+|
+	.global 		_060_imem_read_long
+_060_imem_read_long:
+	btst		#0x5,0x4(%a6)		| check for supervisor state
+	bnes		imrls			| supervisor
+imrlu:	subq.l		#0x4,%sp		| clear space on stack for result
+	move.l		#0x4,-(%sp)		| pass: # bytes to copy
+	pea		0x4(%sp)		| pass: dst addr (stack)
+	move.l		%a0,-(%sp)		| pass: src addr (user mem)
+	bsr.l		_copyin			| "copy in" the data
+	move.l		%d0,%d1			| return success
+	add.l		#0xc,%sp		| delete params
+	move.l		(%sp)+,%d0		| put answer in d0
+	rts
+imrls:	move.l		(%a0),%d0		| fetch super longword
+	clr.l		%d1			| return success
+	rts
+
+|###############################################
+
+|
+| Use these routines if your kernel doesn't have _copyout/_copyin equivalents.
+| Assumes that D0/D1/A0/A1 are scratch registers. The _copyin/_copyout
+| below assume that the SFC/DFC have been set previously.
+|
+
+|
+| int _copyout(supervisor_addr, user_addr, nbytes)
+|
+	.global 		_copyout
+_copyout:
+	move.l		4(%sp),%a0		| source
+	move.l		8(%sp),%a1		| destination
+	move.l		12(%sp),%d0		| count
+moreout:
+	move.b		(%a0)+,%d1		| fetch supervisor byte
+	movs.b		%d1,(%a1)+		| store user byte
+	subq.l		#0x1,%d0		| are we through yet?
+	bne		moreout			| no; so, continue
+	rts
+
+|
+| int _copyin(user_addr, supervisor_addr, nbytes)
+|
+	.global 		_copyin
+_copyin:
+	move.l		4(%sp),%a0		| source
+	move.l		8(%sp),%a1		| destination
+	move.l		12(%sp),%d0		| count
+morein:
+	movs.b		(%a0)+,%d1		| fetch user byte
+	move.b		%d1,(%a1)+		| write supervisor byte
+	subq.l		#0x1,%d0		| are we through yet?
+	bne		morein			| no; so, continue
+	rts
+
+|###########################################################################
+
+|
+| _060_real_trace():
+|
+| This is the exit point for the 060FPSP when an instruction is being traced
+| and there are no other higher priority exceptions pending for this instruction
+| or they have already been processed.
+|
+| The sample code below simply executes an "rte".
+|
+	.global		_060_real_trace
+_060_real_trace:
+	rte
+
+|
+| _060_real_access():
+|
+| This is the exit point for the 060FPSP when an access error exception
+| is encountered. The routine below should point to the operating system
+| handler for access error exceptions. The exception stack frame is an
+| 8-word access error frame.
+|
+| The sample routine below simply executes an "rte" instruction which
+| is most likely the incorrect thing to do and could put the system
+| into an infinite loop.
+|
+	.global		_060_real_access
+_060_real_access:
+	rte
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/ifpsp060/pfpsp.sa linux/arch/m68k/ifpsp060/pfpsp.sa
--- v1.3.93/linux/arch/m68k/ifpsp060/pfpsp.sa	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/ifpsp060/pfpsp.sa	Mon Jan  8 22:08:22 1996
@@ -0,0 +1,1730 @@
+	dc.l	$60ff0000,$17400000,$60ff0000,$15f40000
+	dc.l	$60ff0000,$02b60000,$60ff0000,$04700000
+	dc.l	$60ff0000,$1b100000,$60ff0000,$19aa0000
+	dc.l	$60ff0000,$1b5a0000,$60ff0000,$062e0000
+	dc.l	$60ff0000,$102c0000,$51fc51fc,$51fc51fc
+	dc.l	$51fc51fc,$51fc51fc,$51fc51fc,$51fc51fc
+	dc.l	$51fc51fc,$51fc51fc,$51fc51fc,$51fc51fc
+	dc.l	$51fc51fc,$51fc51fc,$51fc51fc,$51fc51fc
+	dc.l	$2f00203a,$ff2c487b,$0930ffff,$fef8202f
+	dc.l	$00044e74,$00042f00,$203afef2,$487b0930
+	dc.l	$fffffee2,$202f0004,$4e740004,$2f00203a
+	dc.l	$fee0487b,$0930ffff,$fecc202f,$00044e74
+	dc.l	$00042f00,$203afed2,$487b0930,$fffffeb6
+	dc.l	$202f0004,$4e740004,$2f00203a,$fea4487b
+	dc.l	$0930ffff,$fea0202f,$00044e74,$00042f00
+	dc.l	$203afe96,$487b0930,$fffffe8a,$202f0004
+	dc.l	$4e740004,$2f00203a,$fe7c487b,$0930ffff
+	dc.l	$fe74202f,$00044e74,$00042f00,$203afe76
+	dc.l	$487b0930,$fffffe5e,$202f0004,$4e740004
+	dc.l	$2f00203a,$fe68487b,$0930ffff,$fe48202f
+	dc.l	$00044e74,$00042f00,$203afe56,$487b0930
+	dc.l	$fffffe32,$202f0004,$4e740004,$2f00203a
+	dc.l	$fe44487b,$0930ffff,$fe1c202f,$00044e74
+	dc.l	$00042f00,$203afe32,$487b0930,$fffffe06
+	dc.l	$202f0004,$4e740004,$2f00203a,$fe20487b
+	dc.l	$0930ffff,$fdf0202f,$00044e74,$00042f00
+	dc.l	$203afe1e,$487b0930,$fffffdda,$202f0004
+	dc.l	$4e740004,$2f00203a,$fe0c487b,$0930ffff
+	dc.l	$fdc4202f,$00044e74,$00042f00,$203afdfa
+	dc.l	$487b0930,$fffffdae,$202f0004,$4e740004
+	dc.l	$2f00203a,$fde8487b,$0930ffff,$fd98202f
+	dc.l	$00044e74,$00042f00,$203afdd6,$487b0930
+	dc.l	$fffffd82,$202f0004,$4e740004,$2f00203a
+	dc.l	$fdc4487b,$0930ffff,$fd6c202f,$00044e74
+	dc.l	$00042f00,$203afdb2,$487b0930,$fffffd56
+	dc.l	$202f0004,$4e740004,$2f00203a,$fda0487b
+	dc.l	$0930ffff,$fd40202f,$00044e74,$00042f00
+	dc.l	$203afd8e,$487b0930,$fffffd2a,$202f0004
+	dc.l	$4e740004,$2f00203a,$fd7c487b,$0930ffff
+	dc.l	$fd14202f,$00044e74,$00042f00,$203afd6a
+	dc.l	$487b0930,$fffffcfe,$202f0004,$4e740004
+	dc.l	$40c62d38,$d3d64634,$3d6f90ae,$b1e75cc7
+	dc.l	$40000000,$c90fdaa2,$2168c235,$00000000
+	dc.l	$3fff0000,$c90fdaa2,$2168c235,$00000000
+	dc.l	$3fe45f30,$6dc9c883,$4e56ff40,$f32eff6c
+	dc.l	$48ee0303,$ff9cf22e,$bc00ff60,$f22ef0c0
+	dc.l	$ffdc2d6e,$ff68ff44,$206eff44,$58aeff44
+	dc.l	$61ffffff,$ff042d40,$ff40082e,$0005ff42
+	dc.l	$66000116,$41eeff6c,$61ff0000,$051c41ee
+	dc.l	$ff6c61ff,$00002aec,$1d40ff4e,$082e0005
+	dc.l	$ff436726,$e9ee0183,$ff4261ff,$00005cac
+	dc.l	$41eeff78,$61ff0000,$2aca0c00,$00066606
+	dc.l	$61ff0000,$2a2e1d40,$ff4f4280,$102eff63
+	dc.l	$122eff43,$0241007f,$02ae00ff,$01ffff64
+	dc.l	$f23c9000,$00000000,$f23c8800,$00000000
+	dc.l	$41eeff6c,$43eeff78,$223b1530,$00001974
+	dc.l	$4ebb1930,$0000196c,$e9ee0183,$ff4261ff
+	dc.l	$00005cd8,$082e0004,$ff626622,$082e0001
+	dc.l	$ff626644,$f22ed0c0,$ffdcf22e,$9c00ff60
+	dc.l	$4cee0303,$ff9c4e5e,$60ffffff,$fcc6f22e
+	dc.l	$f040ff6c,$3d7ce005,$ff6ef22e,$d0c0ffdc
+	dc.l	$f22e9c00,$ff604cee,$0303ff9c,$f36eff6c
+	dc.l	$4e5e60ff,$fffffcb2,$f22ef040,$ff6c1d7c
+	dc.l	$00c4000b,$3d7ce001,$ff6ef22e,$d0c0ffdc
+	dc.l	$f22e9c00,$ff604cee,$0303ff9c,$f36eff6c
+	dc.l	$4e5e60ff,$fffffcae,$1d7c0000,$ff4e4280
+	dc.l	$102eff63,$02aeffff,$00ffff64,$f23c9000
+	dc.l	$00000000,$f23c8800,$00000000,$41eeff6c
+	dc.l	$61ff0000,$2e0c082e,$0004ff62,$6600ff70
+	dc.l	$082e0001,$ff626600,$ff90f22e,$d0c0ffdc
+	dc.l	$f22e9c00,$ff604cee,$0303ff9c,$4e5e0817
+	dc.l	$000767ff,$fffffc0c,$f22fa400,$00083f7c
+	dc.l	$20240006,$60ffffff,$fcec4e56,$ff40f32e
+	dc.l	$ff6c48ee,$0303ff9c,$f22ebc00,$ff60f22e
+	dc.l	$f0c0ffdc,$2d6eff68,$ff44206e,$ff4458ae
+	dc.l	$ff4461ff,$fffffd42,$2d40ff40,$082e0005
+	dc.l	$ff426600,$013241ee,$ff6c61ff,$0000035a
+	dc.l	$41eeff6c,$61ff0000,$292a1d40,$ff4e082e
+	dc.l	$0005ff43,$672e082e,$0004ff43,$6626e9ee
+	dc.l	$0183ff42,$61ff0000,$5ae241ee,$ff7861ff
+	dc.l	$00002900,$0c000006,$660661ff,$00002864
+	dc.l	$1d40ff4f,$4280102e,$ff63122e,$ff430241
+	dc.l	$007f02ae,$00ff01ff,$ff64f23c,$90000000
+	dc.l	$0000f23c,$88000000,$000041ee,$ff6c43ee
+	dc.l	$ff78223b,$15300000,$17aa4ebb,$19300000
+	dc.l	$17a2e9ee,$0183ff42,$61ff0000,$5b0e082e
+	dc.l	$0003ff62,$6622082e,$0001ff62,$664ef22e
+	dc.l	$d0c0ffdc,$f22e9c00,$ff604cee,$0303ff9c
+	dc.l	$4e5e60ff,$fffffafc,$082e0003,$ff666700
+	dc.l	$ffd6f22e,$f040ff6c,$3d7ce003,$ff6ef22e
+	dc.l	$d0c0ffdc,$f22e9c00,$ff604cee,$0303ff9c
+	dc.l	$f36eff6c,$4e5e60ff,$fffffaf4,$082e0001
+	dc.l	$ff666700,$ffaaf22e,$f040ff6c,$1d7c00c4
+	dc.l	$000b3d7c,$e001ff6e,$f22ed0c0,$ffdcf22e
+	dc.l	$9c00ff60,$4cee0303,$ff9cf36e,$ff6c4e5e
+	dc.l	$60ffffff,$fad01d7c,$0000ff4e,$4280102e
+	dc.l	$ff6302ae,$ffff00ff,$ff64f23c,$90000000
+	dc.l	$0000f23c,$88000000,$000041ee,$ff6c61ff
+	dc.l	$00002c2e,$082e0003,$ff626600,$ff66082e
+	dc.l	$0001ff62,$6600ff90,$f22ed0c0,$ffdcf22e
+	dc.l	$9c00ff60,$4cee0303,$ff9c4e5e,$08170007
+	dc.l	$67ffffff,$fa2ef22f,$a4000008,$3f7c2024
+	dc.l	$000660ff,$fffffb0e,$4e56ff40,$f32eff6c
+	dc.l	$48ee0303,$ff9cf22e,$bc00ff60,$f22ef0c0
+	dc.l	$ffdc082e,$00050004,$66084e68,$2d48ffd8
+	dc.l	$600841ee,$00102d48,$ffd82d6e,$ff68ff44
+	dc.l	$206eff44,$58aeff44,$61ffffff,$fb4c2d40
+	dc.l	$ff40422e,$ff4a082e,$0005ff42,$66000208
+	dc.l	$e9ee0006,$ff420c00,$00136700,$049e02ae
+	dc.l	$00ff00ff,$ff64f23c,$90000000,$0000f23c
+	dc.l	$88000000,$000041ee,$ff6c61ff,$0000013a
+	dc.l	$41eeff6c,$61ff0000,$270a0c00,$00066606
+	dc.l	$61ff0000,$266e1d40,$ff4ee9ee,$0183ff42
+	dc.l	$082e0005,$ff436728,$0c2e003a,$ff436720
+	dc.l	$61ff0000,$58b641ee,$ff7861ff,$000026d4
+	dc.l	$0c000006,$660661ff,$00002638,$1d40ff4f
+	dc.l	$4280102e,$ff63e9ee,$1047ff43,$41eeff6c
+	dc.l	$43eeff78,$223b1d30,$00001598,$4ebb1930
+	dc.l	$00001590,$102eff62,$6634102e,$ff430200
+	dc.l	$00380c00,$0038670c,$e9ee0183,$ff4261ff
+	dc.l	$000058e8,$f22ed0c0,$ffdcf22e,$9c00ff60
+	dc.l	$4cee0303,$ff9c4e5e,$60ffffff,$f8e6c02e
+	dc.l	$ff66edc0,$06086614,$082e0004,$ff6667ba
+	dc.l	$082e0001,$ff6267b2,$60000066,$04800000
+	dc.l	$00180c00,$00066614,$082e0003,$ff666600
+	dc.l	$004a082e,$0004ff66,$66000046,$2f0061ff
+	dc.l	$000007e0,$201f3d7b,$0222ff6e,$f22ed0c0
+	dc.l	$ffdcf22e,$9c00ff60,$4cee0303,$ff9cf36e
+	dc.l	$ff6c4e5e,$60ffffff,$f87ae000,$e006e004
+	dc.l	$e005e003,$e002e001,$e001303c,$000460bc
+	dc.l	$303c0003,$60b6e9ee,$0006ff42,$0c000011
+	dc.l	$67080c00,$00156750,$4e753028,$00000240
+	dc.l	$7fff0c40,$3f806708,$0c40407f,$672c4e75
+	dc.l	$02a87fff,$ffff0004,$671861ff,$000024cc
+	dc.l	$44400640,$3f810268,$80000000,$81680000
+	dc.l	$4e750268,$80000000,$4e750228,$007f0004
+	dc.l	$00687fff,$00004e75,$30280000,$02407fff
+	dc.l	$0c403c00,$67080c40,$43ff67de,$4e7502a8
+	dc.l	$7fffffff,$00046606,$4aa80008,$67c461ff
+	dc.l	$00002478,$44400640,$3c010268,$80000000
+	dc.l	$81680000,$4e75e9ee,$00c3ff42,$0c000003
+	dc.l	$670004a2,$0c000007,$6700049a,$02aeffff
+	dc.l	$00ffff64,$f23c9000,$00000000,$f23c8800
+	dc.l	$00000000,$302eff6c,$02407fff,$671041ee
+	dc.l	$ff6c61ff,$0000246c,$1d40ff4e,$60061d7c
+	dc.l	$0004ff4e,$4280102e,$ff6341ee,$ff6c2d56
+	dc.l	$ffd461ff,$0000292a,$102eff62,$66000086
+	dc.l	$2caeffd4,$082e0005,$00046626,$206effd8
+	dc.l	$4e60f22e,$d0c0ffdc,$f22e9c00,$ff604cee
+	dc.l	$0303ff9c,$4e5e0817,$0007667a,$60ffffff
+	dc.l	$f7220c2e,$0008ff4a,$66d8f22e,$f080ff6c
+	dc.l	$f22ed0c0,$ffdcf22e,$9c00ff60,$4cee0303
+	dc.l	$ff9c2c56,$2f6f00c4,$00b82f6f,$00c800bc
+	dc.l	$2f6f002c,$00c42f6f,$003000c8,$2f6f0034
+	dc.l	$00ccdffc,$000000b8,$08170007,$662860ff
+	dc.l	$fffff6d0,$c02eff66,$edc00608,$662a082e
+	dc.l	$0004ff66,$6700ff6a,$082e0001,$ff626700
+	dc.l	$ff606000,$01663f7c,$20240006,$f22fa400
+	dc.l	$000860ff,$fffff78e,$04800000,$0018303b
+	dc.l	$020a4efb,$00064afc,$00080000,$0000003a
+	dc.l	$00640094,$00000140,$0000f22e,$d0c0ffdc
+	dc.l	$f22e9c00,$ff604cee,$0303ff9c,$3d7c30d8
+	dc.l	$000a3d7c,$e006ff6e,$f36eff6c,$4e5e60ff
+	dc.l	$fffff6d4,$f22ed0c0,$ffdcf22e,$9c00ff60
+	dc.l	$4cee0303,$ff9c3d7c,$30d0000a,$3d7ce004
+	dc.l	$ff6ef36e,$ff6c4e5e,$60ffffff,$f694f22e
+	dc.l	$f040ff6c,$f22ed0c0,$ffdcf22e,$9c00ff60
+	dc.l	$4cee0303,$ff9c3d7c,$30d4000a,$3d7ce005
+	dc.l	$ff6ef36e,$ff6c4e5e,$60ffffff,$f60c2cae
+	dc.l	$ffd4082e,$00050004,$66000038,$206effd8
+	dc.l	$4e60f22e,$f040ff6c,$f22ed0c0,$ffdcf22e
+	dc.l	$9c00ff60,$4cee0303,$ff9c3d7c,$30cc000a
+	dc.l	$3d7ce003,$ff6ef36e,$ff6c4e5e,$60ffffff
+	dc.l	$f5de0c2e,$0008ff4a,$66c8f22e,$f080ff6c
+	dc.l	$f22ef040,$ff78f22e,$d0c0ffdc,$f22e9c00
+	dc.l	$ff604cee,$0303ff9c,$3d7c30cc,$000a3d7c
+	dc.l	$e003ff7a,$f36eff78,$2c562f6f,$00c400b8
+	dc.l	$2f6f00c8,$00bc2f6f,$00cc00c0,$2f6f002c
+	dc.l	$00c42f6f,$003000c8,$2f6f0034,$00ccdffc
+	dc.l	$000000b8,$60ffffff,$f576f22e,$f040ff6c
+	dc.l	$f22ed0c0,$ffdcf22e,$9c00ff60,$4cee0303
+	dc.l	$ff9c3d7c,$30c4000a,$3d7ce001,$ff6ef36e
+	dc.l	$ff6c4e5e,$60ffffff,$f55c02ae,$00ff00ff
+	dc.l	$ff64f23c,$90000000,$0000f23c,$88000000
+	dc.l	$000061ff,$00005548,$41eeff6c,$61ff0000
+	dc.l	$22721d40,$ff4ee9ee,$0183ff42,$082e0005
+	dc.l	$ff436728,$0c2e003a,$ff436720,$61ff0000
+	dc.l	$542a41ee,$ff7861ff,$00002248,$0c000006
+	dc.l	$660661ff,$000021ac,$1d40ff4f,$4280102e
+	dc.l	$ff63e9ee,$1047ff43,$41eeff6c,$43eeff78
+	dc.l	$223b1d30,$0000110c,$4ebb1930,$00001104
+	dc.l	$102eff62,$6600008a,$102eff43,$02000038
+	dc.l	$0c000038,$670ce9ee,$0183ff42,$61ff0000
+	dc.l	$545a082e,$00050004,$6600002a,$206effd8
+	dc.l	$4e60f22e,$d0c0ffdc,$f22e9c00,$ff604cee
+	dc.l	$0303ff9c,$4e5e0817,$00076600,$012660ff
+	dc.l	$fffff440,$082e0002,$ff4a67d6,$f22ed0c0
+	dc.l	$ffdcf22e,$9c00ff60,$4cee0303,$ff9c4e5e
+	dc.l	$2f6f0004,$00102f6f,$0000000c,$dffc0000
+	dc.l	$000c0817,$00076600,$00ea60ff,$fffff404
+	dc.l	$c02eff66,$edc00608,$6618082e,$0004ff66
+	dc.l	$6700ff66,$082e0001,$ff626700,$ff5c6000
+	dc.l	$006e0480,$00000018,$0c000006,$6d14082e
+	dc.l	$0003ff66,$66000060,$082e0004,$ff666600
+	dc.l	$004e082e,$00050004,$66000054,$206effd8
+	dc.l	$4e603d7b,$022aff6e,$f22ed0c0,$ffdcf22e
+	dc.l	$9c00ff60,$4cee0303,$ff9cf36e,$ff6c4e5e
+	dc.l	$08170007,$6600006c,$60ffffff,$f386e000
+	dc.l	$e006e004,$e005e003,$e002e001,$e001303c
+	dc.l	$00036000,$ffae303c,$00046000,$ffa6082e
+	dc.l	$0002ff4a,$67ac3d7b,$02d6ff6e,$f22ed0c0
+	dc.l	$ffdcf22e,$9c00ff60,$4cee0303,$ff9cf36e
+	dc.l	$ff6c4e5e,$2f6f0004,$00102f6f,$0000000c
+	dc.l	$dffc0000,$000c0817,$00076606,$60ffffff
+	dc.l	$f3223f7c,$20240006,$f22fa400,$000860ff
+	dc.l	$fffff402,$02aeffff,$00ffff64,$f23c9000
+	dc.l	$00000000,$f23c8800,$00000000,$e9ee0183
+	dc.l	$ff4261ff,$000051b4,$41eeff6c,$61ff0000
+	dc.l	$20620c00,$00066606,$61ff0000,$1fc61d40
+	dc.l	$ff4e4280,$102eff63,$41eeff6c,$2d56ffd4
+	dc.l	$61ff0000,$248c102e,$ff626600,$00842cae
+	dc.l	$ffd4082e,$00050004,$6628206e,$ffd84e60
+	dc.l	$f22ed0c0,$ffdcf22e,$9c00ff60,$4cee0303
+	dc.l	$ff9c4e5e,$08170007,$6600ff68,$60ffffff
+	dc.l	$f282082e,$0003ff4a,$67d6f22e,$d0c0ffdc
+	dc.l	$f22e9c00,$ff604cee,$0303ff9c,$2c562f6f
+	dc.l	$00c400b8,$2f6f00c8,$00bc2f6f,$003800c4
+	dc.l	$2f6f003c,$00c82f6f,$004000cc,$dffc0000
+	dc.l	$00b80817,$00076600,$ff1a60ff,$fffff234
+	dc.l	$c02eff66,$edc00608,$6700ff74,$2caeffd4
+	dc.l	$0c00001a,$6e0000e8,$67000072,$082e0005
+	dc.l	$0004660a,$206effd8,$4e606000,$fb8e0c2e
+	dc.l	$0008ff4a,$6600fb84,$f22ed0c0,$ffdcf22e
+	dc.l	$9c00ff60,$4cee0303,$ff9c3d7c,$30d8000a
+	dc.l	$3d7ce006,$ff6ef36e,$ff6c2c56,$2f6f00c4
+	dc.l	$00b82f6f,$00c800bc,$2f6f00cc,$00c02f6f
+	dc.l	$003800c4,$2f6f003c,$00c82f6f,$004000cc
+	dc.l	$dffc0000,$00b860ff,$fffff22c,$082e0005
+	dc.l	$00046600,$000c206e,$ffd84e60,$6000fb46
+	dc.l	$0c2e0008,$ff4a6600,$fb3cf22e,$d0c0ffdc
+	dc.l	$f22e9c00,$ff604cee,$0303ff9c,$3d7c30d0
+	dc.l	$000a3d7c,$e004ff6e,$f36eff6c,$2c562f6f
+	dc.l	$00c400b8,$2f6f00c8,$00bc2f6f,$00cc00c0
+	dc.l	$2f6f0038,$00c42f6f,$003c00c8,$2f6f0040
+	dc.l	$00ccdffc,$000000b8,$60ffffff,$f1a4082e
+	dc.l	$00050004,$6600000c,$206effd8,$4e606000
+	dc.l	$fbda0c2e,$0008ff4a,$6600fbd0,$f22ed0c0
+	dc.l	$ffdcf22e,$9c00ff60,$4cee0303,$ff9c3d7c
+	dc.l	$30c4000a,$3d7ce001,$ff6ef36e,$ff6c2c56
+	dc.l	$2f6f00c4,$00b82f6f,$00c800bc,$2f6f00cc
+	dc.l	$00c02f6f,$003800c4,$2f6f003c,$00c82f6f
+	dc.l	$004000cc,$dffc0000,$00b860ff,$fffff106
+	dc.l	$e9ee00c3,$ff420c00,$00016708,$0c000005
+	dc.l	$67344e75,$302eff6c,$02407fff,$67260c40
+	dc.l	$3f806e20,$44400640,$3f81222e,$ff70e0a9
+	dc.l	$08c1001f,$2d41ff70,$026e8000,$ff6c006e
+	dc.l	$3f80ff6c,$4e75302e,$ff6c0240,$7fff673a
+	dc.l	$0c403c00,$6e344a2e,$ff6c5bee,$ff6e3d40
+	dc.l	$ff6c4280,$41eeff6c,$323c3c01,$61ff0000
+	dc.l	$1a66303c,$3c004a2e,$ff6e6704,$08c0000f
+	dc.l	$08ee0007,$ff703d40,$ff6c4e75,$082e0005
+	dc.l	$000467ff,$fffff176,$2d680000,$ff782d68
+	dc.l	$0004ff7c,$2d680008,$ff804281,$4e752f00
+	dc.l	$4e7a0808,$08000001,$66000460,$201f4e56
+	dc.l	$ff4048ee,$0303ff9c,$f22ebc00,$ff60f22e
+	dc.l	$f0c0ffdc,$2d6e0006,$ff44206e,$ff4458ae
+	dc.l	$ff4461ff,$fffff152,$2d40ff40,$4a406b00
+	dc.l	$020e02ae,$00ff00ff,$ff640800,$000a6618
+	dc.l	$206eff44,$43eeff6c,$700c61ff,$fffff0d2
+	dc.l	$4a816600,$04926048,$206eff44,$43eeff6c
+	dc.l	$700c61ff,$fffff0ba,$4a816600,$047ae9ee
+	dc.l	$004fff6c,$0c407fff,$6726102e,$ff6f0200
+	dc.l	$000f660c,$4aaeff70,$66064aae,$ff746710
+	dc.l	$41eeff6c,$61ff0000,$501af22e,$f080ff6c
+	dc.l	$06ae0000,$000cff44,$41eeff6c,$61ff0000
+	dc.l	$1cd21d40,$ff4e0c00,$0006660a,$61ff0000
+	dc.l	$1c321d40,$ff4e422e,$ff53082e,$0005ff43
+	dc.l	$6748082e,$0004ff43,$662ce9ee,$0183ff42
+	dc.l	$61ff0000,$4e7641ee,$ff7861ff,$00001c94
+	dc.l	$1d40ff4f,$0c000006,$662061ff,$00001bf4
+	dc.l	$1d40ff4f,$6014082e,$0003ff43,$670c50ee
+	dc.l	$ff53082e,$0001ff43,$67c04280,$102eff63
+	dc.l	$122eff43,$0241007f,$f23c9000,$00000000
+	dc.l	$f23c8800,$00000000,$41eeff6c,$43eeff78
+	dc.l	$223b1530,$00000b2c,$4ebb1930,$00000b24
+	dc.l	$102eff62,$66404a2e,$ff53660c,$e9ee0183
+	dc.l	$ff4261ff,$00004e84,$2d6e0006,$ff682d6e
+	dc.l	$ff440006,$f22ed0c0,$ffdcf22e,$9c00ff60
+	dc.l	$4cee0303,$ff9c4e5e,$08170007,$66000096
+	dc.l	$60ffffff,$ee6ec02e,$ff66edc0,$06086612
+	dc.l	$082e0004,$ff6667ae,$082e0001,$ff6267ac
+	dc.l	$60340480,$00000018,$0c000006,$6610082e
+	dc.l	$0004ff66,$6620082e,$0003ff66,$66203d7b
+	dc.l	$0206ff6e,$601ee002,$e006e004,$e005e003
+	dc.l	$e002e001,$e0013d7c,$e005ff6e,$60063d7c
+	dc.l	$e003ff6e,$2d6e0006,$ff682d6e,$ff440006
+	dc.l	$f22ed0c0,$ffdcf22e,$9c00ff60,$4cee0303
+	dc.l	$ff9cf36e,$ff6c4e5e,$08170007,$660660ff
+	dc.l	$ffffede0,$2f173f6f,$00080004,$3f7c2024
+	dc.l	$0006f22f,$a4000008,$60ffffff,$eeb80800
+	dc.l	$000e6700,$01c2082e,$00050004,$66164e68
+	dc.l	$2d48ffd8,$61ff0000,$0bce206e,$ffd84e60
+	dc.l	$600001aa,$422eff4a,$41ee000c,$2d48ffd8
+	dc.l	$61ff0000,$0bb20c2e,$0008ff4a,$67000086
+	dc.l	$0c2e0004,$ff4a6600,$0184082e,$00070004
+	dc.l	$66363dae,$00040804,$2daeff44,$08063dbc
+	dc.l	$00f0080a,$41f60804,$2d480004,$f22ed0c0
+	dc.l	$ffdcf22e,$9c00ff60,$4cee0303,$ff9c4e5e
+	dc.l	$2e5f60ff,$ffffed3c,$3dae0004,$08002dae
+	dc.l	$ff440802,$3dbc2024,$08062dae,$00060808
+	dc.l	$41f60800,$2d480004,$f22ed0c0,$ffdcf22e
+	dc.l	$9c00ff60,$4cee0303,$ff9c4e5e,$2e5f60ff
+	dc.l	$ffffedf2,$1d41000a,$1d40000b,$f22ed0c0
+	dc.l	$ffdcf22e,$9c00ff60,$4cee0303,$ff9c2f16
+	dc.l	$2f002f01,$2f2eff44,$4280102e,$000b4480
+	dc.l	$082e0007,$0004671c,$3dae0004,$08002dae
+	dc.l	$00060808,$2d9f0802,$3dbc2024,$08064876
+	dc.l	$08006014,$3dae0004,$08042d9f,$08063dbc
+	dc.l	$00f0080a,$48760804,$4281122e,$000a4a01
+	dc.l	$6a0cf236,$f080080c,$06800000,$000ce309
+	dc.l	$6a0cf236,$f040080c,$06800000,$000ce309
+	dc.l	$6a0cf236,$f020080c,$06800000,$000ce309
+	dc.l	$6a0cf236,$f010080c,$06800000,$000ce309
+	dc.l	$6a0cf236,$f008080c,$06800000,$000ce309
+	dc.l	$6a0cf236,$f004080c,$06800000,$000ce309
+	dc.l	$6a0cf236,$f002080c,$06800000,$000ce309
+	dc.l	$6a06f236,$f001080c,$222f0004,$202f0008
+	dc.l	$2c6f000c,$2e5f0817,$000767ff,$ffffec04
+	dc.l	$60ffffff,$ecf061ff,$00001244,$f22ed0c0
+	dc.l	$ffdcf22e,$9c00ff60,$4cee0303,$ff9c082e
+	dc.l	$00070004,$660e2d6e,$ff440006,$4e5e60ff
+	dc.l	$ffffebd0,$2c563f6f,$00c400c0,$2f6f00c6
+	dc.l	$00c82f6f,$000400c2,$3f7c2024,$00c6dffc
+	dc.l	$000000c0,$60ffffff,$ec9c201f,$4e56ff40
+	dc.l	$48ee0303,$ff9c2d6e,$0006ff44,$206eff44
+	dc.l	$58aeff44,$61ffffff,$ed002d40,$ff404a40
+	dc.l	$6b047010,$60260800,$000e6610,$e9c014c3
+	dc.l	$700c0c01,$00076614,$58806010,$428061ff
+	dc.l	$00000ce6,$202eff44,$90ae0006,$3d40000a
+	dc.l	$4cee0303,$ff9c4e5e,$518f2f00,$3f6f000c
+	dc.l	$00042f6f,$000e0006,$4280302f,$00122f6f
+	dc.l	$00060010,$d1af0006,$3f7c402c,$000a201f
+	dc.l	$60ffffff,$ebe44e7a,$08080800,$0001660c
+	dc.l	$f22e9c00,$ff60f22e,$d0c0ffdc,$4cee0303
+	dc.l	$ff9c4e5e,$514f2eaf,$00083f6f,$000c0004
+	dc.l	$3f7c4008,$00062f6f,$00020008,$2f7c0942
+	dc.l	$8001000c,$08170005,$670608ef,$0002000d
+	dc.l	$60ffffff,$ebd64fee,$ff404e7a,$18080801
+	dc.l	$0001660c,$f22ed0c0,$ffdcf22f,$9c000020
+	dc.l	$2c562f6f,$00c400bc,$3f6f00c8,$00c03f7c
+	dc.l	$400800c2,$2f4800c4,$3f4000c8,$3f7c0001
+	dc.l	$00ca4cef,$0303005c,$defc00bc,$60a64e56
+	dc.l	$ff40f32e,$ff6c48ee,$0303ff9c,$f22ebc00
+	dc.l	$ff60f22e,$f0c0ffdc,$2d6eff68,$ff44206e
+	dc.l	$ff4458ae,$ff4461ff,$ffffebce,$2d40ff40
+	dc.l	$0800000d,$662841ee,$ff6c61ff,$fffff1ea
+	dc.l	$f22ed0c0,$ffdcf22e,$9c00ff60,$4cee0303
+	dc.l	$ff9cf36e,$ff6c4e5e,$60ffffff,$ea94322e
+	dc.l	$ff6c0241,$7fff0c41,$7fff661a,$4aaeff74
+	dc.l	$660c222e,$ff700281,$7fffffff,$67082d6e
+	dc.l	$ff70ff54,$6012223c,$7fffffff,$4a2eff6c
+	dc.l	$6a025281,$2d41ff54,$e9c004c3,$122eff41
+	dc.l	$307b0206,$4efb8802,$006c0000,$0000ff98
+	dc.l	$003e0000,$00100000,$102eff54,$0c010007
+	dc.l	$6f16206e,$000c61ff,$ffffeb86,$4a8166ff
+	dc.l	$00005436,$6000ff6a,$02410007,$61ff0000
+	dc.l	$478e6000,$ff5c302e,$ff540c01,$00076f16
+	dc.l	$206e000c,$61ffffff,$eb6e4a81,$66ff0000
+	dc.l	$54166000,$ff3c0241,$000761ff,$00004724
+	dc.l	$6000ff2e,$202eff54,$0c010007,$6f16206e
+	dc.l	$000c61ff,$ffffeb56,$4a8166ff,$000053f6
+	dc.l	$6000ff0e,$02410007,$61ff0000,$46ba6000
+	dc.l	$ff004e56,$ff40f32e,$ff6c48ee,$0303ff9c
+	dc.l	$f22ebc00,$ff60f22e,$f0c0ffdc,$2d6eff68
+	dc.l	$ff44206e,$ff4458ae,$ff4461ff,$ffffea8a
+	dc.l	$2d40ff40,$0800000d,$6600002a,$41eeff6c
+	dc.l	$61ffffff,$f0a4f22e,$d0c0ffdc,$f22e9c00
+	dc.l	$ff604cee,$0303ff9c,$f36eff6c,$4e5e60ff
+	dc.l	$ffffe964,$e9c004c3,$122eff41,$307b0206
+	dc.l	$4efb8802,$007400a6,$015a0000,$00420104
+	dc.l	$00100000,$102eff70,$08c00006,$0c010007
+	dc.l	$6f16206e,$000c61ff,$ffffea76,$4a8166ff
+	dc.l	$00005326,$6000ffa0,$02410007,$61ff0000
+	dc.l	$467e6000,$ff92302e,$ff7008c0,$000e0c01
+	dc.l	$00076f16,$206e000c,$61ffffff,$ea5a4a81
+	dc.l	$66ff0000,$53026000,$ff6e0241,$000761ff
+	dc.l	$00004610,$6000ff60,$202eff70,$08c0001e
+	dc.l	$0c010007,$6f16206e,$000c61ff,$ffffea3e
+	dc.l	$4a8166ff,$000052de,$6000ff3c,$02410007
+	dc.l	$61ff0000,$45a26000,$ff2e0c01,$00076f2e
+	dc.l	$202eff6c,$02808000,$00000080,$7fc00000
+	dc.l	$222eff70,$e0898081,$206e000c,$61ffffff
+	dc.l	$e9fc4a81,$66ff0000,$529c6000,$fefa202e
+	dc.l	$ff6c0280,$80000000,$00807fc0,$00002f01
+	dc.l	$222eff70,$e0898081,$221f0241,$000761ff
+	dc.l	$00004544,$6000fed0,$202eff6c,$02808000
+	dc.l	$00000080,$7ff80000,$222eff70,$2d40ff84
+	dc.l	$700be0a9,$83aeff84,$222eff70,$02810000
+	dc.l	$07ffe0b9,$2d41ff88,$222eff74,$e0a983ae
+	dc.l	$ff8841ee,$ff84226e,$000c7008,$61ffffff
+	dc.l	$e8cc4a81,$66ff0000,$522a6000,$fe7a422e
+	dc.l	$ff4a3d6e,$ff6cff84,$426eff86,$202eff70
+	dc.l	$08c0001e,$2d40ff88,$2d6eff74,$ff8c082e
+	dc.l	$00050004,$66384e68,$2d48ffd8,$2d56ffd4
+	dc.l	$61ff0000,$02c22248,$2d48000c,$206effd8
+	dc.l	$4e602cae,$ffd441ee,$ff84700c,$61ffffff
+	dc.l	$e86c4a81,$66ff0000,$51d86000,$fe1a2d56
+	dc.l	$ffd461ff,$00000290,$22482d48,$000c2cae
+	dc.l	$ffd40c2e,$0008ff4a,$66ccf22e,$d0c0ffdc
+	dc.l	$f22e9c00,$ff604cee,$0303ff9c,$f36eff6c
+	dc.l	$2c6effd4,$2f6f00c4,$00b82f6f,$00c800bc
+	dc.l	$2f6f00cc,$00c02f6f,$004400c4,$2f6f0048
+	dc.l	$00c82f6f,$004c00cc,$dffc0000,$00b860ff
+	dc.l	$ffffe734,$4e56ff40,$f32eff6c,$48ee0303
+	dc.l	$ff9cf22e,$bc00ff60,$f22ef0c0,$ffdc2d6e
+	dc.l	$ff68ff44,$206eff44,$58aeff44,$61ffffff
+	dc.l	$e7f82d40,$ff400800,$000d6600,$0106e9c0
+	dc.l	$04c36622,$0c6e401e,$ff6c661a,$f23c9000
+	dc.l	$00000000,$f22e4000,$ff70f22e,$6800ff6c
+	dc.l	$3d7ce001,$ff6e41ee,$ff6c61ff,$ffffedea
+	dc.l	$02ae00ff,$01ffff64,$f23c9000,$00000000
+	dc.l	$f23c8800,$00000000,$e9ee1006,$ff420c01
+	dc.l	$00176700,$009641ee,$ff6c61ff,$00001394
+	dc.l	$1d40ff4e,$082e0005,$ff43672e,$082e0004
+	dc.l	$ff436626,$e9ee0183,$ff4261ff,$0000454c
+	dc.l	$41eeff78,$61ff0000,$136a0c00,$00066606
+	dc.l	$61ff0000,$12ce1d40,$ff4f4280,$102eff63
+	dc.l	$122eff43,$0241007f,$41eeff6c,$43eeff78
+	dc.l	$223b1530,$0000022c,$4ebb1930,$00000224
+	dc.l	$e9ee0183,$ff4261ff,$00004590,$f22ed0c0
+	dc.l	$ffdcf22e,$9c00ff60,$4cee0303,$ff9cf36e
+	dc.l	$ff6c4e5e,$60ffffff,$e5cc4280,$102eff63
+	dc.l	$122eff43,$02810000,$007f61ff,$00000396
+	dc.l	$60be1d7c,$0000ff4e,$4280102e,$ff6302ae
+	dc.l	$ffff00ff,$ff6441ee,$ff6c61ff,$00001722
+	dc.l	$60aa4e56,$ff40f32e,$ff6c48ee,$0303ff9c
+	dc.l	$f22ebc00,$ff60f22e,$f0c0ffdc,$2d6eff68
+	dc.l	$ff44206e,$ff4458ae,$ff4461ff,$ffffe69a
+	dc.l	$2d40ff40,$41eeff6c,$61ffffff,$ecbcf22e
+	dc.l	$d0c0ffdc,$f22e9c00,$ff604cee,$0303ff9c
+	dc.l	$f36eff6c,$4e5e60ff,$ffffe592,$0c6f402c
+	dc.l	$000667ff,$ffffe5b2,$60ffffff,$e5962040
+	dc.l	$102eff41,$22000240,$00380281,$00000007
+	dc.l	$0c000018,$67240c00,$0020672c,$80410c00
+	dc.l	$003c6706,$206e000c,$4e751d7c,$0080ff4a
+	dc.l	$41f60162,$ff680004,$4e752008,$61ff0000
+	dc.l	$42ca206e,$000c4e75,$200861ff,$0000430c
+	dc.l	$206e000c,$0c00000c,$67024e75,$51882d48
+	dc.l	$000c4e75,$102eff41,$22000240,$00380281
+	dc.l	$00000007,$0c000018,$670e0c00,$00206700
+	dc.l	$0076206e,$000c4e75,$323b120e,$206e000c
+	dc.l	$4efb1006,$4afc0008,$0010001a,$0024002c
+	dc.l	$0034003c,$0044004e,$06ae0000,$000cffa4
+	dc.l	$4e7506ae,$0000000c,$ffa84e75,$d5fc0000
+	dc.l	$000c4e75,$d7fc0000,$000c4e75,$d9fc0000
+	dc.l	$000c4e75,$dbfc0000,$000c4e75,$06ae0000
+	dc.l	$000cffd4,$4e751d7c,$0004ff4a,$06ae0000
+	dc.l	$000cffd8,$4e75323b,$1214206e,$000c5188
+	dc.l	$51ae000c,$4efb1006,$4afc0008,$00100016
+	dc.l	$001c0020,$00240028,$002c0032,$2d48ffa4
+	dc.l	$4e752d48,$ffa84e75,$24484e75,$26484e75
+	dc.l	$28484e75,$2a484e75,$2d48ffd4,$4e752d48
+	dc.l	$ffd81d7c,$0008ff4a,$4e754afc,$006d0000
+	dc.l	$20700000,$2a660000,$00000000,$2b0a0000
+	dc.l	$3db20000,$00000000,$00000000,$00000000
+	dc.l	$00000000,$00000000,$00000000,$00000000
+	dc.l	$00000000,$00000000,$00000000,$00000000
+	dc.l	$00000000,$00000000,$00000000,$00000000
+	dc.l	$00000000,$00000000,$00000000,$00000000
+	dc.l	$2bb00000,$00000000,$27460000,$00000000
+	dc.l	$00000000,$00000000,$00000000,$00000000
+	dc.l	$233c0000,$00000000,$36220000,$1c7c0000
+	dc.l	$32f20000,$00000000,$00000000,$2fb00000
+	dc.l	$39ea0000,$00000000,$00000000,$00000000
+	dc.l	$00000000,$00000000,$00000000,$00000000
+	dc.l	$00000000,$00000000,$00000000,$00000000
+	dc.l	$00000000,$00000000,$00000000,$00000000
+	dc.l	$2e4e0000,$00000000,$29f40000,$00000000
+	dc.l	$00000000,$00000000,$00000000,$00000000
+	dc.l	$205e0000,$3da00000,$00000000,$00000000
+	dc.l	$20680000,$3daa0000,$00000000,$00000000
+	dc.l	$00000000,$00000000,$00000000,$00000000
+	dc.l	$00000000,$00000000,$00000000,$00000000
+	dc.l	$00000000,$00000000,$00000000,$00000000
+	dc.l	$00000000,$00000000,$00000000,$00000000
+	dc.l	$2b9e0000,$00000000,$27340000,$00000000
+	dc.l	$2ba80000,$00000000,$273e0000,$00000000
+	dc.l	$232a0000,$00000000,$36100000,$1c6a0000
+	dc.l	$23340000,$00000000,$361a0000,$1c740000
+	dc.l	$39d80000,$00000000,$00000000,$00000000
+	dc.l	$39e260fe,$122eff43,$02410070,$e80961ff
+	dc.l	$00003ed2,$02800000,$00ff2f00,$103b0920
+	dc.l	$01482f00,$61ff0000,$0340201f,$221f6700
+	dc.l	$0134082e,$0005ff42,$670000b8,$082e0004
+	dc.l	$ff426600,$001a123b,$1120021e,$082e0005
+	dc.l	$0004670a,$0c2e0008,$ff4a6602,$4e752248
+	dc.l	$9fc041d7,$4a016a0c,$20eeffdc,$20eeffe0
+	dc.l	$20eeffe4,$e3096a0c,$20eeffe8,$20eeffec
+	dc.l	$20eefff0,$e3096a0a,$f210f020,$d1fc0000
+	dc.l	$000ce309,$6a0af210,$f010d1fc,$0000000c
+	dc.l	$e3096a0a,$f210f008,$d1fc0000,$000ce309
+	dc.l	$6a0af210,$f004d1fc,$0000000c,$e3096a0a
+	dc.l	$f210f002,$d1fc0000,$000ce309,$6a0af210
+	dc.l	$f001d1fc,$0000000c,$2d49ff54,$41d72f00
+	dc.l	$61ffffff,$e248201f,$dfc04a81,$6600071e
+	dc.l	$4e752d48,$ff549fc0,$43d72f01,$2f0061ff
+	dc.l	$ffffe214,$201f4a81,$6600070e,$221f41d7
+	dc.l	$4a016a0c,$2d58ffdc,$2d58ffe0,$2d58ffe4
+	dc.l	$e3096a0c,$2d58ffe8,$2d58ffec,$2d58fff0
+	dc.l	$e3096a04,$f218d020,$e3096a04,$f218d010
+	dc.l	$e3096a04,$f218d008,$e3096a04,$f218d004
+	dc.l	$e3096a04,$f218d002,$e3096a04,$f218d001
+	dc.l	$dfc04e75,$4e75000c,$0c180c18,$18240c18
+	dc.l	$18241824,$24300c18,$18241824,$24301824
+	dc.l	$24302430,$303c0c18,$18241824,$24301824
+	dc.l	$24302430,$303c1824,$24302430,$303c2430
+	dc.l	$303c303c,$3c480c18,$18241824,$24301824
+	dc.l	$24302430,$303c1824,$24302430,$303c2430
+	dc.l	$303c303c,$3c481824,$24302430,$303c2430
+	dc.l	$303c303c,$3c482430,$303c303c,$3c48303c
+	dc.l	$3c483c48,$48540c18,$18241824,$24301824
+	dc.l	$24302430,$303c1824,$24302430,$303c2430
+	dc.l	$303c303c,$3c481824,$24302430,$303c2430
+	dc.l	$303c303c,$3c482430,$303c303c,$3c48303c
+	dc.l	$3c483c48,$48541824,$24302430,$303c2430
+	dc.l	$303c303c,$3c482430,$303c303c,$3c48303c
+	dc.l	$3c483c48,$48542430,$303c303c,$3c48303c
+	dc.l	$3c483c48,$4854303c,$3c483c48,$48543c48
+	dc.l	$48544854,$54600080,$40c020a0,$60e01090
+	dc.l	$50d030b0,$70f00888,$48c828a8,$68e81898
+	dc.l	$58d838b8,$78f80484,$44c424a4,$64e41494
+	dc.l	$54d434b4,$74f40c8c,$4ccc2cac,$6cec1c9c
+	dc.l	$5cdc3cbc,$7cfc0282,$42c222a2,$62e21292
+	dc.l	$52d232b2,$72f20a8a,$4aca2aaa,$6aea1a9a
+	dc.l	$5ada3aba,$7afa0686,$46c626a6,$66e61696
+	dc.l	$56d636b6,$76f60e8e,$4ece2eae,$6eee1e9e
+	dc.l	$5ede3ebe,$7efe0181,$41c121a1,$61e11191
+	dc.l	$51d131b1,$71f10989,$49c929a9,$69e91999
+	dc.l	$59d939b9,$79f90585,$45c525a5,$65e51595
+	dc.l	$55d535b5,$75f50d8d,$4dcd2dad,$6ded1d9d
+	dc.l	$5ddd3dbd,$7dfd0383,$43c323a3,$63e31393
+	dc.l	$53d333b3,$73f30b8b,$4bcb2bab,$6beb1b9b
+	dc.l	$5bdb3bbb,$7bfb0787,$47c727a7,$67e71797
+	dc.l	$57d737b7,$77f70f8f,$4fcf2faf,$6fef1f9f
+	dc.l	$5fdf3fbf,$7fff2040,$302eff40,$32000240
+	dc.l	$003f0281,$00000007,$303b020a,$4efb0006
+	dc.l	$4afc0040,$00000000,$00000000,$00000000
+	dc.l	$00000000,$00000000,$00000000,$00000000
+	dc.l	$00000000,$00800086,$008c0090,$00940098
+	dc.l	$009c00a0,$00a600b6,$00c600d2,$00de00ea
+	dc.l	$00f60102,$01180126,$0134013e,$01480152
+	dc.l	$015c0166,$017a0198,$01b601d2,$01ee020a
+	dc.l	$02260242,$02600260,$02600260,$02600260
+	dc.l	$02600260,$02c002da,$02f40314,$00000000
+	dc.l	$00000000,$206effa4,$4e75206e,$ffa84e75
+	dc.l	$204a4e75,$204b4e75,$204c4e75,$204d4e75
+	dc.l	$20564e75,$206effd8,$4e75202e,$ffa42200
+	dc.l	$d2882d41,$ffa42040,$4e75202e,$ffa82200
+	dc.l	$d2882d41,$ffa82040,$4e75200a,$2200d288
+	dc.l	$24412040,$4e75200b,$2200d288,$26412040
+	dc.l	$4e75200c,$2200d288,$28412040,$4e75200d
+	dc.l	$2200d288,$2a412040,$4e752016,$2200d288
+	dc.l	$2c812040,$4e751d7c,$0004ff4a,$202effd8
+	dc.l	$2200d288,$2d41ffd8,$20404e75,$202effa4
+	dc.l	$90882d40,$ffa42040,$4e75202e,$ffa89088
+	dc.l	$2d40ffa8,$20404e75,$200a9088,$24402040
+	dc.l	$4e75200b,$90882640,$20404e75,$200c9088
+	dc.l	$28402040,$4e75200d,$90882a40,$20404e75
+	dc.l	$20169088,$2c802040,$4e751d7c,$0008ff4a
+	dc.l	$202effd8,$90882d40,$ffd82040,$4e75206e
+	dc.l	$ff4454ae,$ff4461ff,$ffffde38,$4a8166ff
+	dc.l	$fffff1b6,$3040d1ee,$ffa44e75,$206eff44
+	dc.l	$54aeff44,$61ffffff,$de1a4a81,$66ffffff
+	dc.l	$f1983040,$d1eeffa8,$4e75206e,$ff4454ae
+	dc.l	$ff4461ff,$ffffddfc,$4a8166ff,$fffff17a
+	dc.l	$3040d1ca,$4e75206e,$ff4454ae,$ff4461ff
+	dc.l	$ffffdde0,$4a8166ff,$fffff15e,$3040d1cb
+	dc.l	$4e75206e,$ff4454ae,$ff4461ff,$ffffddc4
+	dc.l	$4a8166ff,$fffff142,$3040d1cc,$4e75206e
+	dc.l	$ff4454ae,$ff4461ff,$ffffdda8,$4a8166ff
+	dc.l	$fffff126,$3040d1cd,$4e75206e,$ff4454ae
+	dc.l	$ff4461ff,$ffffdd8c,$4a8166ff,$fffff10a
+	dc.l	$3040d1d6,$4e75206e,$ff4454ae,$ff4461ff
+	dc.l	$ffffdd70,$4a8166ff,$fffff0ee,$3040d1ee
+	dc.l	$ffd84e75,$508161ff,$000038fa,$2f00206e
+	dc.l	$ff4454ae,$ff4461ff,$ffffdd48,$4a8166ff
+	dc.l	$fffff0c6,$205f0800,$00086600,$00e62d40
+	dc.l	$ff542200,$e9590241,$000f61ff,$000038c6
+	dc.l	$2f02242e,$ff540802,$000b6602,$48c02202
+	dc.l	$ef590281,$00000003,$e3a849c2,$d082d1c0
+	dc.l	$241f4e75,$206eff44,$54aeff44,$61ffffff
+	dc.l	$dcf24a81,$66ffffff,$f0703040,$4e75206e
+	dc.l	$ff4458ae,$ff4461ff,$ffffdcee,$4a8166ff
+	dc.l	$fffff056,$20404e75,$206eff44,$54aeff44
+	dc.l	$61ffffff,$dcbe4a81,$66ffffff,$f03c3040
+	dc.l	$d1eeff44,$55884e75,$206eff44,$54aeff44
+	dc.l	$61ffffff,$dc9e4a81,$66ffffff,$f01c206e
+	dc.l	$ff445588,$08000008,$66000038,$2d40ff54
+	dc.l	$2200e959,$0241000f,$61ff0000,$38182f02
+	dc.l	$242eff54,$0802000b,$660248c0,$2202ef59
+	dc.l	$02810000,$0003e3a8,$49c2d082,$d1c0241f
+	dc.l	$4e750800,$0006670c,$48e73c00,$2a002608
+	dc.l	$42826028,$2d40ff54,$e9c01404,$61ff0000
+	dc.l	$37d448e7,$3c002400,$2a2eff54,$26080805
+	dc.l	$000b6602,$48c2e9c5,$0542e1aa,$08050007
+	dc.l	$67024283,$e9c50682,$0c000002,$6d346718
+	dc.l	$206eff44,$58aeff44,$61ffffff,$dc0c4a81
+	dc.l	$66ff0000,$00b06018,$206eff44,$54aeff44
+	dc.l	$61ffffff,$dbde4a81,$66ff0000,$009848c0
+	dc.l	$d680e9c5,$07826700,$006e0c00,$00026d34
+	dc.l	$6718206e,$ff4458ae,$ff4461ff,$ffffdbca
+	dc.l	$4a8166ff,$0000006e,$601c206e,$ff4454ae
+	dc.l	$ff4461ff,$ffffdb9c,$4a8166ff,$00000056
+	dc.l	$48c06002,$42802800,$08050002,$67142043
+	dc.l	$61ffffff,$dbd64a81,$66000028,$d082d084
+	dc.l	$6018d682,$204361ff,$ffffdbc0,$4a816600
+	dc.l	$0012d084,$6004d682,$20032040,$4cdf003c
+	dc.l	$4e752043,$4cdf003c,$303c0101,$60ffffff
+	dc.l	$ef184cdf,$003c60ff,$ffffeebe,$61ff0000
+	dc.l	$44ea303c,$00e1600a,$61ff0000,$44de303c
+	dc.l	$0161206e,$ff5460ff,$ffffeeee,$102eff42
+	dc.l	$0c00009c,$670000b2,$0c000098,$67000074
+	dc.l	$0c000094,$6736206e,$ff4458ae,$ff4461ff
+	dc.l	$ffffdb06,$4a8166ff,$ffffee6e,$2d40ff64
+	dc.l	$206eff44,$58aeff44,$61ffffff,$daec4a81
+	dc.l	$66ffffff,$ee542d40,$ff684e75,$206eff44
+	dc.l	$58aeff44,$61ffffff,$dad04a81,$66ffffff
+	dc.l	$ee382d40,$ff60206e,$ff4458ae,$ff4461ff
+	dc.l	$ffffdab6,$4a8166ff,$ffffee1e,$2d40ff68
+	dc.l	$4e75206e,$ff4458ae,$ff4461ff,$ffffda9a
+	dc.l	$4a8166ff,$ffffee02,$2d40ff60,$206eff44
+	dc.l	$58aeff44,$61ffffff,$da804a81,$66ffffff
+	dc.l	$ede82d40,$ff644e75,$206eff44,$58aeff44
+	dc.l	$61ffffff,$da644a81,$66ffffff,$edcc2d40
+	dc.l	$ff60206e,$ff4458ae,$ff4461ff,$ffffda4a
+	dc.l	$4a8166ff,$ffffedb2,$2d40ff64,$206eff44
+	dc.l	$58aeff44,$61ffffff,$da304a81,$66ffffff
+	dc.l	$ed982d40,$ff684e75,$2d680004,$ff882d69
+	dc.l	$0004ff94,$2d680008,$ff8c2d69,$0008ff98
+	dc.l	$30280000,$32290000,$3d40ff84,$3d41ff90
+	dc.l	$02407fff,$02417fff,$3d40ff54,$3d41ff56
+	dc.l	$b0416cff,$0000005c,$61ff0000,$015a2f00
+	dc.l	$0c2e0004,$ff4e6610,$41eeff84,$61ff0000
+	dc.l	$04fa4440,$3d40ff54,$302eff56,$04400042
+	dc.l	$b06eff54,$6c1a302e,$ff54d06f,$0002322e
+	dc.l	$ff840241,$80008041,$3d40ff84,$201f4e75
+	dc.l	$026e8000,$ff8408ee,$0000ff85,$201f4e75
+	dc.l	$61ff0000,$00562f00,$0c2e0004,$ff4f6610
+	dc.l	$41eeff90,$61ff0000,$04a24440,$3d40ff56
+	dc.l	$302eff54,$04400042,$b06eff56,$6c1a302e
+	dc.l	$ff56d06f,$0002322e,$ff900241,$80008041
+	dc.l	$3d40ff90,$201f4e75,$026e8000,$ff9008ee
+	dc.l	$0000ff91,$201f4e75,$322eff84,$30010281
+	dc.l	$00007fff,$02408000,$00403fff,$3d40ff84
+	dc.l	$0c2e0004,$ff4e670a,$203c0000,$3fff9081
+	dc.l	$4e7541ee,$ff8461ff,$00000430,$44802200
+	dc.l	$60e60c2e,$0004ff4e,$673a322e,$ff840281
+	dc.l	$00007fff,$026e8000,$ff840801,$00006712
+	dc.l	$006e3fff,$ff84203c,$00003fff,$9081e280
+	dc.l	$4e75006e,$3ffeff84,$203c0000,$3ffe9081
+	dc.l	$e2804e75,$41eeff84,$61ff0000,$03de0800
+	dc.l	$00006710,$006e3fff,$ff840680,$00003fff
+	dc.l	$e2804e75,$006e3ffe,$ff840680,$00003ffe
+	dc.l	$e2804e75,$322eff90,$30010281,$00007fff
+	dc.l	$02408000,$00403fff,$3d40ff90,$0c2e0004
+	dc.l	$ff4f670a,$203c0000,$3fff9081,$4e7541ee
+	dc.l	$ff9061ff,$00000384,$44802200,$60e60c2e
+	dc.l	$0005ff4f,$67320c2e,$0003ff4f,$673e0c2e
+	dc.l	$0003ff4e,$671408ee,$0006ff70,$00ae0100
+	dc.l	$4080ff64,$41eeff6c,$604200ae,$01000000
+	dc.l	$ff6441ee,$ff6c6034,$00ae0100,$4080ff64
+	dc.l	$08ee0006,$ff7c41ee,$ff786020,$41eeff78
+	dc.l	$0c2e0005,$ff4e66ff,$0000000c,$00ae0000
+	dc.l	$4080ff64,$00ae0100,$0000ff64,$08280007
+	dc.l	$00006708,$00ae0800,$0000ff64,$f210d080
+	dc.l	$4e7500ae,$01002080,$ff64f23b,$d0800170
+	dc.l	$00000008,$4e757fff,$0000ffff,$ffffffff
+	dc.l	$ffff0000,$3f813c01,$e408323b,$02f63001
+	dc.l	$90680000,$0c400042,$6a164280,$082e0001
+	dc.l	$ff666704,$08c0001d,$61ff0000,$001a4e75
+	dc.l	$203c2000,$00003141,$000042a8,$000442a8
+	dc.l	$00084e75,$2d680008,$ff542d40,$ff582001
+	dc.l	$92680000,$6f100c41,$00206d10,$0c410040
+	dc.l	$6d506000,$009a202e,$ff584e75,$2f023140
+	dc.l	$00007020,$90410c41,$001d6d08,$142eff58
+	dc.l	$852eff57,$e9e82020,$0004e9e8,$18000004
+	dc.l	$e9ee0800,$ff542142,$00042141,$0008e8c0
+	dc.l	$009e6704,$08c0001d,$0280e000,$0000241f
+	dc.l	$4e752f02,$31400000,$04410020,$70209041
+	dc.l	$142eff58,$852eff57,$e9e82020,$0004e9e8
+	dc.l	$18000004,$e8c1009e,$660ce8ee,$081fff54
+	dc.l	$66042001,$60062001,$08c0001d,$42a80004
+	dc.l	$21420008,$0280e000,$0000241f,$4e753140
+	dc.l	$00000c41,$00416d12,$672442a8,$000442a8
+	dc.l	$0008203c,$20000000,$4e752028,$00042200
+	dc.l	$0280c000,$00000281,$3fffffff,$60122028
+	dc.l	$00040280,$80000000,$e2880281,$7fffffff
+	dc.l	$66164aa8,$00086610,$4a2eff58,$660a42a8
+	dc.l	$000442a8,$00084e75,$08c0001d,$42a80004
+	dc.l	$42a80008,$4e7561ff,$00000110,$4a806700
+	dc.l	$00fa006e,$0208ff66,$327b1206,$4efb9802
+	dc.l	$004000ea,$00240008,$4a280002,$6b0000dc
+	dc.l	$70ff4841,$0c010004,$6700003e,$6e000094
+	dc.l	$60000064,$4a280002,$6a0000c0,$70ff4841
+	dc.l	$0c010004,$67000022,$6e000078,$60000048
+	dc.l	$e3806400,$00a64841,$0c010004,$6700000a
+	dc.l	$6e000060,$60000030,$06a80000,$01000004
+	dc.l	$640ce4e8,$0004e4e8,$00065268,$00004a80
+	dc.l	$66060268,$fe000006,$02a8ffff,$ff000004
+	dc.l	$42a80008,$4e7552a8,$0008641a,$52a80004
+	dc.l	$6414e4e8,$0004e4e8,$0006e4e8,$0008e4e8
+	dc.l	$000a5268,$00004a80,$66060228,$00fe000b
+	dc.l	$4e7506a8,$00000800,$0008641a,$52a80004
+	dc.l	$6414e4e8,$0004e4e8,$0006e4e8,$0008e4e8
+	dc.l	$000a5268,$00004a80,$66060268,$f000000a
+	dc.l	$02a8ffff,$f8000008,$4e754841,$0c010004
+	dc.l	$6700ff86,$6eea4e75,$48414a01,$66044841
+	dc.l	$4e7548e7,$30000c01,$00046622,$e9e83602
+	dc.l	$0004741e,$e5ab2428,$00040282,$0000003f
+	dc.l	$66284aa8,$00086622,$4a80661e,$6020e9e8
+	dc.l	$35420008,$741ee5ab,$24280008,$02820000
+	dc.l	$01ff6606,$4a806602,$600408c3,$001d2003
+	dc.l	$4cdf000c,$48414e75,$2f022f03,$20280004
+	dc.l	$22280008,$edc02000,$671ae5a8,$e9c13022
+	dc.l	$8083e5a9,$21400004,$21410008,$2002261f
+	dc.l	$241f4e75,$edc12000,$e5a90682,$00000020
+	dc.l	$21410004,$42a80008,$2002261f,$241f4e75
+	dc.l	$ede80000,$0004660e,$ede80000,$00086700
+	dc.l	$00740640,$00204281,$32280000,$02417fff
+	dc.l	$b0416e1c,$92403028,$00000240,$80008240
+	dc.l	$31410000,$61ffffff,$ff82103c,$00004e75
+	dc.l	$0c010020,$6e20e9e8,$08400004,$21400004
+	dc.l	$20280008,$e3a82140,$00080268,$80000000
+	dc.l	$103c0004,$4e750441,$00202028,$0008e3a8
+	dc.l	$21400004,$42a80008,$02688000,$0000103c
+	dc.l	$00044e75,$02688000,$0000103c,$00014e75
+	dc.l	$30280000,$02407fff,$0c407fff,$67480828
+	dc.l	$00070004,$6706103c,$00004e75,$4a406618
+	dc.l	$4aa80004,$660c4aa8,$00086606,$103c0001
+	dc.l	$4e75103c,$00044e75,$4aa80004,$66124aa8
+	dc.l	$0008660c,$02688000,$0000103c,$00014e75
+	dc.l	$103c0006,$4e754aa8,$00086612,$20280004
+	dc.l	$02807fff,$ffff6606,$103c0002,$4e750828
+	dc.l	$00060004,$6706103c,$00034e75,$103c0005
+	dc.l	$4e752028,$00002200,$02807ff0,$0000670e
+	dc.l	$0c807ff0,$00006728,$103c0000,$4e750281
+	dc.l	$000fffff,$66ff0000,$00144aa8,$000466ff
+	dc.l	$0000000a,$103c0001,$4e75103c,$00044e75
+	dc.l	$0281000f,$ffff66ff,$00000014,$4aa80004
+	dc.l	$66ff0000,$000a103c,$00024e75,$08010013
+	dc.l	$66ff0000,$000a103c,$00054e75,$103c0003
+	dc.l	$4e752028,$00002200,$02807f80,$0000670e
+	dc.l	$0c807f80,$0000671e,$103c0000,$4e750281
+	dc.l	$007fffff,$66ff0000,$000a103c,$00014e75
+	dc.l	$103c0004,$4e750281,$007fffff,$66ff0000
+	dc.l	$000a103c,$00024e75,$08010016,$66ff0000
+	dc.l	$000a103c,$00054e75,$103c0003,$4e752f01
+	dc.l	$08280007,$000056e8,$00023228,$00000241
+	dc.l	$7fff9240,$31410000,$2f08202f,$00040240
+	dc.l	$00c0e848,$61ffffff,$fae22057,$322f0006
+	dc.l	$024100c0,$e8494841,$322f0006,$02410030
+	dc.l	$e84961ff,$fffffc22,$205f08a8,$00070000
+	dc.l	$4a280002,$670a08e8,$00070000,$42280002
+	dc.l	$42804aa8,$0004660a,$4aa80008,$660408c0
+	dc.l	$0002082e,$0001ff66,$670608ee,$0005ff67
+	dc.l	$588f4e75,$2f010828,$00070000,$56e80002
+	dc.l	$32280000,$02417fff,$92403141,$00002f08
+	dc.l	$428061ff,$fffffa64,$2057323c,$00044841
+	dc.l	$322f0006,$02410030,$e84961ff,$fffffbaa
+	dc.l	$205f08a8,$00070000,$4a280002,$670a08e8
+	dc.l	$00070000,$42280002,$42804aa8,$0004660a
+	dc.l	$4aa80008,$660408c0,$0002082e,$0001ff66
+	dc.l	$670608ee,$0005ff67,$588f4e75,$02410010
+	dc.l	$e8088200,$3001e309,$600e0241,$00108200
+	dc.l	$48408200,$3001e309,$103b0008,$41fb1620
+	dc.l	$4e750200,$00020200,$00020200,$00020000
+	dc.l	$00000a08,$0a080a08,$0a080a08,$0a087fff
+	dc.l	$00000000,$00000000,$00000000,$00007ffe
+	dc.l	$0000ffff,$ffffffff,$ffff0000,$00007ffe
+	dc.l	$0000ffff,$ffffffff,$ffff0000,$00007fff
+	dc.l	$00000000,$00000000,$00000000,$00007fff
+	dc.l	$00000000,$00000000,$00000000,$0000407e
+	dc.l	$0000ffff,$ff000000,$00000000,$0000407e
+	dc.l	$0000ffff,$ff000000,$00000000,$00007fff
+	dc.l	$00000000,$00000000,$00000000,$00007fff
+	dc.l	$00000000,$00000000,$00000000,$000043fe
+	dc.l	$0000ffff,$ffffffff,$f8000000,$000043fe
+	dc.l	$0000ffff,$ffffffff,$f8000000,$00007fff
+	dc.l	$00000000,$00000000,$00000000,$00000000
+	dc.l	$00000000,$00000000,$00000000,$00000000
+	dc.l	$00000000,$00000000,$00000000,$00000000
+	dc.l	$00000000,$00000000,$00000000,$00000000
+	dc.l	$00000000,$00000000,$00000000,$0000ffff
+	dc.l	$00000000,$00000000,$00000000,$0000fffe
+	dc.l	$0000ffff,$ffffffff,$ffff0000,$0000ffff
+	dc.l	$00000000,$00000000,$00000000,$0000fffe
+	dc.l	$0000ffff,$ffffffff,$ffff0000,$0000ffff
+	dc.l	$00000000,$00000000,$00000000,$0000c07e
+	dc.l	$0000ffff,$ff000000,$00000000,$0000ffff
+	dc.l	$00000000,$00000000,$00000000,$0000c07e
+	dc.l	$0000ffff,$ff000000,$00000000,$0000ffff
+	dc.l	$00000000,$00000000,$00000000,$0000c3fe
+	dc.l	$0000ffff,$ffffffff,$f8000000,$0000ffff
+	dc.l	$00000000,$00000000,$00000000,$0000c3fe
+	dc.l	$0000ffff,$ffffffff,$f8000000,$0000e9ee
+	dc.l	$10c3ff42,$327b120a,$4efb9806,$4afc0008
+	dc.l	$00e001e0,$01480620,$0078041a,$00100620
+	dc.l	$4a2eff4e,$664cf228,$d0800000,$f2009000
+	dc.l	$f2007800,$f23c9000,$00000000,$f201a800
+	dc.l	$836eff66,$122eff41,$02010038,$6714206e
+	dc.l	$000c61ff,$ffffcfaa,$4a8166ff,$0000385a
+	dc.l	$4e75122e,$ff410241,$000761ff,$00002bb0
+	dc.l	$4e752228,$00000281,$80000000,$00810080
+	dc.l	$0000f201,$440060a4,$4a2eff4e,$664cf228
+	dc.l	$d0800000,$f2009000,$f2007000,$f23c9000
+	dc.l	$00000000,$f201a800,$836eff66,$122eff41
+	dc.l	$02010038,$6714206e,$000c61ff,$ffffcf58
+	dc.l	$4a8166ff,$00003800,$4e75122e,$ff410241
+	dc.l	$000761ff,$00002b0c,$4e752228,$00000281
+	dc.l	$80000000,$00810080,$0000f201,$440060a4
+	dc.l	$4a2eff4e,$664cf228,$d0800000,$f2009000
+	dc.l	$f2006000,$f23c9000,$00000000,$f201a800
+	dc.l	$836eff66,$122eff41,$02010038,$6714206e
+	dc.l	$000c61ff,$ffffcf06,$4a8166ff,$000037a6
+	dc.l	$4e75122e,$ff410241,$000761ff,$00002a68
+	dc.l	$4e752228,$00000281,$80000000,$00810080
+	dc.l	$0000f201,$440060a4,$3d680000,$ff84426e
+	dc.l	$ff862d68,$0004ff88,$2d680008,$ff8cf228
+	dc.l	$d0800000,$61ffffff,$e83e2248,$41eeff84
+	dc.l	$700c0c2e,$0008ff4a,$672661ff,$ffffcdee
+	dc.l	$4a816600,$00524a2e,$ff4e6602,$4e7508ee
+	dc.l	$0003ff66,$102eff62,$0200000a,$66164e75
+	dc.l	$61ffffff,$dc4a4a81,$6600002c,$4a2eff4e
+	dc.l	$66dc4e75,$41eeff84,$61ffffff,$f90e4440
+	dc.l	$02407fff,$026e8000,$ff84816e,$ff84f22e
+	dc.l	$d040ff84,$4e752cae,$ffd460ff,$00003702
+	dc.l	$02000030,$00000040,$2d40ff5c,$30280000
+	dc.l	$02407fff,$0c40407e,$6e0000e6,$67000152
+	dc.l	$0c403f81,$6d000058,$f228d080,$0000f22e
+	dc.l	$9000ff5c,$f23c8800,$00000000,$f2006400
+	dc.l	$f23c9000,$00000000,$f201a800,$836eff66
+	dc.l	$122eff41,$02010038,$6714206e,$000c61ff
+	dc.l	$ffffcdda,$4a8166ff,$0000367a,$4e75122e
+	dc.l	$ff410241,$000761ff,$0000293c,$4e7508ee
+	dc.l	$0003ff66,$3d680000,$ff842d68,$0004ff88
+	dc.l	$2d680008,$ff8c2f08,$42800c2e,$0004ff4e
+	dc.l	$660a41ee,$ff8461ff,$fffff840,$41eeff84
+	dc.l	$222eff5c,$61ffffff,$fa5841ee,$ff8461ff
+	dc.l	$0000034c,$122eff41,$02010038,$6714206e
+	dc.l	$000c61ff,$ffffcd66,$4a8166ff,$00003606
+	dc.l	$600e122e,$ff410241,$000761ff,$000028c8
+	dc.l	$122eff62,$0201000a,$660000b8,$588f4e75
+	dc.l	$4a280007,$660e4aa8,$00086608,$006e1048
+	dc.l	$ff666006,$006e1248,$ff662f08,$4a280000
+	dc.l	$5bc1202e,$ff5c61ff,$fffffae4,$f210d080
+	dc.l	$f2006400,$122eff41,$02010038,$6714206e
+	dc.l	$000c61ff,$ffffccf6,$4a8166ff,$00003596
+	dc.l	$600e122e,$ff410241,$000761ff,$00002858
+	dc.l	$122eff62,$0201000a,$6600007c,$588f4e75
+	dc.l	$32280000,$02418000,$00413fff,$3d41ff84
+	dc.l	$2d680004,$ff882d68,$0008ff8c,$f22e9000
+	dc.l	$ff5cf22e,$4800ff84,$f23c9000,$00000000
+	dc.l	$f2000018,$f23c5838,$0002f294,$fe7c6000
+	dc.l	$ff50205f,$3d680000,$ff842d68,$0004ff88
+	dc.l	$2d680008,$ff8c0c2e,$0004ff4e,$662c41ee
+	dc.l	$ff8461ff,$fffff714,$44800240,$7fffefee
+	dc.l	$004fff84,$6014205f,$3d680000,$ff842d68
+	dc.l	$0004ff88,$2d680008,$ff8c08ae,$0007ff84
+	dc.l	$56eeff86,$41eeff84,$122eff5f,$e8090241
+	dc.l	$000c4841,$122eff5f,$e8090241,$00034280
+	dc.l	$61ffffff,$f5544a2e,$ff866706,$08ee0007
+	dc.l	$ff84f22e,$d040ff84,$4e750200,$00300000
+	dc.l	$00802d40,$ff5c3028,$00000240,$7fff0c40
+	dc.l	$43fe6e00,$00c86700,$01200c40,$3c016d00
+	dc.l	$0046f228,$d0800000,$f22e9000,$ff5cf23c
+	dc.l	$88000000,$0000f22e,$7400ff54,$f23c9000
+	dc.l	$00000000,$f200a800,$816eff66,$226e000c
+	dc.l	$41eeff54,$700861ff,$ffffcaf2,$4a8166ff
+	dc.l	$00003450,$4e7508ee,$0003ff66,$3d680000
+	dc.l	$ff842d68,$0004ff88,$2d680008,$ff8c2f08
+	dc.l	$42800c2e,$0004ff4e,$660a41ee,$ff8461ff
+	dc.l	$fffff618,$41eeff84,$222eff5c,$61ffffff
+	dc.l	$f83041ee,$ff8461ff,$000000d2,$2d40ff54
+	dc.l	$2d41ff58,$226e000c,$41eeff54,$700861ff
+	dc.l	$ffffca8a,$4a8166ff,$000033e8,$122eff62
+	dc.l	$0201000a,$6600fe9c,$588f4e75,$3028000a
+	dc.l	$024007ff,$6608006e,$1048ff66,$6006006e
+	dc.l	$1248ff66,$2f084a28,$00005bc1,$202eff5c
+	dc.l	$61ffffff,$f8caf210,$d080f22e,$7400ff54
+	dc.l	$226e000c,$41eeff54,$700861ff,$ffffca2e
+	dc.l	$4a8166ff,$0000338c,$122eff62,$0201000a
+	dc.l	$6600fe74,$588f4e75,$32280000,$02418000
+	dc.l	$00413fff,$3d41ff84,$2d680004,$ff882d68
+	dc.l	$0008ff8c,$f22e9000,$ff5cf22e,$4800ff84
+	dc.l	$f23c9000,$00000000,$f2000018,$f23c5838
+	dc.l	$0002f294,$feae6000,$ff644280,$30280000
+	dc.l	$04403fff,$064003ff,$4a280004,$6b025340
+	dc.l	$4840e988,$4a280000,$6a0408c0,$001f2228
+	dc.l	$0004e9c1,$10548081,$2d40ff54,$22280004
+	dc.l	$7015e1a9,$2d41ff58,$22280008,$e9c10015
+	dc.l	$222eff58,$8280202e,$ff544e75,$42803028
+	dc.l	$00000440,$3fff0640,$007f4a28,$00046b02
+	dc.l	$53404840,$ef884a28,$00006a04,$08c0001f
+	dc.l	$22280004,$02817fff,$ff00e089,$80814e75
+	dc.l	$61ffffff,$e3822f08,$102eff4e,$66000082
+	dc.l	$082e0004,$ff426712,$122eff43,$e8090241
+	dc.l	$000761ff,$000024de,$6004102e,$ff43ebc0
+	dc.l	$06472f00,$41eeff6c,$61ff0000,$2b2002ae
+	dc.l	$cffff00f,$ff84201f,$4a2eff87,$66164aae
+	dc.l	$ff886610,$4aaeff8c,$660a4a80,$6606026e
+	dc.l	$f000ff84,$41eeff84,$225f700c,$0c2e0008
+	dc.l	$ff4a670e,$61ffffff,$c8d44a81,$6600fb38
+	dc.l	$4e7561ff,$ffffd748,$4a816600,$fb2a4e75
+	dc.l	$0c000004,$6700ff7a,$41eeff6c,$426eff6e
+	dc.l	$0c000005,$670260c0,$006e4080,$ff6608ee
+	dc.l	$0006ff70,$60b251fc,$51fc51fc,$51fc51fc
+	dc.l	$ffffc001,$ffffff81,$fffffc01,$00004000
+	dc.l	$0000007f,$000003ff,$02000030,$00000040
+	dc.l	$60080200,$00300000,$00802d40,$ff5c4241
+	dc.l	$122eff4f,$e709822e,$ff4e6600,$02e43d69
+	dc.l	$0000ff90,$2d690004,$ff942d69,$0008ff98
+	dc.l	$3d680000,$ff842d68,$0004ff88,$2d680008
+	dc.l	$ff8c61ff,$ffffef24,$2f0061ff,$ffffefc8
+	dc.l	$d197322e,$ff5eec09,$201fb0bb,$14846700
+	dc.l	$011e6d00,$0062b0bb,$14846700,$021a6e00
+	dc.l	$014af22e,$d080ff90,$f22e9000,$ff5cf23c
+	dc.l	$88000000,$0000f22e,$4823ff84,$f201a800
+	dc.l	$f23c9000,$00000000,$83aeff64,$f22ef080
+	dc.l	$ff842f02,$322eff84,$24010281,$00007fff
+	dc.l	$02428000,$92808242,$3d41ff84,$241ff22e
+	dc.l	$d080ff84,$4e75f22e,$d080ff90,$f22e9000
+	dc.l	$ff5cf23c,$88000000,$0000f22e,$4823ff84
+	dc.l	$f201a800,$f23c9000,$00000000,$83aeff64
+	dc.l	$00ae0000,$1048ff64,$122eff62,$02010013
+	dc.l	$661c082e,$0003ff64,$56c1202e,$ff5c61ff
+	dc.l	$fffff5dc,$812eff64,$f210d080,$4e75222e
+	dc.l	$ff5c0201,$00c06634,$f22ef080,$ff842f02
+	dc.l	$322eff84,$34010281,$00007fff,$92800481
+	dc.l	$00006000,$02417fff,$02428000,$82423d41
+	dc.l	$ff84241f,$f22ed040,$ff8460a6,$f22ed080
+	dc.l	$ff90222e,$ff5c0201,$0030f201,$9000f22e
+	dc.l	$4823ff84,$f23c9000,$00000000,$60aaf22e
+	dc.l	$d080ff90,$f22e9000,$ff5cf23c,$88000000
+	dc.l	$0000f22e,$4823ff84,$f201a800,$f23c9000
+	dc.l	$00000000,$83aeff64,$f2000098,$f23c58b8
+	dc.l	$0002f293,$ff3c6000,$fee408ee,$0003ff66
+	dc.l	$f22ed080,$ff90f23c,$90000000,$0010f23c
+	dc.l	$88000000,$0000f22e,$4823ff84,$f201a800
+	dc.l	$f23c9000,$00000000,$83aeff64,$122eff62
+	dc.l	$0201000b,$6620f22e,$f080ff84,$41eeff84
+	dc.l	$222eff5c,$61ffffff,$f3e8812e,$ff64f22e
+	dc.l	$d080ff84,$4e75f22e,$d040ff90,$222eff5c
+	dc.l	$020100c0,$6652f22e,$9000ff5c,$f23c8800
+	dc.l	$00000000,$f22e48a3,$ff84f23c,$90000000
+	dc.l	$0000f22e,$f040ff84,$2f02322e,$ff842401
+	dc.l	$02810000,$7fff0242,$80009280,$06810000
+	dc.l	$60000241,$7fff8242,$3d41ff84,$241ff22e
+	dc.l	$d040ff84,$6000ff80,$222eff5c,$02010030
+	dc.l	$f2019000,$60a6f22e,$d080ff90,$f22e9000
+	dc.l	$ff5cf23c,$88000000,$0000f22e,$4823ff84
+	dc.l	$f201a800,$f23c9000,$00000000,$83aeff64
+	dc.l	$f2000098,$f23c58b8,$0002f292,$fde0f294
+	dc.l	$fefaf22e,$d040ff90,$222eff5c,$020100c0
+	dc.l	$00010010,$f2019000,$f23c8800,$00000000
+	dc.l	$f22e48a3,$ff84f23c,$90000000,$0000f200
+	dc.l	$0498f23c,$58b80002,$f293fda2,$6000febc
+	dc.l	$323b120a,$4efb1006,$4afc0030,$fd120072
+	dc.l	$00cc006c,$fd120066,$00000000,$00720072
+	dc.l	$0060006c,$00720066,$00000000,$009e0060
+	dc.l	$009e006c,$009e0066,$00000000,$006c006c
+	dc.l	$006c006c,$006c0066,$00000000,$fd120072
+	dc.l	$00cc006c,$fd120066,$00000000,$00660066
+	dc.l	$00660066,$00660066,$00000000,$60ffffff
+	dc.l	$ed6460ff,$ffffecda,$60ffffff,$ecd41028
+	dc.l	$00001229,$0000b101,$6a10f23c,$44008000
+	dc.l	$00001d7c,$000cff64,$4e75f23c,$44000000
+	dc.l	$00001d7c,$0004ff64,$4e75f229,$d0800000
+	dc.l	$10280000,$12290000,$b1016a10,$f2000018
+	dc.l	$f200001a,$1d7c000a,$ff644e75,$f2000018
+	dc.l	$1d7c0002,$ff644e75,$f228d080,$00001028
+	dc.l	$00001229,$0000b101,$6ae260d0,$02000030
+	dc.l	$00000040,$60080200,$00300000,$00802d40
+	dc.l	$ff5c122e,$ff4e6600,$02620200,$00c06600
+	dc.l	$007c4a28,$00006a06,$08ee0003,$ff64f228
+	dc.l	$d0800000,$4e750200,$00c06600,$006008ee
+	dc.l	$0003ff66,$4a280000,$6a0608ee,$0003ff64
+	dc.l	$f228d080,$0000082e,$0003ff62,$66024e75
+	dc.l	$3d680000,$ff842d68,$0004ff88,$2d680008
+	dc.l	$ff8c41ee,$ff8461ff,$ffffef60,$44400640
+	dc.l	$6000322e,$ff840241,$80000240,$7fff8041
+	dc.l	$3d40ff84,$f22ed040,$ff844e75,$0c000040
+	dc.l	$667e3d68,$0000ff84,$2d680004,$ff882d68
+	dc.l	$0008ff8c,$61ffffff,$eac20c80,$0000007f
+	dc.l	$6c000092,$0c80ffff,$ff816700,$01786d00
+	dc.l	$00f4f23c,$88000000,$0000f22e,$9000ff5c
+	dc.l	$f22e4800,$ff84f201,$a800f23c,$90000000
+	dc.l	$000083ae,$ff642f02,$f22ef080,$ff84322e
+	dc.l	$ff843401,$02810000,$7fff9280,$02428000
+	dc.l	$84413d42,$ff84241f,$f22ed080,$ff844e75
+	dc.l	$3d680000,$ff842d68,$0004ff88,$2d680008
+	dc.l	$ff8c61ff,$ffffea44,$0c800000,$03ff6c00
+	dc.l	$00140c80,$fffffc01,$670000fa,$6d000076
+	dc.l	$6000ff80,$08ee0003,$ff664a2e,$ff846a06
+	dc.l	$08ee0003,$ff64122e,$ff620201,$000b661a
+	dc.l	$41eeff84,$222eff5c,$61ffffff,$f084812e
+	dc.l	$ff64f22e,$d080ff84,$4e752d6e,$ff88ff94
+	dc.l	$2d6eff8c,$ff98322e,$ff842f02,$34010281
+	dc.l	$00007fff,$92800242,$80000681,$00006000
+	dc.l	$02417fff,$84413d42,$ff90f22e,$d040ff90
+	dc.l	$241f60ac,$f23c8800,$00000000,$f22e9000
+	dc.l	$ff5cf22e,$4800ff84,$f23c9000,$00000000
+	dc.l	$f201a800,$83aeff64,$00ae0000,$1048ff64
+	dc.l	$122eff62,$02010013,$661c082e,$0003ff64
+	dc.l	$56c1202e,$ff5c61ff,$fffff0f4,$812eff64
+	dc.l	$f210d080,$4e752f02,$322eff84,$24010281
+	dc.l	$00007fff,$02428000,$92800481,$00006000
+	dc.l	$02417fff,$82423d41,$ff84241f,$f22ed040
+	dc.l	$ff8460b6,$f23c8800,$00000000,$f22e9000
+	dc.l	$ff5cf22e,$4800ff84,$f201a800,$f23c9000
+	dc.l	$00000000,$83aeff64,$f2000098,$f23c58b8
+	dc.l	$0002f293,$ff746000,$fe7e0c01,$00046700
+	dc.l	$fdb60c01,$000567ff,$ffffe9ee,$0c010003
+	dc.l	$67ffffff,$e9f8f228,$48000000,$f200a800
+	dc.l	$e1981d40,$ff644e75,$51fc51fc,$51fc51fc
+	dc.l	$00003fff,$0000007e,$000003fe,$ffffc001
+	dc.l	$ffffff81,$fffffc01,$02000030,$00000040
+	dc.l	$60080200,$00300000,$00802d40,$ff5c4241
+	dc.l	$122eff4f,$e709822e,$ff4e6600,$02d63d69
+	dc.l	$0000ff90,$2d690004,$ff942d69,$0008ff98
+	dc.l	$3d680000,$ff842d68,$0004ff88,$2d680008
+	dc.l	$ff8c61ff,$ffffe864,$2f0061ff,$ffffe908
+	dc.l	$4497d197,$322eff5e,$ec09201f,$b0bb148e
+	dc.l	$6f000074,$b0bb1520,$ff7a6700,$020c6e00
+	dc.l	$013cf22e,$d080ff90,$f22e9000,$ff5cf23c
+	dc.l	$88000000,$0000f22e,$4820ff84,$f201a800
+	dc.l	$f23c9000,$00000000,$83aeff64,$f22ef080
+	dc.l	$ff842f02,$322eff84,$24010281,$00007fff
+	dc.l	$02428000,$92808242,$3d41ff84,$241ff22e
+	dc.l	$d080ff84,$4e750000,$7fff0000,$407f0000
+	dc.l	$43ff201f,$60c62f00,$f22ed080,$ff90f22e
+	dc.l	$9000ff5c,$f23c8800,$00000000,$f22e4820
+	dc.l	$ff84f200,$a800f23c,$90000000,$000081ae
+	dc.l	$ff64f227,$e0013017,$dffc0000,$000c0280
+	dc.l	$00007fff,$9097b0bb,$14ae6db6,$201f00ae
+	dc.l	$00001048,$ff64122e,$ff620201,$0013661c
+	dc.l	$082e0003,$ff6456c1,$202eff5c,$61ffffff
+	dc.l	$eeee812e,$ff64f210,$d0804e75,$222eff5c
+	dc.l	$020100c0,$6634f22e,$f080ff84,$2f02322e
+	dc.l	$ff843401,$02810000,$7fff9280,$04810000
+	dc.l	$60000241,$7fff0242,$80008242,$3d41ff84
+	dc.l	$241ff22e,$d040ff84,$60a6f22e,$d080ff90
+	dc.l	$222eff5c,$02010030,$f2019000,$f22e4820
+	dc.l	$ff84f23c,$90000000,$000060aa,$08ee0003
+	dc.l	$ff66f22e,$d080ff90,$f23c9000,$00000010
+	dc.l	$f23c8800,$00000000,$f22e4820,$ff84f201
+	dc.l	$a800f23c,$90000000,$000083ae,$ff64122e
+	dc.l	$ff620201,$000b6620,$f22ef080,$ff8441ee
+	dc.l	$ff84222e,$ff5c61ff,$ffffed36,$812eff64
+	dc.l	$f22ed080,$ff844e75,$f22ed040,$ff90222e
+	dc.l	$ff5c0201,$00c06652,$f22e9000,$ff5cf23c
+	dc.l	$88000000,$0000f22e,$48a0ff84,$f23c9000
+	dc.l	$00000000,$f22ef040,$ff842f02,$322eff84
+	dc.l	$24010281,$00007fff,$02428000,$92800681
+	dc.l	$00006000,$02417fff,$82423d41,$ff84241f
+	dc.l	$f22ed040,$ff846000,$ff80222e,$ff5c0201
+	dc.l	$0030f201,$900060a6,$f22ed080,$ff90f22e
+	dc.l	$9000ff5c,$f23c8800,$00000000,$f22e4820
+	dc.l	$ff84f201,$a800f23c,$90000000,$000083ae
+	dc.l	$ff64f200,$0098f23c,$58b80001,$f292fdee
+	dc.l	$f294fefa,$f22ed040,$ff90222e,$ff5c0201
+	dc.l	$00c00001,$0010f201,$9000f23c,$88000000
+	dc.l	$0000f22e,$48a0ff84,$f23c9000,$00000000
+	dc.l	$f2000498,$f23c58b8,$0001f293,$fdb06000
+	dc.l	$febc323b,$120a4efb,$10064afc,$0030fd20
+	dc.l	$009e0072,$0060fd20,$00660000,$00000072
+	dc.l	$006c0072,$00600072,$00660000,$000000d0
+	dc.l	$00d0006c,$006000d0,$00660000,$00000060
+	dc.l	$00600060,$00600060,$00660000,$0000fd20
+	dc.l	$009e0072,$0060fd20,$00660000,$00000066
+	dc.l	$00660066,$00660066,$00660000,$000060ff
+	dc.l	$ffffe62e,$60ffffff,$e62860ff,$ffffe6a6
+	dc.l	$10280000,$12290000,$b1016a10,$f23c4400
+	dc.l	$80000000,$1d7c000c,$ff644e75,$f23c4400
+	dc.l	$00000000,$1d7c0004,$ff644e75,$006e0410
+	dc.l	$ff661028,$00001229,$0000b101,$6a10f23c
+	dc.l	$4400ff80,$00001d7c,$000aff64,$4e75f23c
+	dc.l	$44007f80,$00001d7c,$0002ff64,$4e751029
+	dc.l	$00001228,$0000b101,$6a16f229,$d0800000
+	dc.l	$f2000018,$f200001a,$1d7c000a,$ff644e75
+	dc.l	$f229d080,$0000f200,$00181d7c,$0002ff64
+	dc.l	$4e750200,$00300000,$00406008,$02000030
+	dc.l	$00000080,$2d40ff5c,$122eff4e,$66000276
+	dc.l	$020000c0,$66000090,$2d680004,$ff882d68
+	dc.l	$0008ff8c,$30280000,$0a408000,$6a061d7c
+	dc.l	$0008ff64,$3d40ff84,$f22ed080,$ff844e75
+	dc.l	$020000c0,$666008ee,$0003ff66,$2d680004
+	dc.l	$ff882d68,$0008ff8c,$30280000,$0a408000
+	dc.l	$6a061d7c,$0008ff64,$3d40ff84,$f22ed080
+	dc.l	$ff84082e,$0003ff62,$66024e75,$41eeff84
+	dc.l	$61ffffff,$e8764440,$06406000,$322eff84
+	dc.l	$02418000,$02407fff,$80413d40,$ff84f22e
+	dc.l	$d040ff84,$4e750c00,$0040667e,$3d680000
+	dc.l	$ff842d68,$0004ff88,$2d680008,$ff8c61ff
+	dc.l	$ffffe3d8,$0c800000,$007f6c00,$00900c80
+	dc.l	$ffffff81,$67000178,$6d0000f4,$f23c8800
+	dc.l	$00000000,$f22e9000,$ff5cf22e,$481aff84
+	dc.l	$f201a800,$f23c9000,$00000000,$83aeff64
+	dc.l	$2f02f22e,$f080ff84,$322eff84,$34010281
+	dc.l	$00007fff,$92800242,$80008441,$3d42ff84
+	dc.l	$241ff22e,$d080ff84,$4e753d68,$0000ff84
+	dc.l	$2d680004,$ff882d68,$0008ff8c,$61ffffff
+	dc.l	$e35a0c80,$000003ff,$6c120c80,$fffffc01
+	dc.l	$670000fc,$6d000078,$6000ff82,$08ee0003
+	dc.l	$ff660a2e,$0080ff84,$6a0608ee,$0003ff64
+	dc.l	$122eff62,$0201000b,$661a41ee,$ff84222e
+	dc.l	$ff5c61ff,$ffffe99a,$812eff64,$f22ed080
+	dc.l	$ff844e75,$2d6eff88,$ff942d6e,$ff8cff98
+	dc.l	$322eff84,$2f022401,$02810000,$7fff0242
+	dc.l	$80009280,$06810000,$60000241,$7fff8242
+	dc.l	$3d41ff90,$f22ed040,$ff90241f,$60acf23c
+	dc.l	$88000000,$0000f22e,$9000ff5c,$f22e481a
+	dc.l	$ff84f23c,$90000000,$0000f201,$a80083ae
+	dc.l	$ff6400ae,$00001048,$ff64122e,$ff620201
+	dc.l	$0013661c,$082e0003,$ff6456c1,$202eff5c
+	dc.l	$61ffffff,$ea0a812e,$ff64f210,$d0804e75
+	dc.l	$2f02322e,$ff842401,$02810000,$7fff0242
+	dc.l	$80009280,$04810000,$60000241,$7fff8242
+	dc.l	$3d41ff84,$f22ed040,$ff84241f,$60b6f23c
+	dc.l	$88000000,$0000f22e,$9000ff5c,$f22e481a
+	dc.l	$ff84f201,$a800f23c,$90000000,$000083ae
+	dc.l	$ff64f200,$0098f23c,$58b80002,$f293ff74
+	dc.l	$6000fe7e,$0c010004,$6700fdb6,$0c010005
+	dc.l	$67ffffff,$e3040c01,$000367ff,$ffffe30e
+	dc.l	$f228481a,$0000f200,$a800e198,$1d40ff64
+	dc.l	$4e75122e,$ff4e6610,$4a280000,$6b024e75
+	dc.l	$1d7c0008,$ff644e75,$0c010001,$67400c01
+	dc.l	$00026724,$0c010005,$67ffffff,$e2bc0c01
+	dc.l	$000367ff,$ffffe2c6,$4a280000,$6b024e75
+	dc.l	$1d7c0008,$ff644e75,$4a280000,$6b081d7c
+	dc.l	$0002ff64,$4e751d7c,$000aff64,$4e754a28
+	dc.l	$00006b08,$1d7c0004,$ff644e75,$1d7c000c
+	dc.l	$ff644e75,$122eff4e,$66280200,$0030f200
+	dc.l	$9000f23c,$88000000,$0000f228,$48010000
+	dc.l	$f23c9000,$00000000,$f200a800,$81aeff64
+	dc.l	$4e750c01,$0001672e,$0c010002,$674e0c01
+	dc.l	$00046710,$0c010005,$67ffffff,$e22c60ff
+	dc.l	$ffffe23a,$3d680000,$ff841d7c,$0080ff88
+	dc.l	$41eeff84,$60a44a28,$00006b10,$f23c4400
+	dc.l	$00000000,$1d7c0004,$ff644e75,$f23c4400
+	dc.l	$80000000,$1d7c000c,$ff644e75,$f228d080
+	dc.l	$00004a28,$00006b08,$1d7c0002,$ff644e75
+	dc.l	$1d7c000a,$ff644e75,$122eff4e,$6618f23c
+	dc.l	$88000000,$0000f228,$48030000,$f200a800
+	dc.l	$81aeff64,$4e750c01,$0001672e,$0c010002
+	dc.l	$674e0c01,$00046710,$0c010005,$67ffffff
+	dc.l	$e19860ff,$ffffe1a6,$3d680000,$ff841d7c
+	dc.l	$0080ff88,$41eeff84,$60b44a28,$00006b10
+	dc.l	$f23c4400,$00000000,$1d7c0004,$ff644e75
+	dc.l	$f23c4400,$80000000,$1d7c000c,$ff644e75
+	dc.l	$f228d080,$00004a28,$00006b08,$1d7c0002
+	dc.l	$ff644e75,$1d7c000a,$ff644e75,$02000030
+	dc.l	$00000040,$60080200,$00300000,$00802d40
+	dc.l	$ff5c122e,$ff4e6600,$025c0200,$00c0667e
+	dc.l	$2d680004,$ff882d68,$0008ff8c,$32280000
+	dc.l	$0881000f,$3d41ff84,$f22ed080,$ff844e75
+	dc.l	$020000c0,$665808ee,$0003ff66,$2d680004
+	dc.l	$ff882d68,$0008ff8c,$30280000,$0880000f
+	dc.l	$3d40ff84,$f22ed080,$ff84082e,$0003ff62
+	dc.l	$66024e75,$41eeff84,$61ffffff,$e41e4440
+	dc.l	$06406000,$322eff84,$02418000,$02407fff
+	dc.l	$80413d40,$ff84f22e,$d040ff84,$4e750c00
+	dc.l	$0040667e,$3d680000,$ff842d68,$0004ff88
+	dc.l	$2d680008,$ff8c61ff,$ffffdf80,$0c800000
+	dc.l	$007f6c00,$00900c80,$ffffff81,$67000170
+	dc.l	$6d0000ec,$f23c8800,$00000000,$f22e9000
+	dc.l	$ff5cf22e,$4818ff84,$f201a800,$f23c9000
+	dc.l	$00000000,$83aeff64,$2f02f22e,$f080ff84
+	dc.l	$322eff84,$24010281,$00007fff,$92800242
+	dc.l	$80008441,$3d42ff84,$241ff22e,$d080ff84
+	dc.l	$4e753d68,$0000ff84,$2d680004,$ff882d68
+	dc.l	$0008ff8c,$61ffffff,$df020c80,$000003ff
+	dc.l	$6c120c80,$fffffc01,$670000f4,$6d000070
+	dc.l	$6000ff82,$08ee0003,$ff6608ae,$0007ff84
+	dc.l	$122eff62,$0201000b,$661a41ee,$ff84222e
+	dc.l	$ff5c61ff,$ffffe54a,$812eff64,$f22ed080
+	dc.l	$ff844e75,$2d6eff88,$ff942d6e,$ff8cff98
+	dc.l	$322eff84,$2f022401,$02810000,$7fff0242
+	dc.l	$80009280,$06810000,$60000241,$7fff8242
+	dc.l	$3d41ff90,$f22ed040,$ff90241f,$60acf23c
+	dc.l	$88000000,$0000f22e,$9000ff5c,$f22e4818
+	dc.l	$ff84f23c,$90000000,$0000f201,$a80083ae
+	dc.l	$ff6400ae,$00001048,$ff64122e,$ff620201
+	dc.l	$0013661c,$082e0003,$ff6456c1,$202eff5c
+	dc.l	$61ffffff,$e5ba812e,$ff64f210,$d0804e75
+	dc.l	$2f02322e,$ff842401,$02810000,$7fff0242
+	dc.l	$80009280,$04810000,$60000241,$7fff8242
+	dc.l	$3d41ff84,$f22ed040,$ff84241f,$60b6f23c
+	dc.l	$88000000,$0000f22e,$9000ff5c,$f22e4818
+	dc.l	$ff84f201,$a800f23c,$90000000,$000083ae
+	dc.l	$ff64f200,$0098f23c,$58b80002,$f293ff74
+	dc.l	$6000fe86,$0c010004,$6700fdc6,$0c010005
+	dc.l	$67ffffff,$deb40c01,$000367ff,$ffffdebe
+	dc.l	$f2284818,$00000c01,$00026708,$1d7c0004
+	dc.l	$ff644e75,$1d7c0002,$ff644e75,$4241122e
+	dc.l	$ff4fe709,$822eff4e,$6618f229,$d0800000
+	dc.l	$f2284838,$0000f200,$a800e198,$1d40ff64
+	dc.l	$4e75323b,$120a4efb,$10064afc,$0030ffdc
+	dc.l	$ffdcffdc,$006000f8,$006e0000,$0000ffdc
+	dc.l	$ffdcffdc,$0060007c,$006e0000,$0000ffdc
+	dc.l	$ffdcffdc,$0060007c,$006e0000,$00000060
+	dc.l	$00600060,$00600060,$006e0000,$00000114
+	dc.l	$009c009c,$006000bc,$006e0000,$0000006e
+	dc.l	$006e006e,$006e006e,$006e0000,$000061ff
+	dc.l	$ffffddde,$022e00f7,$ff644e75,$61ffffff
+	dc.l	$ddd0022e,$00f7ff64,$4e753d68,$0000ff84
+	dc.l	$20280004,$08c0001f,$2d40ff88,$2d680008
+	dc.l	$ff8c41ee,$ff846000,$ff422d69,$0000ff84
+	dc.l	$20290004,$08c0001f,$2d40ff88,$2d690008
+	dc.l	$ff8c43ee,$ff846000,$ff223d69,$0000ff90
+	dc.l	$3d680000,$ff842029,$000408c0,$001f2d40
+	dc.l	$ff942028,$000408c0,$001f2d40,$ff882d69
+	dc.l	$0008ff98,$2d680008,$ff8c43ee,$ff9041ee
+	dc.l	$ff846000,$fee61028,$00001229,$0000b101
+	dc.l	$6b00ff78,$4a006b02,$4e751d7c,$0008ff64
+	dc.l	$4e751028,$00001229,$0000b101,$6b00ff7c
+	dc.l	$4a006a02,$4e751d7c,$0008ff64,$4e752d40
+	dc.l	$ff5c4241,$122eff4f,$e709822e,$ff4e6600
+	dc.l	$02a03d69,$0000ff90,$2d690004,$ff942d69
+	dc.l	$0008ff98,$3d680000,$ff842d68,$0004ff88
+	dc.l	$2d680008,$ff8c61ff,$ffffdbf0,$2f0061ff
+	dc.l	$ffffdc94,$d09f0c80,$ffffc001,$670000f8
+	dc.l	$6d000064,$0c800000,$40006700,$01da6e00
+	dc.l	$0122f22e,$d080ff90,$f22e9000,$ff5cf23c
+	dc.l	$88000000,$0000f22e,$4827ff84,$f201a800
+	dc.l	$f23c9000,$00000000,$83aeff64,$f22ef080
+	dc.l	$ff842f02,$322eff84,$24010281,$00007fff
+	dc.l	$02428000,$92808242,$3d41ff84,$241ff22e
+	dc.l	$d080ff84,$4e75f22e,$d080ff90,$f22e9000
+	dc.l	$ff5cf23c,$88000000,$0000f22e,$4827ff84
+	dc.l	$f201a800,$f23c9000,$00000000,$83aeff64
+	dc.l	$00ae0000,$1048ff64,$122eff62,$02010013
+	dc.l	$6620082e,$0003ff64,$56c1202e,$ff5c0200
+	dc.l	$003061ff,$ffffe2a8,$812eff64,$f210d080
+	dc.l	$4e75f22e,$f080ff84,$2f02322e,$ff842401
+	dc.l	$02810000,$7fff9280,$04810000,$60000241
+	dc.l	$7fff0242,$80008242,$3d41ff84,$241ff22e
+	dc.l	$d040ff84,$60acf22e,$d080ff90,$f22e9000
+	dc.l	$ff5cf23c,$88000000,$0000f22e,$4827ff84
+	dc.l	$f201a800,$f23c9000,$00000000,$83aeff64
+	dc.l	$f2000098,$f23c58b8,$0002f293,$ff646000
+	dc.l	$ff0c08ee,$0003ff66,$f22ed080,$ff90f23c
+	dc.l	$90000000,$0010f23c,$88000000,$0000f22e
+	dc.l	$4827ff84,$f201a800,$f23c9000,$00000000
+	dc.l	$83aeff64,$122eff62,$0201000b,$6620f22e
+	dc.l	$f080ff84,$41eeff84,$222eff5c,$61ffffff
+	dc.l	$e166812e,$ff64f22e,$d080ff84,$4e75f22e
+	dc.l	$d040ff90,$f22e9000,$ff5cf23c,$88000000
+	dc.l	$0000f22e,$48a7ff84,$f23c9000,$00000000
+	dc.l	$f22ef040,$ff842f02,$322eff84,$24010281
+	dc.l	$00007fff,$02428000,$92800681,$00006000
+	dc.l	$02417fff,$82423d41,$ff84241f,$f22ed040
+	dc.l	$ff846000,$ff8af22e,$d080ff90,$f22e9000
+	dc.l	$ff5cf23c,$88000000,$0000f22e,$4827ff84
+	dc.l	$f201a800,$f23c9000,$00000000,$83aeff64
+	dc.l	$f2000098,$f23c58b8,$0002f292,$fe20f294
+	dc.l	$ff12f22e,$d040ff90,$222eff5c,$020100c0
+	dc.l	$00010010,$f2019000,$f23c8800,$00000000
+	dc.l	$f22e48a7,$ff84f23c,$90000000,$0000f200
+	dc.l	$0498f23c,$58b80002,$f293fde2,$6000fed4
+	dc.l	$323b120a,$4efb1006,$4afc0030,$fd560072
+	dc.l	$0078006c,$fd560066,$00000000,$00720072
+	dc.l	$0060006c,$00720066,$00000000,$007e0060
+	dc.l	$007e006c,$007e0066,$00000000,$006c006c
+	dc.l	$006c006c,$006c0066,$00000000,$fd560072
+	dc.l	$0078006c,$fd560066,$00000000,$00660066
+	dc.l	$00660066,$00660066,$00000000,$60ffffff
+	dc.l	$da7460ff,$ffffd9ea,$60ffffff,$d9e460ff
+	dc.l	$ffffed0e,$60ffffff,$ed6260ff,$ffffed2e
+	dc.l	$2d40ff5c,$4241122e,$ff4fe709,$822eff4e
+	dc.l	$6600027c,$3d690000,$ff902d69,$0004ff94
+	dc.l	$2d690008,$ff983d68,$0000ff84,$2d680004
+	dc.l	$ff882d68,$0008ff8c,$61ffffff,$d8ae2f00
+	dc.l	$61ffffff,$d9524497,$d197322e,$ff5eec09
+	dc.l	$201f0c80,$ffffc001,$6f000064,$0c800000
+	dc.l	$3fff6700,$01b66e00,$0100f22e,$d080ff90
+	dc.l	$f22e9000,$ff5cf23c,$88000000,$0000f22e
+	dc.l	$4824ff84,$f201a800,$f23c9000,$00000000
+	dc.l	$83aeff64,$f22ef080,$ff842f02,$322eff84
+	dc.l	$24010281,$00007fff,$02428000,$92808242
+	dc.l	$3d41ff84,$241ff22e,$d080ff84,$4e75f22e
+	dc.l	$d080ff90,$f22e9000,$ff5cf23c,$88000000
+	dc.l	$0000f22e,$4824ff84,$f201a800,$f23c9000
+	dc.l	$00000000,$83aeff64,$f227e001,$3217dffc
+	dc.l	$0000000c,$02810000,$7fff9280,$0c810000
+	dc.l	$7fff6d90,$006e1048,$ff66122e,$ff620201
+	dc.l	$00136620,$082e0003,$ff6456c1,$202eff5c
+	dc.l	$02000030,$61ffffff,$df46812e,$ff64f210
+	dc.l	$d0804e75,$f22ef080,$ff842f02,$322eff84
+	dc.l	$24010281,$00007fff,$02428000,$92800481
+	dc.l	$00006000,$02417fff,$82423d41,$ff84241f
+	dc.l	$f22ed040,$ff8460ac,$08ee0003,$ff66f22e
+	dc.l	$d080ff90,$f23c9000,$00000010,$f23c8800
+	dc.l	$00000000,$f22e4824,$ff84f201,$a800f23c
+	dc.l	$90000000,$000083ae,$ff64122e,$ff620201
+	dc.l	$000b6620,$f22ef080,$ff8441ee,$ff84222e
+	dc.l	$ff5c61ff,$ffffde40,$812eff64,$f22ed080
+	dc.l	$ff844e75,$f22ed040,$ff90f22e,$9000ff5c
+	dc.l	$f23c8800,$00000000,$f22e48a4,$ff84f23c
+	dc.l	$90000000,$0000f22e,$f040ff84,$2f02322e
+	dc.l	$ff842401,$02810000,$7fff0242,$80009280
+	dc.l	$06810000,$60000241,$7fff8242,$3d41ff84
+	dc.l	$241ff22e,$d040ff84,$608af22e,$d080ff90
+	dc.l	$f22e9000,$ff5cf23c,$88000000,$0000f22e
+	dc.l	$4824ff84,$f201a800,$f23c9000,$00000000
+	dc.l	$83aeff64,$f2000098,$f23c58b8,$0001f292
+	dc.l	$fe44f294,$ff14f22e,$d040ff90,$42810001
+	dc.l	$0010f201,$9000f23c,$88000000,$0000f22e
+	dc.l	$48a4ff84,$f23c9000,$00000000,$f2000498
+	dc.l	$f23c58b8,$0001f293,$fe0c6000,$fedc323b
+	dc.l	$120a4efb,$10064afc,$0030fd7a,$00720078
+	dc.l	$0060fd7a,$00660000,$00000078,$006c0078
+	dc.l	$00600078,$00660000,$0000007e,$007e006c
+	dc.l	$0060007e,$00660000,$00000060,$00600060
+	dc.l	$00600060,$00660000,$0000fd7a,$00720078
+	dc.l	$0060fd7a,$00660000,$00000066,$00660066
+	dc.l	$00660066,$00660000,$000060ff,$ffffd6d2
+	dc.l	$60ffffff,$d6cc60ff,$ffffd74a,$60ffffff
+	dc.l	$f0ce60ff,$fffff09c,$60ffffff,$f0f40200
+	dc.l	$00300000,$00406008,$02000030,$00000080
+	dc.l	$2d40ff5c,$4241122e,$ff4fe709,$822eff4e
+	dc.l	$6600024c,$61ffffff,$d4b2f22e,$d080ff90
+	dc.l	$f23c8800,$00000000,$f22e9000,$ff5cf22e
+	dc.l	$4822ff84,$f23c9000,$00000000,$f201a800
+	dc.l	$83aeff64,$f281003c,$2f02f227,$e001322e
+	dc.l	$ff5eec09,$34170282,$00007fff,$9480b4bb
+	dc.l	$14246c38,$b4bb142a,$6d0000b8,$67000184
+	dc.l	$32170241,$80008242,$3e81f21f,$d080241f
+	dc.l	$4e754e75,$00007fff,$0000407f,$000043ff
+	dc.l	$00000000,$00003f81,$00003c01,$00ae0000
+	dc.l	$1048ff64,$122eff62,$02010013,$6624dffc
+	dc.l	$0000000c,$082e0003,$ff6456c1,$202eff5c
+	dc.l	$61ffffff,$dc7a812e,$ff64f210,$d080241f
+	dc.l	$4e75122e,$ff5c0201,$00c0661a,$32170241
+	dc.l	$80000482,$00006000,$02427fff,$82423e81
+	dc.l	$f21fd040,$60bef22e,$d080ff90,$222eff5c
+	dc.l	$02010030,$f2019000,$f22e4822,$ff84f23c
+	dc.l	$90000000,$0000dffc,$0000000c,$f227e001
+	dc.l	$60ba08ee,$0003ff66,$dffc0000,$000cf22e
+	dc.l	$d080ff90,$f23c9000,$00000010,$f23c8800
+	dc.l	$00000000,$f22e4822,$ff84f23c,$90000000
+	dc.l	$0000f201,$a80083ae,$ff64122e,$ff620201
+	dc.l	$000b6622,$f22ef080,$ff8441ee,$ff84222e
+	dc.l	$ff5c61ff,$ffffdaca,$812eff64,$f22ed080
+	dc.l	$ff84241f,$4e75f22e,$d040ff90,$222eff5c
+	dc.l	$020100c0,$664ef22e,$9000ff5c,$f23c8800
+	dc.l	$00000000,$f22e48a2,$ff84f23c,$90000000
+	dc.l	$0000f22e,$f040ff84,$322eff84,$24010281
+	dc.l	$00007fff,$02428000,$92800681,$00006000
+	dc.l	$02417fff,$82423d41,$ff84f22e,$d040ff84
+	dc.l	$6000ff82,$222eff5c,$02010030,$f2019000
+	dc.l	$60aa222e,$ff5c0201,$00c06700,$fe74222f
+	dc.l	$00040c81,$80000000,$6600fe66,$4aaf0008
+	dc.l	$6600fe5e,$082e0001,$ff666700,$fe54f22e
+	dc.l	$d040ff90,$222eff5c,$020100c0,$00010010
+	dc.l	$f2019000,$f23c8800,$00000000,$f22e48a2
+	dc.l	$ff84f23c,$90000000,$0000f200,$0018f200
+	dc.l	$0498f200,$0438f292,$feca6000,$fe14323b
+	dc.l	$120a4efb,$10064afc,$0030fdaa,$00e4011c
+	dc.l	$0060fdaa,$00660000,$000000bc,$006c011c
+	dc.l	$006000bc,$00660000,$00000130,$0130010c
+	dc.l	$00600130,$00660000,$00000060,$00600060
+	dc.l	$00600060,$00660000,$0000fdaa,$00e4011c
+	dc.l	$0060fdaa,$00660000,$00000066,$00660066
+	dc.l	$00660066,$00660000,$000060ff,$ffffd3d2
+	dc.l	$60ffffff,$d3cc1028,$00001229,$0000b101
+	dc.l	$6b000016,$4a006b2e,$f23c4400,$00000000
+	dc.l	$1d7c0004,$ff644e75,$122eff5f,$02010030
+	dc.l	$0c010020,$6710f23c,$44000000,$00001d7c
+	dc.l	$0004ff64,$4e75f23c,$44008000,$00001d7c
+	dc.l	$000cff64,$4e753d68,$0000ff84,$2d680004
+	dc.l	$ff882d68,$0008ff8c,$61ffffff,$d27e426e
+	dc.l	$ff9042ae,$ff9442ae,$ff986000,$fcce3d69
+	dc.l	$0000ff90,$2d690004,$ff942d69,$0008ff98
+	dc.l	$61ffffff,$d302426e,$ff8442ae,$ff8842ae
+	dc.l	$ff8c6000,$fca61028,$00001229,$0000b300
+	dc.l	$6bffffff,$d3a0f228,$d0800000,$4a280000
+	dc.l	$6a1c1d7c,$000aff64,$4e75f229,$d0800000
+	dc.l	$4a290000,$6a081d7c,$000aff64,$4e751d7c
+	dc.l	$0002ff64,$4e750200,$00300000,$00406008
+	dc.l	$02000030,$00000080,$2d40ff5c,$4241122e
+	dc.l	$ff4fe709,$822eff4e,$6600024c,$61ffffff
+	dc.l	$d0eaf22e,$d080ff90,$f23c8800,$00000000
+	dc.l	$f22e9000,$ff5cf22e,$4828ff84,$f23c9000
+	dc.l	$00000000,$f201a800,$83aeff64,$f281003c
+	dc.l	$2f02f227,$e001322e,$ff5eec09,$34170282
+	dc.l	$00007fff,$9480b4bb,$14246c38,$b4bb142a
+	dc.l	$6d0000b8,$67000184,$32170241,$80008242
+	dc.l	$3e81f21f,$d080241f,$4e754e75,$00007fff
+	dc.l	$0000407f,$000043ff,$00000000,$00003f81
+	dc.l	$00003c01,$00ae0000,$1048ff64,$122eff62
+	dc.l	$02010013,$6624dffc,$0000000c,$082e0003
+	dc.l	$ff6456c1,$202eff5c,$61ffffff,$d8b2812e
+	dc.l	$ff64f210,$d080241f,$4e75122e,$ff5c0201
+	dc.l	$00c0661a,$32170241,$80000482,$00006000
+	dc.l	$02427fff,$82423e81,$f21fd040,$60bef22e
+	dc.l	$d080ff90,$222eff5c,$02010030,$f2019000
+	dc.l	$f22e4828,$ff84f23c,$90000000,$0000dffc
+	dc.l	$0000000c,$f227e001,$60ba08ee,$0003ff66
+	dc.l	$dffc0000,$000cf22e,$d080ff90,$f23c9000
+	dc.l	$00000010,$f23c8800,$00000000,$f22e4828
+	dc.l	$ff84f23c,$90000000,$0000f201,$a80083ae
+	dc.l	$ff64122e,$ff620201,$000b6622,$f22ef080
+	dc.l	$ff8441ee,$ff84222e,$ff5c61ff,$ffffd702
+	dc.l	$812eff64,$f22ed080,$ff84241f,$4e75f22e
+	dc.l	$d040ff90,$222eff5c,$020100c0,$664ef22e
+	dc.l	$9000ff5c,$f23c8800,$00000000,$f22e48a8
+	dc.l	$ff84f23c,$90000000,$0000f22e,$f040ff84
+	dc.l	$322eff84,$24010281,$00007fff,$02428000
+	dc.l	$92800681,$00006000,$02417fff,$82423d41
+	dc.l	$ff84f22e,$d040ff84,$6000ff82,$222eff5c
+	dc.l	$02010030,$f2019000,$60aa222e,$ff5c0201
+	dc.l	$00c06700,$fe74222f,$00040c81,$80000000
+	dc.l	$6600fe66,$4aaf0008,$6600fe5e,$082e0001
+	dc.l	$ff666700,$fe54f22e,$d040ff90,$222eff5c
+	dc.l	$020100c0,$00010010,$f2019000,$f23c8800
+	dc.l	$00000000,$f22e48a8,$ff84f23c,$90000000
+	dc.l	$0000f200,$0018f200,$0498f200,$0438f292
+	dc.l	$feca6000,$fe14323b,$120a4efb,$10064afc
+	dc.l	$0030fdaa,$00e2011a,$0060fdaa,$00660000
+	dc.l	$000000ba,$006c011a,$006000ba,$00660000
+	dc.l	$00000130,$0130010a,$00600130,$00660000
+	dc.l	$00000060,$00600060,$00600060,$00660000
+	dc.l	$0000fdaa,$00e2011a,$0060fdaa,$00660000
+	dc.l	$00000066,$00660066,$00660066,$00660000
+	dc.l	$000060ff,$ffffd00a,$60ffffff,$d0041028
+	dc.l	$00001229,$0000b300,$6a144a00,$6b2ef23c
+	dc.l	$44000000,$00001d7c,$0004ff64,$4e75122e
+	dc.l	$ff5f0201,$00300c01,$00206710,$f23c4400
+	dc.l	$00000000,$1d7c0004,$ff644e75,$f23c4400
+	dc.l	$80000000,$1d7c000c,$ff644e75,$3d680000
+	dc.l	$ff842d68,$0004ff88,$2d680008,$ff8c61ff
+	dc.l	$ffffceb8,$426eff90,$42aeff94,$42aeff98
+	dc.l	$6000fcd0,$3d690000,$ff902d69,$0004ff94
+	dc.l	$2d690008,$ff9861ff,$ffffcf3c,$426eff84
+	dc.l	$42aeff88,$42aeff8c,$6000fca8,$10280000
+	dc.l	$12290000,$b3006aff,$ffffcfda,$f228d080
+	dc.l	$0000f200,$001af293,$001e1d7c,$000aff64
+	dc.l	$4e75f229,$d0800000,$4a290000,$6a081d7c
+	dc.l	$000aff64,$4e751d7c,$0002ff64,$4e750200
+	dc.l	$00300000,$00406008,$02000030,$00000080
+	dc.l	$2d40ff5c,$4241122e,$ff4e6600,$02744a28
+	dc.l	$00006bff,$ffffcf7e,$020000c0,$6648f22e
+	dc.l	$9000ff5c,$f23c8800,$00000000,$f2104804
+	dc.l	$f201a800,$83aeff64,$4e754a28,$00006bff
+	dc.l	$ffffcf52,$020000c0,$661c3d68,$0000ff84
+	dc.l	$2d680004,$ff882d68,$0008ff8c,$61ffffff
+	dc.l	$ce046000,$003e0c00,$00406600,$00843d68
+	dc.l	$0000ff84,$2d680004,$ff882d68,$0008ff8c
+	dc.l	$61ffffff,$cde00c80,$0000007e,$67000098
+	dc.l	$6e00009e,$0c80ffff,$ff806700,$01a46d00
+	dc.l	$0120f23c,$88000000,$0000f22e,$9000ff5c
+	dc.l	$f22e4804,$ff84f201,$a800f23c,$90000000
+	dc.l	$000083ae,$ff642f02,$f22ef080,$ff84322e
+	dc.l	$ff842401,$02810000,$7fff9280,$02428000
+	dc.l	$84413d42,$ff84241f,$f22ed080,$ff844e75
+	dc.l	$3d680000,$ff842d68,$0004ff88,$2d680008
+	dc.l	$ff8c61ff,$ffffcd5e,$0c800000,$03fe6700
+	dc.l	$00166e1c,$0c80ffff,$fc006700,$01246d00
+	dc.l	$00a06000,$ff7e082e,$0000ff85,$6600ff74
+	dc.l	$08ee0003,$ff66f23c,$90000000,$0010f23c
+	dc.l	$88000000,$0000f22e,$4804ff84,$f201a800
+	dc.l	$f23c9000,$00000000,$83aeff64,$122eff62
+	dc.l	$0201000b,$6620f22e,$f080ff84,$41eeff84
+	dc.l	$222eff5c,$61ffffff,$d338812e,$ff64f22e
+	dc.l	$d080ff84,$4e752d6e,$ff88ff94,$2d6eff8c
+	dc.l	$ff98322e,$ff842f02,$24010281,$00007fff
+	dc.l	$02428000,$92800681,$00006000,$02417fff
+	dc.l	$82423d41,$ff90f22e,$d040ff90,$241f60a6
+	dc.l	$f23c8800,$00000000,$f22e9000,$ff5cf22e
+	dc.l	$4804ff84,$f23c9000,$00000000,$f201a800
+	dc.l	$83aeff64,$00ae0000,$1048ff64,$122eff62
+	dc.l	$02010013,$661c082e,$0003ff64,$56c1202e
+	dc.l	$ff5c61ff,$ffffd3a8,$812eff64,$f210d080
+	dc.l	$4e752f02,$322eff84,$24010281,$00007fff
+	dc.l	$02428000,$92800481,$00006000,$02417fff
+	dc.l	$82423d41,$ff84f22e,$d040ff84,$241f60b6
+	dc.l	$082e0000,$ff856600,$ff78f23c,$88000000
+	dc.l	$0000f22e,$9000ff5c,$f22e4804,$ff84f201
+	dc.l	$a800f23c,$90000000,$000083ae,$ff64f200
+	dc.l	$0080f23c,$58b80001,$f293ff6a,$6000fe48
+	dc.l	$0c010004,$6700fdb4,$0c010001,$67160c01
+	dc.l	$00026736,$0c010005,$67ffffff,$cc8c60ff
+	dc.l	$ffffcc9a,$4a280000,$6b10f23c,$44000000
+	dc.l	$00001d7c,$0004ff64,$4e75f23c,$44008000
+	dc.l	$00001d7c,$000cff64,$4e754a28,$00006bff
+	dc.l	$ffffccc2,$f228d080,$00001d7c,$0002ff64
+	dc.l	$4e75303b,$12064efb,$00020020,$0026002c
+	dc.l	$00300034,$0038003c,$00400044,$004a0050
+	dc.l	$00540058,$005c0060,$0064202e,$ff9c4e75
+	dc.l	$202effa0,$4e752002,$4e752003,$4e752004
+	dc.l	$4e752005,$4e752006,$4e752007,$4e75202e
+	dc.l	$ffa44e75,$202effa8,$4e75200a,$4e75200b
+	dc.l	$4e75200c,$4e75200d,$4e752016,$4e75202e
+	dc.l	$ffd84e75,$323b1206,$4efb1002,$00100016
+	dc.l	$001c0020,$00240028,$002c0030,$2d40ff9c
+	dc.l	$4e752d40,$ffa04e75,$24004e75,$26004e75
+	dc.l	$28004e75,$2a004e75,$2c004e75,$2e004e75
+	dc.l	$323b1206,$4efb1002,$00100016,$001c0020
+	dc.l	$00240028,$002c0030,$3d40ff9e,$4e753d40
+	dc.l	$ffa24e75,$34004e75,$36004e75,$38004e75
+	dc.l	$3a004e75,$3c004e75,$3e004e75,$323b1206
+	dc.l	$4efb1002,$00100016,$001c0020,$00240028
+	dc.l	$002c0030,$1d40ff9f,$4e751d40,$ffa34e75
+	dc.l	$14004e75,$16004e75,$18004e75,$1a004e75
+	dc.l	$1c004e75,$1e004e75,$323b1206,$4efb1002
+	dc.l	$00100016,$001c0020,$00240028,$002c0030
+	dc.l	$d1aeffa4,$4e75d1ae,$ffa84e75,$d5c04e75
+	dc.l	$d7c04e75,$d9c04e75,$dbc04e75,$d1964e75
+	dc.l	$1d7c0004,$ff4a0c00,$00016706,$d1aeffd8
+	dc.l	$4e7554ae,$ffd84e75,$323b1206,$4efb1002
+	dc.l	$00100016,$001c0020,$00240028,$002c0030
+	dc.l	$91aeffa4,$4e7591ae,$ffa84e75,$95c04e75
+	dc.l	$97c04e75,$99c04e75,$9bc04e75,$91964e75
+	dc.l	$1d7c0008,$ff4a0c00,$00016706,$91aeffd8
+	dc.l	$4e7555ae,$ffd84e75,$303b0206,$4efb0002
+	dc.l	$00100028,$0040004c,$00580064,$0070007c
+	dc.l	$2d6effdc,$ff6c2d6e,$ffe0ff70,$2d6effe4
+	dc.l	$ff7441ee,$ff6c4e75,$2d6effe8,$ff6c2d6e
+	dc.l	$ffecff70,$2d6efff0,$ff7441ee,$ff6c4e75
+	dc.l	$f22ef020,$ff6c41ee,$ff6c4e75,$f22ef010
+	dc.l	$ff6c41ee,$ff6c4e75,$f22ef008,$ff6c41ee
+	dc.l	$ff6c4e75,$f22ef004,$ff6c41ee,$ff6c4e75
+	dc.l	$f22ef002,$ff6c41ee,$ff6c4e75,$f22ef001
+	dc.l	$ff6c41ee,$ff6c4e75,$303b0206,$4efb0002
+	dc.l	$00100028,$0040004c,$00580064,$0070007c
+	dc.l	$2d6effdc,$ff782d6e,$ffe0ff7c,$2d6effe4
+	dc.l	$ff8041ee,$ff784e75,$2d6effe8,$ff782d6e
+	dc.l	$ffecff7c,$2d6efff0,$ff8041ee,$ff784e75
+	dc.l	$f22ef020,$ff7841ee,$ff784e75,$f22ef010
+	dc.l	$ff7841ee,$ff784e75,$f22ef008,$ff7841ee
+	dc.l	$ff784e75,$f22ef004,$ff7841ee,$ff784e75
+	dc.l	$f22ef002,$ff7841ee,$ff784e75,$f22ef001
+	dc.l	$ff7841ee,$ff784e75,$303b0206,$4efb0002
+	dc.l	$00100018,$0020002a,$0034003e,$00480052
+	dc.l	$f22ef080,$ffdc4e75,$f22ef080,$ffe84e75
+	dc.l	$f227e001,$f21fd020,$4e75f227,$e001f21f
+	dc.l	$d0104e75,$f227e001,$f21fd008,$4e75f227
+	dc.l	$e001f21f,$d0044e75,$f227e001,$f21fd002
+	dc.l	$4e75f227,$e001f21f,$d0014e75,$700c61ff
+	dc.l	$ffffbace,$43eeff6c,$700c61ff,$ffffa0d8
+	dc.l	$4a8166ff,$00000a14,$e9ee004f,$ff6c0c40
+	dc.l	$7fff6602,$4e75102e,$ff6f0200,$000f660e
+	dc.l	$4aaeff70,$66084aae,$ff746602,$4e7541ee
+	dc.l	$ff6c61ff,$0000001c,$f22ef080,$ff6c4e75
+	dc.l	$00000000,$02030203,$02030302,$03020203
+	dc.l	$2d680000,$ff842d68,$0004ff88,$2d680008
+	dc.l	$ff8c41ee,$ff8448e7,$3c00f227,$e0017402
+	dc.l	$76042810,$42814c3c,$10010000,$000ae9c4
+	dc.l	$08c4d280,$580351ca,$ffee0804,$001e6702
+	dc.l	$44810481,$00000010,$6c0e4481,$00844000
+	dc.l	$00000090,$40000000,$2f017201,$f23c4400
+	dc.l	$00000000,$e9d00704,$f2005822,$28301c00
+	dc.l	$76007407,$f23c4423,$41200000,$e9c408c4
+	dc.l	$f2005822,$580351ca,$ffec5281,$0c810000
+	dc.l	$00026fd8,$0810001f,$6704f200,$001a2217
+	dc.l	$0c810000,$001b6f00,$00e40810,$001e6674
+	dc.l	$42812810,$e9c40704,$66245281,$7a012830
+	dc.l	$5c006608,$50815285,$28305c00,$42837407
+	dc.l	$e9c408c4,$66085883,$528151ca,$fff42001
+	dc.l	$22179280,$6c104481,$28100084,$40000000
+	dc.l	$00904000,$000043fb,$01700000,$06664283
+	dc.l	$f23c4480,$3f800000,$7403e280,$6406f231
+	dc.l	$48a33800,$06830000,$000c4a80,$66ecf200
+	dc.l	$04236068,$42817a02,$28305c00,$66085385
+	dc.l	$50812830,$5c00761c,$7407e9c4,$08c46608
+	dc.l	$59835281,$51cafff4,$20012217,$92806e10
+	dc.l	$44812810,$0284bfff,$ffff0290,$bfffffff
+	dc.l	$43fb0170,$000005fc,$4283f23c,$44803f80
+	dc.l	$00007403,$e2806406,$f23148a3,$38000683
+	dc.l	$0000000c,$4a8066ec,$f2000420,$262eff60
+	dc.l	$e9c32682,$2810e582,$e9c40002,$d48043fa
+	dc.l	$fe501031,$28004283,$efc30682,$f2039000
+	dc.l	$e280640a,$43fb0170,$00000644,$6016e280
+	dc.l	$640a43fb,$01700000,$06d26008,$43fb0170
+	dc.l	$00000590,$20016a08,$44800090,$40000000
+	dc.l	$4283f23c,$44803f80,$0000e280,$6406f231
+	dc.l	$48a33800,$06830000,$000c4a80,$66ec0810
+	dc.l	$001e6706,$f2000420,$6004f200,$0423f200
+	dc.l	$a8000880,$00096706,$006e0108,$ff66588f
+	dc.l	$f21fd040,$4cdf003c,$f23c9000,$00000000
+	dc.l	$f23c8800,$00000000,$4e753ffd,$00009a20
+	dc.l	$9a84fbcf,$f7980000,$00003ffd,$00009a20
+	dc.l	$9a84fbcf,$f7990000,$00003f80,$00000000
+	dc.l	$00000000,$00000000,$00004000,$00000000
+	dc.l	$00000000,$00000000,$00004120,$00000000
+	dc.l	$00000000,$00000000,$0000459a,$28000000
+	dc.l	$00000000,$00000000,$00000000,$00000303
+	dc.l	$02020302,$02030203,$030248e7,$3f20f227
+	dc.l	$e007f23c,$90000000,$00202d50,$ff582e00
+	dc.l	$422eff50,$0c2e0004,$ff4e6600,$00303010
+	dc.l	$02407fff,$22280004,$24280008,$5340e38a
+	dc.l	$e3914a81,$6cf64a40,$6e0450ee,$ff500240
+	dc.l	$7fff3080,$21410004,$21420008,$2d50ff90
+	dc.l	$2d680004,$ff942d68,$0008ff98,$02ae7fff
+	dc.l	$ffffff90,$4a2eff50,$67082c3c,$ffffecbb
+	dc.l	$6038302e,$ff903d7c,$3fffff90,$f22e4800
+	dc.l	$ff900440,$3ffff200,$5022f23a,$4428ff1c
+	dc.l	$f293000e,$f23a4823,$ff02f206,$6000600a
+	dc.l	$f23a4823,$fee6f206,$6000f23c,$88000000
+	dc.l	$00004245,$4a876f04,$28076006,$28069887
+	dc.l	$52844a84,$6f180c84,$00000011,$6f127811
+	dc.l	$4a876f0c,$00ae0000,$2080ff64,$60027801
+	dc.l	$4a876e06,$be866d02,$2c072006,$52809084
+	dc.l	$48454245,$42424a80,$6c145245,$0c80ffff
+	dc.l	$ecd46e08,$06800000,$00187418,$4480f23a
+	dc.l	$4480fe98,$e9ee1682,$ff60e349,$d245e349
+	dc.l	$4aaeff58,$6c025281,$45fafec0,$16321800
+	dc.l	$e98bf203,$9000e88b,$4a03660a,$43fb0170
+	dc.l	$00000370,$6016e20b,$640a43fb,$01700000
+	dc.l	$03fe6008,$43fb0170,$00000490,$4283e288
+	dc.l	$6406f231,$48a33800,$06830000,$000c4a80
+	dc.l	$66ecf23c,$88000000,$0000f23c,$90000000
+	dc.l	$0010f210,$4800f200,$00184a45,$6608f200
+	dc.l	$04206000,$008e4a2e,$ff506700,$0072f227
+	dc.l	$e0023617,$02437fff,$00508000,$d6500443
+	dc.l	$3fffd669,$00240443,$3fffd669,$00300443
+	dc.l	$3fff6b00,$00480257,$80008757,$02507fff
+	dc.l	$2f280008,$2f280004,$2f3c3fff,$0000f21f
+	dc.l	$d080f21f,$48232f29,$002c2f29,$00282f3c
+	dc.l	$3fff0000,$2f290038,$2f290034,$2f3c3fff
+	dc.l	$0000f21f,$4823f21f,$48236016,$60fe4a42
+	dc.l	$670cf229,$48230024,$f2294823,$0030f200
+	dc.l	$0423f200,$a800f22e,$6800ff90,$45eeff90
+	dc.l	$08000009,$670e00aa,$00000001,$0008f22e
+	dc.l	$4800ff90,$2d6eff60,$ff5402ae,$00000030
+	dc.l	$ff6048e7,$c0c02f2e,$ff542f2e,$ff5841ee
+	dc.l	$ff90f210,$68004aae,$ff586c06,$00908000
+	dc.l	$00002f2e,$ff64f22e,$9000ff60,$f23c8800
+	dc.l	$00000000,$f22e4801,$ff90f200,$a800816e
+	dc.l	$ff661d57,$ff64588f,$2d5fff58,$2d5fff54
+	dc.l	$4cdf0303,$2d6eff58,$ff902d6e,$ff54ff60
+	dc.l	$48454a45,$66ff0000,$0086f23a,$4500fcec
+	dc.l	$20045380,$4283e288,$6406f231,$49233800
+	dc.l	$06830000,$000c4a80,$66ec4a2e,$ff50670a
+	dc.l	$f2000018,$60ff0000,$0028f200,$0018f200
+	dc.l	$0838f293,$001a5386,$3a3c0001,$f23c9000
+	dc.l	$00000020,$f23a4523,$fcc26000,$fda8f23a
+	dc.l	$4523fcb8,$f2000838,$f294005c,$f292000c
+	dc.l	$f23a4420,$fca65286,$604c5286,$3a3c0001
+	dc.l	$f23c9000,$00000020,$6000fd7a,$f23a4500
+	dc.l	$fc6a2004,$4283e288,$6406f231,$49233800
+	dc.l	$06830000,$000c4a80,$66ecf200,$0018f200
+	dc.l	$0838f28e,$0012f23a,$4420fc60,$52865284
+	dc.l	$f23a4523,$fc56f23c,$90000000,$0010f200
+	dc.l	$082041ee,$ff84f210,$68002428,$00042628
+	dc.l	$000842a8,$000442a8,$00082010,$48406714
+	dc.l	$04800000,$3ffd4a80,$6e0a4480,$e28ae293
+	dc.l	$51c8fffa,$4a826604,$4a836710,$42810683
+	dc.l	$00000080,$d5810283,$ffffff80,$20045688
+	dc.l	$61ff0000,$02b04a2e,$ff506728,$f200003a
+	dc.l	$f281000c,$f2064000,$f2000018,$602e4a87
+	dc.l	$6d08f23a,$4400fbe4,$6022f206,$4000f200
+	dc.l	$00186018,$f200003a,$f28e000a,$f23a4400
+	dc.l	$fb9a6008,$f2064000,$f2000018,$f2294820
+	dc.l	$0018f22e,$6800ff90,$242a0004,$262a0008
+	dc.l	$3012670e,$04403ffd,$4440e28a,$e29351c8
+	dc.l	$fffa4281,$06830000,$0080d581,$0283ffff
+	dc.l	$ff807004,$41eeff54,$61ff0000,$0228202e
+	dc.l	$ff54720c,$e2a8efee,$010cff84,$e2a8efee
+	dc.l	$0404ff84,$4a006708,$00ae0000,$2080ff64
+	dc.l	$4280022e,$000fff84,$4aaeff58,$6c027002
+	dc.l	$4a866c02,$5280efee,$0002ff84,$f23c8800
+	dc.l	$00000000,$f21fd0e0,$4cdf04fc,$4e754002
+	dc.l	$0000a000,$00000000,$00004005,$0000c800
+	dc.l	$00000000,$0000400c,$00009c40,$00000000
+	dc.l	$00004019,$0000bebc,$20000000,$00004034
+	dc.l	$00008e1b,$c9bf0400,$00004069,$00009dc5
+	dc.l	$ada82b70,$b59e40d3,$0000c278,$1f49ffcf
+	dc.l	$a6d541a8,$000093ba,$47c980e9,$8ce04351
+	dc.l	$0000aa7e,$ebfb9df9,$de8e46a3,$0000e319
+	dc.l	$a0aea60e,$91c74d48,$0000c976,$75868175
+	dc.l	$0c175a92,$00009e8b,$3b5dc53d,$5de57525
+	dc.l	$0000c460,$52028a20,$979b4002,$0000a000
+	dc.l	$00000000,$00004005,$0000c800,$00000000
+	dc.l	$0000400c,$00009c40,$00000000,$00004019
+	dc.l	$0000bebc,$20000000,$00004034,$00008e1b
+	dc.l	$c9bf0400,$00004069,$00009dc5,$ada82b70
+	dc.l	$b59e40d3,$0000c278,$1f49ffcf,$a6d641a8
+	dc.l	$000093ba,$47c980e9,$8ce04351,$0000aa7e
+	dc.l	$ebfb9df9,$de8e46a3,$0000e319,$a0aea60e
+	dc.l	$91c74d48,$0000c976,$75868175,$0c185a92
+	dc.l	$00009e8b,$3b5dc53d,$5de57525,$0000c460
+	dc.l	$52028a20,$979b4002,$0000a000,$00000000
+	dc.l	$00004005,$0000c800,$00000000,$0000400c
+	dc.l	$00009c40,$00000000,$00004019,$0000bebc
+	dc.l	$20000000,$00004034,$00008e1b,$c9bf0400
+	dc.l	$00004069,$00009dc5,$ada82b70,$b59d40d3
+	dc.l	$0000c278,$1f49ffcf,$a6d541a8,$000093ba
+	dc.l	$47c980e9,$8cdf4351,$0000aa7e,$ebfb9df9
+	dc.l	$de8d46a3,$0000e319,$a0aea60e,$91c64d48
+	dc.l	$0000c976,$75868175,$0c175a92,$00009e8b
+	dc.l	$3b5dc53d,$5de47525,$0000c460,$52028a20
+	dc.l	$979a48e7,$ff007e01,$53802802,$2a03e9c2
+	dc.l	$1003e782,$e9c36003,$e7838486,$e385e394
+	dc.l	$4846d346,$d6854e71,$d5844e71,$d3464846
+	dc.l	$4a476712,$4847e947,$de4110c7,$48474247
+	dc.l	$51c8ffc8,$60124847,$3e014847,$524751c8
+	dc.l	$ffba4847,$e94f10c7,$4cdf00ff,$4e757001
+	dc.l	$610000d6,$3d7c0121,$000a6000,$007e7002
+	dc.l	$610000c6,$3d7c0141,$000a606e,$70046100
+	dc.l	$00b83d7c,$0101000a,$60607008,$610000aa
+	dc.l	$3d7c0161,$000a6052,$700c6100,$009c3d7c
+	dc.l	$0161000a,$60447001,$6100008e,$3d7c00a1
+	dc.l	$000a6036,$70026100,$00803d7c,$00c1000a
+	dc.l	$60287004,$61000072,$3d7c0081,$000a601a
+	dc.l	$70086100,$00643d7c,$00e1000a,$600c700c
+	dc.l	$61000056,$3d7c00e1,$000a2d6e,$ff680006
+	dc.l	$f22ed0c0,$ffdcf22e,$9c00ff60,$4cee0303
+	dc.l	$ff9c4e5e,$2f172f6f,$00080004,$2f6f000c
+	dc.l	$00082f7c,$00000001,$000c3f6f,$0006000c
+	dc.l	$3f7c4008,$00060817,$00056706,$08ef0002
+	dc.l	$000d60ff,$ffff95f4,$122eff41,$02010038
+	dc.l	$0c010018,$6700000c,$0c010020,$67000060
+	dc.l	$4e75122e,$ff410241,$0007323b,$12064efb
+	dc.l	$10020010,$0016001c,$00200024,$0028002c
+	dc.l	$003091ae,$ffa44e75,$91aeffa8,$4e7595c0
+	dc.l	$4e7597c0,$4e7599c0,$4e759bc0,$4e759196
+	dc.l	$4e750c2e,$0030000a,$6612082e,$00050004
+	dc.l	$660a4e7a,$880091c0,$4e7b8800,$4e754480
+	dc.l	$60a051fc,$00000000,$00000000,$00000000
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/kernel/Makefile linux/arch/m68k/kernel/Makefile
--- v1.3.93/linux/arch/m68k/kernel/Makefile	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/kernel/Makefile	Mon Apr  1 21:46:31 1996
@@ -0,0 +1,21 @@
+#
+# 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...
+
+.S.o:
+	$(CC) -D__ASSEMBLY__ -traditional -Wa,-m68030 -c $< -o $*.o
+
+all: kernel.o head.o
+O_TARGET := kernel.o
+O_OBJS := entry.o process.o traps.o ints.o signal.o ptrace.o \
+	  setup.o bios32.o sys_m68k.o console.o time.o
+OX_OBJS = ksyms.o
+
+head.o: head.S
+
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/kernel/bios32.c linux/arch/m68k/kernel/bios32.c
--- v1.3.93/linux/arch/m68k/kernel/bios32.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/kernel/bios32.c	Wed Dec 27 22:46:21 1995
@@ -0,0 +1,7 @@
+/*
+ * bios 32 replacement
+ */
+unsigned long bios32_init(unsigned long memory_start, unsigned long memory_end)
+{
+	return memory_start;
+}
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/kernel/console.c linux/arch/m68k/kernel/console.c
--- v1.3.93/linux/arch/m68k/kernel/console.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/kernel/console.c	Thu Apr 18 02:05:46 1996
@@ -0,0 +1,2561 @@
+/*
+ *  linux/drivers/char/console.c
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ */
+/*
+ *	console.c
+ *
+ * This module exports the console io functions:
+ *
+ *     'void do_keyboard_interrupt(void)'
+ *
+ *     'int vc_allocate(unsigned int console)'
+ *     'int vc_cons_allocated(unsigned int console)'
+ *     'int vc_resize(unsigned long lines, unsigned long cols)'
+ *     'int vc_resize_con(unsigned long lines, unsigned long cols,
+ *			  unsigned int currcons)'
+ *     'void vc_disallocate(unsigned int currcons)'
+ *
+ *     'unsigned long con_init(unsigned long)'
+ *     'int con_open(struct tty_struct *tty, struct file * filp)'
+ *     'void con_write(struct tty_struct * tty)'
+ *     'void console_print(const char * b)'
+ *     'void update_screen(int new_console)'
+ *
+ *     'void do_blank_screen(int)'
+ *     'void do_unblank_screen(void)'
+ *     'void poke_blanked_console(void)'
+ *
+ *     'unsigned short *screen_pos(int currcons, int w_offset, int viewed)'
+ *     'void complement_pos(int currcons, int offset)'
+ *     'void invert_screen(int currcons, int offset, int count, int shift)'
+ *
+ *     'void scrollback(int lines)'
+ *     'void scrollfront(int lines)'
+ *
+ *     'int con_get_font(char *)' 
+ *     'int con_set_font(char *)'
+ * 
+ *     'void mouse_report(struct tty_struct * tty, int butt, int mrx, int mry)'
+ *     'int mouse_reporting(void)'
+ *
+ *     'unsigned long get_video_num_lines(unsigned int console)'
+ *     'unsigned long get_video_num_columns(unsigned int console)'
+ *     'unsigned long get_video_size_row(unsigned int console)'
+ *
+ * Hopefully this will be a rather complete VT102 implementation.
+ *
+ * Beeping thanks to John T Kohl.
+ *
+ * Virtual Consoles, Screen Blanking, Screen Dumping, Color, Graphics
+ *   Chars, and VT100 enhancements by Peter MacDonald.
+ *
+ * Copy and paste function by Andrew Haylett,
+ *   some enhancements by Alessandro Rubini.
+ *
+ * User definable mapping table and font loading by Eugene G. Crosser,
+ * <crosser@pccross.msk.su>
+ *
+ * Code to check for different video-cards mostly by Galen Hunt,
+ * <g-hunt@ee.utah.edu>
+ *
+ * Rudimentary ISO 10646/Unicode/UTF-8 character set support by
+ * Markus Kuhn, <mskuhn@immd4.informatik.uni-erlangen.de>.
+ *
+ * Dynamic allocation of consoles, aeb@cwi.nl, May 1994
+ * Resizing of consoles, aeb, 940926
+ *
+ * Code for xterm like mouse click reporting by Peter Orbaek 20-Jul-94
+ * <poe@daimi.aau.dk>
+ *
+ * 680x0 LINUX support by Arno Griffioen (arno@usn.nl)
+ *
+ * 9-Apr-94:  Arno Griffioen: fixed scrolling and delete-char bug.
+ *            Scrolling code moved to amicon.c
+ *
+ * 18-Apr-94: David Carter [carter@cs.bris.ac.uk]. 680x0 LINUX modified 
+ *            Integrated support for new low level driver `amicon_ocs.c'
+ *
+ */
+
+#define BLANK 0x0020
+#undef CAN_LOAD_EGA_FONTS    /* undefine if the user must not do this */
+
+/* A bitmap for codes <32. A bit of 1 indicates that the code
+ * corresponding to that bit number invokes some special action
+ * (such as cursor movement) and should not be displayed as a
+ * glyph unless the disp_ctrl mode is explicitly enabled.
+ */
+#define CTRL_ACTION 0x0d00ff81
+#define CTRL_ALWAYS 0x0800f501	/* Cannot be overridden by disp_ctrl */
+
+/*
+ * Here is the default bell parameters: 750HZ, 1/8th of a second
+ */
+#define DEFAULT_BELL_PITCH	750
+#define DEFAULT_BELL_DURATION	(HZ/8)
+
+/*
+ *  NOTE!!! We sometimes disable and enable interrupts for a short while
+ * (to put a word in video IO), but this will work even for keyboard
+ * interrupts. We know interrupts aren't enabled when getting a keyboard
+ * interrupt, as we use trap-gates. Hopefully all is well.
+ */
+
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/console.h>
+#include <linux/kd.h>
+#include <linux/malloc.h>
+#include <linux/major.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+
+#include <asm/io.h>
+#include <asm/segment.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+
+#include "../../../drivers/char/kbd_kern.h"
+#include "../../../drivers/char/vt_kern.h"
+#include "../../../drivers/char/consolemap.h"
+#include "../../../drivers/char/selection.h"
+
+
+#ifndef MIN
+#define MIN(a,b)	((a) < (b) ? (a) : (b))
+#endif
+
+struct tty_driver console_driver;
+static int console_refcount;
+static struct tty_struct *console_table[MAX_NR_CONSOLES];
+static struct termios *console_termios[MAX_NR_CONSOLES];
+static struct termios *console_termios_locked[MAX_NR_CONSOLES];
+
+static void vc_init(unsigned int console, int do_clear);
+
+static void update_attr(int currcons);
+static void gotoxy(int currcons, int new_x, int new_y);
+static void save_cur(int currcons);
+static void blank_screen(void);
+static void unblank_screen(void);
+extern void change_console(unsigned int);
+static inline void set_cursor(int currcons);
+static void reset_terminal(int currcons, int do_clear);
+extern void reset_vc(unsigned int new_console);
+extern void vt_init(void);
+extern void register_console(void (*proc)(const char *));
+extern void vesa_blank(void);
+extern void vesa_unblank(void);
+extern void compute_shiftstate(void);
+void poke_blanked_console(void);
+void do_blank_screen(int);
+
+unsigned long	video_num_lines;
+unsigned long	video_num_columns;
+unsigned long	video_size_row;
+
+static int printable = 0;			/* Is console ready for printing? */
+unsigned long video_font_height;	/* Height of current screen font */
+unsigned long video_scan_lines;		/* Number of scan lines on screen */
+unsigned long default_font_height;      /* Height of default screen font */
+int	      video_mode_512ch = 0;	/* 512-character mode */
+static unsigned short console_charmask = 0x0ff;
+
+static unsigned short *vc_scrbuf[MAX_NR_CONSOLES];
+
+/* used by kbd_bh - set by keyboard_interrupt */
+       int do_poke_blanked_console = 0;
+       int console_blanked = 0;
+static int blankinterval = 10*60*HZ;
+
+static struct vc {
+	struct vc_data *d;
+
+	/* might add  scrmem, vt_struct, kbd  at some time,
+	   to have everything in one place - the disadvantage
+	   would be that vc_cons etc can no longer be static */
+} vc_cons [MAX_NR_CONSOLES];
+struct consw *conswitchp;
+
+#define cols            (vc_cons[currcons].d->vc_cols)
+#define rows            (vc_cons[currcons].d->vc_rows)
+#define size_row        (vc_cons[currcons].d->vc_size_row)
+#define screenbuf_size	(vc_cons[currcons].d->vc_screenbuf_size)
+#define cons_num	(vc_cons[currcons].d->vc_num)
+#define origin		(vc_cons[currcons].d->vc_origin)
+#define scr_end		(vc_cons[currcons].d->vc_scr_end)
+#define pos		(vc_cons[currcons].d->vc_pos)
+#define top		(vc_cons[currcons].d->vc_top)
+#define bottom		(vc_cons[currcons].d->vc_bottom)
+#define x		(vc_cons[currcons].d->vc_x)
+#define y		(vc_cons[currcons].d->vc_y)
+#define vc_state	(vc_cons[currcons].d->vc_state)
+#define npar		(vc_cons[currcons].d->vc_npar)
+#define par		(vc_cons[currcons].d->vc_par)
+#define ques		(vc_cons[currcons].d->vc_ques)
+#define attr		(vc_cons[currcons].d->vc_attr)
+#define saved_x		(vc_cons[currcons].d->vc_saved_x)
+#define saved_y		(vc_cons[currcons].d->vc_saved_y)
+#define translate	(vc_cons[currcons].d->vc_translate)
+#define G0_charset	(vc_cons[currcons].d->vc_G0_charset)
+#define G1_charset	(vc_cons[currcons].d->vc_G1_charset)
+#define saved_G0	(vc_cons[currcons].d->vc_saved_G0)
+#define saved_G1	(vc_cons[currcons].d->vc_saved_G1)
+#define utf		(vc_cons[currcons].d->vc_utf)
+#define utf_count	(vc_cons[currcons].d->vc_utf_count)
+#define utf_char	(vc_cons[currcons].d->vc_utf_char)
+#define video_mem_start	(vc_cons[currcons].d->vc_video_mem_start)
+#define video_mem_end	(vc_cons[currcons].d->vc_video_mem_end)
+#define video_erase_char (vc_cons[currcons].d->vc_video_erase_char)	
+#define disp_ctrl	(vc_cons[currcons].d->vc_disp_ctrl)
+#define toggle_meta	(vc_cons[currcons].d->vc_toggle_meta)
+#define decscnm		(vc_cons[currcons].d->vc_decscnm)
+#define decom		(vc_cons[currcons].d->vc_decom)
+#define decawm		(vc_cons[currcons].d->vc_decawm)
+#define deccm		(vc_cons[currcons].d->vc_deccm)
+#define decim		(vc_cons[currcons].d->vc_decim)
+#define deccolm	 	(vc_cons[currcons].d->vc_deccolm)
+#define need_wrap	(vc_cons[currcons].d->vc_need_wrap)
+#define has_scrolled	(vc_cons[currcons].d->vc_has_scrolled)
+#define kmalloced	(vc_cons[currcons].d->vc_kmalloced)
+#define report_mouse	(vc_cons[currcons].d->vc_report_mouse)
+#define can_do_color	(vc_cons[currcons].d->vc_can_do_color)
+#define color		(vc_cons[currcons].d->vc_color)
+#define s_color		(vc_cons[currcons].d->vc_s_color)
+#define def_color	(vc_cons[currcons].d->vc_def_color)
+#define	foreground	(color & 0x0f)
+#define background	(color & 0xf0)
+#define charset		(vc_cons[currcons].d->vc_charset)
+#define s_charset	(vc_cons[currcons].d->vc_s_charset)
+#define	intensity	(vc_cons[currcons].d->vc_intensity)
+#define	underline	(vc_cons[currcons].d->vc_underline)
+#define	blink		(vc_cons[currcons].d->vc_blink)
+#define	reverse		(vc_cons[currcons].d->vc_reverse)
+#define	s_intensity	(vc_cons[currcons].d->vc_s_intensity)
+#define	s_underline	(vc_cons[currcons].d->vc_s_underline)
+#define	s_blink		(vc_cons[currcons].d->vc_s_blink)
+#define	s_reverse	(vc_cons[currcons].d->vc_s_reverse)
+#define	ulcolor		(vc_cons[currcons].d->vc_ulcolor)
+#define	halfcolor	(vc_cons[currcons].d->vc_halfcolor)
+#define tab_stop	(vc_cons[currcons].d->vc_tab_stop)
+#define bell_pitch	(vc_cons[currcons].d->vc_bell_pitch)
+#define bell_duration	(vc_cons[currcons].d->vc_bell_duration)
+#define sw		(vc_cons[currcons].d->vc_sw)
+
+#define vcmode		(vt_cons[currcons]->vc_mode)
+#if 0 /* XXX */
+#define	vtmode		(vt_cons[currcons]->vt_mode)
+#define	vtpid		(vt_cons[currcons]->vt_pid)
+#define	vtnewvt		(vt_cons[currcons]->vt_newvt)
+#endif
+
+#define structsize	(sizeof(struct vc_data) + sizeof(struct vt_struct))
+
+int vc_cons_allocated(unsigned int i)
+{
+	return (i < MAX_NR_CONSOLES && vc_cons[i].d);
+}
+
+int vc_allocate(unsigned int currcons)		/* return 0 on success */
+{
+	if (currcons >= MAX_NR_CONSOLES)
+	  return -ENODEV;
+	if (!vc_cons[currcons].d) {
+	    long p, q;
+
+	    /* prevent users from taking too much memory */
+	    if (currcons >= MAX_NR_USER_CONSOLES && !suser())
+	      return -EPERM;
+
+	    /* due to the granularity of kmalloc, we waste some memory here */
+	    /* the alloc is done in two steps, to optimize the common situation
+	       of a 25x80 console (structsize=216, screenbuf_size=4000) */
+	    p = (long) kmalloc(structsize, GFP_KERNEL);
+	    if (!p)
+		return -ENOMEM;
+	    vc_cons[currcons].d = (struct vc_data *) p;
+	    vt_cons[currcons] = (struct vt_struct *)(p+sizeof(struct vc_data));
+
+	    /* ++Geert: sw->con_init determines console size */
+	    sw = conswitchp;
+	    cons_num = currcons;
+	    sw->con_init (vc_cons[currcons].d);
+	    size_row = cols<<1;
+	    screenbuf_size = rows*size_row;
+
+	    q = (long) kmalloc(screenbuf_size, GFP_KERNEL);
+	    if (!q) {
+		kfree_s((char *) p, structsize);
+		vc_cons[currcons].d = NULL;
+		return -ENOMEM;
+	    }
+	    vc_scrbuf[currcons] = (unsigned short *) q;
+	    kmalloced = 1;
+	    vc_init (currcons, 1);
+	}
+	return 0;
+}
+
+/*
+ * Change # of rows and columns (0 means the size of fg_console)
+ * [this is to be used together with some user program
+ * like resize that changes the hardware videomode]
+ */
+int vc_resize(unsigned long lines, unsigned long columns)
+{
+	unsigned long cc, ll, ss, sr;
+	unsigned long occ, oll, oss, osr;
+	unsigned short *p;
+	unsigned int currcons = fg_console, i;
+	unsigned short *newscreens[MAX_NR_CONSOLES];
+	long ol, nl, rlth, rrem;
+
+	cc = (columns ? columns : cols);
+	ll = (lines ? lines : rows);
+	sr = cc << 1;
+	ss = sr * ll;
+
+	/*
+	 * Some earlier version had all consoles of potentially
+	 * different sizes, but that was really messy.
+	 * So now we only change if there is room for all consoles
+	 * of the same size.
+	 */
+	for (currcons = 0; currcons < MAX_NR_CONSOLES; currcons++) {
+	    if (!vc_cons_allocated(currcons))
+	      newscreens[currcons] = 0;
+	    else {
+		p = (unsigned short *) kmalloc(ss, GFP_USER);
+		if (!p) {
+		    for (i = 0; i< currcons; i++)
+		      if (newscreens[i])
+			kfree_s(newscreens[i], ss);
+		    return -ENOMEM;
+		}
+		newscreens[currcons] = p;
+	    }
+	}
+
+#if 0 /* XXX */
+	get_scrmem(fg_console);
+#endif
+
+	for (currcons = 0; currcons < MAX_NR_CONSOLES; currcons++) {
+	    if (!vc_cons_allocated(currcons))
+	      continue;
+
+	    oll = rows;
+	    occ = cols;
+	    osr = size_row;
+	    oss = screenbuf_size;
+
+	    rows = ll;
+	    cols = cc;
+	    size_row = sr;
+	    screenbuf_size = ss;
+
+	    rlth = MIN(osr, sr);
+	    rrem = sr - rlth;
+	    ol = origin;
+	    nl = (long) newscreens[currcons];
+	    if (ll < oll)
+	      ol += (oll - ll) * osr;
+
+	    update_attr(currcons);
+	    while (ol < scr_end) {
+		/* ++Geert: TODO: Because the attributes have different meanings
+                   on monochrome and color, they should really be converted if
+                   can_do_color changes... */
+		memcpyw((unsigned short *) nl, (unsigned short *) ol, rlth);
+		if (rrem)
+		  memsetw((void *)(nl + rlth), video_erase_char, rrem);
+		ol += osr;
+		nl += sr;
+	    }
+
+	    if (kmalloced)
+	      kfree_s(vc_scrbuf[currcons], oss);
+	    vc_scrbuf[currcons] = newscreens[currcons];
+	    kmalloced = 1;
+	    screenbuf_size = ss;
+
+	    origin = (long) video_mem_start = vc_scrbuf[currcons];
+	    scr_end = video_mem_end = ((long) video_mem_start) + ss;
+
+	    if (scr_end > nl)
+	      memsetw((void *) nl, video_erase_char, scr_end - nl);
+
+	    /* do part of a reset_terminal() */
+	    top = 0;
+	    bottom = rows;
+	    gotoxy(currcons, x, y);
+	    save_cur(currcons);
+	}
+
+#if 0 /* XXX */
+	set_scrmem(fg_console, 0);
+	set_origin(fg_console);
+#endif /* XXX */
+	update_screen(fg_console);
+	set_cursor(fg_console);
+
+	return 0;
+}
+
+/*
+ * ++Geert: Change # of rows and columns for one specific console.
+ * Of course it's not messy to have all consoles of potentially different sizes,
+ * except on PCish hardware :-)
+ *
+ * This is called by the low level console driver (arch/m68k/console/fbcon.c or
+ * arch/m68k/console/txtcon.c)
+ */
+void vc_resize_con(unsigned long lines, unsigned long columns,
+		   unsigned int currcons)
+{
+	unsigned long cc, ll, ss, sr;
+	unsigned long occ, oll, oss, osr;
+	unsigned short *newscreen;
+	long ol, nl, rlth, rrem;
+	struct winsize ws;
+
+	if (!columns || !lines || currcons >= MAX_NR_CONSOLES)
+	    return;
+
+	cc = columns;
+	ll = lines;
+	sr = cc << 1;
+	ss = sr * ll;
+
+	if (!vc_cons_allocated(currcons))
+	    newscreen = 0;
+	else if (!(newscreen = (unsigned short *) kmalloc(ss, GFP_USER)))
+	    return;
+
+	if (vc_cons_allocated(currcons)) {
+	    oll = rows;
+	    occ = cols;
+	    osr = size_row;
+	    oss = screenbuf_size;
+
+	    rows = ll;
+	    cols = cc;
+	    size_row = sr;
+	    screenbuf_size = ss;
+
+	    rlth = MIN(osr, sr);
+	    rrem = sr - rlth;
+	    ol = origin;
+	    nl = (long) newscreen;
+	    if (ll < oll)
+	      ol += (oll - ll) * osr;
+
+	    update_attr(currcons);
+	    while (ol < scr_end) {
+		/* ++Geert: TODO: Because the attributes have different meanings
+                   on monochrome and color, they should really be converted if
+                   can_do_color changes... */
+		memcpyw((unsigned short *) nl, (unsigned short *) ol, rlth);
+		if (rrem)
+		  memsetw((void *)(nl + rlth), video_erase_char, rrem);
+		ol += osr;
+		nl += sr;
+	    }
+
+	    if (kmalloced)
+	      kfree_s(vc_scrbuf[currcons], oss);
+	    vc_scrbuf[currcons] = newscreen;
+	    kmalloced = 1;
+	    screenbuf_size = ss;
+
+	    origin = (long) video_mem_start = vc_scrbuf[currcons];
+	    scr_end = video_mem_end = ((long)video_mem_start) + ss;
+
+	    if (scr_end > nl)
+	      memsetw((void *) nl, video_erase_char, scr_end - nl);
+
+	    /* do part of a reset_terminal() */
+	    top = 0;
+	    bottom = rows;
+	    gotoxy(currcons, x, y);
+	    save_cur(currcons);
+
+	    ws.ws_row = rows;
+	    ws.ws_col = cols;
+	    if (memcmp(&ws, &console_table[currcons]->winsize, sizeof (struct winsize)) &&
+	        console_table[currcons]->pgrp > 0)
+		kill_pg(console_table[currcons]->pgrp, SIGWINCH, 1);
+	    console_table[currcons]->winsize = ws;
+	}
+
+   if (currcons == fg_console)
+      update_screen(fg_console);
+}
+
+void vc_disallocate(unsigned int currcons)
+{
+	if (vc_cons_allocated(currcons)) {
+	    if (kmalloced)
+	      kfree_s(vc_scrbuf[currcons], screenbuf_size);
+	    if (currcons >= MIN_NR_CONSOLES)
+	      kfree_s(vc_cons[currcons].d, structsize);
+	    vc_cons[currcons].d = 0;
+	}
+}
+
+
+#define set_kbd(x) set_vc_kbd_mode(kbd_table+currcons,x)
+#define clr_kbd(x) clr_vc_kbd_mode(kbd_table+currcons,x)
+#define is_kbd(x) vc_kbd_mode(kbd_table+currcons,x)
+
+#define decarm		VC_REPEAT
+#define decckm		VC_CKMODE
+#define kbdapplic	VC_APPLIC
+#define lnm		VC_CRLF
+
+/*
+ * this is what the terminal answers to a ESC-Z or csi0c query.
+ */
+#define VT100ID "\033[?1;2c"
+#define VT102ID "\033[?6c"
+
+static unsigned char color_table[] = { 0, 4, 2, 6, 1, 5, 3, 7,
+				       8,12,10,14, 9,13,11,15 };
+
+/*
+ * gotoxy() must verify all boundaries, because the arguments
+ * might also be negative. If the given position is out of
+ * bounds, the cursor is placed at the nearest margin.
+ */
+static void gotoxy(int currcons, int new_x, int new_y)
+{
+	int max_y;
+
+	if (new_x < 0)
+		x = 0;
+	else
+		if (new_x >= cols)
+			x = cols - 1;
+		else
+			x = new_x;
+ 	if (decom) {
+		new_y += top;
+		max_y = bottom;
+	} else
+		max_y = rows;
+	if (new_y < 0)
+		y = 0;
+	else
+		if (new_y >= max_y)
+			y = max_y - 1;
+		else
+			y = new_y;
+	pos = video_mem_start + y * cols + x;
+	need_wrap = 0;
+}
+
+static void hide_cursor(int currcons)
+{
+	sw->con_cursor(vc_cons[currcons].d,CM_ERASE);
+	return;
+}
+
+static void set_cursor(int currcons)
+{
+	if (currcons != fg_console || console_blanked || vcmode == KD_GRAPHICS)
+		return;
+	if (deccm)
+		sw->con_cursor(vc_cons[currcons].d,CM_DRAW);
+	else
+		hide_cursor(currcons);
+	return;
+}
+
+void no_scroll(char *str, int *ints)
+{
+  /*
+   * no_scroll currently does nothing on the m68k.
+   */
+}
+
+/*
+ * Arno:
+ * Why do we need these? The keyboard code doesn't seem to do anything
+ * with them either...
+ */
+void scrollfront(int l)
+{
+	return;
+}
+
+void scrollback(int l)
+{
+	return;
+}
+
+static void scrup(int currcons, unsigned int t, unsigned int b,
+		  int nr)
+{
+	unsigned short *p;
+	int i;
+
+	if (b > rows || t >= b)
+		return;
+
+	memmove (video_mem_start + t * cols,
+		 video_mem_start + (t + nr) * cols,
+		 (b - t - nr) * cols * 2);
+
+	p = video_mem_start + (b - nr) * cols;
+	for (i = nr * cols; i > 0; i--)
+	  *p++ = video_erase_char;
+
+	if (currcons != fg_console)
+	  return;
+/*
+ * Arno:
+ * Scrolling has now been moved to amicon.c where it should have
+ * been all along.
+ */
+	sw->con_scroll(vc_cons[currcons].d, t, b, SM_UP, nr);
+
+	return;
+	
+}
+
+static void scrdown(int currcons, unsigned int t, unsigned int b,
+		    int nr)
+{
+	unsigned short *p;
+	int i;
+
+	if (b > rows || t >= b)
+		return;
+
+	memmove (video_mem_start + (t + nr) * cols,
+		 video_mem_start + t * cols,
+		 (b - t - nr) * cols * 2);
+
+	p = video_mem_start + t * cols;
+	for (i = nr * cols; i > 0; i--)
+	  *p++ = video_erase_char;
+
+	if (currcons != fg_console)
+	  return;
+/*
+ * Arno:
+ * Scrolling has now been moved to amicon.c where it should have
+ * been all along.
+ */
+	sw->con_scroll(vc_cons[currcons].d, t, b, SM_DOWN, nr);
+
+	return;
+}
+
+static void lf(int currcons)
+{
+    	/* don't scroll if above bottom of scrolling region, or
+	 * if below scrolling region
+	 */
+    	if (y+1 == bottom)
+		scrup(currcons,top,bottom, 1);
+	else if (y < rows-1) {
+	    	y++;
+		pos += cols;
+	}
+	need_wrap = 0;
+}
+
+static void ri(int currcons)
+{
+    	/* don't scroll if below top of scrolling region, or
+	 * if above scrolling region
+	 */
+	if (y == top)
+		scrdown(currcons,top,bottom, 1);
+	else if (y > 0) {
+		y--;
+		pos -= cols;
+	}
+	need_wrap = 0;
+}
+
+static inline void cr(int currcons)
+{
+	pos -= x;
+	need_wrap = x = 0;
+}
+
+static inline void bs(int currcons)
+{
+	if (x) {
+		pos--;
+		x--;
+		need_wrap = 0;
+	}
+}
+
+static inline void del(int currcons)
+{
+	/* ignored */
+}
+
+static void csi_J(int currcons, int vpar)
+{
+	unsigned long count;
+	unsigned short *start;
+
+	switch (vpar) {
+		case 0:	/* erase from cursor to end of display */
+			count = (video_mem_start
+				 + cols * rows
+				 - pos);
+			start = pos;
+			if (currcons != fg_console)
+			  break;
+			/* 680x0 do in two stages */
+			sw->con_clear(vc_cons[currcons].d,y,x,1,cols-x);
+			sw->con_clear(vc_cons[currcons].d,y+1,0,rows-y-1, cols);
+			break;
+		case 1:	/* erase from start to cursor */
+			count = pos - video_mem_start + 1;
+			start = video_mem_start;
+			if (currcons != fg_console)
+			  break;
+			/* 680x0 do in two stages */
+			sw->con_clear(vc_cons[currcons].d,0,0,y, cols);
+			sw->con_clear(vc_cons[currcons].d,y,0,1,x + 1);
+			break;
+		case 2: /* erase whole display */
+			count = cols * rows;
+			start = video_mem_start;
+			if (currcons != fg_console)
+			  break;
+			sw->con_clear(vc_cons[currcons].d,0,0,rows, cols);
+			break;
+		default:
+			return;
+	}
+	while (count-- > 0)
+	  *start++ = video_erase_char;
+	need_wrap = 0;
+}
+
+static void csi_K(int currcons, int vpar)
+{
+	unsigned long count;
+	unsigned short *start;
+
+	switch (vpar) {
+		case 0:	/* erase from cursor to end of line */
+			count = cols - x;
+			start = pos;
+			if (currcons != fg_console)
+			  break;
+			sw->con_clear(vc_cons[currcons].d,y,x,1,cols-x);
+			break;
+		case 1:	/* erase from start of line to cursor */
+			start = pos - x;
+			count = x + 1;
+			if (currcons != fg_console)
+			  break;
+			sw->con_clear(vc_cons[currcons].d,y,0,1,x + 1);
+			break;
+		case 2: /* erase whole line */
+			start = pos - x;
+			count = cols;
+			if (currcons != fg_console)
+			  break;
+			sw->con_clear(vc_cons[currcons].d,y,0,1,cols);
+			break;
+		default:
+			return;
+	}
+	while (count-- > 0)
+	  *start++ = video_erase_char;
+	need_wrap = 0;
+}
+
+static void csi_X(int currcons, int vpar) /* erase the following vpar positions */
+{					  /* not vt100? */
+	unsigned long count;
+	unsigned short * start;
+
+	if (!vpar)
+		vpar++;
+
+	start=pos;
+	count=(vpar > cols-x) ? (cols-x) : vpar;
+
+	if (currcons == fg_console)
+		sw->con_clear(vc_cons[currcons].d,y,x,1,count);
+
+	while (count-- > 0)
+		*start++ = video_erase_char;
+	need_wrap = 0;
+}
+
+/*
+ * Arno: 
+ * On 680x0 attributes are currently not used. This piece of code
+ * seems hardware independent, but uses the EGA/VGA way of representing
+ * attributes. 
+ * TODO: modify for 680x0 and add attribute processing to putc code.
+ *
+ * ++roman: I completely changed the attribute format for monochrome
+ * mode (!can_do_color). The formerly used MDA (monochrome display
+ * adapter) format didn't allow the combination of certain effects.
+ * Now the attribute is just a bit vector:
+ *  Bit 0..1: intensity (0..2)
+ *  Bit 2   : underline
+ *  Bit 3   : reverse
+ *  Bit 7   : blink
+ */
+static void update_attr(int currcons)
+{
+	if (!can_do_color) {
+		/* Special treatment for monochrome */
+		attr = intensity |
+			(underline ? 4 : 0) |
+			((reverse ^ decscnm) ? 8 : 0) |
+			(blink ? 0x80 : 0);
+		video_erase_char = ' ' | ((reverse ^ decscnm) ? 0x800 : 0);
+		return;
+	}
+
+	attr = color;
+	if (underline)
+		attr = (attr & 0xf0) | ulcolor;
+	else if (intensity == 0)
+		attr = (attr & 0xf0) | halfcolor;
+	if (reverse ^ decscnm)
+		attr = reverse_video_char(attr);
+	if (blink)
+		attr ^= 0x80;
+	if (intensity == 2)
+		attr ^= 0x08;
+	if (decscnm)
+		video_erase_char = (reverse_video_char(color) << 8) | ' ';
+	else
+		video_erase_char = (color << 8) | ' ';
+}
+
+static void default_attr(int currcons)
+{
+	intensity = 1;
+	underline = 0;
+	reverse = 0;
+	blink = 0;
+	color = def_color;
+}
+
+static void csi_m(int currcons)
+{
+	int i;
+
+	for (i=0;i<=npar;i++)
+		switch (par[i]) {
+			case 0:	/* all attributes off */
+				default_attr(currcons);
+				break;
+			case 1:
+				intensity = 2;
+				break;
+			case 2:
+				intensity = 0;
+				break;
+			case 4:
+				underline = 1;
+				break;
+			case 5:
+				blink = 1;
+				break;
+			case 7:
+				reverse = 1;
+				break;
+			case 10: /* ANSI X3.64-1979 (SCO-ish?)
+				  * Select primary font, don't display
+				  * control chars if defined, don't set
+				  * bit 8 on output.
+				  */
+				translate = set_translate(charset == 0
+						? G0_charset
+						: G1_charset);
+				disp_ctrl = 0;
+				toggle_meta = 0;
+				break;
+			case 11: /* ANSI X3.64-1979 (SCO-ish?)
+				  * Select first alternate font, let's
+				  * chars < 32 be displayed as ROM chars.
+				  */
+				translate = set_translate(IBMPC_MAP);
+				disp_ctrl = 1;
+				toggle_meta = 0;
+				break;
+			case 12: /* ANSI X3.64-1979 (SCO-ish?)
+				  * Select second alternate font, toggle
+				  * high bit before displaying as ROM char.
+				  */
+				translate = set_translate(IBMPC_MAP);
+				disp_ctrl = 1;
+				toggle_meta = 1;
+				break;
+			case 21:
+			case 22:
+				intensity = 1;
+				break;
+			case 24:
+				underline = 0;
+				break;
+			case 25:
+				blink = 0;
+				break;
+			case 27:
+				reverse = 0;
+				break;
+			case 38: /* ANSI X3.64-1979 (SCO-ish?)
+				  * Enables underscore, white foreground
+				  * with white underscore (Linux - use
+				  * default foreground).
+				  */
+				color = (def_color & 0x0f) | background;
+				underline = 1;
+				break;
+			case 39: /* ANSI X3.64-1979 (SCO-ish?)
+				  * Disable underline option.
+				  * Reset colour to default? It did this
+				  * before...
+				  */
+				color = (def_color & 0x0f) | background;
+				underline = 0;
+				break;
+			case 49:
+				color = (def_color & 0xf0) | foreground;
+				break;
+			default:
+				if (par[i] >= 30 && par[i] <= 37)
+					color = color_table[par[i]-30]
+						| background; 
+				else if (par[i] >= 40 && par[i] <= 47)
+					color = (color_table[par[i]-40]<<4)
+						| foreground;
+				break;
+		}
+	update_attr(currcons);
+}
+
+static void respond_string(const char * p, struct tty_struct * tty)
+{
+	while (*p) {
+		tty_insert_flip_char(tty, *p, 0);
+		p++;
+	}
+	tty_schedule_flip(tty);
+}
+
+static void cursor_report(int currcons, struct tty_struct * tty)
+{
+	char buf[40];
+
+	sprintf(buf, "\033[%ld;%ldR", y + (decom ? top+1 : 1), x+1);
+	respond_string(buf, tty);
+}
+
+static inline void status_report(struct tty_struct * tty)
+{
+	respond_string("\033[0n", tty);	/* Terminal ok */
+}
+
+static inline void respond_ID(struct tty_struct * tty)
+{
+	respond_string(VT102ID, tty);
+}
+
+void mouse_report(struct tty_struct * tty, int butt, int mrx, int mry)
+{
+	char buf[8];
+
+	sprintf(buf, "\033[M%c%c%c", (char)(' ' + butt), (char)('!' + mrx),
+		(char)('!' + mry));
+	respond_string(buf, tty);
+}
+
+/* invoked via ioctl(TIOCLINUX) */
+int mouse_reporting(void)
+{
+	int currcons = fg_console;
+
+	return report_mouse;
+}
+
+static inline unsigned short *screenpos(int currcons, int offset, int viewed)
+{
+	unsigned short *p = (unsigned short *)(origin + offset);
+#if 0
+	if (viewed && currcons == fg_console)
+		p -= (__real_origin - __origin);
+#endif
+	return p;
+}
+
+/* Note: inverting the screen twice should revert to the original state */
+void invert_screen(int currcons, int offset, int count, int viewed)
+{
+	unsigned short *p;
+	unsigned short xx, yy, oldattr;
+
+	count /= 2;
+	p = screenpos(currcons, offset, viewed);
+	xx = (offset >> 1) % cols;
+	yy = (offset >> 1) / cols;
+	oldattr = attr;
+	if (can_do_color)
+		while (count--) {
+			unsigned short old = scr_readw(p);
+			unsigned short new = reverse_video_short(old);
+			scr_writew(new, p);
+			p++;
+			if (currcons != fg_console)
+				continue;
+			attr = new >> 8;
+			sw->con_putc(vc_cons[currcons].d, new & 0xff, yy, xx);
+			if (++xx == cols)
+				xx = 0, ++yy;
+		}
+	else
+		while (count--) {
+			unsigned short old = scr_readw(p);
+			unsigned short new = old ^ 0x800;
+			scr_writew(new, p);
+			p++;
+			if (currcons != fg_console)
+				continue;
+			attr = new >> 8;
+			sw->con_putc(vc_cons[currcons].d, new & 0xff, yy, xx);
+			if (++xx == cols)
+				xx = 0, ++yy;
+		}
+	attr = oldattr;
+}
+
+/* used by selection: complement pointer position */
+void complement_pos(int currcons, int offset)
+{
+	static unsigned short *p = NULL;
+	static unsigned short old = 0;
+	static unsigned short oldx = 0, oldy = 0;
+	unsigned short new, oldattr;
+
+	oldattr = attr;
+	if (p) {
+		scr_writew(old, p);
+		if (currcons == fg_console) {
+			attr = old >> 8;
+			sw->con_putc(vc_cons[currcons].d, old & 0xff, oldy, oldx);
+			attr = oldattr;
+		}
+	}
+	if (offset == -1)
+		p = NULL;
+	else {
+		p = screenpos(currcons, offset, 1);
+		old = scr_readw(p);
+		oldx = (offset >> 1) % cols;
+		oldy = (offset >> 1) / cols;
+		if (can_do_color)
+			new = old ^ 0x7700;
+		else
+			new = old ^ 0x800;
+		scr_writew(new, p);
+		if (currcons == fg_console) {
+			attr = new >> 8;
+			sw->con_putc(vc_cons[currcons].d, new & 0xff, oldy, oldx);
+			attr = oldattr;
+		}
+	}
+}
+
+/* used by selection */
+unsigned short screen_word(int currcons, int offset, int viewed)
+{
+	return scr_readw(screenpos(currcons, offset, viewed));
+}
+
+/* used by selection - convert a screen word to a glyph number */
+int scrw2glyph(unsigned short scr_word)
+{
+	return ( video_mode_512ch )
+		? ((scr_word & 0x0800) >> 3) + (scr_word & 0x00ff)
+		: scr_word & 0x00ff;
+}
+
+/* used by vcs - note the word offset */
+unsigned short *screen_pos(int currcons, int w_offset, int viewed)
+{
+	return screenpos(currcons, 2 * w_offset, viewed);
+}
+
+void getconsxy(int currcons, char *p)
+{
+	p[0] = x;
+	p[1] = y;
+}
+
+void putconsxy(int currcons, char *p)
+{
+	gotoxy(currcons, p[0], p[1]);
+	set_cursor(currcons);
+}
+
+static void set_mode(int currcons, int on_off)
+{
+	int i;
+
+	for (i=0; i<=npar; i++)
+		if (ques) switch(par[i]) {	/* DEC private modes set/reset */
+			case 1:			/* Cursor keys send ^[Ox/^[[x */
+				if (on_off)
+					set_kbd(decckm);
+				else
+					clr_kbd(decckm); 
+				break;
+			case 3:	/* 80/132 mode switch unimplemented */
+				deccolm = on_off;
+#if 0
+				(void) vc_resize(rows, deccolm ? 132 : 80);
+				/* this alone does not suffice; some user mode
+				   utility has to change the hardware regs */
+#endif
+				break;
+			case 5:			/* Inverted screen on/off */
+				if (decscnm != on_off) {
+					decscnm = on_off;
+					invert_screen(currcons, 0, screenbuf_size, 0);
+					update_attr(currcons);
+				}
+				break;
+			case 6:			/* Origin relative/absolute */
+				decom = on_off;
+				gotoxy(currcons,0,0);
+				break;
+			case 7:			/* Autowrap on/off */
+				decawm = on_off;
+				break;
+			case 8:			/* Autorepeat on/off */
+				if (on_off)
+					set_kbd(decarm);
+				else
+					clr_kbd(decarm);
+				break;
+			case 9:
+				report_mouse = on_off ? 1 : 0;
+				break;
+			case 25:		/* Cursor on/off */
+				deccm = on_off;
+				set_cursor(currcons);
+				break;
+			case 1000:
+				report_mouse = on_off ? 2 : 0;
+				break;
+		} else switch(par[i]) {		/* ANSI modes set/reset */
+			case 3:			/* Monitor (display ctrls) */
+				disp_ctrl = on_off;
+				break;
+			case 4:			/* Insert Mode on/off */
+				decim = on_off;
+				break;
+			case 20:		/* Lf, Enter == CrLf/Lf */
+				if (on_off)
+					set_kbd(lnm);
+				else
+					clr_kbd(lnm);
+				break;
+		}
+}
+
+static void setterm_command(int currcons)
+{
+	switch(par[0]) {
+		case 1:	/* set color for underline mode */
+			if (can_do_color && par[1] < 16) {
+				ulcolor = color_table[par[1]];
+				if (underline)
+					update_attr(currcons);
+			}
+			break;
+		case 2:	/* set color for half intensity mode */
+			if (can_do_color && par[1] < 16) {
+				halfcolor = color_table[par[1]];
+				if (intensity == 0)
+					update_attr(currcons);
+			}
+			break;
+		case 8:	/* store colors as defaults */
+			def_color = attr;
+			default_attr(currcons);
+			update_attr(currcons);
+			break;
+		case 9:	/* set blanking interval */
+			blankinterval = ((par[1] < 60) ? par[1] : 60) * 60 * HZ;
+			poke_blanked_console();
+			break;
+		case 10: /* set bell frequency in Hz */
+			if (npar >= 1)
+				bell_pitch = par[1];
+			else
+				bell_pitch = DEFAULT_BELL_PITCH;
+			break;
+		case 11: /* set bell duration in msec */
+			if (npar >= 1)
+				bell_duration = (par[1] < 2000) ?
+					par[1]*HZ/1000 : 0;
+			else
+				bell_duration = DEFAULT_BELL_DURATION;
+			break;
+		case 12: /* bring specified console to the front */
+			if (par[1] >= 1 && vc_cons_allocated(par[1]-1))
+				update_screen(par[1]-1);
+			break;
+		case 13: /* unblank the screen */
+			unblank_screen();
+			break;
+	}
+}
+
+static void insert_char(int currcons)
+{
+	int i;
+	unsigned short *p = pos;
+
+	for (i = cols - x - 2; i >= 0; i--)
+	  p[i + 1] = p[i];
+	*pos = video_erase_char;
+	need_wrap = 0;
+
+	if (currcons != fg_console)
+	  return;
+
+	/* Arno:
+	 * Move the remainder of the line (-1 character) one spot to the right
+	 */
+	sw->con_bmove(vc_cons[currcons].d,y,x,y,x+1,1,(cols-x-1));
+	/*
+	 * Print the erase char on the current position
+	 */
+	sw->con_putc(vc_cons[currcons].d,(video_erase_char & 0x00ff),y,x);
+}
+
+static void csi_at(int currcons, unsigned int nr)
+{
+	int i;
+	unsigned short *p;
+
+	if (nr > cols - x)
+		nr = cols - x;
+	else if (!nr)
+		nr = 1;
+
+	p = pos + cols - x - nr;
+	while (--p >= pos)
+	  p[nr] = *p;
+	for (i = 0; i < nr; i++)
+	  *++p = video_erase_char;
+	need_wrap = 0;
+
+	if (currcons != fg_console)
+	  return;
+
+	sw->con_bmove (vc_cons[currcons].d, y, x, y, x + nr,
+		       1, cols - x - nr);
+	while (nr--)
+	  sw->con_putc (vc_cons[currcons].d, video_erase_char & 0x00ff,
+			y, x + nr);
+}
+
+static void csi_L(int currcons, unsigned int nr)
+{
+	if (nr > rows)
+		nr = rows;
+	else if (!nr)
+		nr = 1;
+	scrdown (currcons, y, bottom, nr);
+	need_wrap = 0;
+}
+
+static void csi_P(int currcons, unsigned int nr)
+{
+	int i;
+	unsigned short *p, *end;
+
+	if (nr > cols - x)
+		nr = cols - x;
+	else if (!nr)
+		nr = 1;
+
+	p = pos;
+	end = pos + cols - x - nr;
+	while (p < end)
+	  *p = p[nr], p++;
+	for (i = 0; i < nr; i++)
+	  *p++ = video_erase_char;
+	need_wrap = 0;
+
+	if (currcons != fg_console)
+	  return;
+
+	sw->con_bmove (vc_cons[currcons].d, y, x + nr, y, x,
+		       1, cols - x - nr);
+
+	while (nr--)
+	  sw->con_putc (vc_cons[currcons].d, video_erase_char & 0x00ff,
+			y, cols - 1 - nr);
+}
+
+static void csi_M(int currcons, unsigned int nr)
+{
+	if (nr > rows)
+		nr = rows;
+	else if (!nr)
+		nr=1;
+	scrup (currcons, y, bottom, nr);
+	need_wrap = 0;
+}
+
+static void save_cur(int currcons)
+{
+	saved_x		= x;
+	saved_y		= y;
+	s_intensity	= intensity;
+	s_underline	= underline;
+	s_blink		= blink;
+	s_reverse	= reverse;
+	s_charset	= charset;
+	s_color		= color;
+	saved_G0	= G0_charset;
+	saved_G1	= G1_charset;
+}
+
+static void restore_cur(int currcons)
+{
+	gotoxy(currcons,saved_x,saved_y);
+	intensity	= s_intensity;
+	underline	= s_underline;
+	blink		= s_blink;
+	reverse		= s_reverse;
+	charset		= s_charset;
+	color		= s_color;
+	G0_charset	= saved_G0;
+	G1_charset	= saved_G1;
+	translate	= set_translate(charset ? G1_charset : G0_charset);
+	update_attr(currcons);
+	need_wrap = 0;
+}
+
+enum { ESnormal, ESesc, ESsquare, ESgetpars, ESgotpars, ESfunckey, 
+	EShash, ESsetG0, ESsetG1, ESpercent, ESignore, ESnonstd,
+	ESpalette };
+
+static void reset_terminal(int currcons, int do_clear)
+{
+	top		= 0;
+	bottom		= rows;
+	vc_state	= ESnormal;
+	ques		= 0;
+	translate	= set_translate(LAT1_MAP);
+	G0_charset	= LAT1_MAP;
+	G1_charset	= GRAF_MAP;
+	charset		= 0;
+	need_wrap	= 0;
+	report_mouse	= 0;
+	utf             = 0;
+	utf_count       = 0;
+
+	disp_ctrl	= 0;
+	toggle_meta	= 0;
+
+	decscnm		= 0;
+	decom		= 0;
+	decawm		= 1;
+	deccm		= 1;
+	decim		= 0;
+
+	set_kbd(decarm);
+	clr_kbd(decckm);
+	clr_kbd(kbdapplic);
+	clr_kbd(lnm);
+	kbd_table[currcons].lockstate = 0;
+	kbd_table[currcons].slockstate = 0;
+	kbd_table[currcons].ledmode = LED_SHOW_FLAGS;
+	kbd_table[currcons].ledflagstate = kbd_table[currcons].default_ledflagstate;
+	set_leds();
+
+	default_attr(currcons);
+	update_attr(currcons);
+
+	tab_stop[0]	= 0x01010100;
+	tab_stop[1]	=
+	tab_stop[2]	=
+	tab_stop[3]	=
+	tab_stop[4]	= 0x01010101;
+
+	bell_pitch = DEFAULT_BELL_PITCH;
+	bell_duration = DEFAULT_BELL_DURATION;
+
+	gotoxy(currcons,0,0);
+	save_cur(currcons);
+	if (do_clear)
+	    csi_J(currcons,2);
+}
+
+/*
+ * Turn the Scroll-Lock LED on when the tty is stopped
+ */
+static void con_stop(struct tty_struct *tty)
+{
+	int console_num;
+	if (!tty)
+		return;
+	console_num = MINOR(tty->device) - (tty->driver.minor_start);
+	if (!vc_cons_allocated(console_num))
+		return;
+	set_vc_kbd_led(kbd_table + console_num, VC_SCROLLOCK);
+	set_leds();
+}
+
+/*
+ * Turn the Scroll-Lock LED off when the console is started
+ */
+static void con_start(struct tty_struct *tty)
+{
+	int console_num;
+	if (!tty)
+		return;
+	console_num = MINOR(tty->device) - (tty->driver.minor_start);
+	if (!vc_cons_allocated(console_num))
+		return;
+	clr_vc_kbd_led(kbd_table + console_num, VC_SCROLLOCK);
+	set_leds();
+}
+
+static int con_write(struct tty_struct * tty, int from_user,
+		     const unsigned char *buf, int count)
+{
+	int c, tc, ok, n = 0;
+	unsigned int currcons;
+	struct vt_struct *vt = (struct vt_struct *)tty->driver_data;
+
+	currcons = vt->vc_num;
+	if (!vc_cons_allocated(currcons)) {
+		/* could this happen? */
+		static int error = 0;
+		if (!error) {
+			error = 1;
+			printk("con_write: tty %d not allocated\n", currcons+1);
+		}
+		return 0;
+	}
+
+	/* undraw cursor first */
+	if (currcons == fg_console)
+		hide_cursor(currcons);
+	
+	/* clear the selection */
+	if (currcons == sel_cons)
+		clear_selection();
+
+        disable_bh(CONSOLE_BH);
+	while (count) {
+		enable_bh(CONSOLE_BH);
+		c = from_user ? get_user(buf) : *buf;
+		buf++; n++; count--;
+		disable_bh(CONSOLE_BH);
+
+		if (utf) {
+		    /* Combine UTF-8 into Unicode */
+		    /* Incomplete characters silently ignored */
+		    if(c > 0x7f) {   
+			if (utf_count > 0 && (c & 0xc0) == 0x80) {
+				utf_char = (utf_char << 6) | (c & 0x3f);
+				utf_count--;
+				if (utf_count == 0)
+				    tc = c = utf_char;
+				else continue;
+			} else {
+				if ((c & 0xe0) == 0xc0) {
+				    utf_count = 1;
+				    utf_char = (c & 0x1f);
+				} else if ((c & 0xf0) == 0xe0) {
+				    utf_count = 2;
+				    utf_char = (c & 0x0f);
+				} else if ((c & 0xf8) == 0xf0) {
+				    utf_count = 3;
+				    utf_char = (c & 0x07);
+				} else if ((c & 0xfc) == 0xf8) {
+				    utf_count = 4;
+				    utf_char = (c & 0x03);
+				} else if ((c & 0xfe) == 0xfc) {
+				    utf_count = 5;
+				    utf_char = (c & 0x01);
+				} else
+				    utf_count = 0;
+				continue;
+			}
+		    } else {
+			tc = c;
+			utf_count = 0;
+		    }
+		} else {	/* no utf */
+		    tc = translate[toggle_meta ? (c|0x80) : c];
+		}
+
+		/* If the original code was < 32 we only allow a
+		 * glyph to be displayed if the code is not normally
+		 * used (such as for cursor movement) or if the
+		 * disp_ctrl mode has been explicitly enabled.
+		 * Note: ESC is *never* allowed to be displayed as
+		 * that would disable all escape sequences!
+		 * To display font position 0x1B, go into UTF mode
+		 * and display character U+F01B, or change the mapping.
+		 */
+		ok = (tc && (c >= 32 || (!utf && !(((disp_ctrl ? CTRL_ALWAYS
+					    : CTRL_ACTION) >> c) & 1))));
+
+		if (vc_state == ESnormal && ok) {
+			/* Now try to find out how to display it */
+			tc = conv_uni_to_pc(tc);
+			if ( tc == -4 )
+			  {
+			    /* If we got -4 (not found) then see if we have
+			       defined a replacement character (U+FFFD) */
+			    tc = conv_uni_to_pc(0xfffd);
+			  }
+			else if ( tc == -3 )
+			  {
+			    /* Bad hash table -- hope for the best */
+			    tc = c;
+			  }
+			if (tc & ~console_charmask)
+			  continue; /* Conversion failed */
+
+			if (need_wrap) {
+				cr(currcons);
+				lf(currcons);
+			}
+			
+#if 1 /* XXX */
+                        /* DPC: 1994-04-12
+                         *   Speed up overstrike mode, using new putcs.
+                         *
+                         * P.S. I hate 8 spaces per tab! Use Emacs!
+			 */
+			
+			/* Only use this for the foreground console,
+                           where we really draw the chars */
+
+                        if (count > 2 &&
+			    !decim && currcons == fg_console) { 
+				static char putcs_buf[256];
+				char   *p     = putcs_buf;
+				int putcs_count  = 1;
+				ushort nextx  = x + 1;
+
+				*p++ = tc;
+				*pos++ = tc | (attr << 8);
+				
+				if (nextx == cols) {
+					sw->con_putc(vc_cons[currcons].d,
+						     *putcs_buf, y, x);
+					pos--;
+					need_wrap = decawm;
+					continue;
+				}
+				
+				/* TAB TAB TAB - Arghh!!!! */
+				
+				while (count)
+				{
+					c = from_user ? get_user(buf) : *buf;
+					tc = translate[toggle_meta ? (c|0x80) : c];
+					if (!tc ||
+					    !(c >= 32
+					      || (disp_ctrl && c != 0x1b)
+					      || !((CTRL_ACTION >> c) & 1)))
+					  break;
+					buf++; n++; count--;
+					*p++ = tc;
+					*pos++ = tc | (attr << 8);
+					++putcs_count;
+					++nextx;
+					if (nextx == cols || 
+					    putcs_count == sizeof (putcs_buf))
+						break;
+				}
+				
+				sw->con_putcs(vc_cons[currcons].d,
+					      putcs_buf, putcs_count, y, x);
+				if (nextx == cols) {
+					pos--;
+					x         = cols-1;
+					need_wrap = decawm;
+				} else
+					x += putcs_count;
+				continue;
+                        }
+			
+                        /* DPC: End of putcs support */
+#endif
+			
+			if (decim)
+				insert_char(currcons);
+			*pos = (attr << 8) + tc;
+			if (currcons == fg_console)
+				sw->con_putc(vc_cons[currcons].d,tc,y,x);
+			if (x == cols - 1)
+				need_wrap = decawm;
+			else {
+				pos++;
+				x++;
+			}
+			continue;
+		}
+
+		/*
+		 *  Control characters can be used in the _middle_
+		 *  of an escape sequence.
+		 */
+		switch (c) {
+		    case 7:
+			if (bell_duration)
+			    kd_mksound(bell_pitch, bell_duration);
+			continue;
+		    case 8:
+			bs(currcons);
+			continue;
+		    case 9:
+			pos -= x;
+			while (x < cols - 1) {
+				x++;
+				if (tab_stop[x >> 5] & (1 << (x & 31)))
+					break;
+			}
+			pos += x;
+			continue;
+		    case 10: case 11: case 12:
+			lf(currcons);
+			if (!is_kbd(lnm))
+				continue;
+		    case 13:
+			cr(currcons);
+			continue;
+  			case 14:
+			charset = 1;
+			translate = set_translate(G1_charset);
+			disp_ctrl = 1;
+			continue;
+		    case 15:
+			charset = 0;
+			translate = set_translate(G0_charset);
+			disp_ctrl = 0;
+			continue;
+		    case 24: case 26:
+			vc_state = ESnormal;
+			continue;
+		    case 27:
+			vc_state = ESesc;
+			continue;
+		    case 127:
+			del(currcons);
+			continue;
+		    case 128+27:
+			vc_state = ESsquare;
+			continue;
+		}
+		switch(vc_state) {
+		    case ESesc:
+			vc_state = ESnormal;
+			switch (c) {
+			    case '[':
+				vc_state = ESsquare;
+				continue;
+			    case ']':
+				vc_state = ESnonstd;
+				continue;
+			    case '%':
+				vc_state = ESpercent;
+				continue;
+			    case 'E':
+				cr(currcons);
+				lf(currcons);
+				continue;
+			    case 'M':
+				ri(currcons);
+				continue;
+			    case 'D':
+				lf(currcons);
+				continue;
+			    case 'H':
+				tab_stop[x >> 5] |= (1 << (x & 31));
+				continue;
+			    case 'Z':
+				respond_ID(tty);
+				continue;
+			    case '7':
+				save_cur(currcons);
+				continue;
+			    case '8':
+				restore_cur(currcons);
+				continue;
+			    case '(':
+				vc_state = ESsetG0;
+				continue;
+			    case ')':
+				vc_state = ESsetG1;
+				continue;
+			    case '#':
+				vc_state = EShash;
+				continue;
+			    case 'c':
+				reset_terminal(currcons,1);
+				continue;
+			    case '>':  /* Numeric keypad */
+				clr_kbd(kbdapplic);
+				continue;
+			    case '=':  /* Appl. keypad */
+				set_kbd(kbdapplic);
+				continue;
+			}	
+			continue;
+		    case ESnonstd:
+			if (c=='P') {   /* palette escape sequence */
+			    for (npar=0; npar<NPAR; npar++)
+				par[npar] = 0 ;
+			    npar = 0 ;
+			    vc_state = ESpalette;
+			    continue;
+			} else if (c=='R') {   /* reset palette */
+#if 0
+			    reset_palette (currcons);
+#endif
+			    vc_state = ESnormal;
+			} else
+			    vc_state = ESnormal;
+			continue;
+		case ESpalette:
+			if ( (c>='0'&&c<='9') || (c>='A'&&c<='F') || (c>='a'&&c<='f') ) {
+			    par[npar++] = (c>'9' ? (c&0xDF)-'A'+10 : c-'0') ;
+			    if (npar==7) {
+#if 0
+				int i = par[0]*3, j = 1;
+				palette[i] = 16*par[j++];
+				palette[i++] += par[j++];
+				palette[i] = 16*par[j++];
+				palette[i++] += par[j++];
+				palette[i] = 16*par[j++];
+				palette[i] += par[j];
+				set_palette() ;
+#endif
+				vc_state = ESnormal;
+			    }
+			} else
+			    vc_state = ESnormal;
+			continue;
+		    case ESsquare:
+			for(npar = 0 ; npar < NPAR ; npar++)
+				par[npar] = 0;
+			npar = 0;
+			vc_state = ESgetpars;
+			if (c == '[') { /* Function key */
+				vc_state=ESfunckey;
+				continue;
+			}
+			ques = (c=='?');
+			if (ques)
+				continue;
+		    case ESgetpars:
+			if (c==';' && npar<NPAR-1) {
+				npar++;
+				continue;
+			} else if (c>='0' && c<='9') {
+				par[npar] *= 10;
+				par[npar] += c-'0';
+				continue;
+			} else vc_state=ESgotpars;
+		    case ESgotpars:
+			vc_state = ESnormal;
+			switch(c) {
+			    case 'h':
+				set_mode(currcons,1);
+				continue;
+			    case 'l':
+				set_mode(currcons,0);
+				continue;
+			    case 'n':
+				if (!ques)
+					if (par[0] == 5)
+						status_report(tty);
+					else if (par[0] == 6)
+						cursor_report(currcons,tty);
+				continue;
+			}
+			if (ques) {
+				ques = 0;
+				continue;
+			}
+			switch(c) {
+			    case 'G': case '`':
+				if (par[0]) par[0]--;
+				gotoxy(currcons,par[0],y);
+				continue;
+			    case 'A':
+				if (!par[0]) par[0]++;
+				gotoxy(currcons,x,y-par[0]);
+				continue;
+			    case 'B': case 'e':
+				if (!par[0]) par[0]++;
+				gotoxy(currcons,x,y+par[0]);
+				continue;
+			    case 'C': case 'a':
+				if (!par[0]) par[0]++;
+				gotoxy(currcons,x+par[0],y);
+				continue;
+			    case 'D':
+				if (!par[0]) par[0]++;
+				gotoxy(currcons,x-par[0],y);
+				continue;
+			    case 'E':
+				if (!par[0]) par[0]++;
+				gotoxy(currcons,0,y+par[0]);
+				continue;
+			    case 'F':
+				if (!par[0]) par[0]++;
+				gotoxy(currcons,0,y-par[0]);
+				continue;
+			    case 'd':
+				if (par[0]) par[0]--;
+				gotoxy(currcons,x,par[0]);
+				continue;
+			    case 'H': case 'f':
+				if (par[0]) par[0]--;
+				if (par[1]) par[1]--;
+				gotoxy(currcons,par[1],par[0]);
+				continue;
+			    case 'J':
+				csi_J(currcons,par[0]);
+				continue;
+			    case 'K':
+				csi_K(currcons,par[0]);
+				continue;
+			    case 'L':
+				csi_L(currcons,par[0]);
+				continue;
+			    case 'M':
+				csi_M(currcons,par[0]);
+				continue;
+			    case 'P':
+				csi_P(currcons,par[0]);
+				continue;
+			    case 'c':
+				if (!par[0])
+					respond_ID(tty);
+				continue;
+			    case 'g':
+				if (!par[0])
+					tab_stop[x >> 5] &= ~(1 << (x & 31));
+				else if (par[0] == 3) {
+					tab_stop[0] =
+						tab_stop[1] =
+							tab_stop[2] =
+								tab_stop[3] =
+									tab_stop[4] = 0;
+				}
+				continue;
+			    case 'm':
+				csi_m(currcons);
+				continue;
+			    case 'q': /* DECLL - but only 3 leds */
+				/* map 0,1,2,3 to 0,1,2,4 */
+				if (par[0] < 4)
+					setledstate(kbd_table + currcons,
+						    (par[0] < 3) ? par[0] : 4);
+				continue;
+			    case 'r':
+				if (!par[0])
+					par[0]++;
+				if (!par[1])
+					par[1] = rows;
+				/* Minimum allowed region is 2 lines */
+				if (par[0] < par[1] &&
+				    par[1] <= rows) {
+					top=par[0]-1;
+					bottom=par[1];
+					gotoxy(currcons,0,0);
+				}
+				continue;
+			    case 's':
+				save_cur(currcons);
+				continue;
+			    case 'u':
+				restore_cur(currcons);
+				continue;
+			    case 'X':
+				csi_X(currcons, par[0]);
+				continue;
+			    case '@':
+				csi_at(currcons,par[0]);
+				continue;
+			    case ']': /* setterm functions */
+				setterm_command(currcons);
+				continue;
+			}
+			continue;
+		    case ESpercent:
+			vc_state = ESnormal;
+			switch (c) {
+			    case '@':  /* defined in ISO 2022 */
+				utf = 0;
+				continue;
+			    case 'G':  /* prelim official escape code */
+			    case '8':  /* retained for compatibility */
+				utf = 1;
+				continue;
+			}
+			continue;
+		    case ESfunckey:
+			vc_state = ESnormal;
+			continue;
+		    case EShash:
+			vc_state = ESnormal;
+			if (c == '8') {
+				/* DEC screen alignment test. kludge :-) */
+				video_erase_char =
+					(video_erase_char & 0xff00) | 'E';
+				/* Arno:
+				 * Doesn't work, because csi_J(c,2)
+				 * calls con_clear and doesn't print
+				 * the erase char..
+				 */
+				csi_J(currcons, 2);
+				video_erase_char =
+					(video_erase_char & 0xff00) | ' ';
+			}
+			continue;
+		    case ESsetG0:
+			if (c == '0')
+				G0_charset = GRAF_MAP;
+			else if (c == 'B')
+				G0_charset = LAT1_MAP;
+			else if (c == 'U')
+				G0_charset = IBMPC_MAP;
+			else if (c == 'K')
+				G0_charset = USER_MAP;
+			if (charset == 0)
+				translate = set_translate(G0_charset);
+			vc_state = ESnormal;
+			continue;
+		    case ESsetG1:
+			if (c == '0')
+				G1_charset = GRAF_MAP;
+			else if (c == 'B')
+				G1_charset = LAT1_MAP;
+			else if (c == 'U')
+				G1_charset = IBMPC_MAP;
+			else if (c == 'K')
+				G1_charset = USER_MAP;
+			if (charset == 1)
+				translate = set_translate(G1_charset);
+			vc_state = ESnormal;
+			continue;
+		    default:
+			vc_state = ESnormal;
+		}
+	}
+	if (vcmode != KD_GRAPHICS)
+		set_cursor(currcons);
+	enable_bh(CONSOLE_BH);
+	return n;
+}
+
+static int con_write_room(struct tty_struct *tty)
+{
+	if (tty->stopped)
+		return 0;
+	return 4096;		/* No limit, really; we're not buffering */
+}
+
+static int con_chars_in_buffer(struct tty_struct *tty)
+{
+	return 0;		/* we're not buffering */
+}
+
+void poke_blanked_console(void)
+{
+	timer_active &= ~(1<<BLANK_TIMER);
+	if (vt_cons[fg_console]->vc_mode == KD_GRAPHICS)
+		return;
+	if (console_blanked) {
+		timer_table[BLANK_TIMER].fn = unblank_screen;
+		timer_table[BLANK_TIMER].expires = 0;
+		timer_active |= 1<<BLANK_TIMER;
+	} else if (blankinterval) {
+		timer_table[BLANK_TIMER].expires = jiffies + blankinterval;
+		timer_active |= 1<<BLANK_TIMER;
+	}
+}
+
+/* DPC: New version of console_print using putcs */
+
+void console_print(const char * b)
+{
+   int currcons = fg_console;
+   unsigned char c;
+   const char *start = b;
+   ushort count      = 0;
+   ushort myx        = x;
+   static int printing = 0;
+
+   if (!printable || printing)
+	   return;	 /* console not yet initialized */
+   printing = 1;
+
+   if (kmsg_redirect && vc_cons_allocated(kmsg_redirect - 1))
+	   currcons = kmsg_redirect - 1;
+
+   if (!vc_cons_allocated(currcons)) {
+	   /* impossible */
+	   printk("console_print: tty %d not allocated ??\n", currcons+1);
+	   printing = 0;
+	   return;
+   }
+
+   /* undraw cursor first */
+   hide_cursor(currcons);
+
+   /* Contrived structure to try and emulate original need_wrap behaviour
+    * Problems caused when we have need_wrap set on '\n' character */
+   
+   while ((c = *(b++)) != 0) {
+       if (c == 10 || c == 13 || c == 8 || need_wrap) {
+           if ((count = b - start - 1) > 0) {
+               sw->con_putcs(vc_cons[currcons].d, start, count ,
+                             y, x);
+               x += count;
+	       if (need_wrap)
+		 x--;
+           }
+
+	   if (c == 8) {	/* backspace */
+	       bs(currcons);
+	       start = b;
+	       myx = x;
+	       continue;
+	   }
+           if (c != 13)
+               lf(currcons);
+           cr(currcons);
+
+           if (c == 10 || c == 13) {
+               start = b; myx = x; continue;
+           }
+
+           start = b-1; myx = x;
+       }
+
+       *pos = c | (attr << 8);
+       if (myx == cols - 1) {
+           need_wrap = 1;
+           continue;
+       }
+       pos++;
+       myx++;
+   }
+
+   if ((count = b - start -1) > 0) {
+       sw->con_putcs(vc_cons[currcons].d, start, count ,
+                     y, x);
+       x += count;
+       if (x == cols)
+	 {
+	   x--;
+           need_wrap = 1;
+	 }
+   }
+   
+   set_cursor(currcons);
+   poke_blanked_console();
+   printing = 0;
+}
+
+
+/*
+ * con_throttle and con_unthrottle are only used for
+ * paste_selection(), which has to stuff in a large number of
+ * characters...
+ */
+static void con_throttle(struct tty_struct *tty)
+{
+}
+
+static void con_unthrottle(struct tty_struct *tty)
+{
+	struct vt_struct *vt = (struct vt_struct *) tty->driver_data;
+
+	wake_up_interruptible(&vt->paste_wait);
+}
+
+static void vc_init(unsigned int currcons, int do_clear)
+{
+	long base = (long) vc_scrbuf[currcons];
+
+	pos = (unsigned short *)(origin = (ulong)video_mem_start = base);
+	scr_end = base + screenbuf_size;
+	video_mem_end = base + screenbuf_size;
+	reset_vc(currcons);
+	def_color       = 0x07;   /* white */
+	ulcolor		= 0x0f;   /* bold white */
+	halfcolor       = 0x08;   /* grey */
+	vt_cons[currcons]->paste_wait = 0;
+	reset_terminal(currcons, do_clear);
+}
+
+/*
+ * This is the console switching bottom half handler.
+ *
+ * Doing console switching in a bottom half handler allows
+ * us to do the switches asynchronously (needed when we want
+ * to switch due to a keyboard interrupt), while still giving
+ * us the option to easily disable it to avoid races when we
+ * need to write to the console.
+ */
+static void console_bh(void)
+{
+	if (want_console >= 0) {
+		if (want_console != fg_console) {
+			change_console(want_console);
+			/* we only changed when the console had already
+			   been allocated - a new console is not created
+			   in an interrupt routine */
+		}
+		want_console = -1;
+	}
+	if (do_poke_blanked_console) { /* do not unblank for a LED change */
+		do_poke_blanked_console = 0;
+		poke_blanked_console();
+	}
+}
+
+/*
+ *  unsigned long con_init(unsigned long);
+ *
+ * This routine initializes console interrupts, and does nothing
+ * else. If you want the screen to clear, call tty_write with
+ * the appropriate escape-sequence.
+ *
+ * Reads the information preserved by setup.s to determine the current display
+ * type and sets everything accordingly.
+ */
+unsigned long con_init(unsigned long kmem_start)
+{
+	char *display_desc = "????";
+	unsigned int currcons = 0;
+	extern int serial_debug;
+
+	memset(&console_driver, 0, sizeof(struct tty_driver));
+	console_driver.magic = TTY_DRIVER_MAGIC;
+	console_driver.name = "tty";
+	console_driver.name_base = 1;
+	console_driver.major = TTY_MAJOR;
+	console_driver.minor_start = 1;
+	console_driver.num = MAX_NR_CONSOLES;
+	console_driver.type = TTY_DRIVER_TYPE_CONSOLE;
+	console_driver.init_termios = tty_std_termios;
+	console_driver.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_RESET_TERMIOS;
+	console_driver.refcount = &console_refcount;
+	console_driver.table = console_table;
+	console_driver.termios = console_termios;
+	console_driver.termios_locked = console_termios_locked;
+
+	console_driver.open = con_open;
+	console_driver.write = con_write;
+	console_driver.write_room = con_write_room;
+	console_driver.chars_in_buffer = con_chars_in_buffer;
+	console_driver.ioctl = vt_ioctl;
+	console_driver.stop = con_stop;
+	console_driver.start = con_start;
+	console_driver.throttle = con_throttle;
+	console_driver.unthrottle = con_unthrottle;
+	
+	if (tty_register_driver(&console_driver))
+		panic("Couldn't register console driver\n");
+	
+	kmem_start = conswitchp->con_startup (kmem_start, &display_desc);
+
+	timer_table[BLANK_TIMER].fn = blank_screen;
+	timer_table[BLANK_TIMER].expires = 0;
+	if (blankinterval) {
+		timer_table[BLANK_TIMER].expires = jiffies + blankinterval;
+		timer_active |= 1<<BLANK_TIMER;
+	}
+
+	/* Due to kmalloc roundup allocating statically is more efficient -
+	   so provide MIN_NR_CONSOLES for people with very little memory */
+	for (currcons = 0; currcons < MIN_NR_CONSOLES; currcons++) {
+		vc_cons[currcons].d = (struct vc_data *) kmem_start;
+		kmem_start += sizeof(struct vc_data);
+		vt_cons[currcons] = (struct vt_struct *) kmem_start;
+		kmem_start += sizeof(struct vt_struct);
+
+		/* ++Geert: sw->con_init determines console size */
+		sw = conswitchp;
+		cons_num = currcons;
+		sw->con_init (vc_cons[currcons].d);
+		size_row = cols<<1;
+		screenbuf_size = rows*size_row;
+
+		vc_scrbuf[currcons] = (unsigned short *) kmem_start;
+		kmem_start += screenbuf_size;
+		kmalloced = 0;
+		vc_init(currcons, currcons);
+	}
+
+	currcons = fg_console = 0;
+
+	gotoxy(currcons,0,0);
+	csi_J(currcons, 0);
+	printable = 1;
+	update_screen(fg_console);
+	sw->con_cursor(vc_cons[currcons].d, CM_DRAW);
+	printable = 1;
+
+	/* If "serdebug" cmd line option was present, don't register for printk */
+	if (!serial_debug)
+		register_console(console_print);
+	printk("Console: %s %s %ldx%ld, %d virtual console%s (max %d)\n",
+		can_do_color ? "colour":"mono",
+		display_desc,
+		cols,rows,
+		MIN_NR_CONSOLES, (MIN_NR_CONSOLES == 1) ? "" : "s", MAX_NR_CONSOLES);
+
+	init_bh(CONSOLE_BH, console_bh);
+	return kmem_start;
+}
+
+void do_blank_screen(int nopowersave)
+{
+	int currcons;
+
+	if (console_blanked)
+		return;
+
+	if (!vc_cons_allocated(fg_console)) {
+		/* impossible */
+		printk("blank_screen: tty %d not allocated ??\n", fg_console+1);
+		return;
+	}
+
+	/* don't blank graphics */
+	if (vt_cons[fg_console]->vc_mode == KD_TEXT) {
+		timer_active &= ~(1<<BLANK_TIMER);
+		timer_table[BLANK_TIMER].fn = unblank_screen;
+
+		/* try not to lose information by blanking,
+		   and not to waste memory */
+		currcons = fg_console;
+		has_scrolled = 0;
+		sw->con_blank (1);
+	}
+	else
+		hide_cursor(fg_console);
+ 	console_blanked = fg_console + 1;
+}
+
+void do_unblank_screen(void)
+{
+	int currcons;
+
+	if (!console_blanked)
+		return;
+	if (!vc_cons_allocated(fg_console)) {
+		/* impossible */
+		printk("unblank_screen: tty %d not allocated ??\n", fg_console+1);
+		return;
+	}
+	timer_table[BLANK_TIMER].fn = blank_screen;
+	if (blankinterval) {
+		timer_table[BLANK_TIMER].expires = jiffies + blankinterval;
+		timer_active |= 1<<BLANK_TIMER;
+	}
+
+	currcons = fg_console;
+  	console_blanked = 0;
+	if (sw->con_blank (0))
+		/* Low-level driver cannot restore -> do it ourselves */
+	  	update_screen( fg_console );
+	set_cursor (fg_console);
+}
+
+void update_screen(int new_console)
+{
+	int currcons = fg_console;
+	int xx, yy, startx, attr_save;
+	char buf[256], *bufp;
+	unsigned short *p;
+	static int lock = 0;
+
+	if (/* new_console == fg_console || */ lock)
+		return;
+	if (!vc_cons_allocated(new_console)) {
+		/* strange ... */
+		printk("update_screen: tty %d not allocated ??\n", new_console+1);
+		return;
+	}
+	lock = 1;
+
+	clear_selection();
+
+	currcons = fg_console = new_console;
+	sw->con_cursor (vc_cons[currcons].d, CM_ERASE);
+	sw->con_switch (vc_cons[new_console].d);
+	/* Update the screen contents */
+	p = video_mem_start;
+	attr_save = attr;
+	for (yy = 0; yy < rows; yy++)
+	  {
+	    bufp = buf;
+	    for (startx = xx = 0; xx < cols; xx++)
+	      {
+		if (attr != ((*p >> 8) & 0xff))
+		  {
+		    if (bufp > buf)
+		      sw->con_putcs (vc_cons[currcons].d, buf, bufp - buf,
+				     yy, startx);
+		    startx = xx;
+		    bufp = buf;
+		    attr = (*p >> 8) & 0xff;
+		  }
+		*bufp++ = *p++;
+		if (bufp == buf + sizeof (buf))
+		  {
+		    sw->con_putcs (vc_cons[currcons].d, buf, bufp - buf,
+				   yy, startx);
+		    startx = xx + 1;
+		    bufp = buf;
+		  }
+	      }
+	    if (bufp > buf)
+	      sw->con_putcs (vc_cons[currcons].d, buf, bufp - buf,
+			     yy, startx);
+	  }
+	set_cursor (currcons);
+	attr = attr_save;
+	set_leds();
+	compute_shiftstate();
+	lock = 0;
+}
+
+/*
+ * If a blank_screen is due to a timer, then a power save is allowed.
+ * If it is related to console_switching, then avoid vesa_blank().
+ */
+static void blank_screen(void)
+{
+	do_blank_screen(0);
+}
+
+static void unblank_screen(void)
+{
+	do_unblank_screen();
+}
+
+/*
+ * Allocate the console screen memory.
+ */
+int con_open(struct tty_struct *tty, struct file * filp)
+{
+	unsigned int currcons;
+	int i;
+
+	currcons = MINOR(tty->device) - tty->driver.minor_start;
+	
+	i = vc_allocate(currcons);
+	if (i)
+		return i;
+
+	vt_cons[currcons]->vc_num = currcons;
+	tty->driver_data = vt_cons[currcons];
+	
+	if (!tty->winsize.ws_row && !tty->winsize.ws_col) {
+		tty->winsize.ws_row = rows;
+		tty->winsize.ws_col = cols;
+ 	}
+
+	return 0;
+}
+
+/*
+ * PIO_FONT support.
+ *
+ * The font loading code goes back to the codepage package by
+ * Joel Hoffman (joel@wam.umd.edu). (He reports that the original
+ * reference is: "From: p. 307 of _Programmer's Guide to PC & PS/2
+ * Video Systems_ by Richard Wilton. 1987.  Microsoft Press".)
+ *
+ * Change for certain monochrome monitors by Yury Shevchuck
+ * (sizif@botik.yaroslavl.su).
+ */
+
+#define colourmap ((char *)0xa0000)
+/* Pauline Middelink <middelin@polyware.iaf.nl> reports that we
+   should use 0xA0000 for the bwmap as well.. */
+#define blackwmap ((char *)0xa0000)
+#define cmapsz 8192
+#define seq_port_reg (0x3c4)
+#define seq_port_val (0x3c5)
+#define gr_port_reg (0x3ce)
+#define gr_port_val (0x3cf)
+
+static int set_get_font(char * arg, int set)
+{
+#ifdef CAN_LOAD_EGA_FONTS
+	int i;
+	char *charmap;
+	int beg;
+
+	/* no use to "load" CGA... */
+
+	if (video_type == VIDEO_TYPE_EGAC) {
+		charmap = colourmap;
+		beg = 0x0e;
+	} else if (video_type == VIDEO_TYPE_EGAM) {
+		charmap = blackwmap;
+		beg = 0x0a;
+	} else
+		return -EINVAL;
+
+	i = verify_area(set ? VERIFY_READ : VERIFY_WRITE, (void *)arg, cmapsz);
+	if (i)
+		return i;
+
+	cli();
+	outb_p( 0x00, seq_port_reg );   /* First, the sequencer */
+	outb_p( 0x01, seq_port_val );   /* Synchronous reset */
+	outb_p( 0x02, seq_port_reg );
+	outb_p( 0x04, seq_port_val );   /* CPU writes only to map 2 */
+	outb_p( 0x04, seq_port_reg );
+	outb_p( 0x07, seq_port_val );   /* Sequential addressing */
+	outb_p( 0x00, seq_port_reg );
+	outb_p( 0x03, seq_port_val );   /* Clear synchronous reset */
+
+	outb_p( 0x04, gr_port_reg );    /* Now, the graphics controller */
+	outb_p( 0x02, gr_port_val );    /* select map 2 */
+	outb_p( 0x05, gr_port_reg );
+	outb_p( 0x00, gr_port_val );    /* disable odd-even addressing */
+	outb_p( 0x06, gr_port_reg );
+	outb_p( 0x00, gr_port_val );    /* map start at A000:0000 */
+	sti();
+
+	if (set)
+		memcpy_fromfs (charmap, arg, cmapsz);
+	else
+		memcpy_tofs (arg, charmap, cmapsz);
+
+	cli();
+	outb_p( 0x00, seq_port_reg );   /* First, the sequencer */
+	outb_p( 0x01, seq_port_val );   /* Synchronous reset */
+	outb_p( 0x02, seq_port_reg );
+	outb_p( 0x03, seq_port_val );   /* CPU writes to maps 0 and 1 */
+	outb_p( 0x04, seq_port_reg );
+	outb_p( 0x03, seq_port_val );   /* odd-even addressing */
+	outb_p( 0x00, seq_port_reg );
+	outb_p( 0x03, seq_port_val );   /* clear synchronous reset */
+
+	outb_p( 0x04, gr_port_reg );    /* Now, the graphics controller */
+	outb_p( 0x00, gr_port_val );    /* select map 0 for CPU */
+	outb_p( 0x05, gr_port_reg );
+	outb_p( 0x10, gr_port_val );    /* enable even-odd addressing */
+	outb_p( 0x06, gr_port_reg );
+	outb_p( beg, gr_port_val );     /* map starts at b800:0 or b000:0 */
+	sti();
+
+	return 0;
+#else
+	return -EINVAL;
+#endif
+}
+
+/*
+ * Load palette into the EGA/VGA DAC registers. arg points to a colour
+ * map, 3 bytes per colour, 16 colours, range from 0 to 255.
+ */
+
+int con_set_cmap (unsigned char *arg)
+{
+	return -EINVAL;
+}
+
+int con_get_cmap (unsigned char *arg)
+{
+	return -EINVAL;
+}
+
+void reset_palette(int currcons)
+{
+}
+
+void set_palette(void)
+{
+}
+
+/*
+ * Load font into the EGA/VGA character generator. arg points to a 8192
+ * byte map, 32 bytes per character. Only first H of them are used for
+ * 8xH fonts (0 < H <= 32).
+ */
+
+int con_set_font (char *arg)
+{
+	hashtable_contents_valid = 0;
+	return set_get_font (arg,1);
+}
+
+int con_get_font (char *arg)
+{
+	return set_get_font (arg,0);
+}
+
+/*
+ * Adjust the screen to fit a font of a certain height
+ *
+ * Returns < 0 for error, 0 if nothing changed, and the number
+ * of lines on the adjusted console if changed.
+ */
+int con_adjust_height(unsigned long fontheight)
+{
+	return -EINVAL;
+}
+
+void set_vesa_blanking(int arg)
+{
+}
+
+unsigned long get_video_num_lines(unsigned int currcons)
+{
+	return(rows);
+}
+
+unsigned long get_video_num_columns(unsigned int currcons)
+{
+	return(cols);
+}
+
+unsigned long get_video_size_row(unsigned int currcons)
+{
+	return(size_row);
+}
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/kernel/entry.S linux/arch/m68k/kernel/entry.S
--- v1.3.93/linux/arch/m68k/kernel/entry.S	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/kernel/entry.S	Sat Apr 13 17:53:59 1996
@@ -0,0 +1,641 @@
+/* -*- mode: asm -*-
+ *
+ *  linux/arch/m68k/kernel/entry.S
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file README.legal in the main directory of this archive
+ * for more details.
+ *
+ * 680x0 support by Hamish Macdonald
+ *
+ */
+
+/*
+ * entry.S  contains the system-call and fault low-level handling routines.
+ * This also contains the timer-interrupt handler, as well as all interrupts
+ * and faults that can result in a task-switch.
+ *
+ * NOTE: This code handles signal-recognition, which happens every time
+ * after a timer-interrupt and after each system call.
+ *
+ * Stack layout in 'ret_from_exception':
+ *
+ *	This allows access to the syscall arguments in registers d1-d5
+ *
+ *	 0(sp) - d1
+ *	 4(sp) - d2
+ *	 8(sp) - d3
+ *	 C(sp) - d4
+ *	10(sp) - d5
+ *	14(sp) - a0
+ *	18(sp) - a1
+ *	1C(sp) - d0
+ *	20(sp) - orig_d0
+ *	24(sp) - stack adjustment
+ *	28(sp) - sr
+ *	2A(sp) - pc
+ *	2E(sp) - format & vector
+ */
+
+/*
+ * 12/03/96 Jes: Currently we only support m68k single-cpu systems, so
+ *               all pointers that used to be 'current' are now entry
+ *               number 0 in the 'current_set' list.
+ */
+
+#include <linux/sys.h>
+
+#include <asm/segment.h>
+
+LCF_MASK	= 0x0001
+
+LENOSYS = 38
+
+/*
+ * these are offsets into the task-struct
+ */
+LTASK_STATE	=  0
+LTASK_COUNTER	=  4
+LTASK_PRIORITY	=  8
+LTASK_SIGNAL	= 12
+LTASK_BLOCKED	= 16
+LTASK_FLAGS	= 20
+LTASK_ERRNO	= 24
+
+#include <linux/config.h>
+#include <linux/linkage.h>
+
+/* the following macro is used when enabling interrupts */
+#if defined(CONFIG_ATARI) && !defined(CONFIG_AMIGA) && !defined(CONFIG_MAC)
+	/* block out HSYNC on the atari */
+#define ALLOWINT 0xfbff
+#else
+	/* portable version */
+#define ALLOWINT 0xf8ff
+#endif /* machine compilation types */ 
+
+LD0		= 0x1C
+LORIG_D0	= 0x20
+LSR		= 0x28
+LFORMATVEC	= 0x2E
+
+/*
+ * This defines the normal kernel pt-regs layout.
+ *
+ * regs are a2-a6 and d6-d7 preserved by C code
+ * the kernel doesn't mess with usp unless it needs to
+ */
+#define SAVE_ALL			\
+	clrl	%sp@-;    /* stk_adj */	\
+	movel	%d0,%sp@-; /* orig d0 */	\
+	movel	%d0,%sp@-; /* d0 */	\
+	moveml	%d1-%d5/%a0-%a1,%sp@-
+
+#define RESTORE_ALL			\
+	moveml	%sp@+,%a0-%a1/%d1-%d5;	\
+	movel	%sp@+,%d0;		\
+	addql	#4,%sp;	 /* orig d0 */	\
+	addl	%sp@+,%sp; /* stk adj */	\
+	rte
+
+#define SWITCH_STACK_SIZE (7*4+4)	/* includes return address */
+
+#define SAVE_SWITCH_STACK \
+	moveml	%a2-%a6/%d6-%d7,%sp@-
+
+#define RESTORE_SWITCH_STACK \
+	moveml	%sp@+,%a2-%a6/%d6-%d7
+
+.globl SYMBOL_NAME(system_call), SYMBOL_NAME(buserr), SYMBOL_NAME(trap)
+.globl SYMBOL_NAME(resume), SYMBOL_NAME(ret_from_exception)
+.globl SYMBOL_NAME(ret_from_signal)
+.globl SYMBOL_NAME(inthandler), SYMBOL_NAME(sys_call_table)
+.globl SYMBOL_NAME(sys_fork), SYMBOL_NAME(sys_clone)
+.globl SYMBOL_NAME(ret_from_interrupt), SYMBOL_NAME(bad_interrupt)
+
+.text
+ENTRY(buserr)
+	SAVE_ALL
+	moveq	#-1,%d0
+	movel	%d0,%sp@(LORIG_D0)	| a -1 in the ORIG_D0 field
+					| signifies that the stack frame
+					| is NOT for syscall
+
+	movel	%sp,%sp@- 		| stack frame pointer argument
+	bsrl	SYMBOL_NAME(buserr_c)
+	addql	#4,%sp
+	jra	SYMBOL_NAME(ret_from_exception)
+
+ENTRY(trap)
+	SAVE_ALL
+	moveq	#-1,%d0
+	movel	%d0,%sp@(LORIG_D0)	| a -1 in the ORIG_D0 field
+					| signifies that the stack frame
+					| is NOT for syscall
+	movel	%sp,%sp@- 		| stack frame pointer argument
+	bsrl	SYMBOL_NAME(trap_c)
+	addql	#4,%sp
+	jra	SYMBOL_NAME(ret_from_exception)
+
+ENTRY(reschedule)
+	| save top of frame
+	pea	%sp@
+	jbsr	SYMBOL_NAME(set_esp0)
+	addql	#4,%sp
+
+	pea	SYMBOL_NAME(ret_from_exception)
+	jmp	SYMBOL_NAME(schedule)
+
+ENTRY(system_call)
+	SAVE_ALL
+	movel	#-LENOSYS,LD0(%sp)	| default return value in d0
+					| original D0 is in orig_d0
+	movel	%d0,%d2
+
+	| save top of frame
+	pea	%sp@
+	jbsr	SYMBOL_NAME(set_esp0)
+	addql	#4,%sp
+
+	cmpl	#NR_syscalls,%d2
+	jcc	SYMBOL_NAME(ret_from_exception)
+	lea	SYMBOL_NAME(sys_call_table),%a0
+	movel	%a0@(%d2:l:4),%d3
+	jeq	SYMBOL_NAME(ret_from_exception)
+	andw	#~LCF_MASK,%sp@(LSR)	| assume syscall success
+	movel	SYMBOL_NAME(current_set),%a0
+	clrl	%a0@(LTASK_ERRNO)
+	btst	#5,%a0@(LTASK_FLAGS+3)	| PF_TRACESYS
+	bnes	1f
+	movel	%d3,%a0
+	jbsr	%a0@
+	movel	%d0,%sp@(LD0)		| save the return value
+	jpl	2f
+	orw	#LCF_MASK,%sp@(LSR)	| set carry to indicate error
+2:
+	movel	SYMBOL_NAME(current_set),%a0
+	movel	%a0@(LTASK_ERRNO),%d1
+	negl	%d1
+	jeq	SYMBOL_NAME(ret_from_exception)
+	movel	%d1,%sp@(LD0)
+	orw	#LCF_MASK,%sp@(LSR)	| set carry to indicate error
+	jra	SYMBOL_NAME(ret_from_exception)
+1:
+	subql	#4,%sp
+	SAVE_SWITCH_STACK
+	jbsr	SYMBOL_NAME(syscall_trace)
+	RESTORE_SWITCH_STACK
+	addql	#4,%sp
+	movel	%d3,%a0
+	jbsr	%a0@
+	movel	%d0,%sp@(LD0)		| save the return value
+	jpl	2f
+	orw	#LCF_MASK,%sp@(LSR)	| set carry to indicate error
+2:
+	movel	SYMBOL_NAME(current_set),%a0
+	movel	%a0@(LTASK_ERRNO),%d1
+	negl	%d1
+	jeq	2f
+	movel	%d1,%sp@(LD0)
+	orw	#LCF_MASK,%sp@(LSR)	| set carry to indicate error
+2:	subql	#4,%sp			| dummy return address
+	SAVE_SWITCH_STACK
+	jbsr	SYMBOL_NAME(syscall_trace)
+
+SYMBOL_NAME_LABEL(ret_from_signal)
+	RESTORE_SWITCH_STACK
+	addql	#4,%sp
+
+SYMBOL_NAME_LABEL(ret_from_exception)
+	btst	#5,%sp@(LSR)		| check if returning to kernel
+	bnes	2f			| if so, skip resched, signals
+	tstl	SYMBOL_NAME(need_resched)
+	jne	SYMBOL_NAME(reschedule)
+	movel	SYMBOL_NAME(current_set),%a0
+	cmpl	#SYMBOL_NAME(task),%a0	| task[0] cannot have signals
+	jeq	2f
+	bclr	#5,%a0@(LTASK_FLAGS+1)	| check for delayed trace
+	jeq	1f
+	bclr	#7,%sp@(LSR)		| clear trace bit in SR
+	pea	1			| send SIGTRAP
+	movel	%a0,%sp@-
+	pea	5
+	jbsr	SYMBOL_NAME(send_sig)
+	addql	#8,%sp
+	addql	#4,%sp
+
+1:
+	moveq	#0,%d0
+	movel	SYMBOL_NAME(current_set),%a0
+	cmpl	%a0@(LTASK_STATE),%d0     | state
+	jne	SYMBOL_NAME(reschedule)
+	cmpl	%a0@(LTASK_COUNTER),%d0   | counter
+	jeq	SYMBOL_NAME(reschedule)
+
+	.word	0xf4f8
+	movel	%a0@(LTASK_BLOCKED),%d0
+	movel	%d0,%d1			| save blocked in d1 for sig handling
+	notl	%d0
+	andl	%a0@(LTASK_SIGNAL),%d0
+	jne	Lsignal_return
+2:	RESTORE_ALL
+
+Lsignal_return:
+	subql	#4,%sp			| dummy return address
+	SAVE_SWITCH_STACK
+	pea	%sp@(SWITCH_STACK_SIZE)
+	movel	%d1,%sp@-
+	bsrl	SYMBOL_NAME(do_signal)
+	addql	#8,%sp
+	RESTORE_SWITCH_STACK
+	addql	#4,%sp
+	RESTORE_ALL
+
+/*
+** This is the main interrupt handler, responsible for calling process_int()
+*/
+SYMBOL_NAME_LABEL(inthandler)
+	SAVE_ALL
+	moveq	#-1,%d0
+	movel	%d0,%sp@(LORIG_D0)	| a -1 in the ORIG_D0 field
+					| signifies that the stack frame
+					| is NOT for syscall
+	
+	addql	#1,SYMBOL_NAME(intr_count)
+
+	movew	%sp@(LFORMATVEC),%d0      |  put exception # in d0
+	andil	#0xfff,%d0		|  mask out format nybble
+
+	movel	%sp,%sp@-		
+	movel	%d0,%sp@- 		|  put vector # on stack
+	jbsr	SYMBOL_NAME(process_int)|  process the IRQ
+	addql	#8,%sp			|  pop parameters off stack
+
+SYMBOL_NAME_LABEL(ret_from_interrupt)
+	/* check if we need to do software interrupts */
+1:
+	movel	SYMBOL_NAME(intr_count),%d2
+	subql	#1,%d2
+	jne	2f
+
+	movel	SYMBOL_NAME(bh_active),%d0
+	andl	SYMBOL_NAME(bh_mask),%d0
+	jne	3f
+
+	movel	%d2,SYMBOL_NAME(intr_count)
+
+	jra	SYMBOL_NAME(ret_from_exception)
+					| deliver signals, reschedule etc..
+
+2:	movel	%d2,SYMBOL_NAME(intr_count)
+	RESTORE_ALL
+3:
+	movew	%sr,%sp@-
+	andiw	#(ALLOWINT),%sr		| allow interrupts
+	jbsr	SYMBOL_NAME(do_bottom_half)
+	movew	%sp@+,%sr
+	jra	1b
+
+
+/* Handler for uninitialized and spurious interrupts */
+
+SYMBOL_NAME_LABEL(bad_interrupt)
+	addql	#1,SYMBOL_NAME(num_spurious)
+	rte
+
+ENTRY(sys_fork)
+	SAVE_SWITCH_STACK	
+	pea	%sp@(SWITCH_STACK_SIZE)
+	jbsr	SYMBOL_NAME(m68k_fork)
+	addql	#4,%sp
+	RESTORE_SWITCH_STACK
+	rts
+
+ENTRY(sys_clone)
+	SAVE_SWITCH_STACK
+	pea	%sp@(SWITCH_STACK_SIZE)
+	jbsr	SYMBOL_NAME(m68k_clone)
+	addql	#4,%sp
+	RESTORE_SWITCH_STACK
+	rts
+
+ENTRY(sys_sigsuspend)
+	SAVE_SWITCH_STACK
+	pea	%sp@(SWITCH_STACK_SIZE)
+	jbsr	SYMBOL_NAME(do_sigsuspend)
+	addql	#4,%sp
+	RESTORE_SWITCH_STACK
+	rts
+
+ENTRY(sys_sigreturn)
+	SAVE_SWITCH_STACK
+	jbsr	SYMBOL_NAME(do_sigreturn)
+	RESTORE_SWITCH_STACK
+	rts
+
+LFLUSH_I_AND_D = 0x00000808
+LBI_CPU = 4
+LTSS_KSP	= 0
+LTSS_USP	= 4
+LTSS_SR		= 8
+LTSS_FS		= 10
+LTSS_CRP	= 20
+LTSS_FPCTXT	= 32
+
+SYMBOL_NAME_LABEL(resume)
+	/*
+	 * Beware - when entering resume, offset of tss is in a1 and
+	 * next (the new task) is in d1, so don't chance these
+	 * registers before their contents have been used.
+	 */
+	
+	/* current tasks task_struct */
+ 	movel	SYMBOL_NAME(current_set),%a0
+
+	/* offset of tss struct (processor state) from beginning
+	   of task struct */
+/*
+	movel	%sp@(8),%a1
+*/
+	addl	%a1,%a0
+
+	/* save sr */
+	movew	%sr,%a0@(LTSS_SR)
+
+	/* disable interrupts */
+	oriw	#0x0700,%sr
+
+	/* save fs (sfc,%dfc) (may be pointing to kernel memory) */
+	movec	%sfc,%d0
+	movew	%d0,%a0@(LTSS_FS)
+
+	/* save usp */
+	/* it is better to use a movel here instead of a movew 8*) */
+	movec	%usp,%d0
+	movel	%d0,%a0@(LTSS_USP)
+
+	/* load new task (before adjusting stack) */
+	/* The task has already been put in d1 by switch_to (Jes) */
+/*
+	movel	%sp@(4),%d1
+*/
+	/* save non-scratch registers on stack */
+	SAVE_SWITCH_STACK
+
+	/* save current kernel stack pointer */
+	movel	%sp,%a0@(LTSS_KSP)
+
+	/* save floating point context */
+	fsave	%a0@(LTSS_FPCTXT+27*4)
+	tstb	%a0@(LTSS_FPCTXT+27*4)
+	jeq	1f
+	fmovemx	%fp0-%fp7,%a0@(LTSS_FPCTXT)
+	fmoveml	%fpcr/%fpsr/%fpiar,%a0@(LTSS_FPCTXT+24*4)
+1:
+
+	/* get pointer to tss struct (d1 contains new task) */
+	movel	%d1,SYMBOL_NAME(current_set)
+	movel	%d1,%a0
+	addl	%a1,%a0
+
+	/* 68040 or 68060 ? */
+	btst	#2,SYMBOL_NAME(boot_info)+LBI_CPU+3
+	bnes	1f
+	btst	#3,SYMBOL_NAME(boot_info)+LBI_CPU+3
+	bnes	1f
+
+	/*
+	 * switch address space
+	 */
+
+	/* flush MC68030/MC68020 caches (they are virtually addressed) */
+	movec	%cacr,%d0
+	oril	#LFLUSH_I_AND_D,%d0
+	movec	%d0,%cacr
+
+	/* switch the root pointer */
+	pmove	%a0@(LTSS_CRP),%crp
+
+	/* flush address translation cache (probably not needed */
+	pflusha
+
+	jra	2f	/* skip m68040 stuff */
+
+1:
+	/*
+	 * switch address space
+	 */
+
+	/* flush address translation cache (user entries) */
+	.word	0xf510			/* pflushan */
+
+	/* switch the root pointer */
+	movel	%a0@(LTSS_CRP+4),%d0
+	.long	0x4e7b0806		/* movec d0,urp */
+
+	/* is it a '060 ? */
+	btst	#3,SYMBOL_NAME(boot_info)+LBI_CPU+3
+	beqs	2f
+	/* clear user entries in the branch cache */
+	movec	%cacr,%d0
+	orl	#0x00200000,%d0
+	movec	%d0,%cacr
+
+2:
+	/* restore floating point context */
+	tstb	%a0@(LTSS_FPCTXT+27*4)
+	jeq	1f
+	fmovemx	%a0@(LTSS_FPCTXT),%fp0-%fp7
+	fmoveml	%a0@(LTSS_FPCTXT+24*4),%fpcr/%fpsr/%fpiar
+1:	frestore %a0@(LTSS_FPCTXT+27*4)
+
+	/* restore the kernel stack pointer */
+	movel	%a0@(LTSS_KSP),%sp
+
+	/* restore non-scratch registers */
+	RESTORE_SWITCH_STACK
+
+	/* restore user stack pointer */
+	movel	%a0@(LTSS_USP),%d0
+	movec	%d0,%usp
+
+	/* restore fs (sfc,%dfc) */
+	movew	%a0@(LTSS_FS),%a1
+	movec	%a1,%sfc
+	movec	%a1,%dfc
+
+	/* restore status register */
+	movew	%a0@(LTSS_SR),%sr
+
+	rts
+
+.data
+ALIGN
+SYMBOL_NAME_LABEL(sys_call_table)
+	.long SYMBOL_NAME(sys_setup)		/* 0 */
+	.long SYMBOL_NAME(sys_exit)
+	.long SYMBOL_NAME(sys_fork)
+	.long SYMBOL_NAME(sys_read)
+	.long SYMBOL_NAME(sys_write)
+	.long SYMBOL_NAME(sys_open)		/* 5 */
+	.long SYMBOL_NAME(sys_close)
+	.long SYMBOL_NAME(sys_waitpid)
+	.long SYMBOL_NAME(sys_creat)
+	.long SYMBOL_NAME(sys_link)
+	.long SYMBOL_NAME(sys_unlink)		/* 10 */
+	.long SYMBOL_NAME(sys_execve)
+	.long SYMBOL_NAME(sys_chdir)
+	.long SYMBOL_NAME(sys_time)
+	.long SYMBOL_NAME(sys_mknod)
+	.long SYMBOL_NAME(sys_chmod)		/* 15 */
+	.long SYMBOL_NAME(sys_chown)
+	.long SYMBOL_NAME(sys_break)
+	.long SYMBOL_NAME(sys_stat)
+	.long SYMBOL_NAME(sys_lseek)
+	.long SYMBOL_NAME(sys_getpid)		/* 20 */
+	.long SYMBOL_NAME(sys_mount)
+	.long SYMBOL_NAME(sys_umount)
+	.long SYMBOL_NAME(sys_setuid)
+	.long SYMBOL_NAME(sys_getuid)
+	.long SYMBOL_NAME(sys_stime)		/* 25 */
+	.long SYMBOL_NAME(sys_ptrace)
+	.long SYMBOL_NAME(sys_alarm)
+	.long SYMBOL_NAME(sys_fstat)
+	.long SYMBOL_NAME(sys_pause)
+	.long SYMBOL_NAME(sys_utime)		/* 30 */
+	.long SYMBOL_NAME(sys_stty)
+	.long SYMBOL_NAME(sys_gtty)
+	.long SYMBOL_NAME(sys_access)
+	.long SYMBOL_NAME(sys_nice)
+	.long SYMBOL_NAME(sys_ftime)		/* 35 */
+	.long SYMBOL_NAME(sys_sync)
+	.long SYMBOL_NAME(sys_kill)
+	.long SYMBOL_NAME(sys_rename)
+	.long SYMBOL_NAME(sys_mkdir)
+	.long SYMBOL_NAME(sys_rmdir)		/* 40 */
+	.long SYMBOL_NAME(sys_dup)
+	.long SYMBOL_NAME(sys_pipe)
+	.long SYMBOL_NAME(sys_times)
+	.long SYMBOL_NAME(sys_prof)
+	.long SYMBOL_NAME(sys_brk)		/* 45 */
+	.long SYMBOL_NAME(sys_setgid)
+	.long SYMBOL_NAME(sys_getgid)
+	.long SYMBOL_NAME(sys_signal)
+	.long SYMBOL_NAME(sys_geteuid)
+	.long SYMBOL_NAME(sys_getegid)		/* 50 */
+	.long SYMBOL_NAME(sys_acct)
+	.long SYMBOL_NAME(sys_phys)
+	.long SYMBOL_NAME(sys_lock)
+	.long SYMBOL_NAME(sys_ioctl)
+	.long SYMBOL_NAME(sys_fcntl)		/* 55 */
+	.long SYMBOL_NAME(sys_mpx)
+	.long SYMBOL_NAME(sys_setpgid)
+	.long SYMBOL_NAME(sys_ulimit)
+	.long SYMBOL_NAME(sys_olduname)
+	.long SYMBOL_NAME(sys_umask)		/* 60 */
+	.long SYMBOL_NAME(sys_chroot)
+	.long SYMBOL_NAME(sys_ustat)
+	.long SYMBOL_NAME(sys_dup2)
+	.long SYMBOL_NAME(sys_getppid)
+	.long SYMBOL_NAME(sys_getpgrp)		/* 65 */
+	.long SYMBOL_NAME(sys_setsid)
+	.long SYMBOL_NAME(sys_sigaction)
+	.long SYMBOL_NAME(sys_sgetmask)
+	.long SYMBOL_NAME(sys_ssetmask)
+	.long SYMBOL_NAME(sys_setreuid)		/* 70 */
+	.long SYMBOL_NAME(sys_setregid)
+	.long SYMBOL_NAME(sys_sigsuspend)
+	.long SYMBOL_NAME(sys_sigpending)
+	.long SYMBOL_NAME(sys_sethostname)
+	.long SYMBOL_NAME(sys_setrlimit)	/* 75 */
+	.long SYMBOL_NAME(sys_getrlimit)
+	.long SYMBOL_NAME(sys_getrusage)
+	.long SYMBOL_NAME(sys_gettimeofday)
+	.long SYMBOL_NAME(sys_settimeofday)
+	.long SYMBOL_NAME(sys_getgroups)	/* 80 */
+	.long SYMBOL_NAME(sys_setgroups)
+	.long SYMBOL_NAME(old_select)
+	.long SYMBOL_NAME(sys_symlink)
+	.long SYMBOL_NAME(sys_lstat)
+	.long SYMBOL_NAME(sys_readlink)		/* 85 */
+	.long SYMBOL_NAME(sys_uselib)
+	.long SYMBOL_NAME(sys_swapon)
+	.long SYMBOL_NAME(sys_reboot)
+	.long SYMBOL_NAME(old_readdir)
+	.long SYMBOL_NAME(old_mmap)		/* 90 */
+	.long SYMBOL_NAME(sys_munmap)
+	.long SYMBOL_NAME(sys_truncate)
+	.long SYMBOL_NAME(sys_ftruncate)
+	.long SYMBOL_NAME(sys_fchmod)
+	.long SYMBOL_NAME(sys_fchown)		/* 95 */
+	.long SYMBOL_NAME(sys_getpriority)
+	.long SYMBOL_NAME(sys_setpriority)
+	.long SYMBOL_NAME(sys_profil)
+	.long SYMBOL_NAME(sys_statfs)
+	.long SYMBOL_NAME(sys_fstatfs)		/* 100 */
+	.long SYMBOL_NAME(sys_ioperm)
+	.long SYMBOL_NAME(sys_socketcall)
+	.long SYMBOL_NAME(sys_syslog)
+	.long SYMBOL_NAME(sys_setitimer)
+	.long SYMBOL_NAME(sys_getitimer)	/* 105 */
+	.long SYMBOL_NAME(sys_newstat)
+	.long SYMBOL_NAME(sys_newlstat)
+	.long SYMBOL_NAME(sys_newfstat)
+	.long SYMBOL_NAME(sys_uname)
+	.long SYMBOL_NAME(sys_ni_syscall)	/* iopl for i386 */ /* 110 */
+	.long SYMBOL_NAME(sys_vhangup)
+	.long SYMBOL_NAME(sys_idle)
+	.long SYMBOL_NAME(sys_ni_syscall)	/* vm86 for i386 */
+	.long SYMBOL_NAME(sys_wait4)
+	.long SYMBOL_NAME(sys_swapoff)		/* 115 */
+	.long SYMBOL_NAME(sys_sysinfo)
+	.long SYMBOL_NAME(sys_ipc)
+	.long SYMBOL_NAME(sys_fsync)
+	.long SYMBOL_NAME(sys_sigreturn)
+	.long SYMBOL_NAME(sys_clone)		/* 120 */
+	.long SYMBOL_NAME(sys_setdomainname)
+	.long SYMBOL_NAME(sys_newuname)
+	.long SYMBOL_NAME(sys_ni_syscall)	/* modify_ldt for i386 */
+	.long SYMBOL_NAME(sys_adjtimex)
+	.long SYMBOL_NAME(sys_mprotect)		/* 125 */
+	.long SYMBOL_NAME(sys_sigprocmask)
+	.long SYMBOL_NAME(sys_create_module)
+	.long SYMBOL_NAME(sys_init_module)
+	.long SYMBOL_NAME(sys_delete_module)
+	.long SYMBOL_NAME(sys_get_kernel_syms)	/* 130 */
+	.long SYMBOL_NAME(sys_quotactl)
+	.long SYMBOL_NAME(sys_getpgid)
+	.long SYMBOL_NAME(sys_fchdir)
+	.long SYMBOL_NAME(sys_bdflush)
+	.long SYMBOL_NAME(sys_sysfs)		/* 135 */
+	.long SYMBOL_NAME(sys_personality)
+	.long SYMBOL_NAME(sys_ni_syscall)	/* for afs_syscall */
+	.long SYMBOL_NAME(sys_setfsuid)
+	.long SYMBOL_NAME(sys_setfsgid)
+	.long SYMBOL_NAME(sys_llseek)		/* 140 */
+	.long SYMBOL_NAME(sys_getdents)
+	.long SYMBOL_NAME(sys_select)
+	.long SYMBOL_NAME(sys_flock)
+	.long SYMBOL_NAME(sys_msync)
+	.long SYMBOL_NAME(sys_readv)		/* 145 */
+	.long SYMBOL_NAME(sys_writev)
+	.long SYMBOL_NAME(sys_getsid)
+	.long SYMBOL_NAME(sys_fdatasync)
+	.long SYMBOL_NAME(sys_sysctl)
+	.long SYMBOL_NAME(sys_mlock)		/* 150 */
+	.long SYMBOL_NAME(sys_munlock)
+	.long SYMBOL_NAME(sys_mlockall)
+	.long SYMBOL_NAME(sys_munlockall)
+	.long SYMBOL_NAME(sys_sched_setparam)
+	.long SYMBOL_NAME(sys_sched_getparam)   /* 155 */
+	.long SYMBOL_NAME(sys_sched_setscheduler)
+	.long SYMBOL_NAME(sys_sched_getscheduler)
+	.long SYMBOL_NAME(sys_sched_yield)
+	.long SYMBOL_NAME(sys_sched_get_priority_max)
+	.long SYMBOL_NAME(sys_sched_get_priority_min)  /* 160 */
+	.long SYMBOL_NAME(sys_sched_rr_get_interval)
+	.long SYMBOL_NAME(sys_nanosleep)
+	.long SYMBOL_NAME(sys_mremap)
+	.space (NR_syscalls-163)*4
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/kernel/head.S linux/arch/m68k/kernel/head.S
--- v1.3.93/linux/arch/m68k/kernel/head.S	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/kernel/head.S	Fri Apr 19 02:19:14 1996
@@ -0,0 +1,1206 @@
+/* -*- mode: asm -*-
+**
+** head.S -- This file contains the initial boot code for the the
+**	     Linux/68k kernel.
+**
+** Copyright 1993 by Hamish Macdonald
+**
+** 68040 fixes by Michael Rausch
+** 68060 fixes by Roman Hodek
+**
+** Atari support by Andreas Schwab, using ideas of Robert de Vries
+** and Bjoern Brauel
+**
+** 94/11/14 Andreas Schwab: put kernel at PAGESIZE
+** 94/11/18 Andreas Schwab: remove identity mapping of STRAM for Atari 
+** ++ Bjoern & Roman: ATARI-68040 support for the Medusa
+**
+** This file is subject to the terms and conditions of the GNU General Public
+** License.  See the file README.legal in the main directory of this archive
+** for more details.
+**
+*/
+
+/*
+ * Linux startup code.
+ *
+ * At this point, the boot loader has:
+ * Disabled interrupts
+ * Disabled caches
+ * Put us in supervisor state.
+ *
+ * The kernel setup code takes the following steps:
+ *   Raise interrupt level
+ *   Set up initial kernel memory mapping.
+ *	This sets up a mapping of the 4M of memory the kernel
+ *	is located in.	It also does a mapping of any initial
+ *	machine specific areas.
+ * Note that the kernel is located at virtual address 0x1000 == _start
+ *   Enable cache memories
+ *   Jump to kernel startup
+ *
+ * Register d6 contains the CPU flags and d4 the machine type
+ * from the boot_info information for most of this file.
+ * The upper word of d6 contains a bit for '040 or '060, since these two
+ * are quite similar for initial mm setup. Another bit in d6 allows
+ * distinction of the '060. The lower word of d6 contains the cache mode
+ * that should be applied to pages containing descriptors. This mode is
+ * non-cached/non-serialized for the '040 and cacheable/write-through for
+ * the '060.
+ */
+
+#include <linux/linkage.h>
+#include <asm/bootinfo.h>
+
+.text
+.globl SYMBOL_NAME(kernel_pg_dir), SYMBOL_NAME(kpt)
+.globl SYMBOL_NAME(availmem), SYMBOL_NAME(is_medusa)
+.globl SYMBOL_NAME(m68k_pgtable_cachemode)
+.globl SYMBOL_NAME(kernel_pmd_table), SYMBOL_NAME(swapper_pg_dir)
+
+PAGESIZE = 4096
+BI_CPU = 4
+BI_MACH = 0
+BI_AMIGA_ECLK = 1234
+LF   = 10
+CR   = 13
+BI_BIT040 = 2	/* CPU bits in bootinfo */
+BI_BIT060 = 3
+BIT0460   = 16	/* indicates '0[46]0 in d6 */
+BIT060    = 17	/* indicates '060 in d6 */
+D6VAL_040 = 0x00010000
+D6VAL_060 = 0x00030000
+/* BIT040 = 2 */
+
+     /* Some definitions for the special registers of the 68040.
+      * (MMU, caches)
+      */
+
+/* Translation control register */
+TC_ENABLE = 0x8000
+TC_PAGE8K = 0x4000
+TC_PAGE4K = 0x0000
+
+/* Transparent translation registers */
+TTR_ENABLE = 0x8000
+
+/* Some bits used in the page and table descriptors as well as in the 
+ * special registers.
+ */
+
+CM_CACHE_WT     = 0x0000          /* cacheable, write-through */
+CM_CACHE_CB     = 0x0020          /* cacheable, copyback */
+CM_NONCACHE_SER = 0x0040          /* noncacheable, serialized */
+CM_NONCACHE     = 0x0060          /* noncacheable */
+CM_MASK         = 0xffffff9f      /* mask */
+
+MODIFIED        = 0x0010
+WRITE_PROT      = 0x0004
+USED            = 0x0008
+GLOBAL          = 0x0400
+SV_ONLY         = 0x0080
+PAGEDESC	= 0x0001
+TABLEDESC	= 0x0002
+INVALID         = 0x0000
+
+/* Cache enabling */
+I_HALF		= 0x00002000	/* half-cache mode for I-cache ('060) */
+I_FREEZE	= 0x00004000	/* freeze I-cache ('060) */
+I_ENABLE        = 0x00008000	/* enable I-cache */
+BC_CLRU		= 0x00200000	/* clear user entries in branch cache ('060) */
+BC_CLRA		= 0x00400000	/* clear all entries in branch cache ('060) */
+BC_ENABLE	= 0x00800000	/* enable branch cache ('060) */
+D_HALF		= 0x08000000	/* half-cache mode for D-cache ('060) */
+PUSH_DPI	= 0x10000000	/* disable CPUSH invalidation ('060) */
+SB_ENABLE	= 0x20000000	/* enable store buffer ('060) */
+D_FREEZE	= 0x40000000	/* freeze D-cache ('060) */
+D_ENABLE        = 0x80000000	/* enable D-cache */
+
+/* Miscellaneous definitions */
+PAGE_MASK       = (~(PAGESIZE-1))
+
+ROOT_TABLE_SIZE = 128
+PTR_TABLE_SIZE  = 128
+PAGE_TABLE_SIZE = 64
+ROOT_INDEX_SHIFT = 25
+PAGE_INDEX_SHIFT = 12
+
+ENTRY(_stext)
+ENTRY(_start)
+	bras	1f /* Jump over bootinfo version numbers */
+/*
+ * Version numbers of the bootinfo interface
+ */
+
+	.long	BOOTINFOV_MAGIC
+	.long	MACH_AMIGA, AMIGA_BOOTI_VERSION
+	.long	MACH_ATARI, ATARI_BOOTI_VERSION
+	.long	0
+
+1:
+
+/*
+ * raise interrupt level
+ */
+
+	movew	#0x2700,%sr
+
+/*
+ * Copy bootinfo from position after BSS to final resting place
+ */
+	lea	%pc@(SYMBOL_NAME(_end)),%a0
+	lea	%pc@(SYMBOL_NAME(boot_info)),%a1
+	movel	%pc@(SYMBOL_NAME(bisize)),%d0
+	subql	#1,%d0
+1:	moveb	%a0@+,%a1@+
+	dbra	%d0,1b
+
+/*
+ * Record the CPU and machine type.
+ */
+	lea	%pc@(SYMBOL_NAME(boot_info)),%a0
+	movel	%a0@(BI_MACH),%d4
+	movel	%a0@(BI_CPU),%d0
+	movel	%a0@(BI_CPU),%d6      /* !!!!!!!!!!!!!!!! */
+
+	btst	#BI_BIT060,%d0
+	beq	1f
+	/* '060: d6 := BIT0460|BIT060, cache mode 0x60 (no-cache/non-ser) */
+	movel	#(D6VAL_060+CM_NONCACHE),%d6
+	bra	2f
+1:	btst	#BI_BIT040,%d0
+	beq	1f
+	/* '040: d6 := BIT0460, cache mode 0x00 (write-through) */
+	movel	#(D6VAL_040+CM_CACHE_WT),%d6
+	bra	2f
+1:	/* '020 or '030: d6 := no CPU bit, cache mode unused */
+	moveq	#0,%d6
+
+2:	lea	%pc@(SYMBOL_NAME(m68k_pgtable_cachemode)),%a0
+	movel	%d6,%a0@		/* save cache mode for page tables */
+	andl	#0x0000ffff,%a0@
+
+/*
+ * Initialize serial port
+ */
+	jbsr Lserial_init
+
+	moveq	#CR,%d7
+	jbsr	Lserial_putc
+	moveq	#LF,%d7
+	jbsr	Lserial_putc
+	moveq	#'A',%d7
+	jbsr	Lserial_putc
+
+/*
+ * Get address at end of kernel code/data/bss and
+ * mask off at a page boundary.
+ */
+	lea	%pc@(SYMBOL_NAME(_end)),%a0
+	movel	%a0,%d0
+	addl	#(PAGESIZE-1),%d0
+	andl	#PAGE_MASK,%d0
+	movel	%d0,%a6
+
+	moveq	#'B',%d7
+	jbsr	Lserial_putc
+
+/*
+ * initialize the kernel root table.
+ */
+	lea	%pc@(SYMBOL_NAME(kernel_pg_dir)),%a4
+	movel	%a4,%a0
+	moveq	#0,%d0
+	moveq	#(ROOT_TABLE_SIZE-1),%d1
+1:	movel	%d0,%a0@+
+	dbra	%d1,1b
+
+	/*
+	 * Initialize root table descriptor pointing to the kernel pointer
+	 * table.
+	 */
+	movel	%a6,%a5
+	addw	#PAGESIZE,%a6
+
+	movel	%a5,%a0
+	addql	#TABLEDESC,%a0
+	movel	%a0,%a4@
+
+	moveq	#'C',%d7
+	jbsr	Lserial_putc
+
+/*
+ * Initialize the pointer tables referred to above.  They either point
+ * to page tables in the case of the 680[46]0 or contain early
+ * termination page descriptors in the case of the 68851 or 68030.
+ *
+ * Each pointer table entry points to a 64 entry page table.  16 of these
+ * page tables are grouped to form a single 1024 entry page table which
+ * fits in a single 4096 byte page.
+ *
+ * Some register usages:
+ *    a0 -> pointer table descriptor address
+ *    a1 -> pointer table descriptor
+ *    d1 -> counter
+ *    d2 -> pointer table descriptor increment (varies according to CPU)
+ */
+
+	/* clear the kernel pointer table */
+	movel	%a5,%a0
+	moveq	#0,%d0
+	moveq	#(PTR_TABLE_SIZE-1),%d1
+1:	movel	%d0,%a0@+
+	dbra	%d1,1b
+
+	movel	%a5,%a0
+	moveq	#15,%d1
+
+	/*
+	 * base value of pointer table descriptor is either
+	 * the address of the first page table (680[46]0)
+	 * or the base address of physical memory (68030).
+	 */
+	btst	#BIT0460,%d6
+	bne	1f
+
+	/* 680[23]0 */
+	lea	%pc@(SYMBOL_NAME(_stext)-PAGESIZE:w),%a1  /* base address */
+	addql	#PAGEDESC,%a1	/* descriptor type */
+	movel	#0x40000,%d2	/* increment */
+	bra	2f
+
+1:	/* 680[46]0 */
+	movel	%a6,%a1		/* base address */
+	addw	#PAGESIZE,%a6	/* allocate the page table */
+	lea	%pc@(SYMBOL_NAME(kpt)),%a3
+	movel	%a1,%a3@		/* save address of page table */
+	addql	#TABLEDESC,%a1	/* descriptor type */
+	movel	#256,%d2 	/* increment */
+
+2:	movel	%a1,%a0@+
+	addl	%d2,%a1
+	dbra	%d1,2b
+
+	moveq	#'D',%d7
+	jbsr	Lserial_putc
+
+/*
+ * If we are running on a 680[46]0, we have a kernel page table and
+ * must initialize it.	Make the entries point to the first
+ * 4M of physical memory (the memory we are residing in).
+ * Set the cache mode bits to Cacheable, Copyback.  Set the Global bits
+ * in the descriptors also.
+ */
+
+	btst	#BIT0460,%d6
+	jeq	Lnot040
+
+	moveq	#'F',%d7
+	jbsr	Lserial_putc
+
+	movel	%pc@(SYMBOL_NAME(kpt)),%a0
+	lea	%pc@(SYMBOL_NAME(_stext)-PAGESIZE:w),%a1
+
+	addw	#(GLOBAL+CM_CACHE_CB+PAGEDESC),%a1
+	movew	#((PAGESIZE/4)-1),%d1
+	movel	#PAGESIZE,%d2
+
+1:	movel	%a1,%a0@+
+	addl	%d2,%a1
+	dbra	%d1,1b
+
+	/*
+	 * on the 68040, pages used to hold mmu tables should
+	 * be initialized as noncachable; the '060 allows write-through.
+	 * Do this for the root table page (which also contains
+	 * all pointer tables utilitized thus far) and the
+	 * kernel page table.
+	 */
+	lea	%pc@(SYMBOL_NAME(_stext)-PAGESIZE:w),%a0
+	movel	%a4,%d0		/* address of root table */
+	subl	%a0,%d0		/* determine offset of root table page */
+	moveq	#PAGE_INDEX_SHIFT,%d1	/* determine offset into kernel page table */
+	lsrl	%d1,%d0		/* i.e. page number of the address offset */
+	movel	%pc@(SYMBOL_NAME(kpt)),%a0
+	lea	%a0@(%d0:l:4),%a0
+	movel	%a0@,%d1
+	andl	#CM_MASK,%d1
+	orw	%d6,%d1
+	movel	%d1,%a0@+
+
+	movel	%a0@,%d1	/* do the same for the kernel page table */
+	bclr	#5,%d1		/* the kernel page table resides in the  */
+	bset	#6,%d1		/* page after the page containing the	 */
+	movel	%d1,%a0@	/* root table				 */
+
+Lnot040:
+/*
+ * Do any machine specific page table initializations.
+ */
+	moveq	#MACH_AMIGA,%d0
+	cmpl	%d4,%d0
+	bne	Lnotami
+
+/*
+ * On the Amiga:
+ * Our current stack (in CHIP ram) may become invalid after the remapping
+ * of the kernel virtual address space, so set it to point to PAGE_SIZE.
+ * This will be in CHIP ram until after the remapping, and in the unused
+ * first page (temporarily) after that.
+ *
+ * Setup a mapping of the first 16M of physical address space at virtual
+ * address 0x80000000, using early termination page descriptors for the
+ * 68030, and proper page tables for the 680[46]0.  Set this area as
+ * non-cacheable.
+ */
+
+	moveq	#'H',%d7
+	jbsr	Lserial_putc
+
+	move.w	#PAGESIZE,%sp
+
+	btst	#BIT0460,%d6
+	bne	Lspami68040
+
+
+	/*
+	 * for the 68030, just setup a translation to map in the first
+	 * 32M of physical address space at virtual address 0x80000000
+         * using an early termination page descriptor.
+	 */
+
+	moveq	#'I',%d7
+	jbsr	Lserial_putc
+
+	moveq	#0x41,%d0
+	movel	%d0,%a4@(64*4)
+
+	bra	Lmapphys
+
+Lspami68040:
+
+	/*
+	 * for the 680[46]0, use another pointer table, and allocate 4 more
+	 * page tables.  Initialize the pointer table to point to the
+	 * page tables.  Then initialize the page tables to point to
+	 * the first 16M of memory, with no caching (noncachable/serialized).
+	 */
+
+	/* clear the amiga pointer table */
+	lea	%a5@(512),%a0
+	moveq	#0,%d0
+	moveq	#(PTR_TABLE_SIZE-1),%d1
+1:	movel	%d0,%a0@+
+	dbra	%d1,1b
+
+	/* allocate 4 page tables */
+	movel	%a6,%a3
+	addw	#(4*PAGESIZE),%a6
+
+	/* initialize the pointer table */
+	lea	%a5@(512),%a0
+	movel	%a3,%a1
+	addql	#TABLEDESC,%a1	/* base descriptor */
+	movel	#256,%d2 	/* increment */
+	moveq	#(PAGE_TABLE_SIZE-1),%d1
+
+1:	movel	%a1,%a0@+
+	addl	%d2,%a1
+	dbra	%d1,1b
+
+	/* ensure that the root table points to the pointer table */
+	lea	%a5@(512),%a0
+	addql	#TABLEDESC,%a0
+	movel	%a0,%a4@(256)	/* 0x80000000>>(ROOT_INDEX_SHIFT-2) doesn't
+				   work */
+
+	/*
+	 * initialize the page tables
+	 * descriptor bits include noncachable/serialized and global bits.
+	 */
+	movel	%a3,%a0
+	movew	#(GLOBAL+CM_NONCACHE_SER+PAGEDESC),%a1
+	movel	#PAGESIZE,%d2
+	movew	#PAGESIZE-1,%d1
+
+1:	movel	%a1,%a0@+
+	addl	%d2,%a1
+	dbra	%d1,1b
+
+	/*
+	 * Finally, since we just allocated 4 page tables, make sure that
+	 * the virtual mapping of the 4 page tables indicates
+	 * noncachable/serialized.
+	 */
+	movel	%a3,%d0		/* ami page table start address */
+	lea	%pc@(SYMBOL_NAME(_stext)-PAGESIZE:w),%a0
+	subl	%a0,%d0		/* determine offset of root table page */
+	moveq	#PAGE_INDEX_SHIFT,%d1	/* determine offset into kernel page table */
+	lsrl	%d1,%d0
+	movel	%pc@(SYMBOL_NAME(kpt)),%a0
+	movel	#3,%d2
+1:	lea	%a0@(%d0:l:4),%a1
+	movel	%a1@,%d1
+	bclr	#5,%d1
+	bset	#6,%d1
+	movel	%d1,%a1@
+	addql	#1,%d0
+	dbra	%d2,1b
+
+	bra	Lmapphys
+
+
+Lnotami:	/* other machines specific mappings go here! */
+
+	moveq	#MACH_ATARI,%d0
+	cmpl	%d4,%d0
+	bne	Lnotatari
+
+	move.w	#PAGESIZE,%sp
+
+/* On the Atari, we map the I/O region (phys. 0x00ffxxxx) by mapping
+   the last 16 MB of virtual address space to the first 16 MB (i.e.
+   0xffxxxxxx -> 0x00xxxxxx). For this, an additional pointer table is
+   needed. I/O ranges are marked non-cachable.
+
+   For the Medusa it is better to map the I/O region transparently
+   (i.e. 0xffxxxxxx -> 0xffxxxxxx), because some I/O registers are
+   accessible only in the high area. The test whether it is a Medusa
+   is done by writing to the byte at phys. 0x0. This should result
+   in a bus error on all other machines.
+
+   ...should, but doesn't. The Atferburner040 for the Falcon has the
+   same behaviour (0x0..0x7 are no ROM shadow). So we have to do
+   another test to distinuish Medusa and AB040. This is a
+   read attempt for 0x00ff82fe phys. that should bus error on a Falcon
+   (+AB040), but is in the range where the Medusa always asserts DTACK.
+*/
+
+	moveq	#0,%d3			/* base addr for others: 0x00000000 */
+	movec	%d3,%vbr
+	lea	    %pc@(Ltest_berr),%a0
+	movel	%a0,0x8
+	movel	%sp,%a0
+	moveb	0x0,%d1
+	clrb	0x0
+	nop
+	moveb	%d1,0x0
+	nop
+	tstb	0x00ff82fe
+	nop
+	movel	#0xff000000,%d3		/* Medusa base addr: 0xff000000 */
+Ltest_berr:
+	movel	%a0,%sp
+	lea     %pc@(SYMBOL_NAME(is_medusa)),%a0
+	movel	%d3,%a0@
+
+	/* Let the root table point to the new pointer table */
+	lea	%a5@(512),%a0
+	addl	#TABLEDESC,%a0
+	movel	%a0,%a4@(508)		/* 0xFE000000 - 0xFFFFFFFF */
+
+	/* clear lower half of the pointer table (0xfexxxxxx) */
+	lea 	%a5@(512),%a0
+	movel	#0,%d0
+	movel	#63,%d2
+1:	movel	%d0,%a0@+
+	dbra	%d2,1b
+
+	btst	#BIT0460,%d6
+	bne	Lspata68040
+
+/* Mapping of the last 16M of virtual address space to the first 16M
+   for efficient addressing of hardware registers */
+	movel	#0x40000,%d1
+	movel	#63,%d2
+	movel	%d3,%d0
+	addl	#PAGEDESC,%d0
+1:	movel	%d0,%a0@+
+	addl	%d1,%d0
+	dbra	%d2,1b
+	moveq	#0x40,%d0	/* make non-cachable */
+	addl	%d0,%a5@(1020)	/* 0xFFFC0000-0xFFFFFFFF (I/O space) */
+/* GK: 0xFFF00000-0xFFF3FFFF (IDE-bus) has to be non-cachable too */
+	addl	%d0,%a5@(1008)
+
+	bra	Lmapphys
+
+Lspata68040:
+	/* allocate 4 page tables */
+	movel	%a6,%a3
+	addw	#(4*PAGESIZE),%a6
+
+/* Initialize the upper half of the pointer table (a0 is still valid) */
+	movel	%a3,%a1
+	addql	#TABLEDESC,%a1
+	movel	#256,%d2
+	moveq	#63,%d1
+1:	movel	%a1,%a0@+
+	addl	%d2,%a1
+	dbra 	%d1,1b
+
+	/* Initialize the page tables as noncacheable/serialized! */
+	movel	%a3,%a0
+	movel	%d3,%a1
+	addw	#(GLOBAL+CM_NONCACHE_SER+PAGEDESC),%a1
+	movel	#PAGESIZE,%d2
+	movew	#(PAGESIZE-1),%d1
+1:	movel	%a1,%a0@+
+	addl	%d2,%a1
+	dbra	%d1,1b
+
+	/*
+	 * Finally, since we just allocated 4 page tables, make sure that
+	 * the virtual mapping of the 4 page tables indicates
+	 * noncachable or write-through.
+	 */
+	movel	%a3,%d0		/* page table start address */
+	lea	%pc@(SYMBOL_NAME(_stext)-PAGESIZE:w),%a0
+	subl	%a0,%d0		/* determine offset of root table page */
+	moveq	#PAGE_INDEX_SHIFT,%d1 /* determine offset into 
+                                         kernel page table */
+	lsrl	%d1,%d0
+	movel	%pc@(SYMBOL_NAME(kpt)),%a0
+	moveq	#3,%d2
+1:	lea	%a0@(%d0:l:4),%a1
+	movel	%a1@,%d1
+	andl	#CM_MASK,%d1
+	orw	%d6,%d1
+	movel	%d1,%a1@
+	addql	#1,%d0
+	dbra	%d2,1b
+
+Lnotatari:
+
+/*
+ * Setup a transparent mapping of the physical memory we are executing in.
+ *
+ * Only do this if the physical memory is not in the first 16M Meg, or not on
+ * an Amiga since the first 16M is already identity mapped on the Amiga.
+ */
+Lmapphys:
+	moveq	#'J',%d7
+	jbsr	Lserial_putc
+
+	clrl	%d5		/* indicate that no cleanup is required */
+
+	cmpl	#MACH_AMIGA,%d4
+	bne	Lmapphysnotamiga	/* other machines will probably have
+					 * to put in code and jump to it here
+					 */
+
+/*
+ * The virtual address of the start of the kernel is 0x1000.  On ALL
+ * Amigas, there is CHIP RAM in this area.  Hence we will copy the MMU
+ * enabling code to CHIP RAM (to the same physical address as the kernel
+ * virtual address) and jump to it.  When the MMU is enabled, we will be
+ * running from the code in the kernel virtual space, rather than the
+ * physical space.
+ */
+
+/*
+ * Setup Supervisor Root Pointer register to point to page directory,
+ * setup translation register contents and enable translation.
+ */
+	btst	#BIT0460,%d6
+	bne	Lamimmu68040
+
+	moveq	#'K',%d7
+	jbsr	Lserial_putc
+
+	lea	%pc@(mmu),%a0
+	movel	#0x80000002,%a0@   /* no limit, 4byte descriptors */
+	movel	%a4,%a0@(4)
+	pmove	%a0@,%srp
+	pmove	%a0@,%crp
+	/*
+	 * enable,super root enable,4096 byte pages,7 bit root index,
+	 * 7 bit pointer index, 6 bit page table index.
+	 */
+	movel	#0x82c07760,%a0@
+
+	/* setup registers for jumping MMU enabling code */
+	lea	%pc@(Ldoit030ami),%a2
+	lea	Ldoit030ami,%a1
+
+	moveq	#CR,%d7
+	jbsr	Lserial_putc
+	moveq	#LF,%d7
+	jbsr	Lserial_putc
+	movel	%a2,%d7
+	jbsr	Lserial_putnum
+	moveq	#' ',%d7
+	jbsr	Lserial_putc
+	movel	%a1,%d7
+	jbsr	Lserial_putnum
+
+	bra	LdoitAmiga
+
+#ifdef __ELF__
+	.align	16
+#else
+	.align	4
+#endif
+Ldoit030ami:
+	pmove	%a0@,%tc	/* enable the MMU */
+	jra	LdoneMMUenable	/* branch to continuation of startup */
+
+Lamimmu68040:
+	moveq	#'L',%d7
+	jbsr	Lserial_putc
+	
+	.word	0xf4d8		/* CINVA I/D */
+	.word	0xf518		/* pflusha	*/
+	.long	0x4e7bc807	/* movec a5,srp */
+	.long	0x4e7bc806	/* movec a5,urp */
+	movel	#(TC_ENABLE+TC_PAGE4K),%d0
+
+	/* setup registers for jumping MMU enabling code */
+	lea	Ldoit040ami,%a1
+	lea	%pc@(Ldoit040ami),%a2
+	bra	LdoitAmiga
+
+#ifdef __ELF__
+	.align	16
+#else
+	.align	4
+#endif
+Ldoit040ami:
+	.long	0x4e7b0003	/* movec d0,tc  (enable the MMU) */
+	jra	LdoneMMUenable	/* branch to continuation of startup */
+
+LdoitAmiga:
+	/* copy the appropriate code (two longwords) to chipmem */
+	movel	%a2@,%a1@
+	movel	%a2@(4),%a1@(4)
+
+	/*
+ 	 * save physaddr of phys mem in register a3
+	 */
+	lea	%pc@(SYMBOL_NAME(_stext)-PAGESIZE:w),%a3
+
+	/* jump to the physical address in chipmem */
+	jmp	%a1@
+
+Lmapphysnotamiga:
+
+	cmpl	#MACH_ATARI,%d4
+	bne	Lmapphysnotatari
+
+	lea	%pc@(SYMBOL_NAME(_stext)-PAGESIZE),%a0
+	tstl	%a0
+	jeq	Lnophys2
+
+	/* The kernel physical address is different from its virtual
+	   address.  Temporarily set up an identity mapping of the
+	   16MB chunk where the kernel is executing. */
+  
+	/* 680[46]0? */
+	btst	#BIT0460,%d6
+	jeq	1f
+
+	/*
+	 * For the 68040, we will use the transparent translation
+	 * registers to identity map the 16M chunk that contains
+	 * the physical memory.
+	 */
+	movel	%a0,%d2
+	andl	#0xff000000,%d2		/* logical address base */
+	orw	#0xc040,%d2		/* add in magic bits */
+	.long	0x4e7b2004		/* movec d2,ittr0 */
+	.long	0x4e7b2006		/* movec d2,dttr0 */
+
+	/* d5 is kept 0 to do no cleanup. This didn't work in head.S, I don't
+	 * know why... The transparent translation is turned off in
+	 * atari/config.c instead.
+	 */
+	jra	Lnophys2
+
+	/* Transparent translation for the 68030 via transparent translation
+	   register */
+
+1:
+	/* cleanup is needed; note it */
+	moveq	#1,%d5
+
+	movel	%a0,%d2
+	andl	#0xff000000,%d2		/* logical address base */
+	orw	#0x8143,%d2		/* add in magic bits */
+	lea	%pc@(mmu),%a0
+	movel	%d2,%a0@
+	pmove	%a0@,%tt0
+
+Lnophys2:
+	/*
+ 	 * save physaddr of phys mem in register a3
+	 */
+	lea	%pc@(SYMBOL_NAME(_stext)-PAGESIZE:w),%a3
+
+	btst	#BIT0460,%d6
+	jne	Latarimmu68040
+
+	moveq	#'K',%d7
+	jbsr	Lserial_putc
+
+	lea	%pc@(mmu),%a0
+	movel	#0x80000002,%a0@   /* no limit, 4byte descriptors */
+	movel	%a4,%a0@(4)
+	pmove	%a0@,%srp
+	pmove	%a0@,%crp
+	/*
+	 * enable,super root enable,4096 byte pages,7 bit root index,
+	 * 7 bit pointer index, 6 bit page table index.
+	 */
+	movel	#0x82c07760,%a0@
+	pmove	%a0@,%tc		/* enable the MMU */
+
+	/* Jump to the virtual address of continuation of startup. */
+	jmp	LdoneMMUenable
+
+Latarimmu68040:
+	moveq	#'L',%d7
+	jbsr	Lserial_putc
+
+	.word	0xf4d8		/* CINVA I/D */
+	.word	0xf518		/* pflusha	*/
+	.long	0x4e7bc807	/* movec a4,srp */
+	.long	0x4e7bc806	/* movec a4,urp */
+	movel	#(TC_ENABLE+TC_PAGE4K),%d0
+	/* this value is also ok for the '060, we don't use the cache
+	 * mode/protection defaults */
+	.long	0x4e7b0003	/* movec d0,tc  (enable the MMU) */
+	jmp	LdoneMMUenable	/* jump to virtual address of
+				   continuation of startup */
+
+Lmapphysnotatari:
+
+
+LdoneMMUenable:
+
+/*
+ * Fixup the addresses for the kernel pointer table and availmem.
+ * Convert them from physical addresses to virtual addresses.
+ */
+
+	/*
+	 * fixup the Amiga custom register location before printing
+	 */
+	addl	#0x80000000,Lcustom
+
+	/* The same for the Atari */
+	movel	#0xff000000,Liobase
+
+	moveq	#'M',%d7
+	jbsr	Lserial_putc
+
+	/*
+	 * a3 contains physaddr of kernel start
+	 */
+	movel	SYMBOL_NAME(kpt),%d1
+	subl	%a3,%d1
+	movel	%d1,SYMBOL_NAME(kpt)
+
+	/*
+	 * do the same conversion on the first available memory
+	 * address (in a6).
+	 */
+	subl	%a3,%a6
+
+	/* Allocate a page to be used by get_kpointer_table.  */
+	movel	%a6,SYMBOL_NAME(kernel_pmd_table)
+	addl	#PAGESIZE,%a6
+	movel	%a6,SYMBOL_NAME(availmem) /* first available memory address */
+
+	moveq	#'N',%d7
+	jbsr	Lserial_putc
+
+	/*
+	 * Clean up the temporary physical mapping (if necessary)
+	 */
+
+	tstl	%d5
+	jeq	Lnoclean
+
+	btst	#BIT0460,%d6
+	jne	Loff040
+
+	/* clean up physical identity mapping for 68020/68030 */
+	/* Is this needed for the Amiga anymore? */
+	/* it's not in 1.2.13pl6 - Jes */
+	cmpl	#MACH_AMIGA,%d4
+	jeq	Lclean030
+	cmpl	#MACH_ATARI,%d4
+	jne	Lnoclean
+
+	/* clear transparent translation register */
+	lea	%pc@(mmu),%a0
+	clrl	%a0@
+	pmove	%a0@,%tt0
+	jra	Lnoclean
+
+Lclean030:
+	movel	%a0,%d2		/* a0 contains physical start address */
+	moveq	#25,%d3		/* find appropriate index in root table */
+	lsrl	%d3,%d2
+	moveq	#0,%d0
+	movel	%d0,%a4@(%d2:l:4)  /* clear descriptor */
+
+	jra	Lnoclean
+
+Loff040:
+	/* turn off transparent translation registers for '0[46]0 */
+	moveq	#0,%d0
+	.long	0x4e7b0004	/* movec d0,ittr0 */
+	.long	0x4e7b0006	/* movec d0,dttr0 */
+
+Lnoclean:
+	moveq	#'O',%d7
+	jbsr	Lserial_putc
+
+
+/*
+ * Enable caches
+ */
+	btst	#BIT0460,%d6
+	jne	Lcache680460
+
+	movel	#0x00001919,%d0
+	movec   %d0,%cacr
+	jra	1f
+
+Lcache680460:
+	btst	#BIT060,%d6
+	jne	Lcache68060
+
+	.word	0xf4d8	     /* CINVA I/D */
+	movel	#I_ENABLE+D_ENABLE,%d0
+	/* MMU stuff works in copyback mode now, so enable the cache */
+	movec	%d0,%cacr
+	jra	1f
+
+Lcache68060:
+	.word	0xf4d8	     /* CINVA I/D */
+	movel	#I_ENABLE+D_ENABLE+SB_ENABLE+PUSH_DPI+BC_ENABLE+BC_CLRA,%d0
+	/* MMU stuff works in copyback mode now, so enable the cache */
+	movec	%d0,%cacr
+	/* enable superscalar dispatch in PCR */
+	moveq	#1,%d0
+	.long	0x4e7b0808	/* movec d0,pcr */
+
+1:
+
+/*
+ * Setup initial stack pointer
+ */
+	lea	SYMBOL_NAME(init_user_stack)+PAGESIZE,%sp
+
+/* jump to the kernel start */
+
+	jbsr	SYMBOL_NAME(start_kernel)
+
+#if 0
+tmp_fault_handler:
+     lea       %pc@(tfh_1st_str),%a0
+     jbsr       Lserial_puts
+     move.l    %sp@(2),%d7                     /* PC */
+     jbsr       Lserial_putnum
+     move.w    %sp@(0xa),%d7
+     swap      %d7
+     move.w    %sp@(0x6),%d7
+     jbsr       Lserial_putnum
+     lea       %pc@(tfh_2nd_str),%a0
+     jbsr       Lserial_puts
+     move.l    %sp@(0x10),%d7                  /* Fault address */
+     jbsr       Lserial_putnum
+     moveq     #CR,%d7
+     jbsr       Lserial_putc
+     moveq     #LF,%d7
+     jbsr       Lserial_putc
+1:   jra       1b
+
+tfh_1st_str:
+     .byte     CR
+     .byte     LF
+     .ascii    "Access fault occurred. PC = "
+     .byte     0
+
+tfh_2nd_str:
+     .byte     CR
+     .byte     LF
+     .ascii    "FaultAddress = "
+     .byte     0
+#endif
+
+/*
+ * Serial port output support.
+ */
+LSERPER      = 0xdff032
+LSERDAT      = 0xdff030
+LSERDATR     = 0xdff018
+LNTSC_PERIOD = 371
+LPAL_PERIOD  = 368/2        /* /2 for 19200 baud */
+LNTSC_ECLOCK = 7159090
+LSERIAL_CNTRL = 0xbfd000
+LSERIAL_DTR   = 7
+
+/*
+ * Debug output support
+ * Atarians have a choice between the parallel port, the serial port
+ * from the MFP or a serial port of the SCC
+ */
+
+/* #define USE_PRINTER */
+/* #define USE_SCC */
+#define USE_MFP
+
+#ifdef USE_PRINTER
+
+LPSG_SELECT	= 0xff8800
+LPSG_READ	= 0xff8800
+LPSG_WRITE	= 0xff8802
+LPSG_IO_A	= 14
+LPSG_IO_B	= 15
+LPSG_CONTROL	= 7
+LSTMFP_GPIP	= 0xfffa01
+LSTMFP_DDR	= 0xfffa05
+LSTMFP_IERB	= 0xfffa09
+
+#elif defined(USE_SCC)
+ 
+LSCC_CTRL_B	= 0xff8c85
+LSCC_DATA_B	= 0xff8c87
+
+/* Initialisation table for SCC */
+scc_initable:
+	.byte	9,12		/* Reset */
+	.byte	4,0x44		/* x16, 1 stopbit, no parity */
+	.byte	3,0xc0		/* receiver: 8 bpc */
+	.byte	5,0xe2		/* transmitter: 8 bpc, assert dtr/rts */
+	.byte	9,0		/* no interrupts */
+	.byte	10,0		/* NRZ */
+	.byte	11,0x50		/* use baud rate generator */
+	.byte	12,24,13,0	/* 9600 baud */
+	.byte	14,2,14,3	/* use master clock for BRG, enable */
+	.byte	3,0xc1		/* enable receiver */
+	.byte	5,0xea		/* enable transmitter */
+	.byte	-1
+	.even
+
+#elif defined(USE_MFP)
+
+LMFP_UCR     = 0xfffa29
+LMFP_TDCDR   = 0xfffa1d
+LMFP_TDDR    = 0xfffa25
+LMFP_TSR     = 0xfffa2d
+LMFP_UDR     = 0xfffa2f
+
+#endif
+
+/*
+ * Initialize serial port hardware for 9600/8/1
+ * a0 thrashed
+ * Atari d0 trashed (a1 in case of SCC)
+ */
+	.even
+Lserial_init:
+	cmpil	#MACH_AMIGA,%d4
+	jne	1f
+	bclr	#LSERIAL_DTR,LSERIAL_CNTRL
+	movew	#LNTSC_PERIOD,LSERPER
+	cmpl	#LNTSC_ECLOCK,%a0@(BI_AMIGA_ECLK)
+	jeq	9f
+	movew	#LPAL_PERIOD,LSERPER
+	jra	9f
+1:	cmpil   #MACH_ATARI,%d4
+	jne	9f
+#ifdef USE_PRINTER
+	bclr	#0,LSTMFP_IERB
+	bclr	#0,LSTMFP_DDR
+	moveb	#LPSG_CONTROL,LPSG_SELECT
+	moveb	#0xff,LPSG_WRITE
+	moveb	#LPSG_IO_B,LPSG_SELECT
+	clrb	LPSG_WRITE
+	moveb	#LPSG_IO_A,LPSG_SELECT
+	moveb	LPSG_READ,%d0
+	bset	#5,%d0
+	moveb	%d0,LPSG_WRITE
+#elif defined(USE_SCC)
+	lea	LSCC_CTRL_B,%a0
+	lea	%pc@(scc_initable:w),%a1
+2:	moveb	%a1@+,%d0
+	jmi	3f
+	moveb	%d0,%a0@
+	moveb	%a1@+,%a0@
+	jra	2b
+3:	clrb	%a0@
+#elif defined(USE_MFP)
+	bclr	#1,LMFP_TSR
+	moveb   #0x88,LMFP_UCR
+	andb	#0x70,LMFP_TDCDR
+	moveb   #2,LMFP_TDDR
+	orb	#1,LMFP_TDCDR
+	bset	#1,LMFP_TSR
+#endif
+9:
+	rts
+
+/*
+ * Output character in d7 on serial port.
+ * d7 thrashed.
+ */
+Lserial_putc:
+	moveml	%a0/%a1,%sp@-
+	cmpil	#MACH_AMIGA,%d4
+	jne	2f
+	andw	#0x00ff,%d7
+	oriw	#0x0100,%d7
+	movel	%pc@(Lcustom),%a1
+	movew	%d7,%a1@(LSERDAT)
+1:	movew	%a1@(LSERDATR),%d7
+	andw	#0x2000,%d7
+	jeq	1b
+	jra	9f
+2:	cmpil   #MACH_ATARI,%d4
+	jne	9f
+	movel	%pc@(Liobase),%a1
+#ifdef USE_PRINTER
+3:	btst	#0,%a1@(LSTMFP_GPIP)
+	jne	3b
+	moveb	#LPSG_IO_B,%a1@(LPSG_SELECT)
+	moveb	%d7,%a1@(LPSG_WRITE)
+	moveb	#LPSG_IO_A,%a1@(LPSG_SELECT)
+	moveb	%a1@(LPSG_READ),%d7
+	bclr	#5,%d7
+	moveb	%d7,%a1@(LPSG_WRITE)
+	nop
+	nop
+	bset	#5,%d7
+	moveb	%d7,%a1@(LPSG_WRITE)
+#elif defined(USE_SCC)
+3:	btst	#2,%a1@(LSCC_CTRL_B)
+	jeq	3b
+	moveb	%d7,%a1@(LSCC_DATA_B)
+#elif defined(USE_MFP)
+3:	btst	#7,%a1@(LMFP_TSR)
+	jeq	3b
+	moveb	%d7,%a1@(LMFP_UDR)
+#endif
+9:
+	moveml	%sp@+,%a0/%a1
+	rts
+
+/*
+ * Output string pointed to by a0 to serial port.
+ * a0 trashed.
+ */
+Lserial_puts:
+	movel	%d7,%sp@-
+1:	moveb	%a0@+,%d7
+	jeq	2f
+	jbsr	Lserial_putc
+	jra	1b
+2:	movel	%sp@+,%d7
+	rts
+
+/*
+ * Output number in d7 in hex notation on serial port.
+ * d0-d2 trashed.
+ * d7 trashed.
+ */
+
+Lserial_putnum:
+	moveml	%d0-%d2/%d7,%sp@-
+	movel	%d7,%d1
+	moveq	#4,%d0
+	moveq	#7,%d2
+L1:	roll	%d0,%d1
+	moveb	%d1,%d7
+	andb	#0x0f,%d7
+	cmpb	#0x0a,%d7
+	bccs	1f
+	addb	#'0',%d7
+	jra	2f
+1:	addb	#'A'-10,%d7
+2:	jbsr	Lserial_putc
+	dbra	%d2,L1
+	moveq	#32,%d7
+	jbsr	Lserial_putc
+	moveml	%sp@+,%d0-%d2/%d7
+	rts
+#if 0
+.globl showtest
+showtest:
+	moveml	%a1/%d7,%sp@-
+	moveq	#'A',%d7
+	jbsr	Lserial_putc
+	moveq	#'=',%d7
+	jbsr	Lserial_putc
+	movel	%a0,%d7
+	jbsr	Lserial_putnum
+
+	ptestr	#5,%a0@,#7,%a1
+
+	moveq	#'D',%d7
+	jbsr	Lserial_putc
+	moveq	#'A',%d7
+	jbsr	Lserial_putc
+	moveq	#'=',%d7
+	jbsr	Lserial_putc
+
+	movel	%a1,%d7
+	jbsr	Lserial_putnum
+
+	moveq	#'D',%d7
+	jbsr	Lserial_putc
+	moveq	#'=',%d7
+	jbsr	Lserial_putc
+	movel	%a1@,%d7
+	jbsr	Lserial_putnum
+
+	moveq	#'S',%d7
+	jbsr	Lserial_putc
+	moveq	#'=',%d7
+	jbsr	Lserial_putc
+
+	lea	%pc@(mmu),%a1
+	pmove	%psr,%a1@
+	clrl	%d7
+	movew	%a1@,%d7
+	jbsr	Lserial_putnum
+
+	moveq	#CR,%d7
+	jbsr	Lserial_putc
+	moveq	#LF,%d7
+	jbsr	Lserial_putc
+
+	moveml	%sp@+,%a1/%d7
+	rts
+#endif
+
+	.align 512	/*
+			 * MMU root-pointers need to be 512-byte
+			 * aligned on the 680[46]0 - Jes
+			 */
+
+SYMBOL_NAME_LABEL(swapper_pg_dir)
+	.skip ROOT_TABLE_SIZE * 4
+SYMBOL_NAME_LABEL(kernel_pg_dir)
+	.skip ROOT_TABLE_SIZE * 4
+
+	.data
+	.even
+Lcustom:
+	.long 0
+Liobase:
+	.long 0
+mmu:	.quad 0
+SYMBOL_NAME_LABEL(kernel_pmd_table)
+	.long 0
+SYMBOL_NAME_LABEL(kpt)
+	.long 0
+SYMBOL_NAME_LABEL(availmem)
+	.long 0
+SYMBOL_NAME_LABEL(is_medusa)
+	.long 0
+SYMBOL_NAME_LABEL(m68k_pgtable_cachemode)
+	.long 0
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/kernel/ints.c linux/arch/m68k/kernel/ints.c
--- v1.3.93/linux/arch/m68k/kernel/ints.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/kernel/ints.c	Sun Mar 31 14:03:24 1996
@@ -0,0 +1,236 @@
+/*
+ * ints.c -- 680x0 Linux general interrupt handling code
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file README.legal in the main directory of this archive
+ * for more details.
+ *
+ * 07/03/96: Timer initialization, and thus mach_sched_init(),
+ *           removed from request_irq() and moved to init_time().
+ *           We should therefore consider renaming our add_isr() and
+ *           remove_isr() to request_irq() and free_irq()
+ *           respectively, so they are compliant with the other
+ *           architectures.                                     /Jes
+ */
+
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/kernel_stat.h>
+#include <linux/errno.h>
+
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/traps.h>
+#include <asm/page.h>
+#include <asm/machdep.h>
+
+/* list is accessed 0-6 for IRQs 1-7 */
+static isr_node_t *isr_list[7];
+
+/* The number of spurious interrupts */
+volatile unsigned long num_spurious;
+/*
+unsigned long interrupt_stack[PAGE_SIZE/sizeof(long)];
+*/
+
+/*
+ * void init_IRQ(void)
+ *
+ * Parameters:	None
+ *
+ * Returns:	Nothing
+ *
+ * This function should be called during kernel startup to initialize
+ * the IRQ handling routines.
+ */
+
+void init_IRQ(void)
+{
+    /* Setup interrupt stack pointer */
+  /*
+    asm ("movec %0,%/isp"
+	 : : "r" (interrupt_stack + sizeof (interrupt_stack) / sizeof (long)));
+	 */
+    mach_init_INTS ();
+}
+
+void insert_isr (isr_node_t **listp, isr_node_t *node)
+{
+    unsigned long spl;
+    isr_node_t *cur;
+
+    save_flags(spl);
+    cli();
+
+    cur = *listp;
+
+    while (cur && cur->pri <= node->pri)
+    {
+	listp = &cur->next;
+	cur = cur->next;
+    }
+
+    node->next = cur;
+    *listp = node;
+
+    restore_flags(spl);
+}
+
+void delete_isr (isr_node_t **listp, isrfunc isr)
+{
+    unsigned long flags;
+    isr_node_t *np;
+
+    save_flags(flags);
+    cli();
+    for (np = *listp; np; listp = &np->next, np = *listp) {
+	if (np->isr == isr) {
+	    *listp = np->next;
+	    /* Mark it as free. */
+	    np->isr = NULL;
+	    restore_flags(flags);
+	    return;
+	}
+    }
+    restore_flags(flags);
+    printk ("delete_isr: isr %p not found on list!\n", isr);
+}
+
+#define NUM_ISR_NODES 100
+static isr_node_t nodes[NUM_ISR_NODES];
+
+isr_node_t *new_isr_node(void)
+{
+    isr_node_t *np;
+
+    for (np = nodes; np < &nodes[NUM_ISR_NODES]; np++)
+	if (np->isr == NULL)
+	    return np;
+
+    printk ("new_isr_node: out of nodes");
+    return NULL;
+}
+
+int add_isr (unsigned long source, isrfunc isr, int pri, void *data,
+	     char *name)
+{
+    isr_node_t *p;
+
+    if (source & IRQ_MACHSPEC)
+    {
+	return mach_add_isr (source, isr, pri, data, name);
+    }
+
+    if (source < IRQ1 || source > IRQ7)
+	panic ("add_isr: Incorrect IRQ source %ld from %s\n", source, name);
+
+    p = new_isr_node();
+    if (p == NULL)
+	return 0;
+    p->isr = isr;
+    p->pri = pri;
+    p->data = data;
+    p->name = name;
+    p->next = NULL;
+
+    insert_isr (&isr_list[source-1], p);
+
+    return 1;
+}
+
+int remove_isr (unsigned long source, isrfunc isr)
+{
+    if (source & IRQ_MACHSPEC)
+	return mach_remove_isr (source, isr);
+
+    if (source < IRQ1 || source > IRQ7) {
+	printk ("remove_isr: Incorrect IRQ source %ld\n", source);
+	return 0;
+    }
+
+    delete_isr (&isr_list[source - 1], isr);
+    return 1;
+}
+
+void call_isr_list(int irq, isr_node_t *p, struct pt_regs *fp)
+{
+    while (p) {
+	p->isr (irq, fp, p->data);
+	p = p->next;
+    }
+}
+
+asmlinkage void process_int(int vec, struct pt_regs *regs)
+{
+	int level;
+
+	if (vec >= VECOFF(VEC_INT1) && vec <= VECOFF(VEC_INT7))
+		level = (vec - VECOFF(VEC_SPUR)) >> 2;
+	else {
+		if (mach_process_int)
+			mach_process_int(vec, regs);
+		else
+			panic("Can't process interrupt vector 0x%03x\n", vec);
+		return;
+	}
+
+	kstat.interrupts[level]++;  	
+	call_isr_list (level, isr_list[level-1], regs);
+}
+
+int request_irq(unsigned int irq,
+		void (*handler)(int, void *, struct pt_regs *),
+		unsigned long flags, const char * devname, void *dev_id)
+{
+	return -EINVAL;
+}
+
+void free_irq(unsigned int irq, void *dev_id)
+{
+}
+
+/*
+ * Do we need these probe functions on the m68k?
+ */
+unsigned long probe_irq_on (void)
+{
+  return 0;
+}
+
+int probe_irq_off (unsigned long irqs)
+{
+  return 0;
+}
+
+void enable_irq(unsigned int irq_nr)
+{
+	if ((irq_nr & IRQ_MACHSPEC) && mach_enable_irq)
+		mach_enable_irq(irq_nr);
+}
+
+void disable_irq(unsigned int irq_nr)
+{
+	if ((irq_nr & IRQ_MACHSPEC) && mach_disable_irq)
+		mach_disable_irq(irq_nr);
+}
+
+int get_irq_list(char *buf)
+{
+    int i, len = 0;
+    isr_node_t *p;
+    
+    /* autovector interrupts */
+    for (i = IRQ1; i <= IRQ7; ++i) {
+	if (!isr_list[i-1])
+	    continue;
+	len += sprintf(buf+len, "auto %2d: %8d ", i, kstat.interrupts[i]);
+	for (p = isr_list[i-1]; p; p = p->next) {
+	    len += sprintf(buf+len, "%s\n", p->name);
+	    if (p->next)
+		len += sprintf(buf+len, "                  ");
+	}
+    }
+
+    len = mach_get_irq_list(buf, len);
+    return len;
+}
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/kernel/ksyms.c linux/arch/m68k/kernel/ksyms.c
--- v1.3.93/linux/arch/m68k/kernel/ksyms.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/kernel/ksyms.c	Tue Apr  9 17:28:13 1996
@@ -0,0 +1,69 @@
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/linkage.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+
+#include <asm/bootinfo.h>
+#include <asm/pgtable.h>
+
+asmlinkage long long __ashrdi3 (long long, int);
+extern char m68k_debug_device[];
+
+#ifdef CONFIG_ATARI
+extern void mach_atari_syms_export (void);
+#endif
+#ifdef CONFIG_AMIGA
+extern void mach_amiga_syms_export (void);
+#endif
+#ifdef CONFIG_MAC
+extern void mach_mac_syms_export (void);
+#endif
+
+static struct symbol_table arch_symbol_table = {
+#include <linux/symtab_begin.h>
+	/* platform dependent support */
+
+	X(memcmp),
+	X(boot_info),
+	X(m68k_is040or060),
+	X(cache_push),
+	X(cache_clear),
+	X(mm_vtop),
+	X(mm_ptov),
+	X(m68k_debug_device),
+
+	/* The following are special because they're not called
+	   explicitly (the C compiler generates them).  Fortunately,
+	   their interface isn't gonna change any time soon now, so
+	   it's OK to leave it out of version control.  */
+	XNOVERS(__ashrdi3),
+	XNOVERS(memcpy),
+	
+#include <linux/symtab_end.h>
+};
+
+void arch_syms_export(void)
+{
+	register_symtab(&arch_symbol_table);
+
+	switch (boot_info.machtype) {
+#ifdef CONFIG_ATARI
+	case MACH_ATARI:
+		mach_atari_syms_export();
+		break;
+#endif
+#ifdef CONFIG_AMIGA
+	case MACH_AMIGA:
+		mach_amiga_syms_export();
+		break;
+#endif
+#ifdef CONFIG_MAC
+	case MACH_MAC:
+		mach_mac_syms_export();
+		break;
+#endif
+	default:
+		break;
+	}
+}
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/kernel/process.c linux/arch/m68k/kernel/process.c
--- v1.3.93/linux/arch/m68k/kernel/process.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/kernel/process.c	Mon Apr  1 21:40:27 1996
@@ -0,0 +1,200 @@
+/*
+ *  linux/arch/m68k/kernel/process.c
+ *
+ *  Copyright (C) 1995  Hamish Macdonald
+ */
+
+/*
+ * This file handles the architecture-dependent parts of process handling..
+ */
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+#include <linux/ptrace.h>
+#include <linux/malloc.h>
+#include <linux/user.h>
+#include <linux/a.out.h>
+
+#include <asm/segment.h>
+#include <asm/system.h>
+#include <asm/traps.h>
+#include <asm/machdep.h>
+
+asmlinkage void ret_from_exception(void);
+
+/*
+ * The idle loop on an m68k..
+ */
+asmlinkage int sys_idle(void)
+{
+	if (current->pid != 0)
+		return -EPERM;
+
+	/* endless idle loop with no priority at all */
+	current->counter = -100;
+	for (;;)
+		schedule();
+}
+
+void hard_reset_now(void)
+{
+	if (mach_reset)
+		mach_reset();
+}
+
+void show_regs(struct pt_regs * regs)
+{
+	printk("\n");
+	printk("Format %02x  Vector: %04x  PC: %08lx  Status: %04x\n",
+	       regs->format, regs->vector, regs->pc, regs->sr);
+	printk("ORIG_D0: %08lx  D0: %08lx  A1: %08lx\n",
+	       regs->orig_d0, regs->d0, regs->a1);
+	printk("A0: %08lx  D5: %08lx  D4: %08lx\n",
+	       regs->a0, regs->d5, regs->d4);
+	printk("D3: %08lx  D2: %08lx  D1: %08lx\n",
+	       regs->d3, regs->d2, regs->d1);
+	if (!(regs->sr & PS_S))
+		printk("USP: %08lx\n", rdusp());
+}
+
+/*
+ * Free current thread data structures etc..
+ */
+void exit_thread(void)
+{
+}
+
+void flush_thread(void)
+{
+	set_fs(USER_DS);
+	current->tss.fs = USER_DS;
+}
+
+/*
+ * "m68k_fork()".. By the time we get here, the
+ * non-volatile registers have also been saved on the
+ * stack. We do some ugly pointer stuff here.. (see
+ * also copy_thread)
+ */
+
+asmlinkage int m68k_fork(struct pt_regs *regs)
+{
+	return do_fork(SIGCHLD, rdusp(), regs);
+}
+
+asmlinkage int m68k_clone(struct pt_regs *regs)
+{
+	unsigned long clone_flags;
+	unsigned long newsp;
+
+	/* syscall2 puts clone_flags in d1 and usp in d2 */
+	clone_flags = regs->d1;
+	newsp = regs->d2;
+	if (!newsp)
+	  newsp  = rdusp();
+	return do_fork(clone_flags, newsp, regs);
+}
+
+void release_thread(struct task_struct *dead_task)
+{
+}
+
+void copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
+		 struct task_struct * p, struct pt_regs * regs)
+{
+	struct pt_regs * childregs;
+	struct switch_stack * childstack, *stack;
+	unsigned long stack_offset, *retp;
+
+	stack_offset = PAGE_SIZE - sizeof(struct pt_regs);
+	childregs = (struct pt_regs *) (p->kernel_stack_page + stack_offset);
+
+	*childregs = *regs;
+	childregs->d0 = 0;
+
+	retp = ((unsigned long *) regs);
+	stack = ((struct switch_stack *) retp) - 1;
+
+	childstack = ((struct switch_stack *) childregs) - 1;
+	*childstack = *stack;
+	childstack->retpc = (unsigned long) ret_from_exception;
+
+	p->tss.usp = usp;
+	p->tss.ksp = (unsigned long)childstack;
+
+	/* Copy the current fpu state */
+	asm volatile ("fsave %0" : : "m" (p->tss.fpstate[0]) : "memory");
+	if (p->tss.fpstate[0])
+	  asm volatile ("fmovemx %/fp0-%/fp7,%0\n\t"
+			"fmoveml %/fpiar/%/fpcr/%/fpsr,%1"
+			: : "m" (p->tss.fp[0]), "m" (p->tss.fpcntl[0])
+			: "memory");
+	/* Restore the state in case the fpu was busy */
+	asm volatile ("frestore %0" : : "m" (p->tss.fpstate[0]));
+}
+
+/* Fill in the fpu structure for a core dump.  */
+
+int dump_fpu (struct user_m68kfp_struct *fpu)
+{
+  char fpustate[216];
+
+  /* First dump the fpu context to avoid protocol violation.  */
+  asm volatile ("fsave %0" :: "m" (fpustate[0]) : "memory");
+  if (!fpustate[0])
+    return 0;
+
+  asm volatile ("fmovem %/fpiar/%/fpcr/%/fpsr,%0"
+		:: "m" (fpu->fpcntl[0])
+		: "memory");
+  asm volatile ("fmovemx %/fp0-%/fp7,%0"
+		:: "m" (fpu->fpregs[0])
+		: "memory");
+  return 1;
+}
+
+/*
+ * fill in the user structure for a core dump..
+ */
+void dump_thread(struct pt_regs * regs, struct user * dump)
+{
+/* changed the size calculations - should hopefully work better. lbt */
+	dump->magic = CMAGIC;
+	dump->start_code = 0;
+	dump->start_stack = rdusp() & ~(PAGE_SIZE - 1);
+	dump->u_tsize = ((unsigned long) current->mm->end_code) >> PAGE_SHIFT;
+	dump->u_dsize = ((unsigned long) (current->mm->brk +
+					  (PAGE_SIZE-1))) >> PAGE_SHIFT;
+	dump->u_dsize -= dump->u_tsize;
+	dump->u_ssize = 0;
+
+	if (dump->start_stack < TASK_SIZE)
+		dump->u_ssize = ((unsigned long) (TASK_SIZE - dump->start_stack)) >> PAGE_SHIFT;
+
+	dump->u_ar0 = (struct pt_regs *)(((int)(&dump->regs)) -((int)(dump)));
+	dump->regs = *regs;
+	dump->regs2 = ((struct switch_stack *)regs)[-1];
+	/* dump floating point stuff */
+	dump->u_fpvalid = dump_fpu (&dump->m68kfp);
+}
+
+/*
+ * sys_execve() executes a new program.
+ */
+asmlinkage int sys_execve(char *name, char **argv, char **envp)
+{
+	int error;
+	char * filename;
+	struct pt_regs *regs = (struct pt_regs *) &name;
+
+	error = getname(name, &filename);
+	if (error)
+		return error;
+	error = do_execve(filename, argv, envp, regs);
+	putname(filename);
+	return error;
+}
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/kernel/ptrace.c linux/arch/m68k/kernel/ptrace.c
--- v1.3.93/linux/arch/m68k/kernel/ptrace.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/kernel/ptrace.c	Fri Apr  5 20:40:35 1996
@@ -0,0 +1,534 @@
+/*
+ *  linux/arch/m68k/kernel/ptrace.c
+ *
+ *  Copyright (C) 1994 by Hamish Macdonald
+ *  Taken from linux/kernel/ptrace.c and modified for M680x0.
+ *  linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License.  See the file README.legal in the main directory of
+ * this archive for more details.
+ */
+
+#include <stddef.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/errno.h>
+#include <linux/ptrace.h>
+#include <linux/user.h>
+
+#include <asm/segment.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/system.h>
+
+/*
+ * does not yet catch signals sent when the child dies.
+ * in exit.c or in signal.c.
+ */
+
+/* determines which bits in the SR the user has access to. */
+/* 1 = access 0 = no access */
+#define SR_MASK 0x001f
+
+/* sets the trace bits. */
+#define TRACE_BITS 0x8000
+
+/* Find the stack offset for a register, relative to tss.esp0. */
+#define PT_REG(reg)	((long)&((struct pt_regs *)0)->reg)
+#define SW_REG(reg)	((long)&((struct switch_stack *)0)->reg \
+			 - sizeof(struct switch_stack))
+/* Mapping from PT_xxx to the stack offset at which the register is
+   saved.  Notice that usp has no stack-slot and needs to be treated
+   specially (see get_reg/put_reg below). */
+static int regoff[] = {
+	PT_REG(d1), PT_REG(d2), PT_REG(d3), PT_REG(d4),
+	PT_REG(d5), SW_REG(d6), SW_REG(d7), PT_REG(a0),
+	PT_REG(a1), SW_REG(a2), SW_REG(a3), SW_REG(a4),
+	SW_REG(a5), SW_REG(a6), PT_REG(d0), -1,
+	PT_REG(orig_d0), PT_REG(sr), PT_REG(pc),
+};
+
+/* change a pid into a task struct. */
+static inline struct task_struct * get_task(int pid)
+{
+	int i;
+
+	for (i = 1; i < NR_TASKS; i++) {
+		if (task[i] != NULL && (task[i]->pid == pid))
+			return task[i];
+	}
+	return NULL;
+}
+
+/*
+ * Get contents of register REGNO in task TASK.
+ */
+static inline long get_reg(struct task_struct *task, int regno)
+{
+	unsigned long *addr;
+
+	if (regno == PT_USP)
+		addr = &task->tss.usp;
+	else if (regno < sizeof(regoff)/sizeof(regoff[0]))
+		addr = (unsigned long *)(task->tss.esp0 + regoff[regno]);
+	else
+		return 0;
+	return *addr;
+}
+
+/*
+ * Write contents of register REGNO in task TASK.
+ */
+static inline int put_reg(struct task_struct *task, int regno,
+			  unsigned long data)
+{
+	unsigned long *addr;
+
+	if (regno == PT_USP)
+		addr = &task->tss.usp;
+	else if (regno < sizeof(regoff)/sizeof(regoff[0]))
+		addr = (unsigned long *) (task->tss.esp0 + regoff[regno]);
+	else
+		return -1;
+	*addr = data;
+	return 0;
+}
+
+/*
+ * This routine gets a long from any process space by following the page
+ * tables. NOTE! You should check that the long isn't on a page boundary,
+ * and that it is in the task area before calling this: this routine does
+ * no checking.
+ *
+ */
+static unsigned long get_long(struct task_struct * tsk, 
+	struct vm_area_struct * vma, unsigned long addr)
+{
+	pgd_t * pgdir;
+	pmd_t * pgmiddle;
+	pte_t * pgtable;
+	unsigned long page;
+
+repeat:
+	pgdir = pgd_offset(vma->vm_mm, addr);
+	if (pgd_none(*pgdir)) {
+		do_no_page(tsk, vma, addr, 0);
+		goto repeat;
+	}
+	if (pgd_bad(*pgdir)) {
+		printk("ptrace: bad page directory %08lx\n", pgd_val(*pgdir));
+		pgd_clear(pgdir);
+		return 0;
+	}
+	pgmiddle = pmd_offset(pgdir,addr);
+	if (pmd_none(*pgmiddle)) {
+		do_no_page(tsk, vma, addr, 0);
+		goto repeat;
+	}
+	if (pmd_bad(*pgmiddle)) {
+		printk("ptrace: bad page directory %08lx\n",
+		       pmd_val(*pgmiddle));
+		pmd_clear(pgmiddle);
+		return 0;
+	}
+	pgtable = pte_offset(pgmiddle, addr);
+	if (!pte_present(*pgtable)) {
+		do_no_page(tsk, vma, addr, 0);
+		goto repeat;
+	}
+	page = pte_page(*pgtable);
+/* this is a hack for non-kernel-mapped video buffers and similar */
+	if (page >= high_memory)
+		return 0;
+	page += addr & ~PAGE_MASK;
+	return *(unsigned long *) page;
+}
+
+/*
+ * This routine puts a long into any process space by following the page
+ * tables. NOTE! You should check that the long isn't on a page boundary,
+ * and that it is in the task area before calling this: this routine does
+ * no checking.
+ *
+ * Now keeps R/W state of page so that a text page stays readonly
+ * even if a debugger scribbles breakpoints into it.  -M.U-
+ */
+static void put_long(struct task_struct * tsk, struct vm_area_struct * vma, unsigned long addr,
+	unsigned long data)
+{
+	pgd_t *pgdir;
+	pmd_t *pgmiddle;
+	pte_t *pgtable;
+	unsigned long page;
+		
+repeat:
+	pgdir = pgd_offset(vma->vm_mm, addr);
+	if (!pgd_present(*pgdir)) {
+		do_no_page(tsk, vma, addr, 1);
+		goto repeat;
+	}
+	if (pgd_bad(*pgdir)) {
+		printk("ptrace: bad page directory %08lx\n", pgd_val(*pgdir));
+		pgd_clear(pgdir);
+		return;
+	}
+	pgmiddle = pmd_offset(pgdir,addr);
+	if (pmd_none(*pgmiddle)) {
+		do_no_page(tsk, vma, addr, 1);
+		goto repeat;
+	}
+	if (pmd_bad(*pgmiddle)) {
+		printk("ptrace: bad page directory %08lx\n",
+		       pmd_val(*pgmiddle));
+		pmd_clear(pgmiddle);
+		return;
+	}
+	pgtable = pte_offset(pgmiddle, addr);
+	if (!pte_present(*pgtable)) {
+		do_no_page(tsk, vma, addr, 1);
+		goto repeat;
+	}
+	page = pte_page(*pgtable);
+	if (!pte_write(*pgtable)) {
+		do_wp_page(tsk, vma, addr, 2);
+		goto repeat;
+	}
+/* this is a hack for non-kernel-mapped video buffers and similar */
+	if (page < high_memory) {
+		*(unsigned long *) (page + (addr & ~PAGE_MASK)) = data;
+	}
+/* 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 */
+	*pgtable = pte_mkdirty(mk_pte(page, vma->vm_page_prot));
+	flush_tlb_all();
+}
+
+static struct vm_area_struct * find_extend_vma(struct task_struct * tsk, unsigned long addr)
+{
+	struct vm_area_struct * vma;
+
+	addr &= PAGE_MASK;
+	vma = find_vma(tsk,addr);
+	if (!vma)
+		return NULL;
+	if (vma->vm_start <= addr)
+		return vma;
+	if (!(vma->vm_flags & VM_GROWSDOWN))
+		return NULL;
+	if (vma->vm_end - addr > tsk->rlim[RLIMIT_STACK].rlim_cur)
+		return NULL;
+	vma->vm_offset -= vma->vm_start - addr;
+	vma->vm_start = addr;
+	return vma;
+}
+
+/*
+ * This routine checks the page boundaries, and that the offset is
+ * within the task area. It then calls get_long() to read a long.
+ */
+static int read_long(struct task_struct * tsk, unsigned long addr,
+	unsigned long * result)
+{
+	struct vm_area_struct * vma = find_extend_vma(tsk, addr);
+
+	if (!vma)
+		return -EIO;
+	if ((addr & ~PAGE_MASK) > PAGE_SIZE-sizeof(long)) {
+		unsigned long low,high;
+		struct vm_area_struct * vma_low = vma;
+
+		if (addr + sizeof(long) >= vma->vm_end) {
+			vma_low = vma->vm_next;
+			if (!vma_low || vma_low->vm_start != vma->vm_end)
+				return -EIO;
+		}
+		high = get_long(tsk, vma,addr & ~(sizeof(long)-1));
+		low = get_long(tsk, vma_low,(addr+sizeof(long)) & ~(sizeof(long)-1));
+		switch (addr & (sizeof(long)-1)) {
+			case 3:
+				low >>= 8;
+				low |= high << 24;
+				break;
+			case 2:
+				low >>= 16;
+				low |= high << 16;
+				break;
+			case 1:
+				low >>= 24;
+				low |= high << 8;
+				break;
+		}
+		*result = low;
+	} else
+		*result = get_long(tsk, vma,addr);
+	return 0;
+}
+
+/*
+ * This routine checks the page boundaries, and that the offset is
+ * within the task area. It then calls put_long() to write a long.
+ */
+static int write_long(struct task_struct * tsk, unsigned long addr,
+	unsigned long data)
+{
+	struct vm_area_struct * vma = find_extend_vma(tsk, addr);
+
+	if (!vma)
+		return -EIO;
+	if ((addr & ~PAGE_MASK) > PAGE_SIZE-sizeof(long)) {
+		unsigned long low,high;
+		struct vm_area_struct * vma_low = vma;
+
+		if (addr + sizeof(long) >= vma->vm_end) {
+			vma_low = vma->vm_next;
+			if (!vma_low || vma_low->vm_start != vma->vm_end)
+				return -EIO;
+		}
+		high = get_long(tsk, vma,addr & ~(sizeof(long)-1));
+		low = get_long(tsk, vma_low,(addr+sizeof(long)) & ~(sizeof(long)-1));
+		switch (addr & (sizeof(long)-1)) {
+			case 0: /* shouldn't happen, but safety first */
+				high = data;
+				break;
+			case 3:
+				low &= 0x000000ff;
+				low |= data << 8;
+				high &= ~0xff;
+				high |= data >> 24;
+				break;
+			case 2:
+				low &= 0x0000ffff;
+				low |= data << 16;
+				high &= ~0xffff;
+				high |= data >> 16;
+				break;
+			case 1:
+				low &= 0x00ffffff;
+				low |= data << 24;
+				high &= ~0xffffff;
+				high |= data >> 8;
+				break;
+		}
+		put_long(tsk, vma,addr & ~(sizeof(long)-1),high);
+		put_long(tsk, vma_low,(addr+sizeof(long)) & ~(sizeof(long)-1),low);
+	} else
+		put_long(tsk, vma,addr,data);
+	return 0;
+}
+
+asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
+{
+	struct task_struct *child;
+	struct user * dummy;
+
+	dummy = NULL;
+
+	if (request == PTRACE_TRACEME) {
+		/* are we already being traced? */
+		if (current->flags & PF_PTRACED)
+			return -EPERM;
+		/* set the ptrace bit in the process flags. */
+		current->flags |= PF_PTRACED;
+		return 0;
+	}
+	if (pid == 1)		/* you may not mess with init */
+		return -EPERM;
+	if (!(child = get_task(pid)))
+		return -ESRCH;
+	if (request == PTRACE_ATTACH) {
+		if (child == current)
+			return -EPERM;
+		if ((!child->dumpable ||
+		    (current->uid != child->euid) ||
+		    (current->uid != child->uid) ||
+	 	    (current->gid != child->egid) ||
+	 	    (current->gid != child->gid)) && !suser())
+			return -EPERM;
+		/* the same process cannot be attached many times */
+		if (child->flags & PF_PTRACED)
+			return -EPERM;
+		child->flags |= PF_PTRACED;
+		if (child->p_pptr != current) {
+			REMOVE_LINKS(child);
+			child->p_pptr = current;
+			SET_LINKS(child);
+		}
+		send_sig(SIGSTOP, child, 1);
+		return 0;
+	}
+	if (!(child->flags & PF_PTRACED))
+		return -ESRCH;
+	if (child->state != TASK_STOPPED) {
+		if (request != PTRACE_KILL)
+			return -ESRCH;
+	}
+	if (child->p_pptr != current)
+		return -ESRCH;
+
+	switch (request) {
+	/* when I and D space are separate, these will need to be fixed. */
+		case PTRACE_PEEKTEXT: /* read word at location addr. */ 
+		case PTRACE_PEEKDATA: {
+			unsigned long tmp;
+			int res;
+
+			res = read_long(child, addr, &tmp);
+			if (res < 0)
+				return res;
+			res = verify_area(VERIFY_WRITE, (void *) data, sizeof(long));
+			if (!res)
+				put_user(tmp, (unsigned long *) data);
+			return res;
+		}
+
+	/* read the word at location addr in the USER area. */
+		case PTRACE_PEEKUSR: {
+			unsigned long tmp;
+			int res;
+			
+			if ((addr & 3) || addr < 0 || addr >= sizeof(struct user))
+				return -EIO;
+			
+			res = verify_area(VERIFY_WRITE, (void *) data,
+					  sizeof(long));
+			if (res)
+				return res;
+			tmp = 0;  /* Default return condition */
+			addr = addr >> 2; /* temporary hack. */
+			if (addr < 19) {
+				tmp = get_reg(child, addr);
+				if (addr == PT_SR)
+					tmp >>= 16;
+			}
+			else if (addr >= 21 && addr < 49)
+				tmp = child->tss.fp[addr - 21];
+			else
+				return -EIO;
+			put_user(tmp,(unsigned long *) data);
+			return 0;
+		}
+
+      /* when I and D space are separate, this will have to be fixed. */
+		case PTRACE_POKETEXT: /* write the word at location addr. */
+		case PTRACE_POKEDATA:
+			return write_long(child,addr,data);
+
+		case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
+			if ((addr & 3) || addr < 0 || addr >= sizeof(struct user))
+				return -EIO;
+
+			addr = addr >> 2; /* temporary hack. */
+			    
+			if (addr == PT_ORIG_D0)
+				return -EIO;
+			if (addr == PT_SR) {
+				data &= SR_MASK;
+				data <<= 16;
+				data |= get_reg(child, PT_SR) & ~(SR_MASK << 16);
+			}
+			if (addr < 19) {
+				if (put_reg(child, addr, data))
+					return -EIO;
+				return 0;
+			}
+			if (addr >= 21 && addr < 48)
+			{
+				child->tss.fp[addr - 21] = data;
+				return 0;
+			}
+			return -EIO;
+
+		case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
+		case PTRACE_CONT: { /* restart after signal. */
+			long tmp;
+
+			if ((unsigned long) data >= NSIG)
+				return -EIO;
+			if (request == PTRACE_SYSCALL)
+				child->flags |= PF_TRACESYS;
+			else
+				child->flags &= ~PF_TRACESYS;
+			child->exit_code = data;
+			wake_up_process(child);
+			/* make sure the single step bit is not set. */
+			tmp = get_reg(child, PT_SR) & ~(TRACE_BITS << 16);
+			put_reg(child, PT_SR, tmp);
+			return 0;
+		}
+
+/*
+ * make the child exit.  Best I can do is send it a sigkill. 
+ * perhaps it should be put in the status that it wants to 
+ * exit.
+ */
+		case PTRACE_KILL: {
+			long tmp;
+
+			if (child->state == TASK_ZOMBIE) /* already dead */
+				return 0;
+			wake_up_process(child);
+			child->exit_code = SIGKILL;
+	/* make sure the single step bit is not set. */
+			tmp = get_reg(child, PT_SR) & ~(TRACE_BITS << 16);
+			put_reg(child, PT_SR, tmp);
+			return 0;
+		}
+
+		case PTRACE_SINGLESTEP: {  /* set the trap flag. */
+			long tmp;
+
+			if ((unsigned long) data >= NSIG)
+				return -EIO;
+			child->flags &= ~PF_TRACESYS;
+			tmp = get_reg(child, PT_SR) | (TRACE_BITS << 16);
+			put_reg(child, PT_SR, tmp);
+
+			wake_up_process(child);
+			child->exit_code = data;
+	/* give it a chance to run. */
+			return 0;
+		}
+
+		case PTRACE_DETACH: { /* detach a process that was attached. */
+			long tmp;
+
+			if ((unsigned long) data >= NSIG)
+				return -EIO;
+			child->flags &= ~(PF_PTRACED|PF_TRACESYS);
+			wake_up_process(child);
+			child->exit_code = data;
+			REMOVE_LINKS(child);
+			child->p_pptr = child->p_opptr;
+			SET_LINKS(child);
+			/* make sure the single step bit is not set. */
+			tmp = get_reg(child, PT_SR) & ~(TRACE_BITS << 16);
+			put_reg(child, PT_SR, tmp);
+			return 0;
+		}
+
+		default:
+			return -EIO;
+	}
+}
+
+asmlinkage void syscall_trace(void)
+{
+	if ((current->flags & (PF_PTRACED|PF_TRACESYS))
+			!= (PF_PTRACED|PF_TRACESYS))
+		return;
+	current->exit_code = SIGTRAP;
+	current->state = TASK_STOPPED;
+	notify_parent(current);
+	schedule();
+	/*
+	 * this isn't the same as continuing with a signal, but it will do
+	 * for normal use.  strace only continues with a signal if the
+	 * stopping signal is not SIGTRAP.  -brl
+	 */
+	if (current->exit_code)
+		current->signal |= (1 << (current->exit_code - 1));
+	current->exit_code = 0;
+	return;
+}
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/kernel/setup.c linux/arch/m68k/kernel/setup.c
--- v1.3.93/linux/arch/m68k/kernel/setup.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/kernel/setup.c	Fri Apr 19 02:41:14 1996
@@ -0,0 +1,355 @@
+/*
+ *  linux/arch/m68k/kernel/setup.c
+ *
+ *  Copyright (C) 1995  Hamish Macdonald
+ */
+
+/*
+ * This file handles the architecture-dependent parts of system setup
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/fs.h>
+#include <linux/console.h>
+#include <linux/genhd.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+
+#include <asm/bootinfo.h>
+#include <asm/irq.h>
+#include <asm/machdep.h>
+#include <asm/amigatypes.h>
+#include <asm/amigahw.h>
+
+#ifdef CONFIG_BLK_DEV_INITRD
+#include <linux/blk.h>
+#include <asm/pgtable.h>
+#endif
+
+struct bootinfo boot_info = {0,};
+int bisize = sizeof boot_info;
+
+int m68k_is040or060 = 0;
+
+char m68k_debug_device[6] = "";
+
+extern int end;
+extern unsigned long availmem;
+
+char saved_command_line[CL_SIZE];
+
+/* setup some dummy routines */
+static void dummy_waitbut(void)
+{
+}
+
+void (*mach_sched_init) (isrfunc);
+int (*mach_keyb_init) (void);
+int (*mach_kbdrate) (struct kbd_repeat *) = NULL;
+void (*mach_kbd_leds) (unsigned int) = NULL;
+void (*mach_init_INTS) (void);
+int (*mach_add_isr) (unsigned long, isrfunc, int, void *, char *);
+int (*mach_remove_isr) (unsigned long, isrfunc);
+void (*mach_process_int) (int, struct pt_regs *) = NULL;
+void (*mach_enable_irq) (unsigned) = NULL;
+void (*mach_disable_irq) (unsigned) = NULL;
+int (*mach_get_irq_list) (char *, int) = NULL;
+unsigned long (*mach_gettimeoffset) (void);
+void (*mach_gettod) (int*, int*, int*, int*, int*, int*);
+int (*mach_hwclk) (int, struct hwclk_time*) = NULL;
+int (*mach_set_clock_mmss) (unsigned long) = NULL;
+void (*mach_check_partition) (struct gendisk *, unsigned int);
+void (*mach_mksound)( unsigned int count, unsigned int ticks );
+void (*mach_reset)( void );
+void (*waitbut)(void) = dummy_waitbut;
+struct fb_info *(*mach_fb_init)(long *);
+long mach_max_dma_address = 0x00ffffff; /* default set to the lower 16MB */
+void (*mach_debug_init)(void);
+void (*mach_video_setup) (char *, int *);
+#ifdef CONFIG_BLK_DEV_FD
+int (*mach_floppy_init) (void) = NULL;
+void (*mach_floppy_setup) (char *, int *) = NULL;
+#endif
+
+extern void config_amiga(void);
+extern void config_atari(void);
+extern void config_mac(void);
+
+extern void register_console(void (*proc)(const char *));
+extern void ami_serial_print (const char *str);
+extern void ata_serial_print (const char *str);
+
+extern void (*kd_mksound)(unsigned int, unsigned int);
+
+extern void amiga_get_model(char *model);
+extern void atari_get_model(char *model);
+extern void mac_get_model(char *model);
+extern int amiga_get_hardware_list(char *buffer);
+extern int atari_get_hardware_list(char *buffer);
+extern int mac_get_hardware_list(char *buffer);
+
+#define MASK_256K 0xfffc0000
+
+void setup_arch(char **cmdline_p,
+		unsigned long * memory_start_p, unsigned long * memory_end_p)
+{
+	unsigned long memory_start, memory_end;
+	extern int _etext, _edata, _end;
+	int i;
+	char *p, *q;
+
+#ifdef CONFIG_AMIGA
+	if (MACH_IS_AMIGA)
+	  register_console (ami_serial_print);
+#endif
+#ifdef CONFIG_ATARI
+	if (MACH_IS_ATARI)
+	  register_console (ata_serial_print);
+#endif
+
+	if (boot_info.cputype & CPU_68040)
+		m68k_is040or060 = 4;
+	else if (boot_info.cputype & CPU_68060)
+		m68k_is040or060 = 6;
+
+	memory_start = availmem;
+	memory_end = 0;
+
+	for (i = 0; i < boot_info.num_memory; i++)
+		memory_end += boot_info.memory[i].size & MASK_256K;
+
+	init_task.mm->start_code = 0;
+	init_task.mm->end_code = (unsigned long) &_etext;
+	init_task.mm->end_data = (unsigned long) &_edata;
+	init_task.mm->brk = (unsigned long) &_end;
+
+	*cmdline_p = boot_info.command_line;
+	memcpy(saved_command_line, *cmdline_p, CL_SIZE);
+
+	/* Parse the command line for arch-specific options.
+	 * For the m68k, this is currently only "debug=xxx" to enable printing
+	 * certain kernel messages to some machine-specific device.
+	 */
+	for( p = *cmdline_p; p && *p; ) {
+	    i = 0;
+	    if (!strncmp( p, "debug=", 6 )) {
+		strncpy( m68k_debug_device, p+6, sizeof(m68k_debug_device)-1 );
+		m68k_debug_device[sizeof(m68k_debug_device)-1] = 0;
+		if ((q = strchr( m68k_debug_device, ' ' ))) *q = 0;
+		i = 1;
+	    }
+
+	    if (i) {
+		/* option processed, delete it */
+		if ((q = strchr( p, ' ' )))
+		    strcpy( p, q+1 );
+		else
+		    *p = 0;
+	    } else {
+		if ((p = strchr( p, ' ' ))) ++p;
+	    }
+	}
+
+	*memory_start_p = memory_start;
+	*memory_end_p = memory_end;
+
+	switch (boot_info.machtype) {
+#ifdef CONFIG_AMIGA
+	    case MACH_AMIGA:
+		config_amiga();
+		break;
+#endif
+#ifdef CONFIG_ATARI
+	    case MACH_ATARI:
+		config_atari();
+		break;
+#endif
+#ifdef CONFIG_MAC
+	    case MACH_MAC:
+		config_mac();
+		break;
+#endif
+	    default:
+		panic ("No configuration setup");
+	}
+
+#ifdef CONFIG_BLK_DEV_INITRD
+	if (boot_info.ramdisk_size) {
+		initrd_start = PTOV (boot_info.ramdisk_addr);
+		initrd_end = initrd_start + boot_info.ramdisk_size * 1024;
+	}
+#endif
+}
+
+int setkeycode(unsigned int scancode, unsigned int keycode)
+{
+	return -EOPNOTSUPP;
+}
+
+int getkeycode(unsigned int scancode)
+{
+	return -EOPNOTSUPP;
+}
+
+int get_cpuinfo(char * buffer)
+{
+    char *cpu, *mmu, *fpu;
+    u_long clockfreq, clockfactor;
+
+#define CLOCK_FACTOR_68020	(8046)	/*  3107016 loops/s @ 25 MHz (Sun-3) */
+#define CLOCK_FACTOR_68030	(8010)	/*  3994575 loops/s @ 32 MHz */
+#define CLOCK_FACTOR_68040	(3010)	/*  8305552 loops/s @ 25 MHz */
+#define CLOCK_FACTOR_68060	(998)	/* 50081241 loops/s @ 50 MHz */
+
+    if (boot_info.cputype & CPU_68020) {
+	cpu = "68020";
+	mmu = "68851";
+	clockfactor = CLOCK_FACTOR_68020;
+    } else if (boot_info.cputype & CPU_68030) {
+	cpu = mmu = "68030";
+	clockfactor = CLOCK_FACTOR_68030;
+    } else if (boot_info.cputype & CPU_68040) {
+	cpu = mmu = "68040";
+	clockfactor = CLOCK_FACTOR_68040;
+    } else if (boot_info.cputype & CPU_68060) {
+	cpu = mmu = "68060";
+	clockfactor = CLOCK_FACTOR_68060;
+    } else {
+	cpu = mmu = "680x0";
+	clockfactor = 0;
+    }
+
+    if (boot_info.cputype & FPU_68881)
+	fpu = "68881";
+    else if (boot_info.cputype & FPU_68882)
+	fpu = "68882";
+    else if (boot_info.cputype & FPU_68040)
+	fpu = "68040";
+    else if (boot_info.cputype & FPU_68060)
+	fpu = "68060";
+    else
+	fpu = "none";
+
+    clockfreq = loops_per_sec/1000*clockfactor;
+
+    return(sprintf(buffer, "CPU:\t\t%s\n"
+		   "MMU:\t\t%s\n"
+		   "FPU:\t\t%s\n"
+		   "Clockspeed:\t%lu.%1luMHz\n"
+		   "BogoMips:\t%lu.%02lu\n",
+		   cpu, mmu, fpu, clockfreq/1000000,
+		   ((clockfreq+50000)/100000)%10, loops_per_sec/500000,
+		   (loops_per_sec/5000)%100));
+}
+
+int get_hardware_list(char *buffer)
+{
+    int len = 0;
+    char model[80];
+    u_long mem;
+    int i;
+
+    switch (boot_info.machtype) {
+#ifdef CONFIG_AMIGA
+	case MACH_AMIGA:
+	    amiga_get_model(model);
+	    break;
+#endif
+#ifdef CONFIG_ATARI
+	case MACH_ATARI:
+	    atari_get_model(model);
+	    break;
+#endif
+#ifdef CONFIG_MAC
+	case MACH_MAC:
+	    mac_get_model(model);
+	    break;
+#endif
+	default:
+	    strcpy(model, "Unknown m68k");
+    } /* boot_info.machtype */
+
+    len += sprintf(buffer+len, "Model:\t\t%s\n", model);
+    len += get_cpuinfo(buffer+len);
+    for (mem = 0, i = 0; i < boot_info.num_memory; i++)
+	mem += boot_info.memory[i].size;
+    len += sprintf(buffer+len, "System Memory:\t%ldK\n", mem>>10);
+
+    switch (boot_info.machtype) {
+#ifdef CONFIG_AMIGA
+	case MACH_AMIGA:
+	    len += amiga_get_hardware_list(buffer+len);
+	    break;
+#endif
+#ifdef CONFIG_ATARI
+	case MACH_ATARI:
+	    len += atari_get_hardware_list(buffer+len);
+	    break;
+#endif
+#ifdef CONFIG_MAC
+	case MACH_MAC:
+	    break;
+#endif
+    } /* boot_info.machtype */
+
+#if 0 /* ++1.3++ */
+    len += get_serial_list (buffer + len);
+#endif /* ++1.3++ */
+
+    return(len);
+}
+
+#ifdef CONFIG_BLK_DEV_FD
+int floppy_init(void)
+{
+	if (mach_floppy_init)
+		return mach_floppy_init();
+	else
+		return 0;
+}
+
+void floppy_setup(char *str, int *ints)
+{
+	if (mach_floppy_setup)
+		mach_floppy_setup (str, ints);
+}
+#endif
+
+unsigned long arch_kbd_init(void)
+{
+	return mach_keyb_init();
+}
+
+int rs_init(void)
+{
+	return 0;
+}
+
+struct serial_struct;
+int register_serial(struct serial_struct *req)
+{
+    return -1;
+}
+
+void unregister_serial(int line)
+{
+}
+
+void arch_gettod(int *year, int *mon, int *day, int *hour,
+		 int *min, int *sec)
+{
+	if (mach_gettod)
+		mach_gettod(year, mon, day, hour, min, sec);
+	else
+		*year = *mon = *day = *hour = *min = *sec = 0;
+}
+
+void video_setup (char *options, int *ints)
+{
+	if (mach_video_setup)
+		mach_video_setup (options, ints);
+}
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/kernel/signal.c linux/arch/m68k/kernel/signal.c
--- v1.3.93/linux/arch/m68k/kernel/signal.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/kernel/signal.c	Thu Apr 18 02:07:17 1996
@@ -0,0 +1,557 @@
+/*
+ *  linux/arch/m68k/kernel/signal.c
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file README.legal in the main directory of this archive
+ * for more details.
+ */
+
+/*
+ * 680x0 support by Hamish Macdonald
+ */
+
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/kernel.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/wait.h>
+#include <linux/ptrace.h>
+#include <linux/unistd.h>
+
+#include <asm/segment.h>
+#include <asm/pgtable.h>
+#include <asm/traps.h>
+#include <asm/bootinfo.h>
+
+#define offsetof(type, member)  ((size_t)(&((type *)0)->member))
+
+#define _S(nr) (1<<((nr)-1))
+
+#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
+
+asmlinkage int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options);
+asmlinkage int do_signal(unsigned long oldmask, struct pt_regs *regs);
+
+static const int extra_sizes[16] = {
+  0,
+  -1, /* sizeof(((struct frame *)0)->un.fmt1), */
+  sizeof(((struct frame *)0)->un.fmt2),
+  sizeof(((struct frame *)0)->un.fmt3),
+  sizeof(((struct frame *)0)->un.fmt4),
+  -1, /* sizeof(((struct frame *)0)->un.fmt5), */
+  -1, /* sizeof(((struct frame *)0)->un.fmt6), */
+  sizeof(((struct frame *)0)->un.fmt7),
+  -1, /* sizeof(((struct frame *)0)->un.fmt8), */
+  sizeof(((struct frame *)0)->un.fmt9),
+  sizeof(((struct frame *)0)->un.fmta),
+  sizeof(((struct frame *)0)->un.fmtb),
+  -1, /* sizeof(((struct frame *)0)->un.fmtc), */
+  -1, /* sizeof(((struct frame *)0)->un.fmtd), */
+  -1, /* sizeof(((struct frame *)0)->un.fmte), */
+  -1, /* sizeof(((struct frame *)0)->un.fmtf), */
+};
+
+/*
+ * atomically swap in the new signal mask, and wait for a signal.
+ */
+asmlinkage int do_sigsuspend(struct pt_regs *regs)
+{
+	unsigned long oldmask = current->blocked;
+	unsigned long newmask = regs->d3;
+
+	current->blocked = newmask & _BLOCKABLE;
+	regs->d0 = -EINTR;
+	while (1) {
+		current->state = TASK_INTERRUPTIBLE;
+		schedule();
+		if (do_signal(oldmask, regs))
+			return -EINTR;
+	}
+}
+
+static unsigned char fpu_version = 0;	/* version number of fpu, set by setup_frame */
+
+/*
+ * This sets regs->usp even though we don't actually use sigstacks yet..
+ */
+asmlinkage int do_sigreturn(unsigned long __unused)
+{
+	struct sigcontext_struct context;
+	struct frame * regs;
+	struct switch_stack *sw;
+	int fsize = 0;
+	int formatvec = 0;
+	unsigned long fp;
+	unsigned long usp = rdusp();
+
+#if 0
+	printk("sys_sigreturn, usp=%08x\n", (unsigned) usp);
+#endif
+
+	/* get stack frame pointer */
+	sw = (struct switch_stack *) &__unused;
+	regs = (struct frame *) (sw + 1);
+
+	/* get previous context (including pointer to possible extra junk) */
+        if (verify_area(VERIFY_READ, (void *)usp, sizeof(context)))
+                goto badframe;
+
+	memcpy_fromfs(&context,(void *)usp, sizeof(context));
+
+	fp = usp + sizeof (context);
+
+	/* restore signal mask */
+	current->blocked = context.sc_mask & _BLOCKABLE;
+
+	/* restore passed registers */
+	regs->ptregs.d0 = context.sc_d0;
+	regs->ptregs.d1 = context.sc_d1;
+	regs->ptregs.a0 = context.sc_a0;
+	regs->ptregs.a1 = context.sc_a1;
+	regs->ptregs.sr = (regs->ptregs.sr & 0xff00)|(context.sc_sr & 0xff);
+	regs->ptregs.pc = context.sc_pc;
+
+	wrusp(context.sc_usp);
+	formatvec = context.sc_formatvec;
+	regs->ptregs.format = formatvec >> 12;
+	regs->ptregs.vector = formatvec & 0xfff;
+	if (context.sc_fpstate[0])
+	  {
+	    /* Verify the frame format.  */
+	    if (context.sc_fpstate[0] != fpu_version){
+#if DEBUG
+	    printk("fpregs=%08x fpcntl=%08x\n", context.sc_fpregs,
+		   context.sc_fpcntl); 
+	    printk("Wrong fpu: sc_fpstate[0]=%02x fpu_version=%02x\n",
+		   (unsigned) context.sc_fpstate[0], (unsigned) fpu_version);
+	    {
+	      int i;
+	      printk("Saved fp_state: ");
+	      for (i = 0; i < 216; i++){
+		printk("%02x ", context.sc_fpstate[i]);
+	      }
+	      printk("\n");
+	    }
+#endif
+	      goto badframe;
+	    }
+	    if (boot_info.cputype & FPU_68881)
+	      {
+		if (context.sc_fpstate[1] != 0x18
+		    && context.sc_fpstate[1] != 0xb4)
+		  goto badframe;
+	      }
+	    else if (boot_info.cputype & FPU_68882)
+	      {
+		if (context.sc_fpstate[1] != 0x38
+		    && context.sc_fpstate[1] != 0xd4){
+#if 0
+		  printk("Wrong 68882 fpu-state\n");
+#endif
+		  goto badframe;
+		}
+	      }
+	    else if (boot_info.cputype & FPU_68040)
+	      {
+		if (!((context.sc_fpstate[1] == 0x00)|| \
+                      (context.sc_fpstate[1] == 0x28)|| \
+                      (context.sc_fpstate[1] == 0x60))){
+#if 0
+		  printk("Wrong 68040 fpu-state\n");
+#endif
+		  goto badframe;
+		}
+	      }
+	    else if (boot_info.cputype & FPU_68060)
+	      {
+		if (!((context.sc_fpstate[1] == 0x00)|| \
+                      (context.sc_fpstate[1] == 0x60)|| \
+                      (context.sc_fpstate[1] == 0xe0))){
+#if 0
+		  printk("Wrong 68060 fpu-state\n");
+#endif
+		  goto badframe;
+		}
+	      }
+	    __asm__ volatile ("fmovemx %0,%/fp0-%/fp1\n\t"
+			      "fmoveml %1,%/fpcr/%/fpsr/%/fpiar"
+			      : /* no outputs */
+			      : "m" (*context.sc_fpregs),
+				"m" (*context.sc_fpcntl));
+	  }
+	__asm__ volatile ("frestore %0" : : "m" (*context.sc_fpstate));
+
+	fsize = extra_sizes[regs->ptregs.format];
+	if (fsize < 0) {
+		/*
+		 * user process trying to return with weird frame format
+		 */
+#if DEBUG
+	      printk("user process returning with weird frame format\n");
+#endif
+		goto badframe;
+	}
+
+	/* OK.	Make room on the supervisor stack for the extra junk,
+	 * if necessary.
+	 */
+
+	if (fsize) {
+		if (verify_area(VERIFY_READ, (void *)fp, fsize))
+                        goto badframe;
+
+#define frame_offset (sizeof(struct pt_regs)+sizeof(struct switch_stack))
+		__asm__ __volatile__
+			("movel %0,%/a0\n\t"
+			 "subl %1,%/a0\n\t"     /* make room on stack */
+			 "movel %/a0,%/sp\n\t"  /* set stack pointer */
+			 /* move switch_stack and pt_regs */
+			 "1: movel %0@+,%/a0@+\n\t"
+			 "   dbra %2,1b\n\t"
+			 "lea %/sp@(%c3),%/a0\n\t" /* add offset of fmt stuff */
+			 "lsrl  #2,%1\n\t"
+			 "subql #1,%1\n\t"
+			 "2: movesl %4@+,%2\n\t"
+			 "   movel %2,%/a0@+\n\t"
+			 "   dbra %1,2b\n\t"
+			 "bral " SYMBOL_NAME_STR(ret_from_signal)
+			 : /* no outputs, it doesn't ever return */
+			 : "a" (sw), "d" (fsize), "d" (frame_offset/4-1),
+			   "n" (frame_offset), "a" (fp)
+			 : "a0");
+#undef frame_offset
+		goto badframe;
+		/* NOTREACHED */
+	}
+
+	return regs->ptregs.d0;
+badframe:
+        do_exit(SIGSEGV);
+}
+
+/*
+ * Set up a signal frame...
+ *
+ * This routine is somewhat complicated by the fact that if the
+ * kernel may be entered by an exception other than a system call;
+ * e.g. a bus error or other "bad" exception.  If this is the case,
+ * then *all* the context on the kernel stack frame must be saved.
+ *
+ * For a large number of exceptions, the stack frame format is the same
+ * as that which will be created when the process traps back to the kernel
+ * when finished executing the signal handler.	In this case, nothing
+ * must be done.  This is exception frame format "0".  For exception frame
+ * formats "2", "9", "A" and "B", the extra information on the frame must
+ * be saved.  This information is saved on the user stack and restored
+ * when the signal handler is returned.
+ *
+ * The format of the user stack when executing the signal handler is:
+ *
+ *     usp ->  RETADDR (points to code below)
+ *	       signum  (parm #1)
+ *	       sigcode (parm #2 ; vector number)
+ *	       scp     (parm #3 ; sigcontext pointer, pointer to #1 below)
+ *	       code1   (addaw #20,sp) ; pop parms and code off stack
+ *	       code2   (moveq #119,d0; trap #0) ; sigreturn syscall
+ *     #1|     oldmask
+ *	 |     old usp
+ *	 |     d0      (first saved reg)
+ *	 |     d1
+ *	 |     a0
+ *	 |     a1
+ *	 |     sr      (saved status register)
+ *	 |     pc      (old pc; one to return to)
+ *	 |     forvec  (format and vector word of old supervisor stack frame)
+ *	 |     floating point context
+ *
+ * These are optionally followed by some extra stuff, depending on the
+ * stack frame interrupted. This is 1 longword for format "2", 3
+ * longwords for format "9", 6 longwords for format "A", and 21
+ * longwords for format "B".
+ */
+
+#define UFRAME_SIZE(fs) (sizeof(struct sigcontext_struct)/4 + 6 + fs/4)
+
+static void setup_frame (struct sigaction * sa, unsigned long **fp,
+			 unsigned long pc, struct frame *regs, int
+			 signr, unsigned long oldmask)
+{
+	struct sigcontext_struct context;
+	unsigned long *frame, *tframe;
+	int fsize = extra_sizes[regs->ptregs.format];
+
+	if (fsize < 0) {
+		printk ("setup_frame: Unknown frame format %#x\n",
+			regs->ptregs.format);
+		do_exit(SIGSEGV);
+	}
+	frame = *fp - UFRAME_SIZE(fsize);
+	if (verify_area(VERIFY_WRITE,frame,UFRAME_SIZE(fsize)*4))
+		do_exit(SIGSEGV);
+	if (fsize) {
+		memcpy_tofs (frame + UFRAME_SIZE(0), &regs->un, fsize);
+		regs->ptregs.stkadj = fsize;
+	}
+
+/* set up the "normal" stack seen by the signal handler */
+	tframe = frame;
+
+	/* return address points to code on stack */
+	put_user((ulong)(frame+4), tframe); tframe++;
+	if (current->exec_domain && current->exec_domain->signal_invmap)
+	    put_user(current->exec_domain->signal_invmap[signr], tframe);
+	else
+	    put_user(signr, tframe);
+	tframe++;
+
+	put_user(regs->ptregs.vector, tframe); tframe++;
+	/* "scp" parameter.  points to sigcontext */
+	put_user((ulong)(frame+6), tframe); tframe++;
+
+/* set up the return code... */
+	put_user(0xdefc0014,tframe); tframe++; /* addaw #20,sp */
+	put_user(0x70774e40,tframe); tframe++; /* moveq #119,d0; trap #0 */
+
+/* Flush caches so the instructions will be correctly executed. (MA) */
+	cache_push_v ((unsigned long)frame, (int)tframe - (int)frame);
+
+/* setup and copy the sigcontext structure */
+	context.sc_mask       = oldmask;
+	context.sc_usp	      = (unsigned long)*fp;
+	context.sc_d0	      = regs->ptregs.d0;
+	context.sc_d1	      = regs->ptregs.d1;
+	context.sc_a0	      = regs->ptregs.a0;
+	context.sc_a1	      = regs->ptregs.a1;
+	context.sc_sr	      = regs->ptregs.sr;
+	context.sc_pc	      = pc;
+	context.sc_formatvec  = (regs->ptregs.format << 12 |
+				 regs->ptregs.vector);
+#if DEBUG
+	printk("formatvec: %02x\n", (unsigned) context.sc_formatvec);
+#endif
+	__asm__ volatile ("fsave %0" : : "m" (*context.sc_fpstate) : "memory");
+	if (context.sc_fpstate[0])
+	  {
+	    fpu_version = context.sc_fpstate[0];
+#if DEBUG
+	    {
+	      int i;
+	      printk("Saved fp_state: ");
+	      for (i = 0; i < 216; i++){
+		printk("%02x ", context.sc_fpstate[i]);
+	      }
+	      printk("\n");
+	    }
+	    printk("fpregs=%08x fpcntl=%08x\n", context.sc_fpregs,
+		   context.sc_fpcntl); 
+#endif
+	    __asm__ volatile ("fmovemx %/fp0-%/fp1,%0\n\t"
+			      "fmoveml %/fpcr/%/fpsr/%/fpiar,%1"
+			      : /* no outputs */
+			      : "m" (*context.sc_fpregs),
+				"m" (*context.sc_fpcntl)
+			      : "memory");
+	  }
+#if DEBUG
+	{
+	  int i;
+	  printk("Saved fp_state: ");
+	  for (i = 0; i < 216; i++){
+	    printk("%02x ", context.sc_fpstate[i]);
+	  }
+	  printk("\n");
+	}
+#endif
+	memcpy_tofs (tframe, &context, sizeof(context));
+	/*
+	 * no matter what frame format we were using before, we
+	 * will do the "RTE" using a normal 4 word frame.
+	 */
+	regs->ptregs.format = 0;
+
+	/* "return" new usp to caller */
+	*fp = frame;
+}
+
+/*
+ * Note that 'init' is a special process: it doesn't get signals it doesn't
+ * want to handle. Thus you cannot kill init even with a SIGKILL even by
+ * mistake.
+ *
+ * Note that we go through the signals twice: once to check the signals
+ * that the kernel can handle, and then we build all the user-level signal
+ * handling stack-frames in one go after that.
+ */
+asmlinkage int do_signal(unsigned long oldmask, struct pt_regs *regs_in)
+{
+	unsigned long mask = ~current->blocked;
+	unsigned long handler_signal = 0;
+	unsigned long *frame = NULL;
+	unsigned long pc = 0;
+	unsigned long signr;
+	struct frame *regs = (struct frame *)regs_in;
+	struct sigaction * sa;
+
+	current->tss.esp0 = (unsigned long) regs;
+
+	while ((signr = current->signal & mask)) {
+		__asm__("bfffo  %2,#0,#0,%1\n\t"
+			"bfclr  %0,%1,#1\n\t"
+			"eorw   #31,%1"
+			:"=m" (current->signal),"=r" (signr)
+			:"1" (signr));
+		sa = current->sig->action + signr;
+		signr++;
+
+		if ((current->flags & PF_PTRACED) && signr != SIGKILL) {
+			current->exit_code = signr;
+			current->state = TASK_STOPPED;
+			notify_parent(current);
+			schedule();
+			if (!(signr = current->exit_code)) {
+			discard_frame:
+				/* Make sure that a faulted bus cycle
+				   isn't restarted.  */
+				switch (regs->ptregs.format) {
+				case 7:
+				case 9:
+				case 10:
+				case 11:
+				  regs->ptregs.stkadj = extra_sizes[regs->ptregs.format];
+				  regs->ptregs.format = 0;
+				  break;
+				}
+				continue;
+			}
+			current->exit_code = 0;
+			if (signr == SIGSTOP)
+				goto discard_frame;
+			if (_S(signr) & current->blocked) {
+				current->signal |= _S(signr);
+				continue;
+			}
+			sa = current->sig->action + signr - 1;
+		}
+		if (sa->sa_handler == SIG_IGN) {
+			if (signr != SIGCHLD)
+				continue;
+			/* check for SIGCHLD: it's special */
+			while (sys_waitpid(-1,NULL,WNOHANG) > 0)
+				/* nothing */;
+			continue;
+		}
+		if (sa->sa_handler == SIG_DFL) {
+			if (current->pid == 1)
+				continue;
+			switch (signr) {
+			    case SIGCONT: case SIGCHLD: case SIGWINCH:
+				continue;
+
+			    case SIGSTOP: case SIGTSTP: case SIGTTIN: case SIGTTOU:
+				if (current->flags & PF_PTRACED)
+					continue;
+				current->state = TASK_STOPPED;
+				current->exit_code = signr;
+				if (!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags & 
+				      SA_NOCLDSTOP))
+					notify_parent(current);
+				schedule();
+				continue;
+
+			    case SIGQUIT: case SIGILL: case SIGTRAP:
+			    case SIGIOT: case SIGFPE: case SIGSEGV:
+				if (current->binfmt && current->binfmt->core_dump) {
+				    if (current->binfmt->core_dump(signr, (struct pt_regs *)regs))
+					signr |= 0x80;
+				}
+				/* fall through */
+			    default:
+				current->signal |= _S(signr & 0x7f);
+				do_exit(signr);
+			}
+		}
+		/*
+		 * OK, we're invoking a handler
+		 */
+		if (regs->ptregs.orig_d0 >= 0) {
+		  if (regs->ptregs.d0 == -ERESTARTNOHAND ||
+		      (regs->ptregs.d0 == -ERESTARTSYS &&
+		       !(sa->sa_flags & SA_RESTART)))
+		    regs->ptregs.d0 = -EINTR;
+		}
+		handler_signal |= 1 << (signr-1);
+		mask &= ~sa->sa_mask;
+	}
+	if (regs->ptregs.orig_d0 >= 0 &&
+	    (regs->ptregs.d0 == -ERESTARTNOHAND ||
+	     regs->ptregs.d0 == -ERESTARTSYS ||
+	     regs->ptregs.d0 == -ERESTARTNOINTR)) {
+		regs->ptregs.d0 = regs->ptregs.orig_d0;
+		regs->ptregs.pc -= 2;
+	}
+	if (!handler_signal)    /* no handler will be called - return 0 */
+	  {
+	    /* If we are about to discard some frame stuff we must
+	       copy over the remaining frame. */
+	    if (regs->ptregs.stkadj)
+	      {
+		struct frame *tregs =
+		  (struct frame *) ((ulong) regs + regs->ptregs.stkadj);
+
+		/* This must be copied with decreasing addresses to
+		   handle overlaps.  */
+		tregs->ptregs.vector = regs->ptregs.vector;
+		tregs->ptregs.format = regs->ptregs.format;
+		tregs->ptregs.pc = regs->ptregs.pc;
+		tregs->ptregs.sr = regs->ptregs.sr;
+	      }
+	    return 0;
+	  }
+	pc = regs->ptregs.pc;
+	frame = (unsigned long *)rdusp();
+	signr = 1;
+	sa = current->sig->action;
+	for (mask = 1 ; mask ; sa++,signr++,mask += mask) {
+		if (mask > handler_signal)
+			break;
+		if (!(mask & handler_signal))
+			continue;
+		setup_frame(sa,&frame,pc,regs,signr,oldmask);
+		pc = (unsigned long) sa->sa_handler;
+		if (sa->sa_flags & SA_ONESHOT)
+			sa->sa_handler = NULL;
+/* force a supervisor-mode page-in of the signal handler to reduce races */
+		__asm__ __volatile__("movesb %0,%/d0": :"m" (*(char *)pc):"d0");
+		current->blocked |= sa->sa_mask;
+		oldmask |= sa->sa_mask;
+	}
+	wrusp((unsigned long)frame);
+	regs->ptregs.pc = pc;
+
+	/*
+	 * if setup_frame saved some extra frame junk, we need to
+	 * skip over that stuff when doing the RTE.  This means we have
+	 * to move the machine portion of the stack frame to where the
+	 * "RTE" instruction expects it. The signal that we need to
+	 * do this is that regs->stkadj is nonzero.
+	 */
+	if (regs->ptregs.stkadj) {
+		struct frame *tregs =
+			(struct frame *)((ulong)regs + regs->ptregs.stkadj);
+#if DEBUG
+	  printk("Performing stackadjust=%04x\n", (unsigned)
+		 regs->ptregs.stkadj);
+#endif
+		/* This must be copied with decreasing addresses to
+                   handle overlaps.  */
+		tregs->ptregs.vector = regs->ptregs.vector;
+		tregs->ptregs.format = regs->ptregs.format;
+		tregs->ptregs.pc = regs->ptregs.pc;
+		tregs->ptregs.sr = regs->ptregs.sr;
+	}
+
+	return 1;
+}
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/kernel/sys_m68k.c linux/arch/m68k/kernel/sys_m68k.c
--- v1.3.93/linux/arch/m68k/kernel/sys_m68k.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/kernel/sys_m68k.c	Wed Apr 10 23:44:37 1996
@@ -0,0 +1,185 @@
+/*
+ * linux/arch/m68k/kernel/sys_m68k.c
+ *
+ * This file contains various random system calls that
+ * have a non-standard calling sequence on the Linux/m68k
+ * platform.
+ */
+
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/sem.h>
+#include <linux/msg.h>
+#include <linux/shm.h>
+#include <linux/stat.h>
+#include <linux/mman.h>
+
+#include <asm/segment.h>
+
+/*
+ * sys_pipe() is the normal C calling standard for creating
+ * a pipe. It's not the way unix tranditionally does this, though.
+ */
+asmlinkage int sys_pipe(unsigned long * fildes)
+{
+	int fd[2];
+	int error;
+
+	error = verify_area(VERIFY_WRITE,fildes,8);
+	if (error)
+		return error;
+	error = do_pipe(fd);
+	if (error)
+		return error;
+	put_user(fd[0],0+fildes);
+	put_user(fd[1],1+fildes);
+	return 0;
+}
+
+/*
+ * Perform the select(nd, in, out, ex, tv) and mmap() system
+ * calls. Linux/m68k cloned Linux/i386, which didn't use to be able to
+ * handle more than 4 system call parameters, so these system calls
+ * used a memory block for parameter passing..
+ */
+
+asmlinkage int old_mmap(unsigned long *buffer)
+{
+	int error;
+	unsigned long flags;
+	struct file * file = NULL;
+
+	error = verify_area(VERIFY_READ, buffer, 6*sizeof(long));
+	if (error)
+		return error;
+	flags = get_user(buffer+3);
+	if (!(flags & MAP_ANONYMOUS)) {
+		unsigned long fd = get_user(buffer+4);
+		if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
+			return -EBADF;
+	}
+	flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
+	return do_mmap(file, get_user(buffer), get_user(buffer+1),
+		       get_user(buffer+2), flags, get_user(buffer+5));
+}
+
+
+extern asmlinkage int sys_select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
+
+asmlinkage int old_select(unsigned long *buffer)
+{
+	int n;
+	fd_set *inp;
+	fd_set *outp;
+	fd_set *exp;
+	struct timeval *tvp;
+
+	n = verify_area(VERIFY_READ, buffer, 5*sizeof(unsigned long));
+	if (n)
+	  return n;
+
+	n = get_user(buffer);
+	inp = (fd_set *) get_user(buffer+1);
+	outp = (fd_set *) get_user(buffer+2);
+	exp = (fd_set *) get_user(buffer+3);
+	tvp = (struct timeval *) get_user(buffer+4);
+	return sys_select(n, inp, outp, exp, tvp);
+}
+
+/*
+ * sys_ipc() is the de-multiplexer for the SysV IPC calls..
+ *
+ * This is really horribly ugly.
+ */
+asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr, long fifth)
+{
+	int version;
+
+	version = call >> 16; /* hack for backward compatibility */
+	call &= 0xffff;
+
+	if (call <= SEMCTL)
+		switch (call) {
+		case SEMOP:
+			return sys_semop (first, (struct sembuf *)ptr, second);
+		case SEMGET:
+			return sys_semget (first, second, third);
+		case SEMCTL: {
+			union semun fourth;
+			int err;
+			if (!ptr)
+				return -EINVAL;
+			if ((err = verify_area (VERIFY_READ, ptr, sizeof(long))))
+				return err;
+			fourth.__pad = get_user((void **)ptr);
+			return sys_semctl (first, second, third, fourth);
+			}
+		default:
+			return -EINVAL;
+		}
+	if (call <= MSGCTL) 
+		switch (call) {
+		case MSGSND:
+			return sys_msgsnd (first, (struct msgbuf *) ptr, 
+					   second, third);
+		case MSGRCV:
+			switch (version) {
+			case 0: {
+				struct ipc_kludge tmp;
+				int err;
+				if (!ptr)
+					return -EINVAL;
+				if ((err = verify_area (VERIFY_READ, ptr, sizeof(tmp))))
+					return err;
+				memcpy_fromfs (&tmp,(struct ipc_kludge *) ptr,
+					       sizeof (tmp));
+				return sys_msgrcv (first, tmp.msgp, second, tmp.msgtyp, third);
+				}
+			case 1: default:
+				return sys_msgrcv (first, (struct msgbuf *) ptr, second, fifth, third);
+			}
+		case MSGGET:
+			return sys_msgget ((key_t) first, second);
+		case MSGCTL:
+			return sys_msgctl (first, second, (struct msqid_ds *) ptr);
+		default:
+			return -EINVAL;
+		}
+	if (call <= SHMCTL) 
+		switch (call) {
+		case SHMAT:
+			switch (version) {
+			case 0: default: {
+				ulong raddr;
+				int err;
+				if ((err = verify_area(VERIFY_WRITE, (ulong*) third, sizeof(ulong))))
+					return err;
+				err = sys_shmat (first, (char *) ptr, second, &raddr);
+				if (err)
+					return err;
+				put_user (raddr, (ulong *) third);
+				return 0;
+				}
+			case 1:	/* iBCS2 emulator entry point */
+				if (get_fs() != get_ds())
+					return -EINVAL;
+				return sys_shmat (first, (char *) ptr, second, (ulong *) third);
+			}
+		case SHMDT: 
+			return sys_shmdt ((char *)ptr);
+		case SHMGET:
+			return sys_shmget (first, second, third);
+		case SHMCTL:
+			return sys_shmctl (first, second, (struct shmid_ds *) ptr);
+		default:
+			return -EINVAL;
+		}
+	return -EINVAL;
+}
+
+asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on)
+{
+  return -ENOSYS;
+}
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/kernel/time.c linux/arch/m68k/kernel/time.c
--- v1.3.93/linux/arch/m68k/kernel/time.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/kernel/time.c	Sun Mar 17 18:12:32 1996
@@ -0,0 +1,143 @@
+/*
+ *  linux/arch/m68k/kernel/time.c
+ *
+ *  Copyright (C) 1991, 1992, 1995  Linus Torvalds
+ *
+ * This file contains the m68k-specific time handling details.
+ * Most of the stuff is located in the machine specific files.
+ */
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+
+#include <asm/machdep.h>
+#include <asm/segment.h>
+#include <asm/io.h>
+
+#include <linux/timex.h>
+
+
+static inline int set_rtc_mmss(unsigned long nowtime)
+{
+  if (mach_set_clock_mmss)
+    return mach_set_clock_mmss (nowtime);
+  return -1;
+}
+
+/*
+ * 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, struct pt_regs * regs, void *dummy)
+{
+	/* last time the cmos clock got updated */
+	static long last_rtc_update=0;
+
+	do_timer(regs);
+
+	/*
+	 * If we have an externally synchronized Linux clock, then update
+	 * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
+	 * called as close as possible to 500 ms before the new second starts.
+	 */
+	if (time_state != TIME_BAD && xtime.tv_sec > last_rtc_update + 660 &&
+	    xtime.tv_usec > 500000 - (tick >> 1) &&
+	    xtime.tv_usec < 500000 + (tick >> 1))
+	  if (set_rtc_mmss(xtime.tv_sec) == 0)
+	    last_rtc_update = xtime.tv_sec;
+	  else
+	    last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */
+}
+
+/* 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.
+ *
+ * [For the Julian calendar (which was used in Russia before 1917,
+ * Britain & colonies before 1752, anywhere else before 1582,
+ * and is still in use by some communities) leave out the
+ * -year/100+year/400 terms, and add 10.]
+ *
+ * This algorithm was first published by Gauss (I think).
+ *
+ * WARNING: this function will overflow on 2106-02-07 06:28:16 on
+ * machines were long is 32-bit! (However, as time_t is signed, we
+ * will already get problems at other places on 2038-01-19 03:14:08)
+ */
+static inline unsigned long mktime(unsigned int year, unsigned int mon,
+	unsigned int day, unsigned int hour,
+	unsigned int min, unsigned int sec)
+{
+	if (0 >= (int) (mon -= 2)) {	/* 1..12 -> 11,12,1..10 */
+		mon += 12;	/* Puts Feb last since it has leap day */
+		year -= 1;
+	}
+	return (((
+	    (unsigned long)(year/4 - year/100 + year/400 + 367*mon/12 + day) +
+	      year*365 - 719499
+	    )*24 + hour /* now have hours */
+	   )*60 + min /* now have minutes */
+	  )*60 + sec; /* finally seconds */
+}
+
+void time_init(void)
+{
+	unsigned int year, mon, day, hour, min, sec;
+
+	extern void arch_gettod(int *year, int *mon, int *day, int *hour,
+				int *min, int *sec);
+
+	arch_gettod (&year, &mon, &day, &hour, &min, &sec);
+
+	if ((year += 1900) < 1970)
+		year += 100;
+	xtime.tv_sec = mktime(year, mon, day, hour, min, sec);
+	xtime.tv_usec = 0;
+
+	mach_sched_init(timer_interrupt);
+}
+
+/*
+ * This version of gettimeofday has near microsecond resolution.
+ */
+void do_gettimeofday(struct timeval *tv)
+{
+	unsigned long flags;
+
+	save_flags(flags);
+	cli();
+	*tv = xtime;
+	tv->tv_usec += mach_gettimeoffset();
+	if (tv->tv_usec >= 1000000) {
+		tv->tv_usec -= 1000000;
+		tv->tv_sec++;
+	}
+	restore_flags(flags);
+}
+
+void do_settimeofday(struct timeval *tv)
+{
+	cli();
+	/* This is revolting. We need to set the xtime.tv_usec
+	 * correctly. However, the value in this location is
+	 * is value at the last tick.
+	 * Discover what correction gettimeofday
+	 * would have done, and then undo it!
+	 */
+	tv->tv_usec -= mach_gettimeoffset();
+
+	if (tv->tv_usec < 0) {
+		tv->tv_usec += 1000000;
+		tv->tv_sec--;
+	}
+
+	xtime = *tv;
+	time_state = TIME_BAD;
+	time_maxerror = 0x70000000;
+	time_esterror = 0x70000000;
+	sti();
+}
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/kernel/traps.c linux/arch/m68k/kernel/traps.c
--- v1.3.93/linux/arch/m68k/kernel/traps.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/kernel/traps.c	Thu Apr 18 03:01:27 1996
@@ -0,0 +1,901 @@
+/*
+ *  linux/arch/m68k/kernel/traps.c
+ *
+ *  Copyright (C) 1993, 1994 by Hamish Macdonald
+ *
+ *  68040 fixes by Michael Rausch
+ *  68040 fixes by Martin Apel
+ *  68060 fixes by Roman Hodek
+ *  68060 fixes by Jesper Skov
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file README.legal in the main directory of this archive
+ * for more details.
+ */
+
+/*
+ * Sets up all exception vectors
+ */
+
+#include <linux/config.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/types.h>
+#include <linux/a.out.h>
+#include <linux/user.h>
+#include <linux/string.h>
+#include <linux/linkage.h>
+
+#include <asm/system.h>
+#include <asm/segment.h>
+#include <asm/traps.h>
+#include <asm/bootinfo.h>
+#include <asm/pgtable.h>
+#include <asm/machdep.h>
+
+/* assembler routines */
+asmlinkage void system_call(void);
+asmlinkage void buserr(void);
+asmlinkage void trap(void);
+asmlinkage void inthandler(void);
+asmlinkage void nmihandler(void);
+
+e_vector vectors[256] = {
+	0, 0, buserr, trap, trap, trap, trap, trap,
+	trap, trap, trap, trap, trap, trap, trap, trap,
+	trap, trap, trap, trap, trap, trap, trap, trap,
+	inthandler, inthandler, inthandler, inthandler,
+	inthandler, inthandler, inthandler, inthandler,
+	/* TRAP #0-15 */
+	system_call, trap, trap, trap, trap, trap, trap, trap,
+	trap, trap, trap, trap, trap, trap, trap, trap,
+	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+};
+
+/* nmi handler for the Amiga */
+asm(".text\n"
+    __ALIGN_STR "\n"
+    SYMBOL_NAME_STR(nmihandler) ": rte");
+
+void trap_init (void)
+{
+	int i;
+
+	/* setup the exception vector table */
+	__asm__ volatile ("movec %0,%/vbr" : : "r" ((void*)vectors));
+
+	for (i = 48; i < 64; i++)
+		vectors[i] = trap;
+
+	for (i = 64; i < 256; i++)
+		vectors[i] = inthandler;
+
+        /* if running on an amiga, make the NMI interrupt do nothing */
+        if (MACH_IS_AMIGA) {
+                vectors[VEC_INT7] = nmihandler;
+        }
+
+#ifdef CONFIG_FPSP_040
+	if (m68k_is040or060 == 4) {
+		/* set up FPSP entry points */
+		asmlinkage void dz_vec(void) asm ("dz");
+		asmlinkage void inex_vec(void) asm ("inex");
+		asmlinkage void ovfl_vec(void) asm ("ovfl");
+		asmlinkage void unfl_vec(void) asm ("unfl");
+		asmlinkage void snan_vec(void) asm ("snan");
+		asmlinkage void operr_vec(void) asm ("operr");
+		asmlinkage void bsun_vec(void) asm ("bsun");
+		asmlinkage void fline_vec(void) asm ("fline");
+		asmlinkage void unsupp_vec(void) asm ("unsupp");
+
+		vectors[VEC_FPDIVZ] = dz_vec;
+		vectors[VEC_FPIR] = inex_vec;
+		vectors[VEC_FPOVER] = ovfl_vec;
+		vectors[VEC_FPUNDER] = unfl_vec;
+		vectors[VEC_FPNAN] = snan_vec;
+		vectors[VEC_FPOE] = operr_vec;
+		vectors[VEC_FPBRUC] = bsun_vec;
+		vectors[VEC_FPBRUC] = bsun_vec;
+		vectors[VEC_LINE11] = fline_vec;
+		vectors[VEC_FPUNSUP] = unsupp_vec;
+	}
+#endif
+#ifdef CONFIG_IFPSP_060
+	if (m68k_is040or060 == 6) {
+	  /* set up IFPSP entry points */
+ 	  asmlinkage void snan_vec(void) asm ("_060_fpsp_snan");
+ 	  asmlinkage void operr_vec(void) asm ("_060_fpsp_operr");
+ 	  asmlinkage void ovfl_vec(void) asm ("_060_fpsp_ovfl");
+ 	  asmlinkage void unfl_vec(void) asm ("_060_fpsp_unfl");
+ 	  asmlinkage void dz_vec(void) asm ("_060_fpsp_dz");
+ 	  asmlinkage void inex_vec(void) asm ("_060_fpsp_inex");
+ 	  asmlinkage void fline_vec(void) asm ("_060_fpsp_fline");
+ 	  asmlinkage void unsupp_vec(void) asm ("_060_fpsp_unsupp");
+ 	  asmlinkage void effadd_vec(void) asm ("_060_fpsp_effadd");
+  
+ 	  asmlinkage void unimp_vec(void) asm ("_060_isp_unimp");
+  
+ 	  vectors[VEC_FPNAN] = snan_vec;
+ 	  vectors[VEC_FPOE] = operr_vec;
+ 	  vectors[VEC_FPOVER] = ovfl_vec;
+ 	  vectors[VEC_FPUNDER] = unfl_vec;
+ 	  vectors[VEC_FPDIVZ] = dz_vec;
+ 	  vectors[VEC_FPIR] = inex_vec;
+ 	  vectors[VEC_LINE11] = fline_vec;
+ 	  vectors[VEC_FPUNSUP] = unsupp_vec;
+ 	  vectors[VEC_UNIMPEA] = effadd_vec;
+  
+ 	  /* set up ISP entry points */
+  
+ 	  vectors[VEC_UNIMPII] = unimp_vec;
+  
+  	}
+#endif
+}
+
+void set_evector(int vecnum, void (*handler)(void))
+{
+	if (vecnum >= 0 && vecnum <= 256)
+		vectors[vecnum] = handler;
+}
+
+
+static inline void console_verbose(void)
+{
+	extern int console_loglevel;
+	console_loglevel = 15;
+	mach_debug_init();
+}
+
+char *vec_names[] = {
+	"RESET SP", "RESET PC", "BUS ERROR", "ADDRESS ERROR",
+	"ILLEGAL INSTRUCTION", "ZERO DIVIDE", "CHK", "TRAPcc",
+	"PRIVILEGE VIOLATION", "TRACE", "LINE 1010", "LINE 1111",
+	"UNASSIGNED RESERVED 12", "COPROCESSOR PROTOCOL VIOLATION",
+	"FORMAT ERROR", "UNINITIALIZED INTERRUPT",
+	"UNASSIGNED RESERVED 16", "UNASSIGNED RESERVED 17",
+	"UNASSIGNED RESERVED 18", "UNASSIGNED RESERVED 19",
+	"UNASSIGNED RESERVED 20", "UNASSIGNED RESERVED 21",
+	"UNASSIGNED RESERVED 22", "UNASSIGNED RESERVED 23",
+	"SPURIOUS INTERRUPT", "LEVEL 1 INT", "LEVEL 2 INT", "LEVEL 3 INT",
+	"LEVEL 4 INT", "LEVEL 5 INT", "LEVEL 6 INT", "LEVEL 7 INT",
+	"SYSCALL", "TRAP #1", "TRAP #2", "TRAP #3",
+	"TRAP #4", "TRAP #5", "TRAP #6", "TRAP #7",
+	"TRAP #8", "TRAP #9", "TRAP #10", "TRAP #11",
+	"TRAP #12", "TRAP #13", "TRAP #14", "TRAP #15"
+	};
+
+char *space_names[] = {
+	"Space 0", "User Data", "User Program", "Space 3",
+	"Space 4", "Super Data", "Super Program", "CPU"
+	};
+
+
+
+extern void die_if_kernel(char *,struct pt_regs *,int);
+asmlinkage int do_page_fault(struct pt_regs *regs, unsigned long address,
+			      unsigned long error_code);
+
+asmlinkage void trap_c(struct frame *fp);
+
+static inline void access_error060 (struct frame *fp)
+{
+	unsigned long fslw = fp->un.fmt4.pc; /* is really FSLW for access error */
+
+#ifdef DEBUG
+	printk("fslw=%#lx, fa=%#lx\n", ssw, fp->un.fmt4.effaddr);
+#endif
+
+	if (fslw & MMU060_BPE) {
+		/* branch prediction error -> clear branch cache */
+		__asm__ __volatile__ ("movec %/cacr,%/d0\n\t"
+				      "orl   #0x00400000,%/d0\n\t"
+				      "movec %/d0,%/cacr"
+				      : : : "d0" );
+		/* return if there's no other error */
+		if (!(fslw & MMU060_ERR_BITS))
+			return;
+	}
+	
+	if (fslw & (MMU060_DESC_ERR | MMU060_WP)) {
+		unsigned long errorcode;
+		unsigned long addr = fp->un.fmt4.effaddr;
+		errorcode = ((fslw & MMU060_WP) ? 1 : 0) |
+					((fslw & MMU060_W)  ? 2 : 0);
+#ifdef DEBUG
+		printk("errorcode = %d\n", errorcode );
+#endif
+		if (fslw & MMU060_MA)
+		  addr = PAGE_ALIGN(addr);
+		do_page_fault( (struct pt_regs *)fp, addr, errorcode );
+	}
+	else {
+		printk( "68060 access error, fslw=%lx\n", fslw );
+		trap_c( fp );
+	}
+}
+
+static unsigned long probe040 (int iswrite, int fc, unsigned long addr)
+{
+	unsigned long mmusr;
+	unsigned long fs = get_fs();
+
+	set_fs (fc);
+
+  	if (iswrite)
+  		/* write */
+		asm volatile ("movel %1,%/a0\n\t"
+			      ".word 0xf548\n\t"	/* ptestw (a0) */
+			      ".long 0x4e7a8805\n\t"	/* movec mmusr,a0 */
+			      "movel %/a0,%0"
+			      : "=g" (mmusr)
+			      : "g" (addr)
+			      : "a0");
+	else
+		asm volatile ("movel %1,%/a0\n\t"
+			      ".word 0xf568\n\t"	/* ptestr (a0) */
+			      ".long 0x4e7a8805\n\t"	/* movec mmusr,a0 */
+			      "movel %/a0,%0"
+			      : "=g" (mmusr)
+			      : "g" (addr)
+			      : "a0");
+
+
+	set_fs (fs);
+
+	return mmusr;
+}
+
+static void do_040writeback (unsigned short ssw,
+			     unsigned short wbs,
+			     unsigned long wba,
+			     unsigned long wbd,
+			     struct frame *fp)
+{
+	unsigned long fs = get_fs ();
+	unsigned long mmusr;
+	unsigned long errorcode;
+
+	/*
+	 * No special handling for the second writeback anymore.
+	 * It misinterpreted the misaligned status sometimes.
+	 * This way an extra pgae-fault may be caused (Martin Apel).
+	 */
+
+	mmusr = probe040 (1, wbs & WBTM_040,  wba);
+	errorcode = (mmusr & MMU_R_040) ? 3 : 2;
+	if (do_page_fault ((struct pt_regs *)fp, wba, errorcode))
+	  /* just return if we can't perform the writeback */
+	  return;
+
+	set_fs (wbs & WBTM_040);
+	switch (wbs & WBSIZ_040) {
+	    case BA_SIZE_BYTE:
+		put_fs_byte (wbd & 0xff, (char *)wba);
+		break;
+	    case BA_SIZE_WORD:
+		put_fs_word (wbd & 0xffff, (short *)wba);
+		break;
+	    case BA_SIZE_LONG:
+		put_fs_long (wbd, (int *)wba);
+		break;
+	}
+	set_fs (fs);
+}
+
+static inline void access_error040 (struct frame *fp)
+{
+	unsigned short ssw = fp->un.fmt7.ssw;
+	unsigned long mmusr;
+
+#ifdef DEBUG
+	printk("ssw=%#x, fa=%#lx\n", ssw, fp->un.fmt7.faddr);
+        printk("wb1s=%#x, wb2s=%#x, wb3s=%#x\n", fp->un.fmt7.wb1s,  
+		fp->un.fmt7.wb2s, fp->un.fmt7.wb3s);
+	printk ("wb2a=%lx, wb3a=%lx, wb2d=%lx, wb3d=%lx\n", 
+		fp->un.fmt7.wb2a, fp->un.fmt7.wb3a,
+		fp->un.fmt7.wb2d, fp->un.fmt7.wb3d);
+#endif
+
+
+	if (ssw & ATC_040) {
+		unsigned long addr = fp->un.fmt7.faddr;
+		unsigned long errorcode;
+
+		/*
+		 * The MMU status has to be determined AFTER the address
+		 * has been corrected if there was a misaligned access (MA).
+		 */
+		if (ssw & MA_040)
+			addr = PAGE_ALIGN (addr);
+
+		/* MMU error, get the MMUSR info for this access */
+		mmusr = probe040 (!(ssw & RW_040), ssw & TM_040, addr);
+		/*
+#ifdef DEBUG
+		printk("mmusr = %lx\n", mmusr);
+#endif
+*/
+		errorcode = ((mmusr & MMU_R_040) ? 1 : 0) |
+			((ssw & RW_040) ? 0 : 2);
+		do_page_fault ((struct pt_regs *)fp, addr, errorcode);
+	} else {
+		printk ("68040 access error, ssw=%x\n", ssw);
+		trap_c (fp);
+	}
+
+#if 0
+	if (fp->un.fmt7.wb1s & WBV_040)
+		printk("access_error040: cannot handle 1st writeback. oops.\n");
+#endif
+
+/*
+ *  We may have to do a couple of writebacks here.
+ *
+ *  MR: we can speed up the thing a little bit and let do_040writeback()
+ *  not produce another page fault as wb2 corresponds to the address that
+ *  caused the fault. on write faults no second fault is generated, but
+ *  on read faults for security reasons (although per definitionem impossible)
+ */
+
+	if (fp->un.fmt7.wb2s & WBV_040 && (fp->un.fmt7.wb2s &
+					   WBTT_040) != BA_TT_MOVE16)
+		do_040writeback (ssw,
+				 fp->un.fmt7.wb2s, fp->un.fmt7.wb2a,
+				 fp->un.fmt7.wb2d, fp);
+
+	if (fp->un.fmt7.wb3s & WBV_040)
+		do_040writeback (ssw, fp->un.fmt7.wb3s,
+				 fp->un.fmt7.wb3a, fp->un.fmt7.wb3d,
+				 fp);
+}
+
+static inline void bus_error030 (struct frame *fp)
+{
+	volatile unsigned short temp;
+	unsigned short mmusr;
+	unsigned long addr, desc, errorcode;
+	unsigned short ssw = fp->un.fmtb.ssw;
+	int user_space_fault = 1;
+
+#if DEBUG
+	printk ("pid = %x  ", current->pid);
+	printk ("SSW=%#06x  ", ssw);
+
+	if (ssw & (FC | FB))
+		printk ("Instruction fault at %#010lx\n",
+			ssw & FC ?
+			fp->ptregs.format == 0xa ? fp->ptregs.pc + 2 : fp->un.fmtb.baddr - 2
+			:
+			fp->ptregs.format == 0xa ? fp->ptregs.pc + 4 : fp->un.fmtb.baddr);
+	if (ssw & DF)
+		printk ("Data %s fault at %#010lx in %s (pc=%#lx)\n",
+			ssw & RW ? "read" : "write",
+			fp->un.fmtb.daddr,
+			space_names[ssw & DFC], fp->ptregs.pc);
+#endif
+
+	if (fp->ptregs.sr & PS_S) {
+		/* kernel fault must be a data fault to user space */
+		if (! ((ssw & DF) && ((ssw & DFC) == USER_DATA))) {
+			/* instruction fault or kernel data fault! */
+			if (ssw & (FC | FB))
+				printk ("Instruction fault at %#010lx\n",
+					fp->ptregs.pc);
+			if (ssw & DF) {
+				printk ("Data %s fault at %#010lx in %s (pc=%#lx)\n",
+					ssw & RW ? "read" : "write",
+					fp->un.fmtb.daddr,
+					space_names[ssw & DFC], fp->ptregs.pc);
+			}
+			printk ("BAD KERNEL BUSERR\n");
+			die_if_kernel("Oops",&fp->ptregs,0);
+			send_sig(SIGSEGV, current, 1);
+			user_space_fault = 0;
+		}
+	} else {
+		/* user fault */
+		if (!(ssw & (FC | FB)) && !(ssw & DF))
+			/* not an instruction fault or data fault! BAD */
+			panic ("USER BUSERR w/o instruction or data fault");
+		user_space_fault = 1;
+#if DEBUG
+		printk("User space bus-error\n");
+#endif
+	}
+
+	/* ++andreas: If a data fault and an instruction fault happen
+	   at the same time map in both pages.  */
+
+	/* First handle the data fault, if any.  */
+	if (ssw & DF)
+	  {
+	    addr = fp->un.fmtb.daddr;
+
+	    if (user_space_fault) {
+		    asm volatile ("ptestr #1,%2@,#7,%0\n\t"
+				  "pmove %/psr,%1@"
+				  : "=a&" (desc)
+				  : "a" (&temp), "a" (addr));
+		    mmusr = temp;
+	    } else
+		    mmusr = MMU_I;
+      
+#if DEBUG
+	    printk ("mmusr is %#x for addr %#lx in task %p\n",
+		    mmusr, addr, current);
+	    printk ("descriptor address is %#lx, contents %#lx\n",
+		    mm_ptov(desc), *(unsigned long *)mm_ptov(desc));
+#endif
+
+	    errorcode = (mmusr & MMU_I) ? 0 : 1;
+	      /* if (!(ssw & RW)) updated to 1.2.13pl6 */
+ 	    if (!(ssw & RW) || ssw & RM)
+		    errorcode |= 2;
+
+	    if (mmusr & MMU_I)
+		    do_page_fault ((struct pt_regs *)fp, addr, errorcode);
+
+	    /* else if ((mmusr & MMU_WP) && !(ssw & RW)) */
+
+ 	    else if ((mmusr & MMU_WP) && (!(ssw & RW) || ssw & RM))
+		    do_page_fault ((struct pt_regs *)fp, addr, errorcode);
+	    else if (mmusr & (MMU_B|MMU_L|MMU_S)) {
+		    printk ("invalid %s access at %#lx from pc %#lx\n",
+			    !(ssw & RW) ? "write" : "read", addr,
+			    fp->ptregs.pc);
+		    die_if_kernel("Oops",&fp->ptregs,mmusr);
+		    send_sig(SIGSEGV, current, 1);
+		    return;
+	    } else {
+#ifdef DEBUG
+		    static volatile long tlong;
+#endif
+
+		    printk ("weird %s access at %#lx from pc %#lx (ssw is %#x)\n",
+			    !(ssw & RW) ? "write" : "read", addr,
+			    fp->ptregs.pc, ssw);
+		    asm volatile ("ptestr #1,%1@,#0\n\t"
+				  "pmove %/psr,%0@"
+				  : /* no outputs */
+				  : "a" (&temp), "a" (addr));
+		    mmusr = temp;
+
+		    printk ("level 0 mmusr is %#x\n", mmusr);
+#if 0
+		    asm volatile ("pmove %/tt0,%0@"
+				  : /* no outputs */
+				  : "a" (&tlong));
+		    printk ("tt0 is %#lx, ", tlong);
+		    asm volatile ("pmove %/tt1,%0@"
+				  : /* no outputs */
+				  : "a" (&tlong));
+		    printk ("tt1 is %#lx\n", tlong);
+#endif
+#if DEBUG
+		    printk("Unknown SIGSEGV - 1\n");
+#endif
+		    die_if_kernel("Oops",&fp->ptregs,mmusr);
+		    send_sig(SIGSEGV, current, 1);
+		    return;
+	    }
+
+	    /* setup an ATC entry for the access about to be retried */
+	    if (!(ssw & RW))
+		    asm volatile ("ploadw #1,%0@" : /* no outputs */
+				  : "a" (addr));
+	    else
+		    asm volatile ("ploadr #1,%0@" : /* no outputs */
+				  : "a" (addr));
+
+	    /* If this was a data fault due to an invalid page and a
+	       prefetch is pending on the same page, simulate it (but
+	       only if the page is now valid).  Otherwise we'll get an
+	       weird insn access.  */
+	    if ((ssw & RB) && (mmusr & MMU_I))
+	      {
+		unsigned long iaddr;
+
+		if ((fp->ptregs.format) == 0xB)
+		  iaddr = fp->un.fmtb.baddr;
+		else
+		  iaddr = fp->ptregs.pc + 4;
+		if (((addr ^ iaddr) & PAGE_MASK) == 0)
+		  {
+		    /* We only need to check the ATC as the entry has
+		       already been set up above.  */
+		    asm volatile ("ptestr #1,%1@,#0\n\t"
+				  "pmove %/psr,%0@"
+				  : : "a" (&temp), "a" (iaddr));
+		    mmusr = temp;
+#ifdef DEBUG
+		    printk ("prefetch iaddr=%#lx ssw=%#x mmusr=%#x\n",
+			    iaddr, ssw, mmusr);
+#endif
+		    if (!(mmusr & MMU_I))
+		      {
+			unsigned short insn;
+			asm volatile ("movesw %1@,%0"
+				      : "=r" (insn)
+				      : "a" (iaddr));
+			fp->un.fmtb.isb = insn;
+			fp->un.fmtb.ssw &= ~RB;
+		      }
+		  }
+	      }
+	  }
+
+	/* Now handle the instruction fault. */
+
+	/* get the fault address */
+	if ((fp->ptregs.format) == 0xA )
+		if (ssw & FC)
+			addr = fp->ptregs.pc + 2;
+		else if (ssw & FB)
+			addr = fp->ptregs.pc + 4;
+		else
+			return;
+	else
+		if (ssw & FC)
+			addr = fp->un.fmtb.baddr - 2;
+		else if (ssw & FB)
+			addr = fp->un.fmtb.baddr;
+		else
+			return;
+
+	if ((ssw & DF) && ((addr ^ fp->un.fmtb.daddr) & PAGE_MASK) == 0)
+		/* Insn fault on same page as data fault */
+		return;
+
+	if (user_space_fault) {
+		asm volatile ("ptestr #1,%2@,#7,%0\n\t"
+			      "pmove %/psr,%1@"
+			      : "=a&" (desc)
+			      : "a" (&temp), "a" (addr));
+		mmusr = temp;
+	} else
+		mmusr = MMU_I;
+      
+#ifdef DEBUG
+	printk ("mmusr is %#x for addr %#lx in task %p\n",
+		mmusr, addr, current);
+	printk ("descriptor address is %#lx, contents %#lx\n",
+		mm_ptov(desc), *(unsigned long *)mm_ptov(desc));
+#endif
+
+	errorcode = (mmusr & MMU_I) ? 0 : 1;
+
+	if (mmusr & MMU_I)
+		do_page_fault ((struct pt_regs *)fp, addr, errorcode);
+	else if (mmusr & (MMU_B|MMU_L|MMU_S)) {
+		printk ("invalid insn access at %#lx from pc %#lx\n",
+			addr, fp->ptregs.pc);
+#if DEBUG
+		printk("Unknown SIGSEGV - 2\n");
+#endif
+		die_if_kernel("Oops",&fp->ptregs,mmusr);
+		send_sig(SIGSEGV, current, 1);
+		return;
+	} else {
+#ifdef DEBUG
+		static volatile long tlong;
+#endif
+
+		printk ("weird insn access at %#lx from pc %#lx (ssw is %#x)\n",
+			addr, fp->ptregs.pc, ssw);
+		asm volatile ("ptestr #1,%1@,#0\n\t"
+			      "pmove %/psr,%0@"
+			      : /* no outputs */
+			      : "a" (&temp), "a" (addr));
+		mmusr = temp;
+		      
+		printk ("level 0 mmusr is %#x\n", mmusr);
+#ifdef DEBUG
+		if (boot_info.cputype & CPU_68030) {
+			asm volatile ("pmove %/tt0,%0@"
+				      : /* no outputs */
+				      : "a" (&tlong));
+			printk ("tt0 is %#lx, ", tlong);
+			asm volatile ("pmove %/tt1,%0@"
+				      : /* no outputs */
+				      : "a" (&tlong));
+			printk ("tt1 is %#lx\n", tlong);
+		}
+
+#endif
+#if DEBUG
+		printk("Unknown SIGSEGV - 3\n");
+#endif
+		die_if_kernel("Oops",&fp->ptregs,mmusr);
+		send_sig(SIGSEGV, current, 1);
+		return;
+	}
+
+	/* setup an ATC entry for the access about to be retried */
+	asm volatile ("ploadr #1,%0@" : /* no outputs */
+		      : "a" (addr));
+}
+
+asmlinkage void buserr_c(struct frame *fp)
+{
+	/* Only set esp0 if coming from user mode */
+	if (user_mode(&fp->ptregs))
+		current->tss.esp0 = (unsigned long) fp;
+
+#if DEBUG
+	printk ("*** Bus Error *** Format is %x\n", fp->ptregs.format);
+#endif
+
+	switch (fp->ptregs.format) {
+	case 4:				/* 68060 access error */
+	  access_error060 (fp);
+	  break;
+	case 0x7:			/* 68040 access error */
+	  access_error040 (fp);
+	  break;
+	case 0xa:
+	case 0xb:
+	  bus_error030 (fp);
+	  break;
+	default:
+	  die_if_kernel("bad frame format",&fp->ptregs,0);
+#if DEBUG
+	  printk("Unknown SIGSEGV - 4\n");
+#endif
+	  send_sig(SIGSEGV, current, 1);
+	}
+}
+
+
+int kstack_depth_to_print = 48;
+
+/* MODULE_RANGE is a guess of how much space is likely to be
+   vmalloced.  */
+#define MODULE_RANGE (8*1024*1024)
+
+static void dump_stack(struct frame *fp)
+{
+	unsigned long *stack, *endstack, addr, module_start, module_end;
+	extern char _start, _etext;
+	int i;
+
+	addr = (unsigned long)&fp->un;
+	printk("Frame format=%X ", fp->ptregs.format);
+	switch (fp->ptregs.format) {
+	case 0x2:
+	    printk("instr addr=%08lx\n", fp->un.fmt2.iaddr);
+	    addr += sizeof(fp->un.fmt2);
+	    break;
+	case 0x3:
+	    printk("eff addr=%08lx\n", fp->un.fmt3.effaddr);
+	    addr += sizeof(fp->un.fmt3);
+	    break;
+	case 0x4:
+	    printk((m68k_is040or060 == 6 ? "fault addr=%08lx fslw=%08lx\n"
+		    : "eff addr=%08lx pc=%08lx\n"),
+		   fp->un.fmt4.effaddr, fp->un.fmt4.pc);
+	    addr += sizeof(fp->un.fmt4);
+	    break;
+	case 0x7:
+	    printk("eff addr=%08lx ssw=%04x faddr=%08lx\n",
+		   fp->un.fmt7.effaddr, fp->un.fmt7.ssw, fp->un.fmt7.faddr);
+	    printk("wb 1 stat/addr/data: %04x %08lx %08lx\n",
+		   fp->un.fmt7.wb1s, fp->un.fmt7.wb1a, fp->un.fmt7.wb1dpd0);
+	    printk("wb 2 stat/addr/data: %04x %08lx %08lx\n",
+		   fp->un.fmt7.wb2s, fp->un.fmt7.wb2a, fp->un.fmt7.wb2d);
+	    printk("wb 3 stat/addr/data: %04x %08lx %08lx\n",
+		   fp->un.fmt7.wb3s, fp->un.fmt7.wb3a, fp->un.fmt7.wb3d);
+	    printk("push data: %08lx %08lx %08lx %08lx\n",
+		   fp->un.fmt7.wb1dpd0, fp->un.fmt7.pd1, fp->un.fmt7.pd2,
+		   fp->un.fmt7.pd3);
+	    addr += sizeof(fp->un.fmt7);
+	    break;
+	case 0x9:
+	    printk("instr addr=%08lx\n", fp->un.fmt9.iaddr);
+	    addr += sizeof(fp->un.fmt9);
+	    break;
+	case 0xa:
+	    printk("ssw=%04x isc=%04x isb=%04x daddr=%08lx dobuf=%08lx\n",
+		   fp->un.fmta.ssw, fp->un.fmta.isc, fp->un.fmta.isb,
+		   fp->un.fmta.daddr, fp->un.fmta.dobuf);
+	    addr += sizeof(fp->un.fmta);
+	    break;
+	case 0xb:
+	    printk("ssw=%04x isc=%04x isb=%04x daddr=%08lx dobuf=%08lx\n",
+		   fp->un.fmtb.ssw, fp->un.fmtb.isc, fp->un.fmtb.isb,
+		   fp->un.fmtb.daddr, fp->un.fmtb.dobuf);
+	    printk("baddr=%08lx dibuf=%08lx ver=%x\n",
+		   fp->un.fmtb.baddr, fp->un.fmtb.dibuf, fp->un.fmtb.ver);
+	    addr += sizeof(fp->un.fmtb);
+	    break;
+	default:
+	    printk("\n");
+	}
+
+	stack = (unsigned long *)addr;
+	endstack = (unsigned long *)PAGE_ALIGN(addr);
+
+	printk("Stack from %08lx:\n       ", (unsigned long)stack);
+	for (i = 0; i < kstack_depth_to_print; i++) {
+		if (stack + 1 > endstack)
+			break;
+		if (i && ((i % 8) == 0))
+			printk("\n       ");
+		printk("%08lx ", *stack++);
+	}
+
+	printk ("\nCall Trace: ");
+	stack = (unsigned long *) addr;
+	i = 1;
+	module_start = VMALLOC_START;
+	module_end = module_start + MODULE_RANGE;
+	while (stack + 1 <= endstack) {
+		addr = *stack++;
+		/*
+		 * If the address is either in the text segment of the
+		 * kernel, or in the region which contains vmalloc'ed
+		 * memory, it *may* be the address of a calling
+		 * routine; if so, print it so that someone tracing
+		 * down the cause of the crash will be able to figure
+		 * out the call path that was taken.
+		 */
+		if (((addr >= (unsigned long) &_start) &&
+		     (addr <= (unsigned long) &_etext)) ||
+		    ((addr >= module_start) && (addr <= module_end))) {
+			if (i && ((i % 8) == 0))
+				printk("\n       ");
+			printk("[<%08lx>] ", addr);
+			i++;
+		}
+	}
+	printk("\nCode: ");
+	for (i = 0; i < 10; i++)
+		printk("%04x ", 0xffff & ((short *) fp->ptregs.pc)[i]);
+	printk ("\n");
+}
+
+void bad_super_trap (struct frame *fp)
+{
+	console_verbose();
+	if ((fp->ptregs.vector) < 48*4)
+		printk ("*** %s ***   FORMAT=%X\n",
+			vec_names[(fp->ptregs.vector) >> 2],
+			fp->ptregs.format);
+	else
+		printk ("*** Exception %d ***   FORMAT=%X\n",
+			(fp->ptregs.vector) >> 2, 
+			fp->ptregs.format);
+	if (((fp->ptregs.vector) >> 2) == VEC_ADDRERR
+	    && !m68k_is040or060) {
+		unsigned short ssw = fp->un.fmtb.ssw;
+
+		printk ("SSW=%#06x  ", ssw);
+
+		if (ssw & RC)
+			printk ("Pipe stage C instruction fault at %#010lx\n",
+				(fp->ptregs.format) == 0xA ?
+				fp->ptregs.pc + 2 : fp->un.fmtb.baddr - 2);
+		if (ssw & RB)
+			printk ("Pipe stage B instruction fault at %#010lx\n",
+				(fp->ptregs.format) == 0xA ?
+				fp->ptregs.pc + 4 : fp->un.fmtb.baddr);
+		if (ssw & DF)
+			printk ("Data %s fault at %#010lx in %s (pc=%#lx)\n",
+				ssw & RW ? "read" : "write",
+				fp->un.fmtb.daddr, space_names[ssw & DFC],
+				fp->ptregs.pc);
+	}
+	printk ("Current process id is %d\n", current->pid);
+	die_if_kernel("BAD KERNEL TRAP", &fp->ptregs, 0);
+}
+
+asmlinkage void trap_c(struct frame *fp)
+{
+	int sig;
+
+	if ((fp->ptregs.sr & PS_S)
+	    && ((fp->ptregs.vector) >> 2) == VEC_TRACE
+	    && !(fp->ptregs.sr & PS_T)) {
+		/* traced a trapping instruction */
+		unsigned char *lp = ((unsigned char *)&fp->un.fmt2) + 4;
+		current->flags |= PF_DTRACE;
+		/* clear the trace bit */
+		(*(unsigned short *)lp) &= ~PS_T;
+		return;
+	} else if (fp->ptregs.sr & PS_S) {
+		bad_super_trap(fp);
+		return;
+	}
+
+	/* send the appropriate signal to the user program */
+	switch ((fp->ptregs.vector) >> 2) {
+	    case VEC_ADDRERR:
+		sig = SIGBUS;
+		break;
+	    case VEC_BUSERR:
+		sig = SIGSEGV;
+		break;
+	    case VEC_ILLEGAL:
+	    case VEC_PRIV:
+	    case VEC_LINE10:
+	    case VEC_LINE11:
+	    case VEC_COPROC:
+	    case VEC_TRAP1:
+	    case VEC_TRAP2:
+	    case VEC_TRAP3:
+	    case VEC_TRAP4:
+	    case VEC_TRAP5:
+	    case VEC_TRAP6:
+	    case VEC_TRAP7:
+	    case VEC_TRAP8:
+	    case VEC_TRAP9:
+	    case VEC_TRAP10:
+	    case VEC_TRAP11:
+	    case VEC_TRAP12:
+	    case VEC_TRAP13:
+	    case VEC_TRAP14:
+		sig = SIGILL;
+		break;
+	    case VEC_FPBRUC:
+	    case VEC_FPIR:
+	    case VEC_FPDIVZ:
+	    case VEC_FPUNDER:
+	    case VEC_FPOE:
+	    case VEC_FPOVER:
+	    case VEC_FPNAN:
+		{
+		  unsigned char fstate[216];
+
+		  __asm__ __volatile__ ("fsave %0@" : : "a" (fstate) : "memory");
+		  /* Set the exception pending bit in the 68882 idle frame */
+		  if (*(unsigned short *) fstate == 0x1f38)
+		    {
+		      fstate[fstate[1]] |= 1 << 3;
+		      __asm__ __volatile__ ("frestore %0@" : : "a" (fstate));
+		    }
+		}
+		/* fall through */
+	    case VEC_ZERODIV:
+	    case VEC_TRAP:
+		sig = SIGFPE;
+		break;
+	    case VEC_TRACE:		/* ptrace single step */
+		fp->ptregs.sr &= ~PS_T;
+	    case VEC_TRAP15:		/* breakpoint */
+		sig = SIGTRAP;
+		break;
+	    default:
+		sig = SIGILL;
+		break;
+	}
+
+	send_sig (sig, current, 1);
+}
+
+asmlinkage void set_esp0 (unsigned long ssp)
+{
+  current->tss.esp0 = ssp;
+}
+
+void die_if_kernel (char *str, struct pt_regs *fp, int nr)
+{
+	if (!(fp->sr & PS_S))
+		return;
+
+	console_verbose();
+	printk("%s: %08x\n",str,nr);
+	printk("PC: %08lx\nSR: %04x  SP: %p\n", fp->pc, fp->sr, fp);
+	printk("d0: %08lx    d1: %08lx    d2: %08lx    d3: %08lx\n",
+	       fp->d0, fp->d1, fp->d2, fp->d3);
+	printk("d4: %08lx    d5: %08lx    a0: %08lx    a1: %08lx\n",
+	       fp->d4, fp->d5, fp->a0, fp->a1);
+
+	if (STACK_MAGIC != *(unsigned long *)current->kernel_stack_page)
+		printk("Corrupted stack page\n");
+	printk("Process %s (pid: %d, stackpage=%08lx)\n",
+		current->comm, current->pid, current->kernel_stack_page);
+	dump_stack((struct frame *)fp);
+	do_exit(SIGSEGV);
+}
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/lib/Makefile linux/arch/m68k/lib/Makefile
--- v1.3.93/linux/arch/m68k/lib/Makefile	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/lib/Makefile	Mon Apr  1 21:37:48 1996
@@ -0,0 +1,8 @@
+#
+# Makefile for m68k-specific library files..
+#
+
+L_TARGET = lib.a
+L_OBJS  = ashrdi3.o checksum.o memcpy.o memcmp.o
+
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/lib/ashrdi3.c linux/arch/m68k/lib/ashrdi3.c
--- v1.3.93/linux/arch/m68k/lib/ashrdi3.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/lib/ashrdi3.c	Mon Apr  1 21:37:48 1996
@@ -0,0 +1,63 @@
+/* ashrdi3.c extracted from gcc-2.7.2/libgcc2.c which is: */
+/* Copyright (C) 1989, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING.  If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
+
+#define BITS_PER_UNIT 8
+
+typedef 	 int SItype	__attribute__ ((mode (SI)));
+typedef unsigned int USItype	__attribute__ ((mode (SI)));
+typedef		 int DItype	__attribute__ ((mode (DI)));
+typedef int word_type __attribute__ ((mode (__word__)));
+
+struct DIstruct {SItype high, low;};
+
+typedef union
+{
+  struct DIstruct s;
+  DItype ll;
+} DIunion;
+
+DItype
+__ashrdi3 (DItype u, word_type b)
+{
+  DIunion w;
+  word_type bm;
+  DIunion uu;
+
+  if (b == 0)
+    return u;
+
+  uu.ll = u;
+
+  bm = (sizeof (SItype) * BITS_PER_UNIT) - b;
+  if (bm <= 0)
+    {
+      /* w.s.high = 1..1 or 0..0 */
+      w.s.high = uu.s.high >> (sizeof (SItype) * BITS_PER_UNIT - 1);
+      w.s.low = uu.s.high >> -bm;
+    }
+  else
+    {
+      USItype carries = (USItype)uu.s.high << bm;
+      w.s.high = uu.s.high >> b;
+      w.s.low = ((USItype)uu.s.low >> b) | carries;
+    }
+
+  return w.ll;
+}
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/lib/checksum.c linux/arch/m68k/lib/checksum.c
--- v1.3.93/linux/arch/m68k/lib/checksum.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/lib/checksum.c	Sat Apr  6 01:40:19 1996
@@ -0,0 +1,323 @@
+/*
+ * INET		An implementation of the TCP/IP protocol suite for the LINUX
+ *		operating system.  INET is implemented using the  BSD Socket
+ *		interface as the means of communication with the user level.
+ *
+ *		IP/TCP/UDP checksumming routines
+ *
+ * Authors:	Jorge Cwik, <jorge@laser.satlink.net>
+ *		Arnt Gulbrandsen, <agulbra@nvg.unit.no>
+ *		Tom May, <ftom@netcom.com>
+ *		Andreas Schwab, <schwab@issan.informatik.uni-dortmund.de>
+ *		Lots of code moved from tcp.c and ip.c; see those files
+ *		for more names.
+ *
+ * 03/02/96	Jes Sorensen, Andreas Schwab, Roman Hodek:
+ *		Fixed some nasty bugs, causing some horrible crashes.
+ *		A: At some points, the sum (%0) was used as
+ *		length-counter instead of the length counter
+ *		(%1). Thanks to Roman Hodek for pointing this out.
+ *		B: GCC seems to mess up if one uses too many
+ *		data-registers to hold input values and one tries to
+ *		specify d0 and d1 as scratch registers. Letting gcc choose these
+ *      registers itself solves the problem.
+ *
+ *		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 <net/checksum.h>
+
+/*
+ * computes a partial checksum, e.g. for TCP/UDP fragments
+ */
+
+unsigned int
+csum_partial (const unsigned char *buff, int len, unsigned int sum)
+{
+	unsigned long tmp1, tmp2;
+	  /*
+	   * Experiments with ethernet and slip connections show that buff
+	   * is aligned on either a 2-byte or 4-byte boundary.
+	   */
+	__asm__("movel %2,%3\n\t"
+		"btst #1,%3\n\t"	/* Check alignment */
+		"jeq 2f\n\t"
+		"subql #2,%1\n\t"	/* buff%4==2: treat first word */
+		"jgt 1f\n\t"
+		"addql #2,%1\n\t"	/* len was == 2, treat only rest */
+		"jra 4f\n"
+	     "1:\t"
+		"addw %2@+,%0\n\t"	/* add first word to sum */
+		"clrl %3\n\t"
+		"addxl %3,%0\n"		/* add X bit */
+	     "2:\t"
+		/* unrolled loop for the main part: do 8 longs at once */
+		"movel %1,%3\n\t"	/* save len in tmp1 */
+		"lsrl #5,%1\n\t"	/* len/32 */
+		"jeq 2f\n\t"		/* not enough... */
+		"subql #1,%1\n"
+	     "1:\t"
+		"movel %2@+,%4\n\t"
+		"addxl %4,%0\n\t"
+		"movel %2@+,%4\n\t"
+		"addxl %4,%0\n\t"
+		"movel %2@+,%4\n\t"
+		"addxl %4,%0\n\t"
+		"movel %2@+,%4\n\t"
+		"addxl %4,%0\n\t"
+		"movel %2@+,%4\n\t"
+		"addxl %4,%0\n\t"
+		"movel %2@+,%4\n\t"
+		"addxl %4,%0\n\t"
+		"movel %2@+,%4\n\t"
+		"addxl %4,%0\n\t"
+		"movel %2@+,%4\n\t"
+		"addxl %4,%0\n\t"
+		"dbra %1,1b\n\t"
+		"clrl %4\n\t"
+		"addxl %4,%0\n\t"	/* add X bit */
+		"clrw %1\n\t"
+		"subql #1,%1\n\t"
+		"jcc 1b\n"
+	     "2:\t"
+		"movel %3,%1\n\t"	/* restore len from tmp1 */
+		"andw #0x1c,%3\n\t"	/* number of rest longs */
+		"jeq 4f\n\t"
+		"lsrw #2,%3\n\t"
+		"subqw #1,%3\n"
+	     "3:\t"
+		/* loop for rest longs */
+		"movel %2@+,%4\n\t"
+		"addxl %4,%0\n\t"
+		"dbra %3,3b\n\t"
+		"clrl %4\n\t"
+		"addxl %4,%0\n"		/* add X bit */
+	     "4:\t"
+		/* now check for rest bytes that do not fit into longs */
+		"andw #3,%1\n\t"
+		"jeq 7f\n\t"
+		"clrl %4\n\t"		/* clear tmp2 for rest bytes */
+		"subqw #2,%1\n\t"
+		"jlt 5f\n\t"
+		"movew %2@+,%4\n\t"	/* have rest >= 2: get word */
+		"swap %4\n\t"		/* into bits 16..31 */
+		"tstw %1\n\t"		/* another byte? */
+		"jeq 6f\n"
+	     "5:\t"
+		"moveb %2@,%4\n\t"	/* have odd rest: get byte */
+		"lslw #8,%4\n\t"	/* into bits 8..15; 16..31 untouched */
+	     "6:\t"
+		"addl %4,%0\n\t"	/* now add rest long to sum */
+		"clrl %4\n\t"
+		"addxl %4,%0\n"		/* add X bit */
+	     "7:\t"
+		: "=d" (sum), "=d" (len), "=a" (buff),
+		  "=&d" (tmp1), "=&d" (tmp2)
+		: "0" (sum), "1" (len), "2" (buff)
+	    );
+	return(sum);
+}
+
+
+
+/*
+ * copy from fs while checksumming, otherwise like csum_partial
+ */
+
+unsigned int
+csum_partial_copy_fromuser(const char *src, char *dst, int len, int sum)
+{
+	unsigned long tmp1, tmp2;
+	__asm__("movel %2,%4\n\t"
+		"btst #1,%4\n\t"	/* Check alignment */
+		"jeq 2f\n\t"
+		"subql #2,%1\n\t"	/* buff%4==2: treat first word */
+		"jgt 1f\n\t"
+		"addql #2,%1\n\t"	/* len was == 2, treat only rest */
+		"jra 4f\n"
+	     "1:\t"
+		"movesw %2@+,%4\n\t"	/* add first word to sum */
+		"addw %4,%0\n\t"
+		"movew %4,%3@+\n\t"
+		"clrl %4\n\t"
+		"addxl %4,%0\n"		/* add X bit */
+	     "2:\t"
+		/* unrolled loop for the main part: do 8 longs at once */
+		"movel %1,%4\n\t"	/* save len in tmp1 */
+		"lsrl #5,%1\n\t"	/* len/32 */
+		"jeq 2f\n\t"		/* not enough... */
+		"subql #1,%1\n"
+	     "1:\t"
+		"movesl %2@+,%5\n\t"
+		"addxl %5,%0\n\t"
+		"movel %5,%3@+\n\t"
+		"movesl %2@+,%5\n\t"
+		"addxl %5,%0\n\t"
+		"movel %5,%3@+\n\t"
+		"movesl %2@+,%5\n\t"
+		"addxl %5,%0\n\t"
+		"movel %5,%3@+\n\t"
+		"movesl %2@+,%5\n\t"
+		"addxl %5,%0\n\t"
+		"movel %5,%3@+\n\t"
+		"movesl %2@+,%5\n\t"
+		"addxl %5,%0\n\t"
+		"movel %5,%3@+\n\t"
+		"movesl %2@+,%5\n\t"
+		"addxl %5,%0\n\t"
+		"movel %5,%3@+\n\t"
+		"movesl %2@+,%5\n\t"
+		"addxl %5,%0\n\t"
+		"movel %5,%3@+\n\t"
+		"movesl %2@+,%5\n\t"
+		"addxl %5,%0\n\t"
+		"movel %5,%3@+\n\t"
+		"dbra %1,1b\n\t"
+		"clrl %5\n\t"
+		"addxl %5,%0\n\t"	/* add X bit */
+		"clrw %1\n\t"
+		"subql #1,%1\n\t"
+		"jcc 1b\n"
+	     "2:\t"
+		"movel %4,%1\n\t"	/* restore len from tmp1 */
+		"andw #0x1c,%4\n\t"	/* number of rest longs */
+		"jeq 4f\n\t"
+		"lsrw #2,%4\n\t"
+		"subqw #1,%4\n"
+	     "3:\t"
+		/* loop for rest longs */
+		"movesl %2@+,%5\n\t"
+		"addxl %5,%0\n\t"
+		"movel %5,%3@+\n\t"
+		"dbra %4,3b\n\t"
+		"clrl %5\n\t"
+		"addxl %5,%0\n"		/* add X bit */
+	     "4:\t"
+		/* now check for rest bytes that do not fit into longs */
+		"andw #3,%1\n\t"
+		"jeq 7f\n\t"
+		"clrl %5\n\t"		/* clear tmp2 for rest bytes */
+		"subqw #2,%1\n\t"
+		"jlt 5f\n\t"
+		"movesw %2@+,%5\n\t"	/* have rest >= 2: get word */
+		"movew %5,%3@+\n\t"
+		"swap %5\n\t"		/* into bits 16..31 */
+		"tstw %1\n\t"		/* another byte? */
+		"jeq 6f\n"
+	     "5:\t"
+		"movesb %2@,%5\n\t"	/* have odd rest: get byte */
+		"moveb %5,%3@+\n\t"
+		"lslw #8,%5\n\t"	/* into bits 8..15; 16..31 untouched */
+	     "6:\t"
+		"addl %5,%0\n\t"	/* now add rest long to sum */
+		"clrl %5\n\t"
+		"addxl %5,%0\n"		/* add X bit */
+	     "7:\t"
+		: "=d" (sum), "=d" (len), "=a" (src), "=a" (dst),
+		  "=&d" (tmp1), "=&d" (tmp2)
+		: "0" (sum), "1" (len), "2" (src), "3" (dst)
+	    );
+	return(sum);
+}
+/*
+ * copy from ds while checksumming, otherwise like csum_partial
+ */
+
+unsigned int
+csum_partial_copy(const char *src, char *dst, int len, int sum)
+{
+	unsigned long tmp1, tmp2;
+	__asm__("movel %2,%4\n\t"
+		"btst #1,%4\n\t"	/* Check alignment */
+		"jeq 2f\n\t"
+		"subql #2,%1\n\t"	/* buff%4==2: treat first word */
+		"jgt 1f\n\t"
+		"addql #2,%1\n\t"	/* len was == 2, treat only rest */
+		"jra 4f\n"
+	     "1:\t"
+		"movew %2@+,%4\n\t"	/* add first word to sum */
+		"addw %4,%0\n\t"
+		"movew %4,%3@+\n\t"
+		"clrl %4\n\t"
+		"addxl %4,%0\n"		/* add X bit */
+	     "2:\t"
+		/* unrolled loop for the main part: do 8 longs at once */
+		"movel %1,%4\n\t"	/* save len in tmp1 */
+		"lsrl #5,%1\n\t"	/* len/32 */
+		"jeq 2f\n\t"		/* not enough... */
+		"subql #1,%1\n"
+	     "1:\t"
+		"movel %2@+,%5\n\t"
+		"addxl %5,%0\n\t"
+		"movel %5,%3@+\n\t"
+		"movel %2@+,%5\n\t"
+		"addxl %5,%0\n\t"
+		"movel %5,%3@+\n\t"
+		"movel %2@+,%5\n\t"
+		"addxl %5,%0\n\t"
+		"movel %5,%3@+\n\t"
+		"movel %2@+,%5\n\t"
+		"addxl %5,%0\n\t"
+		"movel %5,%3@+\n\t"
+		"movel %2@+,%5\n\t"
+		"addxl %5,%0\n\t"
+		"movel %5,%3@+\n\t"
+		"movel %2@+,%5\n\t"
+		"addxl %5,%0\n\t"
+		"movel %5,%3@+\n\t"
+		"movel %2@+,%5\n\t"
+		"addxl %5,%0\n\t"
+		"movel %5,%3@+\n\t"
+		"movel %2@+,%5\n\t"
+		"addxl %5,%0\n\t"
+		"movel %5,%3@+\n\t"
+		"dbra %1,1b\n\t"
+		"clrl %5\n\t"
+		"addxl %5,%0\n\t"	/* add X bit */
+		"clrw %1\n\t"
+		"subql #1,%1\n\t"
+		"jcc 1b\n"
+	     "2:\t"
+		"movel %4,%1\n\t"	/* restore len from tmp1 */
+		"andw #0x1c,%4\n\t"	/* number of rest longs */
+		"jeq 4f\n\t"
+		"lsrw #2,%4\n\t"
+		"subqw #1,%4\n"
+	     "3:\t"
+		/* loop for rest longs */
+		"movel %2@+,%5\n\t"
+		"addxl %5,%0\n\t"
+		"movel %5,%3@+\n\t"
+		"dbra %4,3b\n\t"
+		"clrl %5\n\t"
+		"addxl %5,%0\n"		/* add X bit */
+	     "4:\t"
+		/* now check for rest bytes that do not fit into longs */
+		"andw #3,%1\n\t"
+		"jeq 7f\n\t"
+		"clrl %5\n\t"		/* clear tmp2 for rest bytes */
+		"subqw #2,%1\n\t"
+		"jlt 5f\n\t"
+		"movew %2@+,%5\n\t"	/* have rest >= 2: get word */
+		"movew %5,%3@+\n\t"
+		"swap %5\n\t"		/* into bits 16..31 */
+		"tstw %1\n\t"		/* another byte? */
+		"jeq 6f\n"
+	     "5:\t"
+		"moveb %2@,%5\n\t"	/* have odd rest: get byte */
+		"moveb %5,%3@+\n\t"
+		"lslw #8,%5\n"		/* into bits 8..15; 16..31 untouched */
+	     "6:\t"
+		"addl %5,%0\n\t"	/* now add rest long to sum */
+		"clrl %5\n\t"
+		"addxl %5,%0\n"		/* add X bit */
+	     "7:\t"
+		: "=d" (sum), "=d" (len), "=a" (src), "=a" (dst),
+		  "=&d" (tmp1), "=&d" (tmp2)
+		: "0" (sum), "1" (len), "2" (src), "3" (dst)
+	    );
+    return(sum);
+}
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/lib/memcmp.c linux/arch/m68k/lib/memcmp.c
--- v1.3.93/linux/arch/m68k/lib/memcmp.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/lib/memcmp.c	Wed Dec 27 22:46:35 1995
@@ -0,0 +1,11 @@
+#include <linux/types.h>
+
+int memcmp(const void * cs,const void * ct,size_t count)
+{
+  const unsigned char *su1, *su2;
+
+  for( su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--)
+    if (*su1 != *su2)
+      return((*su1 < *su2) ? -1 : +1);
+  return(0);
+}
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/lib/memcpy.c linux/arch/m68k/lib/memcpy.c
--- v1.3.93/linux/arch/m68k/lib/memcpy.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/lib/memcpy.c	Wed Dec 27 22:46:35 1995
@@ -0,0 +1,55 @@
+#include <linux/types.h>
+
+void * memcpy(void * to, const void * from, size_t n)
+{
+  void *xto = to;
+  size_t temp;
+
+  if (!n)
+    return xto;
+  if ((long) to & 1)
+    {
+      char *cto = to;
+      const char *cfrom = from;
+      *cto++ = *cfrom++;
+      to = cto;
+      from = cfrom;
+      n--;
+    }
+  if (n > 2 && (long) to & 2)
+    {
+      short *sto = to;
+      const short *sfrom = from;
+      *sto++ = *sfrom++;
+      to = sto;
+      from = sfrom;
+      n -= 2;
+    }
+  temp = n >> 2;
+  if (temp)
+    {
+      long *lto = to;
+      const long *lfrom = from;
+      temp--;
+      do
+	*lto++ = *lfrom++;
+      while (temp--);
+      to = lto;
+      from = lfrom;
+    }
+  if (n & 2)
+    {
+      short *sto = to;
+      const short *sfrom = from;
+      *sto++ = *sfrom++;
+      to = sto;
+      from = sfrom;
+    }
+  if (n & 1)
+    {
+      char *cto = to;
+      const char *cfrom = from;
+      *cto = *cfrom;
+    }
+  return xto;
+}
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/mm/Makefile linux/arch/m68k/mm/Makefile
--- v1.3.93/linux/arch/m68k/mm/Makefile	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/mm/Makefile	Wed Dec 27 22:46:36 1995
@@ -0,0 +1,13 @@
+#
+# Makefile for the linux m68k-specific parts of the memory manager.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definition is now in the main makefile...
+
+O_TARGET := mm.o
+O_OBJS	 := init.o fault.o memory.o
+
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/mm/fault.c linux/arch/m68k/mm/fault.c
--- v1.3.93/linux/arch/m68k/mm/fault.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/mm/fault.c	Thu Apr 18 02:59:59 1996
@@ -0,0 +1,113 @@
+/*
+ *  linux/arch/m68k/mm/fault.c
+ *
+ *  Copyright (C) 1995  Hamish Macdonald
+ */
+
+#include <linux/mman.h>
+#include <linux/mm.h>
+#include <linux/kernel.h>
+#include <linux/ptrace.h>
+
+#include <asm/system.h>
+#include <asm/pgtable.h>
+
+extern void die_if_kernel(char *, struct pt_regs *, long);
+
+/*
+ * This routine handles page faults.  It determines the problem, and
+ * then passes it off to one of the appropriate routines.
+ *
+ * error_code:
+ *	bit 0 == 0 means no page found, 1 means protection fault
+ *	bit 1 == 0 means read, 1 means write
+ *
+ * If this routine detects a bad access, it returns 1, otherwise it
+ * returns 0.
+ */
+asmlinkage int do_page_fault(struct pt_regs *regs, unsigned long address,
+			      unsigned long error_code)
+{
+	struct vm_area_struct * vma;
+
+#ifdef DEBUG
+	printk ("regs->sr=%#x, regs->pc=%#lx, address=%#lx, %ld, %p\n",
+		regs->sr, regs->pc, address, error_code,
+		current->tss.pagedir_v);
+#endif
+
+	vma = find_vma(current, address);
+	if (!vma)
+	  goto bad_area;
+	if (vma->vm_start <= address)
+		goto good_area;
+	if (!(vma->vm_flags & VM_GROWSDOWN))
+		goto bad_area;
+	if (user_mode(regs)) {
+		/* Accessing the stack below usp is always a bug.  The
+		   "+ 256" is there due to some instructions doing
+		   pre-decrement on the stack and that doesn't show up
+		   until later.  */
+		if (address + 256 < rdusp())
+			goto bad_area;
+	}
+	if (expand_stack(vma, address))
+		goto bad_area;
+
+/*
+ * Ok, we have a good vm_area for this memory access, so
+ * we can handle it..
+ */
+good_area:
+	/*
+	 * was it a write?
+	 */
+	if (error_code & 2) {
+	  if (!(vma->vm_flags & VM_WRITE))
+	    goto bad_area;
+	} else {
+		/* read with protection fault? */
+	  if (error_code & 1)
+	    goto bad_area;
+	  if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
+	    goto bad_area;
+	}
+	if (error_code & 1) {
+		do_wp_page(current, vma, address, error_code & 2);
+		return 0;
+	}
+	do_no_page(current, vma, address, error_code & 2);
+
+	/* There seems to be a missing invalidate somewhere in do_no_page.
+	 * Until I found it, this one cures the problem and makes
+	 * 1.2 run on the 68040 (Martin Apel).
+	 */
+	flush_tlb_all();
+
+	return 0;
+
+/*
+ * Something tried to access memory that isn't in our memory map..
+ * Fix it, but check if it's kernel or user first..
+ */
+bad_area:
+	if (user_mode(regs)) {
+		/* User memory access */
+		send_sig (SIGSEGV, current, 1);
+		return 1;
+	}
+
+/*
+ * Oops. The kernel tried to access some bad page. We'll have to
+ * terminate things with extreme prejudice.
+ */
+	if ((unsigned long) address < PAGE_SIZE) {
+		printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference");
+	} else
+		printk(KERN_ALERT "Unable to handle kernel access");
+	printk(" at virtual address %08lx\n",address);
+	die_if_kernel("Oops", regs, error_code);
+	do_exit(SIGKILL);
+
+	return 1;
+}
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/mm/init.c linux/arch/m68k/mm/init.c
--- v1.3.93/linux/arch/m68k/mm/init.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/mm/init.c	Thu Apr 18 03:00:00 1996
@@ -0,0 +1,545 @@
+/*
+ *  linux/arch/m68k/mm/init.c
+ *
+ *  Copyright (C) 1995  Hamish Macdonald
+ */
+
+#include <linux/config.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/swap.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#ifdef CONFIG_BLK_DEV_INITRD
+#include <linux/blk.h>
+#endif
+
+#include <asm/segment.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/system.h>
+#include <asm/bootinfo.h>
+#include <asm/machdep.h>
+
+extern void die_if_kernel(char *,struct pt_regs *,long);
+extern void show_net_buffers(void);
+extern unsigned long mm_phys_to_virt (unsigned long addr);
+extern char *rd_start;
+extern int rd_doload;
+
+unsigned long ramdisk_length;
+
+/*
+ * BAD_PAGE is the page that is used for page faults when linux
+ * is out-of-memory. Older versions of linux just did a
+ * do_exit(), but using this instead means there is less risk
+ * for a process dying in kernel mode, possibly leaving a inode
+ * unused etc..
+ *
+ * BAD_PAGETABLE is the accompanying page-table: it is initialized
+ * to point to BAD_PAGE entries.
+ *
+ * ZERO_PAGE is a special page that is used for zero-initialized
+ * data and COW.
+ */
+static unsigned long empty_bad_page_table;
+
+pte_t *__bad_pagetable(void)
+{
+    memset((void *)empty_bad_page_table, 0, PAGE_SIZE);
+    return (pte_t *)empty_bad_page_table;
+}
+
+static unsigned long empty_bad_page;
+
+pte_t __bad_page(void)
+{
+    memset ((void *)empty_bad_page, 0, PAGE_SIZE);
+    return pte_mkdirty(mk_pte(empty_bad_page, PAGE_SHARED));
+}
+
+unsigned long empty_zero_page;
+
+void show_mem(void)
+{
+    unsigned long i;
+    int free = 0, total = 0, reserved = 0, nonshared = 0, shared = 0;
+
+    printk("\nMem-info:\n");
+    show_free_areas();
+    printk("Free swap:       %6dkB\n",nr_swap_pages<<(PAGE_SHIFT-10));
+    i = high_memory >> PAGE_SHIFT;
+    while (i-- > 0) {
+	total++;
+	if (PageReserved(mem_map+i))
+	    reserved++;
+	else if (!mem_map[i].count)
+	    free++;
+	else if (mem_map[i].count == 1)
+	    nonshared++;
+	else
+	    shared += mem_map[i].count-1;
+    }
+    printk("%d pages of RAM\n",total);
+    printk("%d free pages\n",free);
+    printk("%d reserved pages\n",reserved);
+    printk("%d pages nonshared\n",nonshared);
+    printk("%d pages shared\n",shared);
+    show_buffers();
+#ifdef CONFIG_NET
+    show_net_buffers();
+#endif
+}
+
+#if 0 /* The 68030 doesn't care about reserved bits. */
+/*
+ * Bits to add to page descriptors for "normal" caching mode.
+ * For 68020/030 this is 0.
+ * For 68040, this is _PAGE_CACHE040 (cachable, copyback)
+ */
+unsigned long mm_cachebits;
+#endif
+
+pte_t *kernel_page_table (unsigned long *memavailp)
+{
+	pte_t *ptablep;
+
+	ptablep = (pte_t *)*memavailp;
+	*memavailp += PAGE_SIZE;
+
+	nocache_page ((unsigned long)ptablep);
+
+	return ptablep;
+}
+
+static unsigned long map_chunk (unsigned long addr,
+				unsigned long size,
+				unsigned long *memavailp)
+{
+#define ONEMEG	(1024*1024)
+#define L3TREESIZE (256*1024)
+
+	int is040 = m68k_is040or060;
+	static unsigned long mem_mapped = 0;
+	static unsigned long virtaddr = 0;
+	static pte_t *ktablep = NULL;
+	unsigned long *kpointerp;
+	unsigned long physaddr;
+	extern pte_t *kpt;
+	int pindex;   /* index into pointer table */
+	pgd_t *page_dir = pgd_offset_k (virtaddr);
+
+	if (!pgd_present (*page_dir)) {
+		/* we need a new pointer table */
+		kpointerp = (unsigned long *) get_kpointer_table ();
+		pgd_set (page_dir, (pmd_t *) kpointerp);
+		memset (kpointerp, 0, PTRS_PER_PMD * sizeof (pmd_t));
+	}
+	else
+		kpointerp = (unsigned long *) pgd_page (*page_dir);
+
+	/*
+	 * pindex is the offset into the pointer table for the
+	 * descriptors for the current virtual address being mapped.
+	 */
+	pindex = (virtaddr >> 18) & 0x7f;
+
+#ifdef DEBUG
+	printk ("mm=%ld, kernel_pg_dir=%p, kpointerp=%p, pindex=%d\n",
+		mem_mapped, kernel_pg_dir, kpointerp, pindex);
+#endif
+
+	/*
+	 * if this is running on an '040, we already allocated a page
+	 * table for the first 4M.  The address is stored in kpt by
+	 * arch/head.S
+	 *
+	 */
+	if (is040 && mem_mapped == 0)
+		ktablep = kpt;
+
+	for (physaddr = addr;
+	     physaddr < addr + size;
+	     mem_mapped += L3TREESIZE, virtaddr += L3TREESIZE) {
+
+#ifdef DEBUG
+		printk ("pa=%#lx va=%#lx ", physaddr, virtaddr);
+#endif
+
+		if (pindex > 127 && mem_mapped >= 32*ONEMEG) {
+			/* we need a new pointer table every 32M */
+#ifdef DEBUG
+			printk ("[new pointer]");
+#endif
+
+			kpointerp = (unsigned long *)get_kpointer_table ();
+			pgd_set(pgd_offset_k(virtaddr), (pmd_t *)kpointerp);
+			pindex = 0;
+		}
+
+		if (is040) {
+			int i;
+			unsigned long ktable;
+
+			/* Don't map the first 4 MB again. The pagetables
+			 * for this range have already been initialized
+			 * in boot/head.S. Otherwise the pages used for
+			 * tables would be reinitialized to copyback mode.
+			 */
+
+			if (mem_mapped < 4 * ONEMEG)
+			{
+#ifdef DEBUG
+				printk ("Already initialized\n");
+#endif
+				physaddr += L3TREESIZE;
+				pindex++;
+				continue;
+			}
+#ifdef DEBUG
+			printk ("[setup table]");
+#endif
+
+			/*
+			 * 68040, use page tables pointed to by the
+			 * kernel pointer table.
+			 */
+
+			if ((pindex & 15) == 0) {
+				/* Need new page table every 4M on the '040 */
+#ifdef DEBUG
+				printk ("[new table]");
+#endif
+				ktablep = kernel_page_table (memavailp);
+			}
+
+			ktable = VTOP(ktablep);
+
+			/*
+			 * initialize section of the page table mapping
+			 * this 256K portion.
+			 */
+			for (i = 0; i < 64; i++) {
+				pte_val(ktablep[i]) = physaddr | _PAGE_PRESENT
+					| _PAGE_CACHE040 | _PAGE_GLOBAL040;
+				physaddr += PAGE_SIZE;
+			}
+			ktablep += 64;
+
+			/*
+			 * make the kernel pointer table point to the
+			 * kernel page table.  Each entries point to a
+			 * 64 entry section of the page table.
+			 */
+
+			kpointerp[pindex++] = ktable | _PAGE_TABLE;
+		} else {
+			/*
+			 * 68030, use early termination page descriptors.
+			 * Each one points to 64 pages (256K).
+			 */
+#ifdef DEBUG
+			printk ("[early term] ");
+#endif
+			if (virtaddr == 0UL) {
+				/* map the first 256K using a 64 entry
+				 * 3rd level page table.
+				 * UNMAP the first entry to trap
+				 * zero page (NULL pointer) references
+				 */
+				int i;
+				unsigned long *tbl;
+				
+				tbl = (unsigned long *)get_kpointer_table();
+
+				kpointerp[pindex++] = VTOP(tbl) | _PAGE_TABLE;
+
+				for (i = 0; i < 64; i++, physaddr += PAGE_SIZE)
+					tbl[i] = physaddr | _PAGE_PRESENT;
+				
+				/* unmap the zero page */
+				tbl[0] = 0;
+			} else {
+				/* not the first 256K */
+				kpointerp[pindex++] = physaddr | _PAGE_PRESENT;
+#ifdef DEBUG
+				printk ("%lx=%lx ", VTOP(&kpointerp[pindex-1]),
+					kpointerp[pindex-1]);
+#endif
+				physaddr += 64 * PAGE_SIZE;
+			}
+		}
+#ifdef DEBUG
+		printk ("\n");
+#endif
+	}
+
+	return mem_mapped;
+}
+
+extern unsigned long free_area_init(unsigned long, unsigned long);
+
+extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
+
+/*
+ * paging_init() continues the virtual memory environment setup which
+ * was begun by the code in arch/head.S.
+ * The parameters are pointers to where to stick the starting and ending
+ * addresses  of available kernel virtual memory.
+ */
+unsigned long paging_init(unsigned long start_mem, unsigned long end_mem)
+{
+	int chunk;
+	unsigned long mem_avail = 0;
+	/* pointer to page table for kernel stacks */
+	extern unsigned long availmem;
+
+#ifdef DEBUG
+	{
+		extern pte_t *kpt;
+		printk ("start of paging_init (%p, %p, %lx, %lx, %lx)\n",
+			kernel_pg_dir, kpt, availmem, start_mem, end_mem);
+	}
+#endif
+
+#if 0
+	/*
+	 * Setup cache bits
+	 */
+	mm_cachebits = m68k_is040or060 ? _PAGE_CACHE040 : 0;
+
+	/* Initialize protection map.  */
+	protection_map[0] = PAGE_READONLY;
+	protection_map[1] = PAGE_READONLY;
+	protection_map[2] = PAGE_COPY;
+	protection_map[3] = PAGE_COPY;
+	protection_map[4] = PAGE_READONLY;
+	protection_map[5] = PAGE_READONLY;
+	protection_map[6] = PAGE_COPY;
+	protection_map[7] = PAGE_COPY;
+	protection_map[8] = PAGE_READONLY;
+	protection_map[9] = PAGE_READONLY;
+	protection_map[10] = PAGE_SHARED;
+	protection_map[11] = PAGE_SHARED;
+	protection_map[12] = PAGE_READONLY;
+	protection_map[13] = PAGE_READONLY;
+	protection_map[14] = PAGE_SHARED;
+	protection_map[15] = PAGE_SHARED;
+#endif
+
+	/*
+	 * Map the physical memory available into the kernel virtual
+	 * address space.  It may allocate some memory for page
+	 * tables and thus modify availmem.
+	 */
+
+	for (chunk = 0; chunk < boot_info.num_memory; chunk++) {
+		mem_avail = map_chunk (boot_info.memory[chunk].addr,
+				       boot_info.memory[chunk].size,
+				       &availmem);
+
+	}
+	flush_tlb_all();
+#ifdef DEBUG
+	printk ("memory available is %ldKB\n", mem_avail >> 10);
+#endif
+
+	/*
+	 * virtual address after end of kernel
+	 * "availmem" is setup by the code in head.S.
+	 */
+	start_mem = availmem;
+
+#ifdef DEBUG
+	printk ("start_mem is %#lx\nvirtual_end is %#lx\n",
+		start_mem, end_mem);
+#endif
+
+	/*
+	 * initialize the bad page table and bad page to point
+	 * to a couple of allocated pages
+	 */
+	empty_bad_page_table = start_mem;
+	start_mem += PAGE_SIZE;
+	empty_bad_page = start_mem;
+	start_mem += PAGE_SIZE;
+	empty_zero_page = start_mem;
+	start_mem += PAGE_SIZE;
+	memset((void *)empty_zero_page, 0, PAGE_SIZE);
+
+#if 0
+	/* 
+	 * allocate the "swapper" page directory and
+	 * record in task 0 (swapper) tss 
+	 */
+	swapper_pg_dir = (pgd_t *)get_kpointer_table();
+
+	init_mm.pgd = swapper_pg_dir;
+#endif
+
+	memset (swapper_pg_dir, 0, sizeof(pgd_t)*PTRS_PER_PGD);
+	task[0]->tss.pagedir_v = (unsigned long *)swapper_pg_dir;
+	task[0]->tss.pagedir_p = VTOP (swapper_pg_dir);
+
+#ifdef DEBUG
+	printk ("task 0 pagedir at %p virt, %#lx phys\n",
+		task[0]->tss.pagedir_v, task[0]->tss.pagedir_p);
+#endif
+
+	/* setup CPU root pointer for swapper task */
+	task[0]->tss.crp[0] = 0x80000000 | _PAGE_SHORT;
+	task[0]->tss.crp[1] = task[0]->tss.pagedir_p;
+
+	if (m68k_is040or060)
+		asm ("movel %0,%/d0\n\t"
+		     ".long 0x4e7b0806" /* movec d0,urp */
+		     : /* no outputs */
+		     : "g" (task[0]->tss.crp[1])
+		     : "d0");
+	else
+		asm ("pmove %0@,%/crp"
+		     : /* no outputs */
+		     : "a" (task[0]->tss.crp));
+
+#ifdef DEBUG
+	printk ("set crp\n");
+#endif
+
+	/*
+	 * Set up SFC/DFC registers (user data space)
+	 */
+	set_fs (USER_DS);
+
+#ifdef DEBUG
+	printk ("before free_area_init\n");
+#endif
+
+#ifndef CONFIG_BLK_DEV_INITRD
+	/*
+	 * Since the initialization of the ramdisk's has been changed
+	 * so it fits the new driver initialization scheme, we have to
+	 * make room for our preloaded image here, instead of doing it
+	 * in rd_init() as we cannot kmalloc() a block large enough
+	 * for the image.
+	 */
+
+	ramdisk_length = boot_info.ramdisk_size * 1024;
+
+	if ((ramdisk_length > 0) && (ROOT_DEV == 0)) {
+	  char *rdp;	     /* current location of ramdisk */
+
+	  rd_start = (char *) start_mem;
+
+	  /* get current address of ramdisk */
+	  rdp = (char *)mm_phys_to_virt (boot_info.ramdisk_addr);
+
+	  /* copy the ram disk image */
+	  memcpy (rd_start, rdp, ramdisk_length);
+	  start_mem += ramdisk_length;
+	  rd_doload = 1;     /* tell rd_load to load this thing */
+	}
+#endif
+
+	return free_area_init (start_mem, end_mem);
+}
+
+void mem_init(unsigned long start_mem, unsigned long end_mem)
+{
+	int codepages = 0;
+	int reservedpages = 0;
+	int datapages = 0;
+	unsigned long tmp;
+	extern int _etext;
+
+	end_mem &= PAGE_MASK;
+	high_memory = end_mem;
+
+	start_mem = PAGE_ALIGN(start_mem);
+	while (start_mem < high_memory) {
+		clear_bit(PG_reserved, &mem_map[MAP_NR(start_mem)].flags);
+		start_mem += PAGE_SIZE;
+	}
+
+#ifdef CONFIG_ATARI
+
+	if (MACH_IS_ATARI) {
+
+		/* If the page with physical address 0 isn't the first kernel
+		 * code page, it has to be reserved because the first 2 KB of
+		 * ST-Ram can only be accessed from supervisor mode by
+		 * hardware.
+		 */
+
+		unsigned long virt0 = PTOV( 0 ), adr;
+		extern unsigned long rsvd_stram_beg, rsvd_stram_end;
+		
+		if (virt0 != 0) {
+
+			set_bit(PG_reserved, &mem_map[MAP_NR(virt0)].flags);
+
+			/* Also, reserve all pages that have been marked by
+			 * stram_alloc() (e.g. for the screen memory). (This may
+			 * treat the first ST-Ram page a second time, but that
+			 * doesn't hurt...) */
+			
+			rsvd_stram_end += PAGE_SIZE - 1;
+			rsvd_stram_end &= PAGE_MASK;
+			rsvd_stram_beg &= PAGE_MASK;
+			for( adr = rsvd_stram_beg; adr < rsvd_stram_end; adr += PAGE_SIZE )
+				set_bit(PG_reserved, &mem_map[MAP_NR(adr)].flags);
+		}
+	}
+	
+#endif
+#ifdef DEBUG
+	printk ("task[0] root table is %p\n", task[0]->tss.pagedir_v);
+#endif
+
+	for (tmp = 0 ; tmp < end_mem ; tmp += PAGE_SIZE) {
+		if (VTOP (tmp) >= mach_max_dma_address)
+			clear_bit(PG_DMA, &mem_map[MAP_NR(tmp)].flags);
+		if (PageReserved(mem_map+MAP_NR(tmp))) {
+			if (tmp < (unsigned long)&_etext)
+				codepages++;
+			else
+				datapages++;
+			continue;
+		}
+		mem_map[MAP_NR(tmp)].count = 1;
+#ifdef CONFIG_BLK_DEV_INITRD
+		if (!initrd_start || (tmp < initrd_start || tmp >= initrd_end))
+#endif
+			free_page(tmp);
+	}
+	tmp = nr_free_pages << PAGE_SHIFT;
+	printk("Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data)\n",
+	       tmp >> 10,
+	       high_memory >> 10,
+	       codepages << (PAGE_SHIFT-10),
+	       reservedpages << (PAGE_SHIFT-10),
+	       datapages << (PAGE_SHIFT-10));
+}
+
+void si_meminfo(struct sysinfo *val)
+{
+    unsigned long i;
+
+    i = high_memory >> PAGE_SHIFT;
+    val->totalram = 0;
+    val->sharedram = 0;
+    val->freeram = nr_free_pages << PAGE_SHIFT;
+    val->bufferram = buffermem;
+    while (i-- > 0) {
+	if (PageReserved(mem_map+i))
+	    continue;
+	val->totalram++;
+	if (!mem_map[i].count)
+	    continue;
+	val->sharedram += mem_map[i].count-1;
+    }
+    val->totalram <<= PAGE_SHIFT;
+    val->sharedram <<= PAGE_SHIFT;
+    return;
+}
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/mm/memory.c linux/arch/m68k/mm/memory.c
--- v1.3.93/linux/arch/m68k/mm/memory.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/m68k/mm/memory.c	Thu Apr 18 03:00:00 1996
@@ -0,0 +1,753 @@
+/*
+ *  linux/arch/m68k/mm/memory.c
+ *
+ *  Copyright (C) 1995  Hamish Macdonald
+ */
+
+#include <linux/mm.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/malloc.h>
+
+#include <asm/segment.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/system.h>
+#include <asm/traps.h>
+#include <asm/amigahw.h>
+#include <asm/bootinfo.h>
+
+extern pte_t *kernel_page_table (unsigned long *memavailp);
+
+static struct ptable_desc {
+	struct ptable_desc *prev;
+	struct ptable_desc *next;
+	unsigned long	   page;
+	unsigned char	   alloced;
+} ptable_list = { &ptable_list, &ptable_list, 0, 0xff };
+
+#define PD_NONEFREE(dp) ((dp)->alloced == 0xff)
+#define PD_ALLFREE(dp) ((dp)->alloced == 0)
+#define PD_TABLEFREE(dp,i) (!((dp)->alloced & (1<<(i))))
+#define PD_MARKUSED(dp,i) ((dp)->alloced |= (1<<(i)))
+#define PD_MARKFREE(dp,i) ((dp)->alloced &= ~(1<<(i)))
+
+#define PTABLE_SIZE (PTRS_PER_PMD * sizeof(pmd_t))
+
+pmd_t *get_pointer_table (void)
+{
+	pmd_t *pmdp = NULL;
+	unsigned long flags;
+	struct ptable_desc *dp = ptable_list.next;
+	int i;
+
+	/*
+	 * For a pointer table for a user process address space, a
+	 * table is taken from a page allocated for the purpose.  Each
+	 * page can hold 8 pointer tables.  The page is remapped in
+	 * virtual address space to be noncacheable.
+	 */
+	if (PD_NONEFREE (dp)) {
+
+		if (!(dp = kmalloc (sizeof(struct ptable_desc),GFP_KERNEL))) {
+			return 0;
+		}
+
+		if (!(dp->page = __get_free_page (GFP_KERNEL))) {
+			kfree (dp);
+			return 0;
+		}
+
+		nocache_page (dp->page);
+
+		dp->alloced = 0;
+		/* put at head of list */
+		save_flags(flags);
+		cli();
+		dp->next = ptable_list.next;
+		dp->prev = ptable_list.next->prev;
+		ptable_list.next->prev = dp;
+		ptable_list.next = dp;
+		restore_flags(flags);
+	}
+
+	for (i = 0; i < 8; i++)
+		if (PD_TABLEFREE (dp, i)) {
+			PD_MARKUSED (dp, i);
+			pmdp = (pmd_t *)(dp->page + PTABLE_SIZE*i);
+			break;
+		}
+
+	if (PD_NONEFREE (dp)) {
+		/* move to end of list */
+		save_flags(flags);
+		cli();
+		dp->prev->next = dp->next;
+		dp->next->prev = dp->prev;
+
+		dp->next = ptable_list.next->prev;
+		dp->prev = ptable_list.prev;
+		ptable_list.prev->next = dp;
+		ptable_list.prev = dp;
+		restore_flags(flags);
+	}
+
+	memset (pmdp, 0, PTABLE_SIZE);
+
+	return pmdp;
+}
+
+void free_pointer_table (pmd_t *ptable)
+{
+	struct ptable_desc *dp;
+	unsigned long page = (unsigned long)ptable & PAGE_MASK;
+	int index = ((unsigned long)ptable - page)/PTABLE_SIZE;
+	unsigned long flags;
+
+	for (dp = ptable_list.next; dp->page && dp->page != page; dp = dp->next)
+		;
+
+	if (!dp->page)
+		panic ("unable to find desc for ptable %p on list!", ptable);
+
+	if (PD_TABLEFREE (dp, index))
+		panic ("table already free!");
+
+	PD_MARKFREE (dp, index);
+
+	if (PD_ALLFREE (dp)) {
+		/* all tables in page are free, free page */
+		save_flags(flags);
+		cli();
+		dp->prev->next = dp->next;
+		dp->next->prev = dp->prev;
+		restore_flags(flags);
+		cache_page (dp->page);
+		free_page (dp->page);
+		kfree (dp);
+		return;
+	} else {
+		/*
+		 * move this descriptor the the front of the list, since
+		 * it has one or more free tables.
+		 */
+		save_flags(flags);
+		cli();
+		dp->prev->next = dp->next;
+		dp->next->prev = dp->prev;
+
+		dp->next = ptable_list.next;
+		dp->prev = ptable_list.next->prev;
+		ptable_list.next->prev = dp;
+		ptable_list.next = dp;
+		restore_flags(flags);
+	}
+}
+
+static unsigned char alloced = 0;
+extern pmd_t (*kernel_pmd_table)[PTRS_PER_PMD]; /* initialized in head.S */
+
+pmd_t *get_kpointer_table (void)
+{
+	/* For pointer tables for the kernel virtual address space,
+	 * use a page that is allocated in head.S that can hold up to
+	 * 8 pointer tables.  This allows mapping of 8 * 32M = 256M of
+	 * physical memory.  This should be sufficient for now.
+	 */
+	pmd_t *ptable;
+	int i;
+
+	for (i = 0; i < PAGE_SIZE/(PTRS_PER_PMD*sizeof(pmd_t)); i++)
+		if ((alloced & (1 << i)) == 0) {
+			ptable = kernel_pmd_table[i];
+			memset (ptable, 0, PTRS_PER_PMD*sizeof(pmd_t));
+			alloced |= (1 << i);
+			return ptable;
+		}
+	printk ("no space for kernel pointer table\n");
+	return NULL;
+}
+
+void free_kpointer_table (pmd_t *pmdp)
+{
+	int index = (pmd_t (*)[PTRS_PER_PMD])pmdp - kernel_pmd_table;
+
+	if (index < 0 || index > 7 ||
+	    /* This works because kernel_pmd_table is page aligned. */
+	    ((unsigned long)pmdp & (sizeof(pmd_t) * PTRS_PER_PMD - 1)))
+		panic("attempt to free invalid kernel pointer table");
+	else
+		alloced &= ~(1 << index);
+}
+
+/*
+ * The following two routines map from a physical address to a kernel
+ * virtual address and vice versa.
+ */
+unsigned long mm_vtop (unsigned long vaddr)
+{
+	int i;
+	unsigned long voff = vaddr;
+	unsigned long offset = 0;
+
+	for (i = 0; i < boot_info.num_memory; i++)
+	{
+		if (voff < offset + boot_info.memory[i].size) {
+#ifdef DEBUGPV
+			printk ("VTOP(%lx)=%lx\n", vaddr,
+				boot_info.memory[i].addr + voff - offset);
+#endif
+			return boot_info.memory[i].addr + voff - offset;
+		} else
+			offset += boot_info.memory[i].size;
+	}
+
+	/* not in one of the memory chunks; get the actual
+	 * physical address from the MMU.
+	 */
+	if (m68k_is040or060 == 6) {
+	  unsigned long fs = get_fs();
+	  unsigned long  paddr;
+
+	  set_fs (SUPER_DATA);
+
+	  /* The PLPAR instruction causes an access error if the translation
+	   * is not possible. We don't catch that here, so a bad kernel trap
+	   * will be reported in this case. */
+	  asm volatile ("movel %1,%/a0\n\t"
+			".word 0xf5c8\n\t"	/* plpar (a0) */
+			"movel %/a0,%0"
+			: "=g" (paddr)
+			: "g" (vaddr)
+			: "a0" );
+	  set_fs (fs);
+
+	  return paddr;
+
+	} else if (m68k_is040or060 == 4) {
+	  unsigned long mmusr;
+	  unsigned long fs = get_fs();
+
+	  set_fs (SUPER_DATA);
+
+	  asm volatile ("movel %1,%/a0\n\t"
+			".word 0xf568\n\t"	/* ptestr (a0) */
+			".long 0x4e7a8805\n\t"	/* movec mmusr, a0 */
+			"movel %/a0,%0"
+			: "=g" (mmusr)
+			: "g" (vaddr)
+			: "a0", "d0");
+	  set_fs (fs);
+
+	  if (mmusr & MMU_R_040)
+	    return (mmusr & PAGE_MASK) | (vaddr & (PAGE_SIZE-1));
+
+	  panic ("VTOP040: bad virtual address %08lx (%lx)", vaddr, mmusr);
+	} else {
+	  volatile unsigned short temp;
+	  unsigned short mmusr;
+	  unsigned long *descaddr;
+
+	  asm volatile ("ptestr #5,%2@,#7,%0\n\t"
+			"pmove %/psr,%1@"
+			: "=a&" (descaddr)
+			: "a" (&temp), "a" (vaddr));
+	  mmusr = temp;
+
+	  if (mmusr & (MMU_I|MMU_B|MMU_L))
+	    panic ("VTOP030: bad virtual address %08lx (%x)", vaddr, mmusr);
+
+	  descaddr = (unsigned long *)PTOV(descaddr);
+
+	  switch (mmusr & MMU_NUM) {
+	  case 1:
+	    return (*descaddr & 0xfe000000) | (vaddr & 0x01ffffff);
+	  case 2:
+	    return (*descaddr & 0xfffc0000) | (vaddr & 0x0003ffff);
+	  case 3:
+	    return (*descaddr & PAGE_MASK) | (vaddr & (PAGE_SIZE-1));
+	  default:
+	    panic ("VTOP: bad levels (%u) for virtual address %08lx", 
+		   mmusr & MMU_NUM, vaddr);
+	  }
+	}
+
+	panic ("VTOP: bad virtual address %08lx", vaddr);
+}
+
+unsigned long mm_ptov (unsigned long paddr)
+{
+	int i;
+	unsigned long offset = 0;
+
+	for (i = 0; i < boot_info.num_memory; i++)
+	{
+		if (paddr >= boot_info.memory[i].addr &&
+		    paddr < (boot_info.memory[i].addr
+			     + boot_info.memory[i].size)) {
+#ifdef DEBUGPV
+			printk ("PTOV(%lx)=%lx\n", paddr,
+				(paddr - boot_info.memory[i].addr) + offset);
+#endif
+			return (paddr - boot_info.memory[i].addr) + offset;
+		} else
+			offset += boot_info.memory[i].size;
+	}
+
+	/*
+	 * assume that the kernel virtual address is the same as the
+	 * physical address.
+	 *
+	 * This should be reasonable in most situations:
+	 *  1) They shouldn't be dereferencing the virtual address
+	 *     unless they are sure that it is valid from kernel space.
+	 *  2) The only usage I see so far is converting a page table
+	 *     reference to some non-FASTMEM address space when freeing
+         *     mmaped "/dev/mem" pages.  These addresses are just passed
+	 *     to "free_page", which ignores addresses that aren't in
+	 *     the memory list anyway.
+	 *
+	 */
+
+	/*
+	 * if on an amiga and address is in first 16M, move it 
+	 * to the ZTWO_ADDR range
+	 */
+	if (MACH_IS_AMIGA && paddr < 16*1024*1024)
+		return ZTWO_VADDR(paddr);
+	return paddr;
+}
+
+#define	clear040(paddr) __asm__ __volatile__ ("movel %0,%/a0\n\t"\
+					      ".word 0xf4d0"\
+					      /* CINVP I/D (a0) */\
+					      : : "g" ((paddr))\
+					      : "a0")
+
+#define	push040(paddr) __asm__ __volatile__ ("movel %0,%/a0\n\t"\
+					     ".word 0xf4f0"\
+					     /* CPUSHP I/D (a0) */\
+					     : : "g" ((paddr))\
+					     : "a0")
+
+#define	pushcl040(paddr) do { push040((paddr));\
+			      if (m68k_is040or060 == 6) clear040((paddr));\
+			 } while(0)
+
+#define	pushv040(vaddr) __asm__ __volatile__ ("movel %0,%/a0\n\t"\
+					      /* ptestr (a0) */\
+					      ".word 0xf568\n\t"\
+					      /* movec mmusr,d0 */\
+					      ".long 0x4e7a0805\n\t"\
+					      "andw #0xf000,%/d0\n\t"\
+					      "movel %/d0,%/a0\n\t"\
+					      /* CPUSHP I/D (a0) */\
+					      ".word 0xf4f0"\
+					      : : "g" ((vaddr))\
+					      : "a0", "d0")
+
+#define	pushv060(vaddr) __asm__ __volatile__ ("movel %0,%/a0\n\t"\
+					      /* plpar (a0) */\
+					      ".word 0xf5c8\n\t"\
+					      /* CPUSHP I/D (a0) */\
+					      ".word 0xf4f0"\
+					      : : "g" ((vaddr))\
+					      : "a0")
+
+
+/*
+ * 040: Hit every page containing an address in the range paddr..paddr+len-1.
+ * (Low order bits of the ea of a CINVP/CPUSHP are "don't care"s).
+ * Hit every page until there is a page or less to go. Hit the next page,
+ * and the one after that if the range hits it.
+ */
+/* ++roman: A little bit more care is required here: The CINVP instruction
+ * invalidates cache entries WITHOUT WRITING DIRTY DATA BACK! So the beginning
+ * and the end of the region must be treated differently if they are not
+ * exactly at the beginning or end of a page boundary. Else, maybe too much
+ * data becomes invalidated and thus lost forever. CPUSHP does what we need:
+ * it invalidates the page after pushing dirty data to memory. (Thanks to Jes
+ * for discovering the problem!)
+ */
+/* ... but on the '060, CPUSH doesn't invalidate (for us, since we have set
+ * the DPI bit in the CACR; would it cause problems with temporarily changing
+ * this?). So we have to push first and then additionally to invalidate.
+ */
+void cache_clear (unsigned long paddr, int len)
+{
+    if (m68k_is040or060) {
+	/* ++roman: There have been too many problems with the CINV, it seems
+	 * to break the cache maintainance of DMAing drivers. I don't expect
+	 * too much overhead by using CPUSH instead.
+	 */
+	while (len > PAGE_SIZE) {
+	    pushcl040(paddr);
+	    len -= PAGE_SIZE;
+	    paddr += PAGE_SIZE;
+	}
+	if (len > 0) {
+	    pushcl040(paddr);
+	    if (((paddr + len - 1) ^ paddr) & PAGE_MASK) {
+		/* a page boundary gets crossed at the end */
+		pushcl040(paddr + len - 1);
+	    }
+	}
+    }
+#if 0
+	/* on 68040, invalidate cache lines for pages in the range */
+	while (len > PAGE_SIZE) {
+	    clear040(paddr);
+	    len -= PAGE_SIZE;
+	    paddr += PAGE_SIZE;
+	    }
+	if (len > 0) {
+	    /* 0 < len <= PAGE_SIZE */
+	    clear040(paddr);
+	    if (((paddr + len - 1) / PAGE_SIZE) != (paddr / PAGE_SIZE)) {
+		/* a page boundary gets crossed at the end */
+		clear040(paddr + len - 1);
+		}
+	    }
+#endif
+    else /* 68030 or 68020 */
+	asm volatile ("movec %/cacr,%/d0\n\t"
+		      "oriw %0,%/d0\n\t"
+		      "movec %/d0,%/cacr"
+		      : : "i" (FLUSH_I_AND_D)
+		      : "d0");
+}
+
+
+
+void cache_push (unsigned long paddr, int len)
+{
+    if (m68k_is040or060) {
+	/*
+         * on 68040 or 68060, push cache lines for pages in the range;
+	 * on the '040 this also invalidates the pushed lines, but not on
+	 * the '060!
+	 */
+	while (len > PAGE_SIZE) {
+	    push040(paddr);
+	    len -= PAGE_SIZE;
+	    paddr += PAGE_SIZE;
+	    }
+	if (len > 0) {
+	    push040(paddr);
+#if 0
+	    if (((paddr + len - 1) / PAGE_SIZE) != (paddr / PAGE_SIZE)) {
+#endif
+	    if (((paddr + len - 1) ^ paddr) & PAGE_MASK) {
+		/* a page boundary gets crossed at the end */
+		push040(paddr + len - 1);
+		}
+	    }
+	}
+    
+    
+    /*
+     * 68030/68020 have no writeback cache. On the other hand,
+     * cache_push is actually a superset of cache_clear (the lines
+     * get written back and invalidated), so we should make sure
+     * to perform the corresponding actions. After all, this is getting
+     * called in places where we've just loaded code, or whatever, so
+     * flushing the icache is appropriate; flushing the dcache shouldn't
+     * be required.
+     */
+    else /* 68030 or 68020 */
+	asm volatile ("movec %/cacr,%/d0\n\t"
+		      "oriw %0,%/d0\n\t"
+		      "movec %/d0,%/cacr"
+		      : : "i" (FLUSH_I)
+		      : "d0");
+    }
+
+void cache_push_v (unsigned long vaddr, int len)
+{
+    if (m68k_is040or060 == 4) {
+	/* on 68040, push cache lines for pages in the range */
+	while (len > PAGE_SIZE) {
+	    pushv040(vaddr);
+	    len -= PAGE_SIZE;
+	    vaddr += PAGE_SIZE;
+	    }
+	if (len > 0) {
+	    pushv040(vaddr);
+#if 0
+	    if (((vaddr + len - 1) / PAGE_SIZE) != (vaddr / PAGE_SIZE)) {
+#endif
+	    if (((vaddr + len - 1) ^ vaddr) & PAGE_MASK) {
+		/* a page boundary gets crossed at the end */
+		pushv040(vaddr + len - 1);
+		}
+	    }
+	}
+    else if (m68k_is040or060 == 6) {
+	/* on 68040, push cache lines for pages in the range */
+	while (len > PAGE_SIZE) {
+	    pushv060(vaddr);
+	    len -= PAGE_SIZE;
+	    vaddr += PAGE_SIZE;
+	    }
+	if (len > 0) {
+	    pushv060(vaddr);
+	    if (((vaddr + len - 1) ^ vaddr) & PAGE_MASK) {
+		/* a page boundary gets crossed at the end */
+		pushv060(vaddr + len - 1);
+		}
+	    }
+	}
+    /* 68030/68020 have no writeback cache; still need to clear icache. */
+    else /* 68030 or 68020 */
+	asm volatile ("movec %/cacr,%/d0\n\t"
+		      "oriw %0,%/d0\n\t"
+		      "movec %/d0,%/cacr"
+		      : : "i" (FLUSH_I)
+		      : "d0");
+}
+
+#undef clear040
+#undef push040
+#undef pushv040
+#undef pushv060
+
+unsigned long mm_phys_to_virt (unsigned long addr)
+{
+    return PTOV (addr);
+}
+
+int mm_end_of_chunk (unsigned long addr, int len)
+{
+	int i;
+
+	for (i = 0; i < boot_info.num_memory; i++)
+		if (boot_info.memory[i].addr + boot_info.memory[i].size
+		    == addr + len)
+			return 1;
+	return 0;
+}
+
+/* Map some physical address range into the kernel address space. The
+ * code is copied and adapted from map_chunk().
+ */
+
+unsigned long kernel_map(unsigned long paddr, unsigned long size,
+			 int nocacheflag, unsigned long *memavailp )
+{
+#define STEP_SIZE	(256*1024)
+
+	static unsigned long vaddr = 0xe0000000; /* safe place */
+	unsigned long physaddr, retaddr;
+	pte_t *ktablep = NULL;
+	pmd_t *kpointerp;
+	pgd_t *page_dir;
+	int pindex;   /* index into pointer table */
+	int prot;
+	
+	/* Round down 'paddr' to 256 KB and adjust size */
+	physaddr = paddr & ~(STEP_SIZE-1);
+	size += paddr - physaddr;
+	retaddr = vaddr + (paddr - physaddr);
+	paddr = physaddr;
+	/* Round up the size to 256 KB. It doesn't hurt if too much is
+	 * mapped... */
+	size = (size + STEP_SIZE - 1) & ~(STEP_SIZE-1);
+
+	if (m68k_is040or060) {
+		prot = _PAGE_PRESENT | _PAGE_GLOBAL040;
+		switch( nocacheflag ) {
+		  case KERNELMAP_FULL_CACHING:
+			prot |= _PAGE_CACHE040;
+			break;
+		  case KERNELMAP_NOCACHE_SER:
+		  default:
+			prot |= _PAGE_NOCACHE_S;
+			break;
+		  case KERNELMAP_NOCACHE_NONSER:
+			prot |= _PAGE_NOCACHE;
+			break;
+		  case KERNELMAP_NO_COPYBACK:
+			prot |= _PAGE_CACHE040W;
+			/* prot |= 0; */
+			break;
+		}
+	} else
+		prot = _PAGE_PRESENT |
+			   ((nocacheflag == KERNELMAP_FULL_CACHING ||
+				 nocacheflag == KERNELMAP_NO_COPYBACK) ? 0 : _PAGE_NOCACHE030);
+	
+	page_dir = pgd_offset_k(vaddr);
+	if (pgd_present(*page_dir)) {
+		kpointerp = (pmd_t *)pgd_page(*page_dir);
+		pindex = (vaddr >> 18) & 0x7f;
+		if (pindex != 0 && m68k_is040or060) {
+			if (pmd_present(*kpointerp))
+				ktablep = (pte_t *)pmd_page(*kpointerp);
+			else {
+				ktablep = kernel_page_table (memavailp);
+				/* Make entries invalid */
+				memset( ktablep, 0, sizeof(long)*PTRS_PER_PTE);
+				pmd_set(kpointerp,ktablep);
+			}
+			ktablep += (pindex & 15)*64;
+		}
+	}
+	else {
+		/* we need a new pointer table */
+		kpointerp = get_kpointer_table ();
+		pgd_set(page_dir, (pmd_t *)kpointerp);
+		memset( kpointerp, 0, PTRS_PER_PMD*sizeof(pmd_t));
+		pindex = 0;
+	}
+
+	for (physaddr = paddr; physaddr < paddr + size; vaddr += STEP_SIZE) {
+
+		if (pindex > 127) {
+			/* we need a new pointer table */
+			kpointerp = get_kpointer_table ();
+			pgd_set(pgd_offset_k(vaddr), (pmd_t *)kpointerp);
+			memset( kpointerp, 0, PTRS_PER_PMD*sizeof(pmd_t));
+			pindex = 0;
+		}
+
+		if (m68k_is040or060) {
+			int i;
+			unsigned long ktable;
+
+			/*
+			 * 68040, use page tables pointed to by the
+			 * kernel pointer table.
+			 */
+
+			if ((pindex & 15) == 0) {
+				/* Need new page table every 4M on the '040 */
+				ktablep = kernel_page_table (memavailp);
+				/* Make entries invalid */
+				memset( ktablep, 0, sizeof(long)*PTRS_PER_PTE);
+			}
+
+			ktable = VTOP(ktablep);
+
+			/*
+			 * initialize section of the page table mapping
+			 * this 1M portion.
+			 */
+			for (i = 0; i < 64; i++) {
+				pte_val(*ktablep++) = physaddr | prot;
+				physaddr += PAGE_SIZE;
+			}
+
+			/*
+			 * make the kernel pointer table point to the
+			 * kernel page table.
+			 */
+
+			((unsigned long *)kpointerp)[pindex++] = ktable | _PAGE_TABLE;
+
+		} else {
+			/*
+			 * 68030, use early termination page descriptors.
+			 * Each one points to 64 pages (256K).
+			 */
+			((unsigned long *)kpointerp)[pindex++] = physaddr | prot;
+			physaddr += 64 * PAGE_SIZE;
+		}
+	}
+
+	return( retaddr );
+}
+
+
+static inline void set_cmode_pte( pmd_t *pmd, unsigned long address,
+				  unsigned long size, unsigned cmode )
+{	pte_t *pte;
+	unsigned long end;
+
+	if (pmd_none(*pmd))
+		return;
+
+	pte = pte_offset( pmd, address );
+	address &= ~PMD_MASK;
+	end = address + size;
+	if (end >= PMD_SIZE)
+		end = PMD_SIZE;
+
+	for( ; address < end; pte++ ) {
+		pte_val(*pte) = (pte_val(*pte) & ~_PAGE_NOCACHE) | cmode;
+		address += PAGE_SIZE;
+	}
+}
+
+
+static inline void set_cmode_pmd( pgd_t *dir, unsigned long address,
+				  unsigned long size, unsigned cmode )
+{
+	pmd_t *pmd;
+	unsigned long end;
+
+	if (pgd_none(*dir))
+		return;
+
+	pmd = pmd_offset( dir, address );
+	address &= ~PGDIR_MASK;
+	end = address + size;
+	if (end > PGDIR_SIZE)
+		end = PGDIR_SIZE;
+
+	if ((pmd_val(*pmd) & _DESCTYPE_MASK) == _PAGE_PRESENT) {
+		/* 68030 early termination descriptor */
+		pmd_val(*pmd) = (pmd_val(*pmd) & ~_PAGE_NOCACHE) | cmode;
+		return;
+	}
+	else {
+		/* "normal" tables */
+		for( ; address < end; pmd++ ) {
+			set_cmode_pte( pmd, address, end - address, cmode );
+			address = (address + PMD_SIZE) & PMD_MASK;
+		}
+	}
+}
+
+
+/*
+ * Set new cache mode for some kernel address space.
+ * The caller must push data for that range itself, if such data may already
+ * be in the cache.
+ */
+
+void kernel_set_cachemode( unsigned long address, unsigned long size,
+						   unsigned cmode )
+{
+	pgd_t *dir = pgd_offset_k( address );
+	unsigned long end = address + size;
+	
+	if (m68k_is040or060) {
+		switch( cmode ) {
+		  case KERNELMAP_FULL_CACHING:
+			cmode = _PAGE_CACHE040;
+			break;
+		  case KERNELMAP_NOCACHE_SER:
+		  default:
+			cmode = _PAGE_NOCACHE_S;
+			break;
+		  case KERNELMAP_NOCACHE_NONSER:
+			cmode = _PAGE_NOCACHE;
+			break;
+		  case KERNELMAP_NO_COPYBACK:
+			cmode = _PAGE_CACHE040W;
+			break;
+		}
+	} else
+		cmode = ((cmode == KERNELMAP_FULL_CACHING ||
+				  cmode == KERNELMAP_NO_COPYBACK)    ?
+			 0 : _PAGE_NOCACHE030);
+
+	for( ; address < end; dir++ ) {
+		set_cmode_pmd( dir, address, end - address, cmode );
+		address = (address + PGDIR_SIZE) & PGDIR_MASK;
+	}
+	flush_tlb_all();
+}
+
+
diff -u --recursive --new-file v1.3.93/linux/arch/sparc/kernel/devices.c linux/arch/sparc/kernel/devices.c
--- v1.3.93/linux/arch/sparc/kernel/devices.c	Sun Apr 21 19:21:59 1996
+++ linux/arch/sparc/kernel/devices.c	Mon Apr 22 10:59:39 1996
@@ -5,11 +5,12 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/tasks.h>
 #include <linux/config.h>
 
 #include <asm/page.h>
 #include <asm/oplib.h>
-#include <asm/mp.h>
+#include <asm/smp.h>
 #include <asm/system.h>
 
 struct prom_cpuinfo linux_cpus[NCPUS];
diff -u --recursive --new-file v1.3.93/linux/arch/sparc/kernel/probe.c linux/arch/sparc/kernel/probe.c
--- v1.3.93/linux/arch/sparc/kernel/probe.c	Sun Apr 21 19:22:00 1996
+++ linux/arch/sparc/kernel/probe.c	Thu Jan  1 02:00:00 1970
@@ -1,464 +0,0 @@
-/* $Id: probe.c,v 1.42 1995/12/26 01:38:08 davem Exp $
- * probe.c: Preliminary device tree probing routines...
- *
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- */
-
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/sched.h>
-#include <linux/string.h>
-
-#include <asm/oplib.h>
-#include <asm/vac-ops.h>
-#include <asm/idprom.h>
-#include <asm/machines.h>
-#include <asm/io.h>
-#include <asm/vaddrs.h>
-#include <asm/param.h>
-#include <asm/timer.h>
-#include <asm/mostek.h>
-#include <asm/auxio.h>
-#include <asm/system.h>
-#include <asm/mp.h>
-#include <asm/mbus.h>
-
-/* #define DEBUG_PROBING */
-
-/* XXX Grrr, this stuff should have it's own file, only generic stuff goes
- * XXX here.  Possibly clock.c and timer.c?  This file should get smaller
- * XXX and smaller as time goes on...
- */
-enum sparc_clock_type sp_clock_typ;
-struct mostek48t02 *mstk48t02_regs = 0;
-struct mostek48t08 *mstk48t08_regs = 0;
-volatile unsigned int *master_l10_limit = 0;
-volatile unsigned int *master_l10_counter = 0;
-struct sun4m_timer_regs *sun4m_timers;
-
-static char node_str[128];
-
-/* Cpu-type information and manufacturer strings */
-
-struct cpu_iu_info {
-  int psr_impl;
-  int psr_vers;
-  char* cpu_name;   /* should be enough I hope... */
-};
-
-struct cpu_fp_info {
-  int psr_impl;
-  int fp_vers;
-  char* fp_name;
-};
-
-/* In order to get the fpu type correct, you need to take the IDPROM's
- * machine type value into consideration too.  I will fix this.
- */
-struct cpu_fp_info linux_sparc_fpu[] = {
-  { 0, 0, "Fujitsu MB86910 or Weitek WTL1164/5"},
-  { 0, 1, "Fujitsu MB86911 or Weitek WTL1164/5 or LSI L64831"},
-  { 0, 2, "LSI Logic L64802 or Texas Instruments ACT8847"},
-  /* SparcStation SLC, SparcStation1 */
-  { 0, 3, "Weitek WTL3170/2"},
-  /* SPARCstation-5 */
-  { 0, 4, "Lsi Logic/Meiko L64804 or compatible"},
-  { 0, 5, "reserved"},
-  { 0, 6, "reserved"},
-  { 0, 7, "No FPU"},
-  { 1, 0, "ROSS HyperSparc combined IU/FPU"},
-  { 1, 1, "Lsi Logic L64814"},
-  { 1, 2, "Texas Instruments TMS390-C602A"},
-  { 1, 3, "Cypress CY7C602 FPU"},
-  { 1, 4, "reserved"},
-  { 1, 5, "reserved"},
-  { 1, 6, "reserved"},
-  { 1, 7, "No FPU"},
-  { 2, 0, "BIT B5010 or B5110/20 or B5210"},
-  { 2, 1, "reserved"},
-  { 2, 2, "reserved"},
-  { 2, 3, "reserved"},
-  { 2, 4, "reserved"},
-  { 2, 5, "reserved"},
-  { 2, 6, "reserved"},
-  { 2, 7, "No FPU"},
-  /* SuperSparc 50 module */
-  { 4, 0, "SuperSparc on-chip FPU"},
-  /* SparcClassic */
-  { 4, 4, "TI MicroSparc on chip FPU"},
-  { 5, 0, "Matsushita MN10501"},
-  { 5, 1, "reserved"},
-  { 5, 2, "reserved"},
-  { 5, 3, "reserved"},
-  { 5, 4, "reserved"},
-  { 5, 5, "reserved"},
-  { 5, 6, "reserved"},
-  { 5, 7, "No FPU"},
-};
-
-#define NSPARCFPU  (sizeof(linux_sparc_fpu)/sizeof(struct cpu_fp_info))
-
-struct cpu_iu_info linux_sparc_chips[] = {
-  /* Sun4/100, 4/200, SLC */
-  { 0, 0, "Fujitsu  MB86900/1A or LSI L64831 SparcKIT-40"},
-  /* borned STP1012PGA */
-  { 0, 4, "Fujitsu  MB86904"},
-  /* SparcStation2, SparcServer 490 & 690 */
-  { 1, 0, "LSI Logic Corporation - L64811"},
-  /* SparcStation2 */
-  { 1, 1, "Cypress/ROSS CY7C601"},
-  /* Embedded controller */
-  { 1, 3, "Cypress/ROSS CY7C611"},
-  /* Ross Technologies HyperSparc */
-  { 1, 0xf, "ROSS HyperSparc RT620"},
-  { 1, 0xe, "ROSS HyperSparc RT625"},
-  /* ECL Implementation, CRAY S-MP Supercomputer... AIEEE! */
-  /* Someone please write the code to support this beast! ;) */
-  { 2, 0, "Bipolar Integrated Technology - B5010"},
-  { 3, 0, "LSI Logic Corporation - unknown-type"},
-  { 4, 0, "Texas Instruments, Inc. - SuperSparc 50"},
-  /* SparcClassic  --  borned STP1010TAB-50*/
-  { 4, 1, "Texas Instruments, Inc. - MicroSparc"},
-  { 4, 2, "Texas Instruments, Inc. - MicroSparc II"},
-  { 4, 3, "Texas Instruments, Inc. - SuperSparc 51"},
-  { 4, 4, "Texas Instruments, Inc. - SuperSparc 61"},
-  { 4, 5, "Texas Instruments, Inc. - unknown"},
-  { 5, 0, "Matsushita - MN10501"},
-  { 6, 0, "Philips Corporation - unknown"},
-  { 7, 0, "Harvest VLSI Design Center, Inc. - unknown"},
-  /* Gallium arsenide 200MHz, BOOOOGOOOOMIPS!!! */
-  { 8, 0, "Systems and Processes Engineering Corporation (SPEC)"},
-  { 9, 0, "Fujitsu #3"},
-  { 0xa, 0, "UNKNOWN CPU-VENDOR/TYPE"},
-  { 0xb, 0, "UNKNOWN CPU-VENDOR/TYPE"},
-  { 0xc, 0, "UNKNOWN CPU-VENDOR/TYPE"},
-  { 0xd, 0, "UNKNOWN CPU-VENDOR/TYPE"},
-  { 0xe, 0, "UNKNOWN CPU-VENDOR/TYPE"},
-  { 0xf, 0, "UNKNOWN CPU-VENDOR/TYPE"},
-};
-
-#define NSPARCCHIPS  (sizeof(linux_sparc_chips)/sizeof(struct cpu_iu_info))
-
-char *sparc_cpu_type[NCPUS] = { "cpu-oops", "cpu-oops1", "cpu-oops2", "cpu-oops3" };
-char *sparc_fpu_type[NCPUS] = { "fpu-oops", "fpu-oops1", "fpu-oops2", "fpu-oops3" };
-
-static inline int find_mmu_num_contexts(int cpu)
-{
-	return prom_getintdefault(cpu, "mmu-nctx", 0x8);
-}
-
-unsigned int fsr_storage;
-
-void
-probe_cpu(void)
-{
-	int psr_impl, psr_vers, fpu_vers;
-	int i, cpuid;
-
-	cpuid = get_cpuid();
-
-	psr_impl = ((get_psr()>>28)&0xf);
-	psr_vers = ((get_psr()>>24)&0xf);
-
-	fpu_vers = ((get_fsr()>>17)&0x7);
-
-	for(i = 0; i<NSPARCCHIPS; i++) {
-		if(linux_sparc_chips[i].psr_impl == psr_impl)
-			if(linux_sparc_chips[i].psr_vers == psr_vers) {
-				sparc_cpu_type[cpuid] = linux_sparc_chips[i].cpu_name;
-				break;
-			}
-	}
-
-	if(i==NSPARCCHIPS)
-		printk("DEBUG: psr.impl = 0x%x   psr.vers = 0x%x\n", psr_impl, 
-			    psr_vers);
-
-	for(i = 0; i<NSPARCFPU; i++) {
-		if(linux_sparc_fpu[i].psr_impl == psr_impl)
-			if(linux_sparc_fpu[i].fp_vers == fpu_vers) {
-				sparc_fpu_type[cpuid] = linux_sparc_fpu[i].fp_name;
-				break;
-			}
-	}
-
-	if(i == NSPARCFPU) {
-		printk("DEBUG: psr.impl = 0x%x  fsr.vers = 0x%x\n", psr_impl,
-			    fpu_vers);
-		sparc_fpu_type[cpuid] = linux_sparc_fpu[31].fp_name;
-	}
-}
-
-void
-probe_vac(void)
-{
-	int propval;
-
-	sun4c_disable_vac();
-	sun4c_vacinfo.num_bytes = prom_getintdefault(prom_root_node,
-						     "vac-size", 65536);
-	sun4c_vacinfo.linesize = prom_getintdefault(prom_root_node,
-						    "vac-linesize", 16);
-	sun4c_vacinfo.num_lines =
-		(sun4c_vacinfo.num_bytes / sun4c_vacinfo.linesize);
-	switch(sun4c_vacinfo.linesize) {
-	case 16:
-		sun4c_vacinfo.log2lsize = 4;
-		break;
-	case 32:
-		sun4c_vacinfo.log2lsize = 5;
-		break;
-	default:
-		prom_printf("probe_vac: Didn't expect vac-linesize of %d, halting\n",
-			    sun4c_vacinfo.linesize);
-		prom_halt();
-	};
-
-	propval = prom_getintdefault(prom_root_node, "vac_hwflush", -1);
-	sun4c_vacinfo.do_hwflushes = (propval == -1 ?
-				      prom_getintdefault(prom_root_node,
-							 "vac-hwflush", 0) :
-				      propval);
-
-	if(sun4c_vacinfo.num_bytes != 65536) {
-		prom_printf("WEIRD Sun4C VAC cache size, tell davem");
-		prom_halt();
-	}
-
-	sun4c_flush_all();
-	sun4c_enable_vac();
-}
-
-extern int num_segmaps, num_contexts;
-
-/* XXX Only called on sun4c XXX */
-void
-probe_mmu(void)
-{
-	int cpuid;
-
-	/* who are we? */
-	cpuid = get_cpuid();
-	switch(sparc_cpu_model) {
-	case sun4:
-	case sun4c:
-	case sun4e:
-		/* A sun4, sun4c or sun4e. */
-		num_segmaps = prom_getintdefault(prom_root_node, "mmu-npmg", 128);
-		num_contexts = find_mmu_num_contexts(prom_root_node);
-		break;
-	default:
-		printk("cpu%d probe_mmu: sparc_cpu_model botch\n", cpuid);
-		break;
-	};
-}
-
-/* Clock probing, we probe the timers here also. */
-volatile unsigned int foo_limit;
-
-void
-probe_clock(int fchild)
-{
-	register int node, type;
-	struct linux_prom_registers clk_reg[2];
-
-	/* This will basically traverse the node-tree of the prom to see
-	 * which timer chip is on this machine.
-	 */
-
-	node = 0;
-	if(sparc_cpu_model == sun4) {
-		printk("probe_clock: No SUN4 Clock/Timer support yet...\n");
-		return;
-	}
-	if(sparc_cpu_model == sun4c) node=prom_getchild(prom_root_node);
-	else
-		if(sparc_cpu_model == sun4m)
-			node=prom_getchild(prom_searchsiblings(prom_getchild(prom_root_node), "obio"));
-	type = 0;
-	sp_clock_typ = MSTK_INVALID;
-	for(;;) {
-		prom_getstring(node, "model", node_str, sizeof(node_str));
-		if(strcmp(node_str, "mk48t02") == 0) {
-			sp_clock_typ = MSTK48T02;
-			if(prom_getproperty(node, "reg", (char *) clk_reg, sizeof(clk_reg)) == -1) {
-				printk("probe_clock: FAILED!\n");
-				halt();
-			}
-			prom_apply_obio_ranges(clk_reg, 1);
-			/* Map the clock register io area read-only */
-			mstk48t02_regs = (struct mostek48t02 *) 
-				sparc_alloc_io((void *) clk_reg[0].phys_addr,
-					       (void *) 0, sizeof(*mstk48t02_regs),
-					       "clock", 0x0, 0x0);
-			mstk48t08_regs = 0;  /* To catch weirdness */
-			break;
-		}
-
-		if(strcmp(node_str, "mk48t08") == 0) {
-			sp_clock_typ = MSTK48T08;
-			if(prom_getproperty(node, "reg", (char *) clk_reg,
-					    sizeof(clk_reg)) == -1) {
-				printk("probe_clock: FAILED!\n");
-				halt();
-			}
-			prom_apply_obio_ranges(clk_reg, 1);
-			/* Map the clock register io area read-only */
-			mstk48t08_regs = (struct mostek48t08 *)
-				sparc_alloc_io((void *) clk_reg[0].phys_addr,
-					       (void *) 0, sizeof(*mstk48t08_regs),
-					       "clock", 0x0, 0x0);
-
-			mstk48t02_regs = &mstk48t08_regs->regs;
-			break;
-		}
-
-		node = prom_getsibling(node);
-		if(node == 0) {
-			printk("Aieee, could not find timer chip type\n");
-			return;
-		}
-	}
-
-	if(sparc_cpu_model == sun4c) {
-		/* Map the Timer chip, this is implemented in hardware inside
-		 * the cache chip on the sun4c.
-		 */
-		sparc_alloc_io ((void *) SUN4C_TIMER_PHYSADDR, (void *) TIMER_VADDR,
-				sizeof (*SUN4C_TIMER_STRUCT), "timer", 0x0, 0x0);
-
-		/* Have the level 10 timer tick at 100HZ.  We don't touch the
-		 * level 14 timer limit since we are letting the prom handle
-		 * them until we have a real console driver so L1-A works.
-		 */
-		SUN4C_TIMER_STRUCT->timer_limit10 = (((1000000/HZ) + 1) << 10);
-		master_l10_limit = &(SUN4C_TIMER_STRUCT->timer_limit10);
-		master_l10_counter = &(SUN4C_TIMER_STRUCT->cur_count10);
-	} else {
-		int reg_count;
-		struct linux_prom_registers cnt_regs[PROMREG_MAX];
-		int obio_node, cnt_node;
-
-		cnt_node = 0;
-		if((obio_node =
-		    prom_searchsiblings (prom_getchild(prom_root_node), "obio")) == 0 ||
-		   (obio_node = prom_getchild (obio_node)) == 0 ||
-		   (cnt_node = prom_searchsiblings (obio_node, "counter")) == 0) {
-			printk ("Cannot find /obio/counter node\n");
-			prom_halt ();
-		}
-		reg_count = prom_getproperty(cnt_node, "reg",
-					     (void *) cnt_regs, sizeof(cnt_regs));
-		reg_count = (reg_count/sizeof(struct linux_prom_registers));
-
-		/* Apply the obio ranges to the timer registers. */
-		prom_apply_obio_ranges(cnt_regs, reg_count);
-
-		/* Map the per-cpu Counter registers. */
-		sparc_alloc_io(cnt_regs[0].phys_addr, (void *) TIMER_VADDR,
-			       PAGE_SIZE*NCPUS, "counters_percpu",
-			       cnt_regs[0].which_io, 0x0);
-
-		/* Map the system Counter register. */
-		sparc_alloc_io(cnt_regs[reg_count-1].phys_addr,
-			       (void *) TIMER_VADDR+(NCPUS*PAGE_SIZE),
-			       cnt_regs[reg_count-1].reg_size,
-			       "counters_system", cnt_regs[reg_count-1].which_io, 0x0);
-		sun4m_timers = (struct sun4m_timer_regs *) TIMER_VADDR;
-
-		/* Avoid interrupt bombs... */
-		foo_limit = (volatile) sun4m_timers->l10_timer_limit;
-
-		/* Must set the master pointer first or we will lose badly. */
-		master_l10_limit =
-			&(((struct sun4m_timer_regs *)TIMER_VADDR)->l10_timer_limit);
-		master_l10_counter =
-			&(((struct sun4m_timer_regs *)TIMER_VADDR)->l10_cur_count);
-
-		((struct sun4m_timer_regs *)TIMER_VADDR)->l10_timer_limit =
-			(((1000000/HZ) + 1) << 10);
-	}
-}
-
-/* Probe and map in the Auxiliaary I/O register */
-void
-probe_auxio(void)
-{
-	int node, auxio_nd;
-	struct linux_prom_registers auxregs[1];
-
-	node = prom_getchild(prom_root_node);
-	auxio_nd = prom_searchsiblings(node, "auxiliary-io");
-	if(!auxio_nd) {
-		node = prom_searchsiblings(node, "obio");
-		node = prom_getchild(node);
-		auxio_nd = prom_searchsiblings(node, "auxio");
-		if(!auxio_nd) {
-			printk("Cannot find auxio node, cannot continue...\n");
-			prom_halt();
-		}
-	}
-	prom_getproperty(auxio_nd, "reg", (char *) auxregs, sizeof(auxregs));
-	prom_apply_obio_ranges(auxregs, 0x1);
-	/* Map the register both read and write */
-	sparc_alloc_io(auxregs[0].phys_addr, (void *) AUXIO_VADDR,
-		       auxregs[0].reg_size, "auxilliaryIO", auxregs[0].which_io, 0x0);
-}
-
-extern unsigned long probe_memory(void);
-extern struct sparc_phys_banks sp_banks[SPARC_PHYS_BANKS];
-unsigned int phys_bytes_of_ram, end_of_phys_memory;
-extern void probe_mbus(void);
-
-/* #define DEBUG_PROBE_DEVICES */
-struct prom_cpuinfo linux_cpus[NCPUS];
-int linux_num_cpus;
-
-unsigned long
-probe_devices(unsigned long mem_start)
-{
-	int nd, i, prom_node_cpu, thismid;
-	int cpu_nds[NCPUS];  /* One node for each cpu */
-	int cpu_ctr = 0;
-
-	prom_getstring(prom_root_node, "device_type", node_str, sizeof(node_str));
-	if(strcmp(node_str, "cpu") == 0) {
-		cpu_nds[0] = prom_root_node;
-		cpu_ctr++;
-	} else {
-		int scan;
-		scan = prom_getchild(prom_root_node);
-		nd = 0;
-		while((scan = prom_getsibling(scan)) != 0) {
-			prom_getstring(scan, "device_type", node_str, sizeof(node_str));
-			if(strcmp(node_str, "cpu") == 0) {
-				cpu_nds[cpu_ctr] = scan;
-				linux_cpus[cpu_ctr].prom_node = scan;
-				prom_getproperty(scan, "mid", (char *) &thismid, sizeof(thismid));
-				linux_cpus[cpu_ctr].mid = thismid;
-				cpu_ctr++;
-			}
-		};
-		if(cpu_ctr == 0) {
-			printk("No CPU nodes found, cannot continue.\n");
-			/* Probably a sun4d or sun4e, Sun is trying to trick us ;-) */
-			halt();
-		}
-		printk("Found %d CPU prom device tree node(s).\n", cpu_ctr);
-	};
-	prom_node_cpu = cpu_nds[0];
-
-	linux_num_cpus = cpu_ctr;
-	for(i=0; i<cpu_ctr; i++) {
-		prom_getstring(cpu_nds[i], "name", node_str, sizeof(node_str));
-#if 0
-		printk("cpu%d: %s \n", i, node_str);
-#endif
-	}
-
-	probe_cpu();
-	probe_auxio();
-	if(sparc_cpu_model != sun4c) probe_mbus();
-
-	return mem_start;
-}
diff -u --recursive --new-file v1.3.93/linux/arch/sparc/kernel/tadpole.c linux/arch/sparc/kernel/tadpole.c
--- v1.3.93/linux/arch/sparc/kernel/tadpole.c	Sun Apr 21 19:22:01 1996
+++ linux/arch/sparc/kernel/tadpole.c	Mon Apr 22 10:59:39 1996
@@ -41,18 +41,16 @@
 
 static void clk_slow(void)
 {
-	__asm__ __volatile__("save %sp, -0x68, %sp\n\t"
-			     "set _clk_ctrl, %l0\n\t"
-			     "ld [%l0], %l0\n\t"
-			     "mov 0xcc, %l1\n\t"
-			     "mov 0x4c, %l2\n\t"
-			     "mov 0xcf, %l3\n\t"
-			     "mov 0xdf, %l4\n\t"
-			     "stb %l1, [%l0+3]\n\t"
-			     "stb %l2, [%l0+3]\n\t"
-			     "stb %l3, [%l0+3]\n\t"
-			     "stb %l4, [%l0+3]\n\t"
-			     "restore\n\t");
+	__asm__ __volatile__("mov 0xcc, %%g2\n\t"
+			     "mov 0x4c, %%g3\n\t"
+			     "mov 0xcf, %%g4\n\t"
+			     "mov 0xdf, %%g5\n\t"
+			     "stb %%g2, [%0+3]\n\t"
+			     "stb %%g3, [%0+3]\n\t"
+			     "stb %%g4, [%0+3]\n\t"
+			     "stb %%g5, [%0+3]\n\t" : :
+			     "r" (clk_ctrl) :
+			     "g2", "g3", "g4", "g5");
 }
 
 static void tsu_clockstop(void)
diff -u --recursive --new-file v1.3.93/linux/arch/sparc/mm/mbus.c linux/arch/sparc/mm/mbus.c
--- v1.3.93/linux/arch/sparc/mm/mbus.c	Sat Nov 25 02:59:27 1995
+++ linux/arch/sparc/mm/mbus.c	Thu Jan  1 02:00:00 1970
@@ -1,186 +0,0 @@
-/* $Id: mbus.c,v 1.9 1995/11/25 00:59:26 davem Exp $
- * mbus.c: MBUS probing routines, called from kernel/probe.c
- *
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- */
-
-#include <linux/kernel.h>
-
-#include <asm/oplib.h>
-#include <asm/cache.h>
-#include <asm/page.h>
-#include <asm/pgtable.h>
-#include <asm/asi.h>
-#include <asm/psr.h>
-#include <asm/vac-ops.h>
-#include <asm/mbus.h>
-
-/* #define DEBUG_MBUS */
-
-unsigned int viking_rev, swift_rev, cypress_rev;
-enum mbus_module srmmu_modtype;
-unsigned int hwbug_bitmask;
-
-void
-probe_mbus(void)
-{
-	register unsigned int mreg, vaddr;
-	register int impl, vers, syscntrl, pso, resv, nofault, enable;
-	register int mod_typ, mod_rev;
-
-	srmmu_modtype = SRMMU_INVAL_MOD;
-	hwbug_bitmask = 0;
-	vaddr = 0;
-
-	mreg = srmmu_get_mmureg();
-	impl = (mreg & SRMMU_CTREG_IMPL_MASK) >> SRMMU_CTREG_IMPL_SHIFT;
-	vers = (mreg & SRMMU_CTREG_VERS_MASK) >> SRMMU_CTREG_VERS_SHIFT;
-	syscntrl = (mreg & SRMMU_CTREG_SYSCNTRL_MASK) >> SRMMU_CTREG_SYSCNTRL_SHIFT;
-	pso = (mreg & SRMMU_CTREG_PSO_MASK) >> SRMMU_CTREG_PSO_SHIFT;
-	resv = (mreg & SRMMU_CTREG_RESV_MASK) >> SRMMU_CTREG_RESV_SHIFT;
-	nofault = (mreg & SRMMU_CTREG_NOFAULT_MASK) >> SRMMU_CTREG_NOFAULT_SHIFT;
-	enable = (mreg & SRMMU_CTREG_ENABLE_MASK) >> SRMMU_CTREG_ENABLE_SHIFT;
-
-#ifdef DEBUG_MBUS
-	printk("MMU REGISTER\n");
-	printk("IMPL<%01x> VERS<%01x> SYSCNTRL<%04x> PSO<%d> RESV<%02x> NOFAULT<%d> ENABLE<%d>\n",
-	       impl, vers, syscntrl, (int) pso, resv, (int) nofault, (int) enable);
-#endif
-
-	mod_typ = impl; mod_rev = vers;
-	printk("MBUS: ");
-
-	if(mod_typ == 0x1) /* Ross HyperSparc or Cypress */
-		if (mod_rev == 0x7) {
-			srmmu_modtype = HyperSparc;
-			hwbug_bitmask |= HWBUG_VACFLUSH_BITROT;
-			/* Turn off Cache Wrapping and copyback caching, I don't
-			 * understand them completely yet... */
-			printk("Enabling HyperSparc features...\n");
-			/* FUCK IT, I wanna see this baby chug! */
-			/* First, flush the cache */
-#if 0
-			for(vaddr = 0; vaddr != vac_size; vaddr+=vac_linesize)
-				flush_ei_ctx(vaddr);
-#endif
-			mreg &= (~HYPERSPARC_CWENABLE);
-			mreg &= (~HYPERSPARC_CMODE);
-			mreg &= (~HYPERSPARC_WBENABLE);
-			mreg |= (HYPERSPARC_CENABLE);
-			srmmu_set_mmureg(mreg);
-			/* Clear all the cache tags */
-#if 0
-			for(vaddr = 0; vaddr != vac_size; vaddr+=vac_linesize)
-				__asm__ __volatile__("sta %%g0, [%0] %1" : :
-						     "r" (vaddr), "i" (0xe));
-#endif
-			/* Flush the ICACHE */
-			flush_whole_icache();
-
-		} else {
-			cypress_rev = mod_rev;
-			if(mod_rev == 0xe) {
-				srmmu_modtype = Cypress_vE;
-				hwbug_bitmask |= HWBUG_COPYBACK_BROKEN;
-			} else
-				if(mod_rev == 0xd) {
-					srmmu_modtype = Cypress_vD;
-					hwbug_bitmask |= HWBUG_ASIFLUSH_BROKEN;
-				} else
-					srmmu_modtype = Cypress;
-
-			/* It is a Cypress module */
-			printk("ROSS Cypress Module %s\n",
-			       (srmmu_modtype == Cypress_vE ? "Rev. E" :
-				(srmmu_modtype == Cypress_vD ? "Rev. D" :
-				 "")));
-				/* Enable Cypress features */
-				printk("Enabling Cypress features...\n");
-				mreg &= (~CYPRESS_CMODE);
-				mreg |= (CYPRESS_CENABLE);
-				srmmu_set_mmureg(mreg);
-				/* Maybe play with Cypress 604/605 cache stuff here? */
-		}
-
-
-	if(((get_psr()>>0x18)&0xff)==0x04) {
-		__asm__ __volatile__("lda [%1] %2, %0\n\t" 
-				     "srl %0, 0x18, %0\n\t" :
-				     "=r" (swift_rev) :
-				     "r" (0x10003000), "i" (0x20));
-		printk("Fujitsu MB86904 or higher Swift module\n");  /* MB86905 etc. */
-		switch(swift_rev) {
-		case 0x11:
-		case 0x20:
-		case 0x23:
-		case 0x30:
-			srmmu_modtype = Swift_lots_o_bugs;
-			hwbug_bitmask |= HWBUG_KERN_ACCBROKEN;
-			hwbug_bitmask |= HWBUG_KERN_CBITBROKEN;
-			printk("Detected Swift with Lots 'o' Bugs\n");
-			break;
-		case 0x25:
-		case 0x31:
-			srmmu_modtype = Swift_bad_c;
-			hwbug_bitmask |= HWBUG_KERN_CBITBROKEN;
-			printk("Detected Swift with kernel pte C bit bug\n");
-			break;
-		default:
-			srmmu_modtype = Swift_ok;
-			printk("Detected Swift with no bugs...\n");
-			break;
-		}
-		/* Enable Fujitsu Swift specific features here... */
-		printk("Enabling Swift features...\n");
-		mreg |= 0;
-		srmmu_set_mmureg(mreg);
-	}
-
-	if((((get_psr()>>0x18)&0xff)==0x40 ||
-	    (((get_psr()>>0x18)&0xff)==0x41 && mod_typ==0 && mod_rev==0))) {
-		if(((get_psr()>>0x18)&0xf)==0 && mod_rev==0) {
-			srmmu_modtype = Viking_12;
-			hwbug_bitmask |= HWBUG_MODIFIED_BITROT;
-			hwbug_bitmask |= HWBUG_PC_BADFAULT_ADDR;
-		} else {
-			if(((get_psr()>>0x18)&0xf)!=0) {
-				srmmu_modtype = Viking_2x;
-				hwbug_bitmask |= HWBUG_PC_BADFAULT_ADDR;
-			} else
-				if(mod_rev==1) {
-					srmmu_modtype = Viking_30;
-					hwbug_bitmask |= HWBUG_PACINIT_BITROT;
-				} else  {
-					if (mod_rev<8)
-						srmmu_modtype = Viking_35;
-					else
-						srmmu_modtype = Viking_new;
-				}
-		}
-
-		/* SPARCclassic's STP1010 may be produced under other name */
-		printk("VIKING Module\n");
-		printk("Enabling Viking features...\n");
-		mreg |= (VIKING_DCENABLE | VIKING_ICENABLE | VIKING_SBENABLE |
-			 VIKING_TCENABLE | VIKING_DPENABLE);
-		srmmu_set_mmureg(mreg);
-	}
-   
-	if((((get_psr()>>0x18)&0xff)==0x41) && (mod_typ || mod_rev)) {
-		srmmu_modtype = Tsunami;
-		printk("Tsunami module\n");
-		/* Enable Tsunami features */
-	}
-
-	if(srmmu_modtype == SRMMU_INVAL_MOD) {
-		printk("Unknown SRMMU module type!\n");
-		printk("MMU_CREG: impl=%x vers=%x\n", mod_typ, mod_rev);
-		printk("PSR: impl=%x vers=%x\n", ((get_psr()>>28)&0xf),
-		       ((get_psr()>>24)&0xf));
-		panic("probe_mbus()");
-	}
-
-	/* AIEEE, should get this from the prom... */
-	printk("Boot processor ID %d Module ID %d (%s MBUS)\n",
-	       get_cpuid(), get_modid(), (get_modid() == 0x8 ? "Level 1" : "Level 2"));
-}
diff -u --recursive --new-file v1.3.93/linux/arch/sparc/mm/srmmu_mp.S linux/arch/sparc/mm/srmmu_mp.S
--- v1.3.93/linux/arch/sparc/mm/srmmu_mp.S	Sun Apr 21 19:22:01 1996
+++ linux/arch/sparc/mm/srmmu_mp.S	Thu Jan  1 02:00:00 1970
@@ -1,52 +0,0 @@
-/* srmmu_mp.S:	Low level invalidates for MP SRMMU modules.
- *
- * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
- */
-#include <asm/cprefix.h>
-#include <asm/asi.h>
-
-	/* Protocol is:
-	 *
-	 * %l0 --> %l3  NO TOUCH
-	 * %l7          NO TOUCH
-	 * %l6		return address - 0x8
-	 * %l4, %l5     what we can use
-	 */
-
-	.globl	C_LABEL(hyper_invalidate_low)
-C_LABEL(hyper_invalidate_low):
-	/* First the on-chip cache. */
-	set	C_LABEL(hyper_cache_size), %l5
-	ld	[%l5], %l5
-1:
-	subcc	%l5, 32, %l5
-	bne	1b
-	 sta	%g0, [%l5] ASI_M_FLUSH_CTX
-
-	/* Now the on-chip ICACHE. */
-	sta	%g0, [%g0] ASI_M_FLUSH_IWHOLE
-
-	/* Flush the TLB and return. */
-	mov	0x400, %l4
-	sta	%g0, [%l4] ASI_M_FLUSH_PROBE
-
-	jmpl	%l6 + 0x8, %g0
-	 nop
-
-	.globl	C_LABEL(viking_invalidate_low)
-C_LABEL(viking_invalidate_low):
-	/* Flash clear the I/D caches. */
-	sta	%g0, [%g0] ASI_M_IC_FLCLEAR
-	sta	%g0, [%g0] ASI_M_DC_FLCLEAR
-
-	/* Flush the TLB and return. */
-	mov	0x400, %l4
-	sta	%g0, [%l4] ASI_M_FLUSH_PROBE
-
-	jmpl	%l6 + 0x8, %g0
-	 nop
-
-	/* XXX Write the Cypress when I get access to
-	 * XXX some modules, poke mossip real hard until
-	 * XXX he takes care of the Nubis upgrade.
-	 */
diff -u --recursive --new-file v1.3.93/linux/drivers/Makefile linux/drivers/Makefile
--- v1.3.93/linux/drivers/Makefile	Mon Feb 26 11:58:04 1996
+++ linux/drivers/Makefile	Mon Apr 22 10:59:39 1996
@@ -9,12 +9,16 @@
 
 SUB_DIRS     := block char net #streams
 MOD_SUB_DIRS := $(SUB_DIRS)
-ALL_SUB_DIRS := $(SUB_DIRS) pci scsi sound cdrom isdn
+ALL_SUB_DIRS := $(SUB_DIRS) pci sbus scsi sound cdrom isdn
 
 ifdef CONFIG_PCI
 SUB_DIRS += pci
 endif
 
+ifdef CONFIG_SBUS
+SUB_DIRS += sbus
+endif
+
 # If CONFIG_SCSI is set, the core of scsi support will be added to the kernel,
 # but some of the low-level things may also be modules.
 ifeq ($(CONFIG_SCSI),y)
@@ -46,6 +50,11 @@
   ifeq ($(CONFIG_ISDN),m)
   MOD_SUB_DIRS += isdn
   endif
+endif
+
+ifeq ($(CONFIG_AP1000),y)
+SUB_DIRS += ap1000
+ALL_SUB_DIRS += ap1000
 endif
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.93/linux/drivers/block/amiflop.c linux/drivers/block/amiflop.c
--- v1.3.93/linux/drivers/block/amiflop.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/block/amiflop.c	Sat Mar 30 14:11:12 1996
@@ -0,0 +1,1782 @@
+/*
+ *  linux/amiga/amiflop.c
+ *
+ *  Copyright (C) 1993  Greg Harp
+ *  Portions of this driver are based on code contributed by Brad Pepers
+ *  
+ *  revised 28.5.95 by Joerg Dorchain
+ *  - now no bugs(?) any more for both HD & DD
+ *  - added support for 40 Track 5.25" drives, 80-track hopefully behaves
+ *    like 3.5" dd (no way to test - are there any 5.25" drives out there
+ *    that work on an A4000?)
+ *  - wrote formatting routine (maybe dirty, but works)
+ *
+ *  june/july 1995 added ms-dos support by Joerg Dorchain
+ *  (portions based on messydos.device and various contributors)
+ *  - currently only 9 and 18 sector disks
+ *
+ *  - fixed a bug with the internal trackbuffer when using multiple 
+ *    disks the same time
+ *  - made formatting a bit safer
+ *  - added command line and machine based default for "silent" df0
+ *
+ *  december 1995 adapted for 1.2.13pl4 by Joerg Dorchain
+ *  - works but I think its inefficient. (look in redo_fd_request)
+ *    But the changes were very efficient. (only three and a half lines)
+ *
+ *  january 1995 added special ioctl for tracking down read/write problems
+ *  - usage ioctl(d, RAW_TRACK, ptr); the raw track buffer (MFM-encoded data
+ *    is copied to area. (area should be large enough since no checking is
+ *    done - 30K is currently sufficient). return the actual size of the
+ *    trackbuffer
+ *  - replaced udelays() by a timer (CIAA timer B) for the waits 
+ *    needed for the disk mechanic.
+ *
+ *  revised Marts 3rd, 1996 by Jes Sorensen for use in the 1.3.28 kernel.
+ *  - Minor changes to accept the kdev_t.
+ *  - Replaced some more udelays with ms_delays. Udelay is just a loop,
+ *    and so the delay will be different depending on the given
+ *    processor :-(
+ *  - The driver could use a major cleanup because of the new
+ *    major/minor handling that came with kdev_t. It seems to work for
+ *    the time being, but I can't guarantee that it will stay like
+ *    that when we start using 16 (24?) bit minors.
+ */
+
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/fcntl.h>
+#include <linux/kernel.h>
+#include <linux/timer.h>
+#include <linux/fd.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+
+#include <asm/amifdreg.h>
+#include <asm/amifd.h>
+#include <asm/amigahw.h>
+#include <asm/amigaints.h>
+#include <asm/irq.h>
+#include <asm/bootinfo.h>
+#include <asm/amigatypes.h>
+
+#define MAJOR_NR FLOPPY_MAJOR
+#include <linux/blk.h>
+
+#undef DEBUG /* print _LOTS_ of infos */
+
+#define RAW_IOCTL
+#ifdef RAW_IOCTL
+#define IOCTL_RAW_TRACK 0x5254524B  /* 'RTRK' */
+#endif
+
+/* prototypes */
+
+static int amiga_read(int,unsigned char *, unsigned long, int);
+static void amiga_write(int, unsigned long, unsigned char *, int);
+static int dos_read(int, unsigned char *, unsigned long, int);
+static void dos_write(int, unsigned long, unsigned char *,int);
+static ushort dos_crc(void *, int, int, int);
+static void fd_probe(int);
+
+
+/*
+ *  Defines
+ */
+#define MAX_SECTORS	22
+
+/*
+ *  Error codes
+ */
+#define FD_OK		0	/* operation succeeded */
+#define FD_ERROR	-1	/* general error (seek, read, write, etc) */
+#define FD_NOUNIT	1	/* unit does not exist */
+#define FD_UNITBUSY	2	/* unit already active */
+#define FD_NOTACTIVE	3	/* unit is not active */
+#define FD_NOTREADY	4	/* unit is not ready (motor not on/no disk) */
+
+/*
+ *  Floppy ID values
+ */
+#define FD_NODRIVE	0x00000000  /* response when no unit is present */
+#define FD_DD_3 	0xffffffff  /* double-density 3.5" (880K) drive */
+#define FD_HD_3 	0x55555555  /* high-density 3.5" (1760K) drive */
+#define FD_DD_5 	0xaaaaaaaa  /* double-density 5.25" (440K) drive */
+
+static int fd_def_df0 = 0;     /* default for df0 if it doesn't identify */
+
+
+/*
+ *  Macros
+ */
+#define MOTOR_ON	(ciab.prb &= ~DSKMOTOR)
+#define MOTOR_OFF	(ciab.prb |= DSKMOTOR)
+#define SELECT(mask)    (ciab.prb &= ~mask)
+#define DESELECT(mask)  (ciab.prb |= mask)
+#define SELMASK(drive)  (1 << (3 + (drive & 3)))
+
+#define DRIVE(x) ((x) & 3)
+#define PROBE(x) ((x) >> 2) & 1)
+#define TYPE(x)  ((x) >> 3) & 2)
+#define DATA(x)  ((x) >> 5) & 3)
+
+static struct fd_drive_type drive_types[] = {
+/*  code	name	   tr he   rdsz   wrsz sm pc1 pc2 sd  st st*/
+/*  warning: times are now in milliseconds (ms)                    */
+ { FD_DD_3,	"DD 3.5", 160, 2, 14716, 13630, 1, 80,161, 3, 18, 1},
+ { FD_HD_3,	"HD 3.5", 160, 2, 28344, 27258, 2, 80,161, 3, 18, 1},
+ { FD_DD_5,	"DD 5.25", 80, 2, 14716, 13630, 1, 40, 81, 6, 30, 2},
+ { FD_NODRIVE, "No Drive", 0, 0,     0,     0, 0,  0,  0,  0,  0, 0}
+};
+static int num_dr_types = sizeof(drive_types) / sizeof(drive_types[0]);
+
+/* defaults for 3 1/2" HD-Disks */
+static int floppy_sizes[256]={880,880,880,880,720,720,720,};
+static int floppy_blocksizes[256]={0,};
+/* hardsector size assumed to be 512 */
+
+static struct fd_data_type data_types[] = {
+  { "Amiga", 11 , amiga_read, amiga_write},
+  { "MS-Dos", 9, dos_read, dos_write}
+};
+static int num_da_types = sizeof(data_types) / sizeof(data_types[0]);
+
+/* current info on each unit */
+static struct amiga_floppy_struct unit[FD_MAX_UNITS];
+
+static struct timer_list flush_track_timer;
+static struct timer_list post_write_timer;
+static struct timer_list motor_on_timer;
+static struct timer_list motor_off_timer[FD_MAX_UNITS];
+static int on_attempts;
+
+/* track buffer */
+static int lastdrive = -1;
+static int savedtrack = -1;
+static int writepending = 0;
+static int writefromint = 0;
+static unsigned char trackdata[MAX_SECTORS * 512];
+static char *raw_buf;
+
+#define RAW_BUF_SIZE 30000  /* size of raw disk data */
+
+/*
+ * These are global variables, as that's the easiest way to give
+ * information to interrupts. They are the data used for the current
+ * request.
+ */
+static char block_flag = 0;
+static int selected = 0;
+static struct wait_queue *wait_fd_block = NULL;
+
+/* Synchronization of FDC access. */
+static volatile int fdc_busy = 0;
+static struct wait_queue *fdc_wait = NULL;
+static struct wait_queue *motor_wait = NULL;
+
+/* MS-Dos MFM Coding tables (should go quick and easy) */
+static unsigned char mfmencode[16]={
+  0x2a, 0x29, 0x24, 0x25, 0x12, 0x11, 0x14, 0x15,
+  0x4a, 0x49, 0x44, 0x45, 0x52, 0x51, 0x54, 0x55
+};
+static unsigned char mfmdecode[128];
+
+/* floppy internal millisecond timer stuff */
+static struct semaphore ms_sem = MUTEX;
+static struct wait_queue *ms_wait = NULL;
+#define MS_TICKS ((amiga_eclock+50)/1000)
+
+static void ms_isr(int irq, struct pt_regs *fp, void *dummy)
+{
+wake_up(&ms_wait);
+}
+
+/* with the semaphore waits are queued up 
+   A more generic routine would do a schedule a la timer.device */
+static void ms_delay(int ms)
+{
+  int ticks;
+  if (ms > 0) {
+    down(&ms_sem);
+    ticks=MS_TICKS*ms-1;
+    ciaa.tblo=ticks%256;
+    ciaa.tbhi=ticks/256;
+    ciaa.crb=0x19; /* count clock, force load, one-shot, start */
+    sleep_on(&ms_wait);
+    up(&ms_sem);
+  }
+}
+
+/*
+ * Functions
+ */
+/*======================================================================
+  Turn off the motor of the given drive.  Unit must already be active.
+  Returns standard floppy error code.
+======================================================================*/
+static void fd_motor_off(unsigned long drive)
+{
+	unsigned long flags;
+	unsigned char prb = ~0;
+
+	drive&=3;
+	save_flags(flags);
+	cli();
+
+	if (unit[drive].track % 2 != 0)
+		prb &= ~DSKSIDE;
+	ciab.prb |= (SELMASK(0)|SELMASK(1)|SELMASK(2)|SELMASK(3));
+	ciab.prb = prb;
+	prb &= ~SELMASK(drive);
+	ciab.prb = prb;
+	udelay (1);
+	prb |= (SELMASK(0)|SELMASK(1)|SELMASK(2)|SELMASK(3));
+	ciab.prb = prb;
+	selected = -1;
+	unit[drive].motor = 0;
+
+	restore_flags(flags);
+}
+
+static void motor_on_callback(unsigned long nr)
+{
+  nr &= 3;
+
+	if (!(ciaa.pra & DSKRDY) || --on_attempts == 0) {
+		unit[nr].motor = 1;
+		wake_up (&motor_wait);
+	} else {
+		motor_on_timer.expires = jiffies + HZ/10;
+		add_timer(&motor_on_timer);
+	}
+}
+
+static int motor_on(int nr)
+{
+	unsigned long flags;
+	unsigned char prb = ~0;
+
+	nr &= 3;
+	save_flags (flags);
+	cli();
+	del_timer(motor_off_timer + nr);
+
+	if (!unit[nr].motor) {
+		del_timer(&motor_on_timer);
+		motor_on_timer.data = nr;
+		motor_on_timer.expires = jiffies + HZ/2;
+		add_timer(&motor_on_timer);
+		on_attempts = 10;
+
+
+		prb &= ~DSKMOTOR;
+		if (unit[nr].track % 2 != 0)
+			prb &= ~DSKSIDE;
+		ciab.prb |= (SELMASK(0)|SELMASK(1)|SELMASK(2)|SELMASK(3));
+		ciab.prb = prb;
+		prb &= ~SELMASK(nr);
+		ciab.prb = prb;
+		selected = nr;
+
+		while (!unit[nr].motor)
+			sleep_on (&motor_wait);
+	}
+	restore_flags(flags);
+
+	if (on_attempts == 0) {
+		printk ("motor_on failed, turning motor off\n");
+		fd_motor_off (nr);
+		return 0;
+	}
+
+	return 1;
+}
+
+static void floppy_off (unsigned int nr)
+{
+	nr&=3;
+	del_timer(motor_off_timer+nr);
+	motor_off_timer[nr].expires = jiffies + 3*HZ;
+	add_timer(motor_off_timer+nr);
+}
+
+static void fd_select (int drive)
+{
+	unsigned char prb = ~0;
+
+	drive&=3;
+	if (drive == selected)
+		return;
+	selected = drive;
+
+	if (unit[drive].track % 2 != 0)
+		prb &= ~DSKSIDE;
+	if (unit[drive].motor == 1)
+		prb &= ~DSKMOTOR;
+	ciab.prb |= (SELMASK(0)|SELMASK(1)|SELMASK(2)|SELMASK(3));
+	ciab.prb = prb;
+	prb &= ~SELMASK(drive);
+	ciab.prb = prb;
+}
+
+static void fd_deselect (int drive)
+{
+	unsigned char prb;
+	unsigned long flags;
+
+	drive&=3;
+	if (drive != selected)
+		return;
+
+	save_flags (flags);
+	sti();
+
+	selected = -1;
+
+	prb = ciab.prb;
+	prb |= (SELMASK(0)|SELMASK(1)|SELMASK(2)|SELMASK(3));
+	ciab.prb = prb;
+
+	restore_flags (flags);
+
+}
+
+/*======================================================================
+  Seek the drive to track 0.
+  The drive must be active and the motor must be running.
+  Returns standard floppy error code.
+======================================================================*/
+static int fd_calibrate(int drive)
+{
+	unsigned char prb;
+	int n;
+
+	drive &= 3;
+	if (!motor_on (drive))
+		return 0;
+	fd_select (drive);
+	prb = ciab.prb;
+	prb |= DSKSIDE;
+	prb &= ~DSKDIREC;
+	ciab.prb = prb;
+	for (n = unit[drive].type->tracks/4; n != 0; --n) {
+		if (ciaa.pra & DSKTRACK0)
+			break;
+		prb &= ~DSKSTEP;
+		ciab.prb = prb;
+		prb |= DSKSTEP;
+		ms_delay (2);
+		ciab.prb = prb;
+		ms_delay(unit[drive].type->step_delay);
+	}
+	ms_delay (unit[drive].type->settle_time);
+	prb |= DSKDIREC;
+	n = unit[drive].type->tracks/2 + 20;
+	for (;;) {
+		prb &= ~DSKSTEP;
+		ciab.prb = prb;
+		prb |= DSKSTEP;
+		ms_delay (2);
+		ciab.prb = prb;
+		ms_delay(unit[drive].type->step_delay + 1);
+		if ((ciaa.pra & DSKTRACK0) == 0)
+			break;
+		if (--n == 0) {
+			printk ("calibrate failed, turning motor off\n");
+			fd_motor_off (drive);
+			unit[drive].track = -1;
+			return 0;
+		}
+	}
+	unit[drive].track = 0;
+	ms_delay(unit[drive].type->settle_time);
+
+	return 1;
+}
+
+/*======================================================================
+  Seek the drive to the requested cylinder.
+  The drive must have been calibrated at some point before this.
+  The drive must also be active and the motor must be running.
+======================================================================*/
+static int fd_seek(int drive, int track)
+{
+	unsigned char prb;
+	int cnt;
+
+	drive &= 3;
+	if (unit[drive].track == track)
+		return 1;
+	if (!motor_on(drive))
+		return 0;
+	fd_select (drive);
+	if (unit[drive].track < 0 && !fd_calibrate(drive))
+		return 0;
+
+	cnt = unit[drive].track/2 - track/2;
+	prb = ciab.prb;
+	prb |= DSKSIDE | DSKDIREC;
+	if (track % 2 != 0)
+		prb &= ~DSKSIDE;
+	if (cnt < 0) {
+		cnt = - cnt;
+		prb &= ~DSKDIREC;
+	}
+	ciab.prb = prb;
+	if (track % 2 != unit[drive].track % 2)
+		ms_delay (unit[drive].type->side_time);
+	unit[drive].track = track;
+	if (cnt == 0)
+		return 1;
+	do {
+		prb &= ~DSKSTEP;
+		ciab.prb = prb;
+		prb |= DSKSTEP;
+		ms_delay (1);
+		ciab.prb = prb;
+		ms_delay (unit[drive].type->step_delay);
+	} while (--cnt != 0);
+	ms_delay (unit[drive].type->settle_time);
+
+	return 1;
+}
+
+static void encode(unsigned long data, unsigned long *dest)
+{
+  unsigned long data2;
+
+  data &= 0x55555555;
+  data2 = data ^ 0x55555555;
+  data |= ((data2 >> 1) | 0x80000000) & (data2 << 1);
+
+  if (*(dest - 1) & 0x00000001)
+    data &= 0x7FFFFFFF;
+
+  *dest = data;
+}
+
+static void encode_block(unsigned long *dest, unsigned long *src, int len)
+{
+  int cnt, to_cnt = 0;
+  unsigned long data;
+
+  /* odd bits */
+  for (cnt = 0; cnt < len / 4; cnt++) {
+    data = src[cnt] >> 1;
+    encode(data, dest + to_cnt++);
+  }
+
+  /* even bits */
+  for (cnt = 0; cnt < len / 4; cnt++) {
+    data = src[cnt];
+    encode(data, dest + to_cnt++);
+  }
+}
+
+unsigned long checksum(unsigned long *addr, int len)
+{
+	unsigned long csum = 0;
+
+	len /= sizeof(*addr);
+	while (len-- > 0)
+		csum ^= *addr++;
+	csum = ((csum>>1) & 0x55555555)  ^  (csum & 0x55555555);
+
+	return csum;
+}
+
+struct header {
+	unsigned char magic;
+	unsigned char track;
+	unsigned char sect;
+	unsigned char ord;
+	unsigned char labels[16];
+	unsigned long hdrchk;
+	unsigned long datachk;
+};
+
+static unsigned long *putsec(int disk, unsigned long *raw, int track, int cnt,
+			     unsigned char *data)
+{
+	struct header hdr;
+	int i;
+
+	if (!AMIGAHW_PRESENT(AMI_FLOPPY))
+	    return 0;
+
+	disk&=3;
+	*raw = (raw[-1]&1) ? 0x2AAAAAAA : 0xAAAAAAAA;
+	raw++;
+	*raw++ = 0x44894489;
+
+	hdr.magic = 0xFF;
+	hdr.track = track;
+	hdr.sect = cnt;
+	hdr.ord = unit[disk].sects-cnt;
+	for (i = 0; i < 16; i++)
+		hdr.labels[i] = 0;
+	hdr.hdrchk = checksum((ulong *)&hdr,
+			      (char *)&hdr.hdrchk-(char *)&hdr);
+	hdr.datachk = checksum((ulong *)data, 512);
+
+	encode_block(raw, (ulong *)&hdr.magic, 4);
+	raw += 2;
+	encode_block(raw, (ulong *)&hdr.labels, 16);
+	raw += 8;
+	encode_block(raw, (ulong *)&hdr.hdrchk, 4);
+	raw += 2;
+	encode_block(raw, (ulong *)&hdr.datachk, 4);
+	raw += 2;
+	encode_block(raw, (ulong *)data, 512);
+	raw += 256;
+
+	return raw;
+}
+
+
+/*==========================================================================
+  amiga_write converts track/labels data to raw track data
+==========================================================================*/
+static void amiga_write(int disk, unsigned long raw, unsigned char *data,
+			int track)
+{
+	int cnt;
+	unsigned long *ptr = (unsigned long *)raw;
+
+	disk&=3;
+	/* gap space */
+	for (cnt = 0; cnt < 415 * unit[disk].type->sect_mult; cnt++)
+		*ptr++ = 0xaaaaaaaa;
+
+	/* sectors */
+	for (cnt = 0; cnt < unit[disk].sects; cnt++)
+		ptr = putsec (disk, ptr, track, cnt, data + cnt*512);
+	*(ushort *)ptr = (ptr[-1]&1) ? 0x2AA8 : 0xAAA8;
+	raw = (unsigned long)ptr + 2;
+}
+
+static unsigned long decode (unsigned long *data, unsigned long *raw,
+				   int len)
+{
+	ulong *odd, *even;
+
+	/* convert length from bytes to longwords */
+	len >>= 2;
+	odd = raw;
+	even = odd + len;
+
+	/* prepare return pointer */
+	raw += len * 2;
+
+	do {
+		*data++ = ((*odd++ & 0x55555555) << 1) | (*even++ & 0x55555555);
+	} while (--len != 0);
+
+	return (ulong)raw;
+}
+
+#define MFM_NOSYNC	1
+#define MFM_HEADER	2
+#define MFM_DATA	3
+#define MFM_TRACK	4
+
+/*==========================================================================
+ scan_sync - looks for the next start of sector marked by a sync. d3 is the
+		sector number (10..0). When d3 = 10, can't be certain of a
+		starting sync.
+==========================================================================*/
+static unsigned long scan_sync(unsigned long raw, unsigned long end)
+{
+	ushort *ptr = (ushort *)raw, *endp = (ushort *)end;
+
+	while (ptr < endp && *ptr++ != 0x4489)
+		;
+	if (ptr < endp) {
+		while (*ptr == 0x4489 && ptr < endp)
+			ptr++;
+		return (ulong)ptr;
+	}
+	return 0;
+}
+
+/*==========================================================================
+  amiga_read reads a raw track of data into a track buffer
+==========================================================================*/
+static int amiga_read(int drive, unsigned char *track_data,
+		      unsigned long raw, int track)
+{
+	unsigned long end;
+	int scnt;
+	unsigned long csum;
+	struct header hdr;
+
+	drive&=3;
+	end = raw + unit[drive].type->read_size;
+
+	for (scnt = 0;scnt < unit[drive].sects; scnt++) {
+		if (!(raw = scan_sync(raw, end))) {
+			printk ("can't find sync for sector %d\n", scnt);
+			return MFM_NOSYNC;
+		}
+
+		raw = decode ((ulong *)&hdr.magic, (ulong *)raw, 4);
+		raw = decode ((ulong *)&hdr.labels, (ulong *)raw, 16);
+		raw = decode ((ulong *)&hdr.hdrchk, (ulong *)raw, 4);
+		raw = decode ((ulong *)&hdr.datachk, (ulong *)raw, 4);
+		csum = checksum((ulong *)&hdr,
+				(char *)&hdr.hdrchk-(char *)&hdr);
+
+#ifdef DEBUG
+		printk ("(%x,%d,%d,%d) (%lx,%lx,%lx,%lx) %lx %lx\n",
+			hdr.magic, hdr.track, hdr.sect, hdr.ord,
+			*(ulong *)&hdr.labels[0], *(ulong *)&hdr.labels[4],
+			*(ulong *)&hdr.labels[8], *(ulong *)&hdr.labels[12],
+			hdr.hdrchk, hdr.datachk);
+#endif
+
+		if (hdr.hdrchk != csum) {
+			printk("MFM_HEADER: %08lx,%08lx\n", hdr.hdrchk, csum);
+			return MFM_HEADER;
+		}
+
+		/* verify track */
+		if (hdr.track != track) {
+			printk("MFM_TRACK: %d, %d\n", hdr.track, track);
+			return MFM_TRACK;
+		}
+
+		raw = decode ((ulong *)(track_data + hdr.sect*512),
+			      (ulong *)raw, 512);
+		csum = checksum((ulong *)(track_data + hdr.sect*512), 512);
+
+		if (hdr.datachk != csum) {
+			printk("MFM_DATA: (%x:%d:%d:%d) sc=%d %lx, %lx\n",
+			       hdr.magic, hdr.track, hdr.sect, hdr.ord, scnt,
+			       hdr.datachk, csum);
+			printk ("data=(%lx,%lx,%lx,%lx)\n",
+				((ulong *)(track_data+hdr.sect*512))[0],
+				((ulong *)(track_data+hdr.sect*512))[1],
+				((ulong *)(track_data+hdr.sect*512))[2],
+				((ulong *)(track_data+hdr.sect*512))[3]);
+			return MFM_DATA;
+		}
+	}
+
+	return 0;
+}
+
+struct dos_header {
+unsigned char track,   /* 0-80 */
+              side,    /* 0-1 */
+              sec,     /* 0-...*/
+              len_desc;/* 2 */
+unsigned short crc;     /* on 68000 we got an alignment problem, 
+                           but this compiler solves it  by adding silently 
+                           adding a pad byte so data wont fit
+                           and this cost about 3h to discover.... */
+unsigned char gap1[22];     /* for longword-aligndness (0x4e) */
+};
+
+/* crc routines are borrowed from the messydos-handler  */
+
+static inline ushort dos_hdr_crc (struct dos_header *hdr)
+{
+return dos_crc(&(hdr->track), 0xb2, 0x30, 3); /* precomputed magic */
+}
+
+static inline ushort dos_data_crc(unsigned char *data)
+{
+return dos_crc(data, 0xe2, 0x95 ,511); /* precomputed magic */
+}
+
+/* excerpt from the messydos-device           
+; The CRC is computed not only over the actual data, but including
+; the SYNC mark (3 * $a1) and the 'ID/DATA - Address Mark' ($fe/$fb).
+; As we don't read or encode these fields into our buffers, we have to
+; preload the registers containing the CRC with the values they would have
+; after stepping over these fields.
+;
+; How CRCs "really" work:
+;
+; First, you should regard a bitstring as a series of coefficients of
+; polymomials. We calculate with these polynomials in modulo-2
+; arithmetic, in which both add and subtract are done the same as
+; exclusive-or. Now, we modify our data (a very long polynomial) in
+; such a way that it becomes divisible by the CCITT-standard 16-bit
+;		 16   12   5
+; polynomial:	x  + x	+ x + 1, represented by $11021. The easiest
+; way to do this would be to multiply (using proper arithmetic) our
+; datablock with $11021. So we have:
+;   data * $11021		 =
+;   data * ($10000 + $1021)      =
+;   data * $10000 + data * $1021
+; The left part of this is simple: Just add two 0 bytes. But then
+; the right part (data $1021) remains difficult and even could have
+; a carry into the left part. The solution is to use a modified
+; multiplication, which has a result that is not correct, but with
+; a difference of any multiple of $11021. We then only need to keep
+; the 16 least significant bits of the result.
+;
+; The following algorithm does this for us:
+;
+;   unsigned char *data, c, crclo, crchi;
+;   while (not done) {
+;	c = *data++ + crchi;
+;	crchi = (@ c) >> 8 + crclo;
+;	crclo = @ c;
+;   }
+;
+; Remember, + is done with EOR, the @ operator is in two tables (high
+; and low byte separately), which is calculated as
+;
+;      $1021 * (c & $F0)
+;  xor $1021 * (c & $0F)
+;  xor $1021 * (c >> 4)         (* is regular multiplication)
+;
+;
+; Anyway, the end result is the same as the remainder of the division of
+; the data by $11021. I am afraid I need to study theory a bit more...
+
+
+my only works was to code this from manx to C....
+
+*/
+
+static ushort dos_crc(void * data_a3, int data_d0, int data_d1, int data_d3)
+{
+static unsigned char CRCTable1[] = {
+	0x00,0x10,0x20,0x30,0x40,0x50,0x60,0x70,0x81,0x91,0xa1,0xb1,0xc1,0xd1,0xe1,0xf1,
+	0x12,0x02,0x32,0x22,0x52,0x42,0x72,0x62,0x93,0x83,0xb3,0xa3,0xd3,0xc3,0xf3,0xe3,
+	0x24,0x34,0x04,0x14,0x64,0x74,0x44,0x54,0xa5,0xb5,0x85,0x95,0xe5,0xf5,0xc5,0xd5,
+	0x36,0x26,0x16,0x06,0x76,0x66,0x56,0x46,0xb7,0xa7,0x97,0x87,0xf7,0xe7,0xd7,0xc7,
+	0x48,0x58,0x68,0x78,0x08,0x18,0x28,0x38,0xc9,0xd9,0xe9,0xf9,0x89,0x99,0xa9,0xb9,
+	0x5a,0x4a,0x7a,0x6a,0x1a,0x0a,0x3a,0x2a,0xdb,0xcb,0xfb,0xeb,0x9b,0x8b,0xbb,0xab,
+	0x6c,0x7c,0x4c,0x5c,0x2c,0x3c,0x0c,0x1c,0xed,0xfd,0xcd,0xdd,0xad,0xbd,0x8d,0x9d,
+	0x7e,0x6e,0x5e,0x4e,0x3e,0x2e,0x1e,0x0e,0xff,0xef,0xdf,0xcf,0xbf,0xaf,0x9f,0x8f,
+	0x91,0x81,0xb1,0xa1,0xd1,0xc1,0xf1,0xe1,0x10,0x00,0x30,0x20,0x50,0x40,0x70,0x60,
+	0x83,0x93,0xa3,0xb3,0xc3,0xd3,0xe3,0xf3,0x02,0x12,0x22,0x32,0x42,0x52,0x62,0x72,
+	0xb5,0xa5,0x95,0x85,0xf5,0xe5,0xd5,0xc5,0x34,0x24,0x14,0x04,0x74,0x64,0x54,0x44,
+	0xa7,0xb7,0x87,0x97,0xe7,0xf7,0xc7,0xd7,0x26,0x36,0x06,0x16,0x66,0x76,0x46,0x56,
+	0xd9,0xc9,0xf9,0xe9,0x99,0x89,0xb9,0xa9,0x58,0x48,0x78,0x68,0x18,0x08,0x38,0x28,
+	0xcb,0xdb,0xeb,0xfb,0x8b,0x9b,0xab,0xbb,0x4a,0x5a,0x6a,0x7a,0x0a,0x1a,0x2a,0x3a,
+	0xfd,0xed,0xdd,0xcd,0xbd,0xad,0x9d,0x8d,0x7c,0x6c,0x5c,0x4c,0x3c,0x2c,0x1c,0x0c,
+	0xef,0xff,0xcf,0xdf,0xaf,0xbf,0x8f,0x9f,0x6e,0x7e,0x4e,0x5e,0x2e,0x3e,0x0e,0x1e
+};
+
+static unsigned char CRCTable2[] = {
+	0x00,0x21,0x42,0x63,0x84,0xa5,0xc6,0xe7,0x08,0x29,0x4a,0x6b,0x8c,0xad,0xce,0xef,
+	0x31,0x10,0x73,0x52,0xb5,0x94,0xf7,0xd6,0x39,0x18,0x7b,0x5a,0xbd,0x9c,0xff,0xde,
+	0x62,0x43,0x20,0x01,0xe6,0xc7,0xa4,0x85,0x6a,0x4b,0x28,0x09,0xee,0xcf,0xac,0x8d,
+	0x53,0x72,0x11,0x30,0xd7,0xf6,0x95,0xb4,0x5b,0x7a,0x19,0x38,0xdf,0xfe,0x9d,0xbc,
+	0xc4,0xe5,0x86,0xa7,0x40,0x61,0x02,0x23,0xcc,0xed,0x8e,0xaf,0x48,0x69,0x0a,0x2b,
+	0xf5,0xd4,0xb7,0x96,0x71,0x50,0x33,0x12,0xfd,0xdc,0xbf,0x9e,0x79,0x58,0x3b,0x1a,
+	0xa6,0x87,0xe4,0xc5,0x22,0x03,0x60,0x41,0xae,0x8f,0xec,0xcd,0x2a,0x0b,0x68,0x49,
+	0x97,0xb6,0xd5,0xf4,0x13,0x32,0x51,0x70,0x9f,0xbe,0xdd,0xfc,0x1b,0x3a,0x59,0x78,
+	0x88,0xa9,0xca,0xeb,0x0c,0x2d,0x4e,0x6f,0x80,0xa1,0xc2,0xe3,0x04,0x25,0x46,0x67,
+	0xb9,0x98,0xfb,0xda,0x3d,0x1c,0x7f,0x5e,0xb1,0x90,0xf3,0xd2,0x35,0x14,0x77,0x56,
+	0xea,0xcb,0xa8,0x89,0x6e,0x4f,0x2c,0x0d,0xe2,0xc3,0xa0,0x81,0x66,0x47,0x24,0x05,
+	0xdb,0xfa,0x99,0xb8,0x5f,0x7e,0x1d,0x3c,0xd3,0xf2,0x91,0xb0,0x57,0x76,0x15,0x34,
+	0x4c,0x6d,0x0e,0x2f,0xc8,0xe9,0x8a,0xab,0x44,0x65,0x06,0x27,0xc0,0xe1,0x82,0xa3,
+	0x7d,0x5c,0x3f,0x1e,0xf9,0xd8,0xbb,0x9a,0x75,0x54,0x37,0x16,0xf1,0xd0,0xb3,0x92,
+	0x2e,0x0f,0x6c,0x4d,0xaa,0x8b,0xe8,0xc9,0x26,0x07,0x64,0x45,0xa2,0x83,0xe0,0xc1,
+	0x1f,0x3e,0x5d,0x7c,0x9b,0xba,0xd9,0xf8,0x17,0x36,0x55,0x74,0x93,0xb2,0xd1,0xf0
+};
+
+/* look at the asm-code - what looks in C a bit strange is almost as good as handmade */
+register int i;
+register unsigned char *CRCT1, *CRCT2, *data, c, crch, crcl;
+
+CRCT1=CRCTable1;
+CRCT2=CRCTable2;
+data=data_a3;
+crcl=data_d1;
+crch=data_d0;
+for (i=data_d3; i>=0; i--) {
+  c = (*data++) ^ crch;
+  crch = CRCT1[c] ^ crcl;
+  crcl = CRCT2[c];
+}
+return (crch<<8)|crcl;
+}
+
+static inline unsigned char dos_decode_byte(ushort word)
+{
+register ushort w2;
+register unsigned char byte;
+register unsigned char *dec = mfmdecode;
+
+w2=word;
+w2>>=8;
+w2&=127;
+byte = dec[w2];
+byte <<= 4;
+w2 = word & 127;
+byte |= dec[w2];
+return byte;
+}
+
+static unsigned long dos_decode(unsigned char *data, unsigned short *raw, int len)
+{
+int i;
+
+for (i = 0; i < len; i++)
+  *data++=dos_decode_byte(*raw++);
+return ((ulong)raw);
+}
+
+#ifdef DEBUG
+static void dbg(unsigned long ptr)
+{
+printk("raw data @%08lx: %08lx, %08lx ,%08lx, %08lx\n",ptr,
+  ((ulong *)ptr)[0],((ulong *)ptr)[1],((ulong *)ptr)[2],((ulong *)ptr)[3]);
+}
+#endif
+
+/*******************************************************************
+   this reads a raw track of data into trackbuffer for ms-disks 
+*******************************************************************/
+static int dos_read(int drive, unsigned char *track_data,
+	unsigned long raw, int track)
+{
+  unsigned long end;
+  int scnt;
+  unsigned short crc,data_crc[2];
+  struct dos_header hdr;
+
+  drive&=3;
+  end = raw + unit[drive].type->read_size;
+
+  for (scnt=0;scnt<unit[drive].sects;scnt++) {
+  do { /* search for the right sync of each sec-hdr */
+    if (!(raw = scan_sync (raw, end))) {
+      printk("dos_read: no hdr sync on track %d, unit %d for sector %d\n",
+        track,drive,scnt);
+      return MFM_NOSYNC;
+    }
+#ifdef DEBUG
+  dbg(raw);
+#endif
+  } while (*((ushort *)raw)!=0x5554); /* loop usually only once done */
+  raw+=2; /* skip over headermark */
+  raw = dos_decode((unsigned char *)&hdr,(ushort *) raw,8);
+  crc = dos_hdr_crc(&hdr);
+
+#ifdef DEBUG
+  printk("(%3d,%d,%2d,%d) %x\n", hdr.track, hdr.side,
+     hdr.sec, hdr.len_desc, hdr.crc);
+#endif
+
+  if (crc != hdr.crc) {
+    printk("dos_read: MFM_HEADER %04x,%04x\n", hdr.crc, crc);
+    return MFM_HEADER;
+  }
+  if (hdr.track != track/unit[drive].type->heads) {
+    printk("dos_read: MFM_TRACK %d, %d\n", hdr.track,
+      track/unit[drive].type->heads);
+    return MFM_TRACK;
+  }
+
+  if (hdr.side != track%unit[drive].type->heads) {
+    printk("dos_read: MFM_SIDE %d, %d\n", hdr.side,
+      track%unit[drive].type->heads);
+    return MFM_TRACK;
+  }
+
+  if (hdr.len_desc != 2) {
+    printk("dos_read: unknown sector len descriptor %d\n", hdr.len_desc);
+    return MFM_DATA;
+  }
+#ifdef DEBUG
+  printk("hdr accepted\n");
+#endif
+  if (!(raw = scan_sync (raw, end))) {
+    printk("dos_read: no data sync on track %d, unit %d for sector%d, disk sector %d\n",
+      track, drive, scnt, hdr.sec);
+    return MFM_NOSYNC;
+  }
+#ifdef DEBUG
+  dbg(raw);
+#endif
+
+  if (*((ushort *)raw)!=0x5545) {
+    printk("dos_read: no data mark after sync (%d,%d,%d,%d) sc=%d\n",
+      hdr.track,hdr.side,hdr.sec,hdr.len_desc,scnt);
+    return MFM_NOSYNC;
+  }
+
+  raw+=2;  /* skip data mark (included in checksum) */
+  raw = dos_decode((unsigned char *)(track_data + (hdr.sec - 1) * 512), (ushort *) raw, 512);
+  raw = dos_decode((unsigned char  *)data_crc,(ushort *) raw,4);
+  crc = dos_data_crc(track_data + (hdr.sec - 1) * 512);
+
+  if (crc != data_crc[0]) {
+    printk("dos_read: MFM_DATA (%d,%d,%d,%d) sc=%d, %x %x\n",
+      hdr.track, hdr.side, hdr.sec, hdr.len_desc,
+      scnt,data_crc[0], crc);
+    printk("data=(%lx,%lx,%lx,%lx,...)\n",
+      ((ulong *)(track_data+(hdr.sec-1)*512))[0],
+      ((ulong *)(track_data+(hdr.sec-1)*512))[1],
+      ((ulong *)(track_data+(hdr.sec-1)*512))[2],
+      ((ulong *)(track_data+(hdr.sec-1)*512))[3]);
+    return MFM_DATA;
+  }
+  }
+ return 0;
+}
+
+static inline ushort dos_encode_byte(unsigned char byte)
+{
+register unsigned char *enc, b2, b1;
+register ushort word;
+
+enc=mfmencode;
+b1=byte;
+b2=b1>>4;
+b1&=15;
+word=enc[b2] <<8 | enc [b1];
+return (word|((word&(256|64)) ? 0: 128));
+}
+
+static void dos_encode_block(ushort *dest, unsigned char *src, int len)
+{
+int i;
+
+for (i = 0; i < len; i++) {
+  *dest=dos_encode_byte(*src++);
+  *dest|=((dest[-1]&1)||(*dest&0x4000))? 0: 0x8000;
+  dest++;
+}
+}
+
+static unsigned long *ms_putsec(int drive, unsigned long *raw, int track, int cnt,
+   unsigned char *data)
+{
+static struct dos_header hdr={0,0,0,2,0,
+  {78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78}};
+int i;
+static ushort crc[2]={0,0x4e4e};
+
+drive&=3;
+/* id gap 1 */
+/* the MFM word before is always 9254 */
+for(i=0;i<6;i++)
+  *raw++=0xaaaaaaaa;
+/* 3 sync + 1 headermark */
+*raw++=0x44894489;
+*raw++=0x44895554;
+
+/* fill in the variable parts of the header */
+hdr.track=track/unit[drive].type->heads;
+hdr.side=track%unit[drive].type->heads;
+hdr.sec=cnt+1;
+hdr.crc=dos_hdr_crc(&hdr);
+
+/* header (without "magic") and id gap 2*/
+dos_encode_block((ushort *)raw,(unsigned char *) &hdr.track,28);
+raw+=14;
+
+/*id gap 3 */
+for(i=0;i<6;i++)
+  *raw++=0xaaaaaaaa;
+
+/* 3 syncs and 1 datamark */
+*raw++=0x44894489;
+*raw++=0x44895545;
+
+/* data */
+dos_encode_block((ushort *)raw,(unsigned char *)data,512);
+raw+=256;
+
+/*data crc + jd's special gap (long words :-/) */
+crc[0]=dos_data_crc(data);
+dos_encode_block((ushort *) raw,(unsigned char *)crc,4);
+raw+=2;
+
+/* data gap */
+for(i=0;i<38;i++)
+  *raw++=0x92549254;
+
+return raw; /* wrote 652 MFM words */
+}
+
+
+/**************************************************************
+  builds encoded track data from trackbuffer data
+**************************************************************/
+static void dos_write(int disk, unsigned long raw, unsigned char *data,
+    int track)
+{
+int cnt;
+unsigned long *ptr=(unsigned long *)raw;
+
+disk&=3;
+/* really gap4 + indexgap , but we write it first and round it up */
+for (cnt=0;cnt<425;cnt++)
+  *ptr++=0x92549254;
+
+/* the following is just guessed */
+if (unit[disk].type->sect_mult==2)  /* check for HD-Disks */
+  for(cnt=0;cnt<473;cnt++)
+    *ptr++=0x92549254;
+
+/* now the index marks...*/
+for (cnt=0;cnt<20;cnt++)
+  *ptr++=0x92549254;
+for (cnt=0;cnt<6;cnt++)
+  *ptr++=0xaaaaaaaa;
+*ptr++=0x52245224;
+*ptr++=0x52245552;
+for (cnt=0;cnt<20;cnt++)
+  *ptr++=0x92549254;
+
+/* sectors */
+for(cnt=0;cnt<unit[disk].sects;cnt++)
+  ptr=ms_putsec(disk,ptr,track,cnt,data+cnt*512);
+
+*(ushort *)ptr = 0xaaa8; /* MFM word before is always 0x9254 */
+}
+
+/*
+ * Note that MAX_ERRORS=X doesn't imply that we retry every bad read
+ * max X times - some types of errors increase the errorcount by 2 or
+ * even 3, so we might actually retry only X/2 times before giving up.
+ */
+#define MAX_ERRORS 12
+
+/*
+ * The driver is trying to determine the correct media format
+ * while probing is set. rw_interrupt() clears it after a
+ * successful access.
+ */
+static int probing = 0;
+
+/* Prevent "aliased" accesses. */
+static fd_ref[4] = { 0,0,0,0 };
+static fd_device[4] = { 0,0,0,0 };
+
+/*
+ * Current device number. Taken either from the block header or from the
+ * format request descriptor.
+ */
+#define CURRENT_DEVICE (CURRENT->rq_dev)
+
+/* Current error count. */
+#define CURRENT_ERRORS (CURRENT->errors)
+
+static void request_done(int uptodate)
+{
+  timer_active &= ~(1 << FLOPPY_TIMER);
+  end_request(uptodate);
+}
+
+/*
+ * floppy-change is never called from an interrupt, so we can relax a bit
+ * here, sleep etc. Note that floppy-on tries to set current_DOR to point
+ * to the desired drive, but it will probably not survive the sleep if
+ * several floppies are used at the same time: thus the loop.
+ */
+static int amiga_floppy_change(kdev_t dev)
+{
+	int drive = dev & 3;
+	int changed;
+
+	if (MAJOR(dev) != MAJOR_NR) {
+		printk("floppy_change: not a floppy\n");
+		return 0;
+	}
+
+	fd_select (drive);
+	changed = !(ciaa.pra & DSKCHANGE);
+	fd_deselect (drive);
+
+	if (changed) {
+		fd_probe(dev);
+		unit[drive].track = -1;
+		selected = -1;
+		savedtrack = -1;
+		writepending = 0; /* if this was true before, too bad! */
+		writefromint = 0;
+		return 1;
+	}
+	return 0;
+}
+
+static __inline__ void copy_buffer(void *from, void *to)
+{
+  ulong *p1,*p2;
+  int cnt;
+
+  p1 = (ulong *)from;
+  p2 = (ulong *)to;
+
+  for (cnt = 0; cnt < 512/4; cnt++)
+    *p2++ = *p1++;
+}
+
+static void raw_read(int drive, int track, char *ptrack, int len)
+{
+	drive&=3;
+	/* setup adkcon bits correctly */
+	custom.adkcon = ADK_MSBSYNC;
+	custom.adkcon = ADK_SETCLR|ADK_WORDSYNC|ADK_FAST;
+
+	custom.dsksync = MFM_SYNC;
+
+	custom.dsklen = 0;
+#if 0
+	ms_delay (unit[drive].type->side_time);
+#endif
+	custom.dskptr = (u_char *)ZTWO_PADDR((u_char *)ptrack);
+	custom.dsklen = len/sizeof(short) | DSKLEN_DMAEN;
+	custom.dsklen = len/sizeof(short) | DSKLEN_DMAEN;
+
+	block_flag = 1;
+
+	while (block_flag == 1)
+		sleep_on (&wait_fd_block);
+
+	custom.dsklen = 0;
+}
+
+static int raw_write(int drive, int track, char *ptrack, int len)
+{
+	ushort adk;
+
+	drive&=3;
+	if ((ciaa.pra & DSKPROT) == 0)
+		return 0;
+
+	/* clear adkcon bits */
+	custom.adkcon = ADK_PRECOMP1|ADK_PRECOMP0|ADK_WORDSYNC|ADK_MSBSYNC;
+	/* set appropriate adkcon bits */
+	adk = ADK_SETCLR|ADK_FAST;
+	if ((ulong)track >= unit[drive].type->precomp2)
+		adk |= ADK_PRECOMP1;
+	else if ((ulong)track >= unit[drive].type->precomp1)
+		adk |= ADK_PRECOMP0;
+	custom.adkcon = adk;
+
+	custom.dsklen = DSKLEN_WRITE;
+#if 0
+	ms_delay (unit[drive].type->side_time);
+#endif
+	custom.dskptr = (u_char *)ZTWO_PADDR((u_char *)ptrack);
+	custom.dsklen = len/sizeof(short) | DSKLEN_DMAEN|DSKLEN_WRITE;
+	custom.dsklen = len/sizeof(short) | DSKLEN_DMAEN|DSKLEN_WRITE;
+
+	block_flag = 2;
+	return 1;
+}
+
+static void post_write (unsigned long dummy)
+{
+  custom.dsklen = 0;
+  writepending = 0;
+  writefromint = 0;
+}
+
+static int get_track(int drive, int track)
+{
+	int error;
+
+	drive&=3;
+	if ((lastdrive == drive) && (savedtrack == track))
+		return 0;
+
+	lastdrive = drive;
+	raw_read(drive, track, raw_buf, unit[drive].type->read_size);
+	savedtrack = -1;
+	error = (*unit[drive].dtype->read_fkt)(drive, trackdata, (unsigned long)raw_buf, track);
+	switch (error) {
+	    case 0:
+		savedtrack = track;
+		return 0;
+	    case MFM_TRACK:
+		unit[drive].track = -1;
+		/* fall through */
+	    default:
+		return -1;
+	}
+}
+
+static void flush_track_callback(unsigned long nr)
+{
+  nr&=3;
+  writefromint = 1;
+  (*unit[nr].dtype->write_fkt)(nr, (unsigned long)raw_buf, trackdata, savedtrack);
+  if (!raw_write(nr, savedtrack, raw_buf, unit[nr].type->write_size)) {
+    printk ("floppy disk write protected\n");
+    writefromint = 0;
+    writepending = 0;
+  }
+}
+
+static int non_int_flush_track (unsigned long nr)
+{
+unsigned long flags;
+
+  nr&=3;
+  writefromint = 0;
+  del_timer(&post_write_timer);
+  save_flags(flags);
+  cli();
+  if (writepending != 2) {
+    restore_flags(flags);
+    (*unit[nr].dtype->write_fkt)(nr, (unsigned long)raw_buf, trackdata, savedtrack);
+    if (!raw_write(nr, savedtrack, raw_buf, unit[nr].type->write_size)) {
+      printk ("floppy disk write protected in write!\n");
+      writepending = 0;
+      return 0;
+    }
+    while (block_flag == 2)
+      sleep_on (&wait_fd_block);
+  }
+  else
+    restore_flags(flags);
+  ms_delay(2); /* 2 ms post_write delay */
+  post_write(0);
+  return 1;
+}
+
+static void redo_fd_request(void)
+{
+	unsigned int block, track, sector;
+	int device, drive, cnt;
+	struct amiga_floppy_struct *floppy;
+	char *data;
+	unsigned long flags;
+
+	if (CURRENT && CURRENT->rq_status == RQ_INACTIVE){
+		return;
+	}
+
+    repeat:
+	if (!CURRENT) {
+		if (!fdc_busy)
+			printk("FDC access conflict!");
+		fdc_busy = 0;
+		wake_up(&fdc_wait);
+		CLEAR_INTR;
+		return;
+	}
+
+	if (MAJOR(CURRENT->rq_dev) != MAJOR_NR)
+		panic(DEVICE_NAME ": request list destroyed");
+
+	if (CURRENT->bh && !buffer_locked(CURRENT->bh))
+		panic(DEVICE_NAME ": block not locked");
+
+	probing = 0;
+	device = MINOR(CURRENT_DEVICE);
+	if (device > 3) {
+		/* manual selection */
+		drive = device & 3;
+		floppy = unit + drive;
+	} else {
+		/* Auto-detection */
+		/* printk("redo_fd_request: can't handle auto detect\n");*/
+		/* printk("redo_fd_request: default to normal\n");*/
+		drive = device & 3;
+		floppy = unit + drive;
+	}
+
+	save_flags (flags);
+	cli();
+	if (drive != selected && writepending) {
+	  del_timer (&flush_track_timer);
+	  restore_flags (flags);
+	  if (!non_int_flush_track (selected)) {
+	    end_request(0);
+	    goto repeat;
+	  }
+	} else
+	  restore_flags (flags);
+
+ /* Here someone could investigate to be more efficient */
+	for (cnt = 0; cnt < CURRENT->current_nr_sectors; cnt++) { 
+#ifdef DEBUG
+		printk("fd: sector %d + %d requested\n",CURRENT->sector,cnt);
+#endif
+		block = CURRENT->sector + cnt;
+		if ((int)block > floppy->blocks) {
+			request_done(0);
+			goto repeat;
+		}
+
+		track = block / floppy->sects;
+		sector = block % floppy->sects;
+		data = CURRENT->buffer + 512 * cnt;
+
+		save_flags (flags);
+		cli();
+		if (track != savedtrack && writepending) {
+		  del_timer (&flush_track_timer);
+		  restore_flags (flags);
+		  if (!non_int_flush_track (selected)) {
+		    end_request(0);
+		    goto repeat;
+		  }
+		} else
+		  restore_flags (flags);
+
+		switch (CURRENT->cmd) {
+		    case READ:
+			if (!motor_on (drive)) {
+				end_request(0);
+				goto repeat;
+			}
+			fd_select (drive);
+			if (!fd_seek(drive, track)) {
+				end_request(0);
+				goto repeat;
+			}
+			if (get_track(drive, track) == -1) {
+				end_request(0);
+				goto repeat;
+			}
+			copy_buffer(trackdata + sector * 512, data);
+			break;
+
+		    case WRITE:
+			if (!motor_on (drive)) {
+				end_request(0);
+				goto repeat;
+			}
+			fd_select (drive);
+			if (!fd_seek(drive, track)) {
+				end_request(0);
+				goto repeat;
+			}
+			if (get_track(drive, track) == -1) {
+				end_request(0);
+				goto repeat;
+			}
+			copy_buffer(data, trackdata + sector * 512);
+			/*
+			 * setup a callback to write the track buffer
+			 * after a short (1 tick) delay.
+			 */
+			save_flags (flags);
+			cli();
+
+			if (writepending)
+			    /* reset the timer */
+			    del_timer (&flush_track_timer);
+			    
+			writepending = 1;
+			flush_track_timer.data = drive;
+			flush_track_timer.expires = jiffies + 1;
+			add_timer (&flush_track_timer);
+			restore_flags (flags);
+			break;
+
+		    default:
+			printk("do_fd_request: unknown command\n");
+			request_done(0);
+			goto repeat;
+		}
+	}
+	CURRENT->nr_sectors -= CURRENT->current_nr_sectors;
+	CURRENT->sector += CURRENT->current_nr_sectors;
+
+	request_done(1);
+	goto repeat;
+}
+
+static void do_fd_request(void)
+{
+unsigned long flags;
+
+	save_flags(flags);
+	cli();
+	while (fdc_busy) sleep_on(&fdc_wait);
+	fdc_busy = 1;
+	restore_flags(flags); /* sti(); */
+	redo_fd_request();
+}
+
+static int fd_ioctl(struct inode *inode, struct file *filp,
+		    unsigned int cmd, unsigned long param)
+{
+	int drive = inode->i_rdev & 3;
+	static struct floppy_struct getprm;
+	int error;
+
+	switch(cmd)
+	 {
+	  case FDFMTBEG:
+	    if (fd_ref[drive] > 1)
+	      return -EBUSY;
+	    fsync_dev(inode->i_rdev);
+	    if (motor_on(drive) == 0)
+	      return -ENODEV;
+	    if (fd_calibrate(drive) == 0)
+	      return -ENXIO;
+	    floppy_off(drive);
+	    break;
+	  case FDFMTTRK:
+	    if (param < unit[drive].type->tracks)
+	     {
+	      fd_select(drive);
+	      if (fd_seek(drive,param)!=0)
+	       {
+	        savedtrack=param;
+	        memset(trackdata,FD_FILL_BYTE,unit[drive].sects*512);
+	        non_int_flush_track(drive);
+	       }
+	      floppy_off(drive);
+	     }
+	    else
+	      return -EINVAL;
+	    break;
+	  case FDFMTEND:
+	    floppy_off(drive);
+	    invalidate_inodes(inode->i_rdev);
+	    invalidate_buffers(inode->i_rdev);
+	    break;
+	  case FDGETPRM:
+	    error = verify_area(VERIFY_WRITE, (void *)param,
+				sizeof(struct floppy_struct));
+	    if (error)
+	      return error;
+	    memset((void *)&getprm, 0, sizeof (getprm));
+	    getprm.track=unit[drive].type->tracks/unit[drive].type->heads;
+	    getprm.head=unit[drive].type->heads;
+	    getprm.sect=unit[drive].sects;
+	    getprm.size=unit[drive].blocks;
+	    memcpy_tofs((void *)param,(void *)&getprm,sizeof(struct floppy_struct));
+	    break;
+	  case BLKGETSIZE:
+            error = verify_area(VERIFY_WRITE, (void *)param,
+            			sizeof(long));
+            if (error)
+              return error;
+            put_fs_long(unit[drive].blocks,(long *)param);
+            break;
+          case FDSETPRM:
+          case FDDEFPRM:
+            return -EINVAL;
+          case FDFLUSH:
+            if ((drive == selected) && (writepending)) {
+              del_timer (&flush_track_timer);
+              non_int_flush_track(selected);
+            }
+            break;
+#ifdef RAW_IOCTL
+	  case IOCTL_RAW_TRACK:
+	    error = verify_area(VERIFY_WRITE, (void *)param,
+	      unit[drive].type->read_size);
+	    if (error)
+	      return error;
+	    memcpy_tofs((void *)param, raw_buf, unit[drive].type->read_size);
+	    return unit[drive].type->read_size;
+#endif
+	  default:
+	    printk("fd_ioctl: unknown cmd %d for drive %d.",cmd,drive);
+	    return -ENOSYS;
+         }
+	return 0;
+}
+
+/*======================================================================
+  Return unit ID number of given disk
+======================================================================*/
+static unsigned long get_drive_id(int drive)
+{
+	int i;
+	ulong id = 0;
+
+  	drive&=3;
+	/* set up for ID */
+	MOTOR_ON;
+	udelay(2);
+	SELECT(SELMASK(drive));
+	udelay(2);
+	DESELECT(SELMASK(drive));
+	udelay(2);
+	MOTOR_OFF;
+	udelay(2);
+	SELECT(SELMASK(drive));
+	udelay(2);
+	DESELECT(SELMASK(drive));
+	udelay(2);
+
+	/* loop and read disk ID */
+	for (i=0; i<32; i++) {
+		SELECT(SELMASK(drive));
+		udelay(2);
+
+		/* read and store value of DSKRDY */
+		id <<= 1;
+		id |= (ciaa.pra & DSKRDY) ? 0 : 1;	/* cia regs are low-active! */
+
+		DESELECT(SELMASK(drive));
+	}
+
+	selected = -1;
+
+        /*
+         * RB: At least A500/A2000's df0: don't identify themselves.
+         * As every (real) Amiga has at least a 3.5" DD drive as df0:
+         * we default to that if df0: doesn't identify as a certain
+         * type.
+         */
+        if(drive == 0 && id == FD_NODRIVE)
+         {
+                id = fd_def_df0;
+                printk("fd: drive 0 didn't identify, setting default %08lx\n",(ulong)fd_def_df0);
+         }
+	/* return the ID value */
+	return (id);
+}
+
+static void fd_probe(int dev)
+{
+	unsigned long code;
+	int type;
+	int drive;
+	int system;
+
+	drive = dev & 3;
+	code = get_drive_id(drive);
+
+	/* get drive type */
+	unit[drive].type = NULL;
+	for (type = 0; type < num_dr_types; type++)
+		if (drive_types[type].code == code)
+			break;
+
+	if (type >= num_dr_types) {
+		printk("fd_probe: unsupported drive type %08lx found\n",
+		       code);
+		return;
+	}
+
+	unit[drive].type = &drive_types[type];
+	unit[drive].track = -1;
+
+	unit[drive].disk = -1;
+	unit[drive].motor = 0;
+	unit[drive].busy = 0;
+	unit[drive].status = -1;
+
+
+	system=(dev & 4)>>2;
+	unit[drive].dtype=&data_types[system];
+	unit[drive].sects=data_types[system].sects*unit[drive].type->sect_mult;
+	unit[drive].blocks=unit[drive].type->heads*unit[drive].type->tracks*
+	    unit[drive].sects;
+
+	floppy_sizes[MINOR(dev)] = unit[drive].blocks >> 1;
+
+}
+
+static void probe_drives(void)
+{
+	int drive,found;
+
+	printk("FD: probing units\nfound ");
+	found=0;
+	for(drive=0;drive<FD_MAX_UNITS;drive++) {
+	  fd_probe(drive);
+	  if (unit[drive].type->code != FD_NODRIVE) {
+	    printk("fd%d ",drive);
+	    found=1;
+	  }
+	}
+	printk("%s\n",(found==0)?" no drives":"");
+}
+
+/*
+ * floppy_open check for aliasing (/dev/fd0 can be the same as
+ * /dev/PS0 etc), and disallows simultaneous access to the same
+ * drive with different device numbers.
+ */
+static int floppy_open(struct inode *inode, struct file *filp)
+{
+  int drive;
+  int old_dev;
+  int system;
+
+  drive = inode->i_rdev & 3;
+  old_dev = fd_device[drive];
+
+  if (fd_ref[drive])
+    if (old_dev != inode->i_rdev)
+      return -EBUSY;
+
+  if (unit[drive].type->code == FD_NODRIVE)
+    return -ENODEV;
+
+  fd_ref[drive]++;
+  fd_device[drive] = inode->i_rdev;
+
+  if (old_dev && old_dev != inode->i_rdev)
+    invalidate_buffers(old_dev);
+
+  if (filp && filp->f_mode)
+    check_disk_change(inode->i_rdev);
+
+  if (filp && (filp->f_flags & (O_WRONLY|O_RDWR))) {
+	  int wrprot;
+
+	  fd_select (drive);
+	  wrprot = !(ciaa.pra & DSKPROT);
+	  fd_deselect (drive);
+
+	  if (wrprot)
+		  return -EROFS;
+  }
+
+  system=(inode->i_rdev & 4)>>2;
+  unit[drive].dtype=&data_types[system];
+  unit[drive].sects=data_types[system].sects*unit[drive].type->sect_mult;
+  unit[drive].blocks=unit[drive].type->heads*unit[drive].type->tracks*
+        unit[drive].sects;
+
+printk("fd%d: accesing %s-disk with %s-layout\n",drive,unit[drive].type->name,
+  data_types[system].name);
+
+  return 0;
+}
+
+static void floppy_release(struct inode * inode, struct file * filp)
+{
+  unsigned long flags;
+
+  fsync_dev(inode->i_rdev);
+  invalidate_inodes(inode->i_rdev);
+  invalidate_buffers(inode->i_rdev);
+  save_flags (flags);
+  cli();
+  if ((inode->i_rdev & 3) == selected && writepending) {
+    del_timer (&flush_track_timer);
+    restore_flags (flags);
+    non_int_flush_track (selected);
+  } else
+    restore_flags (flags);
+  
+  if (!fd_ref[inode->i_rdev & 3]--) {
+    printk("floppy_release with fd_ref == 0");
+    fd_ref[inode->i_rdev & 3] = 0;
+  }
+}
+
+void amiga_floppy_setup (char *str, int *ints)
+{
+printk ("amiflop: Setting default df0 to %x\n", ints[1]);
+fd_def_df0 = ints[1];
+}
+
+static struct file_operations floppy_fops = {
+	NULL,			/* lseek - default */
+	block_read,		/* read - general block-dev read */
+	block_write,		/* write - general block-dev write */
+	NULL,			/* readdir - bad */
+	NULL,			/* select */
+	fd_ioctl,		/* ioctl */
+	NULL,			/* mmap */
+	floppy_open,		/* open */
+	floppy_release, 	/* release */
+	block_fsync,		/* fsync */
+	NULL,			/* fasync */
+	amiga_floppy_change,	/* check_media_change */
+	NULL,			/* revalidate */
+};
+
+static void fd_block_done(int irq, struct pt_regs *fp, void *dummy)
+{
+  if (block_flag)
+    custom.dsklen = 0x4000;
+
+  block_flag = 0;
+  wake_up (&wait_fd_block);
+
+  if (writefromint) {
+    /* 
+     * if it was a write from an interrupt,
+     * we will call post_write from here
+     */
+    writepending = 2;
+    post_write_timer.expires = 1; /* at least 2 ms */
+    add_timer(&post_write_timer);
+  }
+
+}
+
+int amiga_floppy_init(void)
+{
+  int i;
+
+  if (!AMIGAHW_PRESENT(AMI_FLOPPY))
+    return -ENXIO;
+
+  if (register_blkdev(MAJOR_NR,"fd",&floppy_fops)) {
+    printk("Unable to get major %d for floppy\n",MAJOR_NR);
+    return -EBUSY;
+  }
+
+  /* initialize variables */
+  motor_on_timer.next = NULL;
+  motor_on_timer.prev = NULL;
+  motor_on_timer.expires = 0;
+  motor_on_timer.data = 0;
+  motor_on_timer.function = motor_on_callback;
+  for (i = 0; i < FD_MAX_UNITS; i++) {
+	  motor_off_timer[i].next = NULL;
+	  motor_off_timer[i].prev = NULL;
+	  motor_off_timer[i].expires = 0;
+	  motor_off_timer[i].data = i;
+	  motor_off_timer[i].function = fd_motor_off;
+
+	  unit[i].track = -1;
+  }
+
+  flush_track_timer.next = NULL;
+  flush_track_timer.prev = NULL;
+  flush_track_timer.expires = 0;
+  flush_track_timer.data = 0;
+  flush_track_timer.function = flush_track_callback;
+
+  post_write_timer.next = NULL;
+  post_write_timer.prev = NULL;
+  post_write_timer.expires = 0;
+  post_write_timer.data = 0;
+  post_write_timer.function = post_write;
+  
+  blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
+  blksize_size[MAJOR_NR] = floppy_blocksizes;
+  blk_size[MAJOR_NR] = floppy_sizes;
+
+
+  timer_table[FLOPPY_TIMER].fn = NULL;
+  timer_active &= ~(1 << FLOPPY_TIMER);
+
+  if (fd_def_df0==0) {
+    if ((boot_info.bi_amiga.model == AMI_3000) ||
+        (boot_info.bi_amiga.model == AMI_4000))
+      fd_def_df0=FD_HD_3;
+    else
+      fd_def_df0=FD_DD_3;
+  }
+
+  probe_drives();
+
+  raw_buf = (char *)amiga_chip_alloc (RAW_BUF_SIZE);
+
+  for (i = 0; i < 128; i++)
+    mfmdecode[i]=255;
+  for (i = 0; i < 16; i++)
+    mfmdecode[mfmencode[i]]=i;
+
+  /* make sure that disk DMA is enabled */
+  custom.dmacon = DMAF_SETCLR | DMAF_DISK;
+
+  add_isr(IRQ_FLOPPY, fd_block_done, 0, NULL, "floppy_dma");
+  add_isr(IRQ_AMIGA_CIAA_TB, ms_isr, 0, NULL, "floppy_timer");
+
+  return 0;
+}
diff -u --recursive --new-file v1.3.93/linux/drivers/block/ataflop.c linux/drivers/block/ataflop.c
--- v1.3.93/linux/drivers/block/ataflop.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/block/ataflop.c	Fri Apr 19 02:35:23 1996
@@ -0,0 +1,1948 @@
+/*
+ *  drivers/block/ataflop.c
+ *
+ *  Copyright (C) 1993  Greg Harp
+ *  Atari Support by Bjoern Brauel, Roman Hodek
+ *
+ *  Big cleanup Sep 11..14 1994 Roman Hodek:
+ *   - Driver now works interrupt driven
+ *   - Support for two drives; should work, but I cannot test that :-(
+ *   - Reading is done in whole tracks and buffered to speed up things
+ *   - Disk change detection and drive deselecting after motor-off
+ *     similar to TOS
+ *   - Autodetection of disk format (DD/HD); untested yet, because I
+ *     don't have an HD drive :-(
+ *
+ *  Fixes Nov 13 1994 Martin Schaller:
+ *   - Autodetection works now
+ *   - Support for 5 1/4'' disks
+ *   - Removed drive type (unknown on atari)
+ *   - Do seeks with 8 Mhz
+ *
+ *  Changes by Andreas Schwab:
+ *   - After errors in multiple read mode try again reading single sectors
+ *  (Feb 1995):
+ *   - Clean up error handling
+ *   - Set blk_size for proper size checking
+ *   - Initialize track register when testing presence of floppy
+ *   - Implement some ioctl's
+ *
+ *  Changes by Torsten Lang:
+ *   - When probing the floppies we should add the FDCCMDADD_H flag since
+ *     the FDC will otherwise wait forever when no disk is inserted...
+ *
+ * ++ Freddi Aschwanden (fa) 20.9.95 fixes for medusa:
+ *  - MFPDELAY() after each FDC access -> atari 
+ *  - more/other disk formats
+ *  - DMA to the block buffer directly if we have a 32bit DMA
+ *  - for medusa, the step rate is always 3ms
+ *  - on medusa, use only cache_push()
+ * Roman:
+ *  - Make disk format numbering independant from minors
+ *  - Let user set max. supported drive type (speeds up format
+ *    detection, saves buffer space)
+ *
+ * Roman 10/15/95:
+ *  - implement some more ioctls
+ *  - disk formatting
+ *  
+ * Andreas 95/12/12:
+ *  - increase gap size at start of track for HD/ED disks
+ *
+ *  Things left to do:
+ *   - Formatting
+ *   - Maybe a better strategy for disk change detection (does anyone
+ *     know one?)
+ */
+
+#include <linux/module.h>
+
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/fs.h>
+#include <linux/fcntl.h>
+#include <linux/kernel.h>
+#include <linux/timer.h>
+#include <linux/fd.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/mm.h>
+#include <linux/malloc.h>
+
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <asm/irq.h>
+#include <asm/pgtable.h>
+
+#include <asm/bootinfo.h>
+#include <asm/atafd.h>
+#include <asm/atafdreg.h>
+#include <asm/atarihw.h>
+#include <asm/atariints.h>
+#include <asm/atari_stdma.h>
+
+#define MAJOR_NR FLOPPY_MAJOR
+#include <linux/blk.h>
+
+#define	FD_MAX_UNITS 2
+
+#undef DEBUG
+
+/* Disk types: DD, HD, ED */
+static struct atari_disk_type {
+	const char	*name;
+	unsigned	spt;		/* sectors per track */
+	unsigned	blocks;		/* total number of blocks */
+	unsigned	fdc_speed;	/* fdc_speed setting */
+	unsigned 	stretch;	/* track doubling ? */
+} disk_type[] = {
+	{ "d360",  9, 720, 0, 0},	/*  0: 360kB diskette */
+	{ "D360",  9, 720, 0, 1},	/*  1: 360kb in 720k or 1.2MB drive */
+	{ "D720",  9,1440, 0, 0},	/*  2: 720kb in 720k or 1.2MB drive */
+	{ "D820", 10,1640, 0, 0},	/*  3: DD disk with 82 tracks/10 sectors */
+/* formats above are probed for type DD */
+#define	MAX_TYPE_DD 3
+	{ "h1200",15,2400, 3, 0},	/*  4: 1.2MB diskette */
+	{ "H1440",18,2880, 3, 0},	/*  5: 1.4 MB diskette (HD) */
+	{ "H1640",20,3280, 3, 0},	/*  6: 1.64MB diskette (fat HD) 82 tr 20 sec */
+/* formats above are probed for types DD and HD */
+#define	MAX_TYPE_HD 6
+	{ "E2880",36,5760, 3, 0},	/*  7: 2.8 MB diskette (ED) */
+	{ "E3280",40,6560, 3, 0},	/*  8: 3.2 MB diskette (fat ED) 82 tr 40 sec */
+/* formats above are probed for types DD, HD and ED */
+#define	MAX_TYPE_ED 8
+/* types below are never autoprobed */
+	{ "H1680",21,3360, 3, 0},	/*  9: 1.68MB diskette (fat HD) 80 tr 21 sec */
+	{ "h410",10,820, 0, 1},		/* 10: 410k diskette 41 tr 10 sec, stretch */
+	{ "h1476",18,2952, 3, 0},	/* 11: 1.48MB diskette 82 tr 18 sec */
+	{ "H1722",21,3444, 3, 0},	/* 12: 1.72MB diskette 82 tr 21 sec */
+	{ "h420",10,840, 0, 1},		/* 13: 420k diskette 42 tr 10 sec, stretch */
+	{ "H830",10,1660, 0, 0},	/* 14: 820k diskette 83 tr 10 sec */
+	{ "h1494",18,2952, 3, 0},	/* 15: 1.49MB diskette 83 tr 18 sec */
+	{ "H1743",21,3486, 3, 0},	/* 16: 1.74MB diskette 83 tr 21 sec */
+	{ "h880",11,1760, 0, 0},	/* 17: 880k diskette 80 tr 11 sec */
+	{ "D1040",13,2080, 0, 0},	/* 18: 1.04MB diskette 80 tr 13 sec */
+	{ "D1120",14,2240, 0, 0},	/* 19: 1.12MB diskette 80 tr 14 sec */
+	{ "h1600",20,3200, 3, 0},	/* 20: 1.60MB diskette 80 tr 20 sec */
+	{ "H1760",22,3520, 3, 0},	/* 21: 1.76MB diskette 80 tr 22 sec */
+	{ "H1920",24,3840, 3, 0},	/* 22: 1.92MB diskette 80 tr 24 sec */
+	{ "E3200",40,6400, 3, 0},	/* 23: 3.2MB diskette 80 tr 40 sec */
+	{ "E3520",44,7040, 3, 0},	/* 24: 3.52MB diskette 80 tr 44 sec */
+	{ "E3840",48,7680, 3, 0},	/* 25: 3.84MB diskette 80 tr 48 sec */
+	{ "H1840",23,3680, 3, 0},	/* 26: 1.84MB diskette 80 tr 23 sec */
+	{ "D800",10,1600, 0, 0},	/* 27: 800k diskette 80 tr 10 sec */
+};
+
+static int StartDiskType[] = {
+	MAX_TYPE_DD,
+	MAX_TYPE_HD,
+	MAX_TYPE_ED
+};
+
+#define	TYPE_DD		0
+#define	TYPE_HD		1
+#define	TYPE_ED		2
+
+static int DriveType = TYPE_HD;
+
+/* Array for translating minors into disk formats */
+static struct {
+	int 	 index;
+	unsigned drive_types;
+} minor2disktype[] = {
+	{  0, TYPE_DD },	/*  1: d360 */
+	{  4, TYPE_HD },	/*  2: h1200 */
+	{  1, TYPE_DD },	/*  3: D360 */
+	{  2, TYPE_DD },	/*  4: D720 */
+	{  1, TYPE_DD },	/*  5: h360 = D360 */
+	{  2, TYPE_DD },	/*  6: h720 = D720 */
+	{  5, TYPE_HD },	/*  7: H1440 */
+	{  7, TYPE_ED },	/*  8: E2880 */
+/* some PC formats :-) */
+	{  8, TYPE_ED },	/*  9: E3280    <- was "CompaQ" == E2880 for PC */
+	{  5, TYPE_HD },	/* 10: h1440 = H1440 */
+	{  9, TYPE_HD },	/* 11: H1680 */
+	{ 10, TYPE_DD },	/* 12: h410  */
+	{  3, TYPE_DD },	/* 13: H820     <- == D820, 82x10 */
+	{ 11, TYPE_HD },	/* 14: h1476 */
+	{ 12, TYPE_HD },	/* 15: H1722 */
+	{ 13, TYPE_DD },	/* 16: h420  */
+	{ 14, TYPE_DD },	/* 17: H830  */
+	{ 15, TYPE_HD },	/* 18: h1494 */
+	{ 16, TYPE_HD },	/* 19: H1743 */
+	{ 17, TYPE_DD },	/* 20: h880  */
+	{ 18, TYPE_DD },	/* 21: D1040 */
+	{ 19, TYPE_DD },	/* 22: D1120 */
+	{ 20, TYPE_HD },	/* 23: h1600 */
+	{ 21, TYPE_HD },	/* 24: H1760 */
+	{ 22, TYPE_HD },	/* 25: H1920 */
+	{ 23, TYPE_ED },	/* 26: E3200 */
+	{ 24, TYPE_ED },	/* 27: E3520 */
+	{ 25, TYPE_ED },	/* 28: E3840 */
+	{ 26, TYPE_HD },	/* 29: H1840 */
+	{ 27, TYPE_DD },	/* 30: D800  */
+	{  6, TYPE_HD },	/* 31: H1640    <- was H1600 == h1600 for PC */
+};
+
+#define NUM_DISK_MINORS (sizeof(minor2disktype)/sizeof(*minor2disktype))
+
+/*
+ * Maximum disk size (in kilobytes). This default is used whenever the
+ * current disk size is unknown.
+ */
+#define MAX_DISK_SIZE 3280
+
+static int floppy_sizes[256];
+static int floppy_blocksizes[256] = { 0, };
+
+/* current info on each unit */
+static struct atari_floppy_struct {
+	int connected;				/* !=0 : drive is connected */
+	int autoprobe;				/* !=0 : do autoprobe	    */
+
+	struct atari_disk_type	*disktype;	/* current type of disk */
+
+	int track;		/* current head position or -1 if
+				   unknown */
+	unsigned int steprate;	/* steprate setting */
+	unsigned int wpstat;	/* current state of WP signal (for
+				   disk change detection) */
+	int flags;		/* flags */
+} unit[FD_MAX_UNITS];
+
+#define	UD	unit[drive]
+#define	UDT	unit[drive].disktype
+#define	SUD	unit[SelectedDrive]
+#define	SUDT	unit[SelectedDrive].disktype
+
+
+#define FDC_READ(reg) ({			\
+    /* unsigned long __flags; */		\
+    unsigned short __val;			\
+    /* save_flags(__flags); cli(); */		\
+    dma_wd.dma_mode_status = 0x80 | (reg);	\
+    udelay(25);					\
+    __val = dma_wd.fdc_acces_seccount;		\
+    MFPDELAY();					\
+    /* restore_flags(__flags); */		\
+    __val & 0xff;				\
+})
+
+#define FDC_WRITE(reg,val)			\
+    do {					\
+	/* unsigned long __flags; */		\
+	/* save_flags(__flags); cli(); */	\
+	dma_wd.dma_mode_status = 0x80 | (reg);	\
+	udelay(25);				\
+	dma_wd.fdc_acces_seccount = (val);	\
+	MFPDELAY();				\
+        /* restore_flags(__flags); */		\
+    } while(0)
+
+
+/* Buffering variables:
+ * First, there is a DMA buffer in ST-RAM that is used for floppy DMA
+ * operations. Second, a track buffer is used to cache a whole track
+ * of the disk to save read operations. These are two seperate buffers
+ * because that allows write operations without clearing the track buffer.
+ */
+
+static int MaxSectors[] = {
+	11, 22, 44
+};
+static int BufferSize[] = {
+	15*512, 30*512, 60*512
+};
+
+#define	MAX_SECTORS	(MaxSectors[DriveType])
+#define	BUFFER_SIZE	(BufferSize[DriveType])
+
+unsigned char *DMABuffer;			  /* buffer for writes */
+static unsigned long PhysDMABuffer;   /* physical address */
+
+static int UseTrackbuffer = -1;		  /* Do track buffering? */
+
+unsigned char *TrackBuffer;			  /* buffer for reads */
+static unsigned long PhysTrackBuffer; /* physical address */
+static int BufferDrive, BufferSide, BufferTrack;
+static int read_track;		/* non-zero if we are reading whole tracks */
+
+#define	SECTOR_BUFFER(sec)	(TrackBuffer + ((sec)-1)*512)
+#define	IS_BUFFERED(drive,side,track) \
+    (BufferDrive == (drive) && BufferSide == (side) && BufferTrack == (track))
+
+/*
+ * These are global variables, as that's the easiest way to give
+ * information to interrupts. They are the data used for the current
+ * request.
+ */
+static int SelectedDrive = 0;
+static int ReqCmd, ReqBlock;
+static int ReqSide, ReqTrack, ReqSector, ReqCnt;
+static int HeadSettleFlag = 0;
+static unsigned char *ReqData, *ReqBuffer;
+static int MotorOn = 0, MotorOffTrys;
+static int IsFormatting = 0, FormatError;
+
+static int UserSteprate[FD_MAX_UNITS] = { -1, -1 };
+
+/* Synchronization of FDC access. */
+static volatile int fdc_busy = 0;
+static struct wait_queue *fdc_wait = NULL;
+static struct wait_queue *format_wait = NULL;
+
+static unsigned int changed_floppies = 0xff, fake_change = 0;
+#define	CHECK_CHANGE_DELAY	HZ/2
+
+#define	FD_MOTOR_OFF_DELAY	(3*HZ)
+#define	FD_MOTOR_OFF_MAXTRY	(10*20)
+
+#define FLOPPY_TIMEOUT		(6*HZ)
+#define RECALIBRATE_ERRORS	4	/* Atfer this many errors the drive
+					 * will be recalibrated. */
+#define MAX_ERRORS		8	/* After this many errors the driver
+					 * will give up. */
+
+
+#define	START_MOTOR_OFF_TIMER(delay)				\
+    do {							\
+        motor_off_timer.expires = jiffies + (delay);		\
+        add_timer( &motor_off_timer );				\
+        MotorOffTrys = 0;					\
+	} while(0)
+
+#define	START_CHECK_CHANGE_TIMER(delay)				\
+    do {							\
+        timer_table[FLOPPY_TIMER].expires = jiffies + (delay);	\
+        timer_active |= (1 << FLOPPY_TIMER);			\
+	} while(0)
+
+#define	START_TIMEOUT()						\
+    do {							\
+        del_timer( &timeout_timer );				\
+        timeout_timer.expires = jiffies + FLOPPY_TIMEOUT;	\
+        add_timer( &timeout_timer );				\
+	} while(0)
+
+#define	STOP_TIMEOUT()						\
+    do {							\
+        del_timer( &timeout_timer );				\
+	} while(0)
+
+
+/*
+ * The driver is trying to determine the correct media format
+ * while Probing is set. fd_rwsec_done() clears it after a
+ * successful access.
+ */
+static int Probing = 0;
+
+/* This flag is set when a dummy seek is necesary to make the WP
+ * status bit accessible.
+ */
+static int NeedSeek = 0;
+
+
+#ifdef DEBUG
+#define DPRINT(a)	printk a
+#else
+#define DPRINT(a)
+#endif
+
+/***************************** Prototypes *****************************/
+
+static void fd_select_side( int side );
+static void fd_select_drive( int drive );
+static void fd_deselect( void );
+static void fd_motor_off_timer( unsigned long dummy );
+static void check_change( void );
+static __inline__ void set_head_settle_flag( void );
+static __inline__ int get_head_settle_flag( void );
+static void floppy_irq (int irq, struct pt_regs *fp, void *dummy);
+static void fd_error( void );
+static int do_format(kdev_t drive, struct atari_format_descr *desc);
+static void do_fd_action( int drive );
+static void fd_calibrate( void );
+static void fd_calibrate_done( int status );
+static void fd_seek( void );
+static void fd_seek_done( int status );
+static void fd_rwsec( void );
+static void fd_readtrack_check( unsigned long dummy );
+static void fd_rwsec_done( int status );
+static void fd_writetrack( void );
+static void fd_writetrack_done( int status );
+static void fd_times_out( unsigned long dummy );
+static void finish_fdc( void );
+static void finish_fdc_done( int dummy );
+static void floppy_off( unsigned int nr);
+static __inline__ void copy_buffer( void *from, void *to);
+static void setup_req_params( int drive );
+static void redo_fd_request( void);
+static int invalidate_drive(kdev_t rdev);
+static int fd_ioctl( struct inode *inode, struct file *filp, unsigned int
+                     cmd, unsigned long param);
+static void fd_probe( int drive );
+static int fd_test_drive_present( int drive );
+static void config_types( void );
+static int floppy_open( struct inode *inode, struct file *filp );
+static void floppy_release( struct inode * inode, struct file * filp );
+
+/************************* End of Prototypes **************************/
+
+static struct timer_list motor_off_timer =
+	{ NULL, NULL, 0, 0, fd_motor_off_timer };
+static struct timer_list readtrack_timer =
+	{ NULL, NULL, 0, 0, fd_readtrack_check };
+
+static struct timer_list timeout_timer =
+	{ NULL, NULL, 0, 0, fd_times_out };
+
+
+
+/* Select the side to use. */
+
+static void fd_select_side( int side )
+{
+	unsigned long flags;
+
+	save_flags(flags);
+	cli(); /* protect against various other ints mucking around with the PSG */
+  
+	sound_ym.rd_data_reg_sel = 14; /* Select PSG Port A */
+	sound_ym.wd_data = (side == 0) ? sound_ym.rd_data_reg_sel | 0x01 :
+	                                 sound_ym.rd_data_reg_sel & 0xfe;
+
+	restore_flags(flags);
+}
+
+
+/* Select a drive, update the FDC's track register and set the correct
+ * clock speed for this disk's type.
+ */
+
+static void fd_select_drive( int drive )
+{
+	unsigned long flags;
+	unsigned char tmp;
+  
+	if (drive == SelectedDrive)
+	  return;
+
+	save_flags(flags);
+	cli(); /* protect against various other ints mucking around with the PSG */
+	sound_ym.rd_data_reg_sel = 14; /* Select PSG Port A */
+	tmp = sound_ym.rd_data_reg_sel;
+	sound_ym.wd_data = (tmp | DSKDRVNONE) & ~(drive == 0 ? DSKDRV0 : DSKDRV1);
+	restore_flags(flags);
+
+	/* restore track register to saved value */
+	FDC_WRITE( FDCREG_TRACK, UD.track );
+	udelay(25);
+
+	/* select 8/16 MHz */
+	if (UDT)
+		if (ATARIHW_PRESENT(FDCSPEED))
+			dma_wd.fdc_speed = UDT->fdc_speed;
+	
+	SelectedDrive = drive;
+}
+
+
+/* Deselect both drives. */
+
+static void fd_deselect( void )
+{
+	unsigned long flags;
+
+	save_flags(flags);
+	cli(); /* protect against various other ints mucking around with the PSG */
+	sound_ym.rd_data_reg_sel=14;	/* Select PSG Port A */
+	sound_ym.wd_data = sound_ym.rd_data_reg_sel | 7; /* no drives selected */
+	SelectedDrive = -1;
+	restore_flags(flags);
+}
+
+
+/* This timer function deselects the drives when the FDC switched the
+ * motor off. The deselection cannot happen earlier because the FDC
+ * counts the index signals, which arrive only if one drive is selected.
+ */
+
+static void fd_motor_off_timer( unsigned long dummy )
+{
+/*	unsigned long flags; */
+	unsigned char status;
+	int		      delay;
+
+	del_timer( &motor_off_timer );
+	
+	if (SelectedDrive < 0)
+		/* no drive selected, needn't deselect anyone */
+		return;
+
+/*	save_flags(flags);
+	cli(); */
+	
+	if (stdma_islocked())
+		goto retry;
+
+	status = FDC_READ( FDCREG_STATUS );
+
+	if (!(status & 0x80)) {
+		/* motor already turned off by FDC -> deselect drives */
+		MotorOn = 0;
+		fd_deselect();
+/*		restore_flags(flags); */
+		return;
+	}
+	/* not yet off, try again */
+
+  retry:
+/*	restore_flags(flags); */
+	/* Test again later; if tested too often, it seems there is no disk
+	 * in the drive and the FDC will leave the motor on forever (or,
+	 * at least until a disk is inserted). So we'll test only twice
+	 * per second from then on...
+	 */
+	delay = (MotorOffTrys < FD_MOTOR_OFF_MAXTRY) ?
+		        (++MotorOffTrys, HZ/20) : HZ/2;
+	START_MOTOR_OFF_TIMER( delay );
+}
+
+
+/* This function is repeatedly called to detect disk changes (as good
+ * as possible) and keep track of the current state of the write protection.
+ */
+
+static void check_change( void )
+{
+	static int    drive = 0;
+
+	unsigned long flags;
+	unsigned char old_porta;
+	int			  stat;
+
+	if (++drive > 1 || !UD.connected)
+		drive = 0;
+
+	save_flags(flags);
+	cli(); /* protect against various other ints mucking around with the PSG */
+
+	if (!stdma_islocked()) {
+		sound_ym.rd_data_reg_sel = 14;
+		old_porta = sound_ym.rd_data_reg_sel;
+		sound_ym.wd_data = (old_porta | DSKDRVNONE) &
+			               ~(drive == 0 ? DSKDRV0 : DSKDRV1);
+		stat = !!(FDC_READ( FDCREG_STATUS ) & FDCSTAT_WPROT);
+		sound_ym.wd_data = old_porta;
+
+		if (stat != UD.wpstat) {
+			DPRINT(( "wpstat[%d] = %d\n", drive, stat ));
+			UD.wpstat = stat;
+			set_bit (drive, &changed_floppies);
+		}
+	}
+	restore_flags(flags);
+
+	START_CHECK_CHANGE_TIMER( CHECK_CHANGE_DELAY );
+}
+
+ 
+/* Handling of the Head Settling Flag: This flag should be set after each
+ * seek operation, because we dont't use seeks with verify.
+ */
+
+static __inline__ void set_head_settle_flag( void )
+{
+	HeadSettleFlag = FDCCMDADD_E;
+}
+
+static __inline__ int get_head_settle_flag( void )
+{
+	int	tmp = HeadSettleFlag;
+	HeadSettleFlag = 0;
+	return( tmp );
+}
+
+  
+  
+
+/* General Interrupt Handling */
+
+static void (*FloppyIRQHandler)( int status ) = NULL;
+
+static void floppy_irq (int irq, struct pt_regs *fp, void *dummy)
+{
+	unsigned char status;
+	void (*handler)( int );
+
+	handler = FloppyIRQHandler;
+	FloppyIRQHandler = NULL;
+
+	if (handler) {
+		nop();
+		status = FDC_READ( FDCREG_STATUS );
+		DPRINT(("FDC irq, status = %02x handler = %08lx\n",status,(unsigned long)handler));
+		handler( status );
+	}
+	else {
+		DPRINT(("FDC irq, no handler\n"));
+	}
+}
+
+
+/* Error handling: If some error happened, retry some times, then
+ * recalibrate, then try again, and fail after MAX_ERRORS.
+ */
+
+static void fd_error( void )
+{
+	if (IsFormatting) {
+		IsFormatting = 0;
+		FormatError = 1;
+		wake_up( &format_wait );
+		return;
+	}
+		
+	if (!CURRENT) return;
+	CURRENT->errors++;
+	if (CURRENT->errors >= MAX_ERRORS) {
+		printk( "fd%d: too many errors.\n", SelectedDrive );
+		end_request( 0 );
+	}
+	else if (CURRENT->errors == RECALIBRATE_ERRORS) {
+		printk( "fd%d: recalibrating\n", SelectedDrive );
+		if (SelectedDrive != -1)
+			SUD.track = -1;
+	}
+	redo_fd_request();
+}
+
+
+
+#define	SET_IRQ_HANDLER(proc) do { FloppyIRQHandler = (proc); } while(0)
+
+
+/* ---------- Formatting ---------- */
+
+#define FILL(n,val)		\
+    do {			\
+	memset( p, val, n );	\
+	p += n;			\
+    } while(0)
+
+static int do_format(kdev_t device, struct atari_format_descr *desc)
+{
+	unsigned char	*p;
+	int sect, nsect;
+	unsigned long	flags;
+	int type, drive = MINOR(device) & 3;
+
+	DPRINT(("do_format( dr=%d tr=%d he=%d offs=%d )\n",
+		drive, desc->track, desc->head, desc->sect_offset ));
+
+	save_flags(flags);
+	cli();
+	while( fdc_busy ) sleep_on( &fdc_wait );
+	fdc_busy = 1;
+	stdma_lock(floppy_irq, NULL);
+	atari_turnon_irq( IRQ_MFP_FDC ); /* should be already, just to be sure */
+	restore_flags(flags);
+
+	type = MINOR(device) >> 2;
+	if (type) {
+		if (--type >= NUM_DISK_MINORS ||
+		    minor2disktype[type].drive_types > DriveType) {
+			redo_fd_request();
+			return -EINVAL;
+		}
+		type = minor2disktype[type].index;
+		UDT = &disk_type[type];
+	}
+
+	if (!UDT || desc->track >= UDT->blocks/UDT->spt/2 || desc->head >= 2) {
+		redo_fd_request();
+		return -EINVAL;
+	}
+
+	nsect = UDT->spt;
+	p = TrackBuffer;
+	/* The track buffer is used for the raw track data, so its
+	   contents become invalid! */
+	BufferDrive = -1;
+	/* stop deselect timer */
+	del_timer( &motor_off_timer );
+
+	FILL( 60 * (nsect / 9), 0x4e );
+	for( sect = 0; sect < nsect; ++sect ) {
+		FILL( 12, 0 );
+		FILL( 3, 0xf5 );
+		*p++ = 0xfe;
+		*p++ = desc->track;
+		*p++ = desc->head;
+		*p++ = (nsect + sect - desc->sect_offset) % nsect + 1;
+		*p++ = 2;
+		*p++ = 0xf7;
+		FILL( 22, 0x4e );
+		FILL( 12, 0 );
+		FILL( 3, 0xf5 );
+		*p++ = 0xfb;
+		FILL( 512, 0xe5 );
+		*p++ = 0xf7;
+		FILL( 40, 0x4e );
+	}
+	FILL( TrackBuffer+BUFFER_SIZE-p, 0x4e );
+
+	IsFormatting = 1;
+	FormatError = 0;
+	ReqTrack = desc->track;
+	ReqSide  = desc->head;
+	do_fd_action( drive );
+
+	sleep_on( &format_wait );
+
+	redo_fd_request();
+	return( FormatError ? -EIO : 0 );	
+}
+
+
+/* do_fd_action() is the general procedure for a fd request: All
+ * required parameter settings (drive select, side select, track
+ * position) are checked and set if needed. For each of these
+ * parameters and the actual reading or writing exist two functions:
+ * one that starts the setting (or skips it if possible) and one
+ * callback for the "done" interrupt. Each done func calls the next
+ * set function to propagate the request down to fd_rwsec_done().
+ */
+
+static void do_fd_action( int drive )
+{
+	DPRINT(("do_fd_action\n"));
+	
+	if (UseTrackbuffer && !IsFormatting) {
+	repeat:
+	    if (IS_BUFFERED( drive, ReqSide, ReqTrack )) {
+		if (ReqCmd == READ) {
+		    copy_buffer( SECTOR_BUFFER(ReqSector), ReqData );
+		    if (++ReqCnt < CURRENT->current_nr_sectors) {
+			/* read next sector */
+			setup_req_params( drive );
+			goto repeat;
+		    }
+		    else {
+			/* all sectors finished */
+			CURRENT->nr_sectors -= CURRENT->current_nr_sectors;
+			CURRENT->sector += CURRENT->current_nr_sectors;
+			end_request( 1 );
+			redo_fd_request();
+			return;
+		    }
+		}
+		else {
+		    /* cmd == WRITE, pay attention to track buffer
+		     * consistency! */
+		    copy_buffer( ReqData, SECTOR_BUFFER(ReqSector) );
+		}
+	    }
+	}
+
+	if (SelectedDrive != drive)
+		fd_select_drive( drive );
+    
+	if (UD.track == -1)
+		fd_calibrate();
+	else if (UD.track != ReqTrack << UDT->stretch)
+		fd_seek();
+	else if (IsFormatting)
+		fd_writetrack();
+	else
+		fd_rwsec();
+}
+
+
+/* Seek to track 0 if the current track is unknown */
+
+static void fd_calibrate( void )
+{
+	if (SUD.track >= 0) {
+		fd_calibrate_done( 0 );
+		return;
+	}
+
+	if (ATARIHW_PRESENT(FDCSPEED))
+		dma_wd.fdc_speed = 0; 	/* always seek with 8 Mhz */;
+	DPRINT(("fd_calibrate\n"));
+	SET_IRQ_HANDLER( fd_calibrate_done );
+	/* we can't verify, since the speed may be incorrect */
+	FDC_WRITE( FDCREG_CMD, FDCCMD_RESTORE | SUD.steprate );
+
+	NeedSeek = 1;
+	MotorOn = 1;
+	START_TIMEOUT();
+	/* wait for IRQ */
+}
+
+
+static void fd_calibrate_done( int status )
+{
+	DPRINT(("fd_calibrate_done()\n"));
+	STOP_TIMEOUT();
+    
+	/* set the correct speed now */
+	if (ATARIHW_PRESENT(FDCSPEED))
+		dma_wd.fdc_speed = SUDT->fdc_speed;
+	if (status & FDCSTAT_RECNF) {
+		printk( "fd%d: restore failed\n", SelectedDrive );
+		fd_error();
+	}
+	else {
+		SUD.track = 0;
+		fd_seek();
+	}
+}
+  
+  
+/* Seek the drive to the requested track. The drive must have been
+ * calibrated at some point before this.
+ */
+  
+static void fd_seek( void )
+{
+	if (SUD.track == ReqTrack << SUDT->stretch) {
+		fd_seek_done( 0 );
+		return;
+	}
+
+	if (ATARIHW_PRESENT(FDCSPEED)) {
+		dma_wd.fdc_speed = 0;	/* always seek witch 8 Mhz */
+		MFPDELAY();
+	}
+
+	DPRINT(("fd_seek() to track %d\n",ReqTrack));
+	FDC_WRITE( FDCREG_DATA, ReqTrack << SUDT->stretch);
+	udelay(25);
+	SET_IRQ_HANDLER( fd_seek_done );
+	FDC_WRITE( FDCREG_CMD, FDCCMD_SEEK | SUD.steprate );
+
+	MotorOn = 1;
+	set_head_settle_flag();
+	START_TIMEOUT();
+	/* wait for IRQ */
+}
+
+
+static void fd_seek_done( int status )
+{
+	DPRINT(("fd_seek_done()\n"));
+	STOP_TIMEOUT();
+	
+	/* set the correct speed */
+	if (ATARIHW_PRESENT(FDCSPEED))
+		dma_wd.fdc_speed = SUDT->fdc_speed;
+	if (status & FDCSTAT_RECNF) {
+		printk( "fd%d: seek error (to track %d)\n",
+				SelectedDrive, ReqTrack );
+		/* we don't know exactly which track we are on now! */
+		SUD.track = -1;
+		fd_error();
+	}
+	else {
+		SUD.track = ReqTrack << SUDT->stretch;
+		NeedSeek = 0;
+		if (IsFormatting)
+			fd_writetrack();
+		else
+			fd_rwsec();
+	}
+}
+
+
+/* This does the actual reading/writing after positioning the head
+ * over the correct track.
+ */
+
+static int MultReadInProgress = 0;
+
+
+static void fd_rwsec( void )
+{
+	unsigned long paddr, flags;
+	unsigned int  rwflag, old_motoron;
+	unsigned int track;
+	
+	DPRINT(("fd_rwsec(), Sec=%d, Access=%c\n",ReqSector, ReqCmd == WRITE ? 'w' : 'r' ));
+	if (ReqCmd == WRITE) {
+		if (ATARIHW_PRESENT(EXTD_DMA)) {
+			paddr = (unsigned long)VTOP(ReqData);
+		}
+		else {
+			copy_buffer( ReqData, DMABuffer );
+			paddr = PhysDMABuffer;
+		}
+		dma_cache_maintainance( paddr, 512, 1 );
+		rwflag = 0x100;
+	}
+	else {
+		if (read_track)
+			paddr = PhysTrackBuffer;
+		else
+			paddr = ATARIHW_PRESENT(EXTD_DMA) ? VTOP(ReqData) : PhysDMABuffer;
+		rwflag = 0;
+	}
+
+	fd_select_side( ReqSide );
+  
+	/* Start sector of this operation */
+	FDC_WRITE( FDCREG_SECTOR, read_track ? 1 : ReqSector );
+	MFPDELAY();
+	/* Cheat for track if stretch != 0 */
+	if (SUDT->stretch) {
+		track = FDC_READ( FDCREG_TRACK);
+		MFPDELAY();
+		FDC_WRITE( FDCREG_TRACK, track >> SUDT->stretch);
+	}
+	udelay(25);
+  
+	/* Setup DMA */
+	save_flags(flags);  
+	cli();
+	dma_wd.dma_lo = (unsigned char)paddr;
+	MFPDELAY();
+	paddr >>= 8;
+	dma_wd.dma_md = (unsigned char)paddr;
+	MFPDELAY();
+	paddr >>= 8;
+	if (ATARIHW_PRESENT(EXTD_DMA))
+		st_dma_ext_dmahi = (unsigned short)paddr;
+	else
+		dma_wd.dma_hi = (unsigned char)paddr;
+	MFPDELAY();
+	restore_flags(flags);
+  
+	/* Clear FIFO and switch DMA to correct mode */  
+	dma_wd.dma_mode_status = 0x90 | rwflag;  
+	MFPDELAY();
+	dma_wd.dma_mode_status = 0x90 | (rwflag ^ 0x100);  
+	MFPDELAY();
+	dma_wd.dma_mode_status = 0x90 | rwflag;
+	MFPDELAY();
+  
+	/* How many sectors for DMA */
+	dma_wd.fdc_acces_seccount = read_track ? SUDT->spt : 1;
+  
+	udelay(25);  
+  
+	/* Start operation */
+	dma_wd.dma_mode_status = FDCSELREG_STP | rwflag;
+	udelay(25);
+	SET_IRQ_HANDLER( fd_rwsec_done );
+	dma_wd.fdc_acces_seccount =
+	  (get_head_settle_flag() |
+	   (rwflag ? FDCCMD_WRSEC : (FDCCMD_RDSEC | (read_track ? FDCCMDADD_M : 0))));
+
+	old_motoron = MotorOn;
+	MotorOn = 1;
+	NeedSeek = 1;
+	/* wait for interrupt */
+
+	if (read_track) {
+		/* If reading a whole track, wait about one disk rotation and
+		 * then check if all sectors are read. The FDC will even
+		 * search for the first non-existant sector and need 1 sec to
+		 * recognise that it isn't present :-(
+		 */
+		readtrack_timer.expires =
+		  jiffies + HZ/5 + (old_motoron ? 0 : HZ);
+		       /* 1 rot. + 5 rot.s if motor was off  */
+		add_timer( &readtrack_timer );
+		MultReadInProgress = 1;
+	}
+	START_TIMEOUT();
+}
+
+    
+static void fd_readtrack_check( unsigned long dummy )
+{
+	unsigned long flags, addr, addr2;
+
+	save_flags(flags);  
+	cli();
+
+	del_timer( &readtrack_timer );
+
+	if (!MultReadInProgress) {
+		/* This prevents a race condition that could arise if the
+		 * interrupt is triggered while the calling of this timer
+		 * callback function takes place. The IRQ function then has
+		 * already cleared 'MultReadInProgress'  when flow of control
+		 * gets here.
+		 */
+		restore_flags(flags);
+		return;
+	}
+
+	/* get the current DMA address */
+	/* ++ f.a. read twice to avoid being fooled by switcher */
+	addr = 0;
+	do {
+		addr2 = addr;
+		addr = dma_wd.dma_lo & 0xff;
+		MFPDELAY();
+		addr |= (dma_wd.dma_md & 0xff) << 8;
+		MFPDELAY();
+		if (ATARIHW_PRESENT( EXTD_DMA ))
+			addr |= (st_dma_ext_dmahi & 0xffff) << 16;
+		else
+			addr |= (dma_wd.dma_hi & 0xff) << 16;
+		MFPDELAY();
+	} while(addr != addr2);
+  
+	if (addr >= PhysTrackBuffer + SUDT->spt*512) {
+		/* already read enough data, force an FDC interrupt to stop
+		 * the read operation
+		 */
+		SET_IRQ_HANDLER( NULL );
+		restore_flags(flags);
+		DPRINT(("fd_readtrack_check(): done\n"));
+		FDC_WRITE( FDCREG_CMD, FDCCMD_FORCI );
+		udelay(25);
+
+		/* No error until now -- the FDC would have interrupted
+		 * otherwise!
+		 */
+		fd_rwsec_done( 0 );
+	}
+	else {
+		/* not yet finished, wait another tenth rotation */
+		restore_flags(flags);
+		DPRINT(("fd_readtrack_check(): not yet finished\n"));
+		readtrack_timer.expires = jiffies + HZ/5/10;
+		add_timer( &readtrack_timer );
+	}
+}
+
+
+static void fd_rwsec_done( int status )
+{
+	unsigned int track;
+
+	DPRINT(("fd_rwsec_done()\n"));
+
+	STOP_TIMEOUT();
+	
+	if (read_track) {
+		if (!MultReadInProgress)
+			return;
+		MultReadInProgress = 0;
+		del_timer( &readtrack_timer );
+	}
+
+	/* Correct the track if stretch != 0 */
+	if (SUDT->stretch) {
+		track = FDC_READ( FDCREG_TRACK);
+		MFPDELAY();
+		FDC_WRITE( FDCREG_TRACK, track << SUDT->stretch);
+	}
+
+	if (!UseTrackbuffer) {
+		dma_wd.dma_mode_status = 0x90;
+		MFPDELAY();
+		if (!(dma_wd.dma_mode_status & 0x01)) {
+			printk( "fd%d: DMA error\n", SelectedDrive );
+			goto err_end;
+		}
+	}
+	MFPDELAY();
+
+	if (ReqCmd == WRITE && (status & FDCSTAT_WPROT)) {
+		printk( "fd%d: is write protected\n", SelectedDrive );
+		goto err_end;
+	}	
+	if ((status & FDCSTAT_RECNF) &&
+	    /* RECNF is no error after a multiple read when the FDC
+	       searched for a non-existant sector! */
+	    !(read_track && FDC_READ(FDCREG_SECTOR) > SUDT->spt)) {
+		if (Probing) {
+			if (SUDT > disk_type) {
+				/* try another disk type */
+				SUDT--;
+				floppy_sizes[SelectedDrive] = SUDT->blocks >> 1;
+			}
+			else {
+				if (SUD.flags & FTD_MSG)
+					printk( "fd%d: Auto-detected floppy type %s\n",
+					       SelectedDrive, SUDT->name );
+				Probing=0;
+			}
+		} else {	
+/* record not found, but not probing. Maybe stretch wrong ? Restart probing */
+			if (SUD.autoprobe) {
+				SUDT = disk_type + StartDiskType[DriveType];
+				floppy_sizes[SelectedDrive] = SUDT->blocks >> 1;
+				Probing = 1;
+			}
+		}
+		if (Probing) {
+			if (ATARIHW_PRESENT(FDCSPEED)) {
+				dma_wd.fdc_speed = SUDT->fdc_speed;
+				MFPDELAY();
+			}
+			setup_req_params( SelectedDrive );
+			BufferDrive = -1;
+			do_fd_action( SelectedDrive );
+			return;
+		}
+
+		printk( "fd%d: sector %d not found (side %d, track %d)\n",
+		       SelectedDrive, FDC_READ (FDCREG_SECTOR), ReqSide, ReqTrack );
+		goto err_end;
+	}
+	if (status & FDCSTAT_CRC) {
+		printk( "fd%d: CRC error (side %d, track %d, sector %d)\n",
+		       SelectedDrive, ReqSide, ReqTrack, FDC_READ (FDCREG_SECTOR) );
+		goto err_end;
+	}
+	if (status & FDCSTAT_LOST) {
+		printk( "fd%d: lost data (side %d, track %d, sector %d)\n",
+		       SelectedDrive, ReqSide, ReqTrack, FDC_READ (FDCREG_SECTOR) );
+		goto err_end;
+	}
+
+	Probing = 0;
+	
+	if (ReqCmd == READ) {
+		if (!read_track) {
+			void *addr;
+			addr = ATARIHW_PRESENT( EXTD_DMA ) ? ReqData : DMABuffer;
+			dma_cache_maintainance( VTOP(addr), 512, 0 );
+			if (!ATARIHW_PRESENT( EXTD_DMA ))
+				copy_buffer (addr, ReqData);
+		} else {
+			dma_cache_maintainance( PhysTrackBuffer, MAX_SECTORS * 512, 0 );
+			BufferDrive = SelectedDrive;
+			BufferSide  = ReqSide;
+			BufferTrack = ReqTrack;
+			copy_buffer (SECTOR_BUFFER (ReqSector), ReqData);
+		}
+	}
+  
+	if (++ReqCnt < CURRENT->current_nr_sectors) {
+		/* read next sector */
+		setup_req_params( SelectedDrive );
+		do_fd_action( SelectedDrive );
+	}
+	else {
+		/* all sectors finished */
+		CURRENT->nr_sectors -= CURRENT->current_nr_sectors;
+		CURRENT->sector += CURRENT->current_nr_sectors;
+		end_request( 1 );
+		redo_fd_request();
+	}
+	return;
+  
+  err_end:
+	BufferDrive = -1;
+	fd_error();
+}
+
+
+static void fd_writetrack( void )
+{
+	unsigned long paddr, flags;
+	unsigned int track;
+	
+	DPRINT(("fd_writetrack() Tr=%d Si=%d\n", ReqTrack, ReqSide ));
+
+	paddr = PhysTrackBuffer;
+	dma_cache_maintainance( paddr, BUFFER_SIZE, 1 );
+
+	fd_select_side( ReqSide );
+  
+	/* Cheat for track if stretch != 0 */
+	if (SUDT->stretch) {
+		track = FDC_READ( FDCREG_TRACK);
+		MFPDELAY();
+		FDC_WRITE(FDCREG_TRACK,track >> SUDT->stretch);
+	}
+	udelay(40);
+  
+	/* Setup DMA */
+	save_flags(flags);  
+	cli();
+	dma_wd.dma_lo = (unsigned char)paddr;
+	MFPDELAY();
+	paddr >>= 8;
+	dma_wd.dma_md = (unsigned char)paddr;
+	MFPDELAY();
+	paddr >>= 8;
+	if (ATARIHW_PRESENT( EXTD_DMA ))
+		st_dma_ext_dmahi = (unsigned short)paddr;
+	else
+		dma_wd.dma_hi = (unsigned char)paddr;
+	MFPDELAY();
+	restore_flags(flags);
+  
+	/* Clear FIFO and switch DMA to correct mode */  
+	dma_wd.dma_mode_status = 0x190;  
+	MFPDELAY();
+	dma_wd.dma_mode_status = 0x90;  
+	MFPDELAY();
+	dma_wd.dma_mode_status = 0x190;
+	MFPDELAY();
+  
+	/* How many sectors for DMA */
+	dma_wd.fdc_acces_seccount = BUFFER_SIZE/512;
+	udelay(40);  
+  
+	/* Start operation */
+	dma_wd.dma_mode_status = FDCSELREG_STP | 0x100;
+	udelay(40);
+	SET_IRQ_HANDLER( fd_writetrack_done );
+	dma_wd.fdc_acces_seccount = FDCCMD_WRTRA | get_head_settle_flag(); 
+
+	MotorOn = 1;
+	START_TIMEOUT();
+	/* wait for interrupt */
+}
+
+
+static void fd_writetrack_done( int status )
+{
+	DPRINT(("fd_writetrack_done()\n"));
+
+	STOP_TIMEOUT();
+
+	if (status & FDCSTAT_WPROT) {
+		printk( "fd%d: is write protected\n", SelectedDrive );
+		goto err_end;
+	}	
+	if (status & FDCSTAT_LOST) {
+		printk( "fd%d: lost data (side %d, track %d)\n",
+				SelectedDrive, ReqSide, ReqTrack );
+		goto err_end;
+	}
+
+	wake_up( &format_wait );
+	return;
+
+  err_end:
+	fd_error();
+}
+
+static void fd_times_out( unsigned long dummy )
+{
+	atari_disable_irq( IRQ_MFP_FDC );
+	if (!FloppyIRQHandler) goto end; /* int occured after timer was fired, but
+					  * before we came here... */
+
+	SET_IRQ_HANDLER( NULL );
+	/* If the timeout occured while the readtrack_check timer was
+	 * active, we need to cancel it, else bad things will happen */
+	if (UseTrackbuffer)
+		del_timer( &readtrack_timer );
+	FDC_WRITE( FDCREG_CMD, FDCCMD_FORCI );
+	udelay( 25 );
+	
+	printk( "floppy timeout\n" );
+	fd_error();
+  end:
+	atari_enable_irq( IRQ_MFP_FDC );
+}
+
+
+/* The (noop) seek operation here is needed to make the WP bit in the
+ * FDC status register accessible for check_change. If the last disk
+ * operation would have been a RDSEC, this bit would always read as 0
+ * no matter what :-( To save time, the seek goes to the track we're
+ * already on.
+ */
+
+static void finish_fdc( void )
+{
+	if (!NeedSeek) {
+		finish_fdc_done( 0 );
+	}
+	else {
+		DPRINT(("finish_fdc: dummy seek started\n"));
+		FDC_WRITE (FDCREG_DATA, SUD.track);
+		SET_IRQ_HANDLER( finish_fdc_done );
+		FDC_WRITE (FDCREG_CMD, FDCCMD_SEEK);
+		MotorOn = 1;
+		START_TIMEOUT();
+		/* we must wait for the IRQ here, because the ST-DMA
+		   is released immediatly afterwards and the interrupt
+		   may be delivered to the wrong driver. */
+	  }
+}
+
+
+static void finish_fdc_done( int dummy )
+{
+	unsigned long flags;
+
+	DPRINT(("finish_fdc_done entered\n"));
+	STOP_TIMEOUT();
+	NeedSeek = 0;
+
+	if ((timer_active & (1 << FLOPPY_TIMER)) &&
+	    timer_table[FLOPPY_TIMER].expires < jiffies + 5)
+		/* If the check for a disk change is done too early after this
+		 * last seek command, the WP bit still reads wrong :-((
+		 */
+		timer_table[FLOPPY_TIMER].expires = jiffies + 5;
+	else
+		START_CHECK_CHANGE_TIMER( CHECK_CHANGE_DELAY );
+	del_timer( &motor_off_timer );
+	START_MOTOR_OFF_TIMER( FD_MOTOR_OFF_DELAY );
+
+	save_flags(flags);
+	cli();
+	stdma_release();
+	fdc_busy = 0;
+	wake_up( &fdc_wait );
+	restore_flags(flags);
+
+	DPRINT(("finish_fdc() finished\n"));
+}
+
+
+/* Prevent "aliased" accesses. */
+static fd_ref[4] = { 0,0,0,0 };
+static fd_device[4] = { 0,0,0,0 };
+
+/*
+ * Current device number. Taken either from the block header or from the
+ * format request descriptor.
+ */
+#define CURRENT_DEVICE (CURRENT->rq_dev)
+
+/* Current error count. */
+#define CURRENT_ERRORS (CURRENT->errors)
+
+
+/* dummy for blk.h */
+static void floppy_off( unsigned int nr) {}
+
+
+/* The detection of disk changes is a dark chapter in Atari history :-(
+ * Because the "Drive ready" signal isn't present in the Atari
+ * hardware, one has to rely on the "Write Protect". This works fine,
+ * as long as no write protected disks are used. TOS solves this
+ * problem by introducing tri-state logic ("maybe changed") and
+ * looking at the serial number in block 0. This isn't possible for
+ * Linux, since the floppy driver can't make assumptions about the
+ * filesystem used on the disk and thus the contents of block 0. I've
+ * choosen the method to always say "The disk was changed" if it is
+ * unsure whether it was. This implies that every open or mount
+ * invalidates the disk buffers if you work with write protected
+ * disks. But at least this is better than working with incorrect data
+ * due to unrecognised disk changes.
+ */
+
+static int check_floppy_change (kdev_t dev)
+{
+	unsigned int drive = MINOR(dev) & 0x03;
+
+	if (MAJOR(dev) != MAJOR_NR) {
+		printk("floppy_changed: not a floppy\n");
+		return 0;
+	}
+	
+	if (test_bit (drive, &fake_change)) {
+		/* simulated change (e.g. after formatting) */
+		return 1;
+	}
+	if (test_bit (drive, &changed_floppies)) {
+		/* surely changed (the WP signal changed at least once) */
+		return 1;
+	}
+	if (UD.wpstat) {
+		/* WP is on -> could be changed: to be sure, buffers should be
+		 * invalidated...
+		 */
+		return 1;
+	}
+
+	return 0;
+}
+
+static int floppy_revalidate (kdev_t dev)
+{
+  int drive = MINOR(dev) & 3;
+
+  if (test_bit (drive, &changed_floppies) || test_bit (drive, &fake_change)
+      || unit[drive].disktype == 0)
+    {
+      BufferDrive = -1;
+      clear_bit (drive, &fake_change);
+      clear_bit (drive, &changed_floppies);
+      UDT = 0;
+    }
+  return 0;
+}
+
+static __inline__ void copy_buffer(void *from, void *to)
+{
+	ulong	*p1 = (ulong *)from, *p2 = (ulong *)to;
+	int		cnt;
+
+	for( cnt = 512/4; cnt; cnt-- )
+		*p2++ = *p1++;
+}
+
+
+/* This sets up the global variables describing the current request. */
+
+static void setup_req_params( int drive )
+{
+	int block = ReqBlock + ReqCnt;
+
+	ReqTrack = block / UDT->spt;
+	ReqSector = block - ReqTrack * UDT->spt + 1;
+	ReqSide = ReqTrack & 1;
+	ReqTrack >>= 1;
+	ReqData = ReqBuffer + 512 * ReqCnt;
+
+	if (UseTrackbuffer)
+		read_track = (ReqCmd == READ && CURRENT_ERRORS == 0);
+	else
+		read_track = 0;
+
+	DPRINT(("Request params: Si=%d Tr=%d Se=%d Data=%08lx\n",ReqSide,
+			ReqTrack, ReqSector, (unsigned long)ReqData ));
+}
+
+
+static void redo_fd_request(void)
+{
+	int device, drive, type;
+  
+	DPRINT(("redo_fd_request: CURRENT=%08lx CURRENT->dev=%04x CURRENT->sector=%ld\n",
+		(unsigned long)CURRENT, CURRENT ? CURRENT->rq_dev : 0,
+		CURRENT ? CURRENT->sector : 0 ));
+
+	IsFormatting = 0;
+
+	if (CURRENT && CURRENT->rq_status == RQ_INACTIVE){
+		return;
+	}
+
+repeat:
+    
+	if (!CURRENT)
+		goto the_end;
+
+	if (MAJOR(CURRENT->rq_dev) != MAJOR_NR)
+		panic(DEVICE_NAME ": request list destroyed");
+
+	if (CURRENT->bh && !buffer_locked(CURRENT->bh))
+		panic(DEVICE_NAME ": block not locked");
+
+	device = MINOR(CURRENT_DEVICE);
+	drive = device & 3;
+	type = device >> 2;
+	
+	if (!UD.connected) {
+		/* drive not connected */
+		printk( "Unknown Device: fd%d\n", drive );
+		end_request(0);
+		goto repeat;
+	}
+		
+	if (type == 0) {
+		if (!UDT) {
+			Probing = 1;
+			UDT = disk_type + StartDiskType[DriveType];
+			floppy_sizes[drive] = UDT->blocks >> 1;
+			UD.autoprobe = 1;
+		}
+	} 
+	else {
+		/* user supplied disk type */
+		if (--type >= NUM_DISK_MINORS) {
+			printk( "fd%d: invalid disk format", drive );
+			end_request( 0 );
+			goto repeat;
+		}
+		if (minor2disktype[type].drive_types > DriveType)  {
+			printk( "fd%d: unsupported disk format", drive );
+			end_request( 0 );
+			goto repeat;
+		}
+		type = minor2disktype[type].index;
+		UDT = &disk_type[type];
+		floppy_sizes[drive] = UDT->blocks >> 1;
+		UD.autoprobe = 0;
+	}
+	
+	if (CURRENT->sector + 1 > UDT->blocks) {
+		end_request(0);
+		goto repeat;
+	}
+
+	/* stop deselect timer */
+	del_timer( &motor_off_timer );
+		
+	ReqCnt = 0;
+	ReqCmd = CURRENT->cmd;
+	ReqBlock = CURRENT->sector;
+	ReqBuffer = CURRENT->buffer;
+	setup_req_params( drive );
+	do_fd_action( drive );
+
+	return;
+
+  the_end:
+	finish_fdc();
+}
+
+
+void do_fd_request(void)
+{
+ 	unsigned long flags;
+
+	DPRINT(("do_fd_request for pid %d\n",current->pid));
+	while( fdc_busy ) sleep_on( &fdc_wait );
+	fdc_busy = 1;
+	stdma_lock(floppy_irq, NULL);
+
+	atari_disable_irq( IRQ_MFP_FDC );
+	save_flags(flags);	/* The request function is called with ints
+	sti();				 * disabled... so must save the IPL for later */ 
+	redo_fd_request();
+	restore_flags(flags);
+	atari_enable_irq( IRQ_MFP_FDC );
+}
+
+
+static int
+invalidate_drive (kdev_t rdev)
+{
+  /* invalidate the buffer track to force a reread */
+  BufferDrive = -1;
+  set_bit (MINOR(rdev) & 3, &fake_change);
+  check_disk_change (rdev);
+  return 0;
+}
+
+static int fd_ioctl(struct inode *inode, struct file *filp,
+		    unsigned int cmd, unsigned long param)
+{
+#define IOCTL_MODE_BIT 8
+#define OPEN_WRITE_BIT 16
+#define IOCTL_ALLOWED (filp && (filp->f_mode & IOCTL_MODE_BIT))
+#define COPYIN(x) (memcpy_fromfs( &(x), (void *) param, sizeof(x)))
+
+	int drive, type, error;
+	kdev_t device;
+	struct atari_format_descr fmt_desc;
+	struct atari_disk_type *dtp;
+	struct floppy_struct getprm;
+
+	device = inode->i_rdev;
+	switch (cmd) {
+		RO_IOCTLS (device, param);
+	}
+	drive = MINOR (device);
+	type  = drive >> 2;
+	drive &= 3;
+	switch (cmd) {
+	case FDGETPRM:
+		if (type) {
+			if (--type >= NUM_DISK_MINORS)
+				return -ENODEV;
+			if (minor2disktype[type].drive_types > DriveType)
+				return -ENODEV;
+			type = minor2disktype[type].index;
+			dtp = &disk_type[type];
+		}
+		else {
+			if (!UDT)
+				return -ENXIO;
+			else
+				dtp = UDT;
+		}
+		error = verify_area(VERIFY_WRITE, (void *)param,
+				    sizeof(struct floppy_struct));
+		if (error)
+			return( error );
+		memset((void *)&getprm, 0, sizeof(getprm));
+		getprm.size = dtp->blocks;
+		getprm.sect = dtp->spt;
+		getprm.head = 2;
+		getprm.track = dtp->blocks/dtp->spt/2;
+		getprm.stretch = dtp->stretch;
+		memcpy_tofs((void *)param, &getprm, sizeof(struct floppy_struct));
+		return 0;
+	}
+	if (!IOCTL_ALLOWED)
+		return -EPERM;
+	switch (cmd) {
+	case FDSETPRM:
+	case FDDEFPRM:
+		return -EINVAL;
+	case FDMSGON:
+		UD.flags |= FTD_MSG;
+		return 0;
+	case FDMSGOFF:
+		UD.flags &= ~FTD_MSG;
+		return 0;
+	case FDSETEMSGTRESH:
+		return -EINVAL;
+	case FDFMTBEG:
+		return 0;
+	case FDFMTTRK:
+		if (fd_ref[drive] != 1 && fd_ref[drive] != -1)
+			return -EBUSY;
+		if ((error = verify_area(VERIFY_READ, (void *)param,
+					 sizeof(struct atari_format_descr) )))
+			return( error );
+		COPYIN( fmt_desc );
+		return do_format(device, &fmt_desc);
+	case FDCLRPRM:
+		UDT = NULL;
+		floppy_sizes[drive] = MAX_DISK_SIZE;
+		return invalidate_drive (device);
+	case FDFMTEND:
+	case FDFLUSH:
+		return invalidate_drive (drive);
+	}
+	return -EINVAL;
+}
+
+
+/* Initialize the 'unit' variable for drive 'drive' */
+
+static void fd_probe( int drive )
+{
+	UD.connected = 0;
+	UDT  = NULL;
+
+	if (!fd_test_drive_present( drive ))
+		return;
+
+	UD.connected = 1;
+	UD.track     = 0;
+	switch( UserSteprate[drive] ) {
+	case 2:
+		UD.steprate = FDCSTEP_2;
+		break;
+	case 3:
+		UD.steprate = FDCSTEP_3;
+		break;
+	case 6:
+		UD.steprate = FDCSTEP_6;
+		break;
+	case 12:
+		UD.steprate = FDCSTEP_12;
+		break;
+	default: /* should be -1 for "not set by user" */
+		if (ATARIHW_PRESENT( FDCSPEED ) || is_medusa)
+			UD.steprate = FDCSTEP_3;
+		else
+			UD.steprate = FDCSTEP_6;
+		break;
+	}
+	MotorOn = 1;	/* from probe restore operation! */
+}
+
+
+/* This function tests the physical presence of a floppy drive (not
+ * whether a disk is inserted). This is done by issuing a restore
+ * command, waiting max. 2 seconds (that should be enough to move the
+ * head across the whole disk) and looking at the state of the "TR00"
+ * signal. This should now be raised if there is a drive connected
+ * (and there is no hardware failure :-) Otherwise, the drive is
+ * declared absent.
+ */
+
+static int fd_test_drive_present( int drive )
+{
+	unsigned long timeout;
+	unsigned char status;
+	int ok;
+	
+	if (drive > 1) return( 0 );
+	fd_select_drive( drive );
+
+	/* disable interrupt temporarily */
+	atari_turnoff_irq( IRQ_MFP_FDC );
+	FDC_WRITE (FDCREG_TRACK, 0xff00);
+	FDC_WRITE( FDCREG_CMD, FDCCMD_RESTORE | FDCCMDADD_H | FDCSTEP_6 );
+
+	for( ok = 0, timeout = jiffies + 2*HZ+HZ/2; jiffies < timeout; ) {
+		if (!(mfp.par_dt_reg & 0x20))
+			break;
+	}
+
+	status = FDC_READ( FDCREG_STATUS );
+	ok = (status & FDCSTAT_TR00) != 0;
+
+	/* force interrupt to abort restore operation (FDC would try
+	 * about 50 seconds!) */
+	FDC_WRITE( FDCREG_CMD, FDCCMD_FORCI );
+	udelay(500);
+	status = FDC_READ( FDCREG_STATUS );
+	udelay(20);
+
+	if (ok) {
+		/* dummy seek command to make WP bit accessible */
+		FDC_WRITE( FDCREG_DATA, 0 );
+		FDC_WRITE( FDCREG_CMD, FDCCMD_SEEK );
+		while( mfp.par_dt_reg & 0x20 )
+			;
+		status = FDC_READ( FDCREG_STATUS );
+	}
+
+	atari_turnon_irq( IRQ_MFP_FDC );
+	return( ok );
+}
+
+
+/* Look how many and which kind of drives are connected. If there are
+ * floppies, additionally start the disk-change and motor-off timers.
+ */
+
+static void config_types( void )
+{
+	int drive, cnt = 0;
+
+	/* for probing drives, set the FDC speed to 8 MHz */
+	if (ATARIHW_PRESENT(FDCSPEED))
+		dma_wd.fdc_speed = 0;
+
+	printk("Probing floppy drive(s):\n");
+	for( drive = 0; drive < FD_MAX_UNITS; drive++ ) {
+		fd_probe( drive );
+		if (UD.connected) {
+			printk("fd%d\n", drive);
+			++cnt;
+		}
+	}
+
+	if (FDC_READ( FDCREG_STATUS ) & FDCSTAT_BUSY) {
+		/* If FDC is still busy from probing, give it another FORCI
+		 * command to abort the operation. If this isn't done, the FDC
+		 * will interrupt later and its IRQ line stays low, because
+		 * the status register isn't read. And this will block any
+		 * interrupts on this IRQ line :-(
+		 */
+		FDC_WRITE( FDCREG_CMD, FDCCMD_FORCI );
+		udelay(500);
+		FDC_READ( FDCREG_STATUS );
+		udelay(20);
+	}
+	
+	if (cnt > 0) {
+		START_MOTOR_OFF_TIMER( FD_MOTOR_OFF_DELAY );
+		if (cnt == 1) fd_select_drive( 0 );
+		START_CHECK_CHANGE_TIMER( CHECK_CHANGE_DELAY );
+	}
+}
+
+/*
+ * floppy_open check for aliasing (/dev/fd0 can be the same as
+ * /dev/PS0 etc), and disallows simultaneous access to the same
+ * drive with different device numbers.
+ */
+
+static int floppy_open( struct inode *inode, struct file *filp )
+{
+  int drive, type;
+  int old_dev;
+
+  if (!filp)
+    {
+      DPRINT (("Weird, open called with filp=0\n"));
+      return -EIO;
+    }
+
+  drive = MINOR (inode->i_rdev) & 3;
+  type  = MINOR(inode->i_rdev) >> 2;
+  DPRINT(("fd_open: type=%d\n",type));
+  if (type > NUM_DISK_MINORS)
+	return -ENXIO;
+
+  old_dev = fd_device[drive];
+
+  if (fd_ref[drive])
+    if (old_dev != inode->i_rdev)
+      return -EBUSY;
+
+  if (fd_ref[drive] == -1 || (fd_ref[drive] && filp->f_flags & O_EXCL))
+    return -EBUSY;
+
+  if (filp->f_flags & O_EXCL)
+    fd_ref[drive] = -1;
+  else
+    fd_ref[drive]++;
+
+  fd_device[drive] = inode->i_rdev;
+
+  if (old_dev && old_dev != inode->i_rdev)
+    invalidate_buffers(old_dev);
+
+  /* Allow ioctls if we have write-permissions even if read-only open */
+  if (filp->f_mode & 2 || permission (inode, 2) == 0)
+    filp->f_mode |= IOCTL_MODE_BIT;
+  if (filp->f_mode & 2)
+    filp->f_mode |= OPEN_WRITE_BIT;
+
+  if (filp->f_flags & O_NDELAY)
+    return 0;
+
+  if (filp->f_mode & 3) {
+	  check_disk_change( inode->i_rdev );
+	  if (filp->f_mode & 2) {
+		  if (UD.wpstat) {
+			  floppy_release(inode, filp);
+			  return -EROFS;
+		  }
+	  }
+  }
+
+  return 0;
+}
+
+
+static void floppy_release( struct inode * inode, struct file * filp )
+{
+  int drive;
+
+  drive = inode->i_rdev & 3;
+
+  if (!filp || (filp->f_mode & (2 | OPEN_WRITE_BIT)))
+    /* if the file is mounted OR (writable now AND writable at open
+       time) Linus: Does this cover all cases? */
+    block_fsync (inode, filp);
+
+  if (fd_ref[drive] < 0)
+    fd_ref[drive] = 0;
+  else if (!fd_ref[drive]--)
+    {
+      printk("floppy_release with fd_ref == 0");
+      fd_ref[drive] = 0;
+    }
+}
+
+static struct file_operations floppy_fops = {
+	NULL,			/* lseek - default */
+	block_read,		/* read - general block-dev read */
+	block_write,		/* write - general block-dev write */
+	NULL,			/* readdir - bad */
+	NULL,			/* select */
+	fd_ioctl,		/* ioctl */
+	NULL,			/* mmap */
+	floppy_open,		/* open */
+	floppy_release, 	/* release */
+	block_fsync,		/* fsync */
+	NULL,			/* fasync */
+	check_floppy_change,	/* media_change */
+	floppy_revalidate,	/* revalidate */
+};
+
+int atari_floppy_init (void)
+{
+	int i;
+
+	if (register_blkdev(MAJOR_NR,"fd",&floppy_fops)) {
+		printk("Unable to get major %d for floppy\n",MAJOR_NR);
+		return -EBUSY;
+	}
+
+	if (UseTrackbuffer < 0)
+		/* not set by user -> use default: for now, we turn
+		   track buffering off for all Medusas, though it
+		   could be used with ones that have a counter
+		   card. But the test is too hard :-( */
+		UseTrackbuffer = !is_medusa;
+
+	/* initialize variables */
+	SelectedDrive = -1;
+	BufferDrive = -1;
+
+	/* initialize check_change timer */
+	timer_table[FLOPPY_TIMER].fn = check_change;
+	timer_active &= ~(1 << FLOPPY_TIMER);
+
+	DMABuffer = kmalloc(BUFFER_SIZE + 512, GFP_KERNEL | GFP_DMA);
+	if (!DMABuffer) {
+		printk("atari_floppy_init: cannot get dma buffer\n");
+		unregister_blkdev(MAJOR_NR, "fd");
+		return -ENOMEM;
+	}
+	TrackBuffer = DMABuffer + 512;
+	PhysDMABuffer = (unsigned long) VTOP(DMABuffer);
+	PhysTrackBuffer = (unsigned long) VTOP(TrackBuffer);
+	BufferDrive = BufferSide = BufferTrack = -1;
+
+	for (i = 0; i < FD_MAX_UNITS; i++) {
+		unit[i].track = -1;
+		unit[i].flags = 0;
+	}
+
+	for (i = 0; i < 256; i++)
+		if ((i >> 2) > 0 && (i >> 2) <= NUM_DISK_MINORS) {
+			int type = minor2disktype[(i >> 2) - 1].index;
+			floppy_sizes[i] = disk_type[type].blocks >> 1;
+		} else
+			floppy_sizes[i] = MAX_DISK_SIZE;
+
+	blk_size[MAJOR_NR] = floppy_sizes;
+	blksize_size[MAJOR_NR] = floppy_blocksizes;
+	blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
+
+	printk("Atari floppy driver: max. %cD, %strack buffering\n",
+	       DriveType == 0 ? 'D' : DriveType == 1 ? 'H' : 'E',
+	       UseTrackbuffer ? "" : "no ");
+	config_types();
+
+	return 0;
+}
+
+
+void atari_floppy_setup( char *str, int *ints )
+{
+	int i;
+	
+	if (ints[0] < 1) {
+		printk( "ataflop_setup: no arguments!\n" );
+		return;
+	}
+	else if (ints[0] > 2+FD_MAX_UNITS) {
+		printk( "ataflop_setup: too many arguments\n" );
+	}
+
+	if (ints[1] < 0 || ints[1] > 2)
+		printk( "ataflop_setup: bad drive type\n" );
+	else
+		DriveType = ints[1];
+
+	if (ints[0] >= 2)
+		UseTrackbuffer = (ints[2] > 0);
+
+	for( i = 3; i <= ints[0] && i-3 < FD_MAX_UNITS; ++i ) {
+		if (ints[i] != 2 && ints[i] != 3 && ints[i] != 6 && ints[i] != 12)
+			printk( "ataflop_setup: bad steprate\n" );
+		else
+			UserSteprate[i-3] = ints[i];
+	}
+}
+
+#ifdef MODULE
+int init_module (void)
+{
+	return atari_floppy_init ();
+}
+
+void cleanup_module (void)
+{
+	unregister_blkdev(MAJOR_NR, "fd");
+
+	blk_dev[MAJOR_NR].request_fn = 0;
+	timer_active &= ~(1 << FLOPPY_TIMER);
+	timer_table[FLOPPY_TIMER].fn = 0;
+	kfree (DMABuffer);
+}
+#endif
diff -u --recursive --new-file v1.3.93/linux/drivers/char/Config.in linux/drivers/char/Config.in
--- v1.3.93/linux/drivers/char/Config.in	Fri Apr 19 10:07:58 1996
+++ linux/drivers/char/Config.in	Mon Apr 22 07:14:01 1996
@@ -12,6 +12,7 @@
   tristate '  Stallion EasyIO or EC8/32 support' CONFIG_STALLION
   tristate '  Stallion EC8/64, ONboard, Brumby support' CONFIG_ISTALLION
 fi
+tristate 'SDL RISCom/8 card support' CONFIG_RISCOM8
 tristate 'Parallel printer support' CONFIG_PRINTER
 tristate 'Logitech busmouse support' CONFIG_BUSMOUSE
 tristate 'PS/2 mouse (aka "auxiliary device") support' CONFIG_PSMOUSE
diff -u --recursive --new-file v1.3.93/linux/drivers/char/Makefile linux/drivers/char/Makefile
--- v1.3.93/linux/drivers/char/Makefile	Fri Apr 19 10:07:58 1996
+++ linux/drivers/char/Makefile	Mon Apr 22 07:14:54 1996
@@ -60,6 +60,14 @@
   endif
 endif
 
+ifeq ($(CONFIG_RISCOM8),y)
+L_OBJS += riscom8.o
+else
+  ifeq ($(CONFIG_RISCOM8),m)
+  M_OBJS += riscom8.o
+  endif
+endif
+
 ifeq ($(CONFIG_ATIXL_BUSMOUSE),y)
 M = y
 L_OBJS += atixlmouse.o
diff -u --recursive --new-file v1.3.93/linux/drivers/char/amigamouse.c linux/drivers/char/amigamouse.c
--- v1.3.93/linux/drivers/char/amigamouse.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/char/amigamouse.c	Thu Apr 18 02:08:04 1996
@@ -0,0 +1,340 @@
+/*
+ * Amiga Mouse Driver for Linux 68k by Michael Rausch
+ * based upon:
+ *
+ * Logitech Bus Mouse Driver for Linux
+ * by James Banks
+ *
+ * Mods by Matthew Dillon
+ *   calls verify_area()
+ *   tracks better when X is busy or paging
+ *
+ * Heavily modified by David Giller
+ *   changed from queue- to counter- driven
+ *   hacked out a (probably incorrect) mouse_select
+ *
+ * Modified again by Nathan Laredo to interface with
+ *   0.96c-pl1 IRQ handling changes (13JUL92)
+ *   didn't bother touching select code.
+ *
+ * Modified the select() code blindly to conform to the VFS
+ *   requirements. 92.07.14 - Linus. Somebody should test it out.
+ *
+ * Modified by Johan Myreen to make room for other mice (9AUG92)
+ *   removed assignment chr_fops[10] = &mouse_fops; see mouse.c
+ *   renamed mouse_fops => bus_mouse_fops, made bus_mouse_fops public.
+ *   renamed this file mouse.c => busmouse.c
+ *
+ * Modfied for use in the 1.3 kernels by Jes Sorensen.
+ */
+
+#include <linux/module.h>
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/miscdevice.h>
+#include <linux/random.h>
+
+#include <asm/system.h>
+#include <asm/segment.h>
+#include <asm/irq.h>
+#include <asm/amigamouse.h>
+#include <asm/amigahw.h>
+#include <asm/amigaints.h>
+#include <asm/bootinfo.h>
+
+#define MSE_INT_ON()	mouseint_allowed = 1
+#define MSE_INT_OFF()	mouseint_allowed = 0
+
+
+static struct mouse_status mouse;
+
+static int mouseint_allowed;
+
+static void mouse_interrupt(int irq, struct pt_regs *fp, void *dummy)
+{
+	static int lastx=0, lasty=0;
+	int dx, dy;
+	int nx, ny;
+	unsigned char buttons;
+
+	unsigned short joy0dat, potgor;
+
+	if(!mouseint_allowed)
+		return;
+	MSE_INT_OFF();
+
+	/*
+	 *  This routine assumes, just like Kickstart, that the mouse
+	 *  has not moved more than 127 ticks since last VBL.
+	 */
+
+	joy0dat = custom.joy0dat;
+
+	nx = joy0dat & 0xff;
+	ny = joy0dat >> 8;
+
+	dx = nx - lastx;
+	if (dx < - 127)
+		dx = (256 + nx) - lastx;
+
+	if (dx > 127)
+		dx = (nx - 256) - lastx;
+
+	dy = ny - lasty;
+	if (dy < - 127)
+		dy = (256 + ny) - lasty;
+
+	if (dy > 127)
+		dy = (ny - 256) - lasty;
+
+	lastx = nx;
+	lasty = ny;
+
+#if 0
+	dx = -lastdx;
+	dx += (lastdx = joy0dat & 0xff);
+	if (dx < -127)
+	    dx = -255-dx;		/* underrun */
+	else
+	if (dx > 127)
+	    dx = 255-dx;		/* overflow */
+
+	dy = -lastdy;
+	dy += (lastdy = joy0dat >> 8);
+	if (dy < -127)
+	    dy = -255-dy;
+	else
+	if (dy > 127)
+	    dy = 255-dy;
+#endif
+
+
+	potgor = custom.potgor;
+	buttons = (ciaa.pra & 0x40 ? 4 : 0) |	/* left button; note that the bits are low-active, as are the expected results -> double negation */
+#if 1
+		  (potgor & 0x0100 ? 2 : 0) |	/* middle button; emulation goes here */
+#endif
+		  (potgor & 0x0400 ? 1 : 0);	/* right button */
+
+
+	if (dx != 0 || dy != 0 || buttons != mouse.buttons) {
+	  add_mouse_randomness((buttons << 16) + (dy << 8) + dx);
+	  mouse.buttons = buttons;
+	  mouse.dx += dx;
+	  mouse.dy -= dy;
+	  mouse.ready = 1;
+	  wake_up_interruptible(&mouse.wait);
+
+	  /*
+	   * keep dx/dy reasonable, but still able to track when X (or
+	   * whatever) must page or is busy (i.e. long waits between
+	   * reads)
+	   */
+	  if (mouse.dx < -2048)
+	      mouse.dx = -2048;
+	  else
+	  if (mouse.dx >  2048)
+	      mouse.dx =  2048;
+
+	  if (mouse.dy < -2048)
+	      mouse.dy = -2048;
+	  else
+	  if (mouse.dy >  2048)
+	      mouse.dy =  2048;
+
+	  if (mouse.fasyncptr)
+	      kill_fasync(mouse.fasyncptr, SIGIO);
+	}
+	MSE_INT_ON();
+}
+
+static int fasync_mouse(struct inode *inode, struct file *filp, int on)
+{
+	int retval;
+
+	retval = fasync_helper(inode, filp, on, &mouse.fasyncptr);
+	if (retval < 0)
+		return retval;
+	return 0;
+}
+
+/*
+ * close access to the mouse
+ */
+
+static void close_mouse(struct inode * inode, struct file * file)
+{
+	fasync_mouse(inode, file, 0);
+	if (--mouse.active)
+	  return;
+	MSE_INT_OFF();
+	MOD_DEC_USE_COUNT;
+}
+
+/*
+ * open access to the mouse, currently only one open is
+ * allowed.
+ */
+
+static int open_mouse(struct inode * inode, struct file * file)
+{
+  if (!mouse.present)
+    return -EINVAL;
+  if (mouse.active++)
+    return 0;
+  mouse.ready = 0;
+  mouse.dx = 0;
+  mouse.dy = 0;
+  mouse.buttons = 0x87;
+  mouse.active = 1;
+  MOD_INC_USE_COUNT;
+  MSE_INT_ON();
+  return 0;
+}
+
+/*
+ * writes are disallowed
+ */
+
+static int write_mouse(struct inode * inode, struct file * file, const char * buffer, int count)
+{
+	return -EINVAL;
+}
+
+/*
+ * read mouse data.  Currently never blocks.
+ */
+
+static int read_mouse(struct inode * inode, struct file * file, char * buffer, int count)
+{
+	int r;
+	int dx;
+	int dy;
+	unsigned char buttons; 
+
+	if (count < 3)
+		return -EINVAL;
+	if ((r = verify_area(VERIFY_WRITE, buffer, count)))
+		return r;
+	if (!mouse.ready)
+		return -EAGAIN;
+
+	/*
+	 * Obtain the current mouse parameters and limit as appropriate for
+	 * the return data format.  Interrupts are only disabled while 
+	 * obtaining the parameters, NOT during the puts_fs_byte() calls,
+	 * so paging in put_fs_byte() does not effect mouse tracking.
+	 */
+
+	MSE_INT_OFF();
+	dx = mouse.dx;
+	dy = mouse.dy;
+	if (dx < -127)
+	    dx = -127;
+	else
+	if (dx > 127)
+	    dx = 127;
+	if (dy < -127)
+	    dy = -127;
+	else
+	if (dy > 127)
+	    dy = 127;
+	buttons = mouse.buttons;
+	mouse.dx -= dx;
+	mouse.dy -= dy;
+	mouse.ready = 0;
+	MSE_INT_ON();
+
+	put_fs_byte(buttons | 0x80, buffer);
+	put_fs_byte((char)dx, buffer + 1);
+	put_fs_byte((char)dy, buffer + 2);
+	for (r = 3; r < count; r++)
+	    put_fs_byte(0x00, buffer + r);
+	return r;
+}
+
+/*
+ * select for mouse input
+ */
+
+static int mouse_select(struct inode *inode, struct file *file, int sel_type, select_table * wait)
+{
+	if (sel_type == SEL_IN) {
+	    	if (mouse.ready)
+			return 1;
+		select_wait(&mouse.wait, wait);
+    	}
+	return 0;
+}
+
+struct file_operations amiga_mouse_fops = {
+	NULL,		/* mouse_seek */
+	read_mouse,
+	write_mouse,
+	NULL, 		/* mouse_readdir */
+	mouse_select, 	/* mouse_select */
+	NULL, 		/* mouse_ioctl */
+	NULL,		/* mouse_mmap */
+	open_mouse,
+	close_mouse,
+	NULL,
+	fasync_mouse,
+};
+
+static struct miscdevice amiga_mouse = {
+	AMIGAMOUSE_MINOR, "amigamouse", &amiga_mouse_fops
+};
+
+int amiga_mouse_init(void)
+{
+	if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(AMI_MOUSE))
+		return -ENODEV;
+
+	custom.joytest = 0;	/* reset counters */
+
+	MSE_INT_OFF();
+
+	mouse.active = 0;
+	mouse.ready = 0;
+	mouse.buttons = 0x87;
+	mouse.dx = 0;
+	mouse.dy = 0;
+	mouse.wait = NULL;
+
+	/*
+	 *  use VBL to poll mouse deltas
+	 */
+
+	if(!add_isr(IRQ_AMIGA_VERTB, mouse_interrupt, 0, NULL, "Amiga mouse"))
+	{
+		mouse.present = 0;
+		printk(KERN_INFO "Installing Amiga mouse failed.\n");
+		return -EIO;
+	}
+
+	mouse.present = 1;
+
+	printk(KERN_INFO "Amiga mouse installed.\n");
+	misc_register(&amiga_mouse);
+	return 0;
+}
+
+#ifdef MODULE
+#include <asm/bootinfo.h>
+
+int init_module(void)
+{
+	return amiga_mouse_init();
+}
+
+void cleanup_module(void)
+{
+  remove_isr(IRQ_AMIGA_VERTB, mouse_interrupt);
+  misc_deregister(&amiga_mouse);
+}
+#endif
diff -u --recursive --new-file v1.3.93/linux/drivers/char/atarimouse.c linux/drivers/char/atarimouse.c
--- v1.3.93/linux/drivers/char/atarimouse.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/char/atarimouse.c	Thu Apr 18 02:08:04 1996
@@ -0,0 +1,213 @@
+/*
+ * Atari Mouse Driver for Linux
+ * by Robert de Vries (robert@and.nl) 19Jul93
+ *
+ * 16 Nov 1994 Andreas Schwab
+ * Compatibility with busmouse
+ * Support for three button mouse (shamelessly stolen from MiNT)
+ * third button wired to one of the joystick directions on joystick 1
+ *
+ * 1996/02/11 Andreas Schwab
+ * Module support
+ * Allow multiple open's
+ */
+
+#include <linux/module.h>
+
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/miscdevice.h>
+#include <linux/mm.h>
+#include <linux/random.h>
+
+#include <asm/atarikb.h>
+#include <asm/atari_mouse.h>
+#include <asm/segment.h>
+#include <asm/bootinfo.h>
+
+static struct mouse_status mouse;
+static int atari_mouse_x_threshold = 2, atari_mouse_y_threshold = 2;
+extern int atari_mouse_buttons;
+
+static void atari_mouse_interrupt(char *buf)
+{
+    int buttons;
+
+/*    ikbd_mouse_disable(); */
+
+    buttons = ((buf[0] & 1 ? 1 : 0)
+	       | (buf[0] & 2 ? 4 : 0)
+	       | (atari_mouse_buttons & 2));
+    atari_mouse_buttons = buttons;
+    add_mouse_randomness((buttons << 16) + (buf[2] << 8) + buf[1]);
+    mouse.buttons = ~buttons & 7;
+    mouse.dx += buf[1];
+    mouse.dy -= buf[2];
+    mouse.ready = 1;
+    wake_up_interruptible(&mouse.wait);
+    if (mouse.fasyncptr)
+	kill_fasync(mouse.fasyncptr, SIGIO);
+
+/*    ikbd_mouse_rel_pos(); */
+}
+
+static int fasync_mouse(struct inode *inode, struct file *filp, int on)
+{
+	int retval;
+
+	retval = fasync_helper(inode, filp, on, &mouse.fasyncptr);
+	if (retval < 0)
+		return retval;
+	return 0;
+}
+
+static void release_mouse(struct inode *inode, struct file *file)
+{
+    fasync_mouse(inode, file, 0);
+    if (--mouse.active)
+      return;
+    ikbd_mouse_disable();
+
+    atari_mouse_interrupt_hook = NULL;
+    MOD_DEC_USE_COUNT;
+}
+
+static int open_mouse(struct inode *inode, struct file *file)
+{
+    if (mouse.active++)
+	return 0;
+    mouse.ready = 0;
+    mouse.dx = mouse.dy = 0;
+    atari_mouse_buttons = 0;
+    ikbd_mouse_y0_top ();
+    ikbd_mouse_thresh (atari_mouse_x_threshold, atari_mouse_y_threshold);
+    ikbd_mouse_rel_pos();
+    MOD_INC_USE_COUNT;
+    atari_mouse_interrupt_hook = atari_mouse_interrupt;
+    return 0;
+}
+
+static int write_mouse(struct inode *inode, struct file *file, const char *buffer, int count)
+{
+    return -EINVAL;
+}
+
+static int read_mouse(struct inode *inode, struct file *file, char *buffer, int count)
+{
+    int dx, dy, buttons;
+    int r;
+
+    if (count < 3)
+	return -EINVAL;
+    if ((r = verify_area(VERIFY_WRITE, buffer, count)))
+	return r;
+    if (!mouse.ready)
+	return -EAGAIN;
+    /* ikbd_mouse_disable */
+    dx = mouse.dx;
+    dy = mouse.dy;
+    buttons = mouse.buttons;
+    if (dx > 127)
+      dx = 127;
+    else if (dx < -128)
+      dx = -128;
+    if (dy > 127)
+      dy = 127;
+    else if (dy < -128)
+      dy = -128;
+    mouse.dx -= dx;
+    mouse.dy -= dy;
+    if (mouse.dx == 0 && mouse.dy == 0)
+      mouse.ready = 0;
+    /* ikbd_mouse_rel_pos(); */
+    put_user(buttons | 0x80, buffer);
+    put_user((char) dx, buffer + 1);
+    put_user((char) dy, buffer + 2);
+    for (r = 3; r < count; r++)
+      put_user (0, buffer + r);
+    return r;
+}
+
+static int mouse_select(struct inode *inode, struct file *file, int sel_type, select_table *wait)
+{
+	if (sel_type == SEL_IN) {
+	    	if (mouse.ready)
+			return 1;
+		select_wait(&mouse.wait, wait);
+	}
+	return 0;
+}
+
+struct file_operations atari_mouse_fops = {
+    NULL,		/* mouse_seek */
+    read_mouse,
+    write_mouse,
+    NULL,		/* mouse_readdir */
+    mouse_select,
+    NULL,		/* mouse_ioctl */
+    NULL,		/* mouse_mmap */
+    open_mouse,
+    release_mouse,
+    NULL,
+    fasync_mouse,
+};
+
+static struct miscdevice atari_mouse = {
+    ATARIMOUSE_MINOR, "atarimouse", &atari_mouse_fops
+};
+
+int atari_mouse_init(void)
+{
+    mouse.active = 0;
+    mouse.ready = 0;
+    mouse.wait = NULL;
+
+    if (!MACH_IS_ATARI)
+	return -ENODEV;
+    printk(KERN_INFO "Atari mouse installed.\n");
+    misc_register(&atari_mouse);
+    return 0;
+}
+
+
+#define	MIN_THRESHOLD 1
+#define	MAX_THRESHOLD 20	/* more seems not reasonable... */
+
+void atari_mouse_setup( char *str, int *ints )
+{
+    if (ints[0] < 1) {
+	printk( "atari_mouse_setup: no arguments!\n" );
+	return;
+    }
+    else if (ints[0] > 2) {
+	printk( "atari_mouse_setup: too many arguments\n" );
+    }
+
+    if (ints[1] < MIN_THRESHOLD || ints[1] > MAX_THRESHOLD)
+	printk( "atari_mouse_setup: bad threshold value (ignored)\n" );
+    else {
+	atari_mouse_x_threshold = ints[1];
+	atari_mouse_y_threshold = ints[1];
+	if (ints[0] > 1) {
+	    if (ints[2] < MIN_THRESHOLD || ints[2] > MAX_THRESHOLD)
+		printk("atari_mouse_setup: bad threshold value (ignored)\n" );
+	    else
+		atari_mouse_y_threshold = ints[2];
+	}
+    }
+	
+}
+
+#ifdef MODULE
+#include <asm/bootinfo.h>
+
+int init_module(void)
+{
+	return atari_mouse_init();
+}
+
+void cleanup_module(void)
+{
+  misc_deregister(&atari_mouse);
+}
+#endif
diff -u --recursive --new-file v1.3.93/linux/drivers/char/fbmem.c linux/drivers/char/fbmem.c
--- v1.3.93/linux/drivers/char/fbmem.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/char/fbmem.c	Wed Mar 20 19:58:17 1996
@@ -0,0 +1,292 @@
+/*
+ *  linux/drivers/char/fbmem.c
+ *
+ *  Copyright (C) 1994 Martin Schaller
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file README.legal in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/malloc.h>
+#include <linux/mman.h>
+#include <linux/tty.h>
+
+#include <asm/segment.h>
+#include <asm/bootinfo.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+
+#include <linux/fb.h>
+
+#define FB_MAJOR	29
+
+#define FB_MODES_SHIFT    5	/* 32 modes per framebuffer */
+#define FB_NUM_MINORS 	256	/* 256 Minors		    */
+#define FB_MAX		(FB_NUM_MINORS / (1 << FB_MODES_SHIFT))
+
+#define GET_INODE(i) MKDEV(FB_MAJOR, (i) << FB_MODES_SHIFT)
+#define GET_FB_IDX(node) (MINOR(node) >> FB_MODES_SHIFT)
+#define GET_FB_VAR_IDX(node) (MINOR(node) & ((1 << FB_MODES_SHIFT)-1)) 
+
+struct fb_ops *registered_fb[FB_MAX];
+struct fb_var_screeninfo *registered_fb_var[FB_MAX];
+int registered_fb_var_num[FB_MAX];
+int fb_curr_open[FB_MAX];
+int fb_open_count[FB_MAX];
+
+static inline int PROC_CONSOLE(void)
+{
+	if (!current->tty)
+		return fg_console;
+
+	if (MINOR(current->tty->device) < 1)
+		return fg_console;
+
+	return MINOR(current->tty->device) - 1;
+}
+
+static int 
+fb_read(struct inode *inode, struct file *file, char *buf, int count)
+{
+	unsigned long p = file->f_pos;
+	struct fb_ops *fb = registered_fb[GET_FB_IDX(inode->i_rdev)];
+	struct fb_fix_screeninfo fix;
+	char *base_addr;
+	int copy_size;
+
+	if (! fb)
+		return -ENODEV;
+	if (count < 0)
+		return -EINVAL;
+
+	fb->fb_get_fix(&fix,PROC_CONSOLE());
+	base_addr=(char *) fix.smem_start;
+	copy_size=(count + p <= fix.smem_len ? count : fix.smem_len - p);
+	memcpy_tofs(buf, base_addr+p, copy_size);
+	file->f_pos += copy_size;
+	return copy_size;
+}
+
+static int 
+fb_write(struct inode *inode, struct file *file, const char *buf, int count)
+{
+	unsigned long p = file->f_pos;
+	struct fb_ops *fb = registered_fb[GET_FB_IDX(inode->i_rdev)];
+	struct fb_fix_screeninfo fix;
+	char *base_addr;
+	int copy_size;
+
+	if (! fb)
+		return -ENODEV;
+	if (count < 0)
+		return -EINVAL;
+	fb->fb_get_fix(&fix, PROC_CONSOLE());
+	base_addr=(char *) fix.smem_start;
+	copy_size=(count + p <= fix.smem_len ? count : fix.smem_len - p);
+	memcpy_fromfs(base_addr+p, buf, copy_size); 
+	file->f_pos += copy_size;
+	return copy_size;
+}
+
+
+static int 
+fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+	 unsigned long arg)
+{
+	struct fb_ops *fb = registered_fb[GET_FB_IDX(inode->i_rdev)];
+	struct fb_cmap cmap;
+	struct fb_var_screeninfo var;
+	struct fb_fix_screeninfo fix;
+
+	int i,fbidx,vidx;
+	
+	if (! fb)
+		return -ENODEV;
+	switch (cmd) {
+	case FBIOGET_VSCREENINFO:
+		i = verify_area(VERIFY_WRITE, (void *) arg, 
+				sizeof(struct fb_var_screeninfo));
+		if (i) return i;
+		fbidx=GET_FB_IDX(inode->i_rdev);
+		vidx=GET_FB_VAR_IDX(inode->i_rdev);
+		if (! vidx) /* ask device driver for current */
+			i=fb->fb_get_var(&var, PROC_CONSOLE());
+		else
+			var=registered_fb_var[fbidx][vidx-1];
+		memcpy_tofs((void *) arg, &var, sizeof(var));
+		return i;
+	case FBIOPUT_VSCREENINFO:
+		i = verify_area(VERIFY_WRITE, (void *) arg, 
+				sizeof(struct fb_var_screeninfo));
+		if (i) return i;
+		memcpy_fromfs(&var, (void *) arg, sizeof(var));
+		i=fb->fb_set_var(&var, PROC_CONSOLE());
+		memcpy_tofs((void *) arg, &var, sizeof(var));
+		fbidx=GET_FB_IDX(inode->i_rdev);
+		vidx=GET_FB_VAR_IDX(inode->i_rdev);
+		if (! i && vidx)
+			registered_fb_var[fbidx][vidx-1]=var;
+		return i;
+	case FBIOGET_FSCREENINFO:
+		i = verify_area(VERIFY_WRITE, (void *) arg, 
+				sizeof(struct fb_fix_screeninfo));
+		if (i)	return i;
+		i=fb->fb_get_fix(&fix, PROC_CONSOLE());
+		memcpy_tofs((void *) arg, &fix, sizeof(fix));
+		return i;
+	case FBIOPUTCMAP:
+		i = verify_area(VERIFY_READ, (void *) arg,
+				sizeof(struct fb_cmap));
+		if (i) return i;
+		memcpy_fromfs(&cmap, (void *) arg, sizeof(cmap));
+		i = verify_area(VERIFY_READ, (void *) cmap.red, 
+				cmap.len * sizeof(unsigned short));
+		if (i) return i;
+		i = verify_area(VERIFY_READ, (void *) cmap.green, 
+				cmap.len * sizeof(unsigned short));
+		if (i) return i;
+		i = verify_area(VERIFY_READ, (void *) cmap.blue, 
+				cmap.len * sizeof(unsigned short));
+		if (i) return i;
+		if (cmap.transp) {
+			i = verify_area(VERIFY_READ, (void *) cmap.transp, 
+					cmap.len * sizeof(unsigned short));
+			if (i) return i;
+		}
+		return (fb->fb_set_cmap(&cmap, 0, PROC_CONSOLE()));
+	case FBIOGETCMAP:
+		i = verify_area(VERIFY_READ, (void *) arg,
+				sizeof(struct fb_cmap));
+		if (i)	return i;
+		memcpy_fromfs(&cmap, (void *) arg, sizeof(cmap));
+		i = verify_area(VERIFY_WRITE, (void *) cmap.red, 
+				cmap.len * sizeof(unsigned short));
+		if (i) return i;
+		i = verify_area(VERIFY_WRITE, (void *) cmap.green, 
+				cmap.len * sizeof(unsigned short));
+		if (i) return i;
+		i = verify_area(VERIFY_WRITE, (void *) cmap.blue, 
+				cmap.len * sizeof(unsigned short));
+		if (i) return i;
+		if (cmap.transp) {
+			i = verify_area(VERIFY_WRITE, (void *) cmap.transp, 
+					cmap.len * sizeof(unsigned short));
+			if (i) return i;
+		}
+		return (fb->fb_get_cmap(&cmap, 0, PROC_CONSOLE()));
+	default:
+		return (fb->fb_ioctl(inode, file, cmd, arg, PROC_CONSOLE()));
+	}
+}
+
+static int 
+fb_mmap(struct inode *inode, struct file *file, struct vm_area_struct * vma)
+{
+	struct fb_ops *fb = registered_fb[GET_FB_IDX(inode->i_rdev)];
+	struct fb_fix_screeninfo fix;
+
+	if (! fb)
+		return -ENODEV;
+	fb->fb_get_fix(&fix, PROC_CONSOLE());
+	if ((vma->vm_end - vma->vm_start + vma->vm_offset) > fix.smem_len)
+		return -EINVAL;
+	vma->vm_offset += fix.smem_start;
+	if (vma->vm_offset & ~PAGE_MASK)
+		return -ENXIO;
+	if (boot_info.cputype & CPU_68040)
+		pgprot_val(vma->vm_page_prot) &= _CACHEMASK040;
+	if (remap_page_range(vma->vm_start, vma->vm_offset,
+			     vma->vm_end - vma->vm_start, vma->vm_page_prot))
+		return -EAGAIN;
+	vma->vm_inode = inode;
+	inode->i_count++;
+	return 0;
+}
+
+static int
+fb_open(struct inode *inode, struct file *file)
+{
+	int fbidx=GET_FB_IDX(inode->i_rdev);
+	int vidx=GET_FB_VAR_IDX(inode->i_rdev);
+	struct fb_ops *fb = registered_fb[fbidx];
+	int err;
+	
+	if (! vidx)		/* fb?current always succeeds */ 
+		return 0;
+	if (vidx > registered_fb_var_num[fbidx])
+		return -EINVAL;
+	if (fb_curr_open[fbidx] && fb_curr_open[fbidx] != vidx)
+		return -EBUSY;
+ 	if (file->f_mode & 2) /* only set parameters if opened writeable */
+		if ((err=fb->fb_set_var(registered_fb_var[fbidx] + vidx-1, PROC_CONSOLE())))
+			return err;
+	fb_curr_open[fbidx] = vidx;
+	fb_open_count[fbidx]++;
+	return 0;
+}
+
+static void 
+fb_release(struct inode *inode, struct file *file)
+{
+	int fbidx=GET_FB_IDX(inode->i_rdev);
+	int vidx=GET_FB_VAR_IDX(inode->i_rdev);
+	if (! vidx)
+		return;
+	if (! (--fb_open_count[fbidx]))
+		fb_curr_open[fbidx]=0;
+}
+
+static struct file_operations fb_fops = {
+	NULL,		/* lseek	*/
+	fb_read,	/* read		*/
+	fb_write,	/* write	*/
+	NULL,		/* readdir 	*/
+	NULL,		/* select 	*/
+	fb_ioctl,	/* ioctl 	*/
+	fb_mmap,	/* mmap		*/
+	fb_open,	/* open 	*/
+	fb_release,	/* release 	*/
+	NULL		/* fsync 	*/
+};
+
+int
+register_framebuffer(char *id, int *node, struct fb_ops *fbops, int fbvar_num, 
+		     struct fb_var_screeninfo *fbvar)
+{
+	int i;
+	for (i = 0 ; i < FB_MAX; i++)
+		if (! registered_fb[i])
+			break;
+	if (i == FB_MAX)
+		return -ENXIO;
+	registered_fb[i]=fbops;
+	registered_fb_var[i]=fbvar;
+	registered_fb_var_num[i]=fbvar_num;
+	*node=GET_INODE(i);
+	return 0;
+}
+
+int
+unregister_framebuffer(int node)
+{
+	int i=GET_FB_IDX(node);
+	if (! registered_fb[i])
+		return -EINVAL; 
+	registered_fb[i]=NULL;
+	registered_fb_var[i]=NULL;
+	return 0;
+}
+
+void
+fbmem_init(void)
+{
+	if (register_chrdev(FB_MAJOR,"fb",&fb_fops))
+		printk("unable to get major %d for fb devs\n", FB_MAJOR);
+}
+
diff -u --recursive --new-file v1.3.93/linux/drivers/char/ftape/Makefile linux/drivers/char/ftape/Makefile
--- v1.3.93/linux/drivers/char/ftape/Makefile	Fri Apr 12 15:51:52 1996
+++ linux/drivers/char/ftape/Makefile	Mon Apr 22 11:46:18 1996
@@ -30,7 +30,7 @@
 #	FDC_82078SL	- If you have a 82078SL, define this.
 
 FTAPE_OPT       = -DVERIFY_HEADERS -DNR_BUFFERS=3 -DCLK_48MHZ=1 \
-	-DNO_TRACE
+	-DNO_TRACE -DFDC_82078SL
 
 #  If you're using a non-standard floppy disk controller for the
 #  tape drive, enable one (only!) of the following lines and set
diff -u --recursive --new-file v1.3.93/linux/drivers/char/keyb_m68k.c linux/drivers/char/keyb_m68k.c
--- v1.3.93/linux/drivers/char/keyb_m68k.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/char/keyb_m68k.c	Fri Apr  5 17:16:48 1996
@@ -0,0 +1,867 @@
+/*
+ * linux/drivers/char/keyboard.c
+ *
+ * Keyboard driver for Linux v0.99 using Latin-1.
+ *
+ * Written for linux by Johan Myreen as a translation from
+ * the assembly version by Linus (with diacriticals added)
+ *
+ * Some additional features added by Christoph Niemann (ChN), March 1993
+ *
+ * Loadable keymaps by Risto Kankkunen, May 1993
+ *
+ * Diacriticals redone & other small changes, aeb@cwi.nl, June 1993
+ * Added decr/incr_console, dynamic keymaps, Unicode support,
+ * dynamic function/string keys, led setting,  Sept 1994
+ * `Sticky' modifier keys, 951006.
+ * 
+ */
+
+/*
+ * modified to provide 'generic' keyboard support by Hamish Macdonald
+ */
+
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/mm.h>
+#include <linux/random.h>
+
+#include <asm/bitops.h>
+#include <asm/machdep.h>
+
+#include "kbd_kern.h"
+#include "diacr.h"
+#include "vt_kern.h"
+
+#define SIZE(x) (sizeof(x)/sizeof((x)[0]))
+
+#define KBD_REPORT_ERR
+#define KBD_REPORT_UNKN
+/* #define KBD_IS_FOCUS_9000 */
+
+#ifndef KBD_DEFMODE
+#define KBD_DEFMODE ((1 << VC_REPEAT) | (1 << VC_META))
+#endif
+
+#ifndef KBD_DEFLEDS
+/*
+ * Some laptops take the 789uiojklm,. keys as number pad when NumLock
+ * is on. This seems a good reason to start with NumLock off.
+ */
+#define KBD_DEFLEDS 0
+#endif
+
+#ifndef KBD_DEFLOCK
+#define KBD_DEFLOCK 0
+#endif
+
+/*
+ * The default IO slowdown is doing 'inb()'s from 0x61, which should be
+ * safe. But as that is the keyboard controller chip address, we do our
+ * slowdowns here by doing short jumps: the keyboard controller should
+ * be able to keep up
+ */
+#define REALLY_SLOW_IO
+#define SLOW_IO_BY_JUMPING
+#include <asm/io.h>
+#include <asm/system.h>
+
+extern void poke_blanked_console(void);
+extern void ctrl_alt_del(void);
+extern void reset_vc(unsigned int new_console);
+extern void scrollback(int);
+extern void scrollfront(int);
+extern int vc_cons_allocated(unsigned int);
+
+unsigned char kbd_read_mask = 0x01;	/* modified by psaux.c */
+
+/*
+ * global state includes the following, and various static variables
+ * in this module: prev_scancode, shift_state, diacr, npadch, dead_key_next.
+ * (last_console is now a global variable)
+ */
+
+/* shift state counters.. */
+static unsigned char k_down[NR_SHIFT] = {0, };
+/* keyboard key bitmap */
+#define BITS_PER_LONG (8*sizeof(unsigned long))
+static unsigned long key_down[256/BITS_PER_LONG] = { 0, };
+
+static int dead_key_next = 0;
+/* 
+ * In order to retrieve the shift_state (for the mouse server), either
+ * the variable must be global, or a new procedure must be created to 
+ * return the value. I chose the former way.
+ */
+/*static*/ int shift_state = 0;
+static int npadch = -1;			/* -1 or number assembled on pad */
+static unsigned char diacr = 0;
+static char rep = 0;			/* flag telling character repeat */
+struct kbd_struct kbd_table[MAX_NR_CONSOLES];
+static struct tty_struct **ttytab;
+static struct kbd_struct *kbd = kbd_table;
+static struct tty_struct *tty = NULL;
+
+extern void compute_shiftstate(void);
+
+typedef void (*k_hand)(unsigned char value, char up_flag);
+typedef void (k_handfn)(unsigned char value, char up_flag);
+
+static k_handfn
+        do_self, do_fn, do_spec, do_pad, do_dead, do_cons, do_cur, do_shift,
+	do_meta, do_ascii, do_lock, do_lowercase, do_slock, do_ignore;
+
+static k_hand key_handler[16] = {
+	do_self, do_fn, do_spec, do_pad, do_dead, do_cons, do_cur, do_shift,
+	do_meta, do_ascii, do_lock, do_lowercase, do_slock,
+	do_ignore, do_ignore, do_ignore
+};
+
+typedef void (*void_fnp)(void);
+typedef void (void_fn)(void);
+
+static void_fn do_null, enter, show_ptregs, send_intr, lastcons, caps_toggle,
+	num, hold, scroll_forw, scroll_back, boot_it, caps_on, compose,
+	SAK, decr_console, incr_console, spawn_console, bare_num;
+
+static void_fnp spec_fn_table[] = {
+	do_null,	enter,		show_ptregs,	show_mem,
+	show_state,	send_intr,	lastcons,	caps_toggle,
+	num,		hold,		scroll_forw,	scroll_back,
+	boot_it,	caps_on,	compose,	SAK,
+	decr_console,	incr_console,	spawn_console,	bare_num
+};
+
+/* maximum values each key_handler can handle */
+const int max_vals[] = {
+	255, SIZE(func_table) - 1, SIZE(spec_fn_table) - 1, NR_PAD - 1,
+	NR_DEAD - 1, 255, 3, NR_SHIFT - 1,
+	255, NR_ASCII - 1, NR_LOCK - 1, 255,
+	NR_LOCK - 1
+};
+
+const int NR_TYPES = SIZE(max_vals);
+
+static void put_queue(int);
+static unsigned char handle_diacr(unsigned char);
+
+/*
+ * Many other routines do put_queue, but I think either
+ * they produce ASCII, or they produce some user-assigned
+ * string, and in both cases we might assume that it is
+ * in utf-8 already.
+ */
+void to_utf8(ushort c) {
+    if (c < 0x80)
+	put_queue(c);			/*  0*******  */
+    else if (c < 0x800) {
+	put_queue(0xc0 | (c >> 6)); 	/*  110***** 10******  */
+	put_queue(0x80 | (c & 0x3f));
+    } else {
+	put_queue(0xe0 | (c >> 12)); 	/*  1110**** 10****** 10******  */
+	put_queue(0x80 | ((c >> 6) & 0x3f));
+	put_queue(0x80 | (c & 0x3f));
+    }
+    /* UTF-8 is defined for words of up to 31 bits,
+       but we need only 16 bits here */
+}
+
+void process_keycode (int keycode)
+{
+	char up_flag;		                 /* 0 or 0200 */
+	char raw_mode;
+
+	do_poke_blanked_console = 1;
+	mark_bh(KEYBOARD_BH);
+	add_keyboard_randomness(keycode);
+
+	tty = ttytab[fg_console];
+ 	kbd = kbd_table + fg_console;
+	if ((raw_mode = (kbd->kbdmode == VC_RAW))) {
+ 		put_queue(keycode);
+		/* we do not return yet, because we want to maintain
+		   the key_down array, so that we have the correct
+		   values when finishing RAW mode or when changing VT's */
+ 	}
+
+	/*
+	 * At this point the variable `keycode' contains the keycode.
+	 * Note: the keycode must not be 0.
+	 * We keep track of the up/down status of the key, and
+	 * return the keycode if in MEDIUMRAW mode.
+	 */
+
+	up_flag = (keycode & 0200);
+        keycode &= 0x7f;
+	if (up_flag) {
+		rep = 0;
+ 		if(!clear_bit(keycode, key_down)) {
+		    /* unexpected, but this can happen:
+		       maybe this was a key release for a FOCUS 9000
+		       PF key; if we want to see it, we have to clear
+		       up_flag */
+#ifndef __mc68000__
+		    if (keycode >= SC_LIM || keycode == 85)
+		      up_flag = 0;
+#endif
+		}
+	} else
+ 		rep = set_bit(keycode, key_down);
+
+	if (raw_mode)
+	        return;
+
+	if (kbd->kbdmode == VC_MEDIUMRAW) {
+		/* soon keycodes will require more than one byte */
+ 		put_queue(keycode + up_flag);
+		return;
+	}
+
+ 	/*
+	 * Small change in philosophy: earlier we defined repetition by
+	 *	 rep = keycode == prev_keycode;
+	 *	 prev_keycode = keycode;
+	 * but now by the fact that the depressed key was down already.
+	 * Does this ever make a difference? Yes.
+	 */
+
+	/*
+ 	 *  Repeat a key only if the input buffers are empty or the
+ 	 *  characters get echoed locally. This makes key repeat usable
+ 	 *  with slow applications and under heavy loads.
+	 */
+	if (!rep ||
+	    (vc_kbd_mode(kbd,VC_REPEAT) && tty &&
+	     (L_ECHO(tty) || (tty->driver.chars_in_buffer(tty) == 0)))) {
+		u_short keysym;
+		u_char type;
+
+		/* the XOR below used to be an OR */
+		int shift_final = shift_state ^ kbd->lockstate ^ kbd->slockstate;
+		ushort *key_map = key_maps[shift_final];
+
+		if (key_map != NULL) {
+			keysym = key_map[keycode];
+			type = KTYP(keysym);
+
+			if (type >= 0xf0) {
+			    type -= 0xf0;
+			    if (type == KT_LETTER) {
+				type = KT_LATIN;
+				if (vc_kbd_led(kbd, VC_CAPSLOCK)) {
+				    key_map = key_maps[shift_final ^ (1<<KG_SHIFT)];
+				    if (key_map)
+				      keysym = key_map[keycode];
+				}
+			    }
+			    (*key_handler[type])(keysym & 0xff, up_flag);
+			    if (type != KT_SLOCK)
+			      kbd->slockstate = 0;
+			} else {
+			    /* maybe only if (kbd->kbdmode == VC_UNICODE) ? */
+			    if (!up_flag)
+			      to_utf8(keysym);
+			}
+		} else {
+			/* maybe beep? */
+			/* we have at least to update shift_state */
+#if 1			/* how? two almost equivalent choices follow */
+			compute_shiftstate();
+#else
+			keysym = U(plain_map[keycode]);
+			type = KTYP(keysym);
+			if (type == KT_SHIFT)
+			  (*key_handler[type])(keysym & 0xff, up_flag);
+#endif
+		}
+        }
+}
+
+static void put_queue(int ch)
+{
+	wake_up(&keypress_wait);
+	if (tty) {
+		tty_insert_flip_char(tty, ch, 0);
+		tty_schedule_flip(tty);
+	}
+}
+
+static void puts_queue(char *cp)
+{
+	wake_up(&keypress_wait);
+	if (!tty)
+		return;
+
+	while (*cp) {
+		tty_insert_flip_char(tty, *cp, 0);
+		cp++;
+	}
+	tty_schedule_flip(tty);
+}
+
+static void applkey(int key, char mode)
+{
+	static char buf[] = { 0x1b, 'O', 0x00, 0x00 };
+
+	buf[1] = (mode ? 'O' : '[');
+	buf[2] = key;
+	puts_queue(buf);
+}
+
+static void enter(void)
+{
+	put_queue(13);
+	if (vc_kbd_mode(kbd,VC_CRLF))
+		put_queue(10);
+}
+
+static void caps_toggle(void)
+{
+	if (rep)
+		return;
+	chg_vc_kbd_led(kbd, VC_CAPSLOCK);
+}
+
+static void caps_on(void)
+{
+	if (rep)
+		return;
+	set_vc_kbd_led(kbd, VC_CAPSLOCK);
+}
+
+struct pt_regs *pt_regs;
+
+static void show_ptregs(void)
+{
+	if (pt_regs)
+		show_regs(pt_regs);
+	return;
+}
+
+static void hold(void)
+{
+	if (rep || !tty)
+		return;
+
+	/*
+	 * Note: SCROLLOCK will be set (cleared) by stop_tty (start_tty);
+	 * these routines are also activated by ^S/^Q.
+	 * (And SCROLLOCK can also be set by the ioctl KDSKBLED.)
+	 */
+	if (tty->stopped)
+		start_tty(tty);
+	else
+		stop_tty(tty);
+}
+
+static void num(void)
+{
+	if (vc_kbd_mode(kbd,VC_APPLIC))
+		applkey('P', 1);
+	else
+		bare_num();
+}
+
+/*
+ * Bind this to Shift-NumLock if you work in application keypad mode
+ * but want to be able to change the NumLock flag.
+ * Bind this to NumLock if you prefer that the NumLock key always
+ * changes the NumLock flag.
+ */
+static void bare_num(void)
+{
+	if (!rep)
+		chg_vc_kbd_led(kbd,VC_NUMLOCK);
+}
+
+static void lastcons(void)
+{
+	/* switch to the last used console, ChN */
+	set_console(last_console);
+}
+
+static void decr_console(void)
+{
+	int i;
+ 
+	for (i = fg_console-1; i != fg_console; i--) {
+		if (i == -1)
+			i = MAX_NR_CONSOLES-1;
+		if (vc_cons_allocated(i))
+			break;
+	}
+	set_console(i);
+}
+
+static void incr_console(void)
+{
+	int i;
+
+	for (i = fg_console+1; i != fg_console; i++) {
+		if (i == MAX_NR_CONSOLES)
+			i = 0;
+		if (vc_cons_allocated(i))
+			break;
+	}
+	set_console(i);
+}
+
+static void send_intr(void)
+{
+	if (!tty)
+		return;
+	tty_insert_flip_char(tty, 0, TTY_BREAK);
+	tty_schedule_flip(tty);
+}
+
+static void scroll_forw(void)
+{
+	scrollfront(0);
+}
+
+static void scroll_back(void)
+{
+	scrollback(0);
+}
+
+static void boot_it(void)
+{
+	ctrl_alt_del();
+}
+
+static void compose(void)
+{
+	dead_key_next = 1;
+}
+
+int spawnpid, spawnsig;
+
+static void spawn_console(void)
+{
+        if (spawnpid)
+	   if(kill_proc(spawnpid, spawnsig, 1))
+	     spawnpid = 0;
+}
+
+static void SAK(void)
+{
+	do_SAK(tty);
+#if 0
+	/*
+	 * Need to fix SAK handling to fix up RAW/MEDIUM_RAW and
+	 * vt_cons modes before we can enable RAW/MEDIUM_RAW SAK
+	 * handling.
+	 * 
+	 * We should do this some day --- the whole point of a secure
+	 * attention key is that it should be guaranteed to always
+	 * work.
+	 */
+	reset_vc(fg_console);
+	do_unblank_screen();	/* not in interrupt routine? */
+#endif
+}
+
+static void do_ignore(unsigned char value, char up_flag)
+{
+}
+
+static void do_null()
+{
+	compute_shiftstate();
+}
+
+static void do_spec(unsigned char value, char up_flag)
+{
+	if (up_flag)
+		return;
+	if (value >= SIZE(spec_fn_table))
+		return;
+	spec_fn_table[value]();
+}
+
+static void do_lowercase(unsigned char value, char up_flag)
+{
+	printk("keyboard.c: do_lowercase was called - impossible\n");
+}
+
+static void do_self(unsigned char value, char up_flag)
+{
+	if (up_flag)
+		return; 	/* no action, if this is a key release */
+
+	if (diacr)
+		value = handle_diacr(value);
+
+        if (dead_key_next) {
+                dead_key_next = 0;
+                diacr = value;
+                return;
+        }
+
+	put_queue(value);
+}
+
+#define A_GRAVE  '`'
+#define A_ACUTE  '\''
+#define A_CFLEX  '^'
+#define A_TILDE  '~'
+#define A_DIAER  '"'
+static unsigned char ret_diacr[] =
+        {A_GRAVE, A_ACUTE, A_CFLEX, A_TILDE, A_DIAER };
+
+/* If a dead key pressed twice, output a character corresponding to it, */
+/* otherwise just remember the dead key.				*/
+
+static void do_dead(unsigned char value, char up_flag)
+{
+	if (up_flag)
+		return;
+
+        value = ret_diacr[value];
+        if (diacr == value) {   /* pressed twice */
+                diacr = 0;
+                put_queue(value);
+                return;
+        }
+	diacr = value;
+}
+
+
+/* If space is pressed, return the character corresponding the pending	*/
+/* dead key, otherwise try to combine the two.				*/
+
+unsigned char handle_diacr(unsigned char ch)
+{
+        int d = diacr;
+        int i;
+
+        diacr = 0;
+        if (ch == ' ')
+                return d;
+
+	for (i = 0; i < accent_table_size; i++) {
+		if (accent_table[i].diacr == d && accent_table[i].base == ch)
+			return accent_table[i].result;
+	}
+
+        put_queue(d);
+        return ch;
+}
+
+static void do_cons(unsigned char value, char up_flag)
+{
+	if (up_flag)
+		return;
+	set_console(value);
+}
+
+static void do_fn(unsigned char value, char up_flag)
+{
+	if (up_flag)
+		return;
+	if (value < SIZE(func_table)) {
+		if (func_table[value])
+			puts_queue(func_table[value]);
+	} else
+	        printk("do_fn called with value=%d\n", value);
+}
+
+static void do_pad(unsigned char value, char up_flag)
+{
+	static const char *pad_chars = "0123456789+-*/\015,.?";
+	static const char *app_map = "pqrstuvwxylSRQMnn?";
+
+	if (up_flag)
+		return;		/* no action, if this is a key release */
+
+	/* kludge... shift forces cursor/number keys */
+	if (vc_kbd_mode(kbd,VC_APPLIC) && !k_down[KG_SHIFT]) {
+		applkey(app_map[value], 1);
+		return;
+	}
+
+	if (!vc_kbd_led(kbd,VC_NUMLOCK))
+		switch (value) {
+			case KVAL(K_PCOMMA):
+			case KVAL(K_PDOT):
+				do_fn(KVAL(K_REMOVE), 0);
+				return;
+			case KVAL(K_P0):
+				do_fn(KVAL(K_INSERT), 0);
+				return;
+			case KVAL(K_P1):
+				do_fn(KVAL(K_SELECT), 0);
+				return;
+			case KVAL(K_P2):
+				do_cur(KVAL(K_DOWN), 0);
+				return;
+			case KVAL(K_P3):
+				do_fn(KVAL(K_PGDN), 0);
+				return;
+			case KVAL(K_P4):
+				do_cur(KVAL(K_LEFT), 0);
+				return;
+			case KVAL(K_P6):
+				do_cur(KVAL(K_RIGHT), 0);
+				return;
+			case KVAL(K_P7):
+				do_fn(KVAL(K_FIND), 0);
+				return;
+			case KVAL(K_P8):
+				do_cur(KVAL(K_UP), 0);
+				return;
+			case KVAL(K_P9):
+				do_fn(KVAL(K_PGUP), 0);
+				return;
+			case KVAL(K_P5):
+				applkey('G', vc_kbd_mode(kbd, VC_APPLIC));
+				return;
+		}
+
+	put_queue(pad_chars[value]);
+	if (value == KVAL(K_PENTER) && vc_kbd_mode(kbd, VC_CRLF))
+		put_queue(10);
+}
+
+static void do_cur(unsigned char value, char up_flag)
+{
+	static const char *cur_chars = "BDCA";
+	if (up_flag)
+		return;
+
+	applkey(cur_chars[value], vc_kbd_mode(kbd,VC_CKMODE));
+}
+
+static void do_shift(unsigned char value, char up_flag)
+{
+	int old_state = shift_state;
+
+	if (rep)
+		return;
+
+	/* Mimic typewriter:
+	   a CapsShift key acts like Shift but undoes CapsLock */
+	if (value == KVAL(K_CAPSSHIFT)) {
+		value = KVAL(K_SHIFT);
+		if (!up_flag)
+			clr_vc_kbd_led(kbd, VC_CAPSLOCK);
+	}
+
+	if (up_flag) {
+	        /* handle the case that two shift or control
+		   keys are depressed simultaneously */
+		if (k_down[value])
+			k_down[value]--;
+	} else
+		k_down[value]++;
+
+	if (k_down[value])
+		shift_state |= (1 << value);
+	else
+		shift_state &= ~ (1 << value);
+
+	/* kludge */
+	if (up_flag && shift_state != old_state && npadch != -1) {
+		if (kbd->kbdmode == VC_UNICODE)
+		  to_utf8(npadch & 0xffff);
+		else
+		  put_queue(npadch & 0xff);
+		npadch = -1;
+	}
+}
+
+/* called after returning from RAW mode or when changing consoles -
+   recompute k_down[] and shift_state from key_down[] */
+/* maybe called when keymap is undefined, so that shiftkey release is seen */
+void compute_shiftstate(void)
+{
+	int i, j, k, sym, val;
+
+	shift_state = 0;
+	for(i=0; i < SIZE(k_down); i++)
+	  k_down[i] = 0;
+
+	for(i=0; i < SIZE(key_down); i++)
+	  if(key_down[i]) {	/* skip this word if not a single bit on */
+	    k = i*BITS_PER_LONG;
+	    for(j=0; j<BITS_PER_LONG; j++,k++)
+	      if(test_bit(k, key_down)) {
+		sym = U(plain_map[k]);
+		if(KTYP(sym) == KT_SHIFT) {
+		  val = KVAL(sym);
+		  if (val == KVAL(K_CAPSSHIFT))
+		    val = KVAL(K_SHIFT);
+		  k_down[val]++;
+		  shift_state |= (1<<val);
+	        }
+	      }
+	  }
+}
+
+static void do_meta(unsigned char value, char up_flag)
+{
+	if (up_flag)
+		return;
+
+	if (vc_kbd_mode(kbd, VC_META)) {
+		put_queue('\033');
+		put_queue(value);
+	} else
+		put_queue(value | 0x80);
+}
+
+static void do_ascii(unsigned char value, char up_flag)
+{
+	int base;
+
+	if (up_flag)
+		return;
+
+	if (value < 10)    /* decimal input of code, while Alt depressed */
+	    base = 10;
+	else {       /* hexadecimal input of code, while AltGr depressed */
+	    value -= 10;
+	    base = 16;
+	}
+
+	if (npadch == -1)
+	        npadch = value;
+	else
+		npadch = npadch * base + value;
+}
+
+static void do_lock(unsigned char value, char up_flag)
+{
+	if (up_flag || rep)
+		return;
+	chg_vc_kbd_lock(kbd, value);
+}
+
+static void do_slock(unsigned char value, char up_flag)
+{
+	if (up_flag || rep)
+		return;
+	chg_vc_kbd_slock(kbd, value);
+}
+
+/*
+ * The leds display either (i) the status of NumLock, CapsLock, ScrollLock,
+ * or (ii) whatever pattern of lights people want to show using KDSETLED,
+ * or (iii) specified bits of specified words in kernel memory.
+ */
+
+static unsigned char ledstate = 0xff; /* undefined */
+static unsigned char ledioctl;
+
+unsigned char getledstate(void) {
+    return ledstate;
+}
+
+void setledstate(struct kbd_struct *kbd, unsigned int led) {
+    if (!(led & ~7)) {
+	ledioctl = led;
+	kbd->ledmode = LED_SHOW_IOCTL;
+    } else
+	kbd->ledmode = LED_SHOW_FLAGS;
+    set_leds();
+}
+
+static struct ledptr {
+    unsigned int *addr;
+    unsigned int mask;
+    unsigned char valid:1;
+} ledptrs[3];
+
+void register_leds(int console, unsigned int led,
+		   unsigned int *addr, unsigned int mask) {
+    struct kbd_struct *kbd = kbd_table + console;
+    if (led < 3) {
+	ledptrs[led].addr = addr;
+	ledptrs[led].mask = mask;
+	ledptrs[led].valid = 1;
+	kbd->ledmode = LED_SHOW_MEM;
+    } else
+	kbd->ledmode = LED_SHOW_FLAGS;
+}
+
+static inline unsigned char getleds(void){
+    struct kbd_struct *kbd = kbd_table + fg_console;
+    unsigned char leds;
+
+    if (kbd->ledmode == LED_SHOW_IOCTL)
+      return ledioctl;
+    leds = kbd->ledflagstate;
+    if (kbd->ledmode == LED_SHOW_MEM) {
+	if (ledptrs[0].valid) {
+	    if (*ledptrs[0].addr & ledptrs[0].mask)
+	      leds |= 1;
+	    else
+	      leds &= ~1;
+	}
+	if (ledptrs[1].valid) {
+	    if (*ledptrs[1].addr & ledptrs[1].mask)
+	      leds |= 2;
+	    else
+	      leds &= ~2;
+	}
+	if (ledptrs[2].valid) {
+	    if (*ledptrs[2].addr & ledptrs[2].mask)
+	      leds |= 4;
+	    else
+	      leds &= ~4;
+	}
+    }
+    return leds;
+}
+
+/*
+ * This routine is the bottom half of the keyboard interrupt
+ * routine, and runs with all interrupts enabled. It does
+ * console changing, led setting and copy_to_cooked, which can
+ * take a reasonably long time.
+ *
+ * Aside from timing (which isn't really that important for
+ * keyboard interrupts as they happen often), using the software
+ * interrupt routines for this thing allows us to easily mask
+ * this when we don't want any of the above to happen. Not yet
+ * used, but this allows for easy and efficient race-condition
+ * prevention later on.
+ */
+static void kbd_bh(void)
+{
+	unsigned char leds = getleds();
+
+	if (leds != ledstate) {
+		ledstate = leds;
+		if (mach_kbd_leds)
+			mach_kbd_leds(leds);
+	}
+}
+
+int kbd_init(void)
+{
+	int i;
+	struct kbd_struct kbd0;
+	extern struct tty_driver console_driver;
+
+	kbd0.ledflagstate = kbd0.default_ledflagstate = KBD_DEFLEDS;
+	kbd0.ledmode = LED_SHOW_FLAGS;
+	kbd0.lockstate = KBD_DEFLOCK;
+	kbd0.slockstate = 0;
+	kbd0.modeflags = KBD_DEFMODE;
+	kbd0.kbdmode = VC_XLATE;
+ 
+	for (i = 0 ; i < MAX_NR_CONSOLES ; i++)
+		kbd_table[i] = kbd0;
+
+	ttytab = console_driver.table;
+
+	init_bh(KEYBOARD_BH, kbd_bh);
+	mark_bh(KEYBOARD_BH);
+
+	mach_keyb_init ();
+
+	return 0;
+}
diff -u --recursive --new-file v1.3.93/linux/drivers/char/lp_intern.c linux/drivers/char/lp_intern.c
--- v1.3.93/linux/drivers/char/lp_intern.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/char/lp_intern.c	Wed Mar 20 19:53:12 1996
@@ -0,0 +1,169 @@
+
+/*
+ * split into mid and low-level for better support of diffent hardware
+ * by Joerg Dorchain (dorchain@mpi-sb.mpg.de)
+ *
+ * Amiga printer device by Michael Rausch (linux@uni-koblenz.de);
+ * Atari support added by Andreas Schwab (schwab@ls5.informatik.uni-dortmund.de);
+ * based upon work from
+ *
+ * Copyright (C) 1992 by Jim Weigand and Linus Torvalds
+ * Copyright (C) 1992,1993 by Michael K. Johnson
+ * - Thanks much to Gunter Windau for pointing out to me where the error
+ *   checking ought to be.
+ * Copyright (C) 1993 by Nigel Gamble (added interrupt code)
+ */
+
+#include <linux/config.h>
+#include <linux/lp_intern.h>
+#include <linux/kernel.h>
+#ifdef CONFIG_AMIGA
+#include <asm/amigahw.h>
+#endif
+#ifdef CONFIG_ATARI
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <asm/atarihw.h>
+#endif
+
+
+static void lp_int_out(int, int);
+static int lp_int_busy(int);
+static int lp_int_pout(int);
+static int lp_int_online(int);
+static int lp_int_interrupt(int);
+
+int lp_internal_init(struct lp_struct *, int, int, int);
+
+
+static void
+lp_int_out (int c, int dev)
+{
+  switch (boot_info.machtype)
+    {
+#ifdef CONFIG_AMIGA
+    case MACH_AMIGA:
+       {
+	int wait = 0;
+	while (wait != lp_table[dev].wait) wait++;
+	ciaa.prb = c;
+       }
+      break;
+#endif
+#ifdef CONFIG_ATARI
+    case MACH_ATARI:
+       {
+	 int wait = 0;
+	 sound_ym.rd_data_reg_sel = 15;
+	 sound_ym.wd_data = c;
+	 sound_ym.rd_data_reg_sel = 14;
+	 while (wait != lp_table[dev].wait) wait++;
+	 sound_ym.wd_data = sound_ym.rd_data_reg_sel & ~(1 << 5);
+	 while (wait) wait--;
+	 sound_ym.wd_data = sound_ym.rd_data_reg_sel | (1 << 5);
+	 break;
+       }
+#endif
+    }
+}
+
+static int
+lp_int_busy (int dev)
+{
+  switch (boot_info.machtype)
+    {
+#ifdef CONFIG_AMIGA
+    case MACH_AMIGA:
+      return ciab.pra & 1;
+#endif
+#ifdef CONFIG_ATARI
+    case MACH_ATARI:
+      return mfp.par_dt_reg & 1;
+#endif
+    default:
+      return 0;
+    }
+}
+
+static int
+lp_int_pout (int dev)
+{
+  switch (boot_info.machtype)
+    {
+#ifdef CONFIG_AMIGA
+    case MACH_AMIGA:
+      return ciab.pra & 2;
+#endif
+#ifdef CONFIG_ATARI
+    case MACH_ATARI:
+#endif
+    default:
+      return 0;
+    }
+}
+
+static int
+lp_int_online (int dev)
+{
+  switch (boot_info.machtype)
+    {
+#ifdef CONFIG_AMIGA
+    case MACH_AMIGA:
+      return ciab.pra & 4;
+#endif
+#ifdef CONFIG_ATARI
+    case MACH_ATARI:
+      return !(mfp.par_dt_reg & 1);
+#endif
+    default:
+      return 0;
+    }
+}
+
+static int lp_int_interrupt(int dev)
+{
+  return 1;
+}
+
+int lp_internal_init(struct lp_struct *lp_table, int entry,
+		     int max_lp, int irq)
+{
+  if (max_lp-entry < 1)
+    return 0;
+#ifdef CONFIG_AMIGA
+  if (MACH_IS_AMIGA)
+    {
+      ciaa.ddrb = 0xff;
+      ciab.ddra &= 0xf8;
+    }
+#endif
+#ifdef CONFIG_ATARI
+  if (MACH_IS_ATARI)
+    {
+      unsigned long flags;
+
+      save_flags(flags);
+      cli();
+      sound_ym.rd_data_reg_sel = 7;
+      sound_ym.wd_data = (sound_ym.rd_data_reg_sel & 0x3f) | 0xc0;
+      restore_flags(flags);
+    }
+#endif
+  lp_table[entry].name = "Builtin LP";
+  lp_table[entry].lp_out = lp_int_out;
+  lp_table[entry].lp_is_busy = lp_int_busy;
+  lp_table[entry].lp_has_pout = lp_int_pout;
+  lp_table[entry].lp_is_online = lp_int_online;
+  lp_table[entry].lp_my_interrupt = lp_int_interrupt;
+  lp_table[entry].flags = LP_EXIST;
+  lp_table[entry].chars = LP_INIT_CHAR;
+  lp_table[entry].time = LP_INIT_TIME;
+  lp_table[entry].wait = LP_INIT_WAIT;
+  lp_table[entry].lp_wait_q = NULL;
+
+  printk("lp%d: internal port\n", entry);
+
+  return 1;
+}
+
diff -u --recursive --new-file v1.3.93/linux/drivers/char/lp_m68k.c linux/drivers/char/lp_m68k.c
--- v1.3.93/linux/drivers/char/lp_m68k.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/char/lp_m68k.c	Fri Apr 19 02:41:15 1996
@@ -0,0 +1,492 @@
+/*
+ * split in two parts for better support of different hardware
+ * by Joerg Dorchain (dorchain@mpi-sb.mpg.de)
+ *
+ * Amiga printer device by Michael Rausch (linux@uni-koblenz.de);
+ * Atari support added by Andreas Schwab (schwab@ls5.informatik.uni-dortmund.de);
+ * based upon work from
+ *
+ * Copyright (C) 1992 by Jim Weigand and Linus Torvalds
+ * Copyright (C) 1992,1993 by Michael K. Johnson
+ * - Thanks much to Gunter Windau for pointing out to me where the error
+ *   checking ought to be.
+ * Copyright (C) 1993 by Nigel Gamble (added interrupt code)
+ */
+
+/* 01/17/95: Matthias Welwarsky (dg8y@rs11.hrz.th-darmstadt.de)
+ * lp_write(): rewritten from scratch
+ * lp_interrupt(): fixed cli()/sti()-bug
+ * 
+ * 95/05/28: Andreas Schwab (schwab@issan.informatik.uni-dortmund.de)
+ * lp_write() fixed to make it work again.
+ * 95/08/18: Andreas Schwab
+ * lp_write_interrupt: fix race condition
+ *
+ *  * CAUTION, please do check! *    
+ * 
+ *  on 68000-based machines sti() must NEVER appear in interrupt driven
+ *  code. The 68k-CPU has a priority-based interrupt scheme. while an interrupt
+ *  with a certain priority is executed, all requests with lower or same
+ *  priority get locked out. executing the sti()-macro allows ANY interrupt
+ *  to be served. this really causes BIG trouble!
+ *  to protect an interrupt driven routine against beeing interrupted 
+ *  (if absolutely needed!) one should use save_flags();cli()/restore_flags()!
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/sched.h>
+#include <asm/irq.h>
+
+#ifdef CONFIG_AMIGA
+#include <asm/amigaints.h>
+#ifdef CONFIG_MULTIFACE_III_LP
+#include <linux/lp_mfc.h>
+#endif
+#endif
+#ifdef CONFIG_ATARI
+#include <asm/atarihw.h>
+#include <asm/atariints.h>
+#endif
+
+#include <linux/lp_m68k.h>
+#include <linux/lp_intern.h>
+#include <linux/malloc.h>
+#include <linux/interrupt.h>
+
+#include <asm/segment.h>
+#include <asm/system.h>
+
+
+/*
+ *  why bother around with the pio driver when the interrupt works;
+ *  so, for "security" reasons only, it's configurable here.
+ *  saves some bytes, at least ...
+ */
+#define FORCE_POLLING	 0
+#define FORCE_INTERRUPT	 1
+#define PREFER_INTERRUPT 2
+
+#define WHICH_DRIVER	FORCE_INTERRUPT
+
+#define MAX_LP 3 /* the maximum number of devices */
+
+struct lp_struct lp_table[MAX_LP] = {{0,},};
+
+static int max_lp; /* the real number of devices */
+
+/* 
+ * All my debugging code assumes that you debug with only one printer at
+ * a time. RWWH
+ */
+
+#define LP_DEBUG 
+#undef LP_DEBUG 
+
+
+#if WHICH_DRIVER != FORCE_INTERRUPT
+#ifdef LP_DEBUG
+static int lp_max_count = 1;
+#endif
+
+static int lp_char_polled(char lpchar, int dev)
+{
+	unsigned long count  = 0; 
+
+	do {
+		count ++;
+		if(need_resched)
+			schedule();
+	} while (lp_table[dev].lp_is_busy(dev) && count < lp_table[dev].chars);
+
+	if (count == lp_table[dev].chars) {
+		return 0;
+		/* we timed out, and the character was /not/ printed */
+	}
+#ifdef LP_DEBUG
+	if (count > lp_max_count) {
+		printk("lp success after %d counts.\n",count);
+		lp_max_count = count;
+	}
+#endif
+	lp_table[dev].lp_out(lpchar, dev);
+	return 1;
+}
+#endif
+
+
+#ifdef LP_DEBUG
+unsigned int lp_total_chars = 0;
+unsigned int lp_last_call = 0;
+#endif
+
+
+#if WHICH_DRIVER != FORCE_POLLING
+static __inline__ int lp_char_interrupt(char lpchar, int dev)
+{
+	if (!lp_table[dev].lp_is_busy(dev)) {
+		lp_table[dev].lp_out(lpchar,dev);
+		return 1;
+	}
+	return 0;
+}
+
+static int lp_error;
+
+static void lp_interrupt(int irq, struct pt_regs *fp, void *dummy)
+{
+    unsigned long flags;
+    int dev;
+
+    for (dev = 0; dev < max_lp; dev++) {
+	if (lp_table[dev].lp_my_interrupt(dev) != 0)
+	  if (lp_table[dev].do_print)
+	  {
+		  if (lp_table[dev].copy_size)
+		  {
+			  save_flags(flags);
+			  cli();
+			  if (lp_char_interrupt(lp_table[dev].lp_buffer[lp_table[dev].bytes_written], dev)) {
+				  --lp_table[dev].copy_size;
+				  ++lp_table[dev].bytes_written;
+				  restore_flags(flags);
+			  }
+			  else
+			  {
+				  lp_table[dev].do_print = 0;
+				  restore_flags(flags);
+				  lp_error = 1;
+				  wake_up_interruptible(&lp_table[dev].lp_wait_q);
+			  }
+		  }
+		  else
+		  {
+			  lp_table[dev].do_print = 0;
+			  lp_error = 0;
+			  wake_up_interruptible(&lp_table[dev].lp_wait_q);
+		  }
+
+	  }
+    }
+}
+
+#if WHICH_DRIVER == FORCE_INTERRUPT
+static int lp_write(struct inode *inode, struct file *file,
+		    const char *buf, int count)
+#else
+static int lp_write_interrupt(struct inode *inode, struct file *file,
+			      const char *buf, int count)
+#endif
+{
+  unsigned long total_bytes_written = 0;
+  unsigned int flags;
+  int rc;
+  int dev = MINOR(inode->i_rdev);
+
+  do {
+    lp_table[dev].do_print = 0;		/* disable lp_interrupt()   */
+    lp_table[dev].bytes_written = 0;	/* init buffer read-pointer */
+    lp_error = 0;
+    lp_table[dev].copy_size = (count <= LP_BUFFER_SIZE ? count : LP_BUFFER_SIZE);
+    memcpy_fromfs(lp_table[dev].lp_buffer, buf, lp_table[dev].copy_size);
+    while (lp_table[dev].copy_size) {
+      save_flags(flags);
+      cli();				/* no interrupts now */
+      lp_table[dev].do_print = 1;	/* enable lp_interrupt() */
+      if (lp_char_interrupt(lp_table[dev].lp_buffer[lp_table[dev].bytes_written], dev)) {
+	++lp_table[dev].bytes_written;
+	--lp_table[dev].copy_size;
+	lp_error = 0;
+      } else {				/* something went wrong   */
+	lp_table[dev].do_print = 0;	/* disable lp_interrupt() */
+	lp_error = 1;			/* printer caused error   */
+      }
+      if (lp_error) {
+
+	  /* something blocked printing, so we don't want to sleep too long,
+	     in case we have to rekick the interrupt */
+
+	  current->timeout = jiffies + LP_TIMEOUT_POLLED;
+      } else {
+	  current->timeout = jiffies + LP_TIMEOUT_INTERRUPT;
+      }
+  
+      interruptible_sleep_on(&lp_table[dev].lp_wait_q);
+      restore_flags(flags);
+  
+      /* we're up again and running. we first disable lp_interrupt(), then
+	 check what happened meanwhile */
+
+      lp_table[dev].do_print = 0;
+      rc = total_bytes_written + lp_table[dev].bytes_written;
+
+      if (current->signal & ~current->blocked) {
+	if (rc)
+	  return rc;
+	else
+	  return -EINTR;
+      }
+      if (lp_error) {
+
+	/* an error has occured, maybe in lp_interrupt().
+	   figure out the type of error, exit on request or if nothing has 
+	   been printed at all. */
+	
+	if (lp_table[dev].lp_has_pout(dev)) {
+	  printk("lp%d: paper-out\n",dev);
+	  if (!rc) rc = -ENOSPC;
+	} else if (!lp_table[dev].lp_is_online(dev)) {
+	  printk("lp%d: off-line\n",dev);
+	  if (!rc) rc = -EIO;
+	} else if (lp_table[dev].lp_is_busy(dev)) {
+	  printk("lp%d: on fire\n",dev);
+	  if (!rc) rc = -EIO;
+	}
+	if (lp_table[dev].flags & LP_ABORT)
+	  return rc;
+      }
+      /* check if our buffer was completely printed, if not, most likely
+	 an unsolved error blocks the printer. As we can`t do anything
+	 against, we start all over again. Else we set the read-pointer
+	 of the buffer and count the printed characters */
+      
+      if (!lp_table[dev].copy_size) {
+	total_bytes_written += lp_table[dev].bytes_written;
+	buf += lp_table[dev].bytes_written;
+	count -= lp_table[dev].bytes_written;
+      }
+    }
+  } while (count > 0);
+  return total_bytes_written;
+}
+#endif
+
+#if WHICH_DRIVER != FORCE_INTERRUPT
+#if WHICH_DRIVER == FORCE_POLLING
+static int lp_write(struct inode *inode, struct file *file,
+		    const char *buf, int count)
+#else
+static int lp_write_polled(struct inode *inode, struct file *file,
+			   const char *buf, int count)
+#endif
+{
+	char *temp = buf;
+	int dev = MINOR(inode->i_rdev);
+
+#ifdef LP_DEBUG
+	if (jiffies-lp_last_call > lp_table[dev].time) {
+		lp_total_chars = 0;
+		lp_max_count = 1;
+	}
+	lp_last_call = jiffies;
+#endif
+
+	temp = buf;
+	while (count > 0) {
+		if (lp_char_polled(get_user(temp), dev)) {
+			/* only update counting vars if character was printed */
+			count--; temp++;
+#ifdef LP_DEBUG
+			lp_total_chars++;
+#endif
+		} else { /* if printer timed out */
+			if (lp_table[dev].lp_has_pout(dev)) {
+				printk("lp%d: out of paper\n",dev);
+				if (lp_table[dev].flags & LP_ABORT)
+					return temp - buf ? temp-buf : -ENOSPC;
+				current->state = TASK_INTERRUPTIBLE;
+				current->timeout = jiffies + LP_TIMEOUT_POLLED;
+				schedule();
+			} else if (!lp_table[dev].lp_is_online(dev)) {
+				printk("lp%d: off-line\n",dev);
+				if (lp_table[dev].flags & LP_ABORT)
+					return temp - buf ? temp-buf : -EIO;
+				current->state = TASK_INTERRUPTIBLE;
+				current->timeout = jiffies + LP_TIMEOUT_POLLED;
+				schedule();
+			} else
+	                /* not offline or out of paper. on fire? */
+			if (lp_table[dev].lp_is_busy(dev)) {
+				printk("lp%d: on fire\n",dev);
+				if (lp_table[dev].flags & LP_ABORT)
+					return temp - buf ? temp-buf : -EFAULT;
+				current->state = TASK_INTERRUPTIBLE;
+				current->timeout = jiffies + LP_TIMEOUT_POLLED;
+				schedule();
+			}
+
+			/* check for signals before going to sleep */
+			if (current->signal & ~current->blocked) {
+				if (temp != buf)
+					return temp-buf;
+				else
+					return -EINTR;
+			}
+#ifdef LP_DEBUG
+			printk("lp sleeping at %d characters for %d jiffies\n",
+				lp_total_chars, lp_table[dev].time);
+			lp_total_chars = 0;
+#endif
+			current->state = TASK_INTERRUPTIBLE;
+			current->timeout = jiffies + lp_table[dev].time;
+			schedule();
+		}
+	}
+	return temp - buf;
+}
+#endif
+
+static unsigned int lp_irq = 0;
+
+#if WHICH_DRIVER == PREFER_INTERRUPT
+static int lp_write(struct inode *inode, struct file *file,
+		    const char *buf, int count)
+{
+	if (lp_irq)
+		return lp_write_interrupt(inode, file, buf, count);
+	else
+		return lp_write_polled(inode, file, buf, count);
+}
+#endif
+
+static int lp_lseek(struct inode *inode, struct file *file,
+		    off_t offset, int origin)
+{
+	return -ESPIPE;
+}
+
+static int lp_open(struct inode *inode, struct file *file)
+{
+	int dev = MINOR(inode->i_rdev);
+
+	if (dev >= max_lp)
+		return -ENODEV;
+	if (!(lp_table[dev].flags & LP_EXIST))
+		return -ENODEV;
+	if (lp_table[dev].flags & LP_BUSY)
+		return -EBUSY;
+
+	lp_table[dev].flags |= LP_BUSY;
+
+	return 0;
+}
+
+static void lp_release(struct inode *inode, struct file *file)
+{
+	lp_table[MINOR(inode->i_rdev)].flags &= ~LP_BUSY;
+}
+
+
+static int lp_ioctl(struct inode *inode, struct file *file,
+		    unsigned int cmd, unsigned long arg)
+{
+	unsigned int minor = MINOR(inode->i_rdev);
+	int retval = 0;
+
+#ifdef LP_DEBUG
+	printk("lp%d ioctl, cmd: 0x%x, arg: 0x%x\n", minor, cmd, arg);
+#endif
+	if (minor >= max_lp)
+		return -ENODEV;
+	if (!(lp_table[minor].flags & LP_EXIST))
+		return -ENODEV;
+	switch (cmd) {
+	case LPTIME:
+		lp_table[minor].time = arg;
+		break;
+	case LPCHAR:
+		lp_table[minor].chars = arg;
+		break;
+	case LPABORT:
+		if (arg)
+			lp_table[minor].flags |= LP_ABORT;
+		else
+			lp_table[minor].flags &= ~LP_ABORT;
+		break;
+	case LPWAIT:
+		lp_table[minor].wait = arg;
+		break;
+	case LPSETIRQ:
+	case LPGETIRQ:
+	        retval = lp_irq;
+		break;
+	default:
+		retval = -EINVAL;
+	}
+	return retval;
+}
+
+
+static struct file_operations lp_fops = {
+	lp_lseek,
+	NULL,		/* lp_read */
+	lp_write,
+	NULL,		/* lp_readdir */
+	NULL,		/* lp_select */
+	lp_ioctl,
+	NULL,		/* lp_mmap */
+	lp_open,
+	lp_release
+};
+
+
+int lp_init(void)
+{
+	extern char m68k_debug_device[];
+
+	if (!strcmp( m68k_debug_device, "par" ))
+		return -EBUSY;
+
+	if (register_chrdev(LP_MAJOR,"lp", &lp_fops)) {
+		printk("unable to get major %d for line printer\n", LP_MAJOR);
+		return -EBUSY;
+	}
+
+#if WHICH_DRIVER == FORCE_POLLING
+	lp_irq = 0;
+	printk("lp_init: lp using polling driver\n");
+#else
+
+#ifdef CONFIG_AMIGA
+	if (MACH_IS_AMIGA && AMIGAHW_PRESENT(AMI_PARALLEL))
+		lp_irq = add_isr(IRQ_AMIGA_CIAA_FLG, lp_interrupt, 0,
+				 NULL, "printer");
+#endif
+#ifdef CONFIG_ATARI
+	if (MACH_IS_ATARI)
+		lp_irq = add_isr(IRQ_MFP_BUSY, lp_interrupt, IRQ_TYPE_SLOW,
+				 NULL, "printer");
+#endif
+
+	if (lp_irq)
+		printk("lp_init: lp using interrupt\n");
+	else
+
+#if WHICH_DRIVER == PREFER_INTERRUPT
+		printk("lp_init: lp using polling driver\n");
+#else
+		printk("lp_init: cant get interrupt, and polling driver not configured\n");
+#endif
+#endif
+
+	max_lp = 0;
+	max_lp += lp_internal_init(lp_table, max_lp, MAX_LP, WHICH_DRIVER);
+#ifdef CONFIG_MULTIFACE_III_LP
+	max_lp += lp_mfc_init(lp_table, max_lp, MAX_LP, WHICH_DRIVER);
+#if WHICH_DRIVER != FORCE_POLLING
+	add_isr(IRQ_AMIGA_PORTS, lp_interrupt, 0, NULL,
+		"Multiface III printer");
+#endif
+#endif
+	return 0;
+}
+
+/*
+ * Currently we do not accept any lp-parameters, but that may change.
+ */
+void	lp_setup(char *str, int *ints)
+{	
+}
diff -u --recursive --new-file v1.3.93/linux/drivers/char/riscom8.c linux/drivers/char/riscom8.c
--- v1.3.93/linux/drivers/char/riscom8.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/char/riscom8.c	Mon Apr 22 07:14:01 1996
@@ -0,0 +1,1899 @@
+/*
+ *      linux/drivers/char/riscom.c  -- RISCom/8 multiport serial driver.
+ *
+ *      Copyright (C) 1994-1996  Dmitry Gorodchanin (begemot@bgm.rosprint.net)
+ *
+ *      This code is loosely based on the Linux serial driver, written by
+ *      Linus Torvalds, Theodore T'so and others. The RISCom/8 card 
+ *      programming info was obtained from various drivers for other OSes 
+ *	(FreeBSD, ISC, etc), but no source code from those drivers were 
+ *	directly included in this drvier.
+ *
+ *
+ *      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.
+ *
+ *	Revision 1.0 
+ */
+
+#include <linux/module.h>
+
+#include <asm/io.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/errno.h>
+#include <linux/tty.h>
+#include <linux/mm.h>
+#include <linux/serial.h>
+#include <linux/fcntl.h>
+#include <linux/major.h>
+
+#include "riscom8.h"
+#include "riscom8_reg.h"
+
+/* Am I paranoid or not ? ;-) */
+#define RISCOM_PARANOIA_CHECK
+
+/* 
+ * Crazy InteliCom/8 boards sometimes has swapped CTS & DSR signals.
+ * You can slightly speed up things by #undefing the following option,
+ * if you are REALLY sure that your board is correct one. 
+ */
+
+#define RISCOM_BRAIN_DAMAGED_CTS
+
+/* 
+ * The following defines are mostly for testing purposes. But if you need
+ * some nice reporting in your syslog, you can define them also.
+ */
+#undef RC_REPORT_FIFO
+#undef RC_REPORT_OVERRUN
+
+
+#define RISCOM_LEGAL_FLAGS \
+	(ASYNC_HUP_NOTIFY   | ASYNC_SAK          | ASYNC_SPLIT_TERMIOS   | \
+	 ASYNC_SPD_HI       | ASYNC_SPEED_VHI    | ASYNC_SESSION_LOCKOUT | \
+	 ASYNC_PGRP_LOCKOUT | ASYNC_CALLOUT_NOHUP)
+
+#ifndef MIN
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+#endif
+
+DECLARE_TASK_QUEUE(tq_riscom);
+
+#define RISCOM_TYPE_NORMAL	1
+#define RISCOM_TYPE_CALLOUT	2
+
+static struct riscom_board * IRQ_to_board[16] = { NULL, } ;
+static struct tty_driver riscom_driver, riscom_callout_driver;
+static int    riscom_refcount = 0;
+static struct tty_struct * riscom_table[RC_NBOARD * RC_NPORT] = { NULL, };
+static struct termios * riscom_termios[RC_NBOARD * RC_NPORT] = { NULL, };
+static struct termios * riscom_termios_locked[RC_NBOARD * RC_NPORT] = { NULL, };
+static unsigned char * tmp_buf = NULL;
+static struct semaphore tmp_buf_sem = MUTEX;
+
+static unsigned long baud_table[] =  {
+	0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
+	9600, 19200, 38400, 57600, 76800, 0, 
+};
+
+static struct riscom_board rc_board[RC_NBOARD] =  {
+	{ 0, RC_IOBASE1, 0, },
+	{ 0, RC_IOBASE2, 0, },
+	{ 0, RC_IOBASE3, 0, },
+	{ 0, RC_IOBASE4, 0, },
+};
+
+static struct riscom_port rc_port[RC_NBOARD * RC_NPORT] =  {
+	{ 0, },
+};
+		
+/* RISCom/8 I/O ports addresses (without address translation) */
+static unsigned short rc_ioport[] =  {
+#if 1	
+	0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x09, 0x0a, 0x0b, 0x0c,
+#else	
+	0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x09, 0x0a, 0x0b, 0x0c, 0x10,
+	0x11, 0x12, 0x18, 0x28, 0x31, 0x32, 0x39, 0x3a, 0x40, 0x41, 0x61, 0x62,
+	0x63, 0x64, 0x6b, 0x70, 0x71, 0x78, 0x7a, 0x7b, 0x7f, 0x100, 0x101
+#endif	
+};
+#define RC_NIOPORT	(sizeof(rc_ioport) / sizeof(rc_ioport[0]))
+
+
+static inline int rc_paranoia_check(struct riscom_port const * port,
+				    kdev_t device, const char *routine)
+{
+#ifdef RISCOM_PARANOIA_CHECK
+	static const char *badmagic =
+		"rc: Warning: bad riscom port magic number for device %s in %s\n";
+	static const char *badinfo =
+		"rc: Warning: null riscom port for device %s in %s\n";
+
+	if (!port) {
+		printk(badinfo, kdevname(device), routine);
+		return 1;
+	}
+	if (port->magic != RISCOM8_MAGIC) {
+		printk(badmagic, kdevname(device), routine);
+		return 1;
+	}
+#endif
+	return 0;
+}
+
+/*
+ * 
+ *  Service functions for RISCom/8 driver.
+ * 
+ */
+
+/* Get board number from pointer */
+extern inline int board_No (struct riscom_board const * bp)
+{
+	return bp - rc_board;
+}
+
+/* Get port number from pointer */
+extern inline int port_No (struct riscom_port const * port)
+{
+	return RC_PORT(port - rc_port); 
+}
+
+/* Get pointer to board from pointer to port */
+extern inline struct riscom_board * port_Board(struct riscom_port const * port)
+{
+	return &rc_board[RC_BOARD(port - rc_port)];
+}
+
+/* Input Byte from CL CD180 register */
+extern inline unsigned char rc_in(struct riscom_board const * bp, unsigned short reg)
+{
+	return inb(bp->base + RC_TO_ISA(reg));
+}
+
+/* Output Byte to CL CD180 register */
+extern inline void rc_out(struct riscom_board const * bp, unsigned short reg,
+			  unsigned char val)
+{
+	outb(val, bp->base + RC_TO_ISA(reg));
+}
+
+/* Wait for Chanel Command Register ready */
+extern inline void rc_wait_CCR(struct riscom_board const * bp)
+{
+	unsigned long delay;
+
+	/* FIXME: need something more descriptive then 100000 :) */
+	for (delay = 100000; delay; delay--) 
+		if (!rc_in(bp, CD180_CCR))
+			return;
+	
+	printk("rc%d: Timeout waiting for CCR.\n", board_No(bp));
+}
+
+/*
+ *  RISCom/8 probe functions.
+ */
+
+extern inline int rc_check_io_range(struct riscom_board * const bp)
+{
+	int i;
+	
+	for (i = 0; i < RC_NIOPORT; i++)  
+		if (check_region(RC_TO_ISA(rc_ioport[i]) + bp->base, 1))  {
+			printk("rc%d: Skipping probe at 0x%03x. I/O adress in use.\n",
+			       board_No(bp), bp->base);
+			return 1;
+		}
+	return 0;
+}
+
+extern inline void rc_request_io_range(struct riscom_board * const bp)
+{
+	int i;
+	
+	for (i = 0; i < RC_NIOPORT; i++) 
+		request_region(RC_TO_ISA(rc_ioport[i]) + bp->base, 1, "RISCom/8" );
+}
+
+extern inline void rc_release_io_range(struct riscom_board * const bp)
+{
+	int i;
+	
+	for (i = 0; i < RC_NIOPORT; i++)  
+		release_region(RC_TO_ISA(rc_ioport[i]) + bp->base, 1);
+}
+
+	
+/* Must be called with enabled interrupts */
+extern inline void rc_long_delay(unsigned long delay)
+{
+	unsigned long i;
+	
+	for (i = jiffies + delay; i > jiffies; ) ;
+}
+
+/* Reset and setup CD180 chip */
+static void rc_init_CD180(struct riscom_board const * bp)
+{
+	unsigned long flags;
+	
+	save_flags(flags); cli();
+	rc_out(bp, RC_CTOUT, 0);     	           /* Clear timeout             */
+	rc_wait_CCR(bp);			   /* Wait for CCR ready        */
+	rc_out(bp, CD180_CCR, CCR_HARDRESET);      /* Reset CD180 chip          */
+	sti();
+	rc_long_delay(HZ/20);                      /* Delay 0.05 sec            */
+	cli();
+	rc_out(bp, CD180_GIVR, RC_ID);             /* Set ID for this chip      */
+	rc_out(bp, CD180_GICR, 0);                 /* Clear all bits            */
+	rc_out(bp, CD180_PILR1, RC_ACK_MINT);      /* Prio for modem intr       */
+	rc_out(bp, CD180_PILR2, RC_ACK_TINT);      /* Prio for transmitter intr */
+	rc_out(bp, CD180_PILR3, RC_ACK_RINT);      /* Prio for receiver intr    */
+	
+	/* Setting up prescaler. We need 4 ticks per 1 ms */
+	rc_out(bp, CD180_PPRH, (RC_OSCFREQ/(1000000/RISCOM_TPS)) >> 8);
+	rc_out(bp, CD180_PPRL, (RC_OSCFREQ/(1000000/RISCOM_TPS)) & 0xff);
+	
+	restore_flags(flags);
+}
+
+/* Main probing routine, also sets irq. */
+static int rc_probe(struct riscom_board *bp)
+{
+	unsigned char val1, val2;
+	int irqs = 0;
+	int retries;
+	
+	bp->irq = 0;
+
+	if (rc_check_io_range(bp)) 
+		return 1;
+	
+	/* Are the I/O ports here ? */
+	rc_out(bp, CD180_PPRL, 0x5a);
+	outb(0xff, 0x80);
+	val1 = rc_in(bp, CD180_PPRL);
+	rc_out(bp, CD180_PPRL, 0xa5);
+	outb(0x00, 0x80);
+	val2 = rc_in(bp, CD180_PPRL);
+	
+	if ((val1 != 0x5a) || (val2 != 0xa5))  {
+		printk("rc%d: RISCom/8 Board at 0x%03x not found.\n",
+		       board_No(bp), bp->base);
+		return 1;
+	}
+	
+	/* It's time to find IRQ for this board */
+	for (retries = 0; retries < 5 && irqs <= 0; retries++)  {
+		irqs = probe_irq_on();
+		rc_init_CD180(bp);	       		/* Reset CD180 chip       */
+		rc_out(bp, CD180_CAR, 2);               /* Select port 2          */
+		rc_wait_CCR(bp);
+		rc_out(bp, CD180_CCR, CCR_TXEN);        /* Enable transmitter     */
+		rc_out(bp, CD180_IER, IER_TXRDY);       /* Enable tx empty intr   */
+		rc_long_delay(HZ/20);	       		
+		irqs = probe_irq_off(irqs);
+		val1 = rc_in(bp, RC_BSR);		/* Get Board Status reg   */
+		val2 = rc_in(bp, RC_ACK_TINT);          /* ACK interrupt          */
+		rc_init_CD180(bp);	       		/* Reset CD180 again      */
+	
+		if ((val1 & RC_BSR_TINT) || (val2 != (RC_ID | GIVR_IT_TX)))  {
+			printk("rc%d: RISCom/8 Board at 0x%03x not found.\n",
+			       board_No(bp), bp->base);
+			return 1;
+		}
+	}
+	
+	if (irqs <= 0)  {
+		printk("rc%d: Can't find IRQ for RISCom/8 board at 0x%03x.\n",
+		       board_No(bp), bp->base);
+		return 1;
+	}
+	rc_request_io_range(bp);
+	bp->irq = irqs;
+	bp->flags |= RC_BOARD_PRESENT;
+	
+	printk("rc%d: RISCom/8 Rev. %c board detected at 0x%03x, IRQ %d.\n",
+	       board_No(bp),
+	       (rc_in(bp, CD180_GFRCR) & 0x0f) + 'A',   /* Board revision */
+	       bp->base, bp->irq);
+	
+	return 0;
+}
+
+/* 
+ * 
+ *  Inerrupt processing routines.
+ * 
+ */
+
+extern inline void rc_mark_event(struct riscom_port * port, int event)
+{
+	/* 
+         * I'm not quite happy with current scheme all serial
+	 * drivers use their own BH routine.
+         * It seem's this easily can be done with one BH routine
+	 * serving for all serial drivers.
+	 * For now I must introduce another one - RISCOM8_BH.
+	 * Still hope this will be changed in near future.
+         */
+	set_bit(event, &port->event);
+	queue_task_irq_off(&port->tqueue, &tq_riscom);
+	mark_bh(RISCOM8_BH);
+}
+
+extern inline struct riscom_port * rc_get_port(struct riscom_board const * bp,
+					       unsigned char const * what)
+{
+	unsigned char channel;
+	struct riscom_port * port;
+	
+	channel = rc_in(bp, CD180_GICR) >> GICR_CHAN_OFF;
+	if (channel < CD180_NCH)  {
+		port = &rc_port[board_No(bp) * RC_NPORT + channel];
+		if (port->flags & ASYNC_INITIALIZED)  {
+			return port;
+		}
+	}
+	printk("rc%d: %s interrupt from invalid port %d\n", 
+	       board_No(bp), what, channel);
+	return NULL;
+}
+
+extern inline void rc_receive_exc(struct riscom_board const * bp)
+{
+	struct riscom_port *port;
+	struct tty_struct *tty;
+	unsigned char status;
+	unsigned char ch;
+	
+	if (!(port = rc_get_port(bp, "Receive")))
+		return;
+
+	tty = port->tty;
+	if (tty->flip.count >= TTY_FLIPBUF_SIZE)  {
+		printk("rc%d: port %d: Working around flip buffer overflow.\n",
+		       board_No(bp), port_No(port));
+		return;
+	}
+	
+#ifdef RC_REPORT_OVERRUN	
+	status = rc_in(bp, CD180_RCSR);
+	if (status & RCSR_OE)  {
+		port->overrun++;
+#if 0		
+		printk("rc%d: port %d: Overrun. Total %ld overruns.\n", 
+		       board_No(bp), port_No(port), port->overrun);
+#endif		
+	}
+	status &= port->mark_mask;
+#else	
+	status = rc_in(bp, CD180_RCSR) & port->mark_mask;
+#endif	
+	ch = rc_in(bp, CD180_RDR);
+	if (!status)  {
+		return;
+	}
+	if (status & RCSR_TOUT)  {
+		printk("rc%d: port %d: Receiver timeout. Hardware problems ?\n", 
+		       board_No(bp), port_No(port));
+		return;
+		
+	} else if (status & RCSR_BREAK)  {
+		printk("rc%d: port %d: Handling break...\n",
+		       board_No(bp), port_No(port));
+		*tty->flip.flag_buf_ptr++ = TTY_BREAK;
+		if (port->flags & ASYNC_SAK)
+			do_SAK(tty);
+		
+	} else if (status & RCSR_PE) 
+		*tty->flip.flag_buf_ptr++ = TTY_PARITY;
+	
+	else if (status & RCSR_FE) 
+		*tty->flip.flag_buf_ptr++ = TTY_FRAME;
+	
+        else if (status & RCSR_OE)
+		*tty->flip.flag_buf_ptr++ = TTY_OVERRUN;
+	
+	else
+		*tty->flip.flag_buf_ptr++ = 0;
+	
+	*tty->flip.char_buf_ptr++ = ch;
+	tty->flip.count++;
+	queue_task_irq_off(&tty->flip.tqueue, &tq_timer);
+}
+
+extern inline void rc_receive(struct riscom_board const * bp)
+{
+	struct riscom_port *port;
+	struct tty_struct *tty;
+	unsigned char count;
+	
+	if (!(port = rc_get_port(bp, "Receive")))
+		return;
+	
+	tty = port->tty;
+	
+	count = rc_in(bp, CD180_RDCR);
+	
+#ifdef RC_REPORT_FIFO
+	port->hits[count > 8 ? 9 : count]++;
+#endif	
+	
+	while (count--)  {
+		if (tty->flip.count >= TTY_FLIPBUF_SIZE)  {
+			printk("rc%d: port %d: Working around flip buffer overflow.\n",
+			       board_No(bp), port_No(port));
+			break;
+		}
+		*tty->flip.char_buf_ptr++ = rc_in(bp, CD180_RDR);
+		*tty->flip.flag_buf_ptr++ = 0;
+		tty->flip.count++;
+	}
+	queue_task_irq_off(&tty->flip.tqueue, &tq_timer);
+}
+
+extern inline void rc_transmit(struct riscom_board const * bp)
+{
+	struct riscom_port *port;
+	struct tty_struct *tty;
+	unsigned char count;
+	
+	
+	if (!(port = rc_get_port(bp, "Transmit")))
+		return;
+	
+	tty = port->tty;
+	
+	if (port->IER & IER_TXEMPTY)  {
+		/* FIFO drained */
+		rc_out(bp, CD180_CAR, port_No(port));
+		port->IER &= ~IER_TXEMPTY;
+		rc_out(bp, CD180_IER, port->IER);
+		return;
+	}
+	
+	if ((port->xmit_cnt <= 0 && !port->break_length)
+	    || tty->stopped || tty->hw_stopped)  {
+		rc_out(bp, CD180_CAR, port_No(port));
+		port->IER &= ~IER_TXRDY;
+		rc_out(bp, CD180_IER, port->IER);
+		return;
+	}
+	
+	if (port->break_length)  {
+		if (port->break_length > 0)  {
+			if (port->COR2 & COR2_ETC)  {
+				rc_out(bp, CD180_TDR, CD180_C_ESC);
+				rc_out(bp, CD180_TDR, CD180_C_SBRK);
+				port->COR2 &= ~COR2_ETC;
+			}
+			count = MIN(port->break_length, 0xff);
+			rc_out(bp, CD180_TDR, CD180_C_ESC);
+			rc_out(bp, CD180_TDR, CD180_C_DELAY);
+			rc_out(bp, CD180_TDR, count);
+			if (!(port->break_length -= count))
+				port->break_length--;
+		} else  {
+			rc_out(bp, CD180_TDR, CD180_C_ESC);
+			rc_out(bp, CD180_TDR, CD180_C_EBRK);
+			rc_out(bp, CD180_COR2, port->COR2);
+			rc_wait_CCR(bp);
+			rc_out(bp, CD180_CCR, CCR_CORCHG2);
+			port->break_length = 0;
+		}
+		return;
+	}
+	
+	count = CD180_NFIFO;
+	do {
+		rc_out(bp, CD180_TDR, port->xmit_buf[port->xmit_tail++]);
+		port->xmit_tail = port->xmit_tail & (SERIAL_XMIT_SIZE-1);
+		if (--port->xmit_cnt <= 0)
+			break;
+	} while (--count > 0);
+	
+	if (port->xmit_cnt <= 0)  {
+		rc_out(bp, CD180_CAR, port_No(port));
+		port->IER &= ~IER_TXRDY;
+		rc_out(bp, CD180_IER, port->IER);
+	}
+	if (port->xmit_cnt <= port->wakeup_chars)
+		rc_mark_event(port, RS_EVENT_WRITE_WAKEUP);
+}
+
+extern inline void rc_check_modem(struct riscom_board const * bp)
+{
+	struct riscom_port *port;
+	struct tty_struct *tty;
+	unsigned char mcr;
+	
+	if (!(port = rc_get_port(bp, "Modem")))
+		return;
+	
+	tty = port->tty;
+	
+	mcr = rc_in(bp, CD180_MCR);
+	if (mcr & MCR_CDCHG)  {
+		if (rc_in(bp, CD180_MSVR) & MSVR_CD) 
+			wake_up_interruptible(&port->open_wait);
+		else if (!((port->flags & ASYNC_CALLOUT_ACTIVE) &&
+			   (port->flags & ASYNC_CALLOUT_NOHUP)))
+			queue_task_irq_off(&port->tqueue_hangup,  
+					   &tq_scheduler);      
+	}
+	
+#ifdef RISCOM_BRAIN_DAMAGED_CTS
+	if (mcr & MCR_CTSCHG)  {
+		if (rc_in(bp, CD180_MSVR) & MSVR_CTS)  {
+			tty->hw_stopped = 0;
+			port->IER |= IER_TXRDY;
+			if (port->xmit_cnt <= port->wakeup_chars)
+				rc_mark_event(port, RS_EVENT_WRITE_WAKEUP);
+		} else  {
+			tty->hw_stopped = 1;
+			port->IER &= ~IER_TXRDY;
+		}
+		rc_out(bp, CD180_IER, port->IER);
+	}
+	if (mcr & MCR_DSRCHG)  {
+		if (rc_in(bp, CD180_MSVR) & MSVR_DSR)  {
+			tty->hw_stopped = 0;
+			port->IER |= IER_TXRDY;
+			if (port->xmit_cnt <= port->wakeup_chars)
+				rc_mark_event(port, RS_EVENT_WRITE_WAKEUP);
+		} else  {
+			tty->hw_stopped = 1;
+			port->IER &= ~IER_TXRDY;
+		}
+		rc_out(bp, CD180_IER, port->IER);
+	}
+#endif /* RISCOM_BRAIN_DAMAGED_CTS */
+	
+	/* Clear change bits */
+	rc_out(bp, CD180_MCR, 0);
+}
+
+/* The main interrupt processing routine */
+static void rc_interrupt(int irq, void * dev_id, struct pt_regs * regs)
+{
+	unsigned char status;
+	unsigned char ack;
+	struct riscom_board *bp;
+	unsigned long loop = 0;
+	
+	bp = IRQ_to_board[irq];
+	
+	if (!bp || !(bp->flags & RC_BOARD_ACTIVE))  {
+		return;
+	}
+	
+	while ((++loop < 16) && ((status = ~(rc_in(bp, RC_BSR))) &
+				 (RC_BSR_TOUT | RC_BSR_TINT |
+				  RC_BSR_MINT | RC_BSR_RINT))) {
+	
+		if (status & RC_BSR_TOUT) 
+			printk("rc%d: Got timeout. Hardware error ?\n", board_No(bp));
+		
+		else if (status & RC_BSR_RINT) {
+			ack = rc_in(bp, RC_ACK_RINT);
+		
+			if (ack == (RC_ID | GIVR_IT_RCV))
+				rc_receive(bp);
+			else if (ack == (RC_ID | GIVR_IT_REXC))
+				rc_receive_exc(bp);
+			else
+				printk("rc%d: Bad receive ack 0x%02x.\n",
+				       board_No(bp), ack);
+		
+		} else if (status & RC_BSR_TINT) {
+			ack = rc_in(bp, RC_ACK_TINT);
+		
+			if (ack == (RC_ID | GIVR_IT_TX))
+				rc_transmit(bp);
+			else
+				printk("rc%d: Bad transmit ack 0x%02x.\n",
+				       board_No(bp), ack);
+		
+		} else /* if (status & RC_BSR_MINT) */ {
+			ack = rc_in(bp, RC_ACK_MINT);
+		
+			if (ack == (RC_ID | GIVR_IT_MODEM)) 
+				rc_check_modem(bp);
+			else
+				printk("rc%d: Bad modem ack 0x%02x.\n",
+				       board_No(bp), ack);
+		
+		} 
+
+		rc_out(bp, CD180_EOIR, 0);   /* Mark end of interrupt */
+		rc_out(bp, RC_CTOUT, 0);     /* Clear timeout flag    */
+	}
+}
+
+/*
+ *  Routines for open & close processing.
+ */
+
+/* Called with disabled interrupts */
+extern inline int rc_setup_board(struct riscom_board * bp)
+{
+	int error;
+
+	if (bp->flags & RC_BOARD_ACTIVE) 
+		return 0;
+	
+	error = request_irq(bp->irq, rc_interrupt, SA_INTERRUPT, "RISCom/8", NULL);
+	if (error) 
+		return error;
+	
+	rc_out(bp, RC_CTOUT, 0);       		/* Just in case         */
+	bp->DTR = ~0;
+	rc_out(bp, RC_DTR, bp->DTR);	        /* Drop DTR on all ports */
+	
+	IRQ_to_board[bp->irq] = bp;
+	bp->flags |= RC_BOARD_ACTIVE;
+	
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+/* Called with disabled interrupts */
+extern inline void rc_shutdown_board(struct riscom_board *bp)
+{
+	if (!(bp->flags & RC_BOARD_ACTIVE))
+		return;
+	
+	bp->flags &= ~RC_BOARD_ACTIVE;
+	
+	free_irq(bp->irq, NULL);
+	IRQ_to_board[bp->irq] = NULL;
+	
+	bp->DTR = ~0;
+	rc_out(bp, RC_DTR, bp->DTR);	       /* Drop DTR on all ports */
+	
+	MOD_DEC_USE_COUNT;
+}
+
+/*
+ * Setting up port characteristics. 
+ * Must be called with disabled interupts
+ */
+static void rc_change_speed(struct riscom_board *bp, struct riscom_port *port)
+{
+	struct tty_struct *tty;
+	unsigned long baud;
+	long tmp;
+	unsigned char cor1 = 0, cor3 = 0;
+	unsigned char mcor1 = 0, mcor2 = 0;
+	
+	if (!(tty = port->tty) || !tty->termios)
+		return;
+
+	port->IER  = 0;
+	port->COR2 = 0;
+	port->MSVR = MSVR_RTS;
+	
+	baud = C_BAUD(tty);
+	
+	if (baud & CBAUDEX) {
+		baud &= ~CBAUDEX;
+		if (baud < 1 || baud > 2) 
+			port->tty->termios->c_cflag &= ~CBAUDEX;
+		else
+			baud += 15;
+	}
+	if (baud == 15)  {
+		if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
+			baud ++;
+		if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
+			baud += 2;
+	}
+	
+	/* Select port on the board */
+	rc_out(bp, CD180_CAR, port_No(port));
+	
+	if (!baud_table[baud])  {
+		/* Drop DTR & exit */
+		bp->DTR |= (1u << port_No(port));
+		rc_out(bp, RC_DTR, bp->DTR);
+		return;
+	} else  {
+		/* Set DTR on */
+		bp->DTR &= ~(1u << port_No(port));
+		rc_out(bp, RC_DTR, bp->DTR);
+	}
+	
+	/*
+	 * Now we must calculate some speed depended things 
+	 */
+	
+	/* Set baud rate for port */
+	tmp = (((RC_OSCFREQ + baud_table[baud]/2) / baud_table[baud] +
+		CD180_TPC/2) / CD180_TPC);
+
+	rc_out(bp, CD180_RBPRH, (tmp >> 8) & 0xff); 
+	rc_out(bp, CD180_TBPRH, (tmp >> 8) & 0xff); 
+	rc_out(bp, CD180_RBPRL, tmp & 0xff); 
+	rc_out(bp, CD180_TBPRL, tmp & 0xff);
+	
+	baud = (baud_table[baud] + 5) / 10;   /* Estimated CPS */
+	
+	/* Two timer ticks seems enough to wakeup something like SLIP driver */
+	tmp = ((baud + HZ/2) / HZ) * 2 - CD180_NFIFO;		
+	port->wakeup_chars = (tmp < 0) ? 0 : ((tmp >= SERIAL_XMIT_SIZE) ?
+					      SERIAL_XMIT_SIZE - 1 : tmp);
+	
+	/* Receiver timeout will be transmission time for 1.5 chars */
+	tmp = (RISCOM_TPS + RISCOM_TPS/2 + baud/2) / baud;
+	tmp = (tmp > 0xff) ? 0xff : tmp;
+	rc_out(bp, CD180_RTPR, tmp);
+	
+	switch (C_CSIZE(tty))  {
+	 case CS5:
+		cor1 |= COR1_5BITS;
+		break;
+	 case CS6:
+		cor1 |= COR1_6BITS;
+		break;
+	 case CS7:
+		cor1 |= COR1_7BITS;
+		break;
+	 case CS8:
+		cor1 |= COR1_8BITS;
+		break;
+	}
+	
+	if (C_CSTOPB(tty)) 
+		cor1 |= COR1_2SB;
+	
+	cor1 |= COR1_IGNORE;
+	if (C_PARENB(tty))  {
+		cor1 |= COR1_NORMPAR;
+		if (C_PARODD(tty)) 
+			cor1 |= COR1_ODDP;
+		if (I_INPCK(tty)) 
+			cor1 &= ~COR1_IGNORE;
+	}
+	/* Set marking of some errors */
+	port->mark_mask = RCSR_OE | RCSR_TOUT;
+	if (I_INPCK(tty)) 
+		port->mark_mask |= RCSR_FE | RCSR_PE;
+	if (I_BRKINT(tty) || I_PARMRK(tty)) 
+		port->mark_mask |= RCSR_BREAK;
+	if (I_IGNPAR(tty)) 
+		port->mark_mask &= ~(RCSR_FE | RCSR_PE);
+	if (I_IGNBRK(tty))  {
+		port->mark_mask &= ~RCSR_BREAK;
+		if (I_IGNPAR(tty)) 
+			/* Real raw mode. Ignore all */
+			port->mark_mask &= ~RCSR_OE;
+	}
+	/* Enable Hardware FLow Control */
+	if (C_CRTSCTS(tty))  {
+#ifdef RISCOM_BRAIN_DAMAGED_CTS
+		port->IER |= IER_DSR | IER_CTS;
+		mcor1 |= MCOR1_DSRZD | MCOR1_CTSZD;
+		mcor2 |= MCOR2_DSROD | MCOR2_CTSOD;
+		tty->hw_stopped = !(rc_in(bp, CD180_MSVR) & (MSVR_CTS|MSVR_DSR));
+#else
+		port->COR2 |= COR2_CTSAE;
+#endif
+	}
+	/* Enable Software Flow Control. FIXME: I'm not sure about this */
+	/* Some people reported that it works, but I still doubt */
+	if (I_IXON(tty))  {
+		port->COR2 |= COR2_TXIBE;
+		cor3 |= (COR3_FCT | COR3_SCDE);
+		if (I_IXANY(tty))
+			port->COR2 |= COR2_IXM;
+		rc_out(bp, CD180_SCHR1, START_CHAR(tty));
+		rc_out(bp, CD180_SCHR2, STOP_CHAR(tty));
+		rc_out(bp, CD180_SCHR3, START_CHAR(tty));
+		rc_out(bp, CD180_SCHR4, STOP_CHAR(tty));
+	}
+	if (!C_CLOCAL(tty))  {
+		/* Enable CD check */
+		port->IER |= IER_CD;
+		mcor1 |= MCOR1_CDZD;
+		mcor2 |= MCOR2_CDOD;
+	}
+	
+	if (C_CREAD(tty)) 
+		/* Enable receiver */
+		port->IER |= IER_RXD;
+	
+	/* Set input FIFO size (1-8 bytes) */
+	cor3 |= RISCOM_RXFIFO; 
+	/* Setting up CD180 channel registers */
+	rc_out(bp, CD180_COR1, cor1);
+	rc_out(bp, CD180_COR2, port->COR2);
+	rc_out(bp, CD180_COR3, cor3);
+	/* Make CD180 know about registers change */
+	rc_wait_CCR(bp);
+	rc_out(bp, CD180_CCR, CCR_CORCHG1 | CCR_CORCHG2 | CCR_CORCHG3);
+	/* Setting up modem option registers */
+	rc_out(bp, CD180_MCOR1, mcor1);
+	rc_out(bp, CD180_MCOR2, mcor2);
+	/* Enable CD180 trasmitter & receiver */
+	rc_wait_CCR(bp);
+	rc_out(bp, CD180_CCR, CCR_TXEN | CCR_RXEN);
+	/* Enable interrupts */
+	rc_out(bp, CD180_IER, port->IER);
+	/* And finaly set RTS on */
+	rc_out(bp, CD180_MSVR, port->MSVR);
+}
+
+/* Must be called with interrupts enabled */
+static int rc_setup_port(struct riscom_board *bp, struct riscom_port *port)
+{
+	unsigned long flags;
+	
+	if (port->flags & ASYNC_INITIALIZED)
+		return 0;
+	
+	if (!port->xmit_buf) {
+		/* We may sleep in get_free_page() */
+		unsigned long tmp;
+		
+		if (!(tmp = get_free_page(GFP_KERNEL)))
+			return -ENOMEM;
+		    
+		if (port->xmit_buf) {
+			free_page(tmp);
+			return -ERESTARTSYS;
+		}
+		port->xmit_buf = (unsigned char *) tmp;
+	}
+		
+	save_flags(flags); cli();
+		
+	if (port->tty) 
+		clear_bit(TTY_IO_ERROR, &port->tty->flags);
+		
+	if (port->count == 1) 
+		bp->count++;
+		
+	port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
+	rc_change_speed(bp, port);
+	port->flags |= ASYNC_INITIALIZED;
+		
+	restore_flags(flags);
+	return 0;
+}
+
+/* Must be called with interrupts disabled */
+static void rc_shutdown_port(struct riscom_board *bp, struct riscom_port *port)
+{
+	struct tty_struct *tty;
+	
+	if (!(port->flags & ASYNC_INITIALIZED)) 
+		return;
+	
+#ifdef RC_REPORT_OVERRUN
+	printk("rc%d: port %d: Total %ld overruns were detected.\n",
+	       board_No(bp), port_No(port), port->overrun);
+#endif	
+#ifdef RC_REPORT_FIFO
+	{
+		int i;
+		
+		printk("rc%d: port %d: FIFO hits [ ",
+		       board_No(bp), port_No(port));
+		for (i = 0; i < 10; i++)  {
+			printk("%ld ", port->hits[i]);
+		}
+		printk("].\n");
+	}
+#endif	
+	if (port->xmit_buf)  {
+		free_page((unsigned long) port->xmit_buf);
+		port->xmit_buf = NULL;
+	}
+
+	if (!(tty = port->tty) || C_HUPCL(tty))  {
+		/* Drop DTR */
+		bp->DTR |= (1u << port_No(port));
+		rc_out(bp, RC_DTR, bp->DTR);
+	}
+	
+        /* Select port */
+	rc_out(bp, CD180_CAR, port_No(port));
+	/* Reset port */
+	rc_wait_CCR(bp);
+	rc_out(bp, CD180_CCR, CCR_SOFTRESET);
+	/* Disable all interrupts from this port */
+	port->IER = 0;
+	rc_out(bp, CD180_IER, port->IER);
+	
+	if (tty)  
+		set_bit(TTY_IO_ERROR, &tty->flags);
+	port->flags &= ~ASYNC_INITIALIZED;
+	
+	if (--bp->count < 0)  {
+		printk("rc%d: rc_shutdow_port: bad board count: %d\n",
+		       board_No(bp), bp->count);
+		bp->count = 0;
+	}
+	
+	/*
+	 * If this is the last opened port on the board
+	 * shutdown whole board
+	 */
+	if (!bp->count) 
+		rc_shutdown_board(bp);
+}
+
+	
+static int block_til_ready(struct tty_struct *tty, struct file * filp,
+			   struct riscom_port *port)
+{
+	struct wait_queue wait = { current, NULL };
+	struct riscom_board *bp = port_Board(port);
+	int    retval;
+	int    do_clocal = 0;
+	int    CD;
+
+	/*
+	 * If the device is in the middle of being closed, then block
+	 * until it's done, and then try again.
+	 */
+	if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) {
+		interruptible_sleep_on(&port->close_wait);
+		if (port->flags & ASYNC_HUP_NOTIFY)
+			return -EAGAIN;
+		else
+			return -ERESTARTSYS;
+	}
+
+	/*
+	 * If this is a callout device, then just make sure the normal
+	 * device isn't being used.
+	 */
+	if (tty->driver.subtype == RISCOM_TYPE_CALLOUT) {
+		if (port->flags & ASYNC_NORMAL_ACTIVE)
+			return -EBUSY;
+		if ((port->flags & ASYNC_CALLOUT_ACTIVE) &&
+		    (port->flags & ASYNC_SESSION_LOCKOUT) &&
+		    (port->session != current->session))
+		    return -EBUSY;
+		if ((port->flags & ASYNC_CALLOUT_ACTIVE) &&
+		    (port->flags & ASYNC_PGRP_LOCKOUT) &&
+		    (port->pgrp != current->pgrp))
+		    return -EBUSY;
+		port->flags |= ASYNC_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 (port->flags & ASYNC_CALLOUT_ACTIVE)
+			return -EBUSY;
+		port->flags |= ASYNC_NORMAL_ACTIVE;
+		return 0;
+	}
+
+	if (port->flags & ASYNC_CALLOUT_ACTIVE) {
+		if (port->normal_termios.c_cflag & CLOCAL) 
+			do_clocal = 1;
+	} else {
+		if (C_CLOCAL(tty))  
+			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(&port->open_wait, &wait);
+	cli();
+	if (!tty_hung_up_p(filp))
+		port->count--;
+	sti();
+	port->blocked_open++;
+	while (1) {
+		cli();
+		rc_out(bp, CD180_CAR, port_No(port));
+		CD = rc_in(bp, CD180_MSVR) & MSVR_CD;
+		if (!(port->flags & ASYNC_CALLOUT_ACTIVE))  {
+			rc_out(bp, CD180_MSVR, MSVR_RTS);
+			bp->DTR &= ~(1u << port_No(port));
+			rc_out(bp, RC_DTR, bp->DTR);
+		}
+		sti();
+		current->state = TASK_INTERRUPTIBLE;
+		if (tty_hung_up_p(filp) ||
+		    !(port->flags & ASYNC_INITIALIZED)) {
+			if (port->flags & ASYNC_HUP_NOTIFY)
+				retval = -EAGAIN;
+			else
+				retval = -ERESTARTSYS;	
+			break;
+		}
+		if (!(port->flags & ASYNC_CALLOUT_ACTIVE) &&
+		    !(port->flags & ASYNC_CLOSING) &&
+		    (do_clocal || CD))
+			break;
+		if (current->signal & ~current->blocked) {
+			retval = -ERESTARTSYS;
+			break;
+		}
+		schedule();
+	}
+	current->state = TASK_RUNNING;
+	remove_wait_queue(&port->open_wait, &wait);
+	if (!tty_hung_up_p(filp))
+		port->count++;
+	port->blocked_open--;
+	if (retval)
+		return retval;
+	
+	port->flags |= ASYNC_NORMAL_ACTIVE;
+	return 0;
+}	
+
+static int rc_open(struct tty_struct * tty, struct file * filp)
+{
+	int board;
+	int error;
+	struct riscom_port * port;
+	struct riscom_board * bp;
+	unsigned long flags;
+	
+	board = RC_BOARD(MINOR(tty->device));
+	if (board > RC_NBOARD || !(rc_board[board].flags & RC_BOARD_PRESENT))
+		return -ENODEV;
+	
+	bp = &rc_board[board];
+	port = rc_port + board * RC_NPORT + RC_PORT(MINOR(tty->device));
+	if (rc_paranoia_check(port, tty->device, "rc_open"))
+		return -ENODEV;
+	
+	if ((error = rc_setup_board(bp))) 
+		return error;
+		
+	port->count++;
+	tty->driver_data = port;
+	port->tty = tty;
+	
+	if ((error = rc_setup_port(bp, port))) 
+		return error;
+	
+	if ((error = block_til_ready(tty, filp, port)))
+		return error;
+	
+	if ((port->count == 1) && (port->flags & ASYNC_SPLIT_TERMIOS)) {
+		if (tty->driver.subtype == RISCOM_TYPE_NORMAL)
+			*tty->termios = port->normal_termios;
+		else
+			*tty->termios = port->callout_termios;
+		save_flags(flags); cli();
+		rc_change_speed(bp, port);
+		restore_flags(flags);
+	}
+
+	port->session = current->session;
+	port->pgrp = current->pgrp;
+	
+	return 0;
+}
+
+static void rc_close(struct tty_struct * tty, struct file * filp)
+{
+	struct riscom_port *port = (struct riscom_port *) tty->driver_data;
+	struct riscom_board *bp;
+	unsigned long flags;
+	unsigned long timeout;
+	
+	if (!port || rc_paranoia_check(port, tty->device, "close"))
+		return;
+	
+	save_flags(flags); cli();
+	if (tty_hung_up_p(filp))  {
+		restore_flags(flags);
+		return;
+	}
+	
+	bp = port_Board(port);
+	if ((tty->count == 1) && (port->count != 1))  {
+		printk("rc%d: rc_close: bad port count;"
+		       " tty->count is 1, port count is %d\n",
+		       board_No(bp), port->count);
+		port->count = 1;
+	}
+	if (--port->count < 0)  {
+		printk("rc%d: rc_close: bad port count for tty%d: %d\n",
+		       board_No(bp), port_No(port), port->count);
+		port->count = 0;
+	}
+	if (port->count)  {
+		restore_flags(flags);
+		return;
+	}
+	port->flags |= ASYNC_CLOSING;
+	/*
+	 * Save the termios structure, since this port may have
+	 * separate termios for callout and dialin.
+	 */
+	if (port->flags & ASYNC_NORMAL_ACTIVE)
+		port->normal_termios = *tty->termios;
+	if (port->flags & ASYNC_CALLOUT_ACTIVE)
+		port->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 (port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
+		tty_wait_until_sent(tty, port->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.
+	 */
+	port->IER &= ~IER_RXD;
+	if (port->flags & ASYNC_INITIALIZED) {
+		port->IER &= ~IER_TXRDY;
+		port->IER |= IER_TXEMPTY;
+		rc_out(bp, CD180_CAR, port_No(port));
+		rc_out(bp, CD180_IER, port->IER);
+		/*
+		 * Before we drop DTR, make sure the UART transmitter
+		 * has completely drained; this is especially
+		 * important if there is a transmit FIFO!
+		 */
+		timeout = jiffies+HZ;
+		while(port->IER & IER_TXEMPTY)  {
+			current->state = TASK_INTERRUPTIBLE;
+			current->timeout = jiffies + port->timeout;
+			schedule();
+			if (jiffies > timeout)
+				break;
+		}
+	}
+	rc_shutdown_port(bp, port);
+	if (tty->driver.flush_buffer)
+		tty->driver.flush_buffer(tty);
+	if (tty->ldisc.flush_buffer)
+		tty->ldisc.flush_buffer(tty);
+	tty->closing = 0;
+	port->event = 0;
+	port->tty = 0;
+	if (port->blocked_open) {
+		if (port->close_delay) {
+			current->state = TASK_INTERRUPTIBLE;
+			current->timeout = jiffies + port->close_delay;
+			schedule();
+		}
+		wake_up_interruptible(&port->open_wait);
+	}
+	port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE|
+			 ASYNC_CLOSING);
+	wake_up_interruptible(&port->close_wait);
+	restore_flags(flags);
+}
+
+static int rc_write(struct tty_struct * tty, int from_user, 
+		    const unsigned char *buf, int count)
+{
+	struct riscom_port *port = (struct riscom_port *)tty->driver_data;
+	struct riscom_board *bp;
+	int c, total = 0;
+	unsigned long flags;
+				
+	if (rc_paranoia_check(port, tty->device, "rc_write"))
+		return 0;
+	
+	bp = port_Board(port);
+
+	if (!tty || !port->xmit_buf || !tmp_buf)
+		return 0;
+
+	if (from_user)
+		down(&tmp_buf_sem);
+
+	save_flags(flags);
+	while (1) {
+		cli();		
+		c = MIN(count, MIN(SERIAL_XMIT_SIZE - port->xmit_cnt - 1,
+				   SERIAL_XMIT_SIZE - port->xmit_head));
+		if (c <= 0)
+			break;
+
+		if (from_user) {
+			memcpy_fromfs(tmp_buf, buf, c);
+			c = MIN(c, MIN(SERIAL_XMIT_SIZE - port->xmit_cnt - 1,
+				       SERIAL_XMIT_SIZE - port->xmit_head));
+			memcpy(port->xmit_buf + port->xmit_head, tmp_buf, c);
+		} else
+			memcpy(port->xmit_buf + port->xmit_head, buf, c);
+		port->xmit_head = (port->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
+		port->xmit_cnt += c;
+		restore_flags(flags);
+		buf += c;
+		count -= c;
+		total += c;
+	}
+	if (from_user)
+		up(&tmp_buf_sem);
+	if (port->xmit_cnt && !tty->stopped && !tty->hw_stopped &&
+	    !(port->IER & IER_TXRDY)) {
+		port->IER |= IER_TXRDY;
+		rc_out(bp, CD180_CAR, port_No(port));
+		rc_out(bp, CD180_IER, port->IER);
+	}
+	restore_flags(flags);
+	return total;
+}
+
+static void rc_put_char(struct tty_struct * tty, unsigned char ch)
+{
+	struct riscom_port *port = (struct riscom_port *)tty->driver_data;
+	unsigned long flags;
+
+	if (rc_paranoia_check(port, tty->device, "rc_put_char"))
+		return;
+
+	if (!tty || !port->xmit_buf)
+		return;
+
+	save_flags(flags); cli();
+	
+	if (port->xmit_cnt >= SERIAL_XMIT_SIZE - 1) {
+		restore_flags(flags);
+		return;
+	}
+
+	port->xmit_buf[port->xmit_head++] = ch;
+	port->xmit_head &= SERIAL_XMIT_SIZE - 1;
+	port->xmit_cnt++;
+	restore_flags(flags);
+}
+
+static void rc_flush_chars(struct tty_struct * tty)
+{
+	struct riscom_port *port = (struct riscom_port *)tty->driver_data;
+	unsigned long flags;
+				
+	if (rc_paranoia_check(port, tty->device, "rc_flush_chars"))
+		return;
+	
+	if (port->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
+	    !port->xmit_buf)
+		return;
+
+	save_flags(flags); cli();
+	port->IER |= IER_TXRDY;
+	rc_out(port_Board(port), CD180_CAR, port_No(port));
+	rc_out(port_Board(port), CD180_IER, port->IER);
+	restore_flags(flags);
+}
+
+static int rc_write_room(struct tty_struct * tty)
+{
+	struct riscom_port *port = (struct riscom_port *)tty->driver_data;
+	int	ret;
+				
+	if (rc_paranoia_check(port, tty->device, "rc_write_room"))
+		return 0;
+
+	ret = SERIAL_XMIT_SIZE - port->xmit_cnt - 1;
+	if (ret < 0)
+		ret = 0;
+	return ret;
+}
+
+static int rc_chars_in_buffer(struct tty_struct *tty)
+{
+	struct riscom_port *port = (struct riscom_port *)tty->driver_data;
+				
+	if (rc_paranoia_check(port, tty->device, "rc_chars_in_buffer"))
+		return 0;
+	
+	return port->xmit_cnt;
+}
+
+static void rc_flush_buffer(struct tty_struct *tty)
+{
+	struct riscom_port *port = (struct riscom_port *)tty->driver_data;
+	unsigned long flags;
+				
+	if (rc_paranoia_check(port, tty->device, "rc_flush_buffer"))
+		return;
+
+	save_flags(flags); cli();
+	port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
+	restore_flags(flags);
+	
+	wake_up_interruptible(&tty->write_wait);
+	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+	    tty->ldisc.write_wakeup)
+		(tty->ldisc.write_wakeup)(tty);
+}
+
+static int rc_get_modem_info(struct riscom_port * port, unsigned int *value)
+{
+	struct riscom_board * bp;
+	unsigned char status;
+	unsigned int result;
+	unsigned long flags;
+
+	bp = port_Board(port);
+	save_flags(flags); cli();
+	rc_out(bp, CD180_CAR, port_No(port));
+	status = rc_in(bp, CD180_MSVR);
+	result = rc_in(bp, RC_RI) & (1u << port_No(port)) ? 0 : TIOCM_RNG;
+	restore_flags(flags);
+	result |= ((status & MSVR_RTS) ? TIOCM_RTS : 0)
+		| ((status & MSVR_DTR) ? TIOCM_DTR : 0)
+		| ((status & MSVR_CD)  ? TIOCM_CAR : 0)
+		| ((status & MSVR_DSR) ? TIOCM_DSR : 0)
+		| ((status & MSVR_CTS) ? TIOCM_CTS : 0);
+	put_user(result,(unsigned long *) value);
+	return 0;
+}
+
+static int rc_set_modem_info(struct riscom_port * port, unsigned int cmd,
+			     unsigned int *value)
+{
+	int error;
+	unsigned int arg;
+	unsigned long flags;
+	struct riscom_board *bp = port_Board(port);
+
+	error = verify_area(VERIFY_READ, value, sizeof(int));
+	if (error) 
+		return error;
+	arg = get_fs_long((unsigned long *) value);
+	switch (cmd) {
+	 case TIOCMBIS: 
+		if (arg & TIOCM_RTS) 
+			port->MSVR |= MSVR_RTS;
+		if (arg & TIOCM_DTR)
+			bp->DTR &= ~(1u << port_No(port));
+		break;
+	case TIOCMBIC:
+		if (arg & TIOCM_RTS)
+			port->MSVR &= ~MSVR_RTS;
+		if (arg & TIOCM_DTR)
+			bp->DTR |= (1u << port_No(port));
+		break;
+	case TIOCMSET:
+		port->MSVR = (arg & TIOCM_RTS) ? (port->MSVR | MSVR_RTS) : 
+					         (port->MSVR & ~MSVR_RTS);
+		bp->DTR = arg & TIOCM_DTR ? (bp->DTR &= ~(1u << port_No(port))) :
+					    (bp->DTR |=  (1u << port_No(port)));
+		break;
+	 default:
+		return -EINVAL;
+	}
+	save_flags(flags); cli();
+	rc_out(bp, CD180_CAR, port_No(port));
+	rc_out(bp, CD180_MSVR, port->MSVR);
+	rc_out(bp, RC_DTR, bp->DTR);
+	restore_flags(flags);
+	return 0;
+}
+
+extern inline void rc_send_break(struct riscom_port * port, unsigned long length)
+{
+	struct riscom_board *bp = port_Board(port);
+	unsigned long flags;
+	
+	save_flags(flags); cli();
+	port->break_length = RISCOM_TPS / HZ * length;
+	port->COR2 |= COR2_ETC;
+	port->IER  |= IER_TXRDY;
+	rc_out(bp, CD180_CAR, port_No(port));
+	rc_out(bp, CD180_COR2, port->COR2);
+	rc_out(bp, CD180_IER, port->IER);
+	rc_wait_CCR(bp);
+	rc_out(bp, CD180_CCR, CCR_CORCHG2);
+	rc_wait_CCR(bp);
+	restore_flags(flags);
+}
+
+extern inline int rc_set_serial_info(struct riscom_port * port,
+				     struct serial_struct * newinfo)
+{
+	struct serial_struct tmp;
+	struct riscom_board *bp = port_Board(port);
+	int change_speed;
+	unsigned long flags;
+	int error;
+	
+	error = verify_area(VERIFY_READ, (void *) newinfo, sizeof(tmp));
+	if (error)
+		return error;
+	memcpy_fromfs(&tmp, newinfo, sizeof(tmp));
+	
+#if 0	
+	if ((tmp.irq != bp->irq) ||
+	    (tmp.port != bp->base) ||
+	    (tmp.type != PORT_CIRRUS) ||
+	    (tmp.baud_base != (RC_OSCFREQ + CD180_TPC/2) / CD180_TPC) ||
+	    (tmp.custom_divisor != 0) ||
+	    (tmp.xmit_fifo_size != CD180_NFIFO) ||
+	    (tmp.flags & ~RISCOM_LEGAL_FLAGS))
+		return -EINVAL;
+#endif	
+	
+	change_speed = ((port->flags & ASYNC_SPD_MASK) !=
+			(tmp.flags & ASYNC_SPD_MASK));
+	
+	if (!suser()) {
+		if ((tmp.close_delay != port->close_delay) ||
+		    (tmp.closing_wait != port->closing_wait) ||
+		    ((tmp.flags & ~ASYNC_USR_MASK) !=
+		     (port->flags & ~ASYNC_USR_MASK)))  
+			return -EPERM;
+		port->flags = ((port->flags & ~ASYNC_USR_MASK) |
+			       (tmp.flags & ASYNC_USR_MASK));
+	} else  {
+		port->flags = ((port->flags & ~ASYNC_FLAGS) |
+			       (tmp.flags & ASYNC_FLAGS));
+		port->close_delay = tmp.close_delay;
+		port->closing_wait = tmp.closing_wait;
+	}
+	if (change_speed)  {
+		save_flags(flags); cli();
+		rc_change_speed(bp, port);
+		restore_flags(flags);
+	}
+	return 0;
+}
+
+extern inline int rc_get_serial_info(struct riscom_port * port,
+				     struct serial_struct * retinfo)
+{
+	struct serial_struct tmp;
+	struct riscom_board *bp = port_Board(port);
+	int error;
+	
+	error = verify_area(VERIFY_WRITE, (void *) retinfo, sizeof(tmp));
+	if (error)
+		return error;
+	
+	memset(&tmp, 0, sizeof(tmp));
+	tmp.type = PORT_CIRRUS;
+	tmp.line = port - rc_port;
+	tmp.port = bp->base;
+	tmp.irq  = bp->irq;
+	tmp.flags = port->flags;
+	tmp.baud_base = (RC_OSCFREQ + CD180_TPC/2) / CD180_TPC;
+	tmp.close_delay = port->close_delay * HZ/100;
+	tmp.closing_wait = port->closing_wait * HZ/100;
+	tmp.xmit_fifo_size = CD180_NFIFO;
+	memcpy_tofs(retinfo, &tmp, sizeof(tmp));
+	return 0;
+}
+
+static int rc_ioctl(struct tty_struct * tty, struct file * filp, 
+		    unsigned int cmd, unsigned long arg)
+		    
+{
+	struct riscom_port *port = (struct riscom_port *)tty->driver_data;
+	int error;
+	int retval;
+				
+	if (rc_paranoia_check(port, tty->device, "rc_ioctl"))
+		return -ENODEV;
+	
+	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)
+			rc_send_break(port, 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);
+		rc_send_break(port, 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:
+		arg = get_user((unsigned long *) arg);
+		tty->termios->c_cflag =
+			((tty->termios->c_cflag & ~CLOCAL) |
+			(arg ? CLOCAL : 0));
+		return 0;
+	 case TIOCMGET:
+		error = verify_area(VERIFY_WRITE, (void *) arg,
+				    sizeof(unsigned int));
+		if (error)
+			return error;
+		return rc_get_modem_info(port, (unsigned int *) arg);
+	 case TIOCMBIS:
+	 case TIOCMBIC:
+	 case TIOCMSET:
+		return rc_set_modem_info(port, cmd, (unsigned int *) arg);
+	 case TIOCGSERIAL:	
+		return rc_get_serial_info(port, (struct serial_struct *) arg);
+	 case TIOCSSERIAL:	
+		return rc_set_serial_info(port, (struct serial_struct *) arg);
+	 default:
+		return -ENOIOCTLCMD;
+	}
+	return 0;
+}
+
+static void rc_throttle(struct tty_struct * tty)
+{
+	struct riscom_port *port = (struct riscom_port *)tty->driver_data;
+	struct riscom_board *bp;
+	unsigned long flags;
+				
+	if (rc_paranoia_check(port, tty->device, "rc_throttle"))
+		return;
+	
+	bp = port_Board(port);
+	
+	save_flags(flags); cli();
+	port->MSVR &= ~MSVR_RTS;
+	rc_out(bp, CD180_CAR, port_No(port));
+	if (I_IXOFF(tty))  {
+		rc_wait_CCR(bp);
+		rc_out(bp, CD180_CCR, CCR_SSCH2);
+		rc_wait_CCR(bp);
+	}
+	rc_out(bp, CD180_MSVR, port->MSVR);
+	restore_flags(flags);
+}
+
+static void rc_unthrottle(struct tty_struct * tty)
+{
+	struct riscom_port *port = (struct riscom_port *)tty->driver_data;
+	struct riscom_board *bp;
+	unsigned long flags;
+				
+	if (rc_paranoia_check(port, tty->device, "rc_unthrottle"))
+		return;
+	
+	bp = port_Board(port);
+	
+	save_flags(flags); cli();
+	port->MSVR |= MSVR_RTS;
+	rc_out(bp, CD180_CAR, port_No(port));
+	if (I_IXOFF(tty))  {
+		rc_wait_CCR(bp);
+		rc_out(bp, CD180_CCR, CCR_SSCH1);
+		rc_wait_CCR(bp);
+	}
+	rc_out(bp, CD180_MSVR, port->MSVR);
+	restore_flags(flags);
+}
+
+static void rc_stop(struct tty_struct * tty)
+{
+	struct riscom_port *port = (struct riscom_port *)tty->driver_data;
+	struct riscom_board *bp;
+	unsigned long flags;
+				
+	if (rc_paranoia_check(port, tty->device, "rc_stop"))
+		return;
+	
+	bp = port_Board(port);
+	
+	save_flags(flags); cli();
+	port->IER &= ~IER_TXRDY;
+	rc_out(bp, CD180_CAR, port_No(port));
+	rc_out(bp, CD180_IER, port->IER);
+	restore_flags(flags);
+}
+
+static void rc_start(struct tty_struct * tty)
+{
+	struct riscom_port *port = (struct riscom_port *)tty->driver_data;
+	struct riscom_board *bp;
+	unsigned long flags;
+				
+	if (rc_paranoia_check(port, tty->device, "rc_start"))
+		return;
+	
+	bp = port_Board(port);
+	
+	save_flags(flags); cli();
+	if (port->xmit_cnt && port->xmit_buf && !(port->IER & IER_TXRDY))  {
+		port->IER |= IER_TXRDY;
+		rc_out(bp, CD180_CAR, port_No(port));
+		rc_out(bp, CD180_IER, port->IER);
+	}
+	restore_flags(flags);
+}
+
+/*
+ * 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_rc_hangup() -> tty->hangup() -> rc_hangup()
+ * 
+ */
+static void do_rc_hangup(void *private_)
+{
+	struct riscom_port	*port = (struct riscom_port *) private_;
+	struct tty_struct	*tty;
+	
+	tty = port->tty;
+	if (!tty)
+		return;
+
+	tty_hangup(tty);
+}
+
+static void rc_hangup(struct tty_struct * tty)
+{
+	struct riscom_port *port = (struct riscom_port *)tty->driver_data;
+	struct riscom_board *bp;
+				
+	if (rc_paranoia_check(port, tty->device, "rc_hangup"))
+		return;
+	
+	bp = port_Board(port);
+	
+	rc_shutdown_port(bp, port);
+	port->event = 0;
+	port->count = 0;
+	port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE);
+	port->tty = 0;
+	wake_up_interruptible(&port->open_wait);
+}
+
+static void rc_set_termios(struct tty_struct * tty, struct termios * old_termios)
+{
+	struct riscom_port *port = (struct riscom_port *)tty->driver_data;
+	unsigned long flags;
+				
+	if (rc_paranoia_check(port, tty->device, "rc_set_termios"))
+		return;
+	
+	if (tty->termios->c_cflag == old_termios->c_cflag &&
+	    tty->termios->c_iflag == old_termios->c_iflag)
+		return;
+
+	save_flags(flags); cli();
+	rc_change_speed(port_Board(port), port);
+	restore_flags(flags);
+
+	if ((old_termios->c_cflag & CRTSCTS) &&
+	    !(tty->termios->c_cflag & CRTSCTS)) {
+		tty->hw_stopped = 0;
+		rc_start(tty);
+	}
+}
+
+static void do_riscom_bh(void)
+{
+	 run_task_queue(&tq_riscom);
+}
+
+static void do_softint(void *private_)
+{
+	struct riscom_port	*port = (struct riscom_port *) private_;
+	struct tty_struct	*tty;
+	
+	if(!(tty = port->tty)) 
+		return;
+
+	if (clear_bit(RS_EVENT_WRITE_WAKEUP, &port->event)) {
+		if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+		    tty->ldisc.write_wakeup)
+			(tty->ldisc.write_wakeup)(tty);
+		wake_up_interruptible(&tty->write_wait);
+	}
+}
+
+static int rc_init_drivers(void)
+{
+	int error;
+	int i;
+
+	
+	if (!(tmp_buf = (unsigned char *) get_free_page(GFP_KERNEL))) {
+		printk("rc: Couldn't get free page.\n");
+		return 1;
+	}
+	init_bh(RISCOM8_BH, do_riscom_bh);
+	memset(IRQ_to_board, 0, sizeof(IRQ_to_board));
+	memset(&riscom_driver, 0, sizeof(riscom_driver));
+	riscom_driver.magic = TTY_DRIVER_MAGIC;
+	riscom_driver.name = "ttyL";
+	riscom_driver.major = RISCOM8_NORMAL_MAJOR;
+	riscom_driver.num = RC_NBOARD * RC_NPORT;
+	riscom_driver.type = TTY_DRIVER_TYPE_SERIAL;
+	riscom_driver.subtype = RISCOM_TYPE_NORMAL;
+	riscom_driver.init_termios = tty_std_termios;
+	riscom_driver.init_termios.c_cflag =
+		B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+	riscom_driver.flags = TTY_DRIVER_REAL_RAW;
+	riscom_driver.refcount = &riscom_refcount;
+	riscom_driver.table = riscom_table;
+	riscom_driver.termios = riscom_termios;
+	riscom_driver.termios_locked = riscom_termios_locked;
+
+	riscom_driver.open  = rc_open;
+	riscom_driver.close = rc_close;
+	riscom_driver.write = rc_write;
+	riscom_driver.put_char = rc_put_char;
+	riscom_driver.flush_chars = rc_flush_chars;
+	riscom_driver.write_room = rc_write_room;
+	riscom_driver.chars_in_buffer = rc_chars_in_buffer;
+	riscom_driver.flush_buffer = rc_flush_buffer;
+	riscom_driver.ioctl = rc_ioctl;
+	riscom_driver.throttle = rc_throttle;
+	riscom_driver.unthrottle = rc_unthrottle;
+	riscom_driver.set_termios = rc_set_termios;
+	riscom_driver.stop = rc_stop;
+	riscom_driver.start = rc_start;
+	riscom_driver.hangup = rc_hangup;
+
+	riscom_callout_driver = riscom_driver;
+	riscom_callout_driver.name = "cul";
+	riscom_callout_driver.major = RISCOM8_CALLOUT_MAJOR;
+	riscom_callout_driver.subtype = RISCOM_TYPE_CALLOUT;
+	
+	if ((error = tty_register_driver(&riscom_driver)))  {
+		free_page((unsigned long)tmp_buf);
+		printk("rc: Couldn't register RISCom/8 driver, error = %d\n",
+		       error);
+		return 1;
+	}
+	if ((error = tty_register_driver(&riscom_callout_driver)))  {
+		free_page((unsigned long)tmp_buf);
+		tty_unregister_driver(&riscom_driver);
+		printk("rc: Couldn't register RISCom/8 callout driver, error = %d\n",
+		       error);
+		return 1;
+	}
+	
+	memset(rc_port, 0, sizeof(rc_port));
+	for (i = 0; i < RC_NPORT * RC_NBOARD; i++)  {
+		rc_port[i].callout_termios = riscom_callout_driver.init_termios;
+		rc_port[i].normal_termios  = riscom_driver.init_termios;
+		rc_port[i].magic = RISCOM8_MAGIC;
+		rc_port[i].tqueue.routine = do_softint;
+		rc_port[i].tqueue.data = &rc_port[i];
+		rc_port[i].tqueue_hangup.routine = do_rc_hangup;
+		rc_port[i].tqueue_hangup.data = &rc_port[i];
+		rc_port[i].close_delay = 50 * HZ/100;
+		rc_port[i].closing_wait = 3000 * HZ/100;
+	}
+	
+	return 0;
+}
+
+static void rc_release_drivers(void)
+{
+	free_page((unsigned long)tmp_buf);
+	tty_unregister_driver(&riscom_driver);
+	tty_unregister_driver(&riscom_callout_driver);
+}
+
+#ifndef MODULE
+/*
+ * Called at boot time.
+ * 
+ * You can specify IO base for up to RC_NBOARD cards,
+ * using line "riscom8=0xiobase1,0xiobase2,.." at LILO prompt.
+ * Note that there wiil be no probing at default
+ * addresses in this case.
+ *
+ */ 
+void riscom8_setup(char *str, int * ints)
+{
+	int i;
+
+	for (i = 0; i < RC_NBOARD; i++) {
+		if (i < ints[0])
+			rc_board[i].base = ints[i+1];
+		else 
+			rc_board[i].base = 0;
+	}
+}
+#endif
+
+/* 
+ * This routine must be called by kernel at boot time 
+ */
+int riscom8_init(void) 
+{
+	int i;
+	int found = 0;
+
+	printk("rc: SDL RISCom/8 card driver v1.0, (c) D.Gorodchanin 1994-1996.\n");
+
+	if (rc_init_drivers()) 
+		return -EIO;
+
+	for (i = 0; i < RC_NBOARD; i++) 
+		if (rc_board[i].base && !rc_probe(&rc_board[i]))  
+			found++;
+	
+	if (!found)  {
+		rc_release_drivers();
+		printk("rc: No RISCom/8 boards detected.\n");
+		return -EIO;
+	}
+	return 0;
+}
+
+#ifdef MODULE
+int iobase  = 0;
+int iobase1 = 0;
+int iobase2 = 0;
+int iobase3 = 0;
+
+/*
+ * You can setup up to 4 boards (current value of RC_NBOARD)
+ * by specifying "iobase=0xXXX iobase1=0xXXX ..." as isnmod parametr.
+ *
+ */
+int init_module(void) 
+{
+	int i;
+
+	if (iobase || iobase1 || iobase2 || iobase3) {
+		for(i = 0; i < RC_NBOARD; i++)
+			rc_board[0].base = 0;
+	}
+
+	if (iobase)
+		rc_board[0].base = iobase;
+	if (iobase1)
+		rc_board[1].base = iobase1;
+	if (iobase2)
+		rc_board[2].base = iobase2;
+	if (iobase3)
+		rc_board[3].base = iobase3;
+	
+	return riscom8_init();
+}
+	
+void cleanup_module(void)
+{
+	int i;
+	
+	rc_release_drivers();
+	for (i = 0; i < RC_NBOARD; i++)  
+		if (rc_board[i].flags & RC_BOARD_PRESENT) 
+			rc_release_io_range(&rc_board[i]);
+	
+}
+#endif /* MODULE */
diff -u --recursive --new-file v1.3.93/linux/drivers/char/riscom8.h linux/drivers/char/riscom8.h
--- v1.3.93/linux/drivers/char/riscom8.h	Thu Jan  1 02:00:00 1970
+++ linux/drivers/char/riscom8.h	Mon Apr 22 07:14:01 1996
@@ -0,0 +1,106 @@
+/*
+ *      linux/drivers/char/riscom8.h  -- RISCom/8 multiport serial driver.
+ *
+ *      Copyright (C) 1994-1996  Dmitry Gorodchanin (begemot@bgm.rosprint.net)
+ *
+ *      This code is loosely based on the Linux serial driver, written by
+ *      Linus Torvalds, Theodore T'so and others. The RISCom/8 card 
+ *      programming info was obtained from various drivers for other OSes 
+ *	(FreeBSD, ISC, etc), but no source code from those drivers were 
+ *	directly included in this drvier.
+ *
+ *
+ *      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.
+ */
+
+#ifndef __LINUX_RISCOM8_H
+#define __LINUX_RISCOM8_H
+
+#include <linux/serial.h>
+
+#ifdef __KERNEL__
+
+#define RC_NBOARD		4
+/* NOTE: RISCom decoder recognizes 16 addresses... */
+#define RC_NPORT        	8  
+#define RC_BOARD(line)		(((line) >> 3) & 0x07)
+#define RC_PORT(line)		((line) & (RC_NPORT - 1))
+
+/* Ticks per sec. Used for setting receiver timeout and break length */
+#define RISCOM_TPS		4000
+
+/* Yeah, after heavy testing I decided it must be 6.
+ * Sure, You can change it if needed.
+ */
+#define RISCOM_RXFIFO		6	/* Max. receiver FIFO size (1-8) */
+
+#define RISCOM8_MAGIC		0x0907
+
+#define RC_IOBASE1	0x220
+#define RC_IOBASE2	0x240
+#define RC_IOBASE3	0x250
+#define RC_IOBASE4	0x260
+
+struct riscom_board {
+	unsigned long   flags;
+	unsigned short	base;
+	unsigned char 	irq;
+	signed   char	count;
+	unsigned char	DTR;
+};
+
+#define RC_BOARD_PRESENT	0x00000001
+#define RC_BOARD_ACTIVE		0x00000002
+	
+struct riscom_port {
+	int			magic;
+	int			baud_base;
+	int			flags;
+	struct tty_struct 	* tty;
+	int			count;
+	int			blocked_open;
+	int			event;
+	int			timeout;
+	int			close_delay;
+	long			session;
+	long			pgrp;
+	unsigned char 		* xmit_buf;
+	int			custom_divisor;
+	int			xmit_head;
+	int			xmit_tail;
+	int			xmit_cnt;
+	struct termios          normal_termios;
+	struct termios		callout_termios;
+	struct wait_queue	*open_wait;
+	struct wait_queue	*close_wait;
+	struct tq_struct	tqueue;
+	struct tq_struct	tqueue_hangup;
+	short			wakeup_chars;
+	short			break_length;
+	unsigned short		closing_wait;
+	unsigned char		mark_mask;
+	unsigned char		IER;
+	unsigned char		MSVR;
+	unsigned char		COR2;
+#ifdef RC_REPORT_OVERRUN
+	unsigned long		overrun;
+#endif	
+#ifdef RC_REPORT_FIFO
+	unsigned long		hits[10];
+#endif
+};
+
+#endif /* __KERNEL__ */
+#endif /* __LINUX_RISCOM8_H */
diff -u --recursive --new-file v1.3.93/linux/drivers/char/riscom8_reg.h linux/drivers/char/riscom8_reg.h
--- v1.3.93/linux/drivers/char/riscom8_reg.h	Thu Jan  1 02:00:00 1970
+++ linux/drivers/char/riscom8_reg.h	Mon Apr 22 07:14:01 1996
@@ -0,0 +1,254 @@
+/*
+ *      linux/drivers/char/riscom8_reg.h  -- RISCom/8 multiport serial driver.
+ */
+
+/*
+ * Definitions for RISCom/8 Async Mux card by SDL Communications, Inc.
+ */
+
+/*
+ * Address mapping between Cirrus Logic CD180 chip internal registers
+ * and ISA port addresses:
+ *
+ *      CL-CD180                A6  A5   A4  A3                      A2 A1 A0
+ *      ISA             A15 A14 A13 A12  A11 A10 A9 A8  A7 A6 A5 A4  A3 A2 A1 A0
+ */
+#define RC_TO_ISA(r)    ((((r)&0x07)<<1) | (((r)&~0x07)<<7))
+
+
+/* RISCom/8 On-Board Registers (assuming address translation) */
+
+#define RC_RI           0x100   /* Ring Indicator Register (R/O)           */
+#define RC_DTR          0x100   /* DTR Register (W/O)                      */
+#define RC_BSR          0x101   /* Board Status Register (R/O)             */
+#define RC_CTOUT        0x101   /* Clear Timeout (W/O)                     */
+
+
+/* Board Status Register */
+
+#define RC_BSR_TOUT     0x08     /* Hardware Timeout                       */
+#define RC_BSR_RINT     0x04     /* Receiver Interrupt                     */
+#define RC_BSR_TINT     0x02     /* Transmitter Interrupt                  */
+#define RC_BSR_MINT     0x01     /* Modem Ctl Interrupt                    */
+
+
+/* On-board oscillator frequency (in Hz) */
+#define RC_OSCFREQ      9830400
+
+/* Values of choice for Interrupt ACKs */
+#define RC_ACK_MINT     0x81    /* goes to PILR1                           */
+#define RC_ACK_RINT     0x82    /* goes to PILR3                           */
+#define RC_ACK_TINT     0x84    /* goes to PILR2                           */
+
+/* Chip ID (sorry, only one chip now) */
+#define RC_ID           0x10
+
+/* Definitions for Cirrus Logic CL-CD180 8-port async mux chip */
+ 
+#define CD180_NCH       8       /* Total number of channels                */
+#define CD180_TPC       16      /* Ticks per character                     */
+#define CD180_NFIFO	8	/* TX FIFO size                            */
+
+
+/* Global registers */
+
+#define CD180_GIVR      0x40    /* Global Interrupt Vector Register        */
+#define CD180_GICR      0x41    /* Global Interrupting Channel Register    */
+#define CD180_PILR1     0x61    /* Priority Interrupt Level Register 1     */
+#define CD180_PILR2     0x62    /* Priority Interrupt Level Register 2     */
+#define CD180_PILR3     0x63    /* Priority Interrupt Level Register 3     */
+#define CD180_CAR       0x64    /* Channel Access Register                 */
+#define CD180_GFRCR     0x6b    /* Global Firmware Revision Code Register  */
+#define CD180_PPRH      0x70    /* Prescaler Period Register High          */
+#define CD180_PPRL      0x71    /* Prescaler Period Register Low           */
+#define CD180_RDR       0x78    /* Receiver Data Register                  */
+#define CD180_RCSR      0x7a    /* Receiver Character Status Register      */
+#define CD180_TDR       0x7b    /* Transmit Data Register                  */
+#define CD180_EOIR      0x7f    /* End of Interrupt Register               */
+
+
+/* Channel Registers */
+
+#define CD180_CCR       0x01    /* Channel Command Register                */
+#define CD180_IER       0x02    /* Interrupt Enable Register               */
+#define CD180_COR1      0x03    /* Channel Option Register 1               */
+#define CD180_COR2      0x04    /* Channel Option Register 2               */
+#define CD180_COR3      0x05    /* Channel Option Register 3               */
+#define CD180_CCSR      0x06    /* Channel Control Status Register         */
+#define CD180_RDCR      0x07    /* Receive Data Count Register             */
+#define CD180_SCHR1     0x09    /* Special Character Register 1            */
+#define CD180_SCHR2     0x0a    /* Special Character Register 2            */
+#define CD180_SCHR3     0x0b    /* Special Character Register 3            */
+#define CD180_SCHR4     0x0c    /* Special Character Register 4            */
+#define CD180_MCOR1     0x10    /* Modem Change Option 1 Register          */
+#define CD180_MCOR2     0x11    /* Modem Change Option 2 Register          */
+#define CD180_MCR       0x12    /* Modem Change Register                   */
+#define CD180_RTPR      0x18    /* Receive Timeout Period Register         */
+#define CD180_MSVR      0x28    /* Modem Signal Value Register             */
+#define CD180_RBPRH     0x31    /* Receive Baud Rate Period Register High  */
+#define CD180_RBPRL     0x32    /* Receive Baud Rate Period Register Low   */
+#define CD180_TBPRH     0x39    /* Transmit Baud Rate Period Register High */
+#define CD180_TBPRL     0x3a    /* Transmit Baud Rate Period Register Low  */
+
+
+/* Global Interrupt Vector Register (R/W) */
+
+#define GIVR_ITMASK     0x07     /* Interrupt type mask                     */
+#define  GIVR_IT_MODEM   0x01    /* Modem Signal Change Interrupt           */
+#define  GIVR_IT_TX      0x02    /* Transmit Data Interrupt                 */
+#define  GIVR_IT_RCV     0x03    /* Receive Good Data Interrupt             */
+#define  GIVR_IT_REXC    0x07    /* Receive Exception Interrupt             */
+
+
+/* Global Interrupt Channel Register (R/W) */
+ 
+#define GICR_CHAN       0x1c    /* Channel Number Mask                     */
+#define GICR_CHAN_OFF   2       /* Channel Number Offset                   */
+
+
+/* Channel Address Register (R/W) */
+
+#define CAR_CHAN        0x07    /* Channel Number Mask                     */
+#define CAR_A7          0x08    /* A7 Address Extention (unused)           */
+
+
+/* Receive Character Status Register (R/O) */
+
+#define RCSR_TOUT       0x80    /* Rx Timeout                              */
+#define RCSR_SCDET      0x70    /* Special Character Detected Mask         */
+#define  RCSR_NO_SC      0x00   /* No Special Characters Detected          */
+#define  RCSR_SC_1       0x10   /* Special Char 1 (or 1 & 3) Detected      */
+#define  RCSR_SC_2       0x20   /* Special Char 2 (or 2 & 4) Detected      */
+#define  RCSR_SC_3       0x30   /* Special Char 3 Detected                 */
+#define  RCSR_SC_4       0x40   /* Special Char 4 Detected                 */
+#define RCSR_BREAK      0x08    /* Break has been detected                 */
+#define RCSR_PE         0x04    /* Parity Error                            */
+#define RCSR_FE         0x02    /* Frame Error                             */
+#define RCSR_OE         0x01    /* Overrun Error                           */
+
+
+/* Channel Command Register (R/W) (commands in groups can be OR-ed) */
+
+#define CCR_HARDRESET   0x81    /* Reset the chip                          */
+
+#define CCR_SOFTRESET   0x80    /* Soft Channel Reset                      */
+
+#define CCR_CORCHG1     0x42    /* Channel Option Register 1 Changed       */
+#define CCR_CORCHG2     0x44    /* Channel Option Register 2 Changed       */
+#define CCR_CORCHG3     0x48    /* Channel Option Register 3 Changed       */
+
+#define CCR_SSCH1       0x21    /* Send Special Character 1                */
+
+#define CCR_SSCH2       0x22    /* Send Special Character 2                */
+
+#define CCR_SSCH3       0x23    /* Send Special Character 3                */
+
+#define CCR_SSCH4       0x24    /* Send Special Character 4                */
+
+#define CCR_TXEN        0x18    /* Enable Transmitter                      */
+#define CCR_RXEN        0x12    /* Enable Receiver                         */
+
+#define CCR_TXDIS       0x14    /* Disable Transmitter                     */
+#define CCR_RXDIS       0x11    /* Disable Receiver                        */
+
+
+/* Interrupt Enable Register (R/W) */
+
+#define IER_DSR         0x80    /* Enable interrupt on DSR change          */
+#define IER_CD          0x40    /* Enable interrupt on CD change           */
+#define IER_CTS         0x20    /* Enable interrupt on CTS change          */
+#define IER_RXD         0x10    /* Enable interrupt on Receive Data        */
+#define IER_RXSC        0x08    /* Enable interrupt on Receive Spec. Char  */
+#define IER_TXRDY       0x04    /* Enable interrupt on TX FIFO empty       */
+#define IER_TXEMPTY     0x02    /* Enable interrupt on TX completely empty */
+#define IER_RET         0x01    /* Enable interrupt on RX Exc. Timeout     */
+
+
+/* Channel Option Register 1 (R/W) */
+
+#define COR1_ODDP       0x80    /* Odd Parity                              */
+#define COR1_PARMODE    0x60    /* Parity Mode mask                        */
+#define  COR1_NOPAR      0x00   /* No Parity                               */
+#define  COR1_FORCEPAR   0x20   /* Force Parity                            */
+#define  COR1_NORMPAR    0x40   /* Normal Parity                           */
+#define COR1_IGNORE     0x10    /* Ignore Parity on RX                     */
+#define COR1_STOPBITS   0x0c    /* Number of Stop Bits                     */
+#define  COR1_1SB        0x00   /* 1 Stop Bit                              */
+#define  COR1_15SB       0x04   /* 1.5 Stop Bits                           */
+#define  COR1_2SB        0x08   /* 2 Stop Bits                             */
+#define COR1_CHARLEN    0x03    /* Character Length                        */
+#define  COR1_5BITS      0x00   /* 5 bits                                  */
+#define  COR1_6BITS      0x01   /* 6 bits                                  */
+#define  COR1_7BITS      0x02   /* 7 bits                                  */
+#define  COR1_8BITS      0x03   /* 8 bits                                  */
+
+
+/* Channel Option Register 2 (R/W) */
+
+#define COR2_IXM        0x80    /* Implied XON mode                        */
+#define COR2_TXIBE      0x40    /* Enable In-Band (XON/XOFF) Flow Control  */
+#define COR2_ETC        0x20    /* Embedded Tx Commands Enable             */
+#define COR2_LLM        0x10    /* Local Loopback Mode                     */
+#define COR2_RLM        0x08    /* Remote Loopback Mode                    */
+#define COR2_RTSAO      0x04    /* RTS Automatic Output Enable             */
+#define COR2_CTSAE      0x02    /* CTS Automatic Enable                    */
+#define COR2_DSRAE      0x01    /* DSR Automatic Enable                    */
+
+
+/* Channel Option Register 3 (R/W) */
+
+#define COR3_XONCH      0x80    /* XON is a pair of characters (1 & 3)     */
+#define COR3_XOFFCH     0x40    /* XOFF is a pair of characters (2 & 4)    */
+#define COR3_FCT        0x20    /* Flow-Control Transparency Mode          */
+#define COR3_SCDE       0x10    /* Special Character Detection Enable      */
+#define COR3_RXTH       0x0f    /* RX FIFO Threshold value (1-8)           */
+
+
+/* Channel Control Status Register (R/O) */
+
+#define CCSR_RXEN       0x80    /* Receiver Enabled                        */
+#define CCSR_RXFLOFF    0x40    /* Receive Flow Off (XOFF was sent)        */
+#define CCSR_RXFLON     0x20    /* Receive Flow On (XON was sent)          */
+#define CCSR_TXEN       0x08    /* Transmitter Enabled                     */
+#define CCSR_TXFLOFF    0x04    /* Transmit Flow Off (got XOFF)            */
+#define CCSR_TXFLON     0x02    /* Transmit Flow On (got XON)              */
+
+
+/* Modem Change Option Register 1 (R/W) */
+
+#define MCOR1_DSRZD     0x80    /* Detect 0->1 transition of DSR           */
+#define MCOR1_CDZD      0x40    /* Detect 0->1 transition of CD            */
+#define MCOR1_CTSZD     0x20    /* Detect 0->1 transition of CTS           */
+#define MCOR1_DTRTH     0x0f    /* Auto DTR flow control Threshold (1-8)   */
+#define  MCOR1_NODTRFC   0x0     /* Automatic DTR flow control disabled     */
+
+
+/* Modem Change Option Register 2 (R/W) */
+
+#define MCOR2_DSROD     0x80    /* Detect 1->0 transition of DSR           */
+#define MCOR2_CDOD      0x40    /* Detect 1->0 transition of CD            */
+#define MCOR2_CTSOD     0x20    /* Detect 1->0 transition of CTS           */
+
+
+/* Modem Change Register (R/W) */
+
+#define MCR_DSRCHG      0x80    /* DSR Changed                             */
+#define MCR_CDCHG       0x40    /* CD Changed                              */
+#define MCR_CTSCHG      0x20    /* CTS Changed                             */
+
+
+/* Modem Signal Value Register (R/W) */
+
+#define MSVR_DSR        0x80    /* Current state of DSR input              */
+#define MSVR_CD         0x40    /* Current state of CD input               */
+#define MSVR_CTS        0x20    /* Current state of CTS input              */
+#define MSVR_DTR        0x02    /* Current state of DTR output             */
+#define MSVR_RTS        0x01    /* Current state of RTS output             */
+
+
+/* Escape characters */
+
+#define CD180_C_ESC     0x00    /* Escape character                        */
+#define CD180_C_SBRK    0x81    /* Start sending BREAK                     */
+#define CD180_C_DELAY   0x82    /* Delay output                            */
+#define CD180_C_EBRK    0x83    /* Stop sending BREAK                      */
diff -u --recursive --new-file v1.3.93/linux/drivers/char/rtc.c linux/drivers/char/rtc.c
--- v1.3.93/linux/drivers/char/rtc.c	Mon Apr 15 12:20:18 1996
+++ linux/drivers/char/rtc.c	Mon Apr 22 12:12:33 1996
@@ -552,7 +552,6 @@
 	restore_flags(flags);
 
 	p = buf;
-	p += sprintf(p, "Real Time Clock Status:\n");
 
 	get_rtc_time(&tm);
 
@@ -560,9 +559,10 @@
 	 * There is no way to tell if the luser has the RTC set for local
 	 * time or for Universal Standard Time (GMT). Probably local though.
 	 */
-	p += sprintf(p, "\tRTC reports %02d:%02d:%02d of %d-%d-%d.\n",
-		tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_mday, 
-		tm.tm_mon + 1, tm.tm_year + 1900);
+	p += sprintf(p, "date          : %04d-%02d-%02d\n",
+		tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
+	p += sprintf(p, "time          : %02d-%02d-%02d\n",
+		tm.tm_hour, tm.tm_min, tm.tm_sec);
 
 	get_rtc_alm_time(&tm);
 
@@ -571,36 +571,44 @@
 	 * match any value for that particular field. Values that are
 	 * greater than a valid time, but less than 0xc0 shouldn't appear.
 	 */
-	p += sprintf(p, "\tAlarm set to match: ");
+	p += sprintf(p, "alarm         : ");
 	if (tm.tm_hour <= 24)
-		p += sprintf(p, "hour=%d, ", tm.tm_hour);
+		p += sprintf(p, "%02d", tm.tm_hour);
 	else
-		p += sprintf(p, "hour=any, ");
+		p += sprintf(p, "**");
+	p += sprintf(p, "-");
 	if (tm.tm_min <= 59)
-		p += sprintf(p, "min=%d, ", tm.tm_min);
+		p += sprintf(p, "%02d", tm.tm_min);
 	else
-		p += sprintf(p, "min=any, ");
+		p += sprintf(p, "**");
+	p += sprintf(p, "-");
 	if (tm.tm_sec <= 59)
-		p += sprintf(p, "sec=%d.\n", tm.tm_sec);
+		p += sprintf(p, "%02d", tm.tm_sec);
 	else
-		p += sprintf(p, "sec=any.\n");
+		p += sprintf(p, "**");
+	p += sprintf(p, "\n");
 
-	p += sprintf(p, "\tMisc. settings: daylight=%s; BCD=%s; 24hr=%s; Sq-Wave=%s.\n",
-		((ctrl & RTC_DST_EN) ? "yes" : "no" ),
-		((ctrl & RTC_DM_BINARY) ? "no" : "yes" ),
-		((ctrl & RTC_24H) ? "yes" : "no" ),
+	p += sprintf(p, "daylight      : %s\n",
+		((ctrl & RTC_DST_EN) ? "yes" : "no" ));
+	p += sprintf(p, "bcd           : %s\n",
+		((ctrl & RTC_DM_BINARY) ? "no" : "yes" ));
+	p += sprintf(p, "24hr          : %s\n",
+		((ctrl & RTC_24H) ? "yes" : "no" ));
+	p += sprintf(p, "sqwave        : %s\n",
 		((ctrl & RTC_SQWE) ? "yes" : "no" ));
 
-	p += sprintf(p, "\tInterrupt for: alarm=%s; update=%s; periodic=%s.\n",
-		((ctrl & RTC_AIE) ? "yes" : "no" ),
-		((ctrl & RTC_UIE) ? "yes" : "no" ),
+	p += sprintf(p, "alarm_int     : %s\n",
+		((ctrl & RTC_AIE) ? "yes" : "no" ));
+	p += sprintf(p, "update_int    : %s\n",
+		((ctrl & RTC_UIE) ? "yes" : "no" ));
+	p += sprintf(p, "periodic_int  : %s\n",
 		((ctrl & RTC_PIE) ? "yes" : "no" ));
 
-	p += sprintf(p, "\tPeriodic interrupt rate set to %dHz.\n",
+	p += sprintf(p, "periodic_freq : %d\n",
 		(freq ? (65536/(1<<freq)) : 0));
 
-	p += sprintf(p, "\tRTC reports that CMOS battery is %s.\n",
-		(batt ? "okay" : "dead"));
+	p += sprintf(p, "battery_ok    : %s\n",
+		(batt ? "yes" : "no"));
 
 	return  p - buf;
 }
diff -u --recursive --new-file v1.3.93/linux/drivers/char/tty_io.c linux/drivers/char/tty_io.c
--- v1.3.93/linux/drivers/char/tty_io.c	Fri Apr 19 10:07:58 1996
+++ linux/drivers/char/tty_io.c	Mon Apr 22 07:14:01 1996
@@ -1871,6 +1871,9 @@
 #ifdef CONFIG_DIGI
 	pcxe_init();
 #endif
+#ifdef CONFIG_RISCOM8
+	riscom8_init();
+#endif
 	pty_init();
 	vcs_init();
 	return 0;
diff -u --recursive --new-file v1.3.93/linux/drivers/net/a2065.c linux/drivers/net/a2065.c
--- v1.3.93/linux/drivers/net/a2065.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/net/a2065.c	Thu Apr 11 02:14:40 1996
@@ -0,0 +1,798 @@
+/*
+ * Amiga Linux/68k A2065 Ethernet Driver
+ *
+ * (C) Copyright 1995 by Geert Uytterhoeven
+ *                      (Geert.Uytterhoeven@cs.kuleuven.ac.be)
+ *
+ * Fixes and tips by:
+ *	- Janos Farkas (CHEXUM@sparta.banki.hu)
+ *	- Jes Degn Soerensen (jds@kom.auc.dk)
+ *
+ * ----------------------------------------------------------------------------
+ *
+ * This program is based on
+ *
+ *	ariadne.?:	Amiga Linux/68k Ariadne Ethernet Driver
+ *			(C) Copyright 1995 by Geert Uytterhoeven,
+ *                                            Peter De Schrijver
+ *
+ *	lance.c:	An AMD LANCE ethernet driver for linux.
+ *			Written 1993-94 by Donald Becker.
+ *
+ *	Am79C960:	PCnet(tm)-ISA Single-Chip Ethernet Controller
+ *			Advanced Micro Devices
+ *			Publication #16907, Rev. B, Amendment/0, May 1994
+ *
+ * ----------------------------------------------------------------------------
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file README.legal in the main directory of the Linux/68k
+ * distribution for more details.
+ *
+ * ----------------------------------------------------------------------------
+ *
+ * The A2065 is a Zorro-II board made by Commodore/Ameristar. It contains:
+ *
+ *	- an Am7990 Local Area Network Controller for Ethernet (LANCE) with
+ *	  both 10BASE-2 (thin coax) and AUI (DB-15) connectors
+ */
+
+#include <stddef.h>
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/malloc.h>
+#include <linux/interrupt.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include <asm/bootinfo.h>
+#include <asm/amigaints.h>
+#include <asm/amigahw.h>
+#include <asm/zorro.h>
+
+#include "a2065.h"
+
+#ifdef A2065_DEBUG
+int a2065_debug = A2065_DEBUG;
+#else
+int a2065_debug = 1;
+#endif
+
+
+	/*
+	 *		Transmit/Receive Ring Definitions
+	 */
+
+#define LANCE_LOG_TX_BUFFERS	(2)
+#define LANCE_LOG_RX_BUFFERS	(4)
+
+#define TX_RING_SIZE		(1<<LANCE_LOG_TX_BUFFERS)
+#define RX_RING_SIZE		(1<<LANCE_LOG_RX_BUFFERS)
+
+#define TX_RING_MOD_MASK	(TX_RING_SIZE-1)
+#define RX_RING_MOD_MASK	(RX_RING_SIZE-1)
+
+#define PKT_BUF_SIZE		(1520)
+
+
+	/*
+	 *		Private Device Data
+	 */
+
+struct a2065_private {
+	struct A2065Board *board;
+	struct TDRE *tx_ring[TX_RING_SIZE];
+	struct RDRE *rx_ring[RX_RING_SIZE];
+	u_char *tx_buff[TX_RING_SIZE];
+	u_char *rx_buff[RX_RING_SIZE];
+	int cur_tx, cur_rx;		/* The next free ring entry */
+	int dirty_tx;			/* The ring entries to be free()ed. */
+	struct enet_statistics stats;
+	char tx_full;
+	unsigned long lock;
+};
+
+
+	/*
+	 *		Structure Created in the A2065's RAM Buffer
+	 */
+
+struct lancedata {
+	struct InitBlock init;
+	struct TDRE tx_ring[TX_RING_SIZE];
+	struct RDRE rx_ring[RX_RING_SIZE];
+	u_char tx_buff[TX_RING_SIZE][PKT_BUF_SIZE];
+	u_char rx_buff[RX_RING_SIZE][PKT_BUF_SIZE];
+};
+
+
+static int a2065_open(struct device *dev);
+static void a2065_init_ring(struct device *dev);
+static int a2065_start_xmit(struct sk_buff *skb, struct device *dev);
+static int a2065_rx(struct device *dev);
+static void a2065_interrupt(int irq, struct pt_regs *fp, void *data);
+static int a2065_close(struct device *dev);
+static struct enet_statistics *a2065_get_stats(struct device *dev);
+static void set_multicast_list(struct device *dev);
+
+
+int a2065_probe(struct device *dev)
+{
+	int key1, key2;
+	struct ConfigDev *cd;
+	u_long board;
+	u_long sn;
+	struct a2065_private *priv;
+
+	if ((key1 = zorro_find(MANUF_COMMODORE, PROD_A2065, 0, 0)) ||
+	    (key2 = zorro_find(MANUF_AMERISTAR, PROD_AMERISTAR2065, 0, 0))) {
+		cd = zorro_get_board(key1 ? key1 : key2);
+		if ((board = (u_long)cd->cd_BoardAddr)) {
+			sn = cd->cd_Rom.er_SerialNumber;
+			if (key1) {			/* Commodore */
+				dev->dev_addr[0] = 0x00;
+				dev->dev_addr[1] = 0x80;
+				dev->dev_addr[2] = 0x10;
+			} else {			/* Ameristar */
+				dev->dev_addr[0] = 0x00;
+				dev->dev_addr[1] = 0x00;
+				dev->dev_addr[2] = 0x9f;
+			}
+			dev->dev_addr[3] = (sn>>16) & 0xff;
+			dev->dev_addr[4] = (sn>>8) & 0xff;
+			dev->dev_addr[5] = sn & 0xff;
+			printk("%s: A2065 at 0x%08lx, Ethernet Address %02x:%02x:%02x:%02x:%02x:%02x\n",
+			       dev->name, board, dev->dev_addr[0],
+			       dev->dev_addr[1], dev->dev_addr[2],
+			       dev->dev_addr[3], dev->dev_addr[4],
+			       dev->dev_addr[5]);
+
+			init_etherdev(dev, 0);
+
+			dev->priv = kmalloc(sizeof(struct
+						   a2065_private),
+					    GFP_KERNEL);
+			priv = (struct a2065_private *)dev->priv;
+			memset(priv, 0, sizeof(struct a2065_private));
+
+			priv->board = (struct A2065Board *)ZTWO_VADDR(board);
+
+			dev->open = &a2065_open;
+			dev->stop = &a2065_close;
+			dev->hard_start_xmit = &a2065_start_xmit;
+			dev->get_stats = &a2065_get_stats;
+			dev->set_multicast_list = &set_multicast_list;
+
+			zorro_config_board(key1 ? key1 : key2, 0);
+			return(0);
+		}
+	}
+	return(ENODEV);
+}
+
+
+static int a2065_open(struct device *dev)
+{
+	struct a2065_private *priv = (struct a2065_private *)dev->priv;
+	struct A2065Board *board = priv->board;
+	static int interruptinstalled = 0;
+	struct lancedata *lancedata;		/* LANCE point of view */
+	struct lancedata *alancedata;		/* Amiga point of view */
+
+	lancedata = (struct lancedata *)offsetof(struct A2065Board, RAM);
+	alancedata = (struct lancedata *)board->RAM;
+
+	/* Stop the LANCE */
+	board->Lance.RAP = CSR0;		/* LANCE Controller Status */
+	board->Lance.RDP = STOP;
+
+	/* Enable big endian byte ordering */
+	board->Lance.RAP = CSR3;		/* CSR3 */
+	board->Lance.RDP = BSWP;
+
+	/* Set the Init Block Pointer */
+	board->Lance.RAP = CSR1;		/* IADR[15:0] */
+	board->Lance.RDP = (u_long)&lancedata->init;
+	board->Lance.RAP = CSR2;		/* IADR[23:16] */
+	board->Lance.RDP = 0x0000;
+
+	/* Set the Mode */
+	alancedata->init.Mode = 0;
+
+	/* Set the Ethernet Hardware Address */
+	                    /* Physical Address Register */
+	alancedata->init.PADR[0] = dev->dev_addr[1];
+	alancedata->init.PADR[1] = dev->dev_addr[0];
+	alancedata->init.PADR[2] = dev->dev_addr[3];
+	alancedata->init.PADR[3] = dev->dev_addr[2];
+	alancedata->init.PADR[4] = dev->dev_addr[5];
+	alancedata->init.PADR[5] = dev->dev_addr[4];
+
+	/* Set the Multicast Table */
+	                    /* Logical Address Filter, LADRF[31:0] */
+	alancedata->init.LADRF[0] = 0x00000000;
+	                    /* Logical Address Filter, LADRF[63:32] */	
+	alancedata->init.LADRF[1] = 0x00000000;
+
+	/* Set the Receive and Transmit Descriptor Ring Pointers */
+	alancedata->init.RDRA = (u_long)&lancedata->rx_ring;
+	alancedata->init.RLEN = LANCE_LOG_RX_BUFFERS << 13;
+	alancedata->init.TDRA = (u_long)&lancedata->tx_ring;
+	alancedata->init.TLEN = LANCE_LOG_TX_BUFFERS << 13;
+
+	/* Initialise the Rings */
+	a2065_init_ring(dev);
+
+
+	/* Install the Interrupt handler */
+	if (!interruptinstalled) {
+		if (!add_isr(IRQ_AMIGA_PORTS, a2065_interrupt, 0, dev,
+					 "a2065 Ethernet"))
+			return(-EAGAIN);
+		interruptinstalled = 1;
+	}
+
+	/* Make the LANCE read the Init Block */
+	board->Lance.RAP = CSR0;		/* LANCE Controller Status */
+	board->Lance.RDP = INEA|INIT;
+
+	dev->tbusy = 0;
+	dev->interrupt = 0;
+	dev->start = 1;
+
+	return(0);
+}
+
+
+static void a2065_init_ring(struct device *dev)
+{
+	struct a2065_private *priv = (struct a2065_private *)dev->priv;
+	struct A2065Board *board = priv->board;
+	struct lancedata *lancedata;		/* LANCE point of view */
+	struct lancedata *alancedata;		/* Amiga point of view */
+	int i;
+
+	priv->lock = 0, priv->tx_full = 0;
+	priv->cur_rx = priv->cur_tx = 0;
+	priv->dirty_tx = 0;
+
+	lancedata = (struct lancedata *)offsetof(struct A2065Board, RAM);
+	alancedata = (struct lancedata *)board->RAM;
+
+	/* Set up TX Ring */
+	for (i = 0; i < TX_RING_SIZE; i++) {
+		alancedata->tx_ring[i].TMD0 = (u_long)lancedata->tx_buff[i];
+		alancedata->tx_ring[i].TMD1 = TF_STP|TF_ENP;
+		alancedata->tx_ring[i].TMD2 = -PKT_BUF_SIZE;
+		alancedata->tx_ring[i].TMD3 = 0x0000;
+		priv->tx_ring[i] = &alancedata->tx_ring[i];
+		priv->tx_buff[i] = alancedata->tx_buff[i];
+#if 0
+		printk("TX Entry %2d @ 0x%08x (LANCE 0x%08x), Buf @ 0x%08x (LANCE 0x%08x)\n", i,
+		       (int)&alancedata->tx_ring[i],
+		       (int)&lancedata->tx_ring[i],
+		       (int)alancedata->tx_buff[i],
+		       (int)lancedata->tx_buff[i]);
+#endif
+	}
+
+	/* Set up RX Ring */
+	for (i = 0; i < RX_RING_SIZE; i++) {
+		alancedata->rx_ring[i].RMD0 = (u_long)lancedata->rx_buff[i];
+		alancedata->rx_ring[i].RMD1 = RF_OWN;
+		alancedata->rx_ring[i].RMD2 = -PKT_BUF_SIZE;
+		alancedata->rx_ring[i].RMD3 = 0x0000;
+		priv->rx_ring[i] = &alancedata->rx_ring[i];
+		priv->rx_buff[i] = alancedata->rx_buff[i];
+#if 0
+		printk("RX Entry %2d @ 0x%08x (LANCE 0x%08x), Buf @ 0x%08x (LANCE 0x%08x)\n", i,
+		       (int)&alancedata->rx_ring[i],
+		       (int)&lancedata->rx_ring[i],
+		       (int)alancedata->rx_buff[i],
+		       (int)lancedata->rx_buff[i]);
+#endif
+	}
+}
+
+
+static int a2065_close(struct device *dev)
+{
+	struct a2065_private *priv = (struct a2065_private *)dev->priv;
+	struct A2065Board *board = priv->board;
+
+	dev->start = 0;
+	dev->tbusy = 1;
+
+	board->Lance.RAP = CSR0;		/* LANCE Controller Status */
+
+	if (a2065_debug > 1) {
+	  printk("%s: Shutting down ethercard, status was %2.2x.\n",
+		 dev->name, board->Lance.RDP);
+	  printk("%s: %d packets missed\n", dev->name,
+		 priv->stats.rx_missed_errors);
+	}
+
+	/* We stop the LANCE here - it occasionally polls memory if we don't */
+	board->Lance.RDP = STOP;
+
+	return(0);
+}
+
+
+static void a2065_interrupt(int irq, struct pt_regs *fp, void *data)
+{
+	struct device *dev = (struct device *)data;
+	struct a2065_private *priv;
+	struct A2065Board *board;
+	int csr0, boguscnt = 10;
+
+	if (dev == NULL) {
+		printk("a2065_interrupt(): irq for unknown device.\n");
+		return;
+	}
+
+	priv = (struct a2065_private *)dev->priv;
+	board = priv->board;
+
+	board->Lance.RAP = CSR0;	/* LANCE Controller Status */
+
+	if (!(board->Lance.RDP & INTR)) /* Check if any interrrupt has
+					   been generated by the board. */
+		return;
+
+	if (dev->interrupt)
+		printk("%s: Re-entering the interrupt handler.\n", dev->name);
+
+	dev->interrupt = 1;
+
+	while ((csr0 = board->Lance.RDP) & (ERR|RINT|TINT) && --boguscnt >= 0){
+		/* Acknowledge all of the current interrupt sources ASAP. */
+		board->Lance.RDP = csr0 & ~(INEA|TDMD|STOP|STRT|INIT);
+
+#if 0
+		if (a2065_debug > 5) {
+		  printk("%s: interrupt  csr0=%#2.2x new csr=%#2.2x.",
+			 dev->name, csr0, board->Lance.RDP);
+		  printk("[");
+		  if (csr0 & INTR)
+		    printk(" INTR");
+		  if (csr0 & INEA)
+		    printk(" INEA");
+		  if (csr0 & RXON)
+		    printk(" RXON");
+		  if (csr0 & TXON)
+		    printk(" TXON");
+		  if (csr0 & TDMD)
+		    printk(" TDMD");
+		  if (csr0 & STOP)
+		    printk(" STOP");
+		  if (csr0 & STRT)
+		    printk(" STRT");
+		  if (csr0 & INIT)
+		    printk(" INIT");
+		  if (csr0 & ERR)
+		    printk(" ERR");
+		  if (csr0 & BABL)
+		    printk(" BABL");
+		  if (csr0 & CERR)
+		    printk(" CERR");
+		  if (csr0 & MISS)
+		    printk(" MISS");
+		  if (csr0 & MERR)
+		    printk(" MERR");
+		  if (csr0 & RINT)
+		    printk(" RINT");
+		  if (csr0 & TINT)
+		    printk(" TINT");
+		  if (csr0 & IDON)
+		    printk(" IDON");
+		  printk(" ]\n");
+		}
+#endif
+
+		if (csr0 & RINT)			/* Rx interrupt */
+			a2065_rx(dev);
+
+		if (csr0 & TINT) {			/* Tx-done interrupt */
+			int dirty_tx = priv->dirty_tx;
+
+			while (dirty_tx < priv->cur_tx) {
+				int entry = dirty_tx % TX_RING_SIZE;
+				int status =
+				  priv->tx_ring[entry]->TMD1 & 0xff00;
+
+				if (status & TF_OWN)
+					break;	/* It still hasn't been Txed */
+
+				priv->tx_ring[entry]->TMD1 &= 0x00ff;
+
+				if (status & TF_ERR) {
+					/* There was an major error, log it. */
+					int err_status =
+					  priv->tx_ring[entry]->TMD3;
+					priv->stats.tx_errors++;
+					if (err_status & EF_RTRY)
+					  priv->stats.tx_aborted_errors++;
+					if (err_status & EF_LCAR)
+					  priv->stats.tx_carrier_errors++;
+					if (err_status & EF_LCOL)
+					  priv->stats.tx_window_errors++;
+					if (err_status & EF_UFLO) {
+		         /* Ackk!  On FIFO errors the Tx unit is turned off! */
+					  priv->stats.tx_fifo_errors++;
+					  /* Remove this verbosity later! */
+					  printk("%s: Tx FIFO error! Status %4.4x.\n", dev->name, csr0);
+					  /* Restart the chip. */
+					  board->Lance.RDP = STRT;
+					}
+				} else {
+					if (status & (TF_MORE|TF_ONE))
+					  priv->stats.collisions++;
+					priv->stats.tx_packets++;
+				}
+				dirty_tx++;
+			}
+
+#ifndef final_version
+			if (priv->cur_tx - dirty_tx >= TX_RING_SIZE) {
+				printk("out-of-sync dirty pointer, %d vs. %d, full=%d.\n",
+				       dirty_tx, priv->cur_tx, priv->tx_full);
+				dirty_tx += TX_RING_SIZE;
+			}
+#endif
+
+			if (priv->tx_full && dev->tbusy && dirty_tx >
+			    priv->cur_tx - TX_RING_SIZE + 2) {
+				/* The ring is no longer full, clear tbusy. */
+				priv->tx_full = 0;
+				dev->tbusy = 0;
+				mark_bh(NET_BH);
+			}
+
+			priv->dirty_tx = dirty_tx;
+		}
+
+		/* Log misc errors. */
+		if (csr0 & BABL)
+			priv->stats.tx_errors++;       /* Tx babble. */
+		if (csr0 & MISS)
+			priv->stats.rx_errors++;       /* Missed a Rx frame. */
+		if (csr0 & MERR) {
+			printk("%s: Bus master arbitration failure, status %4.4x.\n", dev->name, csr0);
+			/* Restart the chip. */
+			board->Lance.RDP = STRT;
+		}
+	}
+
+	/* Clear any other interrupt, and set interrupt enable. */
+	board->Lance.RAP = CSR0;		/* LANCE Controller Status */
+	board->Lance.RDP = INEA|BABL|CERR|MISS|MERR|IDON;
+
+#if 0
+	if (a2065_debug > 4)
+		printk("%s: exiting interrupt, csr%d=%#4.4x.\n",
+		       dev->name, board->Lance.RAP, board->Lance.RDP);
+#endif
+
+	dev->interrupt = 0;
+	return;
+}
+
+
+static int a2065_start_xmit(struct sk_buff *skb, struct device *dev)
+{
+	struct a2065_private *priv = (struct a2065_private *)dev->priv;
+	struct A2065Board *board = priv->board;
+	int entry;
+
+	/* Transmitter timeout, serious problems. */
+	if (dev->tbusy) {
+		int tickssofar = jiffies - dev->trans_start;
+		if (tickssofar < 20)
+			return(1);
+		board->Lance.RAP = CSR0;	/* LANCE Controller Status */
+		printk("%s: transmit timed out, status %4.4x, resetting.\n", dev->name, board->Lance.RDP);
+		board->Lance.RDP = STOP;
+
+		/* Enable big endian byte ordering */
+		board->Lance.RAP = CSR3;			/* CSR3 */
+		board->Lance.RDP = BSWP;
+
+		priv->stats.tx_errors++;
+#ifndef final_version
+		{
+		  int i;
+		  printk(" Ring data dump: dirty_tx %d cur_tx %d%s cur_rx %d.",
+			 priv->dirty_tx, priv->cur_tx, priv->tx_full ?
+			 " (full)" : "", priv->cur_rx);
+		  for (i = 0 ; i < RX_RING_SIZE; i++)
+		    printk("%s %08x %04x %04x", i & 0x3 ? "" : "\n ",
+			   ((priv->rx_ring[i]->RMD1)<<16) |
+			   priv->rx_ring[i]->RMD0,
+			   -priv->rx_ring[i]->RMD2, priv->rx_ring[i]->RMD3);
+		  for (i = 0 ; i < TX_RING_SIZE; i++)
+		    printk("%s %08x %04x %04x", i & 0x3 ? "" : "\n ",
+			   ((priv->tx_ring[i]->TMD1)<<16) |
+			   priv->tx_ring[i]->TMD0,
+			   -priv->tx_ring[i]->TMD2, priv->tx_ring[i]->TMD3);
+			printk("\n");
+		}
+#endif
+		a2065_init_ring(dev);
+		board->Lance.RDP = INEA|INIT;
+
+		dev->tbusy = 0;
+		dev->trans_start = jiffies;
+
+		return(0);
+	}
+
+	if (skb == NULL) {
+		dev_tint(dev);
+		return(0);
+	}
+
+	if (skb->len <= 0)
+		return(0);
+
+#if 0
+	if (a2065_debug > 3) {
+		board->Lance.RAP = CSR0;	/* LANCE Controller Status */
+		printk("%s: a2065_start_xmit() called, csr0 %4.4x.\n",
+		       dev->name, board->Lance.RDP);
+		board->Lance.RDP = 0x0000;
+	}
+#endif
+
+	/*
+	 * Block a timer-based transmit from overlapping.  This could better be
+	 * done with atomic_swap(1, dev->tbusy), but set_bit() works as well.
+	 */
+	if (set_bit(0, (void*)&dev->tbusy) != 0) {
+		printk("%s: Transmitter access conflict.\n", dev->name);
+		return(1);
+	}
+
+	if (set_bit(0, (void*)&priv->lock) != 0) {
+		if (a2065_debug > 0)
+			printk("%s: tx queue lock!.\n", dev->name);
+		/* don't clear dev->tbusy flag. */
+		return(1);
+	}
+
+	/* Fill in a Tx ring entry */
+
+#if 0
+	printk("TX pkt type 0x%04x from ", ((u_short *)skb->data)[6]);
+	{
+		int i;
+		u_char *ptr = &((u_char *)skb->data)[6];
+		for (i = 0; i < 6; i++)
+			printk("%02x", ptr[i]);
+	}
+	printk(" to ");
+	{
+		int i;
+		u_char *ptr = (u_char *)skb->data;
+		for (i = 0; i < 6; i++)
+			printk("%02x", ptr[i]);
+	}
+	printk(" data 0x%08x len %d\n", (int)skb->data, (int)skb->len);
+#endif
+
+	entry = priv->cur_tx % TX_RING_SIZE;
+
+	priv->tx_ring[entry]->TMD2 = -(ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN);
+	priv->tx_ring[entry]->TMD3 = 0x0000;
+	memcpy(priv->tx_buff[entry], skb->data, skb->len);
+
+#if 0
+	{
+		int i, len;
+
+		len = skb->len > 64 ? 64 : skb->len;
+		for (i = 0; i < len; i += 8) {
+			int j;
+			printk("%02x:", i);
+			for (j = 0; (j < 16) && ((i+j) < len); j++) {
+				if (!(j & 1))
+					printk(" ");
+				printk("%02x", priv->tx_buff[entry][i+j]);
+			}
+			printk("\n");
+		}
+	}
+#endif
+
+	priv->tx_ring[entry]->TMD1 = (priv->tx_ring[entry]->TMD1 &
+				      0x00ff)|TF_OWN|TF_STP|TF_ENP;
+
+	dev_kfree_skb(skb, FREE_WRITE);
+
+	priv->cur_tx++;
+	if ((priv->cur_tx >= TX_RING_SIZE)&&(priv->dirty_tx >= TX_RING_SIZE)){
+
+#if 0
+	  printk("*** Subtracting TX_RING_SIZE from cur_tx (%d) and dirty_tx (%d)\n",
+		 priv->cur_tx, priv->dirty_tx);
+#endif
+
+		priv->cur_tx -= TX_RING_SIZE;
+		priv->dirty_tx -= TX_RING_SIZE;
+	}
+
+	/* Trigger an immediate send poll. */
+	board->Lance.RAP = CSR0;		/* LANCE Controller Status */
+	board->Lance.RDP = INEA|TDMD;
+
+	dev->trans_start = jiffies;
+
+	cli();
+	priv->lock = 0;
+	if ((priv->tx_ring[(entry+1) % TX_RING_SIZE]->TMD1 & 0xff00) == 0)
+		dev->tbusy = 0;
+	else
+		priv->tx_full = 1;
+	sti();
+
+	return(0);
+}
+
+
+static int a2065_rx(struct device *dev)
+{
+	struct a2065_private *priv = (struct a2065_private *)dev->priv;
+	int entry = priv->cur_rx % RX_RING_SIZE;
+	int i;
+
+	/* If we own the next entry, it's a new packet. Send it up. */
+	while (!(priv->rx_ring[entry]->RMD1 & RF_OWN)) {
+		int status = priv->rx_ring[entry]->RMD1 & 0xff00;
+
+		if (status != (RF_STP|RF_ENP)) {      /* There was an error. */
+		  /* There is a tricky error noted by John Murphy,
+		     <murf@perftech.com> to Russ Nelson: Even with full-sized
+		     buffers it's possible for a jabber packet to use two
+		     buffers, with only the last correctly noting the error. */
+			if (status & RF_ENP)
+			  /* Only count a general error at the */
+				priv->stats.rx_errors++; /* end of a packet.*/
+			if (status & RF_FRAM)
+				priv->stats.rx_frame_errors++;
+			if (status & RF_OFLO)
+				priv->stats.rx_over_errors++;
+			if (status & RF_CRC)
+				priv->stats.rx_crc_errors++;
+			if (status & RF_BUFF)
+				priv->stats.rx_fifo_errors++;
+			priv->rx_ring[entry]->RMD1 &= 0x00ff|RF_STP|RF_ENP;
+		} else {
+			/* Malloc up new buffer, compatible with net-3. */
+			short pkt_len = priv->rx_ring[entry]->RMD3;
+			struct sk_buff *skb;
+
+			if(pkt_len<60)
+			{
+				printk("%s: Runt packet!\n",dev->name);
+				priv->stats.rx_errors++;
+			}
+			else
+			{
+				skb = dev_alloc_skb(pkt_len+2);
+				if (skb == NULL) {
+					printk("%s: Memory squeeze, deferring packet.\n", dev->name);
+					for (i = 0; i < RX_RING_SIZE; i++)
+						if (priv->rx_ring[(entry+i) % RX_RING_SIZE]->RMD1 & RF_OWN)
+							break;
+
+					if (i > RX_RING_SIZE-2) {
+						priv->stats.rx_dropped++;
+						priv->rx_ring[entry]->RMD1 |= RF_OWN;
+						priv->cur_rx++;
+					}
+					break;
+				}
+				skb->dev = dev;
+				skb_reserve(skb,2);	/* 16 byte align */
+				skb_put(skb,pkt_len);	/* Make room */
+				eth_copy_and_sum(skb,
+						 priv->rx_buff[entry],
+						 pkt_len,0);
+				skb->protocol=eth_type_trans(skb,dev);
+#if 0
+				printk("RX pkt type 0x%04x from ", 
+				       ((u_short *)skb->data)[6]);
+				{
+				  int i;
+				  u_char *ptr = &((u_char *)skb->data)[6];
+				  for (i = 0; i < 6; i++)
+				    printk("%02x", ptr[i]);
+				}
+				printk(" to ");
+				{
+				  int i;
+				  u_char *ptr = (u_char *)skb->data;
+				  for (i = 0; i < 6; i++)
+				    printk("%02x", ptr[i]);
+				}
+				printk(" data 0x%08x len %d\n",
+				       (int)skb->data, (int)skb->len);
+#endif
+
+				netif_rx(skb);
+				priv->stats.rx_packets++;
+			}
+		}
+		priv->rx_ring[entry]->RMD1 |= RF_OWN;
+		entry = (++priv->cur_rx) % RX_RING_SIZE;
+	}
+
+	priv->cur_rx = priv->cur_rx % RX_RING_SIZE;
+
+	/* We should check that at least two ring entries are free.
+	   If not, we should free one and mark stats->rx_dropped++. */
+
+	return(0);
+}
+
+
+static struct enet_statistics *a2065_get_stats(struct device *dev)
+{
+	struct a2065_private *priv = (struct a2065_private *)dev->priv;
+
+	return(&priv->stats);
+}
+
+
+/* Set or clear the multicast filter for this adaptor.
+ */
+static void set_multicast_list(struct device *dev)
+{
+	struct a2065_private *priv = (struct a2065_private *)dev->priv;
+	struct A2065Board *board = priv->board;
+	struct lancedata *alancedata;	      /* Amiga point of view */
+	alancedata = (struct lancedata *)board->RAM;
+
+	/* We take the simple way out and always enable promiscuous mode. */
+	board->Lance.RAP = CSR0;	      /* LANCE Controller Status */
+	board->Lance.RDP = STOP;	      /* Temporarily stop the lance. */
+
+	/* Enable big endian byte ordering */
+	board->Lance.RAP = CSR3;	      /* CSR3 */
+	board->Lance.RDP = BSWP;
+
+	if (dev->flags&IFF_PROMISC) {
+	  /* Log any net taps. */
+	  printk("%s: Promiscuous mode enabled.\n", dev->name);
+	  alancedata->init.Mode = PROM;	      /* Set promiscuous mode */
+	} else {
+	  short multicast_table[4];
+	  int num_addrs=dev->mc_count;
+	  if(dev->flags&IFF_ALLMULTI)
+		num_addrs=1;
+	  /*
+	   * We don't use the multicast table,
+	   * but rely on upper-layer filtering.
+	   */
+	  memset(multicast_table, (num_addrs == 0) ? 0 : -1,
+		 sizeof(multicast_table));
+	  alancedata->init.LADRF[0] = multicast_table[0]<<16 |
+	    multicast_table[1];
+	  alancedata->init.LADRF[1] = multicast_table[2]<<16 |
+	    multicast_table[3];
+	  alancedata->init.Mode = 0x0000;
+	}
+
+	board->Lance.RAP = CSR0;	        /* LANCE Controller Status */
+	board->Lance.RDP = INEA|STRT|IDON|INIT;	/* Resume normal operation. */
+}
diff -u --recursive --new-file v1.3.93/linux/drivers/net/a2065.h linux/drivers/net/a2065.h
--- v1.3.93/linux/drivers/net/a2065.h	Thu Jan  1 02:00:00 1970
+++ linux/drivers/net/a2065.h	Sun Mar 31 01:00:06 1996
@@ -0,0 +1,195 @@
+/*
+ * Amiga Linux/68k A2065 Ethernet Driver
+ *
+ * (C) Copyright 1995 by Geert Uytterhoeven
+ *			(Geert.Uytterhoeven@cs.kuleuven.ac.be)
+ *
+ * ---------------------------------------------------------------------------
+ *
+ * This program is based on
+ *
+ *	ariadne.?:	Amiga Linux/68k Ariadne Ethernet Driver
+ *			(C) Copyright 1995 by Geert Uytterhoeven,
+ *			Peter De Schrijver
+ *
+ *	lance.c:	An AMD LANCE ethernet driver for linux.
+ *			Written 1993-94 by Donald Becker.
+ *
+ *	Am79C960:	PCnet(tm)-ISA Single-Chip Ethernet Controller
+ *			Advanced Micro Devices
+ *			Publication #16907, Rev. B, Amendment/0, May 1994
+ *
+ * ---------------------------------------------------------------------------
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file README.legal in the main directory of the Linux/68k
+ * distribution for more details.
+ *
+ * ---------------------------------------------------------------------------
+ *
+ * The A2065 is a Zorro-II board made by Commodore/Ameristar. It contains:
+ *
+ *	- an Am7990 Local Area Network Controller for Ethernet (LANCE) with
+ *	  both 10BASE-2 (thin coax) and AUI (DB-15) connectors
+ */
+
+
+/*
+ *		Am7990 Local Area Network Controller for Ethernet (LANCE)
+ */
+
+struct Am7990 {
+	volatile u_short RDP;		/* Register Data Port */
+	volatile u_short RAP;		/* Register Address Port */
+};
+
+
+/*
+ *		Am7990 Control and Status Registers
+ */
+
+#define CSR0		0x0000		/* LANCE Controller Status */
+#define CSR1		0x0001		/* IADR[15:0] */
+#define CSR2		0x0002		/* IADR[23:16] */
+#define CSR3		0x0003		/* Misc */
+
+
+/*
+ *		Bit definitions for CSR0 (LANCE Controller Status)
+ */
+
+#define ERR		0x8000		/* Error */
+#define BABL		0x4000		/* Babble: Transmitted too many bits */
+#define CERR		0x2000		/* No Heartbeat (10BASE-T) */
+#define MISS		0x1000		/* Missed Frame */
+#define MERR		0x0800		/* Memory Error */
+#define RINT		0x0400		/* Receive Interrupt */
+#define TINT		0x0200		/* Transmit Interrupt */
+#define IDON		0x0100		/* Initialization Done */
+#define INTR		0x0080		/* Interrupt Flag */
+#define INEA		0x0040		/* Interrupt Enable */
+#define RXON		0x0020		/* Receive On */
+#define TXON		0x0010		/* Transmit On */
+#define TDMD		0x0008		/* Transmit Demand */
+#define STOP		0x0004		/* Stop */
+#define STRT		0x0002		/* Start */
+#define INIT		0x0001		/* Initialize */
+
+
+/*
+ *		Bit definitions for CSR3
+ */
+
+#define BSWP		0x0004		/* Byte Swap
+					   (on for big endian byte order) */
+#define ACON		0x0002		/* ALE Control
+					   (on for active low ALE) */
+#define BCON		0x0001		/* Byte Control */
+
+
+/*
+ *		Initialization Block
+ */
+
+struct InitBlock {
+	u_short Mode;			/* Mode */
+	u_char PADR[6];			/* Physical Address */
+	u_long LADRF[2];		/* Logical Address Filter */
+	u_short RDRA;			/* Receive Descriptor Ring Address */
+	u_short RLEN;			/* Receive Descriptor Ring Length */
+	u_short TDRA;			/* Transmit Descriptor Ring Address */
+	u_short TLEN;			/* Transmit Descriptor Ring Length */
+};
+
+
+/*
+ *		Mode Flags
+ */
+
+#define PROM		0x8000		/* Promiscuous Mode */
+#define INTL		0x0040		/* Internal Loopback */
+#define DRTY		0x0020		/* Disable Retry */
+#define FCOLL		0x0010		/* Force Collision */
+#define DXMTFCS		0x0008		/* Disable Transmit CRC */
+#define LOOP		0x0004		/* Loopback Enable */
+#define DTX		0x0002		/* Disable Transmitter */
+#define DRX		0x0001		/* Disable Receiver */
+
+
+/*
+ *		Receive Descriptor Ring Entry
+ */
+
+struct RDRE {
+	volatile u_short RMD0;		/* LADR[15:0] */
+	volatile u_short RMD1;		/* HADR[23:16] | Receive Flags */
+	volatile u_short RMD2;		/* Buffer Byte Count
+					   (two's complement) */
+	volatile u_short RMD3;		/* Message Byte Count */
+};
+
+
+/*
+ *		Transmit Descriptor Ring Entry
+ */
+
+struct TDRE {
+	volatile u_short TMD0;		/* LADR[15:0] */
+	volatile u_short TMD1;		/* HADR[23:16] | Transmit Flags */
+	volatile u_short TMD2;		/* Buffer Byte Count
+					   (two's complement) */
+	volatile u_short TMD3;		/* Error Flags */
+};
+
+
+/*
+ *		Receive Flags
+ */
+
+#define RF_OWN		0x8000		/* LANCE owns the descriptor */
+#define RF_ERR		0x4000		/* Error */
+#define RF_FRAM		0x2000		/* Framing Error */
+#define RF_OFLO		0x1000		/* Overflow Error */
+#define RF_CRC		0x0800		/* CRC Error */
+#define RF_BUFF		0x0400		/* Buffer Error */
+#define RF_STP		0x0200		/* Start of Packet */
+#define RF_ENP		0x0100		/* End of Packet */
+
+
+/*
+ *		Transmit Flags
+ */
+
+#define TF_OWN		0x8000		/* LANCE owns the descriptor */
+#define TF_ERR		0x4000		/* Error */
+#define TF_RES		0x2000		/* Reserved,
+					   LANCE writes this with a zero */
+#define TF_MORE		0x1000		/* More than one retry needed */
+#define TF_ONE		0x0800		/* One retry needed */
+#define TF_DEF		0x0400		/* Deferred */
+#define TF_STP		0x0200		/* Start of Packet */
+#define TF_ENP		0x0100		/* End of Packet */
+
+
+/*
+ *		Error Flags
+ */
+
+#define EF_BUFF 	0x8000		/* Buffer Error */
+#define EF_UFLO 	0x4000		/* Underflow Error */
+#define EF_LCOL 	0x1000		/* Late Collision */
+#define EF_LCAR 	0x0800		/* Loss of Carrier */
+#define EF_RTRY 	0x0400		/* Retry Error */
+#define EF_TDR		0x003f		/* Time Domain Reflectometry */
+
+
+/*
+ *		A2065 Expansion Board Structure
+ */
+
+struct A2065Board {
+	u_char Pad1[0x4000];
+	struct Am7990 Lance;
+	u_char Pad2[0x3ffc];
+	volatile u_char RAM[0x8000];
+};
diff -u --recursive --new-file v1.3.93/linux/drivers/net/ariadne.c linux/drivers/net/ariadne.c
--- v1.3.93/linux/drivers/net/ariadne.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/net/ariadne.c	Thu Apr 11 02:15:34 1996
@@ -0,0 +1,836 @@
+/*
+ *  Amiga Linux/m68k Ariadne Ethernet Driver
+ *
+ *  © Copyright 1995 by Geert Uytterhoeven
+ *		       (Geert.Uytterhoeven@cs.kuleuven.ac.be)
+ *			Peter De Schrijver
+ *		       (Peter.DeSchrijver@linux.cc.kuleuven.ac.be)
+ *
+ *  ----------------------------------------------------------------------------------
+ *
+ *  This program is based on
+ *
+ *	lance.c:	An AMD LANCE ethernet driver for linux.
+ *			Written 1993-94 by Donald Becker.
+ *
+ *	Am79C960:	PCnet(tm)-ISA Single-Chip Ethernet Controller
+ *			Advanced Micro Devices
+ *			Publication #16907, Rev. B, Amendment/0, May 1994
+ *
+ *	MC68230:	Parallel Interface/Timer (PI/T)
+ *			Motorola Semiconductors, December, 1983
+ *
+ *  ----------------------------------------------------------------------------------
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License.  See the file README.legal in the main directory of the Linux/m68k
+ *  distribution for more details.
+ *
+ *  ----------------------------------------------------------------------------------
+ *
+ *  The Ariadne is a Zorro-II board made by Village Tronic. It contains:
+ *
+ *	- an Am79C960 PCnet-ISA Single-Chip Ethernet Controller with both
+ *	  10BASE-2 (thin coax) and 10BASE-T (UTP) connectors
+ *
+ *	- an MC68230 Parallel Interface/Timer configured as 2 parallel ports
+ */
+
+#include <stddef.h>
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/malloc.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/interrupt.h>
+#include <linux/skbuff.h>
+
+#include <asm/bitops.h>
+#include <asm/amigaints.h>
+#include <asm/amigahw.h>
+#include <asm/zorro.h>
+#include <asm/bootinfo.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include "ariadne.h"
+
+
+#ifdef ARIADNE_DEBUG
+int ariadne_debug = ARIADNE_DEBUG;
+#else
+int ariadne_debug = 1;
+#endif
+
+
+    /*
+     *	Macros to Fix Endianness problems
+     */
+
+				/* Swap the Bytes in a WORD */
+#define swapw(x)	(((x>>8)&0x00ff)|((x<<8)&0xff00))
+				/* Get the Low BYTE in a WORD */
+#define lowb(x)		(x&0xff)
+				/* Get the Swapped High WORD in a LONG */
+#define swhighw(x)	((((x)>>8)&0xff00)|(((x)>>24)&0x00ff))
+				/* Get the Swapped Low WORD in a LONG */
+#define swloww(x)	((((x)<<8)&0xff00)|(((x)>>8)&0x00ff))
+
+
+    /*
+     *	Transmit/Receive Ring Definitions
+     */
+
+#define TX_RING_SIZE	5
+#define RX_RING_SIZE	16
+
+#define PKT_BUF_SIZE	1520
+
+
+    /*
+     *	Private Device Data
+     */
+
+struct ariadne_private {
+    struct AriadneBoard *board;
+    struct TDRE *tx_ring[TX_RING_SIZE];
+    struct RDRE *rx_ring[RX_RING_SIZE];
+    u_short *tx_buff[TX_RING_SIZE];
+    u_short *rx_buff[RX_RING_SIZE];
+    int cur_tx, cur_rx;			/* The next free ring entry */
+    int dirty_tx;			/* The ring entries to be free()ed. */
+    struct enet_statistics stats;
+    char tx_full;
+    unsigned long lock;
+};
+
+
+    /*
+     *	Structure Created in the Ariadne's RAM Buffer
+     */
+
+struct lancedata {
+    struct TDRE tx_ring[TX_RING_SIZE];
+    struct RDRE rx_ring[RX_RING_SIZE];
+    u_short tx_buff[TX_RING_SIZE][PKT_BUF_SIZE/sizeof(u_short)];
+    u_short rx_buff[RX_RING_SIZE][PKT_BUF_SIZE/sizeof(u_short)];
+};
+
+
+static int ariadne_open(struct device *dev);
+static void ariadne_init_ring(struct device *dev);
+static int ariadne_start_xmit(struct sk_buff *skb, struct device *dev);
+static int ariadne_rx(struct device *dev);
+static void ariadne_interrupt(int irq, struct pt_regs *fp, void *data);
+static int ariadne_close(struct device *dev);
+static struct enet_statistics *ariadne_get_stats(struct device *dev);
+#ifdef HAVE_MULTICAST
+static void set_multicast_list(struct device *dev);
+#endif
+
+
+static void memcpyw(u_short *dest, u_short *src, int len)
+{
+    while (len >= 2) {
+	*(dest++) = *(src++);
+	len -= 2;
+    }
+    if (len == 1)
+	*dest = (*(u_char *)src)<<8;
+}
+
+
+int long ariadne_probe(struct device *dev)
+{
+    int key;
+    struct ConfigDev *cd;
+    u_long board;
+    struct ariadne_private *priv;
+
+    /* Ethernet is part 0, Parallel is part 1 */
+    if ((key = zorro_find(MANUF_VILLAGE_TRONIC, PROD_ARIADNE, 0, 0))) {
+	cd = zorro_get_board(key);
+	if ((board = (u_long)cd->cd_BoardAddr)) {
+	    dev->dev_addr[0] = 0x00;
+	    dev->dev_addr[1] = 0x60;
+	    dev->dev_addr[2] = 0x30;
+	    dev->dev_addr[3] = (cd->cd_Rom.er_SerialNumber>>16)&0xff;
+	    dev->dev_addr[4] = (cd->cd_Rom.er_SerialNumber>>8)&0xff;
+	    dev->dev_addr[5] = cd->cd_Rom.er_SerialNumber&0xff;
+	    printk("%s: Ariadne at 0x%08lx, Ethernet Address "
+		   "%02x:%02x:%02x:%02x:%02x:%02x\n", dev->name, board,
+		   dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
+		   dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
+
+	    init_etherdev(dev, 0);
+
+	    dev->priv = kmalloc(sizeof(struct ariadne_private), GFP_KERNEL);
+	    priv = (struct ariadne_private *)dev->priv;
+	    memset(priv, 0, sizeof(struct ariadne_private));
+
+	    priv->board = (struct AriadneBoard *)ZTWO_VADDR(board);
+
+	    dev->open = &ariadne_open;
+	    dev->stop = &ariadne_close;
+	    dev->hard_start_xmit = &ariadne_start_xmit;
+	    dev->get_stats = &ariadne_get_stats;
+	    dev->set_multicast_list = &set_multicast_list;
+
+	    zorro_config_board(key, 0);
+	    return(0);
+	}
+    }
+    return(ENODEV);
+}
+
+
+static int ariadne_open(struct device *dev)
+{
+    struct ariadne_private *priv = (struct ariadne_private *)dev->priv;
+    struct AriadneBoard *board = priv->board;
+    static int interruptinstalled = 0;
+    struct lancedata *lancedata;
+    u_short in;
+    u_long version;
+
+    /* Reset the LANCE */
+    in = board->Lance.Reset;
+
+    /* Stop the LANCE */
+    board->Lance.RAP = CSR0;	/* PCnet-ISA Controller Status */
+    board->Lance.RDP = STOP;
+
+    /* Check the LANCE version */
+    board->Lance.RAP = CSR88;	/* Chip ID */
+    version = swapw(board->Lance.RDP);
+    board->Lance.RAP = CSR89;	/* Chip ID */
+    version |= swapw(board->Lance.RDP)<<16;
+    if ((version & 0x00000fff) != 0x00000003) {
+	printk("ariadne_open: Couldn't find AMD Ethernet Chip\n");
+	return(-EAGAIN);
+    }
+    if ((version & 0x0ffff000) != 0x00003000) {
+	printk("ariadne_open: Couldn't find Am79C960 (Wrong part number = %ld)\n",
+	       (version & 0x0ffff000)>>12);
+	return(-EAGAIN);
+    }
+#if 0
+    printk("ariadne_open: Am79C960 (PCnet-ISA) Revision %ld\n",
+	   (version & 0xf0000000)>>28);
+#endif
+
+    ariadne_init_ring(dev);
+
+    /* Miscellaneous Stuff */
+    board->Lance.RAP = CSR3;	/* Interrupt Masks and Deferral Control */
+    board->Lance.RDP = 0x0000;
+    board->Lance.RAP = CSR4;	/* Test and Features Control */
+    board->Lance.RDP = DPOLL|APAD_XMT|MFCOM|RCVCCOM|TXSTRTM|JABM;
+
+    /* Set the Multicast Table */
+    board->Lance.RAP = CSR8;	/* Logical Address Filter, LADRF[15:0] */
+    board->Lance.RDP = 0x0000;
+    board->Lance.RAP = CSR9;	/* Logical Address Filter, LADRF[31:16] */
+    board->Lance.RDP = 0x0000;
+    board->Lance.RAP = CSR10;	/* Logical Address Filter, LADRF[47:32] */
+    board->Lance.RDP = 0x0000;
+    board->Lance.RAP = CSR11;	/* Logical Address Filter, LADRF[63:48] */
+    board->Lance.RDP = 0x0000;
+
+    /* Set the Ethernet Hardware Address */
+    board->Lance.RAP = CSR12;	/* Physical Address Register, PADR[15:0] */
+    board->Lance.RDP = ((u_short *)&dev->dev_addr[0])[0];
+    board->Lance.RAP = CSR13;	/* Physical Address Register, PADR[31:16] */
+    board->Lance.RDP = ((u_short *)&dev->dev_addr[0])[1];
+    board->Lance.RAP = CSR14;	/* Physical Address Register, PADR[47:32] */
+    board->Lance.RDP = ((u_short *)&dev->dev_addr[0])[2];
+
+    /* Set the Init Block Mode */
+    board->Lance.RAP = CSR15;	/* Mode Register */
+    board->Lance.RDP = 0x0000;
+
+    lancedata = (struct lancedata *)offsetof(struct AriadneBoard, RAM);
+
+    /* Set the Transmit Descriptor Ring Pointer */
+    board->Lance.RAP = CSR30;	/* Base Address of Transmit Ring */
+    board->Lance.RDP = swloww((u_long)&lancedata->tx_ring);
+    board->Lance.RAP = CSR31;	/* Base Address of transmit Ring */
+    board->Lance.RDP = swhighw((u_long)&lancedata->tx_ring);
+
+    /* Set the Receive Descriptor Ring Pointer */
+    board->Lance.RAP = CSR24;	/* Base Address of Receive Ring */
+    board->Lance.RDP = swloww((u_long)&lancedata->rx_ring);
+    board->Lance.RAP = CSR25;	/* Base Address of Receive Ring */
+    board->Lance.RDP = swhighw((u_long)&lancedata->rx_ring);
+
+    /* Set the Number of RX and TX Ring Entries */
+    board->Lance.RAP = CSR76;	/* Receive Ring Length */
+    board->Lance.RDP = swapw(((u_short)-RX_RING_SIZE));
+    board->Lance.RAP = CSR78;	/* Transmit Ring Length */
+    board->Lance.RDP = swapw(((u_short)-TX_RING_SIZE));
+
+    /* Enable Media Interface Port Auto Select (10BASE-2/10BASE-T) */
+    board->Lance.RAP = ISACSR2;	/* Miscellaneous Configuration */
+    board->Lance.IDP = ASEL;
+
+    /* LED Control */
+    board->Lance.RAP = ISACSR5;	/* LED1 Status */
+    board->Lance.IDP = PSE|XMTE;
+    board->Lance.RAP = ISACSR6;	/* LED2 Status */
+    board->Lance.IDP = PSE|COLE;
+    board->Lance.RAP = ISACSR7;	/* LED3 Status */
+    board->Lance.IDP = PSE|RCVE;
+
+    dev->tbusy = 0;
+    dev->interrupt = 0;
+    dev->start = 1;
+
+    if (!interruptinstalled) {
+	if (!add_isr(IRQ_AMIGA_PORTS, ariadne_interrupt, 0, dev,
+		     "Ariadne Ethernet"))
+	    return(-EAGAIN);
+	interruptinstalled = 1;
+    }
+
+    board->Lance.RAP = CSR0;	/* PCnet-ISA Controller Status */
+    board->Lance.RDP = INEA|STRT;
+
+    return(0);
+}
+
+
+static void ariadne_init_ring(struct device *dev)
+{
+    struct ariadne_private *priv = (struct ariadne_private *)dev->priv;
+    struct AriadneBoard *board = priv->board;
+    struct lancedata *lancedata;	/* LANCE point of view */
+    struct lancedata *alancedata;	/* Amiga point of view */
+    int i;
+
+    priv->lock = 0, priv->tx_full = 0;
+    priv->cur_rx = priv->cur_tx = 0;
+    priv->dirty_tx = 0;
+
+    lancedata = (struct lancedata *)offsetof(struct AriadneBoard, RAM);
+    alancedata = (struct lancedata *)board->RAM;
+
+    /* Set up TX Ring */
+    for (i = 0; i < TX_RING_SIZE; i++) {
+	alancedata->tx_ring[i].TMD0 = swloww((u_long)lancedata->tx_buff[i]);
+	alancedata->tx_ring[i].TMD1 = swhighw((u_long)lancedata->tx_buff[i])|TF_STP|TF_ENP;
+	alancedata->tx_ring[i].TMD2 = swapw((u_short)-PKT_BUF_SIZE);
+	alancedata->tx_ring[i].TMD3 = 0;
+	priv->tx_ring[i] = &alancedata->tx_ring[i];
+	priv->tx_buff[i] = alancedata->tx_buff[i];
+#if 0
+	printk("TX Entry %2d @ 0x%08x (LANCE 0x%08x), Buf @ 0x%08x (LANCE 0x%08x)\n",
+	       i, (int)&alancedata->tx_ring[i], (int)&lancedata->tx_ring[i],
+	       (int)alancedata->tx_buff[i], (int)lancedata->tx_buff[i]);
+#endif
+    }
+
+    /* Set up RX Ring */
+    for (i = 0; i < RX_RING_SIZE; i++) {
+	alancedata->rx_ring[i].RMD0 = swloww((u_long)lancedata->rx_buff[i]);
+	alancedata->rx_ring[i].RMD1 = swhighw((u_long)lancedata->rx_buff[i])|RF_OWN;
+	alancedata->rx_ring[i].RMD2 = swapw((u_short)-PKT_BUF_SIZE);
+	alancedata->rx_ring[i].RMD3 = 0x0000;
+	priv->rx_ring[i] = &alancedata->rx_ring[i];
+	priv->rx_buff[i] = alancedata->rx_buff[i];
+#if 0
+	printk("RX Entry %2d @ 0x%08x (LANCE 0x%08x), Buf @ 0x%08x (LANCE 0x%08x)\n",
+	       i, (int)&alancedata->rx_ring[i], (int)&lancedata->rx_ring[i],
+	       (int)alancedata->rx_buff[i], (int)lancedata->rx_buff[i]);
+#endif
+    }
+}
+
+
+static int ariadne_close(struct device *dev)
+{
+    struct ariadne_private *priv = (struct ariadne_private *)dev->priv;
+    struct AriadneBoard *board = priv->board;
+
+    dev->start = 0;
+    dev->tbusy = 1;
+
+    board->Lance.RAP = CSR112;	/* Missed Frame Count */
+    priv->stats.rx_missed_errors = swapw(board->Lance.RDP);
+    board->Lance.RAP = CSR0;	/* PCnet-ISA Controller Status */
+
+    if (ariadne_debug > 1) {
+	printk("%s: Shutting down ethercard, status was %2.2x.\n", dev->name,
+	       board->Lance.RDP);
+	printk("%s: %d packets missed\n", dev->name,
+	       priv->stats.rx_missed_errors);
+    }
+
+    /* We stop the LANCE here -- it occasionally polls memory if we don't. */
+    board->Lance.RDP = STOP;
+
+    return(0);
+}
+
+
+static void ariadne_interrupt(int irq, struct pt_regs *fp, void *data)
+{
+    struct device *dev = (struct device *)data;
+    struct ariadne_private *priv;
+    struct AriadneBoard *board;
+    int csr0, boguscnt = 10;
+
+    if (dev == NULL) {
+	printk("ariadne_interrupt(): irq for unknown device.\n");
+	return;
+    }
+
+    priv = (struct ariadne_private *)dev->priv;
+    board = priv->board;
+
+    board->Lance.RAP = CSR0;	/* PCnet-ISA Controller Status */
+
+    if (!(board->Lance.RDP & INTR))	/* Check if any interrrupt has been
+	return;				   generated by the board. */
+
+    if (dev->interrupt)
+	printk("%s: Re-entering the interrupt handler.\n", dev->name);
+
+    dev->interrupt = 1;
+
+    while ((csr0 = board->Lance.RDP) & (ERR|RINT|TINT) && --boguscnt >= 0) {
+	/* Acknowledge all of the current interrupt sources ASAP. */
+	board->Lance.RDP = csr0 & ~(INEA|TDMD|STOP|STRT|INIT);
+
+#if 0
+	if (ariadne_debug > 5) {
+	    printk("%s: interrupt  csr0=%#2.2x new csr=%#2.2x.", dev->name,
+		   csr0, board->Lance.RDP);
+	    printk("[");
+	    if (csr0 & INTR)
+		printk(" INTR");
+	    if (csr0 & INEA)
+		printk(" INEA");
+	    if (csr0 & RXON)
+		printk(" RXON");
+	    if (csr0 & TXON)
+		printk(" TXON");
+	    if (csr0 & TDMD)
+		printk(" TDMD");
+	    if (csr0 & STOP)
+		printk(" STOP");
+	    if (csr0 & STRT)
+		printk(" STRT");
+	    if (csr0 & INIT)
+		printk(" INIT");
+	    if (csr0 & ERR)
+		printk(" ERR");
+	    if (csr0 & BABL)
+		printk(" BABL");
+	    if (csr0 & CERR)
+		printk(" CERR");
+	    if (csr0 & MISS)
+		printk(" MISS");
+	    if (csr0 & MERR)
+		printk(" MERR");
+	    if (csr0 & RINT)
+		printk(" RINT");
+	    if (csr0 & TINT)
+		printk(" TINT");
+	    if (csr0 & IDON)
+		printk(" IDON");
+	    printk(" ]\n");
+	}
+#endif
+
+	if (csr0 & RINT)	/* Rx interrupt */
+	    ariadne_rx(dev);
+
+	if (csr0 & TINT) {	/* Tx-done interrupt */
+	    int dirty_tx = priv->dirty_tx;
+
+	    while (dirty_tx < priv->cur_tx) {
+		int entry = dirty_tx % TX_RING_SIZE;
+		int status = lowb(priv->tx_ring[entry]->TMD1);
+
+		if (status & TF_OWN)
+		    break;	/* It still hasn't been Txed */
+
+		priv->tx_ring[entry]->TMD1 &= 0xff00;
+
+		if (status & TF_ERR) {
+		    /* There was an major error, log it. */
+		    int err_status = priv->tx_ring[entry]->TMD3;
+		    priv->stats.tx_errors++;
+		    if (err_status & EF_RTRY)
+			priv->stats.tx_aborted_errors++;
+		    if (err_status & EF_LCAR)
+			priv->stats.tx_carrier_errors++;
+		    if (err_status & EF_LCOL)
+			priv->stats.tx_window_errors++;
+		    if (err_status & EF_UFLO) {
+			/* Ackk!  On FIFO errors the Tx unit is turned off! */
+			priv->stats.tx_fifo_errors++;
+			/* Remove this verbosity later! */
+			printk("%s: Tx FIFO error! Status %4.4x.\n", dev->name,
+			       csr0);
+			/* Restart the chip. */
+			board->Lance.RDP = STRT;
+		    }
+		} else {
+		    if (status & (TF_MORE|TF_ONE))
+			priv->stats.collisions++;
+		    priv->stats.tx_packets++;
+		}
+		dirty_tx++;
+	    }
+
+#ifndef final_version
+	    if (priv->cur_tx - dirty_tx >= TX_RING_SIZE) {
+		printk("out-of-sync dirty pointer, %d vs. %d, full=%d.\n",
+		       dirty_tx, priv->cur_tx, priv->tx_full);
+		dirty_tx += TX_RING_SIZE;
+	    }
+#endif
+
+	    if (priv->tx_full && dev->tbusy &&
+		dirty_tx > priv->cur_tx - TX_RING_SIZE + 2) {
+		/* The ring is no longer full, clear tbusy. */
+		priv->tx_full = 0;
+		dev->tbusy = 0;
+		mark_bh(NET_BH);
+	    }
+
+	    priv->dirty_tx = dirty_tx;
+	}
+
+	/* Log misc errors. */
+	if (csr0 & BABL)
+	    priv->stats.tx_errors++;	/* Tx babble. */
+	if (csr0 & MISS)
+	    priv->stats.rx_errors++;	/* Missed a Rx frame. */
+	if (csr0 & MERR) {
+	    printk("%s: Bus master arbitration failure, status %4.4x.\n",
+		   dev->name, csr0);
+	    /* Restart the chip. */
+	    board->Lance.RDP = STRT;
+	}
+    }
+
+    /* Clear any other interrupt, and set interrupt enable. */
+    board->Lance.RAP = CSR0;	/* PCnet-ISA Controller Status */
+    board->Lance.RDP = INEA|BABL|CERR|MISS|MERR|IDON;
+
+#if 0
+    if (ariadne_debug > 4)
+	printk("%s: exiting interrupt, csr%d=%#4.4x.\n", dev->name,
+	       board->Lance.RAP, board->Lance.RDP);
+#endif
+
+    dev->interrupt = 0;
+    return;
+}
+
+
+static int ariadne_start_xmit(struct sk_buff *skb, struct device *dev)
+{
+    struct ariadne_private *priv = (struct ariadne_private *)dev->priv;
+    struct AriadneBoard *board = priv->board;
+    int entry;
+
+    /* Transmitter timeout, serious problems. */
+    if (dev->tbusy) {
+	int tickssofar = jiffies - dev->trans_start;
+	if (tickssofar < 20)
+	    return(1);
+	board->Lance.RAP = CSR0;	/* PCnet-ISA Controller Status */
+	printk("%s: transmit timed out, status %4.4x, resetting.\n", dev->name,
+	       board->Lance.RDP);
+	board->Lance.RDP = STOP;
+	priv->stats.tx_errors++;
+#ifndef final_version
+	{
+	    int i;
+	    printk(" Ring data dump: dirty_tx %d cur_tx %d%s cur_rx %d.",
+		   priv->dirty_tx, priv->cur_tx, priv->tx_full ? " (full)" : "",
+		   priv->cur_rx);
+	    for (i = 0 ; i < RX_RING_SIZE; i++)
+		printk("%s %08x %04x %04x", i & 0x3 ? "" : "\n ",
+		       (swapw((priv->rx_ring[i]->RMD1))<<16)|swapw(priv->rx_ring[i]->RMD0),
+		       swapw(-priv->rx_ring[i]->RMD2), swapw(priv->rx_ring[i]->RMD3));
+	    for (i = 0 ; i < TX_RING_SIZE; i++)
+		printk("%s %08x %04x %04x", i & 0x3 ? "" : "\n ",
+		       (swapw((priv->tx_ring[i]->TMD1))<<16)|swapw(priv->tx_ring[i]->TMD0),
+		       swapw(-priv->tx_ring[i]->TMD2), priv->tx_ring[i]->TMD3);
+	    printk("\n");
+	}
+#endif
+	ariadne_init_ring(dev);
+	board->Lance.RDP = INEA|STRT;
+
+	dev->tbusy = 0;
+	dev->trans_start = jiffies;
+
+	return(0);
+    }
+
+    if (skb == NULL) {
+	dev_tint(dev);
+	return(0);
+    }
+
+    if (skb->len <= 0)
+	return(0);
+
+#if 0
+    if (ariadne_debug > 3) {
+	board->Lance.RAP = CSR0;	/* PCnet-ISA Controller Status */
+	printk("%s: ariadne_start_xmit() called, csr0 %4.4x.\n", dev->name,
+	       board->Lance.RDP);
+	board->Lance.RDP = 0x0000;
+    }
+#endif
+
+    /* Block a timer-based transmit from overlapping.  This could better be
+	done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
+    if (set_bit(0, (void*)&dev->tbusy) != 0) {
+	printk("%s: Transmitter access conflict.\n", dev->name);
+	return(1);
+    }
+
+    if (set_bit(0, (void*)&priv->lock) != 0) {
+	if (ariadne_debug > 0)
+	    printk("%s: tx queue lock!.\n", dev->name);
+	/* don't clear dev->tbusy flag. */
+	return(1);
+    }
+
+    /* Fill in a Tx ring entry */
+
+#if 0
+    printk("TX pkt type 0x%04x from ", ((u_short *)skb->data)[6]);
+    {
+	int i;
+	u_char *ptr = &((u_char *)skb->data)[6];
+	for (i = 0; i < 6; i++)
+	    printk("%02x", ptr[i]);
+    }
+    printk(" to ");
+    {
+	int i;
+	u_char *ptr = (u_char *)skb->data;
+	for (i = 0; i < 6; i++)
+	    printk("%02x", ptr[i]);
+    }
+    printk(" data 0x%08x len %d\n", (int)skb->data, (int)skb->len);
+#endif
+
+    entry = priv->cur_tx % TX_RING_SIZE;
+
+    /* Caution: the write order is important here, set the base address with
+		the "ownership" bits last. */
+
+    priv->tx_ring[entry]->TMD2 = swapw((u_short)-skb->len);
+    priv->tx_ring[entry]->TMD3 = 0x0000;
+    memcpyw(priv->tx_buff[entry], (u_short *)skb->data, skb->len);
+
+#if 0
+    {
+	int i, len;
+
+	len = skb->len > 64 ? 64 : skb->len;
+	len >>= 1;
+	for (i = 0; i < len; i += 8) {
+	    int j;
+	    printk("%04x:", i);
+	    for (j = 0; (j < 8) && ((i+j) < len); j++) {
+		if (!(j & 1))
+		    printk(" ");
+		printk("%04x", priv->tx_buff[entry][i+j]);
+	    }
+	    printk("\n");
+	}
+    }
+#endif
+
+    priv->tx_ring[entry]->TMD1 = (priv->tx_ring[entry]->TMD1&0xff00)|TF_OWN|TF_STP|TF_ENP;
+
+    dev_kfree_skb(skb, FREE_WRITE);
+
+    priv->cur_tx++;
+    if ((priv->cur_tx >= TX_RING_SIZE) && (priv->dirty_tx >= TX_RING_SIZE)) {
+
+#if 0
+	printk("*** Subtracting TX_RING_SIZE from cur_tx (%d) and dirty_tx (%d)\n",
+	       priv->cur_tx, priv->dirty_tx);
+#endif
+
+	priv->cur_tx -= TX_RING_SIZE;
+	priv->dirty_tx -= TX_RING_SIZE;
+    }
+
+    /* Trigger an immediate send poll. */
+    board->Lance.RAP = CSR0;	/* PCnet-ISA Controller Status */
+    board->Lance.RDP = INEA|TDMD;
+
+    dev->trans_start = jiffies;
+
+    cli();
+    priv->lock = 0;
+    if (lowb(priv->tx_ring[(entry+1) % TX_RING_SIZE]->TMD1) == 0)
+	dev->tbusy = 0;
+    else
+	priv->tx_full = 1;
+    sti();
+
+    return(0);
+}
+
+
+static int ariadne_rx(struct device *dev)
+{
+    struct ariadne_private *priv = (struct ariadne_private *)dev->priv;
+    int entry = priv->cur_rx % RX_RING_SIZE;
+    int i;
+
+    /* If we own the next entry, it's a new packet. Send it up. */
+    while (!(lowb(priv->rx_ring[entry]->RMD1) & RF_OWN)) {
+	int status = lowb(priv->rx_ring[entry]->RMD1);
+
+	if (status != (RF_STP|RF_ENP)) {	/* There was an error. */
+	    /* There is a tricky error noted by John Murphy,
+		<murf@perftech.com> to Russ Nelson: Even with full-sized
+		buffers it's possible for a jabber packet to use two
+		buffers, with only the last correctly noting the error. */
+	    if (status & RF_ENP)
+		/* Only count a general error at the end of a packet.*/
+		priv->stats.rx_errors++;
+	    if (status & RF_FRAM)
+		priv->stats.rx_frame_errors++;
+	    if (status & RF_OFLO)
+		priv->stats.rx_over_errors++;
+	    if (status & RF_CRC)
+		priv->stats.rx_crc_errors++;
+	    if (status & RF_BUFF)
+		priv->stats.rx_fifo_errors++;
+	    priv->rx_ring[entry]->RMD1 &= 0xff00|RF_STP|RF_ENP;
+	} else {
+	    /* Malloc up new buffer, compatible with net-3. */
+	    short pkt_len = swapw(priv->rx_ring[entry]->RMD3);
+	    struct sk_buff *skb;
+
+	    skb = dev_alloc_skb(pkt_len+2);
+	    if (skb == NULL) {
+		printk("%s: Memory squeeze, deferring packet.\n", dev->name);
+		for (i = 0; i < RX_RING_SIZE; i++)
+		    if (lowb(priv->rx_ring[(entry+i) % RX_RING_SIZE]->RMD1) & RF_OWN)
+			break;
+
+		if (i > RX_RING_SIZE-2) {
+		    priv->stats.rx_dropped++;
+		    priv->rx_ring[entry]->RMD1 |= RF_OWN;
+		    priv->cur_rx++;
+		}
+		break;
+	    }
+
+
+	    skb->dev = dev;
+	    skb_reserve(skb,2);		/* 16 byte align */
+	    skb_put(skb,pkt_len);	/* Make room */
+	    eth_copy_and_sum(skb, (char *)priv->rx_buff[entry], pkt_len,0);
+	    skb->protocol=eth_type_trans(skb,dev);
+#if 0
+	    printk("RX pkt type 0x%04x from ", ((u_short *)skb->data)[6]);
+	    {
+		int i;
+		u_char *ptr = &((u_char *)skb->data)[6];
+		for (i = 0; i < 6; i++)
+		    printk("%02x", ptr[i]);
+	    }
+	    printk(" to ");
+	    {
+		int i;
+		u_char *ptr = (u_char *)skb->data;
+		for (i = 0; i < 6; i++)
+		    printk("%02x", ptr[i]);
+	    }
+	    printk(" data 0x%08x len %d\n", (int)skb->data, (int)skb->len);
+#endif
+
+	    netif_rx(skb);
+	    priv->stats.rx_packets++;
+	}
+
+	priv->rx_ring[entry]->RMD1 |= RF_OWN;
+	entry = (++priv->cur_rx) % RX_RING_SIZE;
+    }
+
+    priv->cur_rx = priv->cur_rx % RX_RING_SIZE;
+
+    /* We should check that at least two ring entries are free.	 If not,
+       we should free one and mark stats->rx_dropped++. */
+
+    return(0);
+}
+
+
+static struct enet_statistics *ariadne_get_stats(struct device *dev)
+{
+    struct ariadne_private *priv = (struct ariadne_private *)dev->priv;
+    struct AriadneBoard *board = priv->board;
+    short saved_addr;
+
+    cli();
+    saved_addr = board->Lance.RAP;
+    board->Lance.RAP = CSR112;	/* Missed Frame Count */
+    priv->stats.rx_missed_errors = swapw(board->Lance.RDP);
+    board->Lance.RAP = saved_addr;
+    sti();
+
+    return(&priv->stats);
+}
+
+
+/* Set or clear the multicast filter for this adaptor.
+    num_addrs == -1	Promiscuous mode, receive all packets
+    num_addrs == 0	Normal mode, clear multicast list
+    num_addrs > 0	Multicast mode, receive normal and MC packets, and do
+			best-effort filtering.
+ */
+static void set_multicast_list(struct device *dev)
+{
+    struct ariadne_private *priv = (struct ariadne_private *)dev->priv;
+    struct AriadneBoard *board = priv->board;
+
+    /* We take the simple way out and always enable promiscuous mode. */
+    board->Lance.RAP = CSR0;	/* PCnet-ISA Controller Status */
+    board->Lance.RDP = STOP;	/* Temporarily stop the lance. */
+
+    if (dev->flags & IFF_PROMISC) {
+	/* Log any net taps. */
+	printk("%s: Promiscuous mode enabled.\n", dev->name);
+	board->Lance.RAP = CSR15;	/* Mode Register */
+	board->Lance.RDP = PROM;	/* Set promiscuous mode */
+    } else {
+	short multicast_table[4];
+	int num_addrs = dev->mc_count;
+	int i;
+	/* We don't use the multicast table, but rely on upper-layer filtering. */
+	memset(multicast_table, (num_addrs == 0) ? 0 : -1,
+	       sizeof(multicast_table));
+	for (i = 0; i < 4; i++) {
+	    board->Lance.RAP = CSR8+(i<<8);	/* Logical Address Filter */
+	    board->Lance.RDP = swapw(multicast_table[i]);
+	}
+	board->Lance.RAP = CSR15;	/* Mode Register */
+	board->Lance.RDP = 0x0000;	/* Unset promiscuous mode */
+    }
+
+    board->Lance.RAP = CSR0;		/* PCnet-ISA Controller Status */
+    board->Lance.RDP = INEA|STRT|IDON;	/* Resume normal operation. */
+}
diff -u --recursive --new-file v1.3.93/linux/drivers/net/ariadne.h linux/drivers/net/ariadne.h
--- v1.3.93/linux/drivers/net/ariadne.h	Thu Jan  1 02:00:00 1970
+++ linux/drivers/net/ariadne.h	Tue Apr  9 00:13:56 1996
@@ -0,0 +1,415 @@
+/*
+ *  Amiga Linux/m68k Ariadne Ethernet Driver
+ *
+ *  © Copyright 1995 by Geert Uytterhoeven
+ *		       (Geert.Uytterhoeven@cs.kuleuven.ac.be)
+ *			Peter De Schrijver
+ *		       (Peter.DeSchrijver@linux.cc.kuleuven.ac.be)
+ *
+ *  ----------------------------------------------------------------------------------
+ *
+ *  This program is based on
+ *
+ *	lance.c:	An AMD LANCE ethernet driver for linux.
+ *			Written 1993-94 by Donald Becker.
+ *
+ *	Am79C960:	PCnet(tm)-ISA Single-Chip Ethernet Controller
+ *			Advanced Micro Devices
+ *			Publication #16907, Rev. B, Amendment/0, May 1994
+ *
+ *	MC68230:	Parallel Interface/Timer (PI/T)
+ *			Motorola Semiconductors, December, 1983
+ *
+ *  ----------------------------------------------------------------------------------
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License.  See the file README.legal in the main directory of the Linux/m68k
+ *  distribution for more details.
+ *
+ *  ----------------------------------------------------------------------------------
+ *
+ *  The Ariadne is a Zorro-II board made by Village Tronic. It contains:
+ *
+ *	- an Am79C960 PCnet-ISA Single-Chip Ethernet Controller with both
+ *	  10BASE-2 (thin coax) and 10BASE-T (UTP) connectors
+ *
+ *	- an MC68230 Parallel Interface/Timer configured as 2 parallel ports
+ */
+
+
+    /*
+     *	Am79C960 PCnet-ISA
+     */
+
+struct Am79C960 {
+    volatile u_short AddressPROM[8];
+				/* IEEE Address PROM (Unused in the Ariadne) */
+    volatile u_short RDP;	/* Register Data Port */
+    volatile u_short RAP;	/* Register Address Port */
+    volatile u_short Reset;	/* Reset Chip on Read Access */
+    volatile u_short IDP;	/* ISACSR Data Port */
+};
+
+
+    /*
+     *	Am79C960 Control and Status Registers
+     *
+     *	These values are already swap()ed!!
+     *
+     *	Only registers marked with a `-' are intended for network software
+     *	access
+     */
+
+#define CSR0		0x0000	/* - PCnet-ISA Controller Status */
+#define CSR1		0x0100	/* - IADR[15:0] */
+#define CSR2		0x0200	/* - IADR[23:16] */
+#define CSR3		0x0300	/* - Interrupt Masks and Deferral Control */
+#define CSR4		0x0400	/* - Test and Features Control */
+#define CSR6		0x0600	/*   RCV/XMT Descriptor Table Length */
+#define CSR8		0x0800	/* - Logical Address Filter, LADRF[15:0] */
+#define CSR9		0x0900	/* - Logical Address Filter, LADRF[31:16] */
+#define CSR10		0x0a00	/* - Logical Address Filter, LADRF[47:32] */
+#define CSR11		0x0b00	/* - Logical Address Filter, LADRF[63:48] */
+#define CSR12		0x0c00	/* - Physical Address Register, PADR[15:0] */
+#define CSR13		0x0d00	/* - Physical Address Register, PADR[31:16] */
+#define CSR14		0x0e00	/* - Physical Address Register, PADR[47:32] */
+#define CSR15		0x0f00	/* - Mode Register */
+#define CSR16		0x1000	/*   Initialization Block Address Lower */
+#define CSR17		0x1100	/*   Initialization Block Address Upper */
+#define CSR18		0x1200	/*   Current Receive Buffer Address */
+#define CSR19		0x1300	/*   Current Receive Buffer Address */
+#define CSR20		0x1400	/*   Current Transmit Buffer Address */
+#define CSR21		0x1500	/*   Current Transmit Buffer Address */
+#define CSR22		0x1600	/*   Next Receive Buffer Address */
+#define CSR23		0x1700	/*   Next Receive Buffer Address */
+#define CSR24		0x1800	/* - Base Address of Receive Ring */
+#define CSR25		0x1900	/* - Base Address of Receive Ring */
+#define CSR26		0x1a00	/*   Next Receive Descriptor Address */
+#define CSR27		0x1b00	/*   Next Receive Descriptor Address */
+#define CSR28		0x1c00	/*   Current Receive Descriptor Address */
+#define CSR29		0x1d00	/*   Current Receive Descriptor Address */
+#define CSR30		0x1e00	/* - Base Address of Transmit Ring */
+#define CSR31		0x1f00	/* - Base Address of transmit Ring */
+#define CSR32		0x2000	/*   Next Transmit Descriptor Address */
+#define CSR33		0x2100	/*   Next Transmit Descriptor Address */
+#define CSR34		0x2200	/*   Current Transmit Descriptor Address */
+#define CSR35		0x2300	/*   Current Transmit Descriptor Address */
+#define CSR36		0x2400	/*   Next Next Receive Descriptor Address */
+#define CSR37		0x2500	/*   Next Next Receive Descriptor Address */
+#define CSR38		0x2600	/*   Next Next Transmit Descriptor Address */
+#define CSR39		0x2700	/*   Next Next Transmit Descriptor Address */
+#define CSR40		0x2800	/*   Current Receive Status and Byte Count */
+#define CSR41		0x2900	/*   Current Receive Status and Byte Count */
+#define CSR42		0x2a00	/*   Current Transmit Status and Byte Count */
+#define CSR43		0x2b00	/*   Current Transmit Status and Byte Count */
+#define CSR44		0x2c00	/*   Next Receive Status and Byte Count */
+#define CSR45		0x2d00	/*   Next Receive Status and Byte Count */
+#define CSR46		0x2e00	/*   Poll Time Counter */
+#define CSR47		0x2f00	/*   Polling Interval */
+#define CSR48		0x3000	/*   Temporary Storage */
+#define CSR49		0x3100	/*   Temporary Storage */
+#define CSR50		0x3200	/*   Temporary Storage */
+#define CSR51		0x3300	/*   Temporary Storage */
+#define CSR52		0x3400	/*   Temporary Storage */
+#define CSR53		0x3500	/*   Temporary Storage */
+#define CSR54		0x3600	/*   Temporary Storage */
+#define CSR55		0x3700	/*   Temporary Storage */
+#define CSR56		0x3800	/*   Temporary Storage */
+#define CSR57		0x3900	/*   Temporary Storage */
+#define CSR58		0x3a00	/*   Temporary Storage */
+#define CSR59		0x3b00	/*   Temporary Storage */
+#define CSR60		0x3c00	/*   Previous Transmit Descriptor Address */
+#define CSR61		0x3d00	/*   Previous Transmit Descriptor Address */
+#define CSR62		0x3e00	/*   Previous Transmit Status and Byte Count */
+#define CSR63		0x3f00	/*   Previous Transmit Status and Byte Count */
+#define CSR64		0x4000	/*   Next Transmit Buffer Addres */
+#define CSR65		0x4100	/*   Next Transmit Buffer Addres */
+#define CSR66		0x4200	/*   Next Transmit Status and Byte Count */
+#define CSR67		0x4300	/*   Next Transmit Status and Byte Count */
+#define CSR68		0x4400	/*   Transmit Status Temporary Storage */
+#define CSR69		0x4500	/*   Transmit Status Temporary Storage */
+#define CSR70		0x4600	/*   Temporary Storage */
+#define CSR71		0x4700	/*   Temporary Storage */
+#define CSR72		0x4800	/*   Receive Ring Counter */
+#define CSR74		0x4a00	/*   Transmit Ring Counter */
+#define CSR76		0x4c00	/* - Receive Ring Length */
+#define CSR78		0x4e00	/* - Transmit Ring Length */
+#define CSR80		0x5000	/* - Burst and FIFO Threshold Control */
+#define CSR82		0x5200	/* - Bus Activity Timer */
+#define CSR84		0x5400	/*   DMA Address */
+#define CSR85		0x5500	/*   DMA Address */
+#define CSR86		0x5600	/*   Buffer Byte Counter */
+#define CSR88		0x5800	/* - Chip ID */
+#define CSR89		0x5900	/* - Chip ID */
+#define CSR92		0x5c00	/*   Ring Length Conversion */
+#define CSR94		0x5e00	/*   Transmit Time Domain Reflectometry Count */
+#define CSR96		0x6000	/*   Bus Interface Scratch Register 0 */
+#define CSR97		0x6100	/*   Bus Interface Scratch Register 0 */
+#define CSR98		0x6200	/*   Bus Interface Scratch Register 1 */
+#define CSR99		0x6300	/*   Bus Interface Scratch Register 1 */
+#define CSR104		0x6800	/*   SWAP */
+#define CSR105		0x6900	/*   SWAP */
+#define CSR108		0x6c00	/*   Buffer Management Scratch */
+#define CSR109		0x6d00	/*   Buffer Management Scratch */
+#define CSR112		0x7000	/* - Missed Frame Count */
+#define CSR114		0x7200	/* - Receive Collision Count */
+#define CSR124		0x7c00	/* - Buffer Management Unit Test */
+
+
+    /*
+     *	Am79C960 ISA Control and Status Registers
+     *
+     *	These values are already swap()ed!!
+     */
+
+#define ISACSR0		0x0000	/* Master Mode Read Active */
+#define ISACSR1		0x0100	/* Master Mode Write Active */
+#define ISACSR2		0x0200	/* Miscellaneous Configuration */
+#define ISACSR4		0x0400	/* LED0 Status (Link Integrity) */
+#define ISACSR5		0x0500	/* LED1 Status */
+#define ISACSR6		0x0600	/* LED2 Status */
+#define ISACSR7		0x0700	/* LED3 Status */
+
+
+    /*
+     *	Bit definitions for CSR0 (PCnet-ISA Controller Status)
+     *
+     *	These values are already swap()ed!!
+     */
+
+#define ERR		0x0080	/* Error */
+#define BABL		0x0040	/* Babble: Transmitted too many bits */
+#define CERR		0x0020	/* No Heartbeat (10BASE-T) */
+#define MISS		0x0010	/* Missed Frame */
+#define MERR		0x0008	/* Memory Error */
+#define RINT		0x0004	/* Receive Interrupt */
+#define TINT		0x0002	/* Transmit Interrupt */
+#define IDON		0x0001	/* Initialization Done */
+#define INTR		0x8000	/* Interrupt Flag */
+#define INEA		0x4000	/* Interrupt Enable */
+#define RXON		0x2000	/* Receive On */
+#define TXON		0x1000	/* Transmit On */
+#define TDMD		0x0800	/* Transmit Demand */
+#define STOP		0x0400	/* Stop */
+#define STRT		0x0200	/* Start */
+#define INIT		0x0100	/* Initialize */
+
+
+    /*
+     *	Bit definitions for CSR3 (Interrupt Masks and Deferral Control)
+     *
+     *	These values are already swap()ed!!
+     */
+
+#define BABLM		0x0040	/* Babble Mask */
+#define MISSM		0x0010	/* Missed Frame Mask */
+#define MERRM		0x0008	/* Memory Error Mask */
+#define RINTM		0x0004	/* Receive Interrupt Mask */
+#define TINTM		0x0002	/* Transmit Interrupt Mask */
+#define IDONM		0x0001	/* Initialization Done Mask */
+#define DXMT2PD		0x1000	/* Disable Transmit Two Part Deferral */
+#define EMBA		0x0800	/* Enable Modified Back-off Algorithm */
+
+
+    /*
+     *	Bit definitions for CSR4 (Test and Features Control)
+     *
+     *	These values are already swap()ed!!
+     */
+
+#define ENTST		0x0080	/* Enable Test Mode */
+#define DMAPLUS		0x0040	/* Disable Burst Transaction Counter */
+#define TIMER		0x0020	/* Timer Enable Register */
+#define DPOLL		0x0010	/* Disable Transmit Polling */
+#define APAD_XMT	0x0008	/* Auto Pad Transmit */
+#define ASTRP_RCV	0x0004	/* Auto Pad Stripping */
+#define MFCO		0x0002	/* Missed Frame Counter Overflow Interrupt */
+#define MFCOM		0x0001	/* Missed Frame Counter Overflow Mask */
+#define RCVCCO		0x2000	/* Receive Collision Counter Overflow Interrupt */
+#define RCVCCOM		0x1000	/* Receive Collision Counter Overflow Mask */
+#define TXSTRT		0x0800	/* Transmit Start Status */
+#define TXSTRTM		0x0400	/* Transmit Start Mask */
+#define JAB		0x0200	/* Jabber Error */
+#define JABM		0x0100	/* Jabber Error Mask */
+
+
+    /*
+     *	Bit definitions for CSR15 (Mode Register)
+     *
+     *	These values are already swap()ed!!
+     */
+
+#define PROM		0x0080	/* Promiscuous Mode */
+#define DRCVBC		0x0040	/* Disable Receive Broadcast */
+#define DRCVPA		0x0020	/* Disable Receive Physical Address */
+#define DLNKTST		0x0010	/* Disable Link Status */
+#define DAPC		0x0008	/* Disable Automatic Polarity Correction */
+#define MENDECL		0x0004	/* MENDEC Loopback Mode */
+#define LRTTSEL		0x0002	/* Low Receive Treshold/Transmit Mode Select */
+#define PORTSEL1	0x0001	/* Port Select Bits */
+#define PORTSEL2	0x8000	/* Port Select Bits */
+#define INTL		0x4000	/* Internal Loopback */
+#define DRTY		0x2000	/* Disable Retry */
+#define FCOLL		0x1000	/* Force Collision */
+#define DXMTFCS		0x0800	/* Disable Transmit CRC */
+#define LOOP		0x0400	/* Loopback Enable */
+#define DTX		0x0200	/* Disable Transmitter */
+#define DRX		0x0100	/* Disable Receiver */
+
+
+    /*
+     *	Bit definitions for ISACSR2 (Miscellaneous Configuration)
+     *
+     *	These values are already swap()ed!!
+     */
+
+#define ASEL		0x0200	/* Media Interface Port Auto Select */
+
+
+    /*
+     *	Bit definitions for ISACSR5-7 (LED1-3 Status)
+     *
+     *	These values are already swap()ed!!
+     */
+
+#define LEDOUT		0x0080	/* Current LED Status */
+#define PSE		0x8000	/* Pulse Stretcher Enable */
+#define XMTE		0x1000	/* Enable Transmit Status Signal */
+#define RVPOLE		0x0800	/* Enable Receive Polarity Signal */
+#define RCVE		0x0400	/* Enable Receive Status Signal */
+#define JABE		0x0200	/* Enable Jabber Signal */
+#define COLE		0x0100	/* Enable Collision Signal */
+
+
+    /*
+     *	Receive Descriptor Ring Entry
+     */
+
+struct RDRE {
+    volatile u_short RMD0;	/* LADR[15:0] */
+    volatile u_short RMD1;	/* HADR[23:16] | Receive Flags */
+    volatile u_short RMD2;	/* Buffer Byte Count (two's complement) */
+    volatile u_short RMD3;	/* Message Byte Count */
+};
+
+
+    /*
+     *	Transmit Descriptor Ring Entry
+     */
+
+struct TDRE {
+    volatile u_short TMD0;	/* LADR[15:0] */
+    volatile u_short TMD1;	/* HADR[23:16] | Transmit Flags */
+    volatile u_short TMD2;	/* Buffer Byte Count (two's complement) */
+    volatile u_short TMD3;	/* Error Flags */
+};
+
+
+    /*
+     *	Receive Flags
+     */
+
+#define RF_OWN		0x0080	/* PCnet-ISA controller owns the descriptor */
+#define RF_ERR		0x0040	/* Error */
+#define RF_FRAM		0x0020	/* Framing Error */
+#define RF_OFLO		0x0010	/* Overflow Error */
+#define RF_CRC		0x0008	/* CRC Error */
+#define RF_BUFF		0x0004	/* Buffer Error */
+#define RF_STP		0x0002	/* Start of Packet */
+#define RF_ENP		0x0001	/* End of Packet */
+
+
+    /*
+     *	Transmit Flags
+     */
+
+#define TF_OWN		0x0080	/* PCnet-ISA controller owns the descriptor */
+#define TF_ERR		0x0040	/* Error */
+#define TF_ADD_FCS	0x0020	/* Controls FCS Generation */
+#define TF_MORE		0x0010	/* More than one retry needed */
+#define TF_ONE		0x0008	/* One retry needed */
+#define TF_DEF		0x0004	/* Deferred */
+#define TF_STP		0x0002	/* Start of Packet */
+#define TF_ENP		0x0001	/* End of Packet */
+
+
+    /*
+     *	Error Flags
+     */
+
+#define EF_BUFF		0x0080	/* Buffer Error */
+#define EF_UFLO		0x0040	/* Underflow Error */
+#define EF_LCOL		0x0010	/* Late Collision */
+#define EF_LCAR		0x0008	/* Loss of Carrier */
+#define EF_RTRY		0x0004	/* Retry Error */
+#define EF_TDR		0xff03	/* Time Domain Reflectometry */
+
+
+
+    /*
+     *	MC68230 Parallel Interface/Timer
+     */
+
+struct MC68230 {
+    volatile u_char PGCR;	/* Port General Control Register */
+    u_char Pad1[1];
+    volatile u_char PSRR;	/* Port Service Request Register */
+    u_char Pad2[1];
+    volatile u_char PADDR;	/* Port A Data Direction Register */
+    u_char Pad3[1];
+    volatile u_char PBDDR;	/* Port B Data Direction Register */
+    u_char Pad4[1];
+    volatile u_char PCDDR;	/* Port C Data Direction Register */
+    u_char Pad5[1];
+    volatile u_char PIVR;	/* Port Interrupt Vector Register */
+    u_char Pad6[1];
+    volatile u_char PACR;	/* Port A Control Register */
+    u_char Pad7[1];
+    volatile u_char PBCR;	/* Port B Control Register */
+    u_char Pad8[1];
+    volatile u_char PADR;	/* Port A Data Register */
+    u_char Pad9[1];
+    volatile u_char PBDR;	/* Port B Data Register */
+    u_char Pad10[1];
+    volatile u_char PAAR;	/* Port A Alternate Register */
+    u_char Pad11[1];
+    volatile u_char PBAR;	/* Port B Alternate Register */
+    u_char Pad12[1];
+    volatile u_char PCDR;	/* Port C Data Register */
+    u_char Pad13[1];
+    volatile u_char PSR;	/* Port Status Register */
+    u_char Pad14[5];
+    volatile u_char TCR;	/* Timer Control Register */
+    u_char Pad15[1];
+    volatile u_char TIVR;	/* Timer Interrupt Vector Register */
+    u_char Pad16[3];
+    volatile u_char CPRH;	/* Counter Preload Register (High) */
+    u_char Pad17[1];
+    volatile u_char CPRM;	/* Counter Preload Register (Mid) */
+    u_char Pad18[1];
+    volatile u_char CPRL;	/* Counter Preload Register (Low) */
+    u_char Pad19[3];
+    volatile u_char CNTRH;	/* Count Register (High) */
+    u_char Pad20[1];
+    volatile u_char CNTRM;	/* Count Register (Mid) */
+    u_char Pad21[1];
+    volatile u_char CNTRL;	/* Count Register (Low) */
+    u_char Pad22[1];
+    volatile u_char TSR;	/* Timer Status Register */
+    u_char Pad23[11];
+};
+
+
+    /*
+     *	Ariadne Expansion Board Structure
+     */
+
+struct AriadneBoard {
+    u_char Pad1[0x360];
+    struct Am79C960 Lance;
+    u_char Pad2[0xc88];
+    struct MC68230 PiT;
+    u_char Pad3[0x2fc0];
+    volatile u_short BootPROM[0x2000];	/* I guess it's here :-) */
+    volatile u_short RAM[0x4000];	/* Always access WORDs!! */
+};
diff -u --recursive --new-file v1.3.93/linux/drivers/net/atarilance.c linux/drivers/net/atarilance.c
--- v1.3.93/linux/drivers/net/atarilance.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/net/atarilance.c	Sat Apr 13 14:31:02 1996
@@ -0,0 +1,1194 @@
+/* atarilance.c: Ethernet driver for VME Lance cards on the Atari */
+/*
+	Written 1995/96 by Roman Hodek (Roman.Hodek@informatik.uni-erlangen.de)
+
+	This software may be used and distributed according to the terms
+	of the GNU Public License, incorporated herein by reference.
+
+	This drivers was written with the following sources of reference:
+	 - The driver for the Riebl Lance card by the TU Vienna.
+	 - The modified TUW driver for PAM's VME cards
+	 - The PC-Linux driver for Lance cards (but this is for bus master
+       cards, not the shared memory ones)
+	 - The Amiga Ariadne driver
+
+	v1.0: (in 1.2.13pl4/0.9.13)
+	      Initial version
+	v1.1: (in 1.2.13pl5)
+	      more comments
+		  deleted some debugging stuff
+		  optimized register access (keep AREG pointing to CSR0)
+		  following AMD, CSR0_STRT should be set only after IDON is detected
+		  use memcpy() for data transfers, that also employs long word moves
+		  better probe procedure for 24-bit systems
+          non-VME-RieblCards need extra delays in memcpy
+		  must also do write test, since 0xfxe00000 may hit ROM
+		  use 8/32 tx/rx buffers, which should give better NFS performance;
+		    this is made possible by shifting the last packet buffer after the
+		    RieblCard reserved area
+    v1.2: (in 1.2.13pl8)
+	      again fixed probing for the Falcon; 0xfe01000 hits phys. 0x00010000
+		  and thus RAM, in case of no Lance found all memory contents have to
+		  be restored!
+		  Now possible to compile as module.
+	v1.3: 03/30/96 Jes Sorensen, Roman (in 1.3)
+	      Several little 1.3 adaptions
+		  When the lance is stopped it jumps back into little-endian
+		  mode. It is therefore necessary to put it back where it
+		  belongs, in big endian mode, in order to make things work.
+		  This might be the reason why multicast-mode didn't work
+		  before, but I'm not able to test it as I only got an Amiga
+		  (we had similar problems with the A2065 driver).
+
+*/
+
+static char *version = "atarilance.c: v1.3 04/04/96 "
+					   "Roman.Hodek@informatik.uni-erlangen.de\n";
+
+#include <linux/module.h>
+
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/malloc.h>
+#include <linux/interrupt.h>
+
+#include <asm/irq.h>
+#include <asm/atarihw.h>
+#include <asm/atariints.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/bootinfo.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+/* Debug level:
+ *  0 = silent, print only serious errors
+ *  1 = normal, print error messages
+ *  2 = debug, print debug infos
+ *  3 = debug, print even more debug infos (packet data)
+ */
+
+#define	LANCE_DEBUG	1
+
+#ifdef LANCE_DEBUG
+static int lance_debug = LANCE_DEBUG;
+#else
+static int lance_debug = 1;
+#endif
+
+/* Print debug messages on probing? */
+#undef LANCE_DEBUG_PROBE
+
+#define	DPRINTK(n,a)							\
+	do {										\
+		if (lance_debug >= n)					\
+			printk a;							\
+	} while( 0 )
+
+#ifdef LANCE_DEBUG_PROBE
+# define PROBE_PRINT(a)	printk a
+#else
+# define PROBE_PRINT(a)	
+#endif
+
+/* These define the number of Rx and Tx buffers as log2. (Only powers
+ * of two are valid)
+ * Much more rx buffers (32) are reserved than tx buffers (8), since receiving
+ * is more time critical then sending and packets may have to remain in the
+ * board's memory when main memory is low.
+ */
+
+#define TX_LOG_RING_SIZE			3
+#define RX_LOG_RING_SIZE			5
+
+/* These are the derived values */
+
+#define TX_RING_SIZE			(1 << TX_LOG_RING_SIZE)
+#define TX_RING_LEN_BITS		(TX_LOG_RING_SIZE << 5)
+#define	TX_RING_MOD_MASK		(TX_RING_SIZE - 1)
+
+#define RX_RING_SIZE			(1 << RX_LOG_RING_SIZE)
+#define RX_RING_LEN_BITS		(RX_LOG_RING_SIZE << 5)
+#define	RX_RING_MOD_MASK		(RX_RING_SIZE - 1)
+
+/* The LANCE Rx and Tx ring descriptors. */
+struct lance_rx_head {
+	unsigned short			base;		/* Low word of base addr */
+	volatile unsigned char	flag;
+	unsigned char			base_hi;	/* High word of base addr (unused) */
+	short					buf_length;	/* This length is 2s complement! */
+	volatile short			msg_length;	/* This length is "normal". */
+};
+
+struct lance_tx_head {
+	unsigned short			base;		/* Low word of base addr */
+	volatile unsigned char	flag;
+	unsigned char			base_hi;	/* High word of base addr (unused) */
+	short					length;		/* Length is 2s complement! */
+	volatile short			misc;
+};
+
+struct ringdesc {
+	unsigned short	adr_lo;		/* Low 16 bits of address */
+	unsigned char	len;		/* Length bits */
+	unsigned char	adr_hi;		/* High 8 bits of address (unused) */
+};
+
+/* The LANCE initialization block, described in databook. */
+struct lance_init_block {
+	unsigned short	mode;		/* Pre-set mode */
+	unsigned char	hwaddr[6];	/* Physical ethernet address */
+	unsigned		filter[2];	/* Multicast filter (unused). */
+	/* Receive and transmit ring base, along with length bits. */
+	struct ringdesc	rx_ring;
+	struct ringdesc	tx_ring;
+};
+
+/* The whole layout of the Lance shared memory */
+struct lance_memory {
+	struct lance_init_block	init;
+	struct lance_tx_head	tx_head[TX_RING_SIZE];
+	struct lance_rx_head	rx_head[RX_RING_SIZE];
+	char					packet_area[0];	/* packet data follow after the
+											 * init block and the ring
+											 * descriptors and are located
+											 * at runtime */
+};
+
+/* RieblCard specifics:
+ * The original TOS driver for these cards reserves the area from offset
+ * 0xee70 to 0xeebb for storing configuration data. Of interest to us is the
+ * Ethernet address there, and the magic for verifying the data's validity.
+ * The reserved area isn't touch by packet buffers. Furthermore, offset 0xfffe
+ * is reserved for the interrupt vector number.
+ */
+#define	RIEBL_RSVD_START	0xee70
+#define	RIEBL_RSVD_END		0xeec0
+#define RIEBL_MAGIC			0x09051990
+#define RIEBL_MAGIC_ADDR	((unsigned long *)(((char *)MEM) + 0xee8a))
+#define RIEBL_HWADDR_ADDR	((unsigned char *)(((char *)MEM) + 0xee8e))
+#define RIEBL_IVEC_ADDR		((unsigned short *)(((char *)MEM) + 0xfffe))
+
+/* This is a default address for the old RieblCards without a battery
+ * that have no ethernet address at boot time. 00:00:36:04 is the
+ * prefix for Riebl cards, the 00:00 at the end is arbitrary.
+ */
+
+static unsigned char OldRieblDefHwaddr[6] = {
+	0x00, 0x00, 0x36, 0x04, 0x00, 0x00
+};
+
+
+/* I/O registers of the Lance chip */
+
+struct lance_ioreg {
+/* base+0x0 */	volatile unsigned short	data;
+/* base+0x2 */	volatile unsigned short	addr;
+				unsigned char			_dummy1[3];
+/* base+0x7 */	volatile unsigned char	ivec;
+				unsigned char			_dummy2[5];
+/* base+0xd */	volatile unsigned char	eeprom;
+				unsigned char			_dummy3;
+/* base+0xf */	volatile unsigned char	mem;
+};
+
+/* Types of boards this driver supports */
+
+enum lance_type {
+	OLD_RIEBL,		/* old Riebl card without battery */
+	NEW_RIEBL,		/* new Riebl card with battery */
+	PAM_CARD		/* PAM card with EEPROM */
+};
+
+static char *lance_names[] = {
+	"Riebl-Card (without battery)",
+	"Riebl-Card (with battery)",
+	"PAM intern card"
+};
+
+/* The driver's private device structure */
+
+struct lance_private {
+	enum lance_type		cardtype;
+	struct lance_ioreg	*iobase;
+	struct lance_memory	*mem;
+	int					cur_rx, cur_tx;	/* The next free ring entry */
+	int					dirty_tx;		/* Ring entries to be freeed. */
+						/* copy function */
+	void				*(*memcpy_f)( void *, const void *, size_t );
+	struct enet_statistics stats;
+/* These two must be ints for set_bit() */
+	int					tx_full;
+	int					lock;
+};
+
+/* I/O register access macros */
+
+#define	MEM		lp->mem
+#define	DREG	IO->data
+#define	AREG	IO->addr
+#define	REGA(a)	( AREG = (a), DREG )
+
+/* Definitions for packet buffer access: */
+#define PKT_BUF_SZ		1544
+/* Get the address of a packet buffer corresponding to a given buffer head */
+#define	PKTBUF_ADDR(head)	(((unsigned char *)(MEM)) + (head)->base)
+
+/* Possible memory/IO addresses for probing */
+
+struct lance_addr {
+	unsigned long	memaddr;
+	unsigned long	ioaddr;
+	int				slow_flag;
+} lance_addr_list[] = {
+	{ 0xfe010000, 0xfe00fff0, 0 },	/* RieblCard VME in TT */
+	{ 0xffc10000, 0xffc0fff0, 0 },	/* RieblCard VME in MegaSTE
+									   (highest byte stripped) */
+	{ 0xffe00000, 0xffff7000, 1 },	/* RieblCard in ST
+									   (highest byte stripped) */
+	{ 0xffd00000, 0xffff7000, 1 },	/* RieblCard in ST with hw modif. to
+									   avoid conflict with ROM
+									   (highest byte stripped) */
+	{ 0xffcf0000, 0xffcffff0, 0 },	/* PAMCard VME in TT and MSTE
+									   (highest byte stripped) */
+};
+
+#define	N_LANCE_ADDR	(sizeof(lance_addr_list)/sizeof(*lance_addr_list))
+
+
+/* Definitions for the Lance */
+
+/* tx_head flags */
+#define TMD1_ENP		0x01	/* end of packet */
+#define TMD1_STP		0x02	/* start of packet */
+#define TMD1_DEF		0x04	/* deferred */
+#define TMD1_ONE		0x08	/* one retry needed */
+#define TMD1_MORE		0x10	/* more than one retry needed */
+#define TMD1_ERR		0x40	/* error summary */
+#define TMD1_OWN 		0x80	/* ownership (set: chip owns) */
+
+#define TMD1_OWN_CHIP	TMD1_OWN
+#define TMD1_OWN_HOST	0
+
+/* tx_head misc field */
+#define TMD3_TDR		0x03FF	/* Time Domain Reflectometry counter */
+#define TMD3_RTRY		0x0400	/* failed after 16 retries */
+#define TMD3_LCAR		0x0800	/* carrier lost */
+#define TMD3_LCOL		0x1000	/* late collision */
+#define TMD3_UFLO		0x4000	/* underflow (late memory) */
+#define TMD3_BUFF		0x8000	/* buffering error (no ENP) */
+
+/* rx_head flags */
+#define RMD1_ENP		0x01	/* end of packet */
+#define RMD1_STP		0x02	/* start of packet */
+#define RMD1_BUFF		0x04	/* buffer error */
+#define RMD1_CRC		0x08	/* CRC error */
+#define RMD1_OFLO		0x10	/* overflow */
+#define RMD1_FRAM		0x20	/* framing error */
+#define RMD1_ERR		0x40	/* error summary */
+#define RMD1_OWN 		0x80	/* ownership (set: ship owns) */
+
+#define RMD1_OWN_CHIP	RMD1_OWN
+#define RMD1_OWN_HOST	0
+
+/* register names */
+#define CSR0	0		/* mode/status */
+#define CSR1	1		/* init block addr (low) */
+#define CSR2	2		/* init block addr (high) */
+#define CSR3	3		/* misc */
+#define CSR8	8	  	/* address filter */
+#define CSR15	15		/* promiscous mode */
+
+/* CSR0 */
+/* (R=readable, W=writeable, S=set on write, C=clear on write) */
+#define CSR0_INIT	0x0001		/* initialize (RS) */
+#define CSR0_STRT	0x0002		/* start (RS) */
+#define CSR0_STOP	0x0004		/* stop (RS) */
+#define CSR0_TDMD	0x0008		/* transmit demand (RS) */
+#define CSR0_TXON	0x0010		/* transmitter on (R) */
+#define CSR0_RXON	0x0020		/* receiver on (R) */
+#define CSR0_INEA	0x0040		/* interrupt enable (RW) */
+#define CSR0_INTR	0x0080		/* interrupt active (R) */
+#define CSR0_IDON	0x0100		/* initialization done (RC) */
+#define CSR0_TINT	0x0200		/* transmitter interrupt (RC) */
+#define CSR0_RINT	0x0400		/* receiver interrupt (RC) */
+#define CSR0_MERR	0x0800		/* memory error (RC) */
+#define CSR0_MISS	0x1000		/* missed frame (RC) */
+#define CSR0_CERR	0x2000		/* carrier error (no heartbeat :-) (RC) */
+#define CSR0_BABL	0x4000		/* babble: tx-ed too many bits (RC) */
+#define CSR0_ERR	0x8000		/* error (RC) */
+
+/* CSR3 */
+#define CSR3_BCON	0x0001		/* byte control */
+#define CSR3_ACON	0x0002		/* ALE control */
+#define CSR3_BSWP	0x0004		/* byte swap (1=big endian) */
+
+
+
+/***************************** Prototypes *****************************/
+
+static int addr_accessible( volatile void *regp, int wordflag, int
+                            writeflag );
+static unsigned long lance_probe1( struct device *dev, struct lance_addr
+                                   *init_rec );
+static int lance_open( struct device *dev );
+static void lance_init_ring( struct device *dev );
+static int lance_start_xmit( struct sk_buff *skb, struct device *dev );
+static void lance_interrupt( int irq, struct pt_regs *fp, struct device
+                             *dev );
+static int lance_rx( struct device *dev );
+static int lance_close( struct device *dev );
+static struct enet_statistics *lance_get_stats( struct device *dev );
+static void set_multicast_list( struct device *dev );
+static int lance_set_mac_address( struct device *dev, void *addr );
+
+/************************* End of Prototypes **************************/
+
+
+
+
+
+void *slow_memcpy( void *dst, const void *src, size_t len )
+
+{	char *cto = dst;
+	const char *cfrom = src;
+
+	while( len-- ) {
+		*cto++ = *cfrom++;
+		MFPDELAY();
+	}
+	return( dst );
+}
+
+
+int atarilance_probe( struct device *dev )
+
+{	int i;
+	static int found = 0;
+	
+	if (!MACH_IS_ATARI || found)
+		/* Assume there's only one board possible... That seems true, since
+		 * the Riebl/PAM board's address cannot be changed. */
+		return( ENODEV );
+	
+	for( i = 0; i < N_LANCE_ADDR; ++i ) {
+		if (lance_probe1( dev, &lance_addr_list[i] )) {
+			found = 1;
+			return( 0 );
+		}
+	}
+
+	return( ENODEV );
+}
+
+
+/* Derived from hwreg_present() in atari/config.c: */
+
+static int addr_accessible( volatile void *regp, int wordflag, int writeflag )
+
+{	int		ret;
+	long	flags;
+	long	*vbr, save_berr;
+
+	save_flags(flags);
+	cli();
+
+	__asm__ __volatile__ ( "movec	%/vbr,%0" : "=r" (vbr) : );
+	save_berr = vbr[2];
+	
+	__asm__ __volatile__
+	(	"movel	%/sp,%/d1\n\t"
+		"movel	#Lberr,%2@\n\t"
+		"moveq	#0,%0\n\t"
+		"tstl   %3\n\t"
+		"bne	1f\n\t"
+		"moveb	%1@,%/d0\n\t"
+		"nop	\n\t"
+		"bra	2f\n"
+"1:		 movew	%1@,%/d0\n\t"
+		"nop	\n"
+"2:		 tstl   %4\n\t"
+		"beq	2f\n\t"
+		"tstl	%3\n\t"
+		"bne	1f\n\t"
+		"clrb	%1@\n\t"
+		"nop	\n\t"
+		"moveb	%/d0,%1@\n\t"
+		"nop	\n\t"
+		"bra	2f\n"
+"1:		 clrw	%1@\n\t"
+		"nop	\n\t"
+		"movew	%/d0,%1@\n\t"
+		"nop	\n"
+"2:		 moveq	#1,%0\n"
+"Lberr:	 movel	%/d1,%/sp"
+		: "=&d" (ret)
+		: "a" (regp), "a" (&vbr[2]), "rm" (wordflag), "rm" (writeflag)
+		: "d0", "d1", "memory"
+	);
+
+	vbr[2] = save_berr;
+	restore_flags(flags);
+	
+	return( ret );
+}
+
+
+static unsigned long lance_probe1( struct device *dev,
+								   struct lance_addr *init_rec )
+
+{	volatile unsigned short *memaddr =
+		(volatile unsigned short *)init_rec->memaddr;
+	volatile unsigned short *ioaddr =
+		(volatile unsigned short *)init_rec->ioaddr;
+	struct lance_private	*lp;
+	struct lance_ioreg		*IO;
+	int 					i;
+	static int 				did_version = 0;
+	unsigned short			save1, save2;
+	
+	PROBE_PRINT(( "Probing for Lance card at mem %#lx io %#lx\n",
+				  (long)memaddr, (long)ioaddr ));
+
+	/* Test whether memory readable and writable */
+	PROBE_PRINT(( "lance_probe1: testing memory to be accessible\n" ));
+	if (!addr_accessible( memaddr, 1, 1 )) goto probe_fail;
+
+	/* Written values should come back... */
+	PROBE_PRINT(( "lance_probe1: testing memory to be writable (1)\n" ));
+	save1 = *memaddr;
+	*memaddr = 0x0001;
+	if (*memaddr != 0x0001) goto probe_fail;
+	PROBE_PRINT(( "lance_probe1: testing memory to be writable (2)\n" ));
+	*memaddr = 0x0000;
+	if (*memaddr != 0x0000) goto probe_fail;
+	*memaddr = save1;
+	
+	/* First port should be readable and writable */
+	PROBE_PRINT(( "lance_probe1: testing ioport to be accessible\n" ));
+	if (!addr_accessible( ioaddr, 1, 1 )) goto probe_fail;
+
+	/* and written values should be readable */
+	PROBE_PRINT(( "lance_probe1: testing ioport to be writeable\n" ));
+	save2 = ioaddr[1];
+	ioaddr[1] = 0x0001;
+	if (ioaddr[1] != 0x0001) goto probe_fail;
+
+	/* The CSR0_INIT bit should not be readable */
+	PROBE_PRINT(( "lance_probe1: testing CSR0 register function (1)\n" ));
+	save1 = ioaddr[0];
+	ioaddr[1] = CSR0;
+	ioaddr[0] = CSR0_INIT | CSR0_STOP;
+	if (ioaddr[0] != CSR0_STOP) {
+		ioaddr[0] = save1;
+		ioaddr[1] = save2;
+		goto probe_fail;
+	}
+	PROBE_PRINT(( "lance_probe1: testing CSR0 register function (2)\n" ));
+	ioaddr[0] = CSR0_STOP;
+	if (ioaddr[0] != CSR0_STOP) {
+		ioaddr[0] = save1;
+		ioaddr[1] = save2;
+		goto probe_fail;
+	}
+
+	/* Now ok... */
+	PROBE_PRINT(( "lance_probe1: Lance card detected\n" ));
+	goto probe_ok;
+
+  probe_fail:
+	return( 0 );
+	
+  probe_ok:
+	init_etherdev( dev, sizeof(struct lance_private) );
+	if (!dev->priv)
+		dev->priv = kmalloc( sizeof(struct lance_private), GFP_KERNEL );
+	lp = (struct lance_private *)dev->priv;
+	MEM = (struct lance_memory *)memaddr;
+	IO = lp->iobase = (struct lance_ioreg *)ioaddr;
+	dev->base_addr = (unsigned long)ioaddr; /* informational only */
+	lp->memcpy_f = init_rec->slow_flag ? slow_memcpy : memcpy;
+	
+	REGA( CSR0 ) = CSR0_STOP;
+
+	/* Now test for type: If the eeprom I/O port is readable, it is a
+	 * PAM card */
+	if (addr_accessible( &(IO->eeprom), 0, 0 )) {
+		/* Switch back to Ram */
+		i = IO->mem;
+		lp->cardtype = PAM_CARD;
+	}
+	else if (*RIEBL_MAGIC_ADDR == RIEBL_MAGIC) {
+		lp->cardtype = NEW_RIEBL;
+	}
+	else
+		lp->cardtype = OLD_RIEBL;
+		
+	if (lp->cardtype == PAM_CARD ||
+		memaddr == (unsigned short *)0xffe00000) {
+		/* PAMs card and Riebl on ST use level 5 autovector */
+		add_isr( IRQ_AUTO_5, (isrfunc)lance_interrupt, IRQ_TYPE_PRIO, dev,
+				 "PAM/Riebl-ST Ethernet" );
+		dev->irq = (unsigned short)IRQ_AUTO_5;
+	}
+	else {
+		/* For VME-RieblCards, request a free VME int;
+		 * (This must be unsigned long, since dev->irq is short and the
+		 * IRQ_MACHSPEC bit would be cut off...)
+		 */
+		unsigned long irq = atari_register_vme_int();
+		if (!irq) {
+			printk( "Lance: request for VME interrupt failed\n" );
+			return( 0 );
+		}
+		add_isr( irq, (isrfunc)lance_interrupt, IRQ_TYPE_PRIO, dev,
+				 "Riebl-VME Ethernet" );
+		dev->irq = irq;
+	}
+
+	printk("%s: %s at io %#lx, mem %#lx, irq %d%s, hwaddr ",
+		   dev->name, lance_names[lp->cardtype],
+		   (unsigned long)ioaddr,
+		   (unsigned long)memaddr,
+		   dev->irq,
+		   init_rec->slow_flag ? " (slow memcpy)" : "" );
+
+	/* Get the ethernet address */
+	switch( lp->cardtype ) {
+	  case OLD_RIEBL:
+		/* No ethernet address! (Set some default address) */
+		memcpy( dev->dev_addr, OldRieblDefHwaddr, 6 );
+		break;
+	  case NEW_RIEBL:
+		lp->memcpy_f( dev->dev_addr, RIEBL_HWADDR_ADDR, 6 );
+		break;
+	  case PAM_CARD:
+		i = IO->eeprom;
+		for( i = 0; i < 6; ++i )
+			dev->dev_addr[i] = 
+				((((unsigned short *)MEM)[i*2] & 0x0f) << 4) |
+				((((unsigned short *)MEM)[i*2+1] & 0x0f));
+		i = IO->mem;
+		break;
+	}
+	for( i = 0; i < 6; ++i )
+		printk( "%02x%s", dev->dev_addr[i], (i < 5) ? ":" : "\n" );
+	if (lp->cardtype == OLD_RIEBL) {
+		printk( "%s: Warning: This is a default ethernet address!\n",
+				dev->name );
+		printk( "      Use \"ifconfig hw ether ...\" to set the address.\n" );
+	}
+	
+	MEM->init.mode = 0x0000;		/* Disable Rx and Tx. */
+	for( i = 0; i < 6; i++ )
+		MEM->init.hwaddr[i] = dev->dev_addr[i^1]; /* <- 16 bit swap! */
+	MEM->init.filter[0] = 0x00000000;
+	MEM->init.filter[1] = 0x00000000;
+	MEM->init.rx_ring.adr_lo = offsetof( struct lance_memory, rx_head );
+	MEM->init.rx_ring.adr_hi = 0;
+	MEM->init.rx_ring.len    = RX_RING_LEN_BITS;
+	MEM->init.tx_ring.adr_lo = offsetof( struct lance_memory, tx_head );
+	MEM->init.tx_ring.adr_hi = 0;
+	MEM->init.tx_ring.len    = TX_RING_LEN_BITS;
+
+	if (lp->cardtype == PAM_CARD)
+		IO->ivec = IRQ_SOURCE_TO_VECTOR(dev->irq);
+	else
+		*RIEBL_IVEC_ADDR = IRQ_SOURCE_TO_VECTOR(dev->irq);
+	
+	if (did_version++ == 0)
+		DPRINTK( 1, ( version ));
+
+	/* The LANCE-specific entries in the device structure. */
+	dev->open = &lance_open;
+	dev->hard_start_xmit = &lance_start_xmit;
+	dev->stop = &lance_close;
+	dev->get_stats = &lance_get_stats;
+	dev->set_multicast_list = &set_multicast_list;
+	dev->set_mac_address = &lance_set_mac_address;
+	dev->start = 0;
+
+	memset( &lp->stats, 0, sizeof(lp->stats) );
+	
+	return( 1 );
+}
+
+
+static int lance_open( struct device *dev )
+
+{	struct lance_private *lp = (struct lance_private *)dev->priv;
+	struct lance_ioreg	 *IO = lp->iobase;
+	int i;
+
+	DPRINTK( 2, ( "%s: lance_open()\n", dev->name ));
+
+	lance_init_ring(dev);
+	/* Re-initialize the LANCE, and start it when done. */
+
+	REGA( CSR3 ) = CSR3_BSWP | (lp->cardtype == PAM_CARD ? CSR3_ACON : 0); 
+	REGA( CSR2 ) = 0;
+	REGA( CSR1 ) = 0;
+	REGA( CSR0 ) = CSR0_INIT;
+	/* From now on, AREG is kept to point to CSR0 */
+	
+	i = 1000000;
+	while (--i > 0)
+		if (DREG & CSR0_IDON)
+			break;
+	if (i < 0 || (DREG & CSR0_ERR)) {
+		DPRINTK( 2, ( "lance_open(): opening %s failed, i=%d, csr0=%04x\n",
+					  dev->name, i, DREG ));
+		DREG = CSR0_STOP;
+		return( -EIO );
+	}
+	DREG = CSR0_IDON;
+	DREG = CSR0_STRT;
+	DREG = CSR0_INEA;
+
+	dev->tbusy = 0;
+	dev->interrupt = 0;
+	dev->start = 1;
+
+	DPRINTK( 2, ( "%s: LANCE is open, csr0 %04x\n", dev->name, DREG ));
+	MOD_INC_USE_COUNT;
+
+	return( 0 );
+}
+
+
+/* Initialize the LANCE Rx and Tx rings. */
+
+static void lance_init_ring( struct device *dev )
+
+{	struct lance_private *lp = (struct lance_private *)dev->priv;
+	int i;
+	unsigned offset;
+	
+	lp->lock = 0;
+	lp->tx_full = 0;
+	lp->cur_rx = lp->cur_tx = 0;
+	lp->dirty_tx = 0;
+
+	offset = offsetof( struct lance_memory, packet_area );
+
+/* If the packet buffer at offset 'o' would conflict with the reserved area
+ * of RieblCards, advance it */
+#define	CHECK_OFFSET(o)														 \
+	do {																	 \
+		if (lp->cardtype == OLD_RIEBL || lp->cardtype == NEW_RIEBL) {		 \
+			if (((o) < RIEBL_RSVD_START) ? (o)+PKT_BUF_SZ > RIEBL_RSVD_START \
+										 : (o) < RIEBL_RSVD_END)			 \
+				(o) = RIEBL_RSVD_END;										 \
+		}																	 \
+	} while(0)
+
+	for( i = 0; i < TX_RING_SIZE; i++ ) {
+		CHECK_OFFSET(offset);
+		MEM->tx_head[i].base = offset;
+		MEM->tx_head[i].flag = TMD1_OWN_HOST;
+ 		MEM->tx_head[i].base_hi = 0;
+		MEM->tx_head[i].length = 0;
+		MEM->tx_head[i].misc = 0;
+		offset += PKT_BUF_SZ;
+	}
+
+	for( i = 0; i < RX_RING_SIZE; i++ ) {
+		CHECK_OFFSET(offset);
+		MEM->rx_head[i].base = offset;
+		MEM->rx_head[i].flag = TMD1_OWN_CHIP;
+		MEM->rx_head[i].base_hi = 0;
+		MEM->rx_head[i].buf_length = -PKT_BUF_SZ;
+		MEM->rx_head[i].msg_length = 0;
+		offset += PKT_BUF_SZ;
+	}
+}
+
+
+static int lance_start_xmit( struct sk_buff *skb, struct device *dev )
+
+{	struct lance_private *lp = (struct lance_private *)dev->priv;
+	struct lance_ioreg	 *IO = lp->iobase;
+	int entry, len;
+	struct lance_tx_head *head;
+	unsigned long flags;
+	
+	/* Transmitter timeout, serious problems. */
+	if (dev->tbusy) {
+		int tickssofar = jiffies - dev->trans_start;
+		if (tickssofar < 20)
+			return( 1 );
+		AREG = CSR0;
+		DPRINTK( 1, ( "%s: transmit timed out, status %04x, resetting.\n",
+					  dev->name, DREG ));
+		DREG = CSR0_STOP;
+		/*
+		 * Always set BSWP after a STOP as STOP puts it back into
+		 * little endian mode.
+		 */
+		REGA( CSR3 ) = CSR3_BSWP | (lp->cardtype == PAM_CARD ? CSR3_ACON : 0); 
+		lp->stats.tx_errors++;
+#ifndef final_version
+		{	int i;
+			DPRINTK( 2, ( "Ring data: dirty_tx %d cur_tx %d%s cur_rx %d\n",
+						  lp->dirty_tx, lp->cur_tx,
+						  lp->tx_full ? " (full)" : "",
+						  lp->cur_rx ));
+			for( i = 0 ; i < RX_RING_SIZE; i++ )
+				DPRINTK( 2, ( "rx #%d: base=%04x blen=%04x mlen=%04x\n",
+							  i, MEM->rx_head[i].base,
+							  -MEM->rx_head[i].buf_length,
+							  MEM->rx_head[i].msg_length ));
+			for( i = 0 ; i < TX_RING_SIZE; i++ )
+				DPRINTK( 2, ( "tx #%d: base=%04x len=%04x misc=%04x\n",
+							  i, MEM->tx_head[i].base,
+							  -MEM->tx_head[i].length,
+							  MEM->tx_head[i].misc ));
+		}
+#endif
+		lance_init_ring(dev);
+		REGA( CSR0 ) = CSR0_INEA | CSR0_INIT | CSR0_STRT;
+
+		dev->tbusy = 0;
+		dev->trans_start = jiffies;
+
+		return( 0 );
+	}
+
+	if (skb == NULL) {
+		dev_tint( dev );
+		return( 0 );
+	}
+
+	if (skb->len <= 0)
+		return( 0 );
+
+	DPRINTK( 2, ( "%s: lance_start_xmit() called, csr0 %4.4x.\n",
+				  dev->name, DREG ));
+
+	/* Block a timer-based transmit from overlapping.  This could better be
+	   done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
+	if (set_bit( 0, (void*)&dev->tbusy ) != 0) {
+		DPRINTK( 0, ( "%s: Transmitter access conflict.\n", dev->name ));
+		return 1;
+	}
+
+	if (set_bit( 0, (void*)&lp->lock ) != 0) {
+		DPRINTK( 0, ( "%s: tx queue lock!.\n", dev->name ));
+		/* don't clear dev->tbusy flag. */
+		return 1;
+	}
+
+	/* Fill in a Tx ring entry */
+	if (lance_debug >= 3) {
+		u_char *p;
+		int i;
+		printk( "%s: TX pkt type 0x%04x from ", dev->name,
+				((u_short *)skb->data)[6]);
+		for( p = &((u_char *)skb->data)[6], i = 0; i < 6; i++ )
+			printk("%02x%s", *p++, i != 5 ? ":" : "" );
+		printk(" to ");
+		for( p = (u_char *)skb->data, i = 0; i < 6; i++ )
+			printk("%02x%s", *p++, i != 5 ? ":" : "" );
+		printk(" data at 0x%08x len %d\n", (int)skb->data,
+			   (int)skb->len );
+	}
+
+	/* We're not prepared for the int until the last flags are set/reset. And
+	 * the int may happen already after setting the OWN_CHIP... */
+	save_flags(flags);
+	cli();
+
+	/* Mask to ring buffer boundary. */
+	entry = lp->cur_tx & TX_RING_MOD_MASK;
+	head  = &(MEM->tx_head[entry]);
+	
+	/* Caution: the write order is important here, set the "ownership" bits
+	 * last.
+	 */
+
+	/* The old LANCE chips doesn't automatically pad buffers to min. size. */
+	len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN;
+	/* PAM-Card has a bug: Can only send packets with even number of bytes! */
+	if (lp->cardtype == PAM_CARD && (len & 1))
+		++len;
+
+	head->length = -len;
+	head->misc = 0;
+	lp->memcpy_f( PKTBUF_ADDR(head), (void *)skb->data, skb->len );
+	head->flag = TMD1_OWN_CHIP | TMD1_ENP | TMD1_STP;
+	dev_kfree_skb( skb, FREE_WRITE );
+	lp->cur_tx++;
+	while( lp->cur_tx >= TX_RING_SIZE && lp->dirty_tx >= TX_RING_SIZE ) {
+		lp->cur_tx -= TX_RING_SIZE;
+		lp->dirty_tx -= TX_RING_SIZE;
+	}
+
+	/* Trigger an immediate send poll. */
+	DREG = CSR0_INEA | CSR0_TDMD;
+	dev->trans_start = jiffies;
+
+	lp->lock = 0;
+	if ((MEM->tx_head[(entry+1) & TX_RING_MOD_MASK].flag & TMD1_OWN) ==
+		TMD1_OWN_HOST)
+		dev->tbusy = 0;
+	else
+		lp->tx_full = 1;
+	restore_flags(flags);
+
+	return 0;
+}
+
+/* The LANCE interrupt handler. */
+
+static void lance_interrupt( int irq, struct pt_regs *fp, struct device *dev )
+
+{	struct lance_private *lp;
+	struct lance_ioreg	 *IO;
+	int csr0, boguscnt = 10;
+
+	if (dev == NULL) {
+		DPRINTK( 1, ( "lance_interrupt(): interrupt for unknown device.\n" ));
+		return;
+	}
+
+	lp = (struct lance_private *)dev->priv;
+	IO = lp->iobase;
+	AREG = CSR0;
+
+	if (dev->interrupt)
+		DPRINTK( 2, ( "%s: Re-entering the interrupt handler.\n", dev->name ));
+	dev->interrupt = 1;
+
+	while( ((csr0 = DREG) & (CSR0_ERR | CSR0_TINT | CSR0_RINT)) &&
+		   --boguscnt >= 0) {
+		/* Acknowledge all of the current interrupt sources ASAP. */
+		DREG = csr0 & ~(CSR0_INIT | CSR0_STRT | CSR0_STOP |
+									CSR0_TDMD | CSR0_INEA);
+
+		DPRINTK( 2, ( "%s: interrupt  csr0=%04x new csr=%04x.\n",
+					  dev->name, csr0, DREG ));
+
+		if (csr0 & CSR0_RINT)			/* Rx interrupt */
+			lance_rx( dev );
+
+		if (csr0 & CSR0_TINT) {			/* Tx-done interrupt */
+			int dirty_tx = lp->dirty_tx;
+
+			while( dirty_tx < lp->cur_tx) {
+				int entry = dirty_tx & TX_RING_MOD_MASK;
+				int status = MEM->tx_head[entry].flag;
+			
+				if (status & TMD1_OWN_CHIP)
+					break;			/* It still hasn't been Txed */
+
+				MEM->tx_head[entry].flag = 0;
+
+				if (status & TMD1_ERR) {
+					/* There was an major error, log it. */
+					int err_status = MEM->tx_head[entry].misc;
+					lp->stats.tx_errors++;
+					if (err_status & TMD3_RTRY) lp->stats.tx_aborted_errors++;
+					if (err_status & TMD3_LCAR) lp->stats.tx_carrier_errors++;
+					if (err_status & TMD3_LCOL) lp->stats.tx_window_errors++;
+					if (err_status & TMD3_UFLO) {
+						/* Ackk!  On FIFO errors the Tx unit is turned off! */
+						lp->stats.tx_fifo_errors++;
+						/* Remove this verbosity later! */
+						DPRINTK( 1, ( "%s: Tx FIFO error! Status %04x\n",
+									  dev->name, csr0 ));
+						/* Restart the chip. */
+						DREG = CSR0_STRT;
+					}
+				} else {
+					if (status & (TMD1_MORE | TMD1_ONE | TMD1_DEF))
+						lp->stats.collisions++;
+					lp->stats.tx_packets++;
+				}
+				dirty_tx++;
+			}
+
+#ifndef final_version
+			if (lp->cur_tx - dirty_tx >= TX_RING_SIZE) {
+				DPRINTK( 0, ( "out-of-sync dirty pointer,"
+							  " %d vs. %d, full=%d.\n",
+							  dirty_tx, lp->cur_tx, lp->tx_full ));
+				dirty_tx += TX_RING_SIZE;
+			}
+#endif
+
+			if (lp->tx_full && dev->tbusy
+				&& dirty_tx > lp->cur_tx - TX_RING_SIZE + 2) {
+				/* The ring is no longer full, clear tbusy. */
+				lp->tx_full = 0;
+				dev->tbusy = 0;
+				mark_bh( NET_BH );
+			}
+
+			lp->dirty_tx = dirty_tx;
+		}
+
+		/* Log misc errors. */
+		if (csr0 & CSR0_BABL) lp->stats.tx_errors++; /* Tx babble. */
+		if (csr0 & CSR0_MISS) lp->stats.rx_errors++; /* Missed a Rx frame. */
+		if (csr0 & CSR0_MERR) {
+			DPRINTK( 1, ( "%s: Bus master arbitration failure (?!?), "
+						  "status %04x.\n", dev->name, csr0 ));
+			/* Restart the chip. */
+			DREG = CSR0_STRT;
+		}
+	}
+
+    /* Clear any other interrupt, and set interrupt enable. */
+	DREG = CSR0_BABL | CSR0_CERR | CSR0_MISS | CSR0_MERR |
+		   CSR0_IDON | CSR0_INEA;
+
+	DPRINTK( 2, ( "%s: exiting interrupt, csr0=%#04x.\n",
+				  dev->name, DREG ));
+	dev->interrupt = 0;
+	return;
+}
+
+
+static int lance_rx( struct device *dev )
+
+{	struct lance_private *lp = (struct lance_private *)dev->priv;
+	int entry = lp->cur_rx & RX_RING_MOD_MASK;
+	int i;
+
+	DPRINTK( 2, ( "%s: rx int, flag=%04x\n", dev->name,
+				  MEM->rx_head[entry].flag ));
+	
+	/* If we own the next entry, it's a new packet. Send it up. */
+	while( (MEM->rx_head[entry].flag & RMD1_OWN) == RMD1_OWN_HOST ) {
+		struct lance_rx_head *head = &(MEM->rx_head[entry]);
+		int status = head->flag;
+		
+		if (status != (RMD1_ENP|RMD1_STP)) {		/* There was an error. */
+			/* There is a tricky error noted by John Murphy,
+			   <murf@perftech.com> to Russ Nelson: Even with full-sized
+			   buffers it's possible for a jabber packet to use two
+			   buffers, with only the last correctly noting the error. */
+			if (status & RMD1_ENP)	/* Only count a general error at the */
+				lp->stats.rx_errors++; /* end of a packet.*/
+			if (status & RMD1_FRAM) lp->stats.rx_frame_errors++;
+			if (status & RMD1_OFLO) lp->stats.rx_over_errors++;
+			if (status & RMD1_CRC) lp->stats.rx_crc_errors++;
+			if (status & RMD1_BUFF) lp->stats.rx_fifo_errors++;
+			head->flag &= (RMD1_ENP|RMD1_STP);
+		} else {
+			/* Malloc up new buffer, compatible with net-3. */
+			short pkt_len = head->msg_length & 0xfff;
+			struct sk_buff *skb;
+
+			if (pkt_len < 60) {
+				printk( "%s: Runt packet!\n", dev->name );
+				lp->stats.rx_errors++;
+			}
+			else {
+				skb = dev_alloc_skb( pkt_len+2 );
+				if (skb == NULL) {
+					DPRINTK( 1, ( "%s: Memory squeeze, deferring packet.\n",
+								  dev->name ));
+					for( i = 0; i < RX_RING_SIZE; i++ )
+						if (MEM->rx_head[(entry+i) & RX_RING_MOD_MASK].flag &
+							RMD1_OWN_CHIP)
+							break;
+					
+					if (i > RX_RING_SIZE - 2) {
+						lp->stats.rx_dropped++;
+						head->flag |= RMD1_OWN_CHIP;
+						lp->cur_rx++;
+					}
+					break;
+				}
+
+				if (lance_debug >= 3) {
+					u_char *data = PKTBUF_ADDR(head), *p;
+					printk( "%s: RX pkt type 0x%04x from ", dev->name,
+							((u_short *)data)[6]);
+					for( p = &data[6], i = 0; i < 6; i++ )
+						printk("%02x%s", *p++, i != 5 ? ":" : "" );
+					printk(" to ");
+					for( p = data, i = 0; i < 6; i++ )
+						printk("%02x%s", *p++, i != 5 ? ":" : "" );
+					printk(" data %02x %02x %02x %02x %02x %02x %02x %02x "
+						   "len %d\n",
+						   data[15], data[16], data[17], data[18],
+						   data[19], data[20], data[21], data[22],
+						   pkt_len );
+				}
+				
+				skb->dev = dev;
+				skb_reserve( skb, 2 );	/* 16 byte align */
+				skb_put( skb, pkt_len );	/* Make room */
+				lp->memcpy_f( skb->data, PKTBUF_ADDR(head), pkt_len );
+				skb->protocol = eth_type_trans( skb, dev );
+				netif_rx( skb );
+				lp->stats.rx_packets++;
+			}
+		}
+
+		head->flag |= RMD1_OWN_CHIP;
+		entry = (++lp->cur_rx) & RX_RING_MOD_MASK;
+	}
+	lp->cur_rx &= RX_RING_MOD_MASK;
+
+	/* From lance.c (Donald Becker): */
+	/* We should check that at least two ring entries are free.	 If not,
+	   we should free one and mark stats->rx_dropped++. */
+
+	return 0;
+}
+
+
+static int lance_close( struct device *dev )
+
+{	struct lance_private *lp = (struct lance_private *)dev->priv;
+	struct lance_ioreg	 *IO = lp->iobase;
+
+	dev->start = 0;
+	dev->tbusy = 1;
+
+	AREG = CSR0;
+
+	DPRINTK( 2, ( "%s: Shutting down ethercard, status was %2.2x.\n",
+				  dev->name, DREG ));
+
+	/* We stop the LANCE here -- it occasionally polls
+	   memory if we don't. */
+	DREG = CSR0_STOP;
+
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+
+static struct enet_statistics *lance_get_stats( struct device *dev )
+
+{	struct lance_private *lp = (struct lance_private *)dev->priv;
+
+	return &lp->stats;
+}
+
+
+/* Set or clear the multicast filter for this adaptor.
+   num_addrs == -1		Promiscuous mode, receive all packets
+   num_addrs == 0		Normal mode, clear multicast list
+   num_addrs > 0		Multicast mode, receive normal and MC packets, and do
+						best-effort filtering.
+ */
+
+static void set_multicast_list( struct device *dev )
+
+{	struct lance_private *lp = (struct lance_private *)dev->priv;
+	struct lance_ioreg	 *IO = lp->iobase;
+
+	if (!dev->start)
+		/* Only possible if board is already started */
+		return;
+	
+	/* We take the simple way out and always enable promiscuous mode. */
+	DREG = CSR0_STOP; /* Temporarily stop the lance. */
+
+	if (dev->flags & IFF_PROMISC) {
+		/* Log any net taps. */
+		DPRINTK( 1, ( "%s: Promiscuous mode enabled.\n", dev->name ));
+		REGA( CSR15 ) = 0x8000; /* Set promiscuous mode */
+	} else {
+		short multicast_table[4];
+		int num_addrs = dev->mc_count;
+		int i;
+		/* We don't use the multicast table, but rely on upper-layer
+		 * filtering. */
+		memset( multicast_table, (num_addrs == 0) ? 0 : -1,
+				sizeof(multicast_table) );
+		for( i = 0; i < 4; i++ )
+			REGA( CSR8+i ) = multicast_table[i];
+		REGA( CSR15 ) = 0; /* Unset promiscuous mode */
+	}
+
+	/*
+	 * Always set BSWP after a STOP as STOP puts it back into
+	 * little endian mode.
+	 */
+	REGA( CSR3 ) = CSR3_BSWP | (lp->cardtype == PAM_CARD ? CSR3_ACON : 0); 
+
+	/* Resume normal operation and reset AREG to CSR0 */
+	REGA( CSR0 ) = CSR0_IDON | CSR0_INEA | CSR0_STRT;
+}
+
+
+/* This is needed for old RieblCards and possible for new RieblCards */
+
+static int lance_set_mac_address( struct device *dev, void *addr )
+
+{	struct lance_private *lp = (struct lance_private *)dev->priv;
+	struct sockaddr *saddr = addr;
+	int i;
+	
+	if (lp->cardtype != OLD_RIEBL && lp->cardtype != NEW_RIEBL)
+		return( -EOPNOTSUPP );
+
+	if (dev->start) {
+		/* Only possible while card isn't started */
+		DPRINTK( 1, ( "%s: hwaddr can be set only while card isn't open.\n",
+					  dev->name ));
+		return( -EIO );
+	}
+
+	memcpy( dev->dev_addr, saddr->sa_data, dev->addr_len );
+	for( i = 0; i < 6; i++ )
+		MEM->init.hwaddr[i] = dev->dev_addr[i^1]; /* <- 16 bit swap! */
+	lp->memcpy_f( RIEBL_HWADDR_ADDR, dev->dev_addr, 6 );
+	/* set also the magic for future sessions */
+	*RIEBL_MAGIC_ADDR = RIEBL_MAGIC;
+	
+	return( 0 );
+}
+
+
+#ifdef MODULE
+static char devicename[9] = { 0, };
+
+static struct device atarilance_dev =  
+{
+	devicename,	/* filled in by register_netdev() */
+	0, 0, 0, 0,	/* memory */
+	0, 0,		/* base, irq */
+	0, 0, 0, NULL, atarilance_probe,
+};
+
+int init_module(void)
+
+{	int err;
+	
+	if ((err = register_netdev( &atarilance_dev ))) {
+		if (err == -EIO)  {
+			printk( "No Atari Lance board found. Module not loaded.\n");
+		}
+		return( err );
+	}
+	return( 0 );
+}  
+
+void cleanup_module(void)
+
+{
+	unregister_netdev( &atarilance_dev );
+}
+                      
+#endif /* MODULE */
+
+
+/*
+ * Local variables:
+ *  c-indent-level: 4
+ *  tab-width: 4
+ * End:
+ */
diff -u --recursive --new-file v1.3.93/linux/drivers/scsi/README.g_NCR5380 linux/drivers/scsi/README.g_NCR5380
--- v1.3.93/linux/drivers/scsi/README.g_NCR5380	Fri Apr 12 15:51:59 1996
+++ linux/drivers/scsi/README.g_NCR5380	Mon Apr 22 12:26:21 1996
@@ -41,52 +41,23 @@
 it!).
 
 This driver works as a module.
+When included as a module, parameters can be passed on the insmod/modprobe
+command line:
+  ncr_irq=xx   the interrupt
+  ncr_addr=xx  the port or base address (for port or memory
+               mapped, resp.)
+  ncr_dma=xx   the DMA
+  ncr_5380=1   to set up for a NCR5380 board
+  ncr_53c400=1 to set up for a NCR53C400 board
+e.g.
+modprobe g_NCR5380 ncr_irq=5 ncr_addr=0x350 ncr_5380=1
+  for a port mapped NCR5380 board or
+modprobe g_NCR5380 ncr_irq=255 ncr_addr=0xc8000 ncr_53c400=1
+  for a memory mapped NCR53C400 board with interrupts disabled.
 
-Kevin Lentin
-K.Lentin@cs.monash.edu.au
-README file for the Linux g_NCR5380 driver.
+(255 should be specified for no or DMA interrupt, 254 to autoprobe for an 
+     IRQ line if overridden on the command line.)
 
-(c) 1993 Drew Eckhard
-NCR53c400 extensions (c) 1994,1995,1996 Kevin Lentin
-
-This file documents the NCR53c400 extensions by Kevin Lentin and some
-enhancements to the NCR5380 core.
-
-This driver supports both NCR5380 and NCR53c400 cards in port or memory
-mapped modes. Currently this driver can only support one of those mapping
-modes at a time but it does support both of these chips at the same time.
-The next release of this driver will support port & memory mapped cards at
-the same time. It should be able to handle multiple different cards in the
-same machine.
-
-The drivers/scsi/Makefile has an override in it for the most common
-NCR53c400 card, the Trantor T130B in its default configuration:
-	Port: 0x350
-	IRQ : 5
-
-The NCR53c400 does not support DMA but it does have Pseudo-DMA which is
-supported by the driver.
-
-If the default configuration does not work for you, you can use the kernel
-command lines (eg using the lilo append command):
-	ncr5380=port,irq,dma
-	ncr53c400=port,irq
-or
-	ncr5380=base,irq,dma
-	ncr53c400=base,irq
-
-The driver does not probe for any addresses or ports other than those in
-the OVERRIDE or given to the kernel as above.
-
-This driver provides some information on what it has detected in
-/proc/scsi/g_NCR5380/x where x is the scsi card number as detected at boot
-time. More info to come in the future.
-
-When NCR53c400 support is compiled in, BIOS parameters will be returned by
-the driver (the raw 5380 driver does not and I don't plan to fiddle with
-it!).
-
-This driver works as a module.
 
 Kevin Lentin
 K.Lentin@cs.monash.edu.au
diff -u --recursive --new-file v1.3.93/linux/drivers/scsi/README.st linux/drivers/scsi/README.st
--- v1.3.93/linux/drivers/scsi/README.st	Mon Apr  8 19:01:44 1996
+++ linux/drivers/scsi/README.st	Mon Apr 22 11:13:22 1996
@@ -1,5 +1,5 @@
 This file contains brief information about the SCSI tape driver.
-Last modified: Mon Apr  8 09:34:33 1996 by makisara@kai.makisara.fi
+Last modified: Sun Apr 21 21:19:22 1996 by root@kai.makisara.fi
 
 
 BASICS
@@ -197,13 +197,16 @@
 	   can be specified differently for each mode):
 	     MT_ST_BUFFER_WRITES write buffering (mode)
 	     MT_ST_ASYNC_WRITES asynchronous writes (mode)
-             MT_ST_READ_AHEAD  read ahead (global)
+             MT_ST_READ_AHEAD  read ahead (mode)
              MT_ST_TWO_FM writing of two filemarks (global)
 	     MT_ST_FAST_EOM using the SCSI spacing to EOD (global)
 	     MT_ST_AUTO_LOCK automatic locking of the drive door (global)
              MT_ST_DEF_WRITES the defaults are meant only for writes (mode)
 	     MT_ST_CAN_BSR backspacing over records can be used for
 		repositioning the tape (global)
+	     MT_ST_NO_BLKLIMS the driver does not ask the block limits
+		from the drive (block size can be changed only to
+		variable) (global)
 	     MT_ST_DEBUGGING debugging (global; debugging must be
 		compiled into the driver)
 	MT_ST_SETBOOLEANS
diff -u --recursive --new-file v1.3.93/linux/drivers/scsi/a2091.c linux/drivers/scsi/a2091.c
--- v1.3.93/linux/drivers/scsi/a2091.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/scsi/a2091.c	Mon Apr  1 22:13:57 1996
@@ -0,0 +1,229 @@
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/blk.h>
+
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/bootinfo.h>
+#include <asm/amigaints.h>
+#include <asm/amigahw.h>
+#include <asm/zorro.h>
+#include <asm/irq.h>
+
+#include "scsi.h"
+#include "hosts.h"
+#include "wd33c93.h"
+#include "a2091.h"
+
+#include<linux/stat.h>
+
+struct proc_dir_entry proc_scsi_a2091 = {
+    PROC_SCSI_A2091, 5, "A2091",
+    S_IFDIR | S_IRUGO | S_IXUGO, 2
+};
+
+#define DMA(ptr) ((a2091_scsiregs *)((ptr)->base))
+#define HDATA(ptr) ((struct WD33C93_hostdata *)((ptr)->hostdata))
+
+static struct Scsi_Host *first_instance = NULL;
+static Scsi_Host_Template *a2091_template;
+
+static void a2091_intr (int irq, struct pt_regs *fp, void *dummy)
+{
+    unsigned int status;
+    struct Scsi_Host *instance;
+
+    for (instance = first_instance; instance &&
+	 instance->hostt == a2091_template; instance = instance->next)
+    {
+	status = DMA(instance)->ISTR;
+	if (!(status & (ISTR_INT_F|ISTR_INT_P)))
+	    continue;
+
+	if (status & ISTR_INTS)
+	{
+	    /* disable PORTS interrupt */
+	    custom.intena = IF_PORTS;
+	    wd33c93_intr (instance);
+	    /* enable PORTS interrupt */
+	    custom.intena = IF_SETCLR | IF_PORTS;
+	}
+    }
+}
+
+static int dma_setup (Scsi_Cmnd *cmd, int dir_in)
+{
+    unsigned short cntr = CNTR_PDMD | CNTR_INTEN;
+    unsigned long addr = VTOP(cmd->SCp.ptr);
+    struct Scsi_Host *instance = cmd->host;
+
+    /* don't allow DMA if the physical address is bad */
+    if (addr & A2091_XFER_MASK ||
+	(!dir_in && mm_end_of_chunk (addr, cmd->SCp.this_residual)))
+    {
+	HDATA(instance)->dma_bounce_len = (cmd->SCp.this_residual + 511)
+	    & ~0x1ff;
+	HDATA(instance)->dma_bounce_buffer =
+	    scsi_malloc (HDATA(instance)->dma_bounce_len);
+	
+	/* can't allocate memory; use PIO */
+	if (!HDATA(instance)->dma_bounce_buffer) {
+	    HDATA(instance)->dma_bounce_len = 0;
+	    return 1;
+	}
+
+	/* get the physical address of the bounce buffer */
+	addr = VTOP(HDATA(instance)->dma_bounce_buffer);
+
+	/* the bounce buffer may not be in the first 16M of physmem */
+	if (addr & A2091_XFER_MASK) {
+	    /* we could use chipmem... maybe later */
+	    scsi_free (HDATA(instance)->dma_bounce_buffer,
+		       HDATA(instance)->dma_bounce_len);
+	    HDATA(instance)->dma_bounce_buffer = NULL;
+	    HDATA(instance)->dma_bounce_len = 0;
+	    return 1;
+	}
+
+	if (!dir_in) {
+	    /* copy to bounce buffer for a write */
+	    if (cmd->use_sg)
+#if 0
+		panic ("scsi%ddma: incomplete s/g support",
+		       instance->host_no);
+#else
+		memcpy (HDATA(instance)->dma_bounce_buffer,
+			cmd->SCp.ptr, cmd->SCp.this_residual);
+#endif
+	    else
+		memcpy (HDATA(instance)->dma_bounce_buffer,
+			cmd->request_buffer, cmd->request_bufflen);
+	}
+    }
+
+    /* setup dma direction */
+    if (!dir_in)
+	cntr |= CNTR_DDIR;
+
+    /* remember direction */
+    HDATA(cmd->host)->dma_dir = dir_in;
+
+    DMA(cmd->host)->CNTR = cntr;
+
+    /* setup DMA *physical* address */
+    DMA(cmd->host)->ACR = addr;
+
+    if (dir_in){
+	/* invalidate any cache */
+	cache_clear (addr, cmd->SCp.this_residual);
+    }else{
+	/* push any dirty cache */
+	cache_push (addr, cmd->SCp.this_residual);
+      }
+    /* start DMA */
+    DMA(cmd->host)->ST_DMA = 1;
+
+    /* return success */
+    return 0;
+}
+
+static void dma_stop (struct Scsi_Host *instance, Scsi_Cmnd *SCpnt, 
+		      int status)
+{
+    /* disable SCSI interrupts */
+    unsigned short cntr = CNTR_PDMD;
+
+    if (!HDATA(instance)->dma_dir)
+	    cntr |= CNTR_DDIR;
+
+    /* disable SCSI interrupts */
+    DMA(instance)->CNTR = cntr;
+
+    /* flush if we were reading */
+    if (HDATA(instance)->dma_dir) {
+	DMA(instance)->FLUSH = 1;
+	while (!(DMA(instance)->ISTR & ISTR_FE_FLG))
+	    ;
+    }
+
+    /* clear a possible interrupt */
+    DMA(instance)->CINT = 1;
+
+    /* stop DMA */
+    DMA(instance)->SP_DMA = 1;
+
+    /* restore the CONTROL bits (minus the direction flag) */
+    DMA(instance)->CNTR = CNTR_PDMD | CNTR_INTEN;
+
+    /* copy from a bounce buffer, if necessary */
+    if (status && HDATA(instance)->dma_bounce_buffer) {
+	if (SCpnt && SCpnt->use_sg) {
+#if 0
+	    panic ("scsi%d: incomplete s/g support",
+		   instance->host_no);
+#else
+	    if( HDATA(instance)->dma_dir )
+		memcpy (SCpnt->SCp.ptr, 
+			HDATA(instance)->dma_bounce_buffer,
+			SCpnt->SCp.this_residual);
+	    scsi_free (HDATA(instance)->dma_bounce_buffer,
+		       HDATA(instance)->dma_bounce_len);
+	    HDATA(instance)->dma_bounce_buffer = NULL;
+	    HDATA(instance)->dma_bounce_len = 0;
+	    
+#endif
+	} else {
+	    if (HDATA(instance)->dma_dir && SCpnt)
+		memcpy (SCpnt->request_buffer,
+			HDATA(instance)->dma_bounce_buffer,
+			SCpnt->request_bufflen);
+
+	    scsi_free (HDATA(instance)->dma_bounce_buffer,
+		       HDATA(instance)->dma_bounce_len);
+	    HDATA(instance)->dma_bounce_buffer = NULL;
+	    HDATA(instance)->dma_bounce_len = 0;
+	}
+    }
+}
+
+int a2091_detect(Scsi_Host_Template *tpnt)
+{
+    static unsigned char called = 0;
+    struct Scsi_Host *instance;
+    int i, manuf, product, num_a2091 = 0;
+    caddr_t address;
+
+    if (!MACH_IS_AMIGA || called)
+	return 0;
+    called = 1;
+
+    tpnt->proc_dir = &proc_scsi_a2091;
+
+    for (i = 0; i < boot_info.bi_amiga.num_autocon; i++)
+    {
+	manuf = boot_info.bi_amiga.autocon[i].cd_Rom.er_Manufacturer;
+	product = boot_info.bi_amiga.autocon[i].cd_Rom.er_Product;
+	if (manuf == MANUF_COMMODORE && (product == PROD_A2091 ||
+					 product == PROD_A590)) {
+	    address = boot_info.bi_amiga.autocon[i].cd_BoardAddr;
+	    instance = scsi_register (tpnt,
+				      sizeof (struct WD33C93_hostdata));
+	    instance->base = (unsigned char *)ZTWO_VADDR(address);
+	    DMA(instance)->DAWR = DAWR_A2091;
+	    wd33c93_init(instance, (wd33c93_regs *)&(DMA(instance)->SASR),
+			 dma_setup, dma_stop, WD33C93_FS_8_10);
+	    if (num_a2091++ == 0) {
+		first_instance = instance;
+		a2091_template = instance->hostt;
+		add_isr(IRQ_AMIGA_PORTS, a2091_intr, 0, NULL, "A2091 SCSI");
+	    }
+	    DMA(instance)->CNTR = CNTR_PDMD | CNTR_INTEN;
+
+#if 0 /* The Zorro stuff is not totally integrated yet ! */
+	    boot_info.bi_amiga.autocon_configured |= 1<<i;
+#endif
+	  }
+    }
+
+    return num_a2091;
+}
diff -u --recursive --new-file v1.3.93/linux/drivers/scsi/a2091.h linux/drivers/scsi/a2091.h
--- v1.3.93/linux/drivers/scsi/a2091.h	Thu Jan  1 02:00:00 1970
+++ linux/drivers/scsi/a2091.h	Fri Apr  5 15:15:07 1996
@@ -0,0 +1,107 @@
+#ifndef A2091_H
+
+/* $Id: a2091.h,v 1.3 1996/03/12 20:41:46 root Exp root $
+ *
+ * Header file for the Commodore A2091 Zorro II SCSI controller for Linux
+ *
+ * Written and (C) 1993, Hamish Macdonald, see a2091.c for more info
+ *
+ */
+
+#include <linux/types.h>
+
+int a2091_detect(Scsi_Host_Template *);
+const char *wd33c93_info(void);
+int wd33c93_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+int wd33c93_abort(Scsi_Cmnd *);
+int wd33c93_reset(Scsi_Cmnd *);
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#ifndef CMD_PER_LUN
+#define CMD_PER_LUN 2
+#endif
+
+#ifndef CAN_QUEUE
+#define CAN_QUEUE 16
+#endif
+
+#ifdef HOSTS_C
+
+extern struct proc_dir_entry proc_scsi_a2091;
+
+#define A2091_SCSI {  /* next */                NULL,            \
+		      /* usage_count */         NULL,	         \
+		      /* proc_dir_entry */      &proc_scsi_a2091, \
+		      /* proc_info */           NULL,            \
+		      /* name */                "Commodore A2091/A590 SCSI", \
+		      /* detect */              a2091_detect,    \
+		      /* release */             NULL,            \
+		      /* info */                NULL,	         \
+		      /* command */             NULL,            \
+		      /* queuecommand */        wd33c93_queuecommand, \
+		      /* abort */               wd33c93_abort,   \
+		      /* reset */               wd33c93_reset,   \
+		      /* slave_attach */        NULL,            \
+		      /* bios_param */          NULL, 	         \
+		      /* can_queue */           CAN_QUEUE,       \
+		      /* this_id */             7,               \
+		      /* sg_tablesize */        SG_ALL,          \
+		      /* cmd_per_lun */	        CMD_PER_LUN,     \
+		      /* present */             0,               \
+		      /* unchecked_isa_dma */   0,               \
+		      /* use_clustering */      DISABLE_CLUSTERING }
+#else
+
+/*
+ * if the transfer address ANDed with this results in a non-zero
+ * result, then we can't use DMA.
+ */ 
+#define A2091_XFER_MASK  (0xff000001)
+
+typedef struct {
+             unsigned char      pad1[64];
+    volatile unsigned short     ISTR;
+    volatile unsigned short     CNTR;
+             unsigned char      pad2[60];
+    volatile unsigned int       WTC;
+    volatile unsigned long      ACR;
+             unsigned char      pad3[6];
+    volatile unsigned short     DAWR;
+             unsigned char      pad4;
+    volatile unsigned char      SASR;
+             unsigned char      pad5;
+    volatile unsigned char      SCMD;
+             unsigned char      pad6[76];
+    volatile unsigned short     ST_DMA;
+    volatile unsigned short     SP_DMA;
+    volatile unsigned short     CINT;
+             unsigned char      pad7[2];
+    volatile unsigned short     FLUSH;
+} a2091_scsiregs;
+
+#define DAWR_A2091		(3)
+
+/* CNTR bits. */
+#define CNTR_TCEN		(1<<7)
+#define CNTR_PREST		(1<<6)
+#define CNTR_PDMD		(1<<5)
+#define CNTR_INTEN		(1<<4)
+#define CNTR_DDIR		(1<<3)
+
+/* ISTR bits. */
+#define ISTR_INTX		(1<<8)
+#define ISTR_INT_F		(1<<7)
+#define ISTR_INTS		(1<<6)
+#define ISTR_E_INT		(1<<5)
+#define ISTR_INT_P		(1<<4)
+#define ISTR_UE_INT		(1<<3)
+#define ISTR_OE_INT		(1<<2)
+#define ISTR_FF_FLG		(1<<1)
+#define ISTR_FE_FLG		(1<<0)
+
+#endif /* else def HOSTS_C */
+
+#endif /* A2091_H */
diff -u --recursive --new-file v1.3.93/linux/drivers/scsi/a3000.c linux/drivers/scsi/a3000.c
--- v1.3.93/linux/drivers/scsi/a3000.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/scsi/a3000.c	Sun Mar 17 21:53:33 1996
@@ -0,0 +1,203 @@
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/blk.h>
+
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/bootinfo.h>
+#include <asm/amigaints.h>
+#include <asm/amigahw.h>
+#include <asm/irq.h>
+
+#include "scsi.h"
+#include "hosts.h"
+#include "wd33c93.h"
+#include "a3000.h"
+
+#include<linux/stat.h>
+
+struct proc_dir_entry proc_scsi_a3000 = {
+    PROC_SCSI_A3000, 5, "A3000",
+    S_IFDIR | S_IRUGO | S_IXUGO, 2
+};
+
+#define DMA(ptr) ((a3000_scsiregs *)((ptr)->base))
+#define HDATA(ptr) ((struct WD33C93_hostdata *)((ptr)->hostdata))
+
+static struct Scsi_Host *a3000_host = NULL;
+
+static void a3000_intr (int irq, struct pt_regs *fp, void *dummy)
+{
+    unsigned int status = DMA(a3000_host)->ISTR;
+
+    if (!(status & ISTR_INT_P))
+	return;
+
+    if (status & ISTR_INTS)
+    {
+	/* disable PORTS interrupt */
+	custom.intena = IF_PORTS;
+	wd33c93_intr (a3000_host);
+	/* enable PORTS interrupt */
+	custom.intena = IF_SETCLR | IF_PORTS;
+    } else {
+      printk("Non-serviced A3000 SCSI-interrupt? ISTR = %02x\n", status);
+    }
+}
+
+static int dma_setup (Scsi_Cmnd *cmd, int dir_in)
+{
+    unsigned short cntr = CNTR_PDMD | CNTR_INTEN;
+    unsigned long addr = VTOP(cmd->SCp.ptr);
+
+    /*
+     * if the physical address has the wrong alignment, or if
+     * physical address is bad, or if it is a write and at the
+     * end of a physical memory chunk, then allocate a bounce
+     * buffer
+     */
+    if (addr & A3000_XFER_MASK ||
+	(!dir_in && mm_end_of_chunk (addr, cmd->SCp.this_residual)))
+    {
+	HDATA(a3000_host)->dma_bounce_len = (cmd->SCp.this_residual + 511)
+	    & ~0x1ff;
+	HDATA(a3000_host)->dma_bounce_buffer =
+	    scsi_malloc (HDATA(a3000_host)->dma_bounce_len);
+	
+	/* can't allocate memory; use PIO */
+	if (!HDATA(a3000_host)->dma_bounce_buffer) {
+	    HDATA(a3000_host)->dma_bounce_len = 0;
+	    return 1;
+	}
+
+	if (!dir_in) {
+	    /* copy to bounce buffer for a write */
+	    if (cmd->use_sg) {
+		memcpy (HDATA(a3000_host)->dma_bounce_buffer,
+			cmd->SCp.ptr, cmd->SCp.this_residual);
+	    } else
+		memcpy (HDATA(a3000_host)->dma_bounce_buffer,
+			cmd->request_buffer, cmd->request_bufflen);
+	}
+
+	addr = VTOP(HDATA(a3000_host)->dma_bounce_buffer);
+    }
+
+    /* setup dma direction */
+    if (!dir_in)
+	cntr |= CNTR_DDIR;
+
+    /* remember direction */
+    HDATA(a3000_host)->dma_dir = dir_in;
+
+    DMA(a3000_host)->CNTR = cntr;
+
+    /* setup DMA *physical* address */
+    DMA(a3000_host)->ACR = addr;
+
+
+    if (dir_in)
+      {
+  	/* invalidate any cache */
+        /*
+         * On the 68040 it's not ok to use cache_clear, as it just invalidates
+         * cache-lines, and thereby trashing them. We need to use cache_push
+         * to avoid problems/crashes.
+         * This was a real bitch to catch :-( -Jes
+         */
+
+        if (boot_info.cputype & CPU_68040)
+	  cache_push (addr, cmd->SCp.this_residual);
+	else
+	  cache_clear (addr, cmd->SCp.this_residual);
+      }
+    else
+      /* push any dirty cache */
+      cache_push (addr, cmd->SCp.this_residual);
+      
+
+    /* start DMA */
+    DMA(a3000_host)->ST_DMA = 1;
+
+    /* return success */
+    return 0;
+}
+
+static void dma_stop (struct Scsi_Host *instance, Scsi_Cmnd *SCpnt,
+		      int status)
+{
+    /* disable SCSI interrupts */
+    unsigned short cntr = CNTR_PDMD;
+
+    if (!HDATA(instance)->dma_dir)
+	cntr |= CNTR_DDIR;
+
+    DMA(instance)->CNTR = cntr;
+
+    /* flush if we were reading */
+    if (HDATA(instance)->dma_dir) {
+	DMA(instance)->FLUSH = 1;
+	while (!(DMA(instance)->ISTR & ISTR_FE_FLG))
+	    ;
+    }
+
+    /* clear a possible interrupt */
+    /* I think that this CINT is only necessary if you are
+     * using the terminal count features.   HM 7 Mar 1994
+     */
+    DMA(instance)->CINT = 1;
+
+    /* stop DMA */
+    DMA(instance)->SP_DMA = 1;
+
+    /* restore the CONTROL bits (minus the direction flag) */
+    DMA(instance)->CNTR = CNTR_PDMD | CNTR_INTEN;
+
+    /* copy from a bounce buffer, if necessary */
+    if (status && HDATA(instance)->dma_bounce_buffer) {
+	if (SCpnt && SCpnt->use_sg) {
+	    if (HDATA(instance)->dma_dir && SCpnt)
+		memcpy (SCpnt->SCp.ptr,
+			HDATA(instance)->dma_bounce_buffer,
+			SCpnt->SCp.this_residual);
+	    scsi_free (HDATA(instance)->dma_bounce_buffer,
+		       HDATA(instance)->dma_bounce_len);
+	    HDATA(instance)->dma_bounce_buffer = NULL;
+	    HDATA(instance)->dma_bounce_len = 0;
+	} else {
+	    if (HDATA(instance)->dma_dir && SCpnt)
+		memcpy (SCpnt->request_buffer,
+			HDATA(instance)->dma_bounce_buffer,
+			SCpnt->request_bufflen);
+
+	    scsi_free (HDATA(instance)->dma_bounce_buffer,
+		       HDATA(instance)->dma_bounce_len);
+	    HDATA(instance)->dma_bounce_buffer = NULL;
+	    HDATA(instance)->dma_bounce_len = 0;
+	}
+    }
+}
+
+int a3000_detect(Scsi_Host_Template *tpnt)
+{
+    static unsigned char called = 0;
+
+    if (called)
+	return 0;
+
+    if  (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(A3000_SCSI))
+	return 0;
+
+    tpnt->proc_dir = &proc_scsi_a3000;
+
+    a3000_host = scsi_register (tpnt, sizeof(struct WD33C93_hostdata));
+    a3000_host->base = (unsigned char *)ZTWO_VADDR(0xDD0000);
+    DMA(a3000_host)->DAWR = DAWR_A3000;
+    wd33c93_init(a3000_host, (wd33c93_regs *)&(DMA(a3000_host)->SASR),
+		 dma_setup, dma_stop, WD33C93_FS_12_15);
+    add_isr(IRQ_AMIGA_PORTS, a3000_intr, 0, NULL, "A3000 SCSI");
+    DMA(a3000_host)->CNTR = CNTR_PDMD | CNTR_INTEN;
+    called = 1;
+
+    return 1;
+}
diff -u --recursive --new-file v1.3.93/linux/drivers/scsi/a3000.h linux/drivers/scsi/a3000.h
--- v1.3.93/linux/drivers/scsi/a3000.h	Thu Jan  1 02:00:00 1970
+++ linux/drivers/scsi/a3000.h	Fri Apr  5 15:15:07 1996
@@ -0,0 +1,110 @@
+#ifndef A3000_H
+
+/* $Id: a3000.h,v 1.2 1996/02/29 22:10:29 root Exp root $
+ *
+ * Header file for the Amiga 3000 built-in SCSI controller for Linux
+ *
+ * Written and (C) 1993, Hamish Macdonald, see a3000.c for more info
+ *
+ */
+
+#include <linux/types.h>
+
+int a3000_detect(Scsi_Host_Template *);
+const char *wd33c93_info(void);
+int wd33c93_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+int wd33c93_abort(Scsi_Cmnd *);
+int wd33c93_reset(Scsi_Cmnd *);
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#ifndef CMD_PER_LUN
+#define CMD_PER_LUN 2
+#endif
+
+#ifndef CAN_QUEUE
+#define CAN_QUEUE 16
+#endif
+
+#ifdef HOSTS_C
+
+extern struct proc_dir_entry proc_scsi_a3000;
+
+#define A3000_SCSI {  /* next */                NULL,            \
+		      /* usage_count */         NULL,	         \
+		      /* proc_dir_entry */      &proc_scsi_a3000, \
+		      /* proc_info */           NULL,            \
+		      /* name */                "Amiga 3000 built-in SCSI", \
+		      /* detect */              a3000_detect,    \
+		      /* release */             NULL,            \
+		      /* info */                NULL,	         \
+		      /* command */             NULL,            \
+		      /* queuecommand */        wd33c93_queuecommand, \
+		      /* abort */               wd33c93_abort,   \
+		      /* reset */               wd33c93_reset,   \
+		      /* slave_attach */        NULL,            \
+		      /* bios_param */          NULL, 	         \
+		      /* can_queue */           CAN_QUEUE,       \
+		      /* this_id */             7,               \
+		      /* sg_tablesize */        SG_ALL,          \
+		      /* cmd_per_lun */	        CMD_PER_LUN,     \
+		      /* present */             0,               \
+		      /* unchecked_isa_dma */   0,               \
+		      /* use_clustering */      DISABLE_CLUSTERING }
+#else
+
+/*
+ * if the transfer address ANDed with this results in a non-zero
+ * result, then we can't use DMA.
+ */ 
+#define A3000_XFER_MASK  (0x00000003)
+
+typedef struct {
+             unsigned char      pad1[2];
+    volatile unsigned short     DAWR;
+    volatile unsigned int       WTC;
+             unsigned char      pad2[2];
+    volatile unsigned short     CNTR;
+    volatile unsigned long      ACR;
+             unsigned char      pad3[2];
+    volatile unsigned short     ST_DMA;
+             unsigned char      pad4[2];
+    volatile unsigned short     FLUSH;
+             unsigned char      pad5[2];
+    volatile unsigned short     CINT;
+             unsigned char      pad6[2];
+    volatile unsigned short     ISTR;
+	     unsigned char      pad7[30];
+    volatile unsigned short     SP_DMA;
+             unsigned char      pad8;
+    volatile unsigned char      SASR;
+             unsigned char      pad9;
+    volatile unsigned char      SCMD;
+} a3000_scsiregs;
+
+#define DAWR_A3000		(3)
+
+/* CNTR bits. */
+#define CNTR_TCEN		(1<<5)
+#define CNTR_PREST		(1<<4)
+#define CNTR_PDMD		(1<<3)
+#define CNTR_INTEN		(1<<2)
+#define CNTR_DDIR		(1<<1)
+#define CNTR_IO_DX		(1<<0)
+
+/* ISTR bits. */
+#define ISTR_INTX		(1<<8)
+#define ISTR_INT_F		(1<<7)
+#define ISTR_INTS		(1<<6)
+#define ISTR_E_INT		(1<<5)
+#define ISTR_INT_P		(1<<4)
+#define ISTR_UE_INT		(1<<3)
+#define ISTR_OE_INT		(1<<2)
+#define ISTR_FF_FLG		(1<<1)
+#define ISTR_FE_FLG		(1<<0)
+
+#endif /* else def HOSTS_C */
+
+#endif /* A3000_H */
diff -u --recursive --new-file v1.3.93/linux/drivers/scsi/atari_NCR5380.c linux/drivers/scsi/atari_NCR5380.c
--- v1.3.93/linux/drivers/scsi/atari_NCR5380.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/scsi/atari_NCR5380.c	Sat Apr 13 14:31:03 1996
@@ -0,0 +1,3099 @@
+/* 
+ * NCR 5380 generic driver routines.  These should make it *trivial*
+ * 	to implement 5380 SCSI drivers under Linux with a non-trantor
+ *	architecture.
+ *
+ *	Note that these routines also work with NR53c400 family chips.
+ *
+ * Copyright 1993, Drew Eckhardt
+ *	Visionary Computing 
+ *	(Unix and Linux consulting and custom programming)
+ * 	drew@colorado.edu
+ *	+1 (303) 666-5836
+ *
+ * DISTRIBUTION RELEASE 6. 
+ *
+ * For more information, please consult 
+ *
+ * NCR 5380 Family
+ * SCSI Protocol Controller
+ * Databook
+ *
+ * NCR Microelectronics
+ * 1635 Aeroplaza Drive
+ * Colorado Springs, CO 80916
+ * 1+ (719) 578-3400
+ * 1+ (800) 334-5454
+ */
+
+/*
+ * ++roman: To port the 5380 driver to the Atari, I had to do some changes in
+ * this file, too:
+ *
+ *  - Some of the debug statements were incorrect (undefined variables and the
+ *    like). I fixed that.
+ *
+ *  - In information_transfer(), I think a #ifdef was wrong. Looking at the
+ *    possible DMA transfer size should also happen for REAL_DMA. I added this
+ *    in the #if statement.
+ *
+ *  - When using real DMA, information_transfer() should return in a DATAOUT
+ *    phase after starting the DMA. It has nothing more to do.
+ *
+ *  - The interrupt service routine should run main after end of DMA, too (not
+ *    only after RESELECTION interrupts). Additionally, it should _not_ test
+ *    for more interrupts after running main, since a DMA process may have
+ *    been started and interrupts are turned on now. The new int could happen
+ *    inside the execution of NCR5380_intr(), leading to recursive
+ *    calls.
+ *
+ *  - I've added a function merge_consecutive_buffers() that trys to
+ *    merge scatter-gather buffers that are located at consecutive
+ *    physical addresses and can be processed with the same DMA setup.
+ *    Since most scatter-gather operations work on a page (4K) of
+ *    4 buffers (1K), in more than 90% of all cases three interrupts and
+ *    DMA setup actions are saved.
+ * 
+ */
+
+/*
+ * +++roman: I've deleted all the stuff for AUTOPROBE_IRQ, REAL_DMA_POLL,
+ * PSEUDO_DMA and USLEEP, because these were messing up
+ * readability and will never be needed for Atari SCSI.
+ */
+
+
+/*
+ * $Log: atari_NCR5380.c,v $
+ * Revision 1.2  1996/04/04 13:30:22  root
+ * interrupts more like the pc
+ *
+ * Revision 1.1  1996/03/20 17:51:35  root
+ * Initial revision
+ *
+ * Revision 1.2  1994/11/26  03:38:32  hamish
+ * v0.9pl4
+ *
+ * Revision 1.1  1994/11/08  03:25:43  hamish
+ * Initial revision
+ *
+ * Revision 1.5  1994/01/19  09:14:57  drew
+ * Fixed udelay() hack that was being used on DATAOUT phases
+ * instead of a proper wait for the final handshake.
+ *
+ * Revision 1.4  1994/01/19  06:44:25  drew
+ * *** empty log message ***
+ *
+ * Revision 1.3  1994/01/19  05:24:40  drew
+ * Added support for TCR LAST_BYTE_SENT bit.
+ *
+ * Revision 1.2  1994/01/15  06:14:11  drew
+ * REAL DMA support, bug fixes.
+ *
+ * Revision 1.1  1994/01/15  06:00:54  drew
+ * Initial revision
+ *
+ */
+
+/*
+ * Further development / testing that should be done : 
+ * 1.  Cleanup the NCR5380_transfer_dma function and DMA operation complete
+ *     code so that everything does the same thing that's done at the 
+ *     end of a pseudo-DMA read operation.
+ *
+ * 2.  Fix REAL_DMA (interrupt driven, polled works fine) -
+ *     basically, transfer size needs to be reduced by one 
+ *     and the last byte read as is done with PSEUDO_DMA.
+ * 
+ * 3.  Test USLEEP code 
+ *
+ * 4.  Test SCSI-II tagged queueing (I have no devices which support 
+ *	tagged queueing)
+ *
+ * 5.  Test linked command handling code after Eric is ready with 
+ *      the high level code.
+ */
+
+#if (NDEBUG & NDEBUG_LISTS)
+#define LIST(x,y) \
+  { printk("LINE:%d   Adding %p to %p\n", __LINE__, (void*)(x), (void*)(y)); \
+    if ((x)==(y)) udelay(5); }
+#define REMOVE(w,x,y,z) \
+  { printk("LINE:%d   Removing: %p->%p  %p->%p \n", __LINE__, \
+	   (void*)(w), (void*)(x), (void*)(y), (void*)(z)); \
+    if ((x)==(y)) udelay(5); }
+#else
+#define LIST(x,y)
+#define REMOVE(w,x,y,z)
+#endif
+
+#ifndef notyet
+#undef LINKED
+#endif
+
+/*
+ * Design
+ * Issues :
+ *
+ * The other Linux SCSI drivers were written when Linux was Intel PC-only,
+ * and specifically for each board rather than each chip.  This makes their
+ * adaptation to platforms like the Mac (Some of which use NCR5380's)
+ * more difficult than it has to be.
+ *
+ * Also, many of the SCSI drivers were written before the command queuing
+ * routines were implemented, meaning their implementations of queued 
+ * commands were hacked on rather than designed in from the start.
+ *
+ * When I designed the Linux SCSI drivers I figured that 
+ * while having two different SCSI boards in a system might be useful
+ * for debugging things, two of the same type wouldn't be used.
+ * Well, I was wrong and a number of users have mailed me about running
+ * multiple high-performance SCSI boards in a server.
+ *
+ * Finally, when I get questions from users, I have no idea what 
+ * revision of my driver they are running.
+ *
+ * This driver attempts to address these problems :
+ * This is a generic 5380 driver.  To use it on a different platform, 
+ * one simply writes appropriate system specific macros (ie, data
+ * transfer - some PC's will use the I/O bus, 68K's must use 
+ * memory mapped) and drops this file in their 'C' wrapper.
+ *
+ * As far as command queueing, two queues are maintained for 
+ * each 5380 in the system - commands that haven't been issued yet,
+ * and commands that are currently executing.  This means that an 
+ * unlimited number of commands may be queued, letting 
+ * more commands propagate from the higher driver levels giving higher 
+ * throughput.  Note that both I_T_L and I_T_L_Q nexuses are supported, 
+ * allowing multiple commands to propagate all the way to a SCSI-II device 
+ * while a command is already executing.
+ *
+ * To solve the multiple-boards-in-the-same-system problem, 
+ * there is a separate instance structure for each instance
+ * of a 5380 in the system.  So, multiple NCR5380 drivers will
+ * be able to coexist with appropriate changes to the high level
+ * SCSI code.  
+ *
+ * A NCR5380_PUBLIC_REVISION macro is provided, with the release
+ * number (updated for each public release) printed by the 
+ * NCR5380_print_options command, which should be called from the 
+ * wrapper detect function, so that I know what release of the driver
+ * users are using.
+ *
+ * Issues specific to the NCR5380 : 
+ *
+ * When used in a PIO or pseudo-dma mode, the NCR5380 is a braindead 
+ * piece of hardware that requires you to sit in a loop polling for 
+ * the REQ signal as long as you are connected.  Some devices are 
+ * brain dead (ie, many TEXEL CD ROM drives) and won't disconnect 
+ * while doing long seek operations.
+ * 
+ * The workaround for this is to keep track of devices that have
+ * disconnected.  If the device hasn't disconnected, for commands that
+ * should disconnect, we do something like 
+ *
+ * while (!REQ is asserted) { sleep for N usecs; poll for M usecs }
+ * 
+ * Some tweaking of N and M needs to be done.  An algorithm based 
+ * on "time to data" would give the best results as long as short time
+ * to datas (ie, on the same track) were considered, however these 
+ * broken devices are the exception rather than the rule and I'd rather
+ * spend my time optimizing for the normal case.
+ *
+ * Architecture :
+ *
+ * At the heart of the design is a coroutine, NCR5380_main,
+ * which is started when not running by the interrupt handler,
+ * timer, and queue command function.  It attempts to establish
+ * I_T_L or I_T_L_Q nexuses by removing the commands from the 
+ * issue queue and calling NCR5380_select() if a nexus 
+ * is not established. 
+ *
+ * Once a nexus is established, the NCR5380_information_transfer()
+ * phase goes through the various phases as instructed by the target.
+ * if the target goes into MSG IN and sends a DISCONNECT message,
+ * the command structure is placed into the per instance disconnected
+ * queue, and NCR5380_main tries to find more work.  If USLEEP
+ * was defined, and the target is idle for too long, the system
+ * will try to sleep.
+ *
+ * If a command has disconnected, eventually an interrupt will trigger,
+ * calling NCR5380_intr()  which will in turn call NCR5380_reselect
+ * to reestablish a nexus.  This will run main if necessary.
+ *
+ * On command termination, the done function will be called as 
+ * appropriate.
+ *
+ * SCSI pointers are maintained in the SCp field of SCSI command 
+ * structures, being initialized after the command is connected
+ * in NCR5380_select, and set as appropriate in NCR5380_information_transfer.
+ * Note that in violation of the standard, an implicit SAVE POINTERS operation
+ * is done, since some BROKEN disks fail to issue an explicit SAVE POINTERS.
+ */
+
+/*
+ * Using this file :
+ * This file a skeleton Linux SCSI driver for the NCR 5380 series
+ * of chips.  To use it, you write a architecture specific functions 
+ * and macros and include this file in your driver.
+ *
+ * These macros control options : 
+ * AUTOSENSE - if defined, REQUEST SENSE will be performed automatically
+ *	for commands that return with a CHECK CONDITION status. 
+ *
+ * LINKED - if defined, linked commands are supported.
+ *
+ * REAL_DMA - if defined, REAL DMA is used during the data transfer phases.
+ *
+ * SUPPORT_TAGS - if defined, SCSI-2 tagged queuing is used where possible
+ *
+ * These macros MUST be defined :
+ * 
+ * NCR5380_read(register)  - read from the specified register
+ *
+ * NCR5380_write(register, value) - write to the specific register 
+ *
+ * Either real DMA *or* pseudo DMA may be implemented
+ * REAL functions : 
+ * NCR5380_REAL_DMA should be defined if real DMA is to be used.
+ * Note that the DMA setup functions should return the number of bytes 
+ *	that they were able to program the controller for.
+ *
+ * Also note that generic i386/PC versions of these macros are 
+ *	available as NCR5380_i386_dma_write_setup,
+ *	NCR5380_i386_dma_read_setup, and NCR5380_i386_dma_residual.
+ *
+ * NCR5380_dma_write_setup(instance, src, count) - initialize
+ * NCR5380_dma_read_setup(instance, dst, count) - initialize
+ * NCR5380_dma_residual(instance); - residual count
+ *
+ * PSEUDO functions :
+ * NCR5380_pwrite(instance, src, count)
+ * NCR5380_pread(instance, dst, count);
+ *
+ * If nothing specific to this implementation needs doing (ie, with external
+ * hardware), you must also define 
+ *  
+ * NCR5380_queue_command
+ * NCR5380_reset
+ * NCR5380_abort
+ * NCR5380_proc_info
+ *
+ * to be the global entry points into the specific driver, ie 
+ * #define NCR5380_queue_command t128_queue_command.
+ *
+ * If this is not done, the routines will be defined as static functions
+ * with the NCR5380* names and the user must provide a globally
+ * accessible wrapper function.
+ *
+ * The generic driver is initialized by calling NCR5380_init(instance),
+ * after setting the appropriate host specific fields and ID.  If the 
+ * driver wishes to autoprobe for an IRQ line, the NCR5380_probe_irq(instance,
+ * possible) function may be used.  Before the specific driver initialization
+ * code finishes, NCR5380_print_options should be called.
+ */
+
+static struct Scsi_Host *first_instance = NULL;
+static Scsi_Host_Template *the_template = NULL;
+
+/* Macros ease life... :-) */
+#define	SETUP_HOSTDATA(in)				\
+    struct NCR5380_hostdata *hostdata =			\
+	(struct NCR5380_hostdata *)(in)->hostdata
+#define	HOSTDATA(in) ((struct NCR5380_hostdata *)(in)->hostdata)
+
+#define	NEXT(cmd)	((Scsi_Cmnd *)((cmd)->host_scribble))
+#define	NEXTADDR(cmd)	((Scsi_Cmnd **)&((cmd)->host_scribble))
+
+#define	HOSTNO		instance->host_no
+#define	H_NO(cmd)	(cmd)->host->host_no
+
+#ifdef SUPPORT_TAGS
+
+/*
+ * Functions for handling tagged queuing
+ * =====================================
+ *
+ * ++roman (01/96): Now I've implemented SCSI-2 tagged queuing. Some notes:
+ *
+ * Using consecutive numbers for the tags is no good idea in my eyes. There
+ * could be wrong re-usings if the counter (8 bit!) wraps and some early
+ * command has been preempted for a long time. My solution: a bitfield for
+ * remembering used tags.
+ *
+ * There's also the problem that each target has a certain queue size, but we
+ * cannot know it in advance :-( We just see a QUEUE_FULL status being
+ * returned. So, in this case, the driver internal queue size assumption is
+ * reduced to the number of active tags if QUEUE_FULL is returned by the
+ * target. The command is returned to the mid-level, but with status changed
+ * to BUSY, since --as I've seen-- the mid-level can't handle QUEUE_FULL
+ * correctly.
+ *
+ * We're also not allowed running tagged commands as long as an untagged
+ * command is active. And REQUEST SENSE commands after a contingent allegiance
+ * condition _must_ be untagged. To keep track whether an untagged command has
+ * been issued, the host->busy array is still employed, as it is without
+ * support for tagged queuing.
+ *
+ * One could suspect that there are possible race conditions between
+ * is_lun_busy(), cmd_get_tag() and cmd_free_tag(). But I think this isn't the
+ * case: is_lun_busy() and cmd_get_tag() are both called from NCR5380_main(),
+ * which already guaranteed to be running at most once. It is also the only
+ * place where tags/LUNs are allocated. So no other allocation can slip
+ * between that pair, there could only happen a reselection, which can free a
+ * tag, but that doesn't hurt. Only the sequence in cmd_free_tag() becomes
+ * important: the tag bit must be cleared before 'nr_allocated' is decreased.
+ */
+
+/* -1 for TAG_NONE is not possible with unsigned char cmd->tag */
+#undef TAG_NONE
+#define TAG_NONE 0xff
+
+/* For the m68k, the number of bits in 'allocated' must be a multiple of 32! */
+#if (MAX_TAGS % 32) != 0
+#error "MAX_TAGS must be a multiple of 32!"
+#endif
+
+typedef struct {
+    char	allocated[MAX_TAGS/8];
+    int		nr_allocated;
+    int		queue_size;
+} TAG_ALLOC;
+
+static TAG_ALLOC TagAlloc[8][8]; /* 8 targets and 8 LUNs */
+
+
+static void init_tags( void )
+{
+    int target, lun;
+    TAG_ALLOC *ta;
+    
+    if (!setup_use_tagged_queuing)
+	return;
+    
+    for( target = 0; target < 8; ++target ) {
+	for( lun = 0; lun < 8; ++lun ) {
+	    ta = &TagAlloc[target][lun];
+	    memset( &ta->allocated, 0, MAX_TAGS/8 );
+	    ta->nr_allocated = 0;
+	    /* At the beginning, assume the maximum queue size we could
+	     * support (MAX_TAGS). This value will be decreased if the target
+	     * returns QUEUE_FULL status.
+	     */
+	    ta->queue_size = MAX_TAGS;
+	}
+    }
+}
+
+
+/* Check if we can issue a command to this LUN: First see if the LUN is marked
+ * busy by an untagged command. If the command should use tagged queuing, also
+ * check that there is a free tag and the target's queue won't overflow. This
+ * function should be called with interrupts disabled to avoid race
+ * conditions.
+ */ 
+
+static int is_lun_busy( Scsi_Cmnd *cmd, int should_be_tagged )
+{
+    SETUP_HOSTDATA(cmd->host);
+
+    if (hostdata->busy[cmd->target] & (1 << cmd->lun))
+	return( 1 );
+    if (!should_be_tagged ||
+	!setup_use_tagged_queuing || !cmd->device->tagged_supported)
+	return( 0 );
+    if (TagAlloc[cmd->target][cmd->lun].nr_allocated >=
+	TagAlloc[cmd->target][cmd->lun].queue_size ) {
+#if (NDEBUG & NDEBUG_TAGS)
+	printk( "scsi%d: target %d lun %d: no free tags\n",
+		H_NO(cmd), cmd->target, cmd->lun );
+#endif
+	return( 1 );
+    }
+    return( 0 );
+}
+
+
+/* Allocate a tag for a command (there are no checks anymore, check_lun_busy()
+ * must be called before!), or reserve the LUN in 'busy' if the command is
+ * untagged.
+ */
+
+static void cmd_get_tag( Scsi_Cmnd *cmd, int should_be_tagged )
+{
+    SETUP_HOSTDATA(cmd->host);
+
+    /* If we or the target don't support tagged queuing, allocate the LUN for
+     * an untagged command.
+     */
+    if (!should_be_tagged ||
+	!setup_use_tagged_queuing || !cmd->device->tagged_supported) {
+	cmd->tag = TAG_NONE;
+	hostdata->busy[cmd->target] |= (1 << cmd->lun);
+#if (NDEBUG & NDEBUG_TAGS)
+	printk( "scsi%d: target %d lun %d now allocated by untagged command\n",
+		H_NO(cmd), cmd->target, cmd->lun );
+#endif
+    }
+    else {
+	TAG_ALLOC *ta = &TagAlloc[cmd->target][cmd->lun];
+
+	cmd->tag = find_first_zero_bit( &ta->allocated, MAX_TAGS );
+	set_bit( cmd->tag, &ta->allocated );
+	ta->nr_allocated++;
+#if (NDEBUG & NDEBUG_TAGS)
+	printk( "scsi%d: using tag %d for target %d lun %d "
+		"(now %d tags in use)\n",
+		H_NO(cmd), cmd->tag, cmd->target, cmd->lun,
+		ta->nr_allocated );
+#endif
+    }
+}
+
+
+/* Mark the tag of command 'cmd' as free, or in case of an untagged command,
+ * unlock the LUN.
+ */
+
+static void cmd_free_tag( Scsi_Cmnd *cmd )
+{
+    SETUP_HOSTDATA(cmd->host);
+
+    if (cmd->tag == TAG_NONE) {
+	hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
+#if (NDEBUG & NDEBUG_TAGS)
+	printk( "scsi%d: target %d lun %d untagged cmd finished\n",
+		H_NO(cmd), cmd->target, cmd->lun );
+#endif
+    }
+    else if (cmd->tag >= MAX_TAGS) {
+	printk( "scsi%d: trying to free bad tag %d!\n",
+		H_NO(cmd), cmd->tag );
+    }
+    else {
+	TAG_ALLOC *ta = &TagAlloc[cmd->target][cmd->lun];
+	clear_bit( cmd->tag, &ta->allocated );
+	ta->nr_allocated--;
+#if (NDEBUG & NDEBUG_TAGS)
+	printk( "scsi%d: freed tag %d for target %d lun %d\n",
+		H_NO(cmd), cmd->tag, cmd->target, cmd->lun );
+#endif
+    }
+}
+
+
+#if 0
+static void free_all_tags( void )
+{
+    int target, lun;
+    TAG_ALLOC *ta;
+
+    if (!setup_use_tagged_queuing)
+	return;
+    
+    for( target = 0; target < 8; ++target ) {
+	for( lun = 0; lun < 8; ++lun ) {
+	    ta = &TagAlloc[target][lun];
+	    memset( &ta->allocated, 0, MAX_TAGS/8 );
+	    ta->nr_allocated = 0;
+	}
+    }
+}
+#endif
+
+#endif /* SUPPORT_TAGS */
+
+
+/*
+ * Function: void merge_consecutive_buffers( Scsi_Cmnd *cmd )
+ *
+ * Purpose: Try to merge several scatter-gather requests into one DMA
+ *    transfer. This is possible if the scatter buffers lie on
+ *    physical consecutive addresses.
+ *
+ * Parameters: Scsi_Cmnd *cmd
+ *    The command to work on. The first scatter buffer's data are
+ *    assumed to be already transfered into ptr/this_residual.
+ */
+
+/* A special issue is when the buffer is exactly at the end of the
+ * last physical memory chunk: VTOP would have to calculate the
+ * physical address just 1 byte behind the end of physical memory. But
+ * it will panic if given this address :-( So we need to avoid calling
+ * VTOP on addresses that don't exist. This is done by keeping
+ * 'endadr' to be the real end address of the buffer, not one byte
+ * more (which would be easier).
+ */
+
+static void merge_consecutive_buffers( Scsi_Cmnd *cmd )
+{
+    unsigned long endadr;
+#if (NDEBUG & NDEBUG_MERGING)
+    unsigned long oldlen = cmd->SCp.this_residual;
+    int		  cnt = 1;
+#endif
+
+    for( endadr = VTOP(cmd->SCp.ptr + cmd->SCp.this_residual - 1);
+	 cmd->SCp.buffers_residual &&
+	 VTOP( (cmd->SCp.buffer+1)->address ) == endadr + 1; ) {
+	
+#if (NDEBUG & NDEBUG_MERGING)
+	printk( "%08lx == %08lx -> merging\n",
+		VTOP( (cmd->SCp.buffer+1)->address ), endadr );
+	++cnt;
+#endif
+	++cmd->SCp.buffer;
+	--cmd->SCp.buffers_residual;
+	cmd->SCp.this_residual += cmd->SCp.buffer->length;
+	endadr += cmd->SCp.buffer->length;
+    }
+#if (NDEBUG & NDEBUG_MERGING)
+    if (oldlen != cmd->SCp.this_residual)
+	printk( "merged %d buffers from %08lx, new length %08lx\n",
+		cnt, (long)(cmd->SCp.ptr), cmd->SCp.this_residual );
+#endif
+}
+
+/*
+ * Function : void initialize_SCp(Scsi_Cmnd *cmd)
+ *
+ * Purpose : initialize the saved data pointers for cmd to point to the 
+ *	start of the buffer.
+ *
+ * Inputs : cmd - Scsi_Cmnd structure to have pointers reset.
+ */
+
+static __inline__ void initialize_SCp(Scsi_Cmnd *cmd)
+{
+    /* 
+     * Initialize the Scsi Pointer field so that all of the commands in the 
+     * various queues are valid.
+     */
+
+    if (cmd->use_sg) {
+	cmd->SCp.buffer = (struct scatterlist *) cmd->buffer;
+	cmd->SCp.buffers_residual = cmd->use_sg - 1;
+	cmd->SCp.ptr = (char *) cmd->SCp.buffer->address;
+	cmd->SCp.this_residual = cmd->SCp.buffer->length;
+	/* ++roman: Try to merge some scatter-buffers if they are at
+	 * consecutive physical addresses.
+	 */
+	merge_consecutive_buffers( cmd );
+    } else {
+	cmd->SCp.buffer = NULL;
+	cmd->SCp.buffers_residual = 0;
+	cmd->SCp.ptr = (char *) cmd->request_buffer;
+	cmd->SCp.this_residual = cmd->request_bufflen;
+    }
+}
+
+#include <linux/config.h>
+#include <linux/delay.h>
+
+#ifdef NDEBUG
+static struct {
+    unsigned char mask;
+    const char * name;} 
+signals[] = {{ SR_DBP, "PARITY"}, { SR_RST, "RST" }, { SR_BSY, "BSY" }, 
+    { SR_REQ, "REQ" }, { SR_MSG, "MSG" }, { SR_CD,  "CD" }, { SR_IO, "IO" }, 
+    { SR_SEL, "SEL" }, {0, NULL}}, 
+basrs[] = {{BASR_ATN, "ATN"}, {BASR_ACK, "ACK"}, {0, NULL}},
+icrs[] = {{ICR_ASSERT_RST, "ASSERT RST"},{ICR_ASSERT_ACK, "ASSERT ACK"},
+    {ICR_ASSERT_BSY, "ASSERT BSY"}, {ICR_ASSERT_SEL, "ASSERT SEL"}, 
+    {ICR_ASSERT_ATN, "ASSERT ATN"}, {ICR_ASSERT_DATA, "ASSERT DATA"}, 
+    {0, NULL}},
+mrs[] = {{MR_BLOCK_DMA_MODE, "MODE BLOCK DMA"}, {MR_TARGET, "MODE TARGET"}, 
+    {MR_ENABLE_PAR_CHECK, "MODE PARITY CHECK"}, {MR_ENABLE_PAR_INTR, 
+    "MODE PARITY INTR"}, {MR_ENABLE_EOP_INTR,"MODE EOP INTR"},
+    {MR_MONITOR_BSY, "MODE MONITOR BSY"},
+    {MR_DMA_MODE, "MODE DMA"}, {MR_ARBITRATE, "MODE ARBITRATION"}, 
+    {0, NULL}};
+
+/*
+ * Function : void NCR5380_print(struct Scsi_Host *instance)
+ *
+ * Purpose : print the SCSI bus signals for debugging purposes
+ *
+ * Input : instance - which NCR5380
+ */
+
+static void NCR5380_print(struct Scsi_Host *instance) {
+    unsigned char status, data, basr, mr, icr, i;
+    unsigned long flags;
+
+    save_flags(flags);
+    cli();
+    data = NCR5380_read(CURRENT_SCSI_DATA_REG);
+    status = NCR5380_read(STATUS_REG);
+    mr = NCR5380_read(MODE_REG);
+    icr = NCR5380_read(INITIATOR_COMMAND_REG);
+    basr = NCR5380_read(BUS_AND_STATUS_REG);
+    restore_flags(flags);
+    printk("STATUS_REG: %02x ", status);
+    for (i = 0; signals[i].mask ; ++i) 
+	if (status & signals[i].mask)
+	    printk(",%s", signals[i].name);
+    printk("\nBASR: %02x ", basr);
+    for (i = 0; basrs[i].mask ; ++i) 
+	if (basr & basrs[i].mask)
+	    printk(",%s", basrs[i].name);
+    printk("\nICR: %02x ", icr);
+    for (i = 0; icrs[i].mask; ++i) 
+	if (icr & icrs[i].mask)
+	    printk(",%s", icrs[i].name);
+    printk("\nMODE: %02x ", mr);
+    for (i = 0; mrs[i].mask; ++i) 
+	if (mr & mrs[i].mask)
+	    printk(",%s", mrs[i].name);
+    printk("\n");
+}
+
+static struct {
+    unsigned char value;
+    const char *name;
+} phases[] = {
+    {PHASE_DATAOUT, "DATAOUT"}, {PHASE_DATAIN, "DATAIN"}, {PHASE_CMDOUT, "CMDOUT"},
+    {PHASE_STATIN, "STATIN"}, {PHASE_MSGOUT, "MSGOUT"}, {PHASE_MSGIN, "MSGIN"},
+    {PHASE_UNKNOWN, "UNKNOWN"}};
+
+/* 
+ * Function : void NCR5380_print_phase(struct Scsi_Host *instance)
+ *
+ * Purpose : print the current SCSI phase for debugging purposes
+ *
+ * Input : instance - which NCR5380
+ */
+
+static void NCR5380_print_phase(struct Scsi_Host *instance)
+{
+    unsigned char status;
+    int i;
+
+    status = NCR5380_read(STATUS_REG);
+    if (!(status & SR_REQ)) 
+	printk("scsi%d: REQ not asserted, phase unknown.\n", HOSTNO);
+    else {
+	for (i = 0; (phases[i].value != PHASE_UNKNOWN) && 
+	    (phases[i].value != (status & PHASE_MASK)); ++i); 
+	printk("scsi%d: phase %s\n", HOSTNO, phases[i].name);
+    }
+}
+#endif
+
+/*
+ * We need to have our coroutine active given these constraints : 
+ * 1.  The mutex flag, main_running, can only be set when the main 
+ *     routine can actually process data, otherwise SCSI commands
+ *     will never get issued.
+ *
+ * 2.  NCR5380_main() shouldn't be called before it has exited, because
+ *     other drivers have had kernel stack overflows in similar
+ *     situations.
+ *
+ * 3.  We don't want to inline NCR5380_main() because of space concerns,
+ *     even though it is only called in two places.
+ *
+ * So, the solution is to set the mutex in an inline wrapper for the 
+ * main coroutine, and have the main coroutine exit with interrupts 
+ * disabled after the final search through the queues so that no race 
+ * conditions are possible.
+ */
+
+static volatile int main_running = 0;
+
+/* 
+ * Function : run_main(void)
+ * 
+ * Purpose : insure that the coroutine is running and will process our 
+ * 	request.  main_running is checked/set here (in an inline function)
+ *	rather than in NCR5380_main itself to reduce the chances of stack
+ *	overflow.
+ *
+ */
+
+static void NCR5380_main_a ( unsigned long flags );
+
+static __inline__ void run_main(void)
+{
+    unsigned long flags;
+
+    save_flags(flags);
+    cli();
+    if (!main_running) {
+	main_running = 1;
+        NCR5380_main_a( flags );
+	/* 
+         * main_running is cleared in NCR5380_main once it can't do 
+	 * more work, and NCR5380_main exits with interrupts disabled.
+	 */
+    }
+    restore_flags(flags);
+}
+
+
+static void NCR5380_all_init (void)
+{
+    static int done = 0;
+    if (!done) {
+#if (NDEBUG & NDEBUG_INIT)
+	printk("scsi : NCR5380_all_init()\n");
+#endif
+	done = 1;
+    }
+}
+
+ 
+/*
+ * Function : void NCR58380_print_options (struct Scsi_Host *instance)
+ *
+ * Purpose : called by probe code indicating the NCR5380 driver
+ *	     options that were selected.
+ *
+ * Inputs : instance, pointer to this instance.  Unused.
+ */
+
+static void NCR5380_print_options (struct Scsi_Host *instance)
+{
+    printk(" generic options"
+#ifdef AUTOSENSE 
+    " AUTOSENSE"
+#endif
+#ifdef REAL_DMA
+    " REAL DMA"
+#endif
+#ifdef PARITY
+    " PARITY"
+#endif
+#ifdef SUPPORT_TAGS
+    " SCSI-2 TAGGED QUEUING"
+#endif
+    );
+    printk(" generic release=%d", NCR5380_PUBLIC_RELEASE);
+}
+
+/*
+ * Function : void NCR5380_print_status (struct Scsi_Host *instance)
+ *
+ * Purpose : print commands in the various queues, called from
+ *	NCR5380_abort and NCR5380_debug to aid debugging.
+ *
+ * Inputs : instance, pointer to this instance.  
+ */
+
+static void NCR5380_print_status (struct Scsi_Host *instance)
+{
+    char pr_bfr[256];
+    char *start;
+    int len;
+
+    printk("NCR5380: coroutine is%s running.\n",
+	main_running ? "" : "n't");
+    
+#ifdef NDEBUG
+    NCR5380_print (instance);
+    NCR5380_print_phase (instance);
+#endif
+
+    len = NCR5380_proc_info(pr_bfr, &start, 0, sizeof(pr_bfr), HOSTNO, 0);
+    pr_bfr[len] = 0;
+    printk("\n%s\n", pr_bfr);
+}
+
+
+/******************************************/
+/*
+ * /proc/scsi/[dtc pas16 t128 generic]/[0-ASC_NUM_BOARD_SUPPORTED]
+ *
+ * *buffer: I/O buffer
+ * **start: if inout == FALSE pointer into buffer where user read should start
+ * offset: current offset
+ * length: length of buffer
+ * hostno: Scsi_Host host_no
+ * inout: TRUE - user is writing; FALSE - user is reading
+ *
+ * Return the number of bytes read from or written
+*/
+
+#undef SPRINTF
+#define SPRINTF(args...) do { if(pos < buffer + length) pos += sprintf(pos, ## args); } while(0)
+static
+char *lprint_Scsi_Cmnd (Scsi_Cmnd *cmd, char *pos, char *buffer, int length);
+static
+char *lprint_command (unsigned char *cmd, char *pos, char *buffer, int len);
+static
+char *lprint_opcode(int opcode, char *pos, char *buffer, int length);
+
+#ifndef NCR5380_proc_info
+static
+#endif
+int NCR5380_proc_info (char *buffer, char **start, off_t offset,
+		       int length, int hostno, int inout)
+{
+    char *pos = buffer;
+    struct Scsi_Host *instance;
+    struct NCR5380_hostdata *hostdata;
+    Scsi_Cmnd *ptr;
+    unsigned long flags;
+
+    for (instance = first_instance; instance && HOSTNO != hostno;
+	 instance = instance->next)
+	;
+    if (!instance)
+	return(-ESRCH);
+    hostdata = (struct NCR5380_hostdata *)instance->hostdata;
+
+    if (inout) { /* Has data been written to the file ? */
+	return(-ENOSYS);  /* Currently this is a no-op */
+    }
+    SPRINTF("NCR5380 core release=%d.\n", NCR5380_PUBLIC_RELEASE);
+    save_flags(flags);
+    cli();
+    SPRINTF("NCR5380: coroutine is%s running.\n", main_running ? "" : "n't");
+    if (!hostdata->connected)
+	SPRINTF("scsi%d: no currently connected command\n", HOSTNO);
+    else
+	pos = lprint_Scsi_Cmnd ((Scsi_Cmnd *) hostdata->connected,
+				pos, buffer, length);
+    SPRINTF("scsi%d: issue_queue\n", HOSTNO);
+    for (ptr = (Scsi_Cmnd *) hostdata->issue_queue; ptr; ptr = NEXT(ptr))
+	pos = lprint_Scsi_Cmnd (ptr, pos, buffer, length);
+
+    SPRINTF("scsi%d: disconnected_queue\n", HOSTNO);
+    for (ptr = (Scsi_Cmnd *) hostdata->disconnected_queue; ptr;
+	 ptr = NEXT(ptr))
+	pos = lprint_Scsi_Cmnd (ptr, pos, buffer, length);
+
+    restore_flags(flags);
+    *start = buffer;
+    if (pos - buffer < offset)
+	return 0;
+    else if (pos - buffer - offset < length)
+	return pos - buffer - offset;
+    return length;
+}
+
+static char *
+lprint_Scsi_Cmnd (Scsi_Cmnd *cmd, char *pos, char *buffer, int length)
+{
+    SPRINTF("scsi%d: destination target %d, lun %d\n",
+	    H_NO(cmd), cmd->target, cmd->lun);
+    SPRINTF("        command = ");
+    pos = lprint_command (cmd->cmnd, pos, buffer, length);
+    return (pos);
+}
+
+static char *
+lprint_command (unsigned char *command, char *pos, char *buffer, int length)
+{
+    int i, s;
+    pos = lprint_opcode(command[0], pos, buffer, length);
+    for (i = 1, s = COMMAND_SIZE(command[0]); i < s; ++i)
+	SPRINTF("%02x ", command[i]);
+    SPRINTF("\n");
+    return(pos);
+}
+
+static 
+char *lprint_opcode(int opcode, char *pos, char *buffer, int length)
+{
+    SPRINTF("%2d (0x%02x)", opcode, opcode);
+    return(pos);
+}
+
+
+/* 
+ * Function : void NCR5380_init (struct Scsi_Host *instance)
+ *
+ * Purpose : initializes *instance and corresponding 5380 chip.
+ *
+ * Inputs : instance - instantiation of the 5380 driver.  
+ *
+ * Notes : I assume that the host, hostno, and id bits have been
+ * 	set correctly.  I don't care about the irq and other fields. 
+ * 
+ */
+
+static void NCR5380_init (struct Scsi_Host *instance, int flags)
+{
+    int i;
+    SETUP_HOSTDATA(instance);
+
+    NCR5380_all_init();
+
+    hostdata->aborted = 0;
+    hostdata->id_mask = 1 << instance->this_id;
+    hostdata->id_higher_mask = 0;
+    for (i = hostdata->id_mask; i <= 0x80; i <<= 1)
+	if (i > hostdata->id_mask)
+	    hostdata->id_higher_mask |= i;
+    for (i = 0; i < 8; ++i)
+	hostdata->busy[i] = 0;
+#ifdef SUPPORT_TAGS
+    init_tags();
+#endif
+#if defined (REAL_DMA)
+    hostdata->dma_len = 0;
+#endif
+    hostdata->targets_present = 0;
+    hostdata->connected = NULL;
+    hostdata->issue_queue = NULL;
+    hostdata->disconnected_queue = NULL;
+    hostdata->flags = FLAG_CHECK_LAST_BYTE_SENT;
+
+    if (!the_template) {
+	the_template = instance->hostt;
+	first_instance = instance;
+    }
+	
+
+#ifndef AUTOSENSE
+    if ((instance->cmd_per_lun > 1) || instance->can_queue > 1)) 
+	 printk("scsi%d: WARNING : support for multiple outstanding commands enabled\n"
+	        "        without AUTOSENSE option, contingent allegiance conditions may\n"
+	        "        be incorrectly cleared.\n", HOSTNO);
+#endif /* def AUTOSENSE */
+
+    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+    NCR5380_write(MODE_REG, MR_BASE);
+    NCR5380_write(TARGET_COMMAND_REG, 0);
+    NCR5380_write(SELECT_ENABLE_REG, 0);
+}
+
+/* 
+ * Function : int NCR5380_queue_command (Scsi_Cmnd *cmd, 
+ *	void (*done)(Scsi_Cmnd *)) 
+ *
+ * Purpose :  enqueues a SCSI command
+ *
+ * Inputs : cmd - SCSI command, done - function called on completion, with
+ *	a pointer to the command descriptor.
+ * 
+ * Returns : 0
+ *
+ * Side effects : 
+ *      cmd is added to the per instance issue_queue, with minor 
+ *	twiddling done to the host specific fields of cmd.  If the 
+ *	main coroutine is not running, it is restarted.
+ *
+ */
+
+/* Only make static if a wrapper function is used */
+#ifndef NCR5380_queue_command
+static
+#endif
+int NCR5380_queue_command (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
+{
+    SETUP_HOSTDATA(cmd->host);
+    Scsi_Cmnd *tmp;
+    int oldto;
+    unsigned long flags;
+    extern int scsi_update_timeout(Scsi_Cmnd * SCset, int timeout);
+
+#if (NDEBUG & NDEBUG_NO_WRITE)
+    switch (cmd->cmnd[0]) {
+    case WRITE_6:
+    case WRITE_10:
+	printk("scsi%d: WRITE attempted with NO_WRITE debugging flag set\n",
+	       H_NO(cmd));
+	cmd->result = (DID_ERROR << 16);
+	done(cmd);
+	return 0;
+    }
+#endif /* (NDEBUG & NDEBUG_NO_WRITE) */
+
+
+#ifdef NCR5380_STATS
+# if 0
+    if (!hostdata->connected && !hostdata->issue_queue &&
+	!hostdata->disconnected_queue) {
+	hostdata->timebase = jiffies;
+    }
+# endif
+# ifdef NCR5380_STAT_LIMIT
+    if (cmd->request_bufflen > NCR5380_STAT_LIMIT)
+# endif
+	switch (cmd->cmnd[0])
+	{
+	    case WRITE:
+	    case WRITE_6:
+	    case WRITE_10:
+		hostdata->time_write[cmd->target] -= (jiffies - hostdata->timebase);
+		hostdata->bytes_write[cmd->target] += cmd->request_bufflen;
+		hostdata->pendingw++;
+		break;
+	    case READ:
+	    case READ_6:
+	    case READ_10:
+		hostdata->time_read[cmd->target] -= (jiffies - hostdata->timebase);
+		hostdata->bytes_read[cmd->target] += cmd->request_bufflen;
+		hostdata->pendingr++;
+		break;
+	}
+#endif
+
+    /* 
+     * We use the host_scribble field as a pointer to the next command  
+     * in a queue 
+     */
+
+    NEXT(cmd) = NULL;
+    cmd->scsi_done = done;
+
+    cmd->result = 0;
+
+
+    /* 
+     * Insert the cmd into the issue queue. Note that REQUEST SENSE 
+     * commands are added to the head of the queue since any command will
+     * clear the contingent allegiance condition that exists and the 
+     * sense data is only guaranteed to be valid while the condition exists.
+     */
+
+    save_flags(flags);
+    cli();
+    /* ++guenther: now that the issue queue is being set up, we can lock ST-DMA.
+     * Otherwise a running NCR5380_main may steal the lock.
+     * Lock before actually inserting due to fairness reasons explained in
+     * atari_scsi.c. If we insert first, then it's impossible for this driver
+     * to release the lock.
+     * Stop timer for this command while waiting for the lock, or timeouts
+     * may happen (and they really do), and it's no good if the command doesn't
+     * appear in any of the queues.
+     * ++roman: Just disabling the NCR interrupt isn't sufficient here,
+     * because also a timer int can trigger an abort or reset, which would
+     * alter queues and touch the lock.
+     */
+    if (!IS_A_TT()) {
+	oldto = scsi_update_timeout(cmd, 0);
+	falcon_get_lock();
+	scsi_update_timeout(cmd, oldto);
+    }
+    if (!(hostdata->issue_queue) || (cmd->cmnd[0] == REQUEST_SENSE)) {
+	LIST(cmd, hostdata->issue_queue);
+	NEXT(cmd) = hostdata->issue_queue;
+	hostdata->issue_queue = cmd;
+    } else {
+	for (tmp = (Scsi_Cmnd *)hostdata->issue_queue;
+	     NEXT(tmp); tmp = NEXT(tmp))
+	    ;
+	LIST(cmd, tmp);
+	NEXT(tmp) = cmd;
+    }
+    restore_flags(flags);
+
+#if (NDEBUG & NDEBUG_QUEUES)
+    printk("scsi%d: command added to %s of queue\n", H_NO(cmd),
+	(cmd->cmnd[0] == REQUEST_SENSE) ? "head" : "tail");
+#endif
+
+/* Run the coroutine if it isn't already running. */
+    run_main();
+    return 0;
+}
+
+/*
+ * Function : NCR5380_main (void) 
+ *
+ * Purpose : NCR5380_main is a coroutine that runs as long as more work can 
+ *	be done on the NCR5380 host adapters in a system.  Both 
+ *	NCR5380_queue_command() and NCR5380_intr() will try to start it 
+ *	in case it is not running.
+ * 
+ * NOTE : NCR5380_main exits with interrupts *disabled*, the caller should 
+ *  reenable them.  This prevents reentrancy and kernel stack overflow.
+ */ 	
+    
+static inline void NCR5380_main () {}
+
+static void NCR5380_main_a ( unsigned long flags )
+{
+    Scsi_Cmnd *tmp, *prev;
+    struct Scsi_Host *instance = first_instance;
+    struct NCR5380_hostdata *hostdata = HOSTDATA(instance);
+    int done;
+    
+    /*
+     * We run (with interrupts disabled) until we're sure that none of 
+     * the host adapters have anything that can be done, at which point 
+     * we set main_running to 0 and exit.
+     *
+     * Interrupts are enabled before doing various other internal 
+     * instructions, after we've decided that we need to run through
+     * the loop again.
+     *
+     * this should prevent any race conditions.
+     * 
+     * ++roman: Just disabling the NCR interrupt isn't sufficient here,
+     * because also a timer int can trigger an abort or reset, which can
+     * alter queues and touch the Falcon lock.
+     */
+
+    do {
+	cli(); /* Freeze request queues */
+	done = 1;
+	
+	if (!hostdata->connected) {
+#if (NDEBUG & NDEBUG_MAIN)
+	    printk("scsi%d: not connected\n", HOSTNO);
+#endif
+	    /*
+	     * Search through the issue_queue for a command destined
+	     * for a target that's not busy.
+	     */
+#if (NDEBUG & NDEBUG_LISTS)
+	    for (tmp = (Scsi_Cmnd *) hostdata->issue_queue, prev = NULL;
+		 tmp && (tmp != prev); prev = tmp, tmp = NEXT(tmp))
+		;
+		/*printk("%p  ", tmp);*/
+	    if ((tmp == prev) && tmp) printk(" LOOP\n");/* else printk("\n");*/
+#endif
+	    for (tmp = (Scsi_Cmnd *) hostdata->issue_queue, 
+		 prev = NULL; tmp; prev = tmp, tmp = NEXT(tmp) ) {
+
+#if (NDEBUG & NDEBUG_LISTS)
+		if (prev != tmp)
+		    printk("MAIN tmp=%p   target=%d   busy=%d lun=%d\n",
+			   tmp, tmp->target, hostdata->busy[tmp->target],
+			   tmp->lun);
+#endif
+		/*  When we find one, remove it from the issue queue. */
+		/* ++guenther: possible race with Falcon locking */
+		if (
+#ifdef SUPPORT_TAGS
+		    !is_lun_busy( tmp, tmp->cmnd[0] != REQUEST_SENSE)
+#else
+		    !(hostdata->busy[tmp->target] & (1 << tmp->lun))
+#endif
+		    ) {
+		    cli(); /* ++guenther: just to be sure, this must be atomic */
+		    if (prev) {
+		        REMOVE(prev, NEXT(prev), tmp, NEXT(tmp));
+			NEXT(prev) = NEXT(tmp);
+		    } else {
+		        REMOVE(-1, hostdata->issue_queue, tmp, NEXT(tmp));
+			hostdata->issue_queue = NEXT(tmp);
+		    }
+		    NEXT(tmp) = NULL;
+		    falcon_dont_release++;
+		    
+		    /* reenable interrupts after finding one */
+		    restore_flags(flags);
+		    
+		    /* 
+		     * Attempt to establish an I_T_L nexus here. 
+		     * On success, instance->hostdata->connected is set.
+		     * On failure, we must add the command back to the
+		     *   issue queue so we can keep trying.	
+		     */
+#if (NDEBUG & (NDEBUG_MAIN | NDEBUG_QUEUES))
+		    printk("scsi%d: main(): command for target %d lun %d "
+			   "removed from issue_queue\n",
+			   HOSTNO, tmp->target, tmp->lun);
+#endif
+		    /* 
+		     * REQUEST SENSE commands are issued without tagged
+		     * queueing, even on SCSI-II devices because the 
+		     * contingent allegiance condition exists for the 
+		     * entire unit.
+		     */
+		    /* ++roman: ...and the standard also requires that
+		     * REQUEST SENSE command are untagged.
+		     */
+		    
+#ifdef SUPPORT_TAGS
+		    cmd_get_tag( tmp, tmp->cmnd[0] != REQUEST_SENSE );
+#endif
+		    if (!NCR5380_select(instance, tmp, 
+			    (tmp->cmnd[0] == REQUEST_SENSE) ? TAG_NONE : 
+			    TAG_NEXT)) {
+			falcon_dont_release--;
+			/* release if target did not response! */
+			falcon_release_lock_if_possible( hostdata );
+			break;
+		    } else {
+			cli();
+			LIST(tmp, hostdata->issue_queue);
+			NEXT(tmp) = hostdata->issue_queue;
+			hostdata->issue_queue = tmp;
+#ifdef SUPPORT_TAGS
+			cmd_free_tag( tmp );
+#endif
+			falcon_dont_release--;
+			restore_flags(flags);
+#if (NDEBUG & (NDEBUG_MAIN | NDEBUG_QUEUES))
+			printk("scsi%d: main(): select() failed, "
+			       "returned to issue_queue\n", HOSTNO);
+#endif
+			if (hostdata->connected)
+			    break;
+		    }
+		} /* if target/lun/target queue is not busy */
+	    } /* for issue_queue */
+	} /* if (!hostdata->connected) */
+		
+	if (hostdata->connected 
+#ifdef REAL_DMA
+	    && !hostdata->dma_len
+#endif
+	    ) {
+	    restore_flags(flags);
+#if (NDEBUG & NDEBUG_MAIN)
+	    printk("scsi%d: main() : performing information transfer\n",
+		   HOSTNO);
+#endif
+	    NCR5380_information_transfer(instance);
+#if (NDEBUG & NDEBUG_MAIN)
+	    printk("scsi%d: main() : done set false\n", HOSTNO);
+#endif
+	    done = 0;
+	} else {
+	    cli(); /* ++guenther: be sure to protect main_running */
+	    break;
+	}
+    } while (!done);
+    main_running = 0;
+}
+
+
+#ifdef REAL_DMA
+/*
+ * Function : void NCR5380_dma_complete (struct Scsi_Host *instance)
+ *
+ * Purpose : Called by interrupt handler when DMA finishes or a phase
+ *	mismatch occurs (which would finish the DMA transfer).  
+ *
+ * Inputs : instance - this instance of the NCR5380.
+ *
+ */
+
+static void NCR5380_dma_complete( struct Scsi_Host *instance )
+{
+    SETUP_HOSTDATA(instance);
+    int           transfered, saved_data = 0, overrun = 0, cnt, toPIO;
+    unsigned char **data, p;
+    volatile int  *count;
+
+    if (!hostdata->connected) {
+	printk("scsi%d: received end of DMA interrupt with no connected cmd\n",
+	       HOSTNO);
+	return;
+    }
+    
+    if (atari_read_overruns) {
+	p = hostdata->connected->SCp.phase;
+	if (p & SR_IO) {
+	    udelay(10);
+	    if ((((NCR5380_read(BUS_AND_STATUS_REG)) &
+		  (BASR_PHASE_MATCH|BASR_ACK)) ==
+		 (BASR_PHASE_MATCH|BASR_ACK))) {
+		saved_data = NCR5380_read(INPUT_DATA_REG);
+		overrun = 1;
+#if (NDEBUG & NDEBUG_DMA)
+		printk( "scsi%d: read overrun handled\n", HOSTNO );
+#endif
+	    }
+	}
+    }
+
+#if (NDEBUG & NDEBUG_DMA)
+    printk("scsi%d: real DMA transfer complete, basr 0x%X, sr 0x%X\n",
+	   HOSTNO, NCR5380_read(BUS_AND_STATUS_REG),
+	   NCR5380_read(STATUS_REG));
+#endif
+
+    (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+    NCR5380_write(MODE_REG, MR_BASE);
+    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+
+    transfered = hostdata->dma_len - NCR5380_dma_residual(instance);
+    hostdata->dma_len = 0;
+
+    data = (unsigned char **) &(hostdata->connected->SCp.ptr);
+    count = &(hostdata->connected->SCp.this_residual);
+    *data += transfered;
+    *count -= transfered;
+
+    if (atari_read_overruns) {
+	if ((NCR5380_read(STATUS_REG) & PHASE_MASK) == p && (p & SR_IO)) {
+	    cnt = toPIO = atari_read_overruns;
+	    if (overrun) {
+#if (NDEBUG & NDEBUG_DMA)
+		printk("Got an input overrun, using saved byte\n");
+#endif
+		*(*data)++ = saved_data;
+		(*count)--;
+		cnt--;
+		toPIO--;
+	    }
+#if (NDEBUG & NDEBUG_DMA)
+	    printk( "Doing %d-byte PIO to 0x%08lx\n", cnt, (long)*data );
+#endif
+
+	    NCR5380_transfer_pio(instance, &p, &cnt, data);
+	    *count -= toPIO - cnt;
+	}
+    }
+}
+#endif /* REAL_DMA */
+
+
+/*
+ * Function : void NCR5380_intr (int irq)
+ * 
+ * Purpose : handle interrupts, reestablishing I_T_L or I_T_L_Q nexuses
+ *	from the disconnected queue, and restarting NCR5380_main() 
+ *	as required.
+ *
+ * Inputs : int irq, irq that caused this interrupt.
+ *
+ */
+
+static void NCR5380_intr (int irq, void *dev_id, struct pt_regs *regs)
+{
+    struct Scsi_Host *instance = first_instance;
+    int done = 1;
+    unsigned char basr;
+
+#if (NDEBUG & NDEBUG_INTR)
+    printk("scsi%d: NCR5380 irq triggered\n", HOSTNO);
+#endif
+
+    /* Look for pending interrupts */
+    basr = NCR5380_read(BUS_AND_STATUS_REG);
+#if (NDEBUG & NDEBUG_INTR)
+    printk( "scsi%d: BASR=%02x\n", HOSTNO, basr );
+#endif
+    /* dispatch to appropriate routine if found and done=0 */
+    if (basr & BASR_IRQ) {
+#if (NDEBUG & NDEBUG_INTR)
+	NCR5380_print(instance);
+#endif
+	if ((NCR5380_read(STATUS_REG) & (SR_SEL|SR_IO)) == (SR_SEL|SR_IO)) {
+	    done = 0;
+	    ENABLE_IRQ();
+#if (NDEBUG & NDEBUG_INTR)
+	    printk("scsi%d: SEL interrupt\n", HOSTNO);
+#endif
+	    NCR5380_reselect(instance);
+	    (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+	}
+	else if (basr & BASR_PARITY_ERROR) {
+#if (NDEBUG & NDEBUG_INTR)
+	    printk("scsi%d: PARITY interrupt\n", HOSTNO);
+#endif
+	    (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+	}
+	else if ((NCR5380_read(STATUS_REG) & SR_RST) == SR_RST) {
+#if (NDEBUG & NDEBUG_INTR)
+	    printk("scsi%d: RESET interrupt\n", HOSTNO);
+#endif
+	    (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+	}
+	else {
+	    /*  
+	     * The rest of the interrupt conditions can occur only during a
+	     * DMA transfer
+	     */
+
+#if defined(REAL_DMA)
+	    /*
+	     * We should only get PHASE MISMATCH and EOP interrupts if we have
+	     * DMA enabled, so do a sanity check based on the current setting
+	     * of the MODE register.
+	     */
+
+	    if ((NCR5380_read(MODE_REG) & MR_DMA_MODE) &&
+		((basr & BASR_END_DMA_TRANSFER) || 
+		 !(basr & BASR_PHASE_MATCH))) {
+		    
+#if (NDEBUG & NDEBUG_INTR)
+		printk("scsi%d: PHASE MISM or EOP interrupt\n", HOSTNO);
+#endif
+		NCR5380_dma_complete( instance );
+		done = 0;
+		ENABLE_IRQ();
+	    } else
+#endif /* REAL_DMA */
+	    {
+#if 1 || (NDEBUG & NDEBUG_INTR)
+/* MS: Ignore unknown phase mismatch interrupts (caused by EOP interrupt) */
+		if (basr & BASR_PHASE_MATCH)
+		    printk("scsi%d: unknown interrupt, "
+			   "BASR 0x%x, MR 0x%x, SR 0x%x\n",
+			   HOSTNO, basr, NCR5380_read(MODE_REG),
+			   NCR5380_read(STATUS_REG));
+#endif
+		(void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+	    }
+	} /* if !(SELECTION || PARITY) */
+    } /* BASR & IRQ */
+    else {
+#if 1 || (NDEBUG & NDEBUG_INTR)
+	printk("scsi%d: interrupt without IRQ bit set in BASR, "
+	       "BASR 0x%X, MR 0x%X, SR 0x%x\n", HOSTNO, basr,
+	       NCR5380_read(MODE_REG), NCR5380_read(STATUS_REG));
+#endif
+	(void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+    }
+    
+    if (!done) {
+#if (NDEBUG & NDEBUG_INTR)
+	printk("scsi%d: in int routine, calling main\n", HOSTNO );
+#endif
+	run_main();
+    }
+}
+
+#ifdef NCR5380_STATS
+static void collect_stats(struct NCR5380_hostdata* hostdata, Scsi_Cmnd* cmd)
+{
+# ifdef NCR5380_STAT_LIMIT
+    if (cmd->request_bufflen > NCR5380_STAT_LIMIT)
+# endif
+	switch (cmd->cmnd[0])
+	{
+	    case WRITE:
+	    case WRITE_6:
+	    case WRITE_10:
+		hostdata->time_write[cmd->target] += (jiffies - hostdata->timebase);
+		/*hostdata->bytes_write[cmd->target] += cmd->request_bufflen;*/
+		hostdata->pendingw--;
+		break;
+	    case READ:
+	    case READ_6:
+	    case READ_10:
+		hostdata->time_read[cmd->target] += (jiffies - hostdata->timebase);
+		/*hostdata->bytes_read[cmd->target] += cmd->request_bufflen;*/
+		hostdata->pendingr--;
+		break;
+	}
+}
+#endif
+
+/* 
+ * Function : int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd, 
+ *	int tag);
+ *
+ * Purpose : establishes I_T_L or I_T_L_Q nexus for new or existing command,
+ *	including ARBITRATION, SELECTION, and initial message out for 
+ *	IDENTIFY and queue messages. 
+ *
+ * Inputs : instance - instantiation of the 5380 driver on which this 
+ * 	target lives, cmd - SCSI command to execute, tag - set to TAG_NEXT for 
+ *	new tag, TAG_NONE for untagged queueing, otherwise set to the tag for 
+ *	the command that is presently connected.
+ * 
+ * Returns : -1 if selection could not execute for some reason,
+ *	0 if selection succeeded or failed because the target 
+ * 	did not respond.
+ *
+ * Side effects : 
+ * 	If bus busy, arbitration failed, etc, NCR5380_select() will exit 
+ *		with registers as they should have been on entry - ie
+ *		SELECT_ENABLE will be set appropriately, the NCR5380
+ *		will cease to drive any SCSI bus signals.
+ *
+ *	If successful : I_T_L or I_T_L_Q nexus will be established, 
+ *		instance->connected will be set to cmd.  
+ * 		SELECT interrupt will be disabled.
+ *
+ *	If failed (no target) : cmd->scsi_done() will be called, and the 
+ *		cmd->result host byte set to DID_BAD_TARGET.
+ */
+
+static int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd, int tag)
+{
+    SETUP_HOSTDATA(instance);
+    unsigned char tmp[3], phase;
+    unsigned char *data;
+    int len;
+    unsigned long timeout;
+    unsigned long flags;
+
+    hostdata->restart_select = 0;
+#if defined (NDEBUG) && (NDEBUG & NDEBUG_ARBITRATION) 
+    NCR5380_print(instance);
+    printk("scsi%d: starting arbitration, id = %d\n", HOSTNO,
+	instance->this_id);
+#endif
+
+    /* 
+     * Set the phase bits to 0, otherwise the NCR5380 won't drive the 
+     * data bus during SELECTION.
+     */
+
+    save_flags(flags);
+    cli();
+    if (hostdata->connected) {
+	restore_flags(flags);
+	return -1;
+    }
+    NCR5380_write(TARGET_COMMAND_REG, 0);
+
+
+    /* 
+     * Start arbitration.
+     */
+    
+    NCR5380_write(OUTPUT_DATA_REG, hostdata->id_mask);
+    NCR5380_write(MODE_REG, MR_ARBITRATE);
+
+    restore_flags(flags);
+
+    /* Wait for arbitration logic to complete */
+#if NCR_TIMEOUT
+    {
+      unsigned long timeout = jiffies + 2*NCR_TIMEOUT;
+
+      while (!(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_PROGRESS)
+	   && jiffies < timeout && !hostdata->connected)
+	;
+      if (jiffies >= timeout)
+      {
+	printk("scsi : arbitration timeout at %d\n", __LINE__);
+	NCR5380_write(MODE_REG, MR_BASE);
+	NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+	return -1;
+      }
+    }
+#else /* NCR_TIMEOUT */
+    while (!(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_PROGRESS)
+	 && !hostdata->connected);
+#endif
+
+#if (NDEBUG & NDEBUG_ARBITRATION) 
+    printk("scsi%d: arbitration complete\n", HOSTNO);
+/* Avoid GCC 2.4.5 asm needs to many reloads error */
+    __asm__("nop");
+#endif
+
+    if (hostdata->connected) {
+	NCR5380_write(MODE_REG, MR_BASE); 
+	return -1;
+    }
+    /* 
+     * The arbitration delay is 2.2us, but this is a minimum and there is 
+     * no maximum so we can safely sleep for ceil(2.2) usecs to accommodate
+     * the integral nature of udelay().
+     *
+     */
+
+    udelay(3);
+
+    /* Check for lost arbitration */
+    if ((NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) ||
+	(NCR5380_read(CURRENT_SCSI_DATA_REG) & hostdata->id_higher_mask) ||
+	(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) ||
+	hostdata->connected) {
+	NCR5380_write(MODE_REG, MR_BASE); 
+#if (NDEBUG & NDEBUG_ARBITRATION)
+    printk("scsi%d: lost arbitration, deasserting MR_ARBITRATE\n", HOSTNO);
+#endif
+	return -1;
+    }
+
+     /* after/during arbitration, BSY should be asserted.
+	IBM DPES-31080 Version S31Q works now */
+     /* Tnx to Thomas_Roesch@m2.maus.de for finding this! (Roman) */
+    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_SEL |
+					 ICR_ASSERT_BSY ) ;
+    
+    if ((NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) ||
+	hostdata->connected) {
+	NCR5380_write(MODE_REG, MR_BASE);
+	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+#if (NDEBUG & NDEBUG_ARBITRATION)
+    printk("scsi%d: lost arbitration, deasserting ICR_ASSERT_SEL\n", HOSTNO);
+#endif
+	return -1;
+    }
+
+    /* 
+     * Again, bus clear + bus settle time is 1.2us, however, this is 
+     * a minimum so we'll udelay ceil(1.2)
+     */
+
+#ifdef CONFIG_ATARI_SCSI_TOSHIBA_DELAY
+    /* ++roman: But some targets (see above :-) seem to need a bit more... */
+    udelay(15);
+#else
+    udelay(2);
+#endif
+    
+    if (hostdata->connected) {
+	NCR5380_write(MODE_REG, MR_BASE);
+	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+	return -1;
+    }
+
+#if (NDEBUG & NDEBUG_ARBITRATION)
+    printk("scsi%d: won arbitration\n", HOSTNO);
+#endif
+
+
+    /* 
+     * Now that we have won arbitration, start Selection process, asserting 
+     * the host and target ID's on the SCSI bus.
+     */
+
+    NCR5380_write(OUTPUT_DATA_REG, (hostdata->id_mask | (1 << cmd->target)));
+
+    /* 
+     * Raise ATN while SEL is true before BSY goes false from arbitration,
+     * since this is the only way to guarantee that we'll get a MESSAGE OUT
+     * phase immediately after selection.
+     */
+
+    NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_BSY | 
+	ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_SEL ));
+    NCR5380_write(MODE_REG, MR_BASE);
+
+    /* 
+     * Reselect interrupts must be turned off prior to the dropping of BSY,
+     * otherwise we will trigger an interrupt.
+     */
+
+    if (hostdata->connected) {
+	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+	return -1;
+    }
+
+    NCR5380_write(SELECT_ENABLE_REG, 0);
+
+    /*
+     * The initiator shall then wait at least two deskew delays and release 
+     * the BSY signal.
+     */
+    udelay(1);        /* wingel -- wait two bus deskew delay >2*45ns */
+
+    /* Reset BSY */
+    NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_DATA | 
+	ICR_ASSERT_ATN | ICR_ASSERT_SEL));
+
+    /* 
+     * Something weird happens when we cease to drive BSY - looks
+     * like the board/chip is letting us do another read before the 
+     * appropriate propagation delay has expired, and we're confusing
+     * a BSY signal from ourselves as the target's response to SELECTION.
+     *
+     * A small delay (the 'C++' frontend breaks the pipeline with an
+     * unnecessary jump, making it work on my 386-33/Trantor T128, the
+     * tighter 'C' code breaks and requires this) solves the problem - 
+     * the 1 us delay is arbitrary, and only used because this delay will 
+     * be the same on other platforms and since it works here, it should 
+     * work there.
+     *
+     * wingel suggests that this could be due to failing to wait
+     * one deskew delay.
+     */
+
+    udelay(1);
+
+#if (NDEBUG & NDEBUG_SELECTION)
+    printk("scsi%d: selecting target %d\n", HOSTNO, cmd->target);
+#endif
+
+    /* 
+     * The SCSI specification calls for a 250 ms timeout for the actual 
+     * selection.
+     */
+
+    timeout = jiffies + 25; 
+
+    /* 
+     * XXX very interesting - we're seeing a bounce where the BSY we 
+     * asserted is being reflected / still asserted (propagation delay?)
+     * and it's detecting as true.  Sigh.
+     */
+
+#if 0
+    /* ++roman: If a target conformed to the SCSI standard, it wouldn't assert
+     * IO while SEL is true. But again, there are some disks out the in the
+     * world that do that nevertheless. (Somebody claimed that this announces
+     * reselection capability of the target.) So we better skip that test and
+     * only wait for BSY... (Famous german words: Der Klügere gibt nach :-)
+     */
+
+    while ((jiffies < timeout) && !(NCR5380_read(STATUS_REG) & 
+	(SR_BSY | SR_IO)));
+
+    if ((NCR5380_read(STATUS_REG) & (SR_SEL | SR_IO)) == 
+	    (SR_SEL | SR_IO)) {
+	    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+	    NCR5380_reselect(instance);
+	    printk ("scsi%d: reselection after won arbitration?\n", HOSTNO);
+	    NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+	    return -1;
+    }
+#else
+    while ((jiffies < timeout) && !(NCR5380_read(STATUS_REG) & SR_BSY));
+#endif
+
+    /* 
+     * No less than two deskew delays after the initiator detects the 
+     * BSY signal is true, it shall release the SEL signal and may 
+     * change the DATA BUS.                                     -wingel
+     */
+
+    udelay(1);
+
+    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
+
+    if (!(NCR5380_read(STATUS_REG) & SR_BSY)) {
+	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+	if (hostdata->targets_present & (1 << cmd->target)) {
+	    printk("scsi%d: weirdness\n", HOSTNO);
+	    if (hostdata->restart_select)
+		printk("\trestart select\n");
+#ifdef NDEBUG
+	    NCR5380_print (instance);
+#endif
+	    NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+	    return -1;
+	}
+	cmd->result = DID_BAD_TARGET << 16;
+#ifdef NCR5380_STATS
+	collect_stats(hostdata, cmd);
+#endif
+#ifdef SUPPORT_TAGS
+	cmd_free_tag( cmd );
+#endif
+	cmd->scsi_done(cmd);
+	NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+#if (NDEBUG & NDEBUG_SELECTION)
+	printk("scsi%d: target did not respond within 250ms\n", HOSTNO);
+#endif
+	NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+	return 0;
+    } 
+
+    hostdata->targets_present |= (1 << cmd->target);
+
+    /*
+     * Since we followed the SCSI spec, and raised ATN while SEL 
+     * was true but before BSY was false during selection, the information
+     * transfer phase should be a MESSAGE OUT phase so that we can send the
+     * IDENTIFY message.
+     * 
+     * If SCSI-II tagged queuing is enabled, we also send a SIMPLE_QUEUE_TAG
+     * message (2 bytes) with a tag ID that we increment with every command
+     * until it wraps back to 0.
+     *
+     * XXX - it turns out that there are some broken SCSI-II devices,
+     *	     which claim to support tagged queuing but fail when more than
+     *	     some number of commands are issued at once.
+     */
+
+    /* Wait for start of REQ/ACK handshake */
+    while (!(NCR5380_read(STATUS_REG) & SR_REQ));
+
+#if (NDEBUG & NDEBUG_SELECTION)
+    printk("scsi%d: target %d selected, going into MESSAGE OUT phase.\n",
+	   HOSTNO, cmd->target);
+#endif
+    tmp[0] = IDENTIFY(1, cmd->lun);
+
+#ifdef SUPPORT_TAGS
+    if (cmd->tag != TAG_NONE) {
+	tmp[1] = hostdata->last_message = SIMPLE_QUEUE_TAG;
+	tmp[2] = cmd->tag;
+	len = 3;
+    } else 
+	len = 1;
+#else
+    len = 1;
+    cmd->tag=0;
+#endif /* SUPPORT_TAGS */
+
+    /* Send message(s) */
+    data = tmp;
+    phase = PHASE_MSGOUT;
+    NCR5380_transfer_pio(instance, &phase, &len, &data);
+#if (NDEBUG & NDEBUG_SELECTION)
+    printk("scsi%d: nexus established.\n", HOSTNO);
+#endif
+    /* XXX need to handle errors here */
+    hostdata->connected = cmd;
+#ifndef SUPPORT_TAGS
+    hostdata->busy[cmd->target] |= (1 << cmd->lun);
+#endif    
+
+    initialize_SCp(cmd);
+
+
+    return 0;
+}
+
+/* 
+ * Function : int NCR5380_transfer_pio (struct Scsi_Host *instance, 
+ *      unsigned char *phase, int *count, unsigned char **data)
+ *
+ * Purpose : transfers data in given phase using polled I/O
+ *
+ * Inputs : instance - instance of driver, *phase - pointer to 
+ *	what phase is expected, *count - pointer to number of 
+ *	bytes to transfer, **data - pointer to data pointer.
+ * 
+ * Returns : -1 when different phase is entered without transferring
+ *	maximum number of bytes, 0 if all bytes are transfered or exit
+ *	is in same phase.
+ *
+ * 	Also, *phase, *count, *data are modified in place.
+ *
+ * XXX Note : handling for bus free may be useful.
+ */
+
+/*
+ * Note : this code is not as quick as it could be, however it 
+ * IS 100% reliable, and for the actual data transfer where speed
+ * counts, we will always do a pseudo DMA or DMA transfer.
+ */
+
+static int NCR5380_transfer_pio( struct Scsi_Host *instance, 
+				 unsigned char *phase, int *count,
+				 unsigned char **data)
+{
+    register unsigned char p = *phase, tmp;
+    register int c = *count;
+    register unsigned char *d = *data;
+
+    /* 
+     * The NCR5380 chip will only drive the SCSI bus when the 
+     * phase specified in the appropriate bits of the TARGET COMMAND
+     * REGISTER match the STATUS REGISTER
+     */
+
+    NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p));
+
+    do {
+	/* 
+	 * Wait for assertion of REQ, after which the phase bits will be 
+	 * valid 
+	 */
+	while (!((tmp = NCR5380_read(STATUS_REG)) & SR_REQ));
+
+#if (NDEBUG & NDEBUG_HANDSHAKE)
+	printk("scsi%d: REQ detected\n", HOSTNO);
+#endif
+
+	/* Check for phase mismatch */	
+	if ((tmp & PHASE_MASK) != p) {
+#if (NDEBUG & NDEBUG_PIO)
+	    printk("scsi%d: phase mismatch\n", HOSTNO);
+	    NCR5380_print_phase(instance);
+#endif
+	    break;
+	}
+
+	/* Do actual transfer from SCSI bus to / from memory */
+	if (!(p & SR_IO)) 
+	    NCR5380_write(OUTPUT_DATA_REG, *d);
+	else 
+	    *d = NCR5380_read(CURRENT_SCSI_DATA_REG);
+
+	++d;
+
+	/* 
+	 * The SCSI standard suggests that in MSGOUT phase, the initiator
+	 * should drop ATN on the last byte of the message phase
+	 * after REQ has been asserted for the handshake but before
+	 * the initiator raises ACK.
+	 */
+
+	if (!(p & SR_IO)) {
+	    if (!((p & SR_MSG) && c > 1)) {
+		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | 
+		    ICR_ASSERT_DATA);
+#if (NDEBUG & NDEBUG_PIO)
+		NCR5380_print(instance);
+#endif
+		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | 
+			ICR_ASSERT_DATA | ICR_ASSERT_ACK);
+	    } else {
+		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
+		    ICR_ASSERT_DATA | ICR_ASSERT_ATN);
+#if (NDEBUG & NDEBUG_PIO)
+		NCR5380_print(instance);
+#endif
+		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | 
+		    ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_ACK);
+	    }
+	} else {
+#if (NDEBUG & NDEBUG_PIO)
+	    NCR5380_print(instance);
+#endif
+	    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ACK);
+	}
+
+	while (NCR5380_read(STATUS_REG) & SR_REQ);
+
+#if (NDEBUG & NDEBUG_HANDSHAKE)
+	printk("scsi%d: req false, handshake complete\n", HOSTNO);
+#endif
+
+/*
+ * We have several special cases to consider during REQ/ACK handshaking : 
+ * 1.  We were in MSGOUT phase, and we are on the last byte of the 
+ *	message.  ATN must be dropped as ACK is dropped.
+ *
+ * 2.  We are in a MSGIN phase, and we are on the last byte of the  
+ *	message.  We must exit with ACK asserted, so that the calling
+ *	code may raise ATN before dropping ACK to reject the message.
+ *
+ * 3.  ACK and ATN are clear and the target may proceed as normal.
+ */
+	if (!(p == PHASE_MSGIN && c == 1)) {  
+	    if (p == PHASE_MSGOUT && c > 1)
+		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
+	    else
+		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+	} 
+    } while (--c);
+
+#if (NDEBUG & NDEBUG_PIO) 
+    printk("scsi%d: residual %d\n", HOSTNO, c);
+#endif
+
+    *count = c;
+    *data = d;
+    tmp = NCR5380_read(STATUS_REG);
+    /* The phase read from the bus is valid if either REQ is (already)
+     * asserted or if ACK hasn't been released yet. The latter is the case if
+     * we're in MSGIN and all wanted bytes have been received. */
+    if ((tmp & SR_REQ) || (p == PHASE_MSGIN && c == 0))
+	*phase = tmp & PHASE_MASK;
+    else 
+	*phase = PHASE_UNKNOWN;
+
+    if (!c || (*phase == p))
+	return 0;
+    else 
+	return -1;
+}
+
+/*
+ * Function : do_abort (Scsi_Host *host)
+ * 
+ * Purpose : abort the currently established nexus.  Should only be 
+ * 	called from a routine which can drop into a 
+ * 
+ * Returns : 0 on success, -1 on failure.
+ */
+
+static int do_abort (struct Scsi_Host *host) 
+{
+    unsigned char tmp, *msgptr, phase;
+    int len;
+
+    /* Request message out phase */
+    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
+
+    /* 
+     * Wait for the target to indicate a valid phase by asserting 
+     * REQ.  Once this happens, we'll have either a MSGOUT phase 
+     * and can immediately send the ABORT message, or we'll have some 
+     * other phase and will have to source/sink data.
+     * 
+     * We really don't care what value was on the bus or what value
+     * the target see's, so we just handshake.
+     */
+    
+    while (!(tmp = NCR5380_read(STATUS_REG)) & SR_REQ);
+
+    NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp));
+
+    if ((tmp & PHASE_MASK) != PHASE_MSGOUT) {
+	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN | 
+		      ICR_ASSERT_ACK);
+	while (NCR5380_read(STATUS_REG) & SR_REQ);
+	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
+    }
+   
+    tmp = ABORT;
+    msgptr = &tmp;
+    len = 1;
+    phase = PHASE_MSGOUT;
+    NCR5380_transfer_pio (host, &phase, &len, &msgptr);
+
+    /*
+     * If we got here, and the command completed successfully,
+     * we're about to go into bus free state.
+     */
+
+    return len ? -1 : 0;
+}
+
+#if defined(REAL_DMA)
+/* 
+ * Function : int NCR5380_transfer_dma (struct Scsi_Host *instance, 
+ *      unsigned char *phase, int *count, unsigned char **data)
+ *
+ * Purpose : transfers data in given phase using either real
+ *	or pseudo DMA.
+ *
+ * Inputs : instance - instance of driver, *phase - pointer to 
+ *	what phase is expected, *count - pointer to number of 
+ *	bytes to transfer, **data - pointer to data pointer.
+ * 
+ * Returns : -1 when different phase is entered without transferring
+ *	maximum number of bytes, 0 if all bytes or transfered or exit
+ *	is in same phase.
+ *
+ * 	Also, *phase, *count, *data are modified in place.
+ *
+ */
+
+
+static int NCR5380_transfer_dma( struct Scsi_Host *instance, 
+				 unsigned char *phase, int *count,
+				 unsigned char **data)
+{
+    SETUP_HOSTDATA(instance);
+    register int c = *count;
+    register unsigned char p = *phase;
+    register unsigned char *d = *data;
+    unsigned char tmp;
+    unsigned long flags;
+
+    if ((tmp = (NCR5380_read(STATUS_REG) & PHASE_MASK)) != p) {
+        *phase = tmp;
+        return -1;
+    }
+
+    if (atari_read_overruns && (p & SR_IO)) {
+	c -= atari_read_overruns;
+    }
+
+#if (NDEBUG & NDEBUG_DMA)
+    printk("scsi%d: initializing DMA channel %d for %s, %d bytes %s %0x\n",
+	   HOSTNO, instance->dma_channel, (p & SR_IO) ? "reading" :
+	   "writing", c, (p & SR_IO) ? "to" : "from", (unsigned) d);
+#endif
+
+    NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p));
+
+#ifdef REAL_DMA
+    NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | MR_ENABLE_EOP_INTR | MR_MONITOR_BSY);
+#endif /* def REAL_DMA  */
+
+    if (IS_A_TT()) {
+	/* On the Medusa, it is a must to initialize the DMA before
+	 * starting the NCR. This is also the cleaner way for the TT.
+	 */
+	save_flags(flags);
+	cli();
+	hostdata->dma_len = (p & SR_IO) ?
+	    NCR5380_dma_read_setup(instance, d, c) : 
+	    NCR5380_dma_write_setup(instance, d, c);
+	restore_flags(flags);
+    }
+    
+    if (p & SR_IO)
+	NCR5380_write(START_DMA_INITIATOR_RECEIVE_REG, 0);
+    else {
+	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA);
+	NCR5380_write(START_DMA_SEND_REG, 0);
+    }
+
+    if (!IS_A_TT()) {
+	/* On the Falcon, the DMA setup must be done after the last */
+	/* NCR access, else the DMA setup gets trashed!
+	 */
+	save_flags(flags);
+	cli();
+	hostdata->dma_len = (p & SR_IO) ?
+	    NCR5380_dma_read_setup(instance, d, c) : 
+	    NCR5380_dma_write_setup(instance, d, c);
+	restore_flags(flags);
+    }
+    return 0;
+}
+#endif /* defined(REAL_DMA) */
+
+/*
+ * Function : NCR5380_information_transfer (struct Scsi_Host *instance)
+ *
+ * Purpose : run through the various SCSI phases and do as the target 
+ * 	directs us to.  Operates on the currently connected command, 
+ *	instance->connected.
+ *
+ * Inputs : instance, instance for which we are doing commands
+ *
+ * Side effects : SCSI things happen, the disconnected queue will be 
+ *	modified if a command disconnects, *instance->connected will
+ *	change.
+ *
+ * XXX Note : we need to watch for bus free or a reset condition here 
+ * 	to recover from an unexpected bus free condition.
+ */
+ 
+static void NCR5380_information_transfer (struct Scsi_Host *instance)
+{
+    SETUP_HOSTDATA(instance);
+    unsigned long flags;
+    unsigned char msgout = NOP;
+    int sink = 0;
+    int len;
+#if defined(REAL_DMA)
+    int transfersize;
+#endif
+    unsigned char *data;
+    unsigned char phase, tmp, extended_msg[10], old_phase=0xff;
+    Scsi_Cmnd *cmd = (Scsi_Cmnd *) hostdata->connected;
+
+    while (1) {
+	tmp = NCR5380_read(STATUS_REG);
+	/* We only have a valid SCSI phase when REQ is asserted */
+	if (tmp & SR_REQ) {
+	    phase = (tmp & PHASE_MASK); 
+	    if (phase != old_phase) {
+		old_phase = phase;
+#if (NDEBUG & NDEBUG_INFORMATION)
+		NCR5380_print_phase(instance);
+#endif
+	    }
+	    
+	    if (sink && (phase != PHASE_MSGOUT)) {
+		NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp));
+
+		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN | 
+		    ICR_ASSERT_ACK);
+		while (NCR5380_read(STATUS_REG) & SR_REQ);
+		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | 
+		    ICR_ASSERT_ATN);
+		sink = 0;
+		continue;
+	    }
+
+	    switch (phase) {
+	    case PHASE_DATAOUT:
+#if (NDEBUG & NDEBUG_NO_DATAOUT)
+		printk("scsi%d: NDEBUG_NO_DATAOUT set, attempted DATAOUT "
+		       "aborted\n", HOSTNO);
+		sink = 1;
+		do_abort(instance);
+		cmd->result = DID_ERROR  << 16;
+		cmd->done(cmd);
+		return;
+#endif
+	    case PHASE_DATAIN:
+		/* 
+		 * If there is no room left in the current buffer in the
+		 * scatter-gather list, move onto the next one.
+		 */
+
+		if (!cmd->SCp.this_residual && cmd->SCp.buffers_residual) {
+		    ++cmd->SCp.buffer;
+		    --cmd->SCp.buffers_residual;
+		    cmd->SCp.this_residual = cmd->SCp.buffer->length;
+		    cmd->SCp.ptr = cmd->SCp.buffer->address;
+		    /* ++roman: Try to merge some scatter-buffers if
+		     * they are at consecutive physical addresses.
+		     */
+		    merge_consecutive_buffers( cmd );
+#if (NDEBUG & NDEBUG_INFORMATION)
+		    printk("scsi%d: %d bytes and %d buffers left\n",
+			   HOSTNO, cmd->SCp.this_residual,
+			   cmd->SCp.buffers_residual);
+#endif
+		}
+
+		/*
+		 * The preferred transfer method is going to be 
+		 * PSEUDO-DMA for systems that are strictly PIO,
+		 * since we can let the hardware do the handshaking.
+		 *
+		 * For this to work, we need to know the transfersize
+		 * ahead of time, since the pseudo-DMA code will sit
+		 * in an unconditional loop.
+		 */
+
+/* ++roman: I suggest, this should be
+ *   #if def(REAL_DMA)
+ * instead of leaving REAL_DMA out.
+ */
+
+#if defined(REAL_DMA)
+		if (!cmd->device->borken &&
+		    (transfersize = NCR5380_dma_xfer_len(instance,cmd,phase)) > 31) {
+		    len = transfersize;
+		    cmd->SCp.phase = phase;
+		    if (NCR5380_transfer_dma(instance, &phase,
+			&len, (unsigned char **) &cmd->SCp.ptr)) {
+			/*
+			 * If the watchdog timer fires, all future
+			 * accesses to this device will use the
+			 * polled-IO. */ 
+			printk("scsi%d: switching target %d lun %d to slow "
+			       "handshake\n", HOSTNO, cmd->target, cmd->lun);
+			cmd->device->borken = 1;
+			NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | 
+			    ICR_ASSERT_ATN);
+			sink = 1;
+			do_abort(instance);
+			cmd->result = DID_ERROR  << 16;
+			cmd->done(cmd);
+			/* XXX - need to source or sink data here, as appropriate */
+		    } else {
+#ifdef REAL_DMA
+			/* ++roman: When using real DMA,
+			 * information_transfer() should return after
+			 * starting DMA since it has nothing more to
+			 * do.
+			 */
+			return;
+#else			
+			cmd->SCp.this_residual -= transfersize - len;
+#endif
+		    }
+		} else
+#endif /* defined(REAL_DMA) */
+		  NCR5380_transfer_pio(instance, &phase, 
+		    (int *) &cmd->SCp.this_residual, (unsigned char **)
+		    &cmd->SCp.ptr);
+		break;
+	    case PHASE_MSGIN:
+		len = 1;
+		data = &tmp;
+		NCR5380_write(SELECT_ENABLE_REG, 0); 	/* disable reselects */
+		NCR5380_transfer_pio(instance, &phase, &len, &data);
+		cmd->SCp.Message = tmp;
+
+		switch (tmp) {
+		/*
+		 * Linking lets us reduce the time required to get the 
+		 * next command out to the device, hopefully this will
+		 * mean we don't waste another revolution due to the delays
+		 * required by ARBITRATION and another SELECTION.
+		 *
+		 * In the current implementation proposal, low level drivers
+		 * merely have to start the next command, pointed to by 
+		 * next_link, done() is called as with unlinked commands.
+		 */
+#ifdef LINKED
+		case LINKED_CMD_COMPLETE:
+		case LINKED_FLG_CMD_COMPLETE:
+		    /* Accept message by clearing ACK */
+		    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+		    
+#if (NDEBUG & NDEBUG_LINKED) 
+		    printk("scsi%d: target %d lun %d linked command complete.\n",
+			HOSTNO, cmd->target, cmd->lun);
+#endif
+		    /* Enable reselect interupts */
+		    NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+		    /*
+		     * Sanity check : A linked command should only terminate
+		     * with one of these messages if there are more linked
+		     * commands available.
+		     */
+
+		    if (!cmd->next_link) {
+			 printk("scsi%d: target %d lun %d linked command "
+				"complete, no next_link\n",
+				HOSTNO, cmd->target, cmd->lun);
+			    sink = 1;
+			    do_abort (instance);
+			    return;
+		    }
+
+		    initialize_SCp(cmd->next_link);
+		    /* The next command is still part of this process; copy it
+		     * and don't free it! */
+		    cmd->next_link->tag = cmd->tag;
+		    cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8); 
+#if (NDEBUG & NDEBUG_LINKED) 
+		    printk("scsi%d: target %d lun %d linked request done, "
+			   "calling scsi_done().\n",
+			   HOSTNO, cmd->target, cmd->lun);
+#endif
+#ifdef NCR5380_STATS
+		    collect_stats(hostdata, cmd);
+#endif
+		    cmd->scsi_done(cmd);
+		    cmd = hostdata->connected;
+		    break;
+#endif /* def LINKED */
+		case ABORT:
+		case COMMAND_COMPLETE: 
+		    /* Accept message by clearing ACK */
+		    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+		    /* ++guenther: possible race with Falcon locking */
+		    falcon_dont_release++;
+		    hostdata->connected = NULL;
+#if (NDEBUG & NDEBUG_QUEUES)
+		    printk("scsi%d: command for target %d, lun %d completed\n",
+			   HOSTNO, cmd->target, cmd->lun);
+#endif
+#ifdef SUPPORT_TAGS
+		    cmd_free_tag( cmd );
+		    if (cmd->SCp.Status == QUEUE_FULL) {
+			/* Turn a QUEUE FULL status into BUSY, I think the
+			 * mid level cannot handle QUEUE FULL :-( (The
+			 * command is retried after BUSY). Also update our
+			 * queue size to the number of currently issued
+			 * commands now.
+			 */
+			TAG_ALLOC *ta = &TagAlloc[cmd->target][cmd->lun];
+#if (NDEBUG & NDEBUG_TAGS)
+			printk( "scsi%d: target %d lun %d returned "
+				"QUEUE_FULL after %d commands\n",
+				HOSTNO, cmd->target, cmd->lun,
+				ta->nr_allocated );
+#endif
+			if (ta->queue_size > ta->nr_allocated)
+			    ta->nr_allocated = ta->queue_size;
+			cmd->SCp.Status = BUSY;
+		    }
+#else
+		    hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
+#endif
+		    /* Enable reselect interupts */
+		    NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+
+		    /* 
+		     * I'm not sure what the correct thing to do here is : 
+		     * 
+		     * If the command that just executed is NOT a request 
+		     * sense, the obvious thing to do is to set the result
+		     * code to the values of the stored parameters.
+		     * 
+		     * If it was a REQUEST SENSE command, we need some way to
+		     * differentiate between the failure code of the original
+		     * and the failure code of the REQUEST sense - the obvious
+		     * case is success, where we fall through and leave the
+		     * result code unchanged.
+		     * 
+		     * The non-obvious place is where the REQUEST SENSE failed
+		     */
+
+		    if (cmd->cmnd[0] != REQUEST_SENSE) 
+			cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8); 
+		    else if (cmd->SCp.Status != GOOD)
+			cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16);
+		    
+#ifdef AUTOSENSE
+		    if ((cmd->cmnd[0] != REQUEST_SENSE) && 
+			(cmd->SCp.Status == CHECK_CONDITION)) {
+#if (NDEBUG & NDEBUG_AUTOSENSE) 
+			printk("scsi%d: performing request sense\n", HOSTNO);
+#endif
+			cmd->cmnd[0] = REQUEST_SENSE;
+			cmd->cmnd[1] &= 0xe0;
+			cmd->cmnd[2] = 0;
+			cmd->cmnd[3] = 0;
+			cmd->cmnd[4] = sizeof(cmd->sense_buffer);
+			cmd->cmnd[5] = 0;
+
+			cmd->SCp.buffer = NULL;
+			cmd->SCp.buffers_residual = 0;
+			cmd->SCp.ptr = (char *) cmd->sense_buffer;
+			cmd->SCp.this_residual = sizeof(cmd->sense_buffer);
+
+			save_flags(flags);
+			cli();
+			LIST(cmd,hostdata->issue_queue);
+			NEXT(cmd) = hostdata->issue_queue;
+		        hostdata->issue_queue = (Scsi_Cmnd *) cmd;
+		        restore_flags(flags);
+#if (NDEBUG & NDEBUG_QUEUES)
+			printk("scsi%d: REQUEST SENSE added to head of "
+			       "issue queue\n", H_NO(cmd));
+#endif
+		   } else
+#endif /* def AUTOSENSE */
+		   {
+#ifdef NCR5380_STATS
+		       collect_stats(hostdata, cmd);
+#endif
+		       cmd->scsi_done(cmd);
+		    }
+
+		    NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+		    /* 
+		     * Restore phase bits to 0 so an interrupted selection, 
+		     * arbitration can resume.
+		     */
+		    NCR5380_write(TARGET_COMMAND_REG, 0);
+		    
+		    while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected)
+			barrier();
+
+		    falcon_dont_release--;
+		    /* ++roman: For Falcon SCSI, release the lock on the
+		     * ST-DMA here if no other commands are waiting on the
+		     * disconnected queue.
+		     */
+		    falcon_release_lock_if_possible( hostdata );
+		    return;
+		case MESSAGE_REJECT:
+		    /* Accept message by clearing ACK */
+		    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+		    /* Enable reselect interupts */
+		    NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+		    switch (hostdata->last_message) {
+		    case HEAD_OF_QUEUE_TAG:
+		    case ORDERED_QUEUE_TAG:
+		    case SIMPLE_QUEUE_TAG:
+			/* The target obviously doesn't support tagged
+			 * queuing, even though it announced this ability in
+			 * its INQUIRY data ?!? (maybe only this LUN?) Ok,
+			 * clear 'tagged_supported' and lock the LUN, since
+			 * the command is treated as untagged furtheron.
+			 */
+			cmd->device->tagged_supported = 0;
+			hostdata->busy[cmd->target] |= (1 << cmd->lun);
+			cmd->tag = TAG_NONE;
+#if (NDEBUG & NDEBUG_TAGS)
+			printk( "scsi%d: target %d lun %d rejected QUEUE_TAG "
+				"message; tagged queuing disabled\n",
+				HOSTNO, cmd->target, cmd->lun );
+#endif
+			break;
+		    }
+		    break;
+		case DISCONNECT:
+		    /* Accept message by clearing ACK */
+		    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+		    save_flags(flags);
+		    cli();
+		    cmd->device->disconnect = 1;
+		    LIST(cmd,hostdata->disconnected_queue);
+		    NEXT(cmd) = hostdata->disconnected_queue;
+		    hostdata->connected = NULL;
+		    hostdata->disconnected_queue = cmd;
+		    restore_flags(flags);
+#if (NDEBUG & NDEBUG_QUEUES)
+		    printk("scsi%d: command for target %d lun %d was moved from connected to"
+		           "  the disconnected_queue\n", HOSTNO, 
+			    cmd->target, cmd->lun);
+#endif
+		    /* 
+		     * Restore phase bits to 0 so an interrupted selection, 
+		     * arbitration can resume.
+		     */
+		    NCR5380_write(TARGET_COMMAND_REG, 0);
+
+		    /* Enable reselect interrupts */
+		    NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+		    /* Wait for bus free to avoid nasty timeouts */
+		    while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected)
+		    	barrier();
+		    return;
+		/* 
+		 * The SCSI data pointer is *IMPLICITLY* saved on a disconnect
+		 * operation, in violation of the SCSI spec so we can safely 
+		 * ignore SAVE/RESTORE pointers calls.
+		 *
+		 * Unfortunately, some disks violate the SCSI spec and 
+		 * don't issue the required SAVE_POINTERS message before
+		 * disconnecting, and we have to break spec to remain 
+		 * compatible.
+		 */
+		case SAVE_POINTERS:
+		case RESTORE_POINTERS:
+		    /* Accept message by clearing ACK */
+		    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+		    /* Enable reselect interupts */
+		    NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+		    break;
+		case EXTENDED_MESSAGE:
+/* 
+ * Extended messages are sent in the following format :
+ * Byte 	
+ * 0		EXTENDED_MESSAGE == 1
+ * 1		length (includes one byte for code, doesn't 
+ *		include first two bytes)
+ * 2 		code
+ * 3..length+1	arguments
+ *
+ * Start the extended message buffer with the EXTENDED_MESSAGE
+ * byte, since print_msg() wants the whole thing.  
+ */
+		    extended_msg[0] = EXTENDED_MESSAGE;
+		    /* Accept first byte by clearing ACK */
+		    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+
+#if (NDEBUG & NDEBUG_EXTENDED)
+		    printk("scsi%d: receiving extended message\n", HOSTNO);
+#endif
+
+		    len = 2;
+		    data = extended_msg + 1;
+		    phase = PHASE_MSGIN;
+		    NCR5380_transfer_pio(instance, &phase, &len, &data);
+
+#if (NDEBUG & NDEBUG_EXTENDED)
+		    printk("scsi%d: length=%d, code=0x%02x\n", HOSTNO,
+			   (int) extended_msg[1],
+			   (int) extended_msg[2]);
+#endif
+
+		    if (!len && extended_msg[1] <= 
+			(sizeof (extended_msg) - 1)) {
+			/* Accept third byte by clearing ACK */
+			NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+			len = extended_msg[1] - 1;
+			data = extended_msg + 3;
+			phase = PHASE_MSGIN;
+
+			NCR5380_transfer_pio(instance, &phase, &len, &data);
+
+#if (NDEBUG & NDEBUG_EXTENDED)
+		    printk("scsi%d: message received, residual %d\n",
+			   HOSTNO, len);
+#endif
+
+			switch (extended_msg[2]) {
+			case EXTENDED_SDTR:
+			case EXTENDED_WDTR:
+			case EXTENDED_MODIFY_DATA_POINTER:
+			case EXTENDED_EXTENDED_IDENTIFY:
+			    tmp = 0;
+			}
+		    } else if (len) {
+			printk("scsi%d: error receiving extended message\n",
+			       HOSTNO);
+			tmp = 0;
+		    } else {
+			printk("scsi%d: extended message code %02x length %d is too long\n",
+			       HOSTNO, extended_msg[2], extended_msg[1]);
+			tmp = 0;
+		    }
+		/* Fall through to reject message */
+
+		/* 
+  		 * If we get something weird that we aren't expecting, 
+ 		 * reject it.
+		 */
+		default:
+		    if (!tmp) {
+			printk("scsi%d: rejecting message ", HOSTNO);
+			print_msg (extended_msg);
+			printk("\n");
+		    } else if (tmp != EXTENDED_MESSAGE)
+			printk("scsi%d: rejecting unknown message %02x from target %d, lun %d\n",
+			       HOSTNO, tmp, cmd->target, cmd->lun);
+		    else
+			printk("scsi%d: rejecting unknown extended message "
+			       "code %02x, length %d from target %d, lun %d\n",
+			       HOSTNO, extended_msg[1], extended_msg[0],
+			       cmd->target, cmd->lun);
+   
+
+		    msgout = MESSAGE_REJECT;
+		    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | 
+			ICR_ASSERT_ATN);
+		    break;
+		} /* switch (tmp) */
+		break;
+	    case PHASE_MSGOUT:
+		len = 1;
+		data = &msgout;
+		hostdata->last_message = msgout;
+		NCR5380_transfer_pio(instance, &phase, &len, &data);
+		if (msgout == ABORT) {
+#ifdef SUPPORT_TAGS
+		    cmd_free_tag( cmd );
+#else
+		    hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
+#endif
+		    hostdata->connected = NULL;
+		    cmd->result = DID_ERROR << 16;
+#ifdef NCR5380_STATS
+		    collect_stats(hostdata, cmd);
+#endif
+		    cmd->scsi_done(cmd);
+		    NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+		    falcon_release_lock_if_possible( hostdata );
+		    return;
+		}
+		msgout = NOP;
+		break;
+	    case PHASE_CMDOUT:
+		len = cmd->cmd_len;
+		data = cmd->cmnd;
+		/* 
+		 * XXX for performance reasons, on machines with a 
+		 * PSEUDO-DMA architecture we should probably 
+		 * use the dma transfer function.  
+		 */
+		NCR5380_transfer_pio(instance, &phase, &len, 
+		    &data);
+		break;
+	    case PHASE_STATIN:
+		len = 1;
+		data = &tmp;
+		NCR5380_transfer_pio(instance, &phase, &len, &data);
+		cmd->SCp.Status = tmp;
+		break;
+	    default:
+		printk("scsi%d: unknown phase\n", HOSTNO);
+#ifdef NDEBUG
+		NCR5380_print(instance);
+#endif
+	    } /* switch(phase) */
+	} /* if (tmp * SR_REQ) */ 
+    } /* while (1) */
+}
+
+/*
+ * Function : void NCR5380_reselect (struct Scsi_Host *instance)
+ *
+ * Purpose : does reselection, initializing the instance->connected 
+ *	field to point to the Scsi_Cmnd for which the I_T_L or I_T_L_Q 
+ *	nexus has been reestablished,
+ *	
+ * Inputs : instance - this instance of the NCR5380.
+ *
+ */
+
+
+static void NCR5380_reselect (struct Scsi_Host *instance)
+{
+    SETUP_HOSTDATA(instance);
+    unsigned char target_mask;
+    unsigned char lun, phase;
+    int len;
+#ifdef SUPPORT_TAGS
+    unsigned char tag;
+#endif
+    unsigned char msg[3];
+    unsigned char *data;
+    Scsi_Cmnd *tmp = NULL, *prev;
+/*    unsigned long flags; */
+
+    /*
+     * Disable arbitration, etc. since the host adapter obviously
+     * lost, and tell an interrupted NCR5380_select() to restart.
+     */
+
+    NCR5380_write(MODE_REG, MR_BASE);
+    hostdata->restart_select = 1;
+
+    target_mask = NCR5380_read(CURRENT_SCSI_DATA_REG) & ~(hostdata->id_mask);
+
+#if (NDEBUG & NDEBUG_RESELECTION)
+    printk("scsi%d: reselect\n", HOSTNO);
+#endif
+
+    /* 
+     * At this point, we have detected that our SCSI ID is on the bus,
+     * SEL is true and BSY was false for at least one bus settle delay
+     * (400 ns).
+     *
+     * We must assert BSY ourselves, until the target drops the SEL
+     * signal.
+     */
+
+    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_BSY);
+    
+    while (NCR5380_read(STATUS_REG) & SR_SEL);
+    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+
+    /*
+     * Wait for target to go into MSGIN.
+     */
+
+    while (!(NCR5380_read(STATUS_REG) & SR_REQ));
+
+    len = 1;
+    data = msg;
+    phase = PHASE_MSGIN;
+    NCR5380_transfer_pio(instance, &phase, &len, &data);
+
+    if (!msg[0] & 0x80) {
+	printk("scsi%d: expecting IDENTIFY message, got ", HOSTNO);
+	print_msg(msg);
+	do_abort(instance);
+	return;
+    }
+    lun = (msg[0] & 0x07);
+
+#ifdef SUPPORT_TAGS
+    /* If the phase is still MSGIN, the target wants to send some more
+     * messages. In case it supports tagged queuing, this is probably a
+     * SIMPLE_QEUE_TAG for the I_T_L_Q nexus.
+     */
+    tag = TAG_NONE;
+    if (phase == PHASE_MSGIN && setup_use_tagged_queuing) {
+	/* Accept previous IDENTIFY message by clearing ACK */
+	NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE );
+	len = 2;
+	data = msg+1;
+	if (!NCR5380_transfer_pio(instance, &phase, &len, &data) &&
+	    msg[1] == SIMPLE_QUEUE_TAG)
+	    tag = msg[2];
+#if (NDEBUG & NDEBUG_TAGS)
+	printk("scsi%d: target mask %02x, lun %d sent tag %d at reselection\n",
+	       HOSTNO, target_mask, lun, tag );
+#endif
+    }
+#endif
+    
+    /* 
+     * Find the command corresponding to the I_T_L or I_T_L_Q  nexus we 
+     * just reestablished, and remove it from the disconnected queue.
+     */
+
+    for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue, prev = NULL; 
+	 tmp; prev = tmp, tmp = NEXT(tmp) ) {
+	if ((target_mask == (1 << tmp->target)) && (lun == tmp->lun)
+#ifdef SUPPORT_TAGS
+	    && (tag == tmp->tag) 
+#endif
+	    ) {
+	    /* ++guenther: prevent race with falcon_release_lock */
+	    falcon_dont_release++;
+	    if (prev) {
+		REMOVE(prev, NEXT(prev), tmp, NEXT(tmp));
+		NEXT(prev) = NEXT(tmp);
+	    } else {
+		REMOVE(-1, hostdata->disconnected_queue, tmp, NEXT(tmp));
+		hostdata->disconnected_queue = NEXT(tmp);
+	    }
+	    NEXT(tmp) = NULL;
+	    break;
+	}
+    }
+    
+    if (!tmp) {
+	printk( "scsi%d: warning: target bitmask %02x lun %d "
+#ifdef SUPPORT_TAGS
+		"tag %d "
+#endif
+		"not in disconnect_queue.\n",
+		HOSTNO, target_mask, lun
+#ifdef SUPPORT_TAGS
+		, tag
+#endif
+		);
+	/* 
+	 * Since we have an established nexus that we can't do anything
+	 * with, we must abort it.  
+	 */
+	do_abort(instance);
+	return;
+    }
+
+    /* Accept message by clearing ACK */
+    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+
+    hostdata->connected = tmp;
+#if (NDEBUG & NDEBUG_RESELECTION)
+    printk("scsi%d: nexus established, target = %d, lun = %d, tag = %d\n",
+	   HOSTNO, tmp->target, tmp->lun, tmp->tag);
+#endif
+    falcon_dont_release--;
+}
+
+
+/*
+ * Function : int NCR5380_abort (Scsi_Cmnd *cmd)
+ *
+ * Purpose : abort a command
+ *
+ * Inputs : cmd - the Scsi_Cmnd to abort, code - code to set the 
+ * 	host byte of the result field to, if zero DID_ABORTED is 
+ *	used.
+ *
+ * Returns : 0 - success, -1 on failure.
+ *
+ * XXX - there is no way to abort the command that is currently 
+ * 	 connected, you have to wait for it to complete.  If this is 
+ *	 a problem, we could implement longjmp() / setjmp(), setjmp()
+ * 	 called where the loop started in NCR5380_main().
+ */
+
+#ifndef NCR5380_abort
+static
+#endif
+int NCR5380_abort (Scsi_Cmnd *cmd)
+{
+    struct Scsi_Host *instance = cmd->host;
+    SETUP_HOSTDATA(instance);
+    Scsi_Cmnd *tmp, **prev;
+    unsigned long flags;
+
+    printk("scsi%d: aborting command\n", HOSTNO);
+    print_Scsi_Cmnd (cmd);
+
+    NCR5380_print_status (instance);
+
+    save_flags(flags);
+    cli();
+    
+    if (!IS_A_TT() && !falcon_got_lock)
+	printk("scsi%d: !!BINGO!! Falcon has no lock in NCR5380_abort\n",
+	       HOSTNO);
+
+#if (NDEBUG & NDEBUG_ABORT)
+    printk("scsi%d: abort called basr 0x%02x, sr 0x%02x\n", HOSTNO,
+	   NCR5380_read(BUS_AND_STATUS_REG),
+	   NCR5380_read(STATUS_REG));
+#endif
+
+#if 0
+/* 
+ * Case 1 : If the command is the currently executing command, 
+ * we'll set the aborted flag and return control so that 
+ * information transfer routine can exit cleanly.
+ */
+
+    if (hostdata->connected == cmd) {
+#if (NDEBUG & NDEBUG_ABORT)
+	printk("scsi%d: aborting connected command\n", HOSTNO);
+#endif
+	hostdata->aborted = 1;
+/*
+ * We should perform BSY checking, and make sure we haven't slipped
+ * into BUS FREE.
+ */
+
+	NCR5380_write(INITIATOR_COMMAND_REG, ICR_ASSERT_ATN);
+/* 
+ * Since we can't change phases until we've completed the current 
+ * handshake, we have to source or sink a byte of data if the current
+ * phase is not MSGOUT.
+ */
+
+/* 
+ * Return control to the executing NCR drive so we can clear the
+ * aborted flag and get back into our main loop.
+ */ 
+ 
+	return 0;
+    }
+#endif
+
+/* 
+ * Case 2 : If the command hasn't been issued yet, we simply remove it 
+ * 	    from the issue queue.
+ */
+    for (prev = (Scsi_Cmnd **) &(hostdata->issue_queue), 
+	tmp = (Scsi_Cmnd *) hostdata->issue_queue;
+	tmp; prev = NEXTADDR(tmp), tmp = NEXT(tmp) )
+	if (cmd == tmp) {
+	    REMOVE(5, *prev, tmp, NEXT(tmp));
+	    (*prev) = NEXT(tmp);
+	    NEXT(tmp) = NULL;
+	    tmp->result = DID_ABORT << 16;
+	    restore_flags(flags);
+#if (NDEBUG & NDEBUG_ABORT)
+	    printk("scsi%d: abort removed command from issue queue.\n",
+		   HOSTNO);
+#endif
+	    /* Tagged queuing note: no tag to free here, hasn't been assigned
+	     * yet... */
+	    tmp->done(tmp);
+	    falcon_release_lock_if_possible( hostdata );
+	    return SCSI_ABORT_SUCCESS;
+	}
+
+/* 
+ * Case 3 : If any commands are connected, we're going to fail the abort
+ *	    and let the high level SCSI driver retry at a later time or 
+ *	    issue a reset.
+ *
+ *	    Timeouts, and therefore aborted commands, will be highly unlikely
+ *          and handling them cleanly in this situation would make the common
+ *	    case of noresets less efficient, and would pollute our code.  So,
+ *	    we fail.
+ */
+
+    if (hostdata->connected) {
+	restore_flags(flags);
+#if (NDEBUG & NDEBUG_ABORT)
+    printk("scsi%d: abort failed, command connected.\n", HOSTNO);
+#endif
+        return SCSI_ABORT_NOT_RUNNING;
+    }
+
+/*
+ * Case 4: If the command is currently disconnected from the bus, and 
+ * 	there are no connected commands, we reconnect the I_T_L or 
+ *	I_T_L_Q nexus associated with it, go into message out, and send 
+ *      an abort message.
+ *
+ * This case is especially ugly. In order to reestablish the nexus, we
+ * need to call NCR5380_select().  The easiest way to implement this 
+ * function was to abort if the bus was busy, and let the interrupt
+ * handler triggered on the SEL for reselect take care of lost arbitrations
+ * where necessary, meaning interrupts need to be enabled.
+ *
+ * When interrupts are enabled, the queues may change - so we 
+ * can't remove it from the disconnected queue before selecting it
+ * because that could cause a failure in hashing the nexus if that 
+ * device reselected.
+ * 
+ * Since the queues may change, we can't use the pointers from when we
+ * first locate it.
+ *
+ * So, we must first locate the command, and if NCR5380_select()
+ * succeeds, then issue the abort, relocate the command and remove
+ * it from the disconnected queue.
+ */
+
+    for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue; tmp;
+	 tmp = NEXT(tmp)) 
+        if (cmd == tmp) {
+            restore_flags(flags);
+#if (NDEBUG & NDEBUG_ABORT)
+    printk("scsi%d: aborting disconnected command.\n", HOSTNO);
+#endif
+  
+            if (NCR5380_select (instance, cmd, (int) cmd->tag)) 
+		return SCSI_ABORT_BUSY;
+
+#if (NDEBUG & NDEBUG_ABORT)
+    printk("scsi%d: nexus reestablished.\n", HOSTNO);
+#endif
+
+	    do_abort (instance);
+
+	    save_flags(flags);
+	    cli();
+	    for (prev = (Scsi_Cmnd **) &(hostdata->disconnected_queue), 
+		tmp = (Scsi_Cmnd *) hostdata->disconnected_queue;
+		tmp; prev = NEXTADDR(tmp), tmp = NEXT(tmp) )
+		    if (cmd == tmp) {
+		    REMOVE(5, *prev, tmp, NEXT(tmp));
+		    *prev = NEXT(tmp);
+		    NEXT(tmp) = NULL;
+		    tmp->result = DID_ABORT << 16;
+		    /* We must unlock the tag/LUN immediately here, since the
+		     * target goes to BUS FREE and doesn't send us another
+		     * message (COMMAND_COMPLETE or the like)
+		     */
+#ifdef SUPPORT_TAGS
+		    cmd_free_tag( tmp );
+#else
+		    hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
+#endif
+		    restore_flags(flags);
+		    tmp->done(tmp);
+		    falcon_release_lock_if_possible( hostdata );
+		    return SCSI_ABORT_SUCCESS;
+		}
+	}
+
+/*
+ * Case 5 : If we reached this point, the command was not found in any of 
+ *	    the queues.
+ *
+ * We probably reached this point because of an unlikely race condition
+ * between the command completing successfully and the abortion code,
+ * so we won't panic, but we will notify the user in case something really
+ * broke.
+ */
+
+    restore_flags(flags);
+    printk("scsi%d: warning : SCSI command probably completed successfully\n"
+           "        before abortion\n", HOSTNO); 
+
+/* Maybe it is sufficient just to release the ST-DMA lock... (if
+ * possible at all) At least, we should check if the lock could be
+ * released after the abort, in case it is kept due to some bug.
+ */
+    falcon_release_lock_if_possible( hostdata );
+
+    return SCSI_ABORT_NOT_RUNNING;
+}
+
+
+/* 
+ * Function : int NCR5380_reset (Scsi_Cmnd *cmd)
+ * 
+ * Purpose : reset the SCSI bus.
+ *
+ * Returns : SCSI_RESET_WAKEUP
+ *
+ */ 
+
+static int NCR5380_reset( Scsi_Cmnd *cmd )
+{
+#if 0
+    SETUP_HOSTDATA(cmd->host);
+    int           i;
+    unsigned long flags;
+    Scsi_Cmnd *connected, *disconnected_queue;
+#endif
+
+    if (!IS_A_TT() && !falcon_got_lock)
+	printk("scsi%d: !!BINGO!! Falcon has no lock in NCR5380_reset\n",
+	       H_NO(cmd) );
+
+    NCR5380_print_status (cmd->host);
+
+    /* get in phase */
+    NCR5380_write( TARGET_COMMAND_REG,
+		   PHASE_SR_TO_TCR( NCR5380_read(STATUS_REG) ));
+    /* assert RST */
+    NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST );
+    udelay (40);
+    /* reset NCR registers */
+    NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE );
+    NCR5380_write( MODE_REG, MR_BASE );
+    NCR5380_write( TARGET_COMMAND_REG, 0 );
+    NCR5380_write( SELECT_ENABLE_REG, 0 );
+    /* ++roman: reset interrupt condition! otherwise no interrupts don't get
+     * through anymore ... */
+    (void)NCR5380_read( RESET_PARITY_INTERRUPT_REG );
+
+#if 0 /* XXX Now done by midlevel code XXX */
+
+    /* After the reset, there are no more connected or disconnected commands
+     * and no busy units; to avoid problems with re-inserting the commands
+     * into the issue_queue (via scsi_done()), the aborted commands are
+     * remebered in local variables first.
+     */
+    save_flags(flags);
+    cli();
+    connected = (Scsi_Cmnd *)hostdata->connected;
+    hostdata->connected = NULL;
+    disconnected_queue = (Scsi_Cmnd *)hostdata->disconnected_queue;
+    hostdata->disconnected_queue = NULL;
+#ifdef SUPPORT_TAGS
+    free_all_tags();
+#endif
+    for( i = 0; i < 8; ++i )
+	hostdata->busy[i] = 0;
+#ifdef REAL_DMA
+    hostdata->dma_len = 0;
+#endif
+    restore_flags(flags);
+
+    if ((cmd = connected)) {
+#if (NDEBUG & NDEBUG_ABORT)
+    printk( "scsi%d: reset aborted a connected command\n", H_NO(cmd));
+#endif
+	cmd->result = (cmd->result & 0xffff) | (DID_RESET << 16);
+	cmd->scsi_done( cmd );
+    }
+
+    for (i = 0; (cmd = disconnected_queue); ++i) {
+	disconnected_queue = NEXT(cmd);
+	NEXT(cmd) = NULL;
+	cmd->result = (cmd->result & 0xffff) | (DID_RESET << 16);
+	cmd->scsi_done( cmd );
+    }
+#if (NDEBUG & NDEBUG_ABORT)
+    if (i > 0)
+	printk( "scsi : reset aborted %d disconnected command(s)\n", i );
+#endif
+
+/* The Falcon lock should be released after a reset...
+ */
+/* ++guenther: moved to atari_scsi_reset(), to prevent a race between
+ * unlocking and enabling dma interrupt.
+ */
+/*    falcon_release_lock_if_possible( hostdata );*/
+
+#endif /* 0 */
+
+    return SCSI_RESET_WAKEUP;
+}
+
+/* Local Variables: */
+/* tab-width: 8     */
+/* End:             */
diff -u --recursive --new-file v1.3.93/linux/drivers/scsi/atari_scsi.c linux/drivers/scsi/atari_scsi.c
--- v1.3.93/linux/drivers/scsi/atari_scsi.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/scsi/atari_scsi.c	Fri Apr 19 02:35:24 1996
@@ -0,0 +1,1163 @@
+/*
+ * atari_scsi.c -- Device dependant functions for the Atari generic SCSI port
+ *
+ * Copyright 1994 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de>
+ *
+ *   Loosely based on the work of Robert De Vries' team and added:
+ *    - working real DMA
+ *    - Falcon support (untested yet!)   ++bjoern fixed and now it works
+ *    - lots of extensions and bug fixes.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file README.legal in the main directory of this archive
+ * for more details.
+ *
+ */
+
+
+/**************************************************************************/
+/*                                                                        */
+/* Notes for Falcon SCSI:                                                 */
+/* ----------------------                                                 */
+/*                                                                        */
+/* Since the Falcon SCSI uses the ST-DMA chip, that is shared among       */
+/* several device drivers, locking and unlocking the access to this       */
+/* chip is required. But locking is not possible from an interrupt,       */
+/* since it puts the process to sleep if the lock is not available.       */
+/* This prevents "late" locking of the DMA chip, i.e. locking it just     */
+/* before using it, since in case of disconnection-reconnection           */
+/* commands, the DMA is started from the reselection interrupt.           */
+/*                                                                        */
+/* Two possible schemes for ST-DMA-locking would be:                      */
+/*  1) The lock is taken for each command separately and disconnecting    */
+/*     is forbidden (i.e. can_queue = 1).                                 */
+/*  2) The DMA chip is locked when the first command comes in and         */
+/*     released when the last command is finished and all queues are      */
+/*     empty.                                                             */
+/* The first alternative would result in bad performance, since the       */
+/* interleaving of commands would not be used. The second is unfair to    */
+/* other drivers using the ST-DMA, because the queues will seldom be      */
+/* totally empty if there is a lot of disk traffic.                       */
+/*                                                                        */
+/* For this reasons I decided to employ a more elaborate scheme:          */
+/*  - First, we give up the lock everytime we can (for fairness), this    */
+/*    means every time a command finishes and there are no other commands */
+/*    on the disconnected queue.                                          */
+/*  - If there are others waiting to lock the DMA chip, we stop           */
+/*    issueing commands, i.e. moving them onto the issue queue.           */
+/*    Because of that, the disconnected queue will run empty in a         */
+/*    while. Instead we go to sleep on a 'fairness_queue'.                */
+/*  - If the lock is released, all processes waiting on the fairness      */
+/*    queue will be woken. The first of them trys to re-lock the DMA,     */
+/*    the others wait for the first to finish this task. After that,      */
+/*    they can all run on and do their commands...                        */
+/* This sounds complicated (and it is it :-(), but it seems to be a       */
+/* good compromise between fairness and performance: As long as noone     */
+/* else wants to work with the ST-DMA chip, SCSI can go along as          */
+/* usual. If now someone else comes, this behaviour is changed to a       */
+/* "fairness mode": just already initiated commands are finished and      */
+/* then the lock is released. The other one waiting will probably win     */
+/* the race for locking the DMA, since it was waiting for longer. And     */
+/* after it has finished, SCSI can go ahead again. Finally: I hope I      */
+/* have not produced any deadlock possibilities!                          */
+/*                                                                        */
+/**************************************************************************/
+
+
+
+#include <linux/config.h>
+#include <linux/module.h>
+
+/* #define NDEBUG (NDEBUG_DMA) */
+
+#define AUTOSENSE
+/* For the Atari version, use only polled IO or REAL_DMA */
+#define	REAL_DMA
+/* Support tagged queuing? (on devices that are able to... :-) */
+#define	SUPPORT_TAGS
+#define	MAX_TAGS 32
+
+#include <linux/types.h>
+#include <linux/stddef.h>
+#include <linux/ctype.h>
+#include <linux/delay.h>
+#include <linux/mm.h>
+#include <linux/blk.h>
+
+#include <asm/bootinfo.h>
+#include <asm/atarihw.h>
+#include <asm/atariints.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/irq.h>
+#include <asm/traps.h>
+#include <asm/bitops.h>
+
+#include "scsi.h"
+#include "hosts.h"
+#include "atari_scsi.h"
+#include "NCR5380.h"
+#include "constants.h"
+#include <asm/atari_stdma.h>
+#include <asm/io.h>
+
+#include<linux/stat.h>
+
+struct proc_dir_entry proc_scsi_atari = {
+    PROC_SCSI_ATARI, 5, "Atari",
+    S_IFDIR | S_IRUGO | S_IXUGO, 2
+};
+
+#define	IS_A_TT()	ATARIHW_PRESENT(TT_SCSI)
+
+#define	SCSI_DMA_WRITE_P(elt,val)				\
+	do {							\
+		unsigned long v = val;				\
+		tt_scsi_dma.elt##_lo = v & 0xff;		\
+		v >>= 8;					\
+		tt_scsi_dma.elt##_lmd = v & 0xff;		\
+		v >>= 8;					\
+		tt_scsi_dma.elt##_hmd = v & 0xff;		\
+		v >>= 8;					\
+		tt_scsi_dma.elt##_hi = v & 0xff;		\
+	} while(0)
+
+#define	SCSI_DMA_READ_P(elt)					\
+	(((unsigned long)tt_scsi_dma.elt##_hi  << 24) |		\
+	 ((unsigned long)tt_scsi_dma.elt##_hmd << 16) |		\
+	 ((unsigned long)tt_scsi_dma.elt##_lmd << 8) |		\
+	  (unsigned long)tt_scsi_dma.elt##_lo)
+
+
+#define	SCSI_DMA_SETADR(adr)				\
+    do {						\
+	unsigned long __adr = (adr);			\
+	st_dma.dma_lo = (unsigned char)__adr;		\
+	MFPDELAY();					\
+	__adr >>= 8;					\
+	st_dma.dma_md = (unsigned char)__adr;		\
+	MFPDELAY();					\
+	__adr >>= 8;					\
+	st_dma.dma_hi = (unsigned char)__adr;		\
+	MFPDELAY();					\
+    } while(0)
+
+#define	SCSI_DMA_GETADR() ({				\
+    unsigned long	__adr;				\
+    __adr = st_dma.dma_lo;				\
+    MFPDELAY();						\
+    __adr |= (st_dma.dma_md & 0xff) << 8;		\
+    MFPDELAY();						\
+    __adr |= (st_dma.dma_hi & 0xff) << 16;		\
+    MFPDELAY();						\
+    __adr;						\
+})
+
+#define	ENABLE_IRQ()					\
+	do {						\
+		if (IS_A_TT())				\
+			atari_enable_irq( IRQ_TT_MFP_SCSI );	\
+		else					\
+			atari_enable_irq( IRQ_MFP_FSCSI );	\
+	} while(0)
+
+#define	DISABLE_IRQ()					\
+	do {						\
+		if (IS_A_TT())				\
+			atari_disable_irq( IRQ_TT_MFP_SCSI );	\
+		else					\
+			atari_disable_irq( IRQ_MFP_FSCSI );	\
+	} while(0)
+
+
+#define HOSTDATA_DMALEN		(((struct NCR5380_hostdata *) \
+				(atari_scsi_host->hostdata))->dma_len)
+
+/* Time (in jiffies) to wait after a reset; the SCSI standard calls for 250ms,
+ * we usually do 0.5s to be on the safe side. But Toshiba CD-ROMs once more
+ * need ten times the standard value... */
+#ifndef CONFIG_ATARI_SCSI_TOSHIBA_DELAY
+#define	AFTER_RESET_DELAY	(HZ/2)
+#else
+#define	AFTER_RESET_DELAY	(5*HZ/2)
+#endif
+
+/***************************** Prototypes *****************************/
+
+#ifdef REAL_DMA
+static int scsi_dma_is_ignored_buserr( unsigned char dma_stat );
+static void scsi_dma_buserr( int irq, struct pt_regs *fp, void *dummy);
+static void atari_scsi_fetch_restbytes( void );
+static long atari_scsi_dma_residual( struct Scsi_Host *instance );
+static int falcon_classify_cmd( Scsi_Cmnd *cmd );
+static unsigned long atari_dma_xfer_len( unsigned long wanted_len,
+                                         Scsi_Cmnd *cmd, int write_flag );
+#endif
+static void scsi_tt_intr( int irq, struct pt_regs *fp, void *dummy);
+static void scsi_falcon_intr( int irq, struct pt_regs *fp, void *dummy);
+static void falcon_release_lock_if_possible( struct NCR5380_hostdata *
+                                             hostdata );
+static void falcon_get_lock( void );
+static void atari_scsi_reset_boot( void );
+static unsigned char atari_scsi_tt_reg_read( unsigned char reg );
+static void atari_scsi_tt_reg_write( unsigned char reg, unsigned char value);
+static unsigned char atari_scsi_falcon_reg_read( unsigned char reg );
+static void atari_scsi_falcon_reg_write( unsigned char reg, unsigned char value );
+
+/************************* End of Prototypes **************************/
+
+
+static struct Scsi_Host *atari_scsi_host = NULL;
+static unsigned char (*atari_scsi_reg_read)( unsigned char reg );
+static void (*atari_scsi_reg_write)( unsigned char reg, unsigned char value );
+
+#ifdef REAL_DMA
+static unsigned long	atari_dma_residual, atari_dma_startaddr;
+static short		atari_dma_active;
+/* pointer to the dribble buffer */
+static char		*atari_dma_buffer = NULL;
+/* precalculated physical address of the dribble buffer */
+static unsigned long	atari_dma_phys_buffer;
+/* != 0 tells the Falcon int handler to copy data from the dribble buffer */
+static char		*atari_dma_orig_addr;
+/* size of the dribble buffer; 4k seems enough, since the Falcon cannot use
+ * scatter-gather anyway, so most transfers are 1024 byte only. In the rare
+ * cases where requests to physical contiguous buffers have been merged, this
+ * request is <= 4k (one page). So I don't think we have to split transfers
+ * just due to this buffer size...
+ */
+#define	STRAM_BUFFER_SIZE	(4096)
+/* mask for address bits that can't be used with the ST-DMA */
+static unsigned long	atari_dma_stram_mask;
+#define STRAM_ADDR(a)	(((a) & atari_dma_stram_mask) == 0)
+/* number of bytes to cut from a transfer to handle NCR overruns */
+static int atari_read_overruns = 0;
+#endif
+
+int setup_can_queue = -1;
+int setup_cmd_per_lun = -1;
+int setup_sg_tablesize = -1;
+#ifdef SUPPORT_TAGS
+int setup_use_tagged_queuing = -1;
+#endif
+int setup_hostid = -1;
+
+
+#if defined(REAL_DMA)
+
+static int scsi_dma_is_ignored_buserr( unsigned char dma_stat )
+{
+	int i;
+	unsigned long	addr = SCSI_DMA_READ_P( dma_addr ), end_addr;
+
+	if (dma_stat & 0x01) {
+
+		/* A bus error happens when DMA-ing from the last page of a
+		 * physical memory chunk (DMA prefetch!), but that doesn't hurt.
+		 * Check for this case:
+		 */
+		
+		for( i = 0; i < boot_info.num_memory; ++i ) {
+			end_addr = boot_info.memory[i].addr +
+				boot_info.memory[i].size;
+			if (end_addr <= addr && addr <= end_addr + 4)
+				return( 1 );
+		}
+	}
+	return( 0 );
+}
+
+
+static void scsi_dma_buserr (int irq, struct pt_regs *fp, void *dummy)
+{
+	unsigned char	dma_stat = tt_scsi_dma.dma_ctrl;
+
+	/* Don't do anything if a NCR interrupt is pending. Probably it's just
+	 * masked... */
+	if (atari_irq_pending( IRQ_TT_MFP_SCSI ))
+		return;
+	
+	printk("Bad SCSI DMA interrupt! dma_addr=0x%08lx dma_stat=%02x dma_cnt=%08lx\n",
+	       SCSI_DMA_READ_P(dma_addr), dma_stat, SCSI_DMA_READ_P(dma_cnt));
+	if (dma_stat & 0x80) {
+		if (!scsi_dma_is_ignored_buserr( dma_stat ))
+			printk( "SCSI DMA bus error -- bad DMA programming!\n" );
+	}
+	else {
+		/* Under normal circumstances we never should get to this point,
+		 * since both interrupts are triggered simultaneously and the 5380
+		 * int has higher priority. When this irq is handled, that DMA
+		 * interrupt is cleared. So a warning message is printed here.
+		 */
+		printk( "SCSI DMA intr ?? -- this shouldn't happen!\n" );
+	}
+}
+
+#endif
+
+
+static void scsi_tt_intr (int irq, struct pt_regs *fp, void *dummy)
+{
+	unsigned long	flags;
+#ifdef REAL_DMA
+	int dma_stat;
+#endif
+
+	/* If we got this interrupt, we don't need the other one from the DMA any
+	 * more. So clear it. */
+	atari_clear_pending_irq( IRQ_TT_MFP_SCSIDMA );
+	/* After this has been done, we can make this int handler "slow", i.e.
+	 * mask the NCR int and lower the IPL, as a slow int would do (see
+	 * arch/m68k/atari/ataints.c) */
+	atari_disable_irq( IRQ_TT_MFP_SCSI );
+	save_flags(flags);
+	flags &= 0xf8ff;
+	flags |= fp->sr & 0x0700;
+	restore_flags(flags);
+	
+#ifdef REAL_DMA
+	dma_stat = tt_scsi_dma.dma_ctrl;
+
+#if (NDEBUG & NDEBUG_INTR)
+	printk("scsi%d: NCR5380 interrupt, DMA status = %02x\n",
+	       atari_scsi_host->host_no, dma_stat & 0xff);
+#endif
+
+	/* Look if it was the DMA that has interrupted: First possibility
+	 * is that a bus error occured...
+	 */
+	if (dma_stat & 0x80) {
+		if (!scsi_dma_is_ignored_buserr( dma_stat )) {
+			printk( "SCSI DMA caused bus error near 0x%08lx\n",
+					SCSI_DMA_READ_P( dma_addr ));
+			panic( "SCSI DMA bus error -- bad DMA programming!" );
+		}
+	}
+
+	/* If the DMA is active but not finished, we have the the case
+	 * that some other 5380 interrupt occured within the DMA transfer.
+	 * This means we have residual bytes, if the desired end address
+	 * is not yet reached. Maybe we have to fetch some bytes from the
+	 * rest data register, too. The residual must be calculated from
+	 * the address pointer, not the counter register, because only the
+	 * addr reg counts bytes not yet written and pending in the rest
+	 * data reg!
+	 */
+	if ((dma_stat & 0x02) && !(dma_stat & 0x40)) {
+		atari_dma_residual = HOSTDATA_DMALEN - (SCSI_DMA_READ_P( dma_addr ) -
+												atari_dma_startaddr);
+#if (NDEBUG & NDEBUG_DMA)
+		printk( "SCSI DMA: There are %ld residual bytes.\n",
+				atari_dma_residual );
+#endif
+		if ((signed int)atari_dma_residual < 0)
+			atari_dma_residual = 0;
+		if ((dma_stat & 1) == 0) {
+			/* After read operations, we maybe have to
+			   transport some rest bytes */
+			atari_scsi_fetch_restbytes();
+		}
+		else {
+			/* There seems to be a nasty bug in some SCSI-DMA/NCR
+			   combinations: If a target disconnects while a write
+			   operation is going on, the address register of the
+			   DMA may be a few bytes farer than it actually read.
+			   This is probably due to DMA prefetching and a delay
+			   between DMA and NCR.  Experiments showed that the
+			   dma_addr is 9 bytes to high, but this could vary.
+			   The problem is, that the residual is thus calculated
+			   wrong and the next transfer will start behind where
+			   it should.  So we round up the residual to the next
+			   multiple of a sector size, if it isn't already a
+			   multiple and the originally expected transfer size
+			   was.  The latter condition is there to ensure that
+			   the correction is taken only for "real" data
+			   transfers and not for, e.g., the parameters of some
+			   other command.  These shouldn't disconnect anyway.
+			   */
+			if (atari_dma_residual & 0x1ff) {
+#if (NDEBUG & NDEBUG_DMA)
+				printk("SCSI DMA: DMA bug corrected, difference %ld bytes\n",
+				       512 - (atari_dma_residual & 0x1ff));
+#endif
+				atari_dma_residual = (atari_dma_residual + 511) & ~0x1ff;
+			}
+		}
+		tt_scsi_dma.dma_ctrl = 0;
+	}
+
+	/* If the DMA is finished, fetch the rest bytes and turn it off */
+	if (dma_stat & 0x40) {
+		atari_dma_residual = 0;
+		if ((dma_stat & 1) == 0)
+			atari_scsi_fetch_restbytes();
+		tt_scsi_dma.dma_ctrl = 0;
+	}
+
+#endif /* REAL_DMA */
+	
+	NCR5380_intr (0, 0, 0);
+
+	/* To be sure the int is not masked */
+	atari_enable_irq( IRQ_TT_MFP_SCSI );
+}
+
+
+static void scsi_falcon_intr (int irq, struct pt_regs *fp, void *dummy)
+{
+#ifdef REAL_DMA
+	int dma_stat;
+
+	/* Turn off DMA and select sector counter register before
+	 * accessing the status register (Atari recommendation!)
+	 */
+	st_dma.dma_mode_status = 0x90;
+	dma_stat = st_dma.dma_mode_status;
+
+	/* Bit 0 indicates some error in the DMA process... don't know
+	 * what happened exactly (no further docu).
+	 */
+	if (!(dma_stat & 0x01)) {
+		/* DMA error */
+		printk( "SCSI DMA error near 0x%08lx!\n", SCSI_DMA_GETADR() );
+	}
+
+	/* If the DMA was active, but now bit 1 is not clear, it is some
+	 * other 5380 interrupt that finishes the DMA transfer. We have to
+	 * calculate the number of residual bytes and give a warning if
+	 * bytes are stuck in the ST-DMA fifo (there's no way to reach them!)
+	 */
+	if (atari_dma_active && (dma_stat & 0x02)) {
+		unsigned long	transferred;
+
+		transferred = SCSI_DMA_GETADR() - atari_dma_startaddr;
+		/* The ST-DMA address is incremented in 2-byte steps, but the
+		 * data are written only in 16-byte chunks. If the number of
+		 * transferred bytes is not divisible by 16, the remainder is
+		 * lost somewhere in outer space.
+		 */
+		if (transferred & 15)
+			printk( "SCSI DMA error: %ld bytes lost in ST-DMA fifo :-((\n",
+			       transferred & 15 );
+
+		atari_dma_residual = HOSTDATA_DMALEN - transferred;
+#if (NDEBUG & NDEBUG_DMA)
+		printk( "SCSI DMA: There are %ld residual bytes.\n",
+		       atari_dma_residual );
+#endif
+	}
+	else
+		atari_dma_residual = 0;
+	atari_dma_active = 0;
+
+	if (atari_dma_orig_addr) {
+		/* If the dribble buffer was used on a read operation, copy the DMA-ed
+		 * data to the original destination address.
+		 */
+		memcpy( atari_dma_orig_addr, (void *)PTOV(atari_dma_startaddr),
+		       HOSTDATA_DMALEN - atari_dma_residual );
+		atari_dma_orig_addr = NULL;
+	}
+
+#endif /* REAL_DMA */
+
+	NCR5380_intr (0, 0, 0);
+}
+
+
+#ifdef REAL_DMA
+static void atari_scsi_fetch_restbytes( void )
+{
+	int nr;
+	char	*src, *dst;
+
+	/* fetch rest bytes in the DMA register */
+	dst = (char *)SCSI_DMA_READ_P( dma_addr );
+	if ((nr = ((long)dst & 3))) {
+		/* there are 'nr' bytes left for the last long address before the
+		   DMA pointer */
+		dst = (char *)( (unsigned long)dst & ~3 );
+#if (NDEBUG & NDEBUG_DMA)
+		printk( "SCSI DMA: there are %d rest bytes for phys addr 0x%08lx",
+		       nr, (long)dst );
+#endif
+		dst = (char *)PTOV(dst);  /* The content of the DMA pointer
+					   * is a physical address! */
+#if (NDEBUG & NDEBUG_DMA)
+		printk( " = virt addr 0x%08lx\n", (long)dst );
+#endif
+		for( src = (char *)&tt_scsi_dma.dma_restdata; nr > 0; --nr )
+			*dst++ = *src++;
+	}
+}
+#endif /* REAL_DMA */
+
+
+static int falcon_got_lock = 0;
+static struct wait_queue	*falcon_fairness_wait = NULL;
+static int falcon_trying_lock = 0;
+static struct wait_queue	*falcon_try_wait = NULL;
+static int falcon_dont_release = 0;
+
+/* This function releases the lock on the DMA chip if there is no
+ * connected command and the disconnected queue is empty. On
+ * releasing, instances of falcon_get_lock are awoken, that put
+ * themselves to sleep for fairness. They can now try to get the lock
+ * again (but others waiting longer more probably will win).
+ */
+
+static void
+falcon_release_lock_if_possible( struct NCR5380_hostdata * hostdata )
+{
+	unsigned long	oldflags;
+		
+	if (IS_A_TT()) return;
+	
+	save_flags(oldflags);
+	cli();
+
+	if (falcon_got_lock &&
+		!hostdata->disconnected_queue &&
+		!hostdata->issue_queue &&
+		!hostdata->connected) {
+
+		if (falcon_dont_release) {
+#if 0
+			printk("WARNING: Lock release not allowed. Ignored\n");
+#endif
+			restore_flags(oldflags);
+			return;
+		}
+		falcon_got_lock = 0;
+		stdma_release();
+		wake_up( &falcon_fairness_wait );
+	}
+
+	restore_flags(oldflags);
+}
+
+/* This function manages the locking of the ST-DMA.
+ * If the DMA isn't locked already for SCSI, it trys to lock it by
+ * calling stdma_lock(). But if the DMA is locked by the SCSI code and
+ * there are other drivers waiting for the chip, we do not issue the
+ * command immediately but wait on 'falcon_fairness_queue'. We will be
+ * waked up when the DMA is unlocked by some SCSI interrupt. After that
+ * we try to get the lock again.
+ * But we must be prepared that more than one instance of
+ * falcon_get_lock() is waiting on the fairness queue. They should not
+ * try all at once to call stdma_lock(), one is enough! For that, the
+ * first one sets 'falcon_trying_lock', others that see that variable
+ * set wait on the queue 'falcon_try_wait'.
+ * Complicated, complicated.... Sigh...
+ */
+
+static void falcon_get_lock( void )
+{
+	unsigned long	oldflags;
+
+	if (IS_A_TT()) return;
+
+	save_flags(oldflags);
+	cli();
+
+	while( intr_count == 0 && falcon_got_lock && stdma_others_waiting() )
+		sleep_on( &falcon_fairness_wait );
+
+	while (!falcon_got_lock) {
+		if (intr_count > 0)
+			panic( "Falcon SCSI hasn't ST-DMA lock in interrupt" );
+		if (!falcon_trying_lock) {
+			falcon_trying_lock = 1;
+			stdma_lock(scsi_falcon_intr, NULL);
+			falcon_got_lock = 1;
+			falcon_trying_lock = 0;
+			wake_up( &falcon_try_wait );
+		}
+		else {
+			sleep_on( &falcon_try_wait );
+		}
+	}	
+
+	restore_flags(oldflags);
+	if (!falcon_got_lock)
+		panic("Falcon SCSI: someone stole the lock :-(\n");
+}
+
+
+/* This is the wrapper function for NCR5380_queue_command(). It just
+ * trys to get the lock on the ST-DMA (see above) and then calls the
+ * original function.
+ */
+
+#if 0
+int atari_queue_command (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
+{
+	/* falcon_get_lock();
+	 * ++guenther: moved to NCR5380_queue_command() to prevent
+	 * race condition, see there for an explanation.
+	 */
+	return( NCR5380_queue_command( cmd, done ) );
+}
+#endif
+
+
+#define	RTC_READ(reg)				\
+    ({	unsigned char	__val;			\
+		outb(reg,&tt_rtc.regsel);	\
+		__val = tt_rtc.data;		\
+		__val;				\
+	})
+
+#define	RTC_WRITE(reg,val)			\
+    do {					\
+		outb(reg,&tt_rtc.regsel);	\
+		tt_rtc.data = (val);		\
+	} while(0)
+    
+				   
+int atari_scsi_detect (Scsi_Host_Template *host)
+{
+	static int called = 0;
+	struct Scsi_Host *instance;
+
+	if (!MACH_IS_ATARI ||
+	    (!ATARIHW_PRESENT(ST_SCSI) && !ATARIHW_PRESENT(TT_SCSI)) ||
+	    called)
+		return( 0 );
+
+	host->proc_dir = &proc_scsi_atari;
+
+	atari_scsi_reg_read  = IS_A_TT() ? atari_scsi_tt_reg_read :
+					   atari_scsi_falcon_reg_read;
+	atari_scsi_reg_write = IS_A_TT() ? atari_scsi_tt_reg_write :
+					   atari_scsi_falcon_reg_write;
+
+	/* setup variables */
+	host->can_queue =
+		(setup_can_queue > 0) ? setup_can_queue :
+		IS_A_TT() ? ATARI_TT_CAN_QUEUE : ATARI_FALCON_CAN_QUEUE;
+	host->cmd_per_lun =
+		(setup_cmd_per_lun > 0) ? setup_cmd_per_lun :
+		IS_A_TT() ? ATARI_TT_CMD_PER_LUN : ATARI_FALCON_CMD_PER_LUN;
+	/* Force sg_tablesize to 0 on a Falcon! */
+	host->sg_tablesize =
+		!IS_A_TT() ? ATARI_FALCON_SG_TABLESIZE :
+		(setup_sg_tablesize >= 0) ? setup_sg_tablesize : ATARI_TT_SG_TABLESIZE;
+
+	if (setup_hostid >= 0)
+		host->this_id = setup_hostid;
+	else {
+		/* use 7 as default */
+		host->this_id = 7;
+		/* Test if a host id is set in the NVRam */
+		if (ATARIHW_PRESENT(TT_CLK)) {
+			unsigned char sum = 0, b;
+			int i;
+			
+			/* Make checksum */
+			for( i = 14; i < 62; ++i )
+				sum += RTC_READ(i);
+			
+			if (/* NV-Ram checksum valid? */
+				RTC_READ(62) == sum && RTC_READ(63) == ~sum &&
+				/* Arbitration enabled? (for TOS) */
+				(b = RTC_READ( 30 )) & 0x80) {
+				host->this_id = b & 7;
+			}
+		}
+	}
+
+#ifdef SUPPORT_TAGS
+	if (setup_use_tagged_queuing < 0)
+		setup_use_tagged_queuing = DEFAULT_USE_TAGGED_QUEUING;
+#endif
+
+	/* If running on a Falcon and if there's TT-Ram (i.e., more than one
+	 * memory block, since there's always ST-Ram in a Falcon), then allocate a
+	 * STRAM_BUFFER_SIZE byte dribble buffer for transfers from/to alternative
+	 * Ram.
+	 */
+	if (MACH_IS_ATARI && ATARIHW_PRESENT(ST_SCSI) &&
+	    !ATARIHW_PRESENT(EXTD_DMA) && boot_info.num_memory > 1) {
+		atari_dma_buffer = scsi_init_malloc(STRAM_BUFFER_SIZE,
+						    GFP_ATOMIC | GFP_DMA);
+		atari_dma_phys_buffer = VTOP( atari_dma_buffer );
+		atari_dma_orig_addr = 0;
+	}
+
+	instance = scsi_register (host, sizeof (struct NCR5380_hostdata));
+	atari_scsi_host = instance;
+	instance->irq = IS_A_TT() ? IRQ_TT_MFP_SCSI : IRQ_MFP_FSCSI;
+
+	atari_scsi_reset_boot();
+	NCR5380_init (instance, 0);
+
+	if (IS_A_TT()) {
+
+		/* This int is actually "pseudo-slow", i.e. it acts like a slow
+		 * interrupt after having cleared the pending flag for the DMA
+		 * interrupt. */
+		add_isr(IRQ_TT_MFP_SCSI, scsi_tt_intr, IRQ_TYPE_PRIO,
+			NULL, "SCSI NCR5380");
+		tt_mfp.active_edge |= 0x80;		/* SCSI int on L->H */
+#ifdef REAL_DMA
+		/* On the TT, we got a second interrupt for DMA ready and DMA buserror.
+		 * Since on DMA ready we get a "normal" interrupt, too, the service
+		 * routine for the second int just checks for buserrs.
+		 */
+		add_isr(IRQ_TT_MFP_SCSIDMA, scsi_dma_buserr, IRQ_TYPE_SLOW,
+			NULL, "SCSI DMA");
+		tt_mfp.active_edge &= ~0x20;	/* DMA int on H->L */
+
+		tt_scsi_dma.dma_ctrl = 0;
+		atari_dma_residual = 0;
+#endif /* REAL_DMA */
+
+		if (is_medusa) {
+			/* While the read overruns (described by Drew Eckhardt in
+			 * NCR5380.c) never happened on TTs, they do in fact on the Medusa
+			 * (This was the cause why SCSI didn't work right for so long
+			 * there.) Since handling the overruns slows down a bit, I turned
+			 * the #ifdef's into a runtime condition.
+			 *
+			 * In principle it should be sufficient to do max. 1 byte with
+			 * PIO, but there is another problem on the Medusa with the DMA
+			 * rest data register. So 'atari_read_overruns' is currently set
+			 * to 4 to avoid having transfers that aren't a multiple of 4. If
+			 * the rest data bug is fixed, this can be lowered to 1.
+			 */
+			atari_read_overruns = 4;
+		}
+		
+	}
+	else { /* ! IS_A_TT */
+		
+		/* Nothing to do for the interrupt: the ST-DMA is initialized
+		 * already by atari_init_INTS()
+		 */
+
+#ifdef REAL_DMA
+		atari_dma_residual = 0;
+		atari_dma_active = 0;
+		atari_dma_stram_mask = (ATARIHW_PRESENT(EXTD_DMA) ? 0x00000000
+					: 0xff000000);
+#endif
+	}
+
+	printk( "scsi%d: options CAN_QUEUE=%d CMD_PER_LUN=%d SCAT-GAT=%d "
+#ifdef SUPPORT_TAGS
+			"TAGGED-QUEUING=%s "
+#endif
+			"HOSTID=%d",
+			instance->host_no, instance->hostt->can_queue,
+			instance->hostt->cmd_per_lun,
+			instance->hostt->sg_tablesize,
+#ifdef SUPPORT_TAGS
+			setup_use_tagged_queuing ? "yes" : "no",
+#endif
+			instance->hostt->this_id );
+	NCR5380_print_options (instance);
+	printk ("\n");
+
+	called = 1;
+	return( 1 );
+}
+
+#ifdef MODULE
+int atari_scsi_release (struct Scsi_Host *sh)
+{
+	if (IS_A_TT()) {
+		remove_isr (IRQ_TT_MFP_SCSI, scsi_tt_intr);
+#ifdef REAL_DMA
+		remove_isr (IRQ_TT_MFP_SCSIDMA, scsi_dma_buserr);
+#endif
+	}
+	if (atari_dma_bufffer)
+		scsi_init_free (atari_dma_buffer, STRAM_BUFFER_SIZE);
+	return 1;
+}
+#endif
+
+void atari_scsi_setup( char *str, int *ints )
+{
+	/* Format of atascsi parameter is:
+	 *   atascsi=<can_queue>,<cmd_per_lun>,<sg_tablesize>,<hostid>,<use_tags>
+	 * Defaults depend on TT or Falcon, hostid determined at run time.
+	 * Negative values mean don't change.
+	 */
+	
+	/* Grmbl... the standard parameter parsing can't handle negative numbers
+	 * :-( So let's do it ourselves!
+	 */
+
+	int i = ints[0]+1, fact;
+
+	while( str && (isdigit(*str) || *str == '-') && i <= 10) {
+		if (*str == '-')
+			fact = -1, ++str;
+		else
+			fact = 1;
+		ints[i++] = simple_strtoul( str, NULL, 0 ) * fact;
+		if ((str = strchr( str, ',' )) != NULL)
+			++str;
+	}
+	ints[0] = i-1;
+	
+	if (ints[0] < 1) {
+		printk( "atari_scsi_setup: no arguments!\n" );
+		return;
+	}
+
+	if (ints[0] >= 1) {
+		if (ints[1] > 0)
+			/* no limits on this, just > 0 */
+			setup_can_queue = ints[1];
+	}
+	if (ints[0] >= 2) {
+		if (ints[2] > 0)
+			setup_cmd_per_lun = ints[2];
+	}
+	if (ints[0] >= 3) {
+		if (ints[3] >= 0) {
+			setup_sg_tablesize = ints[3];
+			/* Must be <= SG_ALL (255) */
+			if (setup_sg_tablesize > SG_ALL)
+				setup_sg_tablesize = SG_ALL;
+		}
+	}
+	if (ints[0] >= 4) {
+		/* Must be between 0 and 7 */
+		if (ints[4] >= 0 && ints[4] <= 7)
+			setup_hostid = ints[4];
+		else if (ints[4] > 7)
+			printk( "atari_scsi_setup: invalid host ID %d !\n", ints[4] );
+	}
+#ifdef SUPPORT_TAGS
+	if (ints[0] >= 5) {
+		if (ints[5] >= 0)
+			setup_use_tagged_queuing = !!ints[5];
+	}
+#endif
+}
+
+int atari_scsi_reset( Scsi_Cmnd *cmd )
+{
+	int		rv;
+	struct NCR5380_hostdata *hostdata =
+		(struct NCR5380_hostdata *)cmd->host->hostdata;
+
+	/* For doing the reset, SCSI interrupts must be disabled first,
+	 * since the 5380 raises its IRQ line while _RST is active and we
+	 * can't disable interrupts completely, since we need the timer.
+	 */
+	/* And abort a maybe active DMA transfer */
+	if (IS_A_TT()) {
+		atari_turnoff_irq( IRQ_TT_MFP_SCSI );
+#ifdef REAL_DMA
+		tt_scsi_dma.dma_ctrl = 0;
+#endif /* REAL_DMA */
+	}
+	else {
+		atari_turnoff_irq( IRQ_MFP_FSCSI );
+#ifdef REAL_DMA
+		st_dma.dma_mode_status = 0x90;
+		atari_dma_active = 0;
+		atari_dma_orig_addr = NULL;
+#endif /* REAL_DMA */
+	}
+
+	rv = NCR5380_reset( cmd );
+
+	/* Re-enable ints */
+	if (IS_A_TT()) {
+		atari_turnon_irq( IRQ_TT_MFP_SCSI );
+	}
+	else {
+		atari_turnon_irq( IRQ_MFP_FSCSI );
+	}
+	falcon_release_lock_if_possible(hostdata);
+
+	return( rv );
+}
+
+	
+static void atari_scsi_reset_boot( void )
+{
+	unsigned long end;
+	
+	/*
+	 * Do a SCSI reset to clean up the bus during initialization. No messing
+	 * with the queues, interrupts, or locks necessary here.
+	 */
+
+	printk( "Atari SCSI: resetting the SCSI bus..." );
+
+	/* get in phase */
+	NCR5380_write( TARGET_COMMAND_REG,
+		      PHASE_SR_TO_TCR( NCR5380_read(STATUS_REG) ));
+
+	/* assert RST */
+	NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST );
+	/* The min. reset hold time is 25us, so 40us should be enough */
+	udelay( 50 );
+	/* reset RST and interrupt */
+	NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE );
+	NCR5380_read( RESET_PARITY_INTERRUPT_REG );
+
+	for( end = jiffies + AFTER_RESET_DELAY; jiffies < end; )
+		barrier();
+
+	printk( " done\n" );
+}
+
+
+const char * atari_scsi_info (struct Scsi_Host *host)
+{
+	/* atari_scsi_detect() is verbose enough... */
+	static const char string[] = "Atari native SCSI";
+	return string;
+}
+
+
+#if defined(REAL_DMA)
+
+unsigned long atari_scsi_dma_setup( struct Scsi_Host *instance, void *data,
+				   unsigned long count, int dir )
+{
+	unsigned long addr = VTOP( data );
+
+#if (NDEBUG & NDEBUG_DMA)
+	printk ("scsi%d: setting up dma, data = %p, phys = %lx, count = %ld, dir = %d\n",
+		instance->host_no, data, addr, count, dir);
+#endif
+
+	if (!IS_A_TT() && !STRAM_ADDR(addr)) {
+		/* If we have a non-DMAable address on a Falcon, use the dribble
+		 * buffer; 'orig_addr' != 0 in the read case tells the interrupt
+		 * handler to copy data from the dribble buffer to the originally
+		 * wanted address.
+		 */
+		if (dir)
+			memcpy( atari_dma_buffer, data, count );
+		else
+			atari_dma_orig_addr = data;
+		addr = atari_dma_phys_buffer;
+	}
+	
+	atari_dma_startaddr = addr;	/* Needed for calculating residual later. */
+  
+	/* Cache cleanup stuff: On writes, push any dirty cache out before sending
+	 * it to the peripheral. (Must be done before DMA setup, since at least
+	 * the ST-DMA begins to fill internal buffers right after setup. For
+	 * reads, invalidate any cache, may be altered after DMA without CPU
+	 * knowledge.
+	 * 
+	 * ++roman: For the Medusa, there's no need at all for that cache stuff,
+	 * because the hardware does bus snooping (fine!).
+	 */
+	dma_cache_maintainance( addr, count, dir );
+
+	if (count == 0)
+		printk("SCSI warning: DMA programmed for 0 bytes !\n");
+
+	if (IS_A_TT()) {
+		tt_scsi_dma.dma_ctrl = dir;
+		SCSI_DMA_WRITE_P( dma_addr, addr );
+		SCSI_DMA_WRITE_P( dma_cnt, count );
+		tt_scsi_dma.dma_ctrl = dir | 2;
+	}
+	else { /* ! IS_A_TT */
+  
+		/* set address */
+		SCSI_DMA_SETADR( addr );
+
+		/* toggle direction bit to clear FIFO and set DMA direction */
+		dir <<= 8;
+		st_dma.dma_mode_status = 0x90 | dir;
+		st_dma.dma_mode_status = 0x90 | (dir ^ 0x100);
+		st_dma.dma_mode_status = 0x90 | dir;
+		udelay(40);
+		/* On writes, round up the transfer length to the next multiple of 512
+		 * (see also comment at atari_dma_xfer_len()). */
+		st_dma.fdc_acces_seccount = (count + (dir ? 511 : 0)) >> 9;
+		udelay(40);
+		st_dma.dma_mode_status = 0x10 | dir;
+		udelay(40);
+		/* need not restore value of dir, only boolean value is tested */
+		atari_dma_active = 1;
+	}
+
+	return( count );
+}
+
+
+static long atari_scsi_dma_residual( struct Scsi_Host *instance )
+{
+	return( atari_dma_residual );
+}
+
+
+#define	CMD_SURELY_BLOCK_MODE	0
+#define	CMD_SURELY_BYTE_MODE	1
+#define	CMD_MODE_UNKNOWN		2
+
+static int falcon_classify_cmd( Scsi_Cmnd *cmd )
+{
+	unsigned char opcode = cmd->cmnd[0];
+	
+	if (opcode == READ_DEFECT_DATA || opcode == READ_LONG ||
+		opcode == READ_BUFFER)
+		return( CMD_SURELY_BYTE_MODE );
+	else if (opcode == READ_6 || opcode == READ_10 ||
+		 opcode == 0xa8 /* READ_12 */ || opcode == READ_REVERSE ||
+		 opcode == RECOVER_BUFFERED_DATA) {
+		/* In case of a sequential-access target (tape), special care is
+		 * needed here: The transfer is block-mode only if the 'fixed' bit is
+		 * set! */
+		if (cmd->device->type == TYPE_TAPE && !(cmd->cmnd[1] & 1))
+			return( CMD_SURELY_BYTE_MODE );
+		else
+			return( CMD_SURELY_BLOCK_MODE );
+	}
+	else
+		return( CMD_MODE_UNKNOWN );
+}
+
+
+/* This function calculates the number of bytes that can be transferred via
+ * DMA. On the TT, this is arbitrary, but on the Falcon we have to use the
+ * ST-DMA chip. There are only multiples of 512 bytes possible and max.
+ * 255*512 bytes :-( This means also, that defining READ_OVERRUNS is not
+ * possible on the Falcon, since that would require to program the DMA for
+ * n*512 - atari_read_overrun bytes. But it seems that the Falcon doesn't have
+ * the overrun problem, so this question is academic :-)
+ */
+
+static unsigned long atari_dma_xfer_len( unsigned long wanted_len,
+					Scsi_Cmnd *cmd,
+					int write_flag )
+{
+	unsigned long	possible_len, limit;
+
+	if (IS_A_TT())
+		/* TT SCSI DMA can transfer arbitrary #bytes */
+		return( wanted_len );
+
+	/* ST DMA chip is stupid -- only multiples of 512 bytes! (and max.
+	 * 255*512 bytes, but this should be enough)
+	 *
+	 * ++roman: Aaargl! Another Falcon-SCSI problem... There are some commands
+	 * that return a number of bytes which cannot be known beforehand. In this
+	 * case, the given transfer length is an "allocation length". Now it
+	 * can happen that this allocation length is a multiple of 512 bytes and
+	 * the DMA is used. But if not n*512 bytes really arrive, some input data
+	 * will be lost in the ST-DMA's FIFO :-( Thus, we have to distinguish
+	 * between commands that do block transfers and those that do byte
+	 * transfers. But this isn't easy... there are lots of vendor specific
+	 * commands, and the user can issue any command via the
+	 * SCSI_IOCTL_SEND_COMMAND.
+	 *
+	 * The solution: We classify SCSI commands in 1) surely block-mode cmd.s,
+	 * 2) surely byte-mode cmd.s and 3) cmd.s with unknown mode. In case 1)
+	 * and 3), the thing to do is obvious: allow any number of blocks via DMA
+	 * or none. In case 2), we apply some heuristic: Byte mode is assumed if
+	 * the transfer (allocation) length is < 1024, hoping that no cmd. not
+	 * explicitly known as byte mode have such big allocation lengths...
+	 * BTW, all the discussion above applies only to reads. DMA writes are
+	 * unproblematic anyways, since the targets aborts the transfer after
+	 * receiving a sufficient number of bytes.
+	 *
+	 * Another point: If the transfer is from/to an non-ST-RAM address, we
+	 * use the dribble buffer and thus can do only STRAM_BUFFER_SIZE bytes.
+	 */
+
+	if (write_flag) {
+		/* Write operation can always use the DMA, but the transfer size must
+		 * be rounded up to the next multiple of 512 (atari_dma_setup() does
+		 * this).
+		 */
+		possible_len = wanted_len;
+	}
+	else {
+		/* Read operations: if the wanted transfer length is not a multiple of
+		 * 512, we cannot use DMA, since the ST-DMA cannot split transfers
+		 * (no interrupt on DMA finished!)
+		 */
+		if (wanted_len & 0x1ff)
+			possible_len = 0;
+		else {
+			/* Now classify the command (see above) and decide whether it is
+			 * allowed to do DMA at all */
+			switch( falcon_classify_cmd( cmd )) {
+			  case CMD_SURELY_BLOCK_MODE:
+				possible_len = wanted_len;
+				break;
+			  case CMD_SURELY_BYTE_MODE:
+				possible_len = 0; /* DMA prohibited */
+				break;
+			  case CMD_MODE_UNKNOWN:
+			  default:
+				/* For unknown commands assume block transfers if the transfer
+				 * size/allocation length is >= 1024 */
+				possible_len = (wanted_len < 1024) ? 0 : wanted_len;
+				break;
+			}
+		}
+	}
+	
+	/* Last step: apply the hard limit on DMA transfers */
+	limit = (atari_dma_buffer && !STRAM_ADDR( VTOP(cmd->SCp.ptr) )) ?
+		    STRAM_BUFFER_SIZE : 255*512;
+	if (possible_len > limit)
+		possible_len = limit;
+
+#if (NDEBUG & NDEBUG_DMA)
+	if (possible_len != wanted_len)
+		printk( "Sorry, must cut DMA transfer size to %ld bytes instead of %ld\n",
+				possible_len, wanted_len );
+#endif
+
+	return( possible_len );
+}
+
+
+#endif	/* REAL_DMA */
+
+
+/* NCR5380 register access functions
+ *
+ * There are separate functions for TT and Falcon, because the access
+ * methods are quite different. The calling macros NCR5380_read and
+ * NCR5380_write call these functions via function pointers.
+ */
+
+static unsigned char atari_scsi_tt_reg_read( unsigned char reg )
+{
+	return( tt_scsi_regp[reg * 2] );
+}
+
+static void atari_scsi_tt_reg_write( unsigned char reg, unsigned char value )
+{
+	tt_scsi_regp[reg * 2] = value;
+}
+
+static unsigned char atari_scsi_falcon_reg_read( unsigned char reg )
+{
+	dma_wd.dma_mode_status= (u_short)(0x88 + reg);
+	return( (u_char)dma_wd.fdc_acces_seccount );
+}
+
+static void atari_scsi_falcon_reg_write( unsigned char reg, unsigned char value )
+{
+	dma_wd.dma_mode_status = (u_short)(0x88 + reg);
+	dma_wd.fdc_acces_seccount = (u_short)value;
+}
+
+
+#include "atari_NCR5380.c"
+
+#ifdef MODULE
+Scsi_Host_Template driver_template = ATARI_SCSI;
+
+#include "scsi_module.c"
+#endif
diff -u --recursive --new-file v1.3.93/linux/drivers/scsi/atari_scsi.h linux/drivers/scsi/atari_scsi.h
--- v1.3.93/linux/drivers/scsi/atari_scsi.h	Thu Jan  1 02:00:00 1970
+++ linux/drivers/scsi/atari_scsi.h	Sat Apr 13 14:31:03 1996
@@ -0,0 +1,99 @@
+/*
+ * atari_scsi.h -- Header file for the Atari native SCSI driver
+ *
+ * Copyright 1994 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de>
+ *
+ * (Loosely based on the work of Robert De Vries' team)
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file README.legal in the main directory of this archive
+ * for more details.
+ *
+ */
+
+
+#ifndef ATARI_SCSI_H
+#define ATARI_SCSI_H
+
+/* (I_HAVE_OVERRUNS stuff removed) */
+
+#ifndef ASM
+int atari_scsi_abort (Scsi_Cmnd *);
+int atari_scsi_detect (Scsi_Host_Template *);
+const char *atari_scsi_info (struct Scsi_Host *);
+int atari_scsi_queue_command (Scsi_Cmnd *, void (*done) (Scsi_Cmnd *));
+int atari_scsi_reset (Scsi_Cmnd *);
+int atari_scsi_proc_info (char *, char **, off_t, int, int, int);
+#ifdef MODULE
+int atari_scsi_release (struct Scsi_Host *);
+#else
+#define atari_scsi_release NULL
+#endif
+
+/* The values for CMD_PER_LUN and CAN_QUEUE are somehow arbitrary. Higher
+ * values should work, too; try it! (but cmd_per_lun costs memory!) */
+
+/* But there seems to be a bug somewhere that requires CAN_QUEUE to be
+ * 2*CMD_OER_LUN. At least on a TT, no suprious timeouts seen since
+ * changed CMD_PER_LUN... */
+
+/* Note: The Falcon currently uses 8/1 setting due to unsolved problems with
+ * cmd_per_lun != 1 */
+
+#define ATARI_TT_CAN_QUEUE		16
+#define ATARI_TT_CMD_PER_LUN		8
+#define ATARI_TT_SG_TABLESIZE		SG_ALL
+
+#define ATARI_FALCON_CAN_QUEUE		8
+#define ATARI_FALCON_CMD_PER_LUN	1
+#define ATARI_FALCON_SG_TABLESIZE	SG_NONE
+
+#define	DEFAULT_USE_TAGGED_QUEUING	0
+
+
+#if defined (HOSTS_C) || defined (MODULE)
+
+#define ATARI_SCSI { NULL, NULL, NULL,				\
+  atari_scsi_proc_info,						\
+  "Atari native SCSI",						\
+  atari_scsi_detect,						\
+  atari_scsi_release,						\
+  atari_scsi_info,						\
+  /* command */ NULL,						\
+  atari_scsi_queue_command,					\
+  atari_scsi_abort,						\
+  atari_scsi_reset,						\
+  /* slave_attach */	NULL,					\
+  /* bios_param */	NULL,					\
+  /* can queue */	0, /* initialized at run-time */	\
+  /* host_id */		0, /* initialized at run-time */	\
+  /* scatter gather */	0, /* initialized at run-time */	\
+  /* cmd per lun */	0, /* initialized at run-time */	\
+  /* present */		0,					\
+  /* unchecked ISA DMA */ 0,					\
+  /* use_clustering */	DISABLE_CLUSTERING }
+
+#endif
+
+#ifndef HOSTS_C
+
+#define	NCR5380_implementation_fields	/* none */
+
+#define NCR5380_read(reg)		  atari_scsi_reg_read( reg )
+#define NCR5380_write(reg, value) atari_scsi_reg_write( reg, value )
+
+#define NCR5380_intr atari_scsi_intr
+#define NCR5380_queue_command atari_scsi_queue_command
+#define NCR5380_abort atari_scsi_abort
+#define NCR5380_proc_info atari_scsi_proc_info
+#define NCR5380_dma_read_setup(inst,d,c) atari_scsi_dma_setup (inst, d, c, 0)
+#define NCR5380_dma_write_setup(inst,d,c) atari_scsi_dma_setup (inst, d, c, 1)
+#define NCR5380_dma_residual(inst) atari_scsi_dma_residual( inst )
+#define	NCR5380_dma_xfer_len(i,cmd,phase) \
+	atari_dma_xfer_len(cmd->SCp.this_residual,cmd,((phase) & SR_IO) ? 0 : 1)
+
+#endif /* else def HOSTS_C */
+#endif /* ndef ASM */
+#endif /* ATARI_SCSI_H */
+
+
diff -u --recursive --new-file v1.3.93/linux/drivers/scsi/gvp11.c linux/drivers/scsi/gvp11.c
--- v1.3.93/linux/drivers/scsi/gvp11.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/scsi/gvp11.c	Mon Apr  1 22:14:33 1996
@@ -0,0 +1,246 @@
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/blk.h>
+
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/bootinfo.h>
+#include <asm/amigaints.h>
+#include <asm/amigahw.h>
+#include <asm/zorro.h>
+#include <asm/irq.h>
+
+#include "scsi.h"
+#include "hosts.h"
+#include "wd33c93.h"
+#include "gvp11.h"
+
+#include<linux/stat.h>
+
+struct proc_dir_entry proc_scsi_gvp11 = {
+    PROC_SCSI_GVP11, 5, "GVP11",
+    S_IFDIR | S_IRUGO | S_IXUGO, 2
+};
+
+#define DMA(ptr) ((gvp11_scsiregs *)((ptr)->base))
+#define HDATA(ptr) ((struct WD33C93_hostdata *)((ptr)->hostdata))
+
+static struct Scsi_Host *first_instance = NULL;
+static Scsi_Host_Template *gvp11_template;
+
+static void gvp11_intr (int irq, struct pt_regs *fp, void *dummy)
+{
+    unsigned int status;
+    struct Scsi_Host *instance;
+
+    for (instance = first_instance; instance &&
+	 instance->hostt == gvp11_template; instance = instance->next)
+    {
+	status = DMA(instance)->CNTR;
+	if (!(status & GVP11_DMAC_INT_PENDING))
+	    continue;
+
+	/* disable PORTS interrupt */
+	custom.intena = IF_PORTS;
+	wd33c93_intr (instance);
+	/* enable PORTS interrupt */
+	custom.intena = IF_SETCLR | IF_PORTS;
+    }
+}
+
+/*
+ * DMA transfer mask for GVP Series II SCSI controller.
+ * Some versions can only DMA into the 24 bit address space
+ * (0->16M).  Others can DMA into the full 32 bit address
+ * space.  The default is to only allow DMA into the 24 bit
+ * address space.  The "gvp11=0xFFFFFFFE" setup parameter can
+ * be supplied to force an alternate (32 bit) mask.
+ */
+static int gvp11_xfer_mask = GVP11_XFER_MASK;
+
+void gvp11_setup (char *str, int *ints)
+{
+    gvp11_xfer_mask = ints[1];
+}
+
+static int dma_setup (Scsi_Cmnd *cmd, int dir_in)
+{
+    unsigned short cntr = GVP11_DMAC_INT_ENABLE;
+    unsigned long addr = VTOP(cmd->SCp.ptr);
+
+    /* don't allow DMA if the physical address is bad */
+    if (addr & gvp11_xfer_mask ||
+	(!dir_in && mm_end_of_chunk (addr, cmd->SCp.this_residual)))
+    {
+	HDATA(cmd->host)->dma_bounce_len = (cmd->SCp.this_residual + 511)
+	    & ~0x1ff;
+	HDATA(cmd->host)->dma_bounce_buffer =
+	    scsi_malloc (HDATA(cmd->host)->dma_bounce_len);
+	
+	/* can't allocate memory; use PIO */
+	if (!HDATA(cmd->host)->dma_bounce_buffer) {
+	    HDATA(cmd->host)->dma_bounce_len = 0;
+	    return 1;
+	}
+
+	/* check if the address of the bounce buffer is OK */
+	addr = VTOP(HDATA(cmd->host)->dma_bounce_buffer);
+
+	if (addr & gvp11_xfer_mask) {
+	    scsi_free (HDATA(cmd->host)->dma_bounce_buffer,
+		       HDATA(cmd->host)->dma_bounce_len);
+	    HDATA(cmd->host)->dma_bounce_buffer = NULL;
+	    HDATA(cmd->host)->dma_bounce_len = 0;
+	    return 1;
+	}
+	    
+	if (!dir_in) {
+	    /* copy to bounce buffer for a write */
+	    if (cmd->use_sg)
+#if 0
+		panic ("scsi%ddma: incomplete s/g support",
+		       cmd->host->host_no);
+#else
+		memcpy (HDATA(cmd->host)->dma_bounce_buffer,
+				cmd->SCp.ptr, cmd->SCp.this_residual);
+#endif
+	    else
+		memcpy (HDATA(cmd->host)->dma_bounce_buffer,
+			cmd->request_buffer, cmd->request_bufflen);
+	}
+    }
+
+    /* setup dma direction */
+    if (!dir_in)
+	cntr |= GVP11_DMAC_DIR_WRITE;
+
+    HDATA(cmd->host)->dma_dir = dir_in;
+    DMA(cmd->host)->CNTR = cntr;
+
+    /* setup DMA *physical* address */
+    DMA(cmd->host)->ACR = addr;
+
+    if (dir_in)
+	/* invalidate any cache */
+	cache_clear (addr, cmd->SCp.this_residual);
+    else
+	/* push any dirty cache */
+	cache_push (addr, cmd->SCp.this_residual);
+
+    /* start DMA */
+    DMA(cmd->host)->ST_DMA = 1;
+
+    /* return success */
+    return 0;
+}
+
+static void dma_stop (struct Scsi_Host *instance, Scsi_Cmnd *SCpnt,
+		      int status)
+{
+    /* stop DMA */
+    DMA(instance)->SP_DMA = 1;
+    /* remove write bit from CONTROL bits */
+    DMA(instance)->CNTR = GVP11_DMAC_INT_ENABLE;
+
+    /* copy from a bounce buffer, if necessary */
+    if (status && HDATA(instance)->dma_bounce_buffer) {
+	if (SCpnt && SCpnt->use_sg) {
+#if 0
+	    panic ("scsi%d: incomplete s/g support",
+		   instance->host_no);
+#else
+	    if( HDATA(instance)->dma_dir )
+		memcpy (SCpnt->SCp.ptr, 
+			HDATA(instance)->dma_bounce_buffer,
+			SCpnt->SCp.this_residual);
+	    scsi_free (HDATA(instance)->dma_bounce_buffer,
+		       HDATA(instance)->dma_bounce_len);
+	    HDATA(instance)->dma_bounce_buffer = NULL;
+	    HDATA(instance)->dma_bounce_len = 0;
+	    
+#endif
+	} else {
+	    if (HDATA(instance)->dma_dir && SCpnt)
+		memcpy (SCpnt->request_buffer,
+			HDATA(instance)->dma_bounce_buffer,
+			SCpnt->request_bufflen);
+
+	    scsi_free (HDATA(instance)->dma_bounce_buffer,
+		       HDATA(instance)->dma_bounce_len);
+	    HDATA(instance)->dma_bounce_buffer = NULL;
+	    HDATA(instance)->dma_bounce_len = 0;
+	}
+    }
+}
+
+int gvp11_detect(Scsi_Host_Template *tpnt)
+{
+    static unsigned char called = 0;
+    struct Scsi_Host *instance;
+    int i, manuf, product, num_gvp11 = 0;
+    caddr_t address;
+    enum GVP_ident epc;
+
+    if (!MACH_IS_AMIGA || called)
+	return 0;
+    called = 1;
+
+    tpnt->proc_dir = &proc_scsi_gvp11;
+
+    for (i = 0; i < boot_info.bi_amiga.num_autocon; i++)
+    {
+	manuf = boot_info.bi_amiga.autocon[i].cd_Rom.er_Manufacturer;
+	product = boot_info.bi_amiga.autocon[i].cd_Rom.er_Product;
+#if 0
+/* this seems to catch some non HD boards.  GVP is sooooo stupid */
+	if (manuf == MANUF_GVP &&
+	    ((product == PROD_GVPIISCSI) || (product == PROD_GVPIISCSI_2))) {
+#else
+        if (manuf == MANUF_GVP && product == PROD_GVPIISCSI) {
+#endif
+	    /* check extended product code */
+	    address = boot_info.bi_amiga.autocon[i].cd_BoardAddr;
+	    epc = *(unsigned short *)(ZTWO_VADDR(address) + 0x8000);
+
+	    epc = epc & GVP_EPCMASK;
+
+	    /* 
+	     * This should (hopefully) be the correct way to identify
+	     * all the different GVP SCSI controllers (except for the
+	     * SERIES I though).
+	     */
+	    if (!((epc == GVP_A1291_SCSI) || 
+		  (epc == GVP_GFORCE_040_SCSI) ||
+		  (epc == GVP_GFORCE_030_SCSI) ||
+		  (epc == GVP_A530_SCSI) ||
+		  (epc == GVP_COMBO_R4_SCSI) ||
+		  (epc == GVP_COMBO_R3_SCSI) ||
+		  (epc == GVP_SERIESII)))
+		continue;
+
+	    instance = scsi_register (tpnt,
+				      sizeof (struct WD33C93_hostdata));
+	    instance->base = (unsigned char *)ZTWO_VADDR(address);
+	    DMA(instance)->secret2 = 1;
+	    DMA(instance)->secret1 = 0;
+	    DMA(instance)->secret3 = 15;
+	    while (DMA(instance)->CNTR & GVP11_DMAC_BUSY) ;
+	    DMA(instance)->CNTR = 0;
+	    wd33c93_init(instance, (wd33c93_regs *)&(DMA(instance)->SASR),
+			 dma_setup, dma_stop, WD33C93_FS_8_10);
+	    if (num_gvp11++ == 0) {
+		first_instance = instance;
+		gvp11_template = instance->hostt;
+		add_isr(IRQ_AMIGA_PORTS, gvp11_intr, 0, NULL, "GVP11 SCSI");
+	    }
+	    DMA(instance)->CNTR = GVP11_DMAC_INT_ENABLE;
+
+#if 0 /* The Zorro stuff is not totally integrated yet ! */
+	    boot_info.bi_amiga.autocon_configured |= 1<<i;
+#endif
+
+	}
+    }
+
+    return num_gvp11;
+}
diff -u --recursive --new-file v1.3.93/linux/drivers/scsi/gvp11.h linux/drivers/scsi/gvp11.h
--- v1.3.93/linux/drivers/scsi/gvp11.h	Thu Jan  1 02:00:00 1970
+++ linux/drivers/scsi/gvp11.h	Fri Apr  5 15:15:07 1996
@@ -0,0 +1,91 @@
+#ifndef GVP11_H
+
+/* $Id: gvp11.h,v 1.4 1996/03/12 20:42:40 root Exp root $
+ *
+ * Header file for the GVP Series II SCSI controller for Linux
+ *
+ * Written and (C) 1993, Ralf Baechle, see gvp11.c for more info
+ * based on a2091.h (C) 1993 by Hamish Macdonald
+ *
+ */
+
+#include <linux/types.h>
+
+int gvp11_detect(Scsi_Host_Template *);
+const char *wd33c93_info(void);
+int wd33c93_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+int wd33c93_abort(Scsi_Cmnd *);
+int wd33c93_reset(Scsi_Cmnd *);
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#ifndef CMD_PER_LUN
+#define CMD_PER_LUN 2
+#endif
+
+#ifndef CAN_QUEUE
+#define CAN_QUEUE 16
+#endif
+
+#ifdef HOSTS_C
+
+extern struct proc_dir_entry proc_scsi_gvp11;
+
+#define GVP11_SCSI {  /* next */                NULL,            \
+		      /* usage_count */         NULL,	         \
+                      /* proc_dir_entry */      &proc_scsi_gvp11, \
+		      /* proc_info */           NULL,            \
+		      /* name */                "GVP Series II SCSI", \
+		      /* detect */              gvp11_detect,    \
+		      /* release */             NULL,            \
+		      /* info */                NULL,	         \
+		      /* command */             NULL,            \
+		      /* queuecommand */        wd33c93_queuecommand, \
+		      /* abort */               wd33c93_abort,   \
+		      /* reset */               wd33c93_reset,   \
+		      /* slave_attach */        NULL,            \
+		      /* bios_param */          NULL, 	         \
+		      /* can_queue */           CAN_QUEUE,       \
+		      /* this_id */             7,               \
+		      /* sg_tablesize */        SG_ALL,          \
+		      /* cmd_per_lun */	        CMD_PER_LUN,     \
+		      /* present */             0,               \
+		      /* unchecked_isa_dma */   0,               \
+		      /* use_clustering */      DISABLE_CLUSTERING }
+#else
+
+/*
+ * if the transfer address ANDed with this results in a non-zero
+ * result, then we can't use DMA.
+ */ 
+#define GVP11_XFER_MASK  (0xff000001)
+
+typedef struct {
+             unsigned char      pad1[64];
+    volatile unsigned short     CNTR;
+             unsigned char      pad2[31];
+    volatile unsigned char      SASR;
+             unsigned char      pad3;
+    volatile unsigned char      SCMD;
+             unsigned char      pad4[4];
+    volatile unsigned short     BANK;
+             unsigned char      pad5[6];
+    volatile unsigned long      ACR;
+    volatile unsigned short     secret1; /* store 0 here */
+    volatile unsigned short     ST_DMA;
+    volatile unsigned short     SP_DMA;
+    volatile unsigned short     secret2; /* store 1 here */
+    volatile unsigned short     secret3; /* store 15 here */
+} gvp11_scsiregs;
+
+/* bits in CNTR */
+#define GVP11_DMAC_BUSY		(1<<0)
+#define GVP11_DMAC_INT_PENDING	(1<<1)
+#define GVP11_DMAC_INT_ENABLE	(1<<3)
+#define GVP11_DMAC_DIR_WRITE	(1<<4)
+
+#endif /* else def HOSTS_C */
+
+#endif /* GVP11_H */
diff -u --recursive --new-file v1.3.93/linux/drivers/scsi/st.c linux/drivers/scsi/st.c
--- v1.3.93/linux/drivers/scsi/st.c	Mon Apr  8 19:01:44 1996
+++ linux/drivers/scsi/st.c	Mon Apr 22 11:13:22 1996
@@ -11,7 +11,7 @@
   Copyright 1992 - 1996 Kai Makisara
 		 email Kai.Makisara@metla.fi
 
-  Last modified: Sun Apr  7 20:33:27 1996 by root@kai.makisara.fi
+  Last modified: Sun Apr 21 22:03:50 1996 by root@kai.makisara.fi
   Some small formal changes - aeb, 950809
 */
 
@@ -77,6 +77,10 @@
 #define TAPE_NR(x) (MINOR(x) & ~(128 | ST_MODE_MASK))
 #define TAPE_MODE(x) ((MINOR(x) & ST_MODE_MASK) >> ST_MODE_SHIFT)
 
+/* Internal ioctl to set both density (uppermost 8 bits) and blocksize (lower
+   24 bits) */
+#define SET_DENS_AND_BLK 0x10001
+
 static int st_nbr_buffers;
 static ST_buffer **st_buffers;
 static int st_buffer_size = ST_BUFFER_SIZE;
@@ -459,7 +463,8 @@
 scsi_tape_open(struct inode * inode, struct file * filp)
 {
     unsigned short flags;
-    int i, need_dma_buffer, new_session = FALSE, setting_failed;
+    int i, need_dma_buffer, new_session = FALSE, set_it;
+    unsigned int arg;
     unsigned char cmd[10];
     Scsi_Cmnd * SCpnt;
     Scsi_Tape * STp;
@@ -568,28 +573,32 @@
       return 0;
     }
 
-    memset ((void *) &cmd[0], 0, 10);
-    cmd[0] = READ_BLOCK_LIMITS;
+    if (STp->omit_blklims)
+      STp->min_block = STp->max_block = (-1);
+    else {
+      memset ((void *) &cmd[0], 0, 10);
+      cmd[0] = READ_BLOCK_LIMITS;
 
-    SCpnt = st_do_scsi(SCpnt, STp, cmd, 6, ST_TIMEOUT, MAX_READY_RETRIES);
+      SCpnt = st_do_scsi(SCpnt, STp, cmd, 6, ST_TIMEOUT, MAX_READY_RETRIES);
 
-    if (!SCpnt->result && !SCpnt->sense_buffer[0]) {
-      STp->max_block = ((STp->buffer)->b_data[1] << 16) |
-	((STp->buffer)->b_data[2] << 8) | (STp->buffer)->b_data[3];
-      STp->min_block = ((STp->buffer)->b_data[4] << 8) |
-	(STp->buffer)->b_data[5];
+      if (!SCpnt->result && !SCpnt->sense_buffer[0]) {
+	STp->max_block = ((STp->buffer)->b_data[1] << 16) |
+	  ((STp->buffer)->b_data[2] << 8) | (STp->buffer)->b_data[3];
+	STp->min_block = ((STp->buffer)->b_data[4] << 8) |
+	  (STp->buffer)->b_data[5];
 #if DEBUG
-      if (debugging)
-	printk(ST_DEB_MSG "st%d: Block limits %d - %d bytes.\n", dev, STp->min_block,
-	       STp->max_block);
+	if (debugging)
+	  printk(ST_DEB_MSG "st%d: Block limits %d - %d bytes.\n", dev, STp->min_block,
+		 STp->max_block);
 #endif
-    }
-    else {
-      STp->min_block = STp->max_block = (-1);
+      }
+      else {
+	STp->min_block = STp->max_block = (-1);
 #if DEBUG
-      if (debugging)
-	printk(ST_DEB_MSG "st%d: Can't read block limits.\n", dev);
+	if (debugging)
+	  printk(ST_DEB_MSG "st%d: Can't read block limits.\n", dev);
 #endif
+      }
     }
 
     memset ((void *) &cmd[0], 0, 10);
@@ -674,34 +683,34 @@
       STp->density_changed = STp->blksize_changed = FALSE;
       STp->compression_changed = FALSE;
       if (!(STm->defaults_for_writes)) {
-	setting_failed = FALSE;
+	set_it = FALSE;
+	if (STm->default_density >= 0 &&
+	    STm->default_density != STp->density) {
+	  arg = STm->default_density;
+	  set_it = TRUE;
+	}
+	else
+	  arg = STp->density;
+	arg <<= MT_ST_DENSITY_SHIFT;
 	if (STm->default_blksize >= 0 &&
 	    STm->default_blksize != STp->block_size) {
-	  if (STm->default_density >= 0 &&
-	      STm->default_density != STp->density)
-	    STp->density = STm->default_density;  /* Dirty trick! */
-	  if (st_int_ioctl(inode, filp, MTSETBLK, STm->default_blksize)) {
-	    printk(KERN_WARNING "st%d: Can't set default block size to %d bytes.\n",
-		   dev, STm->default_blksize);
-	    if (modes_defined)
-	      setting_failed = TRUE;
-	  }
+	  arg |= STm->default_blksize;
+	  set_it = TRUE;
 	}
-	if (STm->default_density >= 0 &&
-	    STm->default_density != STp->density) {
-	  if (st_int_ioctl(inode, filp, MTSETDENSITY, STm->default_density)) {
-	    printk(KERN_WARNING "st%d: Can't set default density to %x.\n",
-		   dev, STm->default_density);
-	    if (modes_defined)
-	      setting_failed = TRUE;
+	else
+	  arg |= STp->block_size;
+	if (set_it &&
+	    st_int_ioctl(inode, filp, SET_DENS_AND_BLK, arg)) {
+	  printk(KERN_WARNING
+		 "st%d: Can't set default block size to %d bytes and density %x.\n",
+		 dev, STm->default_blksize, STm->default_density);
+	  if (modes_defined) {
+	    (STp->buffer)->in_use = 0;
+	    STp->buffer = 0;
+	    STp->in_use = 0;
+	    return (-EINVAL);
 	  }
 	}
-	if (setting_failed) {
-	  (STp->buffer)->in_use = 0;
-	  STp->buffer = 0;
-	  STp->in_use = 0;
-	  return (-EINVAL);
-	}
       }
       if (STp->default_drvbuffer != 0xff) {
 	if (st_int_ioctl(inode, filp, MTSETDRVBUFFER, STp->default_drvbuffer))
@@ -807,7 +816,8 @@
 {
     int total, do_count, blks, retval, transfer;
     int write_threshold;
-    int doing_write = 0;
+    int doing_write = 0, set_it;
+    unsigned int arg;
     static unsigned char cmd[10];
     const char *b_point;
     Scsi_Cmnd * SCpnt = NULL;
@@ -854,32 +864,33 @@
        return retval;
       STp->rw = ST_WRITING;
     }
-    else if (STp->rw != ST_WRITING) {
-      if (STm->defaults_for_writes &&
-	  (STp->mt_status)->mt_fileno == 0 && STp->drv_block == 0) {
-	/* Force unless explicitly changed by the user */
-	if (!(STp->blksize_changed) && STm->default_blksize >= 0 &&
-	    STp->block_size != STm->default_blksize) {
-	  if (STm->default_density >= 0 &&
-	      STm->default_density != STp->density)
-	    STp->density = STm->default_density;  /* Dirty trick! */
-	  if (st_int_ioctl(inode, filp, MTSETBLK, STm->default_blksize)) {
-	    printk(KERN_WARNING "st%d: Can't set default block size to %d bytes.\n",
-		   dev, STm->default_blksize);
-	    if (modes_defined)
-	      return (-EINVAL);
-	  }
-	}
-	if (!(STp->density_changed) && STm->default_density >= 0 &&
-	    STm->default_density != STp->density) {
-	  if (st_int_ioctl(inode, filp, MTSETDENSITY, STm->default_density)) {
-	    printk(KERN_WARNING "st%d: Can't set default density %x.\n",
-		   dev, STm->default_density);
-	    if (modes_defined)
-	      return (-EINVAL);
-	  }
-	}
+    else if (STp->rw != ST_WRITING &&
+	     (STp->mt_status)->mt_fileno == 0 && STp->drv_block == 0) {
+      set_it = FALSE;
+      if (!STp->density_changed && STm->default_density >= 0 &&
+	  STm->default_density != STp->density) {
+	  arg = STm->default_density;
+	  set_it = TRUE;
+      }
+      else
+	arg = STp->density;
+      arg <<= MT_ST_DENSITY_SHIFT;
+      if (!STp->blksize_changed && STm->default_blksize >= 0 &&
+	  STm->default_blksize != STp->block_size) {
+	arg |= STm->default_blksize;
+	set_it = TRUE;
       }
+      else
+	arg |= STp->block_size;
+      if (set_it &&
+	  st_int_ioctl(inode, filp, SET_DENS_AND_BLK, arg)) {
+	printk(KERN_WARNING
+	       "st%d: Can't set default block size to %d bytes and density %x.\n",
+	       dev, STm->default_blksize, STm->default_density);
+	if (modes_defined)
+	  return (-EINVAL);
+      }
+
       if (STm->default_compression != ST_DONT_TOUCH &&
 	  !(STp->compression_changed)) {
 	if (st_compression(STp, (STm->default_compression == ST_YES))) {
@@ -1104,12 +1115,14 @@
     static unsigned char cmd[10];
     Scsi_Cmnd * SCpnt = NULL;
     Scsi_Tape * STp;
+    ST_mode * STm;
     int dev = TAPE_NR(inode->i_rdev);
 
     STp = &(scsi_tapes[dev]);
     if (STp->ready != ST_READY)
       return (-EIO);
-    if (!STp->modes[STp->current_mode].defined)
+    STm = &(STp->modes[STp->current_mode]);
+    if (!STm->defined)
       return (-ENXIO);
 #if DEBUG
     if (!STp->in_use) {
@@ -1123,7 +1136,7 @@
 	!enlarge_buffer(STp->buffer, count, STp->restr_dma))
       return (-EOVERFLOW);
 
-    if (!(STp->do_read_ahead) && STp->block_size != 0 &&
+    if (!(STm->do_read_ahead) && STp->block_size != 0 &&
 	(count % STp->block_size) != 0)
       return (-EIO);	/* Read must be integral number of blocks */
 
@@ -1162,12 +1175,12 @@
 	if (STp->block_size == 0)
 	  blks = bytes = count;
 	else {
-	  if (STp->do_read_ahead) {
+	  if (STm->do_read_ahead) {
 	    blks = (STp->buffer)->buffer_blocks;
 	    bytes = blks * STp->block_size;
 	  }
 	  else {
-	    bytes = count;
+	    bytes = count - total;
 	    if (bytes > (STp->buffer)->buffer_size)
 	      bytes = (STp->buffer)->buffer_size;
 	    blks = bytes / STp->block_size;
@@ -1346,11 +1359,13 @@
   printk(KERN_INFO
 "st%d: Mode %d options: buffer writes: %d, async writes: %d, read ahead: %d\n",
 	 dev, STp->current_mode, STm->do_buffer_writes, STm->do_async_writes,
-	 STp->do_read_ahead);
+	 STm->do_read_ahead);
+  printk(KERN_INFO
+"st%d:    can bsr: %d, two FMs: %d, fast mteom: %d, auto lock: %d,\n",
+	 dev, STp->can_bsr, STp->two_fm, STp->fast_mteom, STp->do_auto_lock);
   printk(KERN_INFO
-"st%d:    can bsr: %d, two FMs: %d, fast mteom: %d, auto lock: %d, defs for wr: %d \n",
-	 dev, STp->can_bsr, STp->two_fm, STp->fast_mteom, STp->do_auto_lock,
-	 STm->defaults_for_writes);
+"st%d:    defs for wr: %d, no block limits: %d\n",
+	 dev, STm->defaults_for_writes, STp->omit_blklims);
 #if DEBUG
   printk(KERN_INFO
 	 "st%d:    debugging: %d\n",
@@ -1385,11 +1400,12 @@
     STm->do_buffer_writes = (options & MT_ST_BUFFER_WRITES) != 0;
     STm->do_async_writes  = (options & MT_ST_ASYNC_WRITES) != 0;
     STm->defaults_for_writes = (options & MT_ST_DEF_WRITES) != 0;
-    STp->do_read_ahead    = (options & MT_ST_READ_AHEAD) != 0;
+    STm->do_read_ahead    = (options & MT_ST_READ_AHEAD) != 0;
     STp->two_fm		  = (options & MT_ST_TWO_FM) != 0;
     STp->fast_mteom	  = (options & MT_ST_FAST_MTEOM) != 0;
     STp->do_auto_lock     = (options & MT_ST_AUTO_LOCK) != 0;
     STp->can_bsr          = (options & MT_ST_CAN_BSR) != 0;
+    STp->omit_blklims	  = (options & MT_ST_NO_BLKLIMS) != 0;
 #if DEBUG
     debugging = (options & MT_ST_DEBUGGING) != 0;
 #endif
@@ -1404,7 +1420,7 @@
     if ((options & MT_ST_DEF_WRITES) != 0)
       STm->defaults_for_writes = value;
     if ((options & MT_ST_READ_AHEAD) != 0)
-      STp->do_read_ahead = value;
+      STm->do_read_ahead = value;
     if ((options & MT_ST_TWO_FM) != 0)
       STp->two_fm = value;
     if ((options & MT_ST_FAST_MTEOM) != 0)
@@ -1413,6 +1429,8 @@
       STp->do_auto_lock = value;
     if ((options & MT_ST_CAN_BSR) != 0)
       STp->can_bsr = value;
+    if ((options & MT_ST_NO_BLKLIMS) != 0)
+      STp->omit_blklims = value;
 #if DEBUG
     if ((options & MT_ST_DEBUGGING) != 0)
       debugging = value;
@@ -1875,12 +1893,14 @@
      case MTSETBLK:  /* Set block length */
      case MTSETDENSITY: /* Set tape density */
      case MTSETDRVBUFFER: /* Set drive buffering */
+     case SET_DENS_AND_BLK: /* Set density and block size */
        if (STp->dirty || (STp->buffer)->buffer_bytes != 0)
 	 return (-EIO);   /* Not allowed if data in buffer */
-       if (cmd_in == MTSETBLK &&
-	   arg != 0 &&
-	   (arg < STp->min_block || arg > STp->max_block ||
-	    arg > st_buffer_size)) {
+       if ((cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK) &&
+	   (arg & MT_ST_BLKSIZE_MASK) != 0 &&
+	   ((arg & MT_ST_BLKSIZE_MASK) < STp->min_block ||
+	    (arg & MT_ST_BLKSIZE_MASK) > STp->max_block ||
+	    (arg & MT_ST_BLKSIZE_MASK) > st_buffer_size)) {
 	 printk(KERN_WARNING "st%d: Illegal block size.\n", dev);
 	 return (-EINVAL);
        }
@@ -1898,11 +1918,14 @@
 	 (STp->buffer)->b_data[4] = arg;
 	 STp->density_changed = TRUE;  /* At least we tried ;-) */
        }
+       else if (cmd_in == SET_DENS_AND_BLK)
+	 (STp->buffer)->b_data[4] = arg >> 24;
        else
 	 (STp->buffer)->b_data[4] = STp->density;
-       if (cmd_in == MTSETBLK) {
-	 ltmp = arg;
-	 STp->blksize_changed = TRUE;  /* At least we tried ;-) */
+       if (cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK) {
+	 ltmp = arg & MT_ST_BLKSIZE_MASK;
+	 if (cmd_in == MTSETBLK)
+	   STp->blksize_changed = TRUE;  /* At least we tried ;-) */
        }
        else
 	 ltmp = STp->block_size;
@@ -1912,15 +1935,15 @@
        timeout = ST_TIMEOUT;
 #if DEBUG
        if (debugging) {
-	 if (cmd_in == MTSETBLK)
+	 if (cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK)
 	   printk(ST_DEB_MSG "st%d: Setting block size to %d bytes.\n", dev,
 		  (STp->buffer)->b_data[9] * 65536 +
 		  (STp->buffer)->b_data[10] * 256 +
 		  (STp->buffer)->b_data[11]);
-	 else if (cmd_in == MTSETDENSITY)
+	 if (cmd_in == MTSETDENSITY || cmd_in == SET_DENS_AND_BLK)
 	   printk(ST_DEB_MSG "st%d: Setting density code to %x.\n", dev,
 		  (STp->buffer)->b_data[4]);
-	 else
+	 if (cmd_in == MTSETDRVBUFFER)
 	   printk(ST_DEB_MSG "st%d: Setting drive buffer code to %d.\n", dev,
 		  ((STp->buffer)->b_data[2] >> 4) & 7);
        }
@@ -1960,9 +1983,9 @@
        ioctl_result = st_int_ioctl(inode, file, MTFSF, 1);
      else if (cmd_in == MTFSFM)
        ioctl_result = st_int_ioctl(inode, file, MTBSF, 1);
-     else if (cmd_in == MTSETBLK) {
-       STp->block_size = arg;
-       if (arg != 0)
+     else if (cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK) {
+       STp->block_size = arg & MT_ST_BLKSIZE_MASK;
+       if (STp->block_size != 0)
 	 (STp->buffer)->buffer_blocks =
 	   (STp->buffer)->buffer_size / STp->block_size;
        (STp->buffer)->buffer_bytes = (STp->buffer)->read_pointer = 0;
@@ -1979,6 +2002,8 @@
        STp->eof = ST_NOEOF;
        STp->eof_hit = 0;
      }
+     if (cmd_in == SET_DENS_AND_BLK)
+       STp->density = arg >> MT_ST_DENSITY_SHIFT;
      if (cmd_in == MTOFFL || cmd_in == MTUNLOAD)
        STp->rew_at_close = 0;
      else if (cmd_in == MTLOAD)
@@ -2450,7 +2475,6 @@
    tpnt->drv_buffer = 1;  /* Try buffering if no mode sense */
    tpnt->restr_dma = (SDp->host)->unchecked_isa_dma;
    tpnt->density = 0;
-   tpnt->do_read_ahead = ST_READ_AHEAD;
    tpnt->do_auto_lock = ST_AUTO_LOCK;
    tpnt->can_bsr = ST_IN_FILE_POS;
    tpnt->two_fm = ST_TWO_FM;
@@ -2467,6 +2491,7 @@
      tpnt->modes[i].defaults_for_writes = 0;
      tpnt->modes[i].do_async_writes = ST_ASYNC_WRITES;
      tpnt->modes[i].do_buffer_writes = ST_BUFFER_WRITES;
+     tpnt->modes[i].do_read_ahead = ST_READ_AHEAD;
      tpnt->modes[i].default_compression = ST_DONT_TOUCH;
      tpnt->modes[i].default_blksize = (-1);  /* No forced size */
      tpnt->modes[i].default_density = (-1);  /* No forced density */
diff -u --recursive --new-file v1.3.93/linux/drivers/scsi/st.h linux/drivers/scsi/st.h
--- v1.3.93/linux/drivers/scsi/st.h	Mon Apr  8 19:01:44 1996
+++ linux/drivers/scsi/st.h	Mon Apr 22 11:13:22 1996
@@ -31,6 +31,7 @@
   unsigned char defined;
   unsigned char do_async_writes;
   unsigned char do_buffer_writes;
+  unsigned char do_read_ahead;
   unsigned char defaults_for_writes;
   unsigned char default_compression; /* 0 = don't touch, etc */
   short default_density; /* Forced density, -1 = no value */
@@ -53,7 +54,7 @@
   ST_buffer * buffer;
 
   /* Drive characteristics */
-  unsigned char do_read_ahead;
+  unsigned char omit_blklims;
   unsigned char do_auto_lock;
   unsigned char can_bsr;
   unsigned char two_fm;
diff -u --recursive --new-file v1.3.93/linux/drivers/scsi/wd33c93.c linux/drivers/scsi/wd33c93.c
--- v1.3.93/linux/drivers/scsi/wd33c93.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/scsi/wd33c93.c	Sun Mar 17 22:44:39 1996
@@ -0,0 +1,1339 @@
+/*
+ *    wd33c93.c - Linux-68k device driver for the Commodore
+ *                Amiga A2091/590 SCSI controller card
+ *
+ * Copyright (c) 1996 John Shifflett, GeoLog Consulting
+ *    john@geolog.com
+ *    jshiffle@netcom.com
+ *
+ * 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, 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.
+ *
+ *
+ * Drew Eckhardt's excellent 'Generic NCR5380' sources from Linux-PC
+ * provided much of the inspiration and some of the code for this
+ * driver. Everything I know about Amiga DMA was gleaned from careful
+ * reading of Hamish Mcdonald's original wd33c93 driver; in fact, I
+ * borrowed shamelessly from all over that source. Thanks Hamish!
+ *
+ * _This_ driver is (I feel) an improvement over the old one in
+ * several respects:
+ *
+ *    -  Target Disconnection/Reconnection  is now supported. Any
+ *          system with more than one device active on the SCSI bus
+ *          will benefit from this.
+ *
+ *    -  Synchronous data transfers are now supported. The driver
+ *          automatically uses this faster protocol with any device
+ *          able to handle it.
+ *
+ *    -  Runtime operating parameters can now be specified through
+ *       either the 'amiboot' or the LILO command line. Something
+ *       like:
+ *          "wd33c93=0x0000"
+ *       The value 0x0000 results in the defaults being used; bits
+ *       are defined in wd33c93.h.
+ *
+ *    -  The old driver relied exclusively on what the Western Digital
+ *          docs call "Combination Level 2 Commands", which are a great
+ *          idea in that the CPU is relieved of a lot of interrupt
+ *          overhead. However, by accepting a certain (user-settable)
+ *          amount of additional interrupts, this driver achieves
+ *          better control over the SCSI bus, and data transfers are
+ *          almost as fast while being much easier to define, track,
+ *          and debug.
+ *
+ *
+ * TODO:
+ *       more speed. tagged queuing.
+ *
+ *
+ * People with bug reports, wish-lists, complaints, comments,
+ * or improvements are asked to pah-leeez email me (John Shifflett)
+ * at john@geolog.com or jshiffle@netcom.com! I'm anxious to get
+ * this thing into as good a shape as possible, and I'm positive
+ * there are lots of lurking bugs and "Stupid Places".
+ *
+ */
+
+#include <asm/system.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+#include <linux/blk.h>
+#include "scsi.h"
+#include "hosts.h"
+#include "wd33c93.h"
+
+
+#define SYNC_DEBUG
+
+#define DEBUGGING_ON
+
+#define WD33C93_VERSION    "1.17"
+#define WD33C93_DATE       "06/Feb/1996"
+
+#ifdef DEBUGGING_ON
+#define DB(f,a) if (hostdata->args & (f)) a;
+#else
+#define DB(f,a)
+#endif
+
+#define IS_DIR_OUT(cmd) ((cmd)->cmnd[0] == WRITE_6  || \
+                         (cmd)->cmnd[0] == WRITE_10 || \
+                         (cmd)->cmnd[0] == WRITE_12)
+
+
+/*
+ * setup_default is a bunch of bits that define some of the operating
+ * parameters and settings for this driver. It is used unless a LILO
+ * or insmod command line has been specified, in which case setup_default
+ * is _completely_ ignored. Take a look at the "defines for hostdata->args"
+ * section in wd33c93.h - that stuff is what you'd use here if you want
+ * to change the defaults.
+ */
+
+static unsigned int setup_default = 0;
+
+
+inline uchar read_wd33c93(wd33c93_regs *regp,uchar reg_num)
+{
+   regp->SASR = reg_num;
+   return(regp->SCMD);
+}
+
+
+#define READ_AUX_STAT() (regp->SASR)
+
+
+inline void write_wd33c93(wd33c93_regs *regp,uchar reg_num, uchar value)
+{
+   regp->SASR = reg_num;
+   regp->SCMD = value;
+}
+
+
+inline void write_wd33c93_cmd(wd33c93_regs *regp, uchar cmd)
+{
+   regp->SASR = WD_COMMAND;
+   regp->SCMD = cmd;
+}
+
+
+inline uchar read_1_byte(wd33c93_regs *regp)
+{
+uchar asr;
+uchar x = 0;
+
+   write_wd33c93(regp, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED);
+   write_wd33c93_cmd(regp, WD_CMD_TRANS_INFO|0x80);
+   do {
+      asr = READ_AUX_STAT();
+      if (asr & ASR_DBR)
+         x = read_wd33c93(regp, WD_DATA);
+      } while (!(asr & ASR_INT));
+   return x;
+}
+
+
+void write_wd33c93_count(wd33c93_regs *regp,unsigned long value)
+{
+   regp->SASR = WD_TRANSFER_COUNT_MSB;
+   regp->SCMD = value >> 16;
+   regp->SCMD = value >> 8;
+   regp->SCMD = value;
+}
+
+
+unsigned long read_wd33c93_count(wd33c93_regs *regp)
+{
+unsigned long value;
+
+   regp->SASR = WD_TRANSFER_COUNT_MSB;
+   value = regp->SCMD << 16;
+   value |= regp->SCMD << 8;
+   value |= regp->SCMD;
+   return value;
+}
+
+
+
+static struct sx_period sx_table[] = {
+   {  1, 0x20},
+   {252, 0x20},
+   {376, 0x30},
+   {500, 0x40},
+   {624, 0x50},
+   {752, 0x60},
+   {876, 0x70},
+   {1000,0x00},
+   {0,   0} };
+
+uchar calc_sync_xfer(unsigned int period, unsigned int offset)
+{
+uchar result;
+int x;
+
+   period *= 4;   /* convert SDTR code to ns */
+   result = 0x00;
+   for (x=1; sx_table[x].period_ns; x++) {
+      if ((period <= sx_table[x-0].period_ns) &&
+          (period >  sx_table[x-1].period_ns)) {
+         result = sx_table[x].reg_value;
+         break;
+         }
+      }
+   result |= (offset < OPTIMUM_SX_OFF)?offset:OPTIMUM_SX_OFF;
+   return result;
+}
+
+
+
+static void wd33c93_execute(struct Scsi_Host *instance);
+
+int wd33c93_queuecommand (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
+{
+struct WD33C93_hostdata *hostdata;
+Scsi_Cmnd *tmp;
+unsigned long flags;
+
+   hostdata = (struct WD33C93_hostdata *)cmd->host->hostdata;
+
+DB(DB_QUEUE_COMMAND,printk("Q-%d-%02x-%ld( ",cmd->target,cmd->cmnd[0],cmd->pid))
+
+
+/*
+ * Set up a few fields in the Scsi_Cmnd structure for our own use:
+ *  - host_scribble is the pointer to the next cmd in the input queue
+ *  - scsi_done points to the routine we call when a cmd is finished
+ *  - result is what you'd expect
+ */
+
+   cmd->host_scribble = NULL;
+   cmd->scsi_done = done;
+   cmd->result = 0;
+
+/* We use the Scsi_Pointer structure that's included with each command
+ * as a scratchpad (as it's intended to be used!). The handy thing about
+ * the SCp.xxx fields is that they're always associated with a given
+ * cmd, and are preserved across disconnect-reselect. This means we
+ * can pretty much ignore SAVE_POINTERS and RESTORE_POINTERS messages
+ * if we keep all the critical pointers and counters in SCp:
+ *  - SCp.ptr is the pointer into the RAM buffer
+ *  - SCp.this_residual is the size of that buffer
+ *  - SCp.buffer points to the current scatter-gather buffer
+ *  - SCp.buffers_residual tells us how many S.G. buffers there are
+ */
+
+   if (cmd->use_sg) {
+      cmd->SCp.buffer = (struct scatterlist *)cmd->buffer;
+      cmd->SCp.buffers_residual = cmd->use_sg - 1;
+      cmd->SCp.ptr = (char *)cmd->SCp.buffer->address;
+      cmd->SCp.this_residual = cmd->SCp.buffer->length;
+      }
+   else {
+      cmd->SCp.buffer = NULL;
+      cmd->SCp.buffers_residual = 0;
+      cmd->SCp.ptr = (char *)cmd->request_buffer;
+      cmd->SCp.this_residual = cmd->request_bufflen;
+      }
+
+/* Preset the command status to GOOD, since that's the normal case */
+
+   cmd->SCp.Status = GOOD;
+
+   /*
+    * Add the cmd to the end of 'input_Q'. Note that REQUEST SENSE
+    * commands are added to the head of the queue so that the desired
+    * sense data is not lost before REQUEST_SENSE executes.
+    */
+
+   save_flags(flags);
+   cli();
+   if (!(hostdata->input_Q) || (cmd->cmnd[0] == REQUEST_SENSE)) {
+      cmd->host_scribble = (uchar *)hostdata->input_Q;
+      hostdata->input_Q = cmd;
+      }
+   else {
+      for (tmp=(Scsi_Cmnd *)hostdata->input_Q; tmp->host_scribble;
+            tmp=(Scsi_Cmnd *)tmp->host_scribble)
+         ;
+      tmp->host_scribble = (uchar *)cmd;
+      }
+   restore_flags(flags);
+
+/* We know that there's at least one command in 'input_Q' now.
+ * Go see if any of them are runnable!
+ */
+
+   wd33c93_execute(cmd->host);
+
+DB(DB_QUEUE_COMMAND,printk(")Q-%d-%02x-%ld ",cmd->target,cmd->cmnd[0],cmd->pid))
+   return 0;
+}
+
+
+
+/*
+ * This routine attempts to start a scsi command. If the host_card is
+ * already connected, we give up immediately. Otherwise, look through
+ * the input_Q, using the first command we find that's intended
+ * for a currently non-busy target/lun.
+ */
+static void wd33c93_execute (struct Scsi_Host *instance)
+{
+struct WD33C93_hostdata *hostdata;
+wd33c93_regs *regp;
+Scsi_Cmnd *cmd, *prev;
+unsigned long flags;
+int i;
+
+
+   save_flags(flags);
+   cli();
+   hostdata = (struct WD33C93_hostdata *)instance->hostdata;
+   regp = hostdata->regp;
+
+DB(DB_EXECUTE,printk("EX( "))
+
+   if (hostdata->selecting || hostdata->connected) {
+DB(DB_EXECUTE,printk(")EX-0 "))
+      restore_flags(flags);
+      return;
+      }
+
+    /*
+     * Search through the input_Q for a command destined
+     * for an idle target/lun.
+     */
+
+   cmd = (Scsi_Cmnd *)hostdata->input_Q;
+   prev = 0;
+   while (cmd) {
+      if (!(hostdata->busy[cmd->target] & (1 << cmd->lun)))
+         break;
+      prev = cmd;
+      cmd = (Scsi_Cmnd *)cmd->host_scribble;
+      }
+
+   /* quit if queue empty or all possible targets are busy */
+
+   if (!cmd) {
+DB(DB_EXECUTE,printk(")EX-1 "))
+      restore_flags(flags);
+      return;
+      }
+
+   /*  remove command from queue, put it in selecting */
+   
+   if (prev)
+      prev->host_scribble = cmd->host_scribble;
+   else
+      hostdata->input_Q = (Scsi_Cmnd *)cmd->host_scribble;
+   hostdata->selecting = cmd;
+
+   /*
+    * Start the selection process
+    */
+
+   if (IS_DIR_OUT(cmd))
+      write_wd33c93(regp, WD_DESTINATION_ID, cmd->target);
+   else
+      write_wd33c93(regp, WD_DESTINATION_ID, cmd->target | DSTID_DPD);
+
+   write_wd33c93(regp, WD_TARGET_LUN, cmd->lun);
+   write_wd33c93(regp, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED);
+   write_wd33c93_count(regp, 0); /* this guarantees a DATA_PHASE interrupt */
+   hostdata->busy[cmd->target] |= (1 << cmd->lun);
+
+   if ((hostdata->level2 == L2_NONE) ||
+       (hostdata->sync_stat[cmd->target] == SS_UNSET)) {
+
+         /*
+          * Now do a 'Select-With-ATN' command. This will end with
+          * one of the following interrupts:
+          *    CSR_RESEL_AM:  failure - can try again later.
+          *    CSR_TIMEOUT:   failure - give up.
+          *    CSR_SELECT:    success - proceed.
+          */
+
+/* Every target has its own synchronous transfer setting, kept in the
+ * sync_xfer array, and a corresponding status byte in sync_stat[].
+ * Each target's sync_stat[] entry is initialized to SX_UNSET, and its
+ * sync_xfer[] entry is initialized to the default/safe value. SS_UNSET
+ * means that the parameters are undetermined as yet, and that we
+ * need to send an SDTR message to this device after selection is
+ * complete. We set SS_FIRST to tell the interrupt routine to do so,
+ * unless we've been asked not to try synchronous transfers on this
+ * target (and _all_ luns within it): In this case we set SS_SET to
+ * make the defaults final.
+ */
+      if (hostdata->sync_stat[cmd->target] == SS_UNSET) {
+         if (hostdata->args & (1 << cmd->target))
+            hostdata->sync_stat[cmd->target] = SS_SET;
+         else
+            hostdata->sync_stat[cmd->target] = SS_FIRST;
+         }
+      hostdata->state = S_SELECTING;
+      write_wd33c93_cmd(regp, WD_CMD_SEL_ATN);
+      }
+
+   else {
+
+         /*
+          * Now do a 'Select-With-ATN-Xfer' command. This will end with
+          * one of the following interrupts:
+          *    CSR_RESEL_AM:  failure - can try again later.
+          *    CSR_TIMEOUT:   failure - give up.
+          *    anything else: success - proceed.
+          */
+
+      hostdata->connected = cmd;
+      hostdata->selecting = NULL;
+      write_wd33c93(regp, WD_COMMAND_PHASE, 0);
+
+   /* copy command_descriptor_block into WD chip */
+
+      for (i=0; i<cmd->cmd_len; i++)
+         write_wd33c93(regp, WD_CDB_1+i, cmd->cmnd[i]);
+
+   /* The wd33c93 only knows about Group 0, 1, and 5 commands when
+    * it's doing a 'select-and-transfer'. To be safe, we write the
+    * size of the CDB into the OWN_ID register for every case. This
+    * way there won't be problems with vendor-unique, audio, etc.
+    */
+
+      write_wd33c93(regp, WD_OWN_ID, cmd->cmd_len);
+
+      hostdata->state = S_RUNNING_LEVEL2;
+      write_wd33c93_cmd(regp, WD_CMD_SEL_ATN_XFER);
+      }
+
+   /*
+    * Since the SCSI bus can handle only 1 connection at a time,
+    * we get out of here now. If the selection fails, or when
+    * the command disconnects, we'll come back to this routine
+    * to search the input_Q again...
+    */
+      
+DB(DB_EXECUTE,printk(")EX-2 "))
+   restore_flags(flags);
+}
+
+
+
+void transfer_pio(wd33c93_regs *regp, uchar **buf, int *cnt,
+                  int data_in_dir, struct WD33C93_hostdata *hostdata)
+{
+uchar *b, asr;
+int c;
+
+   write_wd33c93(regp, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED);
+   b = *buf;
+   c = *cnt;
+DB(DB_TRANSFER_DATA,printk("[[%p/%d]]",b,c))
+   write_wd33c93_count(regp,c);
+   write_wd33c93_cmd(regp, WD_CMD_TRANS_INFO);
+   if (data_in_dir) {
+      do {
+         asr = READ_AUX_STAT();
+         if (asr & ASR_DBR)
+            *b++ = read_wd33c93(regp, WD_DATA);
+         } while (!(asr & ASR_INT));
+      }
+   else {
+      do {
+         asr = READ_AUX_STAT();
+         if (asr & ASR_DBR)
+            write_wd33c93(regp, WD_DATA, *b++);
+         } while (!(asr & ASR_INT));
+      }
+
+/* update original buffer pointer and original count */
+
+   *cnt = read_wd33c93_count(regp);
+   if (data_in_dir)
+      *buf = b;
+   else
+      *buf += (c - *cnt);
+
+   /* Note: we are returning with the interrupt UN-cleared.
+   * Since (presumably) an entire I/O operation has
+   * completed, the bus phase is probably different, and
+   * the interrupt routine will discover this when it
+   * responds to the uncleared int.
+   */
+
+}
+
+
+
+void transfer_bytes(wd33c93_regs *regp, Scsi_Cmnd *cmd, int data_in_dir)
+{
+struct WD33C93_hostdata *hostdata;
+
+   hostdata = (struct WD33C93_hostdata *)cmd->host->hostdata;
+
+/* Normally, you'd expect 'this_residual' to be non-zero here.
+ * In a series of scatter-gather transfers, however, this
+ * routine will usually be called with 'this_residual' equal
+ * to 0 and 'buffers_residual' non-zero. This means that a
+ * previous transfer completed, clearing 'this_residual', and
+ * now we need to setup the next scatter-gather buffer as the
+ * source or destination for THIS transfer.
+ */
+   if (!cmd->SCp.this_residual && cmd->SCp.buffers_residual) {
+      ++cmd->SCp.buffer;
+      --cmd->SCp.buffers_residual;
+      cmd->SCp.this_residual = cmd->SCp.buffer->length;
+      cmd->SCp.ptr = cmd->SCp.buffer->address;
+      }
+
+   write_wd33c93(regp,WD_SYNCHRONOUS_TRANSFER,hostdata->sync_xfer[cmd->target]);
+
+/* 'dma_setup()' will return TRUE if we can't do DMA. */
+
+   if (hostdata->dma_setup(cmd, data_in_dir)) {
+      transfer_pio(regp, (uchar **)&cmd->SCp.ptr, &cmd->SCp.this_residual,
+                         data_in_dir, hostdata);
+      }
+
+/* We are able to do DMA (in fact, the Amiga hardware is
+ * already going!), so start up the wd33c93 in DMA mode.
+ * We set 'hostdata->dma' = D_DMA_RUNNING so that when the
+ * transfer completes and causes an interrupt, we're
+ * reminded to tell the Amiga to shut down its end. We'll
+ * postpone the updating of 'this_residual' and 'ptr'
+ * until then.
+ */
+
+   else {
+      write_wd33c93(regp, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_DMA);
+DB(DB_TRANSFER_DATA,printk("[%p/%d]",cmd->SCp.ptr,cmd->SCp.this_residual))
+      write_wd33c93_count(regp,cmd->SCp.this_residual);
+
+      if (hostdata->level2 >= L2_DATA) {
+         write_wd33c93(regp, WD_COMMAND_PHASE, 0x41);
+         write_wd33c93_cmd(regp, WD_CMD_SEL_ATN_XFER);
+         hostdata->state = S_RUNNING_LEVEL2;
+         }
+      else
+         write_wd33c93_cmd(regp, WD_CMD_TRANS_INFO);
+
+      hostdata->dma = D_DMA_RUNNING;
+      }
+}
+
+
+
+void wd33c93_intr (struct Scsi_Host *instance)
+{
+struct WD33C93_hostdata *hostdata;
+Scsi_Cmnd *patch, *cmd;
+wd33c93_regs *regp;
+uchar asr, sr, phs, id, lun, *ucp, msg;
+unsigned long length;
+int i;
+
+
+   hostdata = (struct WD33C93_hostdata *)instance->hostdata;
+   regp = hostdata->regp;
+
+   asr = READ_AUX_STAT();
+   if (!(asr & ASR_INT) || (asr & ASR_BSY))
+      return;
+
+   cmd = (Scsi_Cmnd *)hostdata->connected;   /* assume we're connected */
+   sr = read_wd33c93(regp, WD_SCSI_STATUS);  /* clear the interrupt */
+   phs = read_wd33c93(regp, WD_COMMAND_PHASE);
+
+DB(DB_INTR,printk("{%02x:%02x-",asr,sr))
+
+/* After starting a DMA transfer, the next interrupt
+ * is guaranteed to be in response to completion of
+ * the transfer. Since the Amiga DMA hardware runs in
+ * in an open-ended fashion, it needs to be told when
+ * to stop; do that here if D_DMA_RUNNING is true.
+ * Also, we have to update 'this_residual' and 'ptr'
+ * based on the contents of the TRANSFER_COUNT register,
+ * in case the device decided to do an intermediate
+ * disconnect (a device may do this if it has to do a
+ * seek, or just to be nice and let other devices have
+ * some bus time during long transfers). After doing
+ * whatever is needed, we go on and service the WD3393
+ * interrupt normally.
+ */
+
+   if (hostdata->dma == D_DMA_RUNNING) {
+DB(DB_TRANSFER_DATA,printk("[%p/%d:",cmd->SCp.ptr,cmd->SCp.this_residual))
+      hostdata->dma_stop(cmd->host, cmd, 1);
+      hostdata->dma = D_DMA_OFF;
+      length = cmd->SCp.this_residual;
+      cmd->SCp.this_residual = read_wd33c93_count(regp);
+      cmd->SCp.ptr += (length - cmd->SCp.this_residual);
+DB(DB_TRANSFER_DATA,printk("%p/%d]",cmd->SCp.ptr,cmd->SCp.this_residual))
+      }
+
+/* Respond to the specific WD3393 interrupt - there are quite a few! */
+
+   switch (sr) {
+
+      case CSR_TIMEOUT:
+         cli();
+DB(DB_INTR,printk("TIMEOUT"))
+         if (hostdata->state == S_RUNNING_LEVEL2) {
+            hostdata->connected = NULL;
+            hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
+            }
+         else {
+            cmd = (Scsi_Cmnd *)hostdata->selecting;   /* get a valid cmd */
+            hostdata->selecting = NULL;
+            }
+
+         cmd->result = DID_NO_CONNECT << 16;
+         hostdata->selecting = NULL;
+         hostdata->state = S_UNCONNECTED;
+         cmd->scsi_done(cmd);    /* I think scsi_done() enables ints */
+
+/* We are not connected to a target - check to see if there
+ * are commands waiting to be executed.
+ */
+
+         wd33c93_execute(instance);
+         break;
+
+
+/* Note: this interrupt should not occur in a LEVEL2 command */
+
+      case CSR_SELECT:
+         cli();
+DB(DB_INTR,printk("SELECT"))
+         hostdata->connected = cmd = (Scsi_Cmnd *)hostdata->selecting;
+         hostdata->selecting = NULL;
+
+      /* construct an IDENTIFY message with correct disconnect bit */
+
+         if (hostdata->args & A_NO_DISCONNECT)
+            hostdata->outgoing_msg[0] = (0x80 | cmd->lun);
+         else
+            hostdata->outgoing_msg[0] = (0x80 | 0x40 | cmd->lun);
+
+         if (hostdata->sync_stat[cmd->target] == SS_FIRST) {
+#ifdef SYNC_DEBUG
+printk(" sending SDTR ");
+#endif
+
+            hostdata->sync_stat[cmd->target] = SS_WAITING;
+
+      /* tack on a 2nd message to ask about synchronous transfers */
+
+            hostdata->outgoing_msg[1] = EXTENDED_MESSAGE;
+            hostdata->outgoing_msg[2] = 3;
+            hostdata->outgoing_msg[3] = EXTENDED_SDTR;
+            hostdata->outgoing_msg[4] = OPTIMUM_SX_PER/4;
+            hostdata->outgoing_msg[5] = OPTIMUM_SX_OFF;
+            hostdata->outgoing_len = 6;
+            }
+         else
+            hostdata->outgoing_len = 1;
+
+         hostdata->state = S_CONNECTED;
+         break;
+
+
+      case CSR_XFER_DONE|PHS_DATA_IN:
+      case CSR_UNEXP    |PHS_DATA_IN:
+      case CSR_SRV_REQ  |PHS_DATA_IN:
+DB(DB_INTR,printk("IN-%d.%d",cmd->SCp.this_residual,cmd->SCp.buffers_residual))
+         transfer_bytes(regp, cmd, DATA_IN_DIR);
+         if (hostdata->state != S_RUNNING_LEVEL2)
+            hostdata->state = S_CONNECTED;
+         break;
+
+
+      case CSR_XFER_DONE|PHS_DATA_OUT:
+      case CSR_UNEXP    |PHS_DATA_OUT:
+      case CSR_SRV_REQ  |PHS_DATA_OUT:
+DB(DB_INTR,printk("OUT-%d.%d",cmd->SCp.this_residual,cmd->SCp.buffers_residual))
+         transfer_bytes(regp, cmd, DATA_OUT_DIR);
+         if (hostdata->state != S_RUNNING_LEVEL2)
+            hostdata->state = S_CONNECTED;
+         break;
+
+
+/* Note: this interrupt should not occur in a LEVEL2 command */
+
+      case CSR_XFER_DONE|PHS_COMMAND:
+      case CSR_SRV_REQ  |PHS_COMMAND:
+DB(DB_INTR,printk("CMND-%02x,%ld",cmd->cmnd[0],cmd->pid))
+         ucp = cmd->cmnd;
+         i = cmd->cmd_len;
+         transfer_pio(regp, &ucp, &i, DATA_OUT_DIR, hostdata);
+         hostdata->state = S_CONNECTED;
+         break;
+
+
+      case CSR_XFER_DONE|PHS_STATUS:
+      case CSR_UNEXP    |PHS_STATUS:
+      case CSR_SRV_REQ  |PHS_STATUS:
+DB(DB_INTR,printk("STATUS"))
+
+         cmd->SCp.Status = read_1_byte(regp);
+         if (hostdata->level2 >= L2_BASIC) {
+            sr = read_wd33c93(regp, WD_SCSI_STATUS);  /* clear interrupt */
+            hostdata->state = S_RUNNING_LEVEL2;
+            write_wd33c93(regp, WD_COMMAND_PHASE, 0x50);
+            write_wd33c93_cmd(regp, WD_CMD_SEL_ATN_XFER);
+            }
+         else {
+DB(DB_INTR,printk("=%02x",cmd->SCp.Status))
+            hostdata->state = S_CONNECTED;
+            }
+         break;
+
+
+      case CSR_XFER_DONE|PHS_MESS_IN:
+      case CSR_UNEXP    |PHS_MESS_IN:
+      case CSR_SRV_REQ  |PHS_MESS_IN:
+DB(DB_INTR,printk("MSG_IN="))
+
+         msg = read_1_byte(regp);
+         sr = read_wd33c93(regp, WD_SCSI_STATUS);  /* clear interrupt */
+
+         hostdata->incoming_msg[hostdata->incoming_ptr] = msg;
+         if (hostdata->incoming_msg[0] == EXTENDED_MESSAGE)
+            msg = EXTENDED_MESSAGE;
+         else
+            hostdata->incoming_ptr = 0;
+
+         cmd->SCp.Message = msg;
+         switch (msg) {
+
+            case COMMAND_COMPLETE:
+DB(DB_INTR,printk("CCMP-%ld",cmd->pid))
+               write_wd33c93_cmd(regp,WD_CMD_NEGATE_ACK);
+               hostdata->state = S_PRE_CMP_DISC;
+               break;
+
+            case SAVE_POINTERS:
+DB(DB_INTR,printk("SDP"))
+               write_wd33c93_cmd(regp,WD_CMD_NEGATE_ACK);
+               hostdata->state = S_CONNECTED;
+               break;
+
+            case RESTORE_POINTERS:
+DB(DB_INTR,printk("RDP"))
+
+               if (hostdata->level2 >= L2_BASIC) {
+                  write_wd33c93(regp, WD_COMMAND_PHASE, 0x45);
+                  write_wd33c93_cmd(regp, WD_CMD_SEL_ATN_XFER);
+                  hostdata->state = S_RUNNING_LEVEL2;
+                  }
+               else {
+                  write_wd33c93_cmd(regp, WD_CMD_NEGATE_ACK);
+                  hostdata->state = S_CONNECTED;
+                  }
+               break;
+
+            case DISCONNECT:
+DB(DB_INTR,printk("DIS"))
+               cmd->device->disconnect = 1;
+               write_wd33c93_cmd(regp,WD_CMD_NEGATE_ACK);
+               hostdata->state = S_PRE_TMP_DISC;
+               break;
+
+            case MESSAGE_REJECT:
+DB(DB_INTR,printk("REJ"))
+#ifdef SYNC_DEBUG
+printk("-REJ-");
+#endif
+               if (hostdata->sync_stat[cmd->target] == SS_WAITING)
+                  hostdata->sync_stat[cmd->target] = SS_SET;
+               write_wd33c93_cmd(regp,WD_CMD_NEGATE_ACK);
+               hostdata->state = S_CONNECTED;
+               break;
+
+            case EXTENDED_MESSAGE:
+DB(DB_INTR,printk("EXT"))
+
+               ucp = hostdata->incoming_msg;
+
+#ifdef SYNC_DEBUG
+printk("%02x",ucp[hostdata->incoming_ptr]);
+#endif
+         /* Is this the last byte of the extended message? */
+
+               if ((hostdata->incoming_ptr >= 2) &&
+                   (hostdata->incoming_ptr == (ucp[1] + 1))) {
+
+                  switch (ucp[2]) {   /* what's the EXTENDED code? */
+                     case EXTENDED_SDTR:
+                        id = calc_sync_xfer(ucp[3],ucp[4]);
+                        if (hostdata->sync_stat[cmd->target] != SS_WAITING) {
+                           printk("Rejecting target's SDTR message ");
+                           write_wd33c93_cmd(regp,WD_CMD_ASSERT_ATN); /* want MESS_OUT */
+                           hostdata->outgoing_msg[0] = MESSAGE_REJECT;
+                           hostdata->outgoing_len = 1;
+                           }
+                        else {
+                           hostdata->sync_xfer[cmd->target] = id;
+                           hostdata->sync_stat[cmd->target] = SS_SET;
+                           }
+#ifdef SYNC_DEBUG
+printk("sync_xfer=%02x",id);
+#endif
+                        write_wd33c93_cmd(regp,WD_CMD_NEGATE_ACK);
+                        hostdata->state = S_CONNECTED;
+                        break;
+                     default:
+                        printk("Rejecting Unknown Extended Message(%02x). ",ucp[2]);
+                        write_wd33c93_cmd(regp,WD_CMD_ASSERT_ATN); /* want MESS_OUT */
+                        hostdata->outgoing_msg[0] = MESSAGE_REJECT;
+                        hostdata->outgoing_len = 1;
+                        write_wd33c93_cmd(regp,WD_CMD_NEGATE_ACK);
+                        hostdata->state = S_CONNECTED;
+                        break;
+                     }
+                  hostdata->incoming_ptr = 0;
+                  }
+
+         /* We need to read more MESS_IN bytes for the extended message */
+
+               else {
+                  hostdata->incoming_ptr++;
+                  write_wd33c93_cmd(regp,WD_CMD_NEGATE_ACK);
+                  hostdata->state = S_CONNECTED;
+                  }
+               break;
+
+            default:
+               printk("Rejecting Unknown Message(%02x) ",ucp[0]);
+               write_wd33c93_cmd(regp,WD_CMD_ASSERT_ATN); /* want MESS_OUT */
+               hostdata->outgoing_msg[0] = MESSAGE_REJECT;
+               hostdata->outgoing_len = 1;
+               write_wd33c93_cmd(regp,WD_CMD_NEGATE_ACK);
+               hostdata->state = S_CONNECTED;
+            }
+         break;
+
+
+/* Note: this interrupt will occur only after a LEVEL2 command */
+
+      case CSR_SEL_XFER_DONE:
+         cli();
+         if (phs == 0x60) {
+DB(DB_INTR,printk("SX-DONE-%ld",cmd->pid))
+            cmd->SCp.Message = COMMAND_COMPLETE;
+            lun = read_wd33c93(regp, WD_TARGET_LUN);
+            if (cmd->SCp.Status == GOOD)
+               cmd->SCp.Status = lun;
+            hostdata->connected = NULL;
+            if (cmd->cmnd[0] != REQUEST_SENSE)
+               cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8);
+            else if (cmd->SCp.Status != GOOD)
+               cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16);
+            hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
+            hostdata->state = S_UNCONNECTED;
+            cmd->scsi_done(cmd);    /* I think scsi_done() enables ints */
+
+/* We are no longer  connected to a target - check to see if
+ * there are commands waiting to be executed.
+ */
+
+            wd33c93_execute(instance);
+            }
+         else {
+            printk("%02x:%02x:%02x-%ld: Unknown SEL_XFER_DONE phase!!---",asr,sr,phs,cmd->pid);
+            }
+         break;
+
+
+/* Note: this interrupt will occur only after a LEVEL2 command */
+
+      case CSR_SDP:
+DB(DB_INTR,printk("SDP"))
+            hostdata->state = S_RUNNING_LEVEL2;
+            write_wd33c93(regp, WD_COMMAND_PHASE, 0x41);
+            write_wd33c93_cmd(regp, WD_CMD_SEL_ATN_XFER);
+         break;
+
+
+      case CSR_XFER_DONE|PHS_MESS_OUT:
+      case CSR_UNEXP    |PHS_MESS_OUT:
+      case CSR_SRV_REQ  |PHS_MESS_OUT:
+DB(DB_INTR,printk("MSG_OUT="))
+
+/* To get here, we've probably requested MESSAGE_OUT and have
+ * already put the correct bytes in outgoing_msg[] and filled
+ * in outgoing_len. We simply send them out to the SCSI bus.
+ * Sometimes we get MESSAGE_OUT phase when we're not expecting
+ * it - like when our SDTR message is rejected by a target. Some
+ * targets send the REJECT before receiving all of the extended
+ * message, and then seem to go back to MESSAGE_OUT for a byte
+ * or two. Not sure why, ot if I'm doing something wrong to
+ * casue this to happen. Regardless, it seems that sending
+ * NOP messages in these situations results in no harm and
+ * makes everyone happy.
+ */
+
+         if (hostdata->outgoing_len == 0) {
+            hostdata->outgoing_len = 1;
+            hostdata->outgoing_msg[0] = NOP;
+            }
+         ucp = hostdata->outgoing_msg;
+         i = hostdata->outgoing_len;
+         transfer_pio(regp, &ucp, &i, DATA_OUT_DIR, hostdata);
+DB(DB_INTR,printk("%02x",hostdata->outgoing_msg[0]))
+         hostdata->outgoing_len = 0;
+         hostdata->state = S_CONNECTED;
+         break;
+
+
+      case CSR_DISC:
+DB(DB_INTR,printk("DISC"))
+         if (cmd == NULL) {
+            printk(" - Already disconnected! ");
+            hostdata->state = S_UNCONNECTED;
+            return;
+            }
+         switch (hostdata->state) {
+            case S_PRE_CMP_DISC:
+               hostdata->connected = NULL;
+               hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
+               hostdata->state = S_UNCONNECTED;
+               if (cmd->cmnd[0] != REQUEST_SENSE)
+                  cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8);
+               else if (cmd->SCp.Status != GOOD)
+                  cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16);
+               cmd->scsi_done(cmd);    /* I think scsi_done() enables ints */
+               break;
+            case S_PRE_TMP_DISC:
+            case S_RUNNING_LEVEL2:
+               cmd->host_scribble = (uchar *)hostdata->disconnected_Q;
+               hostdata->disconnected_Q = cmd;
+               hostdata->connected = NULL;
+               hostdata->state = S_UNCONNECTED;
+               break;
+            default:
+               printk("*** Unexpected DISCONNECT interrupt! ***");
+               hostdata->state = S_UNCONNECTED;
+            }
+
+/* We are no longer connected to a target - check to see if
+ * there are commands waiting to be executed.
+ */
+
+         wd33c93_execute(instance);
+         break;
+
+
+      case CSR_RESEL_AM:
+DB(DB_INTR,printk("RESEL"))
+
+         cli();
+
+   /* First we have to make sure this reselection didn't */
+   /* happen during Arbitration/Selection of some other device. */
+   /* If yes, put losing command back on top of input_Q. */
+
+         if (hostdata->level2 == L2_NONE) {
+
+            if (hostdata->selecting) {
+               cmd = (Scsi_Cmnd *)hostdata->selecting;
+               hostdata->selecting = NULL;
+               hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
+               cmd->host_scribble = (uchar *)hostdata->input_Q;
+               hostdata->input_Q = cmd;
+               }
+            }
+
+         else {
+
+            if (cmd) {
+               if (phs == 0x00) {
+                  hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
+                  cmd->host_scribble = (uchar *)hostdata->input_Q;
+                  hostdata->input_Q = cmd;
+                  }
+               else {
+                  printk("---%02x:%02x:%02x-TROUBLE: Intrusive ReSelect!---",asr,sr,phs);
+                  while (1)
+                     printk("\r");
+                  }
+               }
+
+            }
+
+   /* OK - find out which device reslected us. */
+
+         id = read_wd33c93(regp, WD_SOURCE_ID);
+         id &= SRCID_MASK;
+
+   /* and extract the lun from the ID message. (Note that we don't
+    * bother to check for a valid message here - I guess this is
+    * not the right way to go, but...)
+    */
+
+         lun = read_wd33c93(regp, WD_DATA);
+         if (hostdata->level2 < L2_RESELECT)
+            write_wd33c93_cmd(regp,WD_CMD_NEGATE_ACK);
+         lun &= 7;
+
+   /* Now we look for the command that's reconnecting. */
+
+         cmd = (Scsi_Cmnd *)hostdata->disconnected_Q;
+         patch = NULL;
+         while (cmd) {
+            if (id == cmd->target && lun == cmd->lun)
+               break;
+            patch = cmd;
+            cmd = (Scsi_Cmnd *)cmd->host_scribble;
+            }
+
+   /* Hmm. Couldn't find a valid command.... What to do? */
+
+         if (!cmd) {
+            printk("---TROUBLE: target %d.%d not in disconnect queue---",id,lun);
+            return;
+            }
+
+   /* Ok, found the command - now start it up again. */
+
+         if (patch)
+            patch->host_scribble = cmd->host_scribble;
+         else
+            hostdata->disconnected_Q = (Scsi_Cmnd *)cmd->host_scribble;
+         hostdata->connected = cmd;
+
+   /* We don't need to worry about 'initialize_SCp()' or 'hostdata->busy[]'
+    * because these things are preserved over a disconnect.
+    * But we DO need to fix the DPD bit so it's correct for this command.
+    */
+
+         if (IS_DIR_OUT(cmd))
+            write_wd33c93(regp, WD_DESTINATION_ID, cmd->target);
+         else
+            write_wd33c93(regp, WD_DESTINATION_ID, cmd->target | DSTID_DPD);
+         if (hostdata->level2 >= L2_RESELECT) {
+            write_wd33c93_count(regp, 0);  /* we want a DATA_PHASE interrupt */
+            write_wd33c93(regp, WD_COMMAND_PHASE, 0x45);
+            write_wd33c93_cmd(regp, WD_CMD_SEL_ATN_XFER);
+            hostdata->state = S_RUNNING_LEVEL2;
+            }
+         else
+            hostdata->state = S_CONNECTED;
+
+DB(DB_INTR,printk("-%ld",cmd->pid))
+         break;
+         
+      default:
+         printk("\n---UNKNOWN INTERRUPT:%02x:%02x:%02x!!---",asr,sr,phs);
+      }
+
+DB(DB_INTR,printk("} "))
+
+}
+
+
+
+void reset_wd33c93(struct Scsi_Host *instance)
+{
+struct WD33C93_hostdata *hostdata;
+wd33c93_regs *regp;
+uchar sr;
+
+   hostdata = (struct WD33C93_hostdata *)instance->hostdata;
+   regp = hostdata->regp;
+
+   write_wd33c93(regp, WD_OWN_ID, OWNID_EAF | OWNID_RAF |
+                 instance->this_id | hostdata->clock_freq);
+   write_wd33c93(regp, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED);
+   write_wd33c93(regp, WD_SYNCHRONOUS_TRANSFER,
+                 calc_sync_xfer(DEFAULT_SX_PER/4,DEFAULT_SX_OFF));
+   write_wd33c93(regp, WD_COMMAND, WD_CMD_RESET);
+
+   while (!(READ_AUX_STAT() & ASR_INT))
+      ;
+   sr = read_wd33c93(regp, WD_SCSI_STATUS);
+
+   hostdata->microcode = read_wd33c93(regp, WD_CDB_1);
+   if (sr == 0x00)
+      hostdata->chip = C_WD33C93;
+   else if (sr == 0x01) {
+      write_wd33c93(regp, WD_QUEUE_TAG, 0xa5);  /* any random number */
+      sr = read_wd33c93(regp, WD_QUEUE_TAG);
+      if (sr == 0xa5) {
+         hostdata->chip = C_WD33C93B;
+         write_wd33c93(regp, WD_QUEUE_TAG, 0);
+         }
+      else
+         hostdata->chip = C_WD33C93A;
+      }
+   else
+      hostdata->chip = C_UNKNOWN_CHIP;
+
+   write_wd33c93(regp, WD_TIMEOUT_PERIOD, TIMEOUT_PERIOD_VALUE);
+   if (hostdata->args & A_NO_DISCONNECT)
+      write_wd33c93(regp, WD_SOURCE_ID, 0);
+   else
+      write_wd33c93(regp, WD_SOURCE_ID, SRCID_ER);
+   write_wd33c93(regp, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED);
+}
+
+
+
+int wd33c93_reset(Scsi_Cmnd *SCpnt)
+{
+unsigned long flags;
+struct Scsi_Host *instance;
+
+   instance = SCpnt->host;
+
+   printk("scsi%d: reset. ", instance->host_no);
+   save_flags(flags);
+   cli();
+   ((struct WD33C93_hostdata *)instance->hostdata)->dma_stop(instance,NULL,0);
+   reset_wd33c93(instance);
+   SCpnt->result = DID_RESET << 16;
+   restore_flags(flags);
+   return 0;
+}
+
+
+
+int wd33c93_abort (Scsi_Cmnd *cmd)
+{
+struct Scsi_Host *instance;
+struct WD33C93_hostdata *hostdata;
+wd33c93_regs *regp;
+Scsi_Cmnd *tmp, **prev;
+unsigned long flags;
+
+   instance = cmd->host;
+   hostdata = (struct WD33C93_hostdata *)instance->hostdata;
+   regp = hostdata->regp;
+
+   printk ("scsi%d: abort. ", instance->host_no);
+
+   save_flags (flags);
+   cli();
+
+/*
+ * Case 1 : If the command hasn't been issued yet, we simply remove it
+ *     from the issue queue.
+ */
+   for (prev=(Scsi_Cmnd **)&(hostdata->input_Q),tmp=(Scsi_Cmnd *)hostdata->input_Q;
+         tmp;
+         prev=(Scsi_Cmnd **)&(tmp->host_scribble),tmp=(Scsi_Cmnd *)tmp->host_scribble)
+      if (cmd == tmp) {
+         (*prev) = (Scsi_Cmnd *)tmp->host_scribble;
+         tmp->host_scribble = NULL;
+         tmp->result = DID_ABORT << 16;
+         restore_flags(flags);
+         printk("scsi%d : abort removed command from issue queue. ",
+           instance->host_no);
+         tmp->scsi_done(tmp);
+         return SCSI_ABORT_SUCCESS;
+         }
+
+/*
+ * Case 2 : If any commands are connected, we're going to fail the abort
+ *     and let the high level SCSI driver retry at a later time or
+ *     issue a reset.
+ *
+ *     Timeouts, and therefore aborted commands, will be highly unlikely
+ *     and handling them cleanly in this situation would make the common
+ *     case of noresets less efficient, and would pollute our code.  So,
+ *     we fail.
+ */
+
+   if (hostdata->connected == cmd) {
+      uchar sr, asr;
+      unsigned long timeout;
+
+      printk("scsi%d : aborting connected command. ", instance->host_no);
+
+      if (hostdata->dma == D_DMA_RUNNING) {
+         hostdata->dma_stop(instance, cmd, 0);
+         hostdata->dma = D_DMA_OFF;
+         }
+
+         printk("scsi%d : wd33c93 asr is %x. ", instance->host_no, READ_AUX_STAT());
+
+      write_wd33c93(regp, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED);
+      write_wd33c93_cmd(regp, WD_CMD_ABORT);
+
+/* Now we have to attempt to flush out the FIFO... */
+
+      timeout = 1000000;
+      do {
+         asr = READ_AUX_STAT();
+         if (asr & ASR_DBR)
+            read_wd33c93(regp, WD_DATA);
+         } while (!(asr & ASR_INT) && timeout-- > 0);
+      sr = read_wd33c93(regp, WD_SCSI_STATUS);
+      printk("scsi%d : wd33c93 sr is %x. ", instance->host_no,
+         read_wd33c93(regp, WD_SCSI_STATUS));
+
+      if (sr >= (CSR_ABORT|PHS_DATA_OUT) && sr <= (CSR_ABORT|PHS_MESS_IN)) {
+   /*
+    * Abort command processed.
+    * Still connected.
+    * We must disconnect.
+    */
+         printk("scsi%d : count was %ld. ", instance->host_no,
+            read_wd33c93_count(regp));
+
+         timeout = 1000000;
+         while ((asr & ASR_CIP) && timeout-- > 0)
+            asr = READ_AUX_STAT();
+         write_wd33c93_cmd(regp, WD_CMD_DISCONNECT);
+         asr = READ_AUX_STAT();
+         if (asr & ASR_LCI)
+            printk ("scsi%d: disconnect command ignored. ",
+               instance->host_no);
+         timeout = 1000000;
+         while ((asr & ASR_CIP) && timeout-- > 0)
+            asr = READ_AUX_STAT();
+         }
+      asr = READ_AUX_STAT();
+      sr = read_wd33c93(regp, WD_SCSI_STATUS);
+      printk("scsi%d : asr is %x, sr is %x. ",instance->host_no,asr,sr);
+      write_wd33c93_cmd(regp, WD_CMD_DISCONNECT);
+      timeout = 1000000;
+      while ((asr & ASR_CIP) && timeout-- > 0)
+         asr = READ_AUX_STAT();
+      sr = read_wd33c93(regp, WD_SCSI_STATUS);
+      printk("scsi%d : asr is %x, sr is %x. ",instance->host_no,asr,sr);
+      reset_wd33c93(instance);
+      cmd->result = DID_ABORT << 16;
+      cmd->scsi_done(cmd);
+      hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
+      hostdata->connected = NULL;
+      hostdata->state = S_UNCONNECTED;
+      wd33c93_execute (instance);
+      restore_flags(flags);
+      return SCSI_ABORT_SUCCESS;
+      }
+
+/*
+ * Case 3: If the command is currently disconnected from the bus,
+ * we're not going to expend much effort here: Let's just return
+ * an ABORT_SNOOZE and hope for the best...
+ */
+
+   for (tmp=(Scsi_Cmnd *)hostdata->disconnected_Q; tmp;
+         tmp=(Scsi_Cmnd *)tmp->host_scribble)
+      if (cmd == tmp) {
+         restore_flags(flags);
+         return SCSI_ABORT_SNOOZE;
+         }
+
+/*
+ * Case 4 : If we reached this point, the command was not found in any of
+ *     the queues.
+ *
+ * We probably reached this point because of an unlikely race condition
+ * between the command completing successfully and the abortion code,
+ * so we won't panic, but we will notify the user in case somethign really
+ * broke.
+ */
+
+   restore_flags(flags);
+   printk("scsi%d : warning : SCSI command probably completed successfully\n"
+      "         before abortion. ", instance->host_no);
+   return SCSI_ABORT_NOT_RUNNING;
+}
+
+
+
+#define MAX_WD33C93_HOSTS 8
+static unsigned int setup_args_array[MAX_WD33C93_HOSTS];
+static int setup_args_array_x = 0;
+
+void wd33c93_setup (char *str, int *ints)
+{
+int i;
+
+   for (i=0; i<ints[0]; i++) {
+      setup_args_array[i] = ints[i+1];
+      }
+}
+
+
+
+void wd33c93_init (struct Scsi_Host *instance, wd33c93_regs *regs,
+         dma_setup_t setup, dma_stop_t stop, int clock_freq)
+{
+struct WD33C93_hostdata *hostdata;
+int i;
+
+   hostdata = (struct WD33C93_hostdata *)instance->hostdata;
+
+   hostdata->regp = regs;
+   hostdata->clock_freq = clock_freq;
+   hostdata->dma_setup = setup;
+   hostdata->dma_stop = stop;
+   hostdata->dma_bounce_buffer = NULL;
+   hostdata->dma_bounce_len = 0;
+   for (i = 0; i < 8; i++) {
+      hostdata->busy[i] = 0;
+      hostdata->sync_xfer[i] = calc_sync_xfer(DEFAULT_SX_PER/4,DEFAULT_SX_OFF);
+      hostdata->sync_stat[i] = SS_UNSET;  /* using default sync values */
+      }
+   hostdata->input_Q = NULL;
+   hostdata->selecting = NULL;
+   hostdata->connected = NULL;
+   hostdata->disconnected_Q = NULL;
+   hostdata->state = S_UNCONNECTED;
+   hostdata->dma = D_DMA_OFF;
+   hostdata->incoming_ptr = 0;
+   hostdata->outgoing_len = 0;
+
+   hostdata->args = setup_default;
+   if ((setup_args_array_x < MAX_WD33C93_HOSTS) &&
+       (setup_args_array[setup_args_array_x]))
+      hostdata->args = setup_args_array[setup_args_array_x];
+   setup_args_array_x++;
+
+   i = hostdata->args & (A_LEVEL2_0 | A_LEVEL2_1 | A_LEVEL2_2);
+   i >>= 8;
+   if (i == 0)
+      i = L2_DEFAULT;
+   hostdata->level2 = i;
+
+   cli();
+   reset_wd33c93(instance);
+   sti();
+
+   printk("wd33c93-%d: ",instance->host_no);
+   switch (hostdata->chip) {
+      case C_WD33C93:
+         printk("Found WD33c93 chip! This driver probably needs at least the 'A' version!\n");
+         break;
+      case C_WD33C93A:
+         printk("Found WD33c93A chip: microcode=%02x\n",hostdata->microcode);
+         break;
+      case C_WD33C93B:
+         printk("Found WD33c93B chip: microcode=%02x\n",hostdata->microcode);
+         break;
+      default:
+         printk("Unknown 3393 chip!\n");
+      }
+   printk("wd33c93-%d: LEVEL2 commands %s (%d)\n",instance->host_no,
+            (hostdata->level2 == L2_NONE)?"disabled":"enabled",
+            hostdata->level2);
+#ifdef DEBUGGING_ON
+   printk("wd33c93-%d: debug_flags = %04x\n",instance->host_no,hostdata->args);
+#endif
+   printk("wd33c93-%d: driver version %s - %s\n",instance->host_no,
+                     WD33C93_VERSION,WD33C93_DATE);
+}
+
diff -u --recursive --new-file v1.3.93/linux/drivers/scsi/wd33c93.h linux/drivers/scsi/wd33c93.h
--- v1.3.93/linux/drivers/scsi/wd33c93.h	Thu Jan  1 02:00:00 1970
+++ linux/drivers/scsi/wd33c93.h	Sat Mar 16 02:50:46 1996
@@ -0,0 +1,292 @@
+#ifndef WD33C93_H
+#define WD33C93_H
+
+/*
+ *    wd33c93.h -  Linux device driver definitions for the
+ *                 Commodore Amiga A2091/590 SCSI controller card
+ *
+ * Copyright (c) 1996 John Shifflett, GeoLog Consulting
+ *    john@geolog.com
+ *    jshiffle@netcom.com
+ *
+ * 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, 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.
+ *
+ */
+
+
+
+#define uchar unsigned char
+
+
+/* wd register names */
+#define WD_OWN_ID    0x00
+#define WD_CONTROL      0x01
+#define WD_TIMEOUT_PERIOD  0x02
+#define WD_CDB_1     0x03
+#define WD_CDB_2     0x04
+#define WD_CDB_3     0x05
+#define WD_CDB_4     0x06
+#define WD_CDB_5     0x07
+#define WD_CDB_6     0x08
+#define WD_CDB_7     0x09
+#define WD_CDB_8     0x0a
+#define WD_CDB_9     0x0b
+#define WD_CDB_10    0x0c
+#define WD_CDB_11    0x0d
+#define WD_CDB_12    0x0e
+#define WD_TARGET_LUN      0x0f
+#define WD_COMMAND_PHASE   0x10
+#define WD_SYNCHRONOUS_TRANSFER 0x11
+#define WD_TRANSFER_COUNT_MSB 0x12
+#define WD_TRANSFER_COUNT  0x13
+#define WD_TRANSFER_COUNT_LSB 0x14
+#define WD_DESTINATION_ID  0x15
+#define WD_SOURCE_ID    0x16
+#define WD_SCSI_STATUS     0x17
+#define WD_COMMAND      0x18
+#define WD_DATA      0x19
+#define WD_QUEUE_TAG    0x1a
+#define WD_AUXILIARY_STATUS   0x1f
+
+/* WD commands */
+#define WD_CMD_RESET    0x00
+#define WD_CMD_ABORT    0x01
+#define WD_CMD_ASSERT_ATN  0x02
+#define WD_CMD_NEGATE_ACK  0x03
+#define WD_CMD_DISCONNECT  0x04
+#define WD_CMD_RESELECT    0x05
+#define WD_CMD_SEL_ATN     0x06
+#define WD_CMD_SEL      0x07
+#define WD_CMD_SEL_ATN_XFER   0x08
+#define WD_CMD_SEL_XFER    0x09
+#define WD_CMD_RESEL_RECEIVE  0x0a
+#define WD_CMD_RESEL_SEND  0x0b
+#define WD_CMD_WAIT_SEL_RECEIVE 0x0c
+#define WD_CMD_TRANS_ADDR  0x18
+#define WD_CMD_TRANS_INFO  0x20
+#define WD_CMD_TRANSFER_PAD   0x21
+#define WD_CMD_SBT_MODE    0x80
+
+/* ASR register */
+#define ASR_INT         (0x80)
+#define ASR_LCI         (0x40)
+#define ASR_BSY         (0x20)
+#define ASR_CIP         (0x10)
+#define ASR_PE          (0x02)
+#define ASR_DBR         (0x01)
+
+/* SCSI Bus Phases */
+#define PHS_DATA_OUT    0x00
+#define PHS_DATA_IN     0x01
+#define PHS_COMMAND     0x02
+#define PHS_STATUS      0x03
+#define PHS_MESS_OUT    0x06
+#define PHS_MESS_IN     0x07
+
+/* Command Status Register definitions */
+
+  /* reset state interrupts */
+#define CSR_RESET    0x00
+#define CSR_RESET_AF    0x01
+
+  /* successful completion interrupts */
+#define CSR_RESELECT    0x10
+#define CSR_SELECT      0x11
+#define CSR_SEL_XFER_DONE  0x16
+#define CSR_XFER_DONE      0x18
+
+  /* paused or aborted interrupts */
+#define CSR_MSGIN    0x20
+#define CSR_SDP         0x21
+#define CSR_SEL_ABORT      0x22
+#define CSR_RESEL_ABORT    0x25
+#define CSR_RESEL_ABORT_AM 0x27
+#define CSR_ABORT    0x28
+
+  /* terminated interrupts */
+#define CSR_INVALID     0x40
+#define CSR_UNEXP_DISC     0x41
+#define CSR_TIMEOUT     0x42
+#define CSR_PARITY      0x43
+#define CSR_PARITY_ATN     0x44
+#define CSR_BAD_STATUS     0x45
+#define CSR_UNEXP    0x48
+
+  /* service required interrupts */
+#define CSR_RESEL    0x80
+#define CSR_RESEL_AM    0x81
+#define CSR_DISC     0x85
+#define CSR_SRV_REQ     0x88
+
+   /* Own ID/CDB Size register */
+#define OWNID_EAF    0x08
+#define OWNID_EHP    0x10
+#define OWNID_RAF    0x20
+#define OWNID_FS_8   0x00
+#define OWNID_FS_12  0x40
+#define OWNID_FS_16  0x80
+
+   /* define these so we don't have to change a2091.c, etc. */
+#define WD33C93_FS_8_10  OWNID_FS_8
+#define WD33C93_FS_12_15 OWNID_FS_12
+#define WD33C93_FS_16_20 OWNID_FS_16
+
+   /* Control register */
+#define CTRL_HSP     0x01
+#define CTRL_HA      0x02
+#define CTRL_IDI     0x04
+#define CTRL_EDI     0x08
+#define CTRL_HHP     0x10
+#define CTRL_POLLED  0x00
+#define CTRL_BURST   0x20
+#define CTRL_BUS     0x40
+#define CTRL_DMA     0x80
+
+   /* Timeout Period register */
+#define TIMEOUT_PERIOD_VALUE  20    /* results in 200 ms. */
+
+   /* Synchronous Transfer Register */
+#define STR_FSS      0x80
+
+   /* Destination ID register */
+#define DSTID_DPD    0x40
+#define DATA_OUT_DIR 0
+#define DATA_IN_DIR  1
+#define DSTID_SCC    0x80
+
+   /* Source ID register */
+#define SRCID_MASK   0x07
+#define SRCID_SIV    0x08
+#define SRCID_DSP    0x20
+#define SRCID_ES     0x40
+#define SRCID_ER     0x80
+
+   /* This is what the 3393 chip looks like to us */
+typedef struct {
+   volatile unsigned char   SASR;
+   char                     pad;
+   volatile unsigned char   SCMD;
+} wd33c93_regs;
+
+
+typedef int (*dma_setup_t) (Scsi_Cmnd *SCpnt, int dir_in);
+typedef void (*dma_stop_t) (struct Scsi_Host *instance, Scsi_Cmnd *SCpnt,
+             int status);
+
+
+#define DEFAULT_SX_PER   500     /* (ns) fairly safe */
+#define DEFAULT_SX_OFF   0       /* aka async */
+
+#define OPTIMUM_SX_PER   252     /* (ns) best we can do (mult-of-4) */
+#define OPTIMUM_SX_OFF   12      /* size of wd3393 fifo */
+
+struct sx_period {
+   unsigned int   period_ns;
+   uchar          reg_value;
+   };
+
+
+struct WD33C93_hostdata {
+    struct Scsi_Host *next;
+    wd33c93_regs     *regp;
+    uchar            clock_freq;
+    uchar            chip;             /* what kind of wd33c93? */
+    uchar            microcode;        /* microcode rev if 'B' */
+    int              dma_dir;          /* data transfer dir. */
+    dma_setup_t      dma_setup;
+    dma_stop_t       dma_stop;
+    uchar            *dma_bounce_buffer;
+    unsigned int     dma_bounce_len;
+    volatile uchar   busy[8];          /* index = target, bit = lun */
+    volatile Scsi_Cmnd *input_Q;       /* commands waiting to be started */
+    volatile Scsi_Cmnd *selecting;     /* trying to select this command */
+    volatile Scsi_Cmnd *connected;     /* currently connected command */
+    volatile Scsi_Cmnd *disconnected_Q;/* commands waiting for reconnect */
+    uchar            state;            /* what we are currently doing */
+    uchar            dma;              /* current state of DMA (on/off) */
+    uchar            level2;           /* extent to which Level-2 commands are used */
+    unsigned int     args;             /* set from command-line argument */
+    uchar            incoming_msg[8];  /* filled during message_in phase */
+    int              incoming_ptr;     /* mainly used with EXTENDED messages */
+    uchar            outgoing_msg[8];  /* send this during next message_out */
+    int              outgoing_len;     /* length of outgoing message */
+    uchar            sync_xfer[8];     /* sync_xfer reg settings per target */
+    uchar            sync_stat[8];     /* status of sync negotiation per target */
+    };
+
+
+/* defines for hostdata->chip */
+
+#define C_WD33C93       0
+#define C_WD33C93A      1
+#define C_WD33C93B      2
+#define C_UNKNOWN_CHIP  100
+
+/* defines for hostdata->state */
+
+#define S_UNCONNECTED         0
+#define S_SELECTING           1
+#define S_RUNNING_LEVEL2      2
+#define S_CONNECTED           3
+#define S_PRE_TMP_DISC        4
+#define S_PRE_CMP_DISC        5
+
+/* defines for hostdata->dma */
+
+#define D_DMA_OFF          0
+#define D_DMA_RUNNING      1
+
+/* defines for hostdata->level2 */
+/* NOTE: only the first 3 are implemented so far - having trouble
+ * when more than 1 device is reading/writing at the same time...
+ */
+
+#define L2_NONE      1  /* no combination commands - we get lots of ints */
+#define L2_SELECT    2  /* start with SEL_ATN_XFER, but never resume it */
+#define L2_BASIC     3  /* resume after STATUS ints & RDP messages */
+#define L2_DATA      4  /* resume after DATA_IN/OUT ints */
+#define L2_MOST      5  /* resume after anything except a RESELECT int */
+#define L2_RESELECT  6  /* resume after everything, including RESELECT ints */
+#define L2_ALL       7  /* always resume */
+#define L2_DEFAULT   L2_BASIC
+
+/* defines for hostdata->args */
+/*  (The first 8 bits are reserved for compatability. They function
+ *   as they did in the old driver - note that turning off sync_xfer
+ *   on a target affects all LUNs at that SCSI id.)
+ */
+
+#define A_LEVEL2_0            1<<8
+#define A_LEVEL2_1            1<<9
+#define A_LEVEL2_2            1<<10
+#define A_NO_DISCONNECT       1<<11
+
+#define DB_QUEUE_COMMAND      1<<12
+#define DB_EXECUTE            1<<13
+#define DB_INTR               1<<14
+#define DB_TRANSFER_DATA      1<<15
+
+/* defines for hostdata->sync_stat[] */
+
+#define SS_UNSET     0
+#define SS_FIRST     1
+#define SS_WAITING   2
+#define SS_SET       3
+
+
+void wd33c93_init (struct Scsi_Host *instance, wd33c93_regs *regs,
+         dma_setup_t setup, dma_stop_t stop, int clock_freq);
+int wd33c93_abort (Scsi_Cmnd *cmd);
+int wd33c93_reset (Scsi_Cmnd *);
+int wd33c93_queuecommand (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *));
+void wd33c93_intr (struct Scsi_Host *instance);
+
+#endif /* WD33C93_H */
diff -u --recursive --new-file v1.3.93/linux/drivers/sound/dmasound.c linux/drivers/sound/dmasound.c
--- v1.3.93/linux/drivers/sound/dmasound.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/sound/dmasound.c	Thu Apr 18 02:03:28 1996
@@ -0,0 +1,3252 @@
+
+/* linux/drivers/sound/dmasound.c */
+
+/*
+
+VoxWare compatible Atari TT DMA sound driver for 680x0 Linux
+
+(c) 1995 by Michael Schlueter & Michael Marte
+
+Michael Schlueter (michael@duck.syd.de) did the basic structure of the VFS
+interface and the u-law to signed byte conversion.
+
+Michael Marte (marte@informatik.uni-muenchen.de) did the sound queue,
+/dev/mixer, /dev/sndstat and complemented the VFS interface. He would like
+to thank:
+Michael Schlueter for initial ideas and documentation on the MFP and
+the DMA sound hardware.
+Therapy? for their CD 'Troublegum' which really made me rock.
+
+/dev/sndstat is based on code by Hannu Savolainen, the author of the
+VoxWare family of drivers.
+
+This file is subject to the terms and conditions of the GNU General Public
+License.  See the file README.legal in the main directory of this archive
+for more details.
+
+History:
+1995/8/25	first release
+
+1995/9/02	++roman: fixed atari_stram_alloc() call, the timer programming
+			and several race conditions
+
+1995/9/14	++roman: After some discussion with Michael Schlueter, revised
+			the interrupt disabling
+			Slightly speeded up U8->S8 translation by using long
+			operations where possible
+			Added 4:3 interpolation for /dev/audio
+
+1995/9/20	++TeSche: Fixed a bug in sq_write and changed /dev/audio
+			converting to play at 12517Hz instead of 6258Hz.
+
+1995/9/23	++TeSche: Changed sq_interrupt() and sq_play() to pre-program
+			the DMA for another frame while there's still one
+			running. This allows the IRQ response to be
+			arbitrarily delayed and playing will still continue.
+
+1995/10/14	++Guenther_Kelleter@ac3.maus.de, ++TeSche: better support for
+			Falcon audio (the Falcon doesn't raise an IRQ at the
+			end of a frame, but at the beginning instead!). uses
+			'if (codec_dma)' in lots of places to simply switch
+			between Falcon and TT code.
+
+1995/11/06	++TeSche: started introducing a hardware abstraction scheme
+			(may perhaps also serve for Amigas?), can now play
+			samples at almost all frequencies by means of a more
+			generalized expand routine, takes a good deal of care
+			to cut data only at sample sizes, buffer size is now
+			a kernel runtime option, implemented fsync() & several
+			minor improvements
+		++Guenther: useful hints and bugfixes, cross-checked it for
+			Falcons
+
+1996/3/9	++geert: support added for Amiga, A-law, 16-bit little endian.
+			Unification to drivers/sound/dmasound.c.
+1996/4/6	++Martin Mitchell: updated to 1.3 kernel.
+*/
+
+
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/major.h>
+#include <linux/config.h>
+#include <linux/fcntl.h>
+#include <linux/errno.h>
+#include <linux/mm.h>
+#include <linux/malloc.h>
+
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/pgtable.h>
+#include <asm/bootinfo.h>
+
+#ifdef CONFIG_ATARI
+#include <asm/atarihw.h>
+#include <asm/atariints.h>
+#endif /* CONFIG_ATARI */
+#ifdef CONFIG_AMIGA
+#include <asm/amigahw.h>
+#include <asm/amigaints.h>
+#endif /* CONFIG_AMIGA */
+
+#include "dmasound.h"
+#include <linux/soundcard.h>
+
+
+#ifdef CONFIG_ATARI
+extern void atari_microwire_cmd(int cmd);
+#endif /* CONFIG_ATARI */
+
+#ifdef CONFIG_AMIGA
+   /*
+    *	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;
+
+
+   /*
+    *	amiga_mksound() should be able to restore the period after beeping
+    *	(Imported from arch/m68k/amiga/amisound.c)
+    */
+
+extern u_short amiga_audio_period;
+
+
+   /*
+    *	Audio DMA masks
+    */
+
+#define AMI_AUDIO_OFF	(DMAF_AUD0 | DMAF_AUD1 | DMAF_AUD2 | DMAF_AUD3)
+#define AMI_AUDIO_8	(DMAF_SETCLR | DMAF_MASTER | DMAF_AUD0 | DMAF_AUD1)
+#define AMI_AUDIO_14	(AMI_AUDIO_8 | DMAF_AUD2 | DMAF_AUD3)
+
+#endif /* CONFIG_AMIGA */
+
+
+/*** Some declarations *******************************************************/
+
+
+#define DMASND_TT		1
+#define DMASND_FALCON		2
+#define DMASND_AMIGA		3
+
+#define MAX_CATCH_RADIUS	10
+#define MIN_BUFFERS		4
+#define MIN_BUFSIZE 		4
+#define MAX_BUFSIZE		128	/* Limit for Amiga */
+
+static int catchRadius = 0, numBufs = 4, bufSize = 32;
+
+
+#define arraysize(x)	(sizeof(x)/sizeof(*(x)))
+#define min(x, y)	((x) < (y) ? (x) : (y))
+#define le2be16(x)	(((x)<<8 & 0xff00) | ((x)>>8 & 0x00ff))
+#define le2be16dbl(x)	(((x)<<8 & 0xff00ff00) | ((x)>>8 & 0x00ff00ff))
+
+#define IOCTL_IN(arg)		get_user((int *)(arg))
+#define IOCTL_OUT(arg, ret)	ioctl_return((int *)arg, ret)
+
+
+/*** Some low level helpers **************************************************/
+
+
+/* 8 bit mu-law */
+
+static char ulaw2dma8[] = {
+    -126,   -122,   -118,   -114,   -110,   -106,   -102,    -98,
+     -94,    -90,    -86,    -82,    -78,    -74,    -70,    -66,
+     -63,    -61,    -59,    -57,    -55,    -53,    -51,    -49,
+     -47,    -45,    -43,    -41,    -39,    -37,    -35,    -33,
+     -31,    -30,    -29,    -28,    -27,    -26,    -25,    -24,
+     -23,    -22,    -21,    -20,    -19,    -18,    -17,    -16,
+     -16,    -15,    -15,    -14,    -14,    -13,    -13,    -12,
+     -12,    -11,    -11,    -10,    -10,     -9,     -9,     -8,
+      -8,     -8,     -7,     -7,     -7,     -7,     -6,     -6,
+      -6,     -6,     -5,     -5,     -5,     -5,     -4,     -4,
+      -4,     -4,     -4,     -4,     -3,     -3,     -3,     -3,
+      -3,     -3,     -3,     -3,     -2,     -2,     -2,     -2,
+      -2,     -2,     -2,     -2,     -2,     -2,     -2,     -2,
+      -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,
+      -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,
+      -1,     -1,     -1,     -1,     -1,     -1,     -1,      0,
+     125,    121,    117,    113,    109,    105,    101,     97,
+      93,     89,     85,     81,     77,     73,     69,     65,
+      62,     60,     58,     56,     54,     52,     50,     48,
+      46,     44,     42,     40,     38,     36,     34,     32,
+      30,     29,     28,     27,     26,     25,     24,     23,
+      22,     21,     20,     19,     18,     17,     16,     15,
+      15,     14,     14,     13,     13,     12,     12,     11,
+      11,     10,     10,      9,      9,      8,      8,      7,
+       7,      7,      6,      6,      6,      6,      5,      5,
+       5,      5,      4,      4,      4,      4,      3,      3,
+       3,      3,      3,      3,      2,      2,      2,      2,
+       2,      2,      2,      2,      1,      1,      1,      1,
+       1,      1,      1,      1,      1,      1,      1,      1,
+       0,      0,      0,      0,      0,      0,      0,      0,
+       0,      0,      0,      0,      0,      0,      0,      0,
+       0,      0,      0,      0,      0,      0,      0,      0
+};
+
+/* 8 bit A-law */
+
+static char alaw2dma8[] = {
+     -22,    -21,    -24,    -23,    -18,    -17,    -20,    -19,
+     -30,    -29,    -32,    -31,    -26,    -25,    -28,    -27,
+     -11,    -11,    -12,    -12,     -9,     -9,    -10,    -10,
+     -15,    -15,    -16,    -16,    -13,    -13,    -14,    -14,
+     -86,    -82,    -94,    -90,    -70,    -66,    -78,    -74,
+    -118,   -114,   -126,   -122,   -102,    -98,   -110,   -106,
+     -43,    -41,    -47,    -45,    -35,    -33,    -39,    -37,
+     -59,    -57,    -63,    -61,    -51,    -49,    -55,    -53,
+      -2,     -2,     -2,     -2,     -2,     -2,     -2,     -2,
+      -2,     -2,     -2,     -2,     -2,     -2,     -2,     -2,
+      -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,
+      -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,
+      -6,     -6,     -6,     -6,     -5,     -5,     -5,     -5,
+      -8,     -8,     -8,     -8,     -7,     -7,     -7,     -7,
+      -3,     -3,     -3,     -3,     -3,     -3,     -3,     -3,
+      -4,     -4,     -4,     -4,     -4,     -4,     -4,     -4,
+      21,     20,     23,     22,     17,     16,     19,     18,
+      29,     28,     31,     30,     25,     24,     27,     26,
+      10,     10,     11,     11,      8,      8,      9,      9,
+      14,     14,     15,     15,     12,     12,     13,     13,
+      86,     82,     94,     90,     70,     66,     78,     74,
+     118,    114,    126,    122,    102,     98,    110,    106,
+      43,     41,     47,     45,     35,     33,     39,     37,
+      59,     57,     63,     61,     51,     49,     55,     53,
+       1,      1,      1,      1,      1,      1,      1,      1,
+       1,      1,      1,      1,      1,      1,      1,      1,
+       0,      0,      0,      0,      0,      0,      0,      0,
+       0,      0,      0,      0,      0,      0,      0,      0,
+       5,      5,      5,      5,      4,      4,      4,      4,
+       7,      7,      7,      7,      6,      6,      6,      6,
+       2,      2,      2,      2,      2,      2,      2,      2,
+       3,      3,      3,      3,      3,      3,      3,      3
+};
+
+
+#ifdef HAS_16BIT_TABLES
+
+/* 16 bit mu-law */
+
+static char ulaw2dma16[] = {
+    -32124, -31100, -30076, -29052, -28028, -27004, -25980, -24956,
+    -23932, -22908, -21884, -20860, -19836, -18812, -17788, -16764,
+    -15996, -15484, -14972, -14460, -13948, -13436, -12924, -12412,
+    -11900, -11388, -10876, -10364,  -9852,  -9340,  -8828,  -8316,
+     -7932,  -7676,  -7420,  -7164,  -6908,  -6652,  -6396,  -6140,
+     -5884,  -5628,  -5372,  -5116,  -4860,  -4604,  -4348,  -4092,
+     -3900,  -3772,  -3644,  -3516,  -3388,  -3260,  -3132,  -3004,
+     -2876,  -2748,  -2620,  -2492,  -2364,  -2236,  -2108,  -1980,
+     -1884,  -1820,  -1756,  -1692,  -1628,  -1564,  -1500,  -1436,
+     -1372,  -1308,  -1244,  -1180,  -1116,  -1052,   -988,   -924,
+      -876,   -844,   -812,   -780,   -748,   -716,   -684,   -652,
+      -620,   -588,   -556,   -524,   -492,   -460,   -428,   -396,
+      -372,   -356,   -340,   -324,   -308,   -292,   -276,   -260,
+      -244,   -228,   -212,   -196,   -180,   -164,   -148,   -132,
+      -120,   -112,   -104,    -96,    -88,    -80,    -72,    -64,
+       -56,    -48,    -40,    -32,    -24,    -16,     -8,      0,
+     32124,  31100,  30076,  29052,  28028,  27004,  25980,  24956,
+     23932,  22908,  21884,  20860,  19836,  18812,  17788,  16764,
+     15996,  15484,  14972,  14460,  13948,  13436,  12924,  12412,
+     11900,  11388,  10876,  10364,   9852,   9340,   8828,   8316,
+      7932,   7676,   7420,   7164,   6908,   6652,   6396,   6140,
+      5884,   5628,   5372,   5116,   4860,   4604,   4348,   4092,
+      3900,   3772,   3644,   3516,   3388,   3260,   3132,   3004,
+      2876,   2748,   2620,   2492,   2364,   2236,   2108,   1980,
+      1884,   1820,   1756,   1692,   1628,   1564,   1500,   1436,
+      1372,   1308,   1244,   1180,   1116,   1052,    988,    924,
+       876,    844,    812,    780,    748,    716,    684,    652,
+       620,    588,    556,    524,    492,    460,    428,    396,
+       372,    356,    340,    324,    308,    292,    276,    260,
+       244,    228,    212,    196,    180,    164,    148,    132,
+       120,    112,    104,     96,     88,     80,     72,     64,
+        56,     48,     40,     32,     24,     16,      8,      0,
+};
+
+/* 16 bit A-law */
+
+static char alaw2dma16[] = {
+     -5504,  -5248,  -6016,  -5760,  -4480,  -4224,  -4992,  -4736,
+     -7552,  -7296,  -8064,  -7808,  -6528,  -6272,  -7040,  -6784,
+     -2752,  -2624,  -3008,  -2880,  -2240,  -2112,  -2496,  -2368,
+     -3776,  -3648,  -4032,  -3904,  -3264,  -3136,  -3520,  -3392,
+    -22016, -20992, -24064, -23040, -17920, -16896, -19968, -18944,
+    -30208, -29184, -32256, -31232, -26112, -25088, -28160, -27136,
+    -11008, -10496, -12032, -11520,  -8960,  -8448,  -9984,  -9472,
+    -15104, -14592, -16128, -15616, -13056, -12544, -14080, -13568,
+      -344,   -328,   -376,   -360,   -280,   -264,   -312,   -296,
+      -472,   -456,   -504,   -488,   -408,   -392,   -440,   -424,
+       -88,    -72,   -120,   -104,    -24,     -8,    -56,    -40,
+      -216,   -200,   -248,   -232,   -152,   -136,   -184,   -168,
+     -1376,  -1312,  -1504,  -1440,  -1120,  -1056,  -1248,  -1184,
+     -1888,  -1824,  -2016,  -1952,  -1632,  -1568,  -1760,  -1696,
+      -688,   -656,   -752,   -720,   -560,   -528,   -624,   -592,
+      -944,   -912,  -1008,   -976,   -816,   -784,   -880,   -848,
+      5504,   5248,   6016,   5760,   4480,   4224,   4992,   4736,
+      7552,   7296,   8064,   7808,   6528,   6272,   7040,   6784,
+      2752,   2624,   3008,   2880,   2240,   2112,   2496,   2368,
+      3776,   3648,   4032,   3904,   3264,   3136,   3520,   3392,
+     22016,  20992,  24064,  23040,  17920,  16896,  19968,  18944,
+     30208,  29184,  32256,  31232,  26112,  25088,  28160,  27136,
+     11008,  10496,  12032,  11520,   8960,   8448,   9984,   9472,
+     15104,  14592,  16128,  15616,  13056,  12544,  14080,  13568,
+       344,    328,    376,    360,    280,    264,    312,    296,
+       472,    456,    504,    488,    408,    392,    440,    424,
+        88,     72,    120,    104,     24,      8,     56,     40,
+       216,    200,    248,    232,    152,    136,    184,    168,
+      1376,   1312,   1504,   1440,   1120,   1056,   1248,   1184,
+      1888,   1824,   2016,   1952,   1632,   1568,   1760,   1696,
+       688,    656,    752,    720,    560,    528,    624,    592,
+       944,    912,   1008,    976,    816,    784,    880,    848,
+};
+#endif /* HAS_16BIT_TABLES */
+
+
+#ifdef HAS_14BIT_TABLES
+
+/* 14 bit mu-law (lsb) */
+
+static char alaw2dma14l[] = {
+        33,     33,     33,     33,     33,     33,     33,     33,
+        33,     33,     33,     33,     33,     33,     33,     33,
+        33,     33,     33,     33,     33,     33,     33,     33,
+        33,     33,     33,     33,     33,     33,     33,     33,
+         1,      1,      1,      1,      1,      1,      1,      1,
+         1,      1,      1,      1,      1,      1,      1,      1,
+        49,     17,     49,     17,     49,     17,     49,     17,
+        49,     17,     49,     17,     49,     17,     49,     17,
+        41,     57,      9,     25,     41,     57,      9,     25,
+        41,     57,      9,     25,     41,     57,      9,     25,
+        37,     45,     53,     61,      5,     13,     21,     29,
+        37,     45,     53,     61,      5,     13,     21,     29,
+        35,     39,     43,     47,     51,     55,     59,     63,
+         3,      7,     11,     15,     19,     23,     27,     31,
+        34,     36,     38,     40,     42,     44,     46,     48,
+        50,     52,     54,     56,     58,     60,     62,      0,
+        31,     31,     31,     31,     31,     31,     31,     31,
+        31,     31,     31,     31,     31,     31,     31,     31,
+        31,     31,     31,     31,     31,     31,     31,     31,
+        31,     31,     31,     31,     31,     31,     31,     31,
+        63,     63,     63,     63,     63,     63,     63,     63,
+        63,     63,     63,     63,     63,     63,     63,     63,
+        15,     47,     15,     47,     15,     47,     15,     47,
+        15,     47,     15,     47,     15,     47,     15,     47,
+        23,      7,     55,     39,     23,      7,     55,     39,
+        23,      7,     55,     39,     23,      7,     55,     39,
+        27,     19,     11,      3,     59,     51,     43,     35,
+        27,     19,     11,      3,     59,     51,     43,     35,
+        29,     25,     21,     17,     13,      9,      5,      1,
+        61,     57,     53,     49,     45,     41,     37,     33,
+        30,     28,     26,     24,     22,     20,     18,     16,
+        14,     12,     10,      8,      6,      4,      2,      0
+};
+
+/* 14 bit A-law (lsb) */
+
+static char alaw2dma14l[] = {
+        32,     32,     32,     32,     32,     32,     32,     32,
+        32,     32,     32,     32,     32,     32,     32,     32,
+        16,     48,     16,     48,     16,     48,     16,     48,
+        16,     48,     16,     48,     16,     48,     16,     48,
+         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,
+        42,     46,     34,     38,     58,     62,     50,     54,
+        10,     14,      2,      6,     26,     30,     18,     22,
+        42,     46,     34,     38,     58,     62,     50,     54,
+        10,     14,      2,      6,     26,     30,     18,     22,
+        40,     56,      8,     24,     40,     56,      8,     24,
+        40,     56,      8,     24,     40,     56,      8,     24,
+        20,     28,      4,     12,     52,     60,     36,     44,
+        20,     28,      4,     12,     52,     60,     36,     44,
+        32,     32,     32,     32,     32,     32,     32,     32,
+        32,     32,     32,     32,     32,     32,     32,     32,
+        48,     16,     48,     16,     48,     16,     48,     16,
+        48,     16,     48,     16,     48,     16,     48,     16,
+         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,
+        22,     18,     30,     26,      6,      2,     14,     10,
+        54,     50,     62,     58,     38,     34,     46,     42,
+        22,     18,     30,     26,      6,      2,     14,     10,
+        54,     50,     62,     58,     38,     34,     46,     42,
+        24,      8,     56,     40,     24,      8,     56,     40,
+        24,      8,     56,     40,     24,      8,     56,     40,
+        44,     36,     60,     52,     12,      4,     28,     20,
+        44,     36,     60,     52,     12,      4,     28,     20
+};
+#endif /* HAS_14BIT_TABLES */
+
+
+/*** Translations ************************************************************/
+
+
+#ifdef CONFIG_ATARI
+static long ata_ct_law(const u_char *userPtr, long userCount, u_char frame[],
+		       long *frameUsed, long frameLeft);
+static long ata_ct_s8(const u_char *userPtr, long userCount, u_char frame[],
+		      long *frameUsed, long frameLeft);
+static long ata_ct_u8(const u_char *userPtr, long userCount, u_char frame[],
+		      long *frameUsed, long frameLeft);
+static long ata_ct_s16be(const u_char *userPtr, long userCount, u_char frame[],
+			 long *frameUsed, long frameLeft);
+static long ata_ct_u16be(const u_char *userPtr, long userCount, u_char frame[],
+			 long *frameUsed, long frameLeft);
+static long ata_ct_s16le(const u_char *userPtr, long userCount, u_char frame[],
+			 long *frameUsed, long frameLeft);
+static long ata_ct_u16le(const u_char *userPtr, long userCount, u_char frame[],
+			 long *frameUsed, long frameLeft);
+static long ata_ctx_law(const u_char *userPtr, long userCount, u_char frame[],
+			long *frameUsed, long frameLeft);
+static long ata_ctx_s8(const u_char *userPtr, long userCount, u_char frame[],
+		       long *frameUsed, long frameLeft);
+static long ata_ctx_u8(const u_char *userPtr, long userCount, u_char frame[],
+		        long *frameUsed, long frameLeft);
+static long ata_ctx_s16be(const u_char *userPtr, long userCount, u_char frame[],
+			  long *frameUsed, long frameLeft);
+static long ata_ctx_u16be(const u_char *userPtr, long userCount, u_char frame[],
+			  long *frameUsed, long frameLeft);
+static long ata_ctx_s16le(const u_char *userPtr, long userCount, u_char frame[],
+			  long *frameUsed, long frameLeft);
+static long ata_ctx_u16le(const u_char *userPtr, long userCount, u_char frame[],
+			  long *frameUsed, long frameLeft);
+#endif /* CONFIG_ATARI */
+
+#ifdef CONFIG_AMIGA
+static long ami_ct_law(const u_char *userPtr, long userCount, u_char frame[],
+		       long *frameUsed, long frameLeft);
+static long ami_ct_s8(const u_char *userPtr, long userCount, u_char frame[],
+		      long *frameUsed, long frameLeft);
+static long ami_ct_u8(const u_char *userPtr, long userCount, u_char frame[],
+		      long *frameUsed, long frameLeft);
+static long ami_ct_s16be(const u_char *userPtr, long userCount, u_char frame[],
+			 long *frameUsed, long frameLeft);
+static long ami_ct_u16be(const u_char *userPtr, long userCount, u_char frame[],
+			 long *frameUsed, long frameLeft);
+static long ami_ct_s16le(const u_char *userPtr, long userCount, u_char frame[],
+			 long *frameUsed, long frameLeft);
+static long ami_ct_u16le(const u_char *userPtr, long userCount, u_char frame[],
+			 long *frameUsed, long frameLeft);
+#endif /* CONFIG_AMIGA */
+
+
+/*** Machine definitions *****************************************************/
+
+
+typedef struct {
+    int type;
+    void *(*dma_alloc)(unsigned int, int);
+    void (*dma_free)(void *, unsigned int);
+    int (*irqinit)(void);
+    void (*init)(void);
+    void (*silence)(void);
+    int (*setFormat)(int);
+    int (*setVolume)(int);
+    int (*setBass)(int);
+    int (*setTreble)(int);
+    void (*play)(void);
+} MACHINE;
+
+
+/*** Low level stuff *********************************************************/
+
+
+typedef struct {
+    int format;		/* AFMT_* */
+    int stereo;		/* 0 = mono, 1 = stereo */
+    int size;		/* 8/16 bit*/
+    int speed;		/* speed */
+} SETTINGS;
+
+typedef struct {
+    long (*ct_ulaw)(const u_char *, long, u_char *, long *, long);
+    long (*ct_alaw)(const u_char *, long, u_char *, long *, long);
+    long (*ct_s8)(const u_char *, long, u_char *, long *, long);
+    long (*ct_u8)(const u_char *, long, u_char *, long *, long);
+    long (*ct_s16be)(const u_char *, long, u_char *, long *, long);
+    long (*ct_u16be)(const u_char *, long, u_char *, long *, long);
+    long (*ct_s16le)(const u_char *, long, u_char *, long *, long);
+    long (*ct_u16le)(const u_char *, long, u_char *, long *, long);
+} TRANS;
+
+struct sound_settings {
+    MACHINE mach;	/* machine dependend things */
+    SETTINGS hard;	/* hardware settings */
+    SETTINGS soft;	/* software settings */
+    SETTINGS dsp;	/* /dev/dsp default settings */
+    TRANS *trans;	/* supported translations */
+    int volume_left;	/* volume (range is machine dependent) */
+    int volume_right;
+    int bass;		/* tone (range is machine dependent) */
+    int treble;
+    int minDev;		/* minor device number currently open */
+#ifdef CONFIG_ATARI
+    int bal;		/* balance factor for expanding (not volume!) */
+    u_long data;	/* data for expanding */
+#endif /* CONFIG_ATARI */
+};
+
+static struct sound_settings sound;
+
+
+#ifdef CONFIG_ATARI
+static void *AtaAlloc(unsigned int size, int flags);
+static void AtaFree(void *, unsigned int size);
+static int AtaIrqInit(void);
+static int AtaSetBass(int bass);
+static int AtaSetTreble(int treble);
+static void TTSilence(void);
+static void TTInit(void);
+static int TTSetFormat(int format);
+static int TTSetVolume(int volume);
+static void FalconSilence(void);
+static void FalconInit(void);
+static int FalconSetFormat(int format);
+static int FalconSetVolume(int volume);
+static void ata_sq_play_next_frame(int index);
+static void AtaPlay(void);
+static void ata_sq_interrupt(int irq, struct pt_regs *fp, void *dummy);
+#endif /* CONFIG_ATARI */
+
+#ifdef CONFIG_AMIGA
+static void *AmiAlloc(unsigned int size, int flags);
+static void AmiFree(void *, unsigned int);
+static int AmiIrqInit(void);
+static void AmiSilence(void);
+static void AmiInit(void);
+static int AmiSetFormat(int format);
+static int AmiSetVolume(int volume);
+static int AmiSetTreble(int treble);
+static void ami_sq_play_next_frame(int index);
+static void AmiPlay(void);
+static void ami_sq_interrupt(int irq, struct pt_regs *fp, void *dummy);
+#endif /* CONFIG_AMIGA */
+
+
+/*** Mid level stuff *********************************************************/
+
+
+static void sound_silence(void);
+static void sound_init(void);
+static int sound_set_format(int format);
+static int sound_set_speed(int speed);
+static int sound_set_stereo(int stereo);
+static int sound_set_volume(int volume);
+#ifdef CONFIG_ATARI
+static int sound_set_bass(int bass);
+#endif /* CONFIG_ATARI */
+static int sound_set_treble(int treble);
+static long sound_copy_translate(const u_char *userPtr, long userCount,
+				 u_char frame[], long *frameUsed,
+				 long frameLeft);
+
+
+/*
+ * /dev/mixer abstraction
+ */
+
+struct sound_mixer {
+    int busy;
+};
+
+static struct sound_mixer mixer;
+
+static void mixer_init(void);
+static int mixer_open(int open_mode);
+static int mixer_release(void);
+static int mixer_ioctl(struct inode *inode, struct file *file, u_int cmd,
+		       u_long arg);
+
+
+/*
+ * Sound queue stuff, the heart of the driver
+ */
+
+struct sound_queue {
+    int max_count, block_size;
+    char **buffers;
+
+    /* it shouldn't be necessary to declare any of these volatile */
+    int front, rear, count;
+    int rear_size;
+    /*
+     *	The use of the playing field depends on the hardware
+     *
+     *	Atari: The number of frames that are loaded/playing
+     *
+     *	Amiga: Bit 0 is set: a frame is loaded
+     *	       Bit 1 is set: a frame is playing
+     */
+    int playing;
+    struct wait_queue *write_queue, *open_queue, *sync_queue;
+    int open_mode;
+    int busy, syncing;
+#ifdef CONFIG_ATARI
+    int ignore_int;		/* ++TeSche: used for Falcon */
+#endif /* CONFIG_ATARI */
+#ifdef CONFIG_AMIGA
+    int block_size_half, block_size_quarter;
+#endif /* CONFIG_AMIGA */
+};
+
+static struct sound_queue sq;
+
+#define sq_block_address(i)	(sq.buffers[i])
+#define SIGNAL_RECEIVED	(current->signal & ~current->blocked)
+#define NON_BLOCKING(open_mode)	(open_mode & O_NONBLOCK)
+#define ONE_SECOND	HZ	/* in jiffies (100ths of a second) */
+#define NO_TIME_LIMIT	0xffffffff
+#define SLEEP(queue, time_limit) \
+	current->timeout = jiffies+(time_limit); \
+	interruptible_sleep_on(&queue);
+#define WAKE_UP(queue)	(wake_up_interruptible(&queue))
+
+static void sq_init(int numBufs, int bufSize, char **buffers);
+static void sq_play(void);
+static int sq_write(const char *src, int uLeft);
+static int sq_open(int open_mode);
+static void sq_reset(void);
+static int sq_sync(void);
+static int sq_release(void);
+
+
+/*
+ * /dev/sndstat
+ */
+
+struct sound_state {
+    int busy;
+    char buf[512];
+    int len, ptr;
+};
+
+static struct sound_state state;
+
+static void state_init(void);
+static int state_open(int open_mode);
+static int state_release(void);
+static int state_read(char *dest, int count);
+
+
+/*** High level stuff ********************************************************/
+
+
+static int sound_open(struct inode *inode, struct file *file);
+static int sound_fsync(struct inode *inode, struct file *filp);
+static void sound_release(struct inode *inode, struct file *file);
+static int sound_lseek(struct inode *inode, struct file *file, off_t offset,
+		       int orig);
+static int sound_read(struct inode *inode, struct file *file, char *buf,
+		      int count);
+static int sound_write(struct inode *inode, struct file *file, const char *buf,
+		       int count);
+static int ioctl_return(int *addr, int value);
+static int unknown_minor_dev(char *fname, int dev);
+static int sound_ioctl(struct inode *inode, struct file *file, u_int cmd,
+		       u_long arg);
+
+
+/*** Config & Setup **********************************************************/
+
+
+void soundcard_init(void);
+void dmasound_setup(char *str, int *ints);
+void sound_setup(char *str, int *ints);		/* ++Martin: stub for now */
+
+
+/*** Translations ************************************************************/
+
+
+/* ++TeSche: radically changed for new expanding purposes...
+ *
+ * These two routines now deal with copying/expanding/translating the samples
+ * from user space into our buffer at the right frequency. They take care about
+ * how much data there's actually to read, how much buffer space there is and
+ * to convert samples into the right frequency/encoding. They will only work on
+ * complete samples so it may happen they leave some bytes in the input stream
+ * if the user didn't write a multiple of the current sample size. They both
+ * return the number of bytes they've used from both streams so you may detect
+ * such a situation. Luckily all programs should be able to cope with that.
+ *
+ * I think I've optimized anything as far as one can do in plain C, all
+ * variables should fit in registers and the loops are really short. There's
+ * one loop for every possible situation. Writing a more generalized and thus
+ * parametrized loop would only produce slower code. Feel free to optimize
+ * this in assembler if you like. :)
+ *
+ * I think these routines belong here because they're not yet really hardware
+ * independend, especially the fact that the Falcon can play 16bit samples
+ * only in stereo is hardcoded in both of them!
+ *
+ * ++geert: split in even more functions (one per format)
+ */
+
+#ifdef CONFIG_ATARI
+static long ata_ct_law(const u_char *userPtr, long userCount, u_char frame[],
+		       long *frameUsed, long frameLeft)
+{
+    char *table = sound.soft.format == AFMT_MU_LAW ? ulaw2dma8 : alaw2dma8;
+    long count, used;
+    u_char *p = &frame[*frameUsed];
+
+    count = min(userCount, frameLeft);
+    if (sound.soft.stereo)
+	count &= ~1;
+    used = count;
+    while (count > 0) {
+	*p++ = table[get_user(userPtr++)];
+	count--;
+    }
+    *frameUsed += used;
+    return(used);
+}
+
+
+static long ata_ct_s8(const u_char *userPtr, long userCount, u_char frame[],
+		      long *frameUsed, long frameLeft)
+{
+    long count, used;
+    void *p = &frame[*frameUsed];
+
+    count = min(userCount, frameLeft);
+    if (sound.soft.stereo)
+	count &= ~1;
+    used = count;
+    memcpy_fromfs(p, userPtr, count);
+    *frameUsed += used;
+    return(used);
+}
+
+
+static long ata_ct_u8(const u_char *userPtr, long userCount, u_char frame[],
+		      long *frameUsed, long frameLeft)
+{
+    long count, used;
+
+    if (!sound.soft.stereo) {
+	u_char *p = &frame[*frameUsed];
+	count = min(userCount, frameLeft);
+	used = count;
+	while (count > 0) {
+	    *p++ = get_user(userPtr++) ^ 0x80;
+	    count--;
+	}
+    } else {
+	u_short *p = (u_short *)&frame[*frameUsed];
+	count = min(userCount, frameLeft)>>1;
+	used = count*2;
+	while (count > 0) {
+	    *p++ = get_user(((u_short *)userPtr)++) ^ 0x8080;
+	    count--;
+	}
+    }
+    *frameUsed += used;
+    return(used);
+}
+
+
+static long ata_ct_s16be(const u_char *userPtr, long userCount, u_char frame[],
+			 long *frameUsed, long frameLeft)
+{
+    long count, used;
+    u_long data;
+
+    if (!sound.soft.stereo) {
+	u_short *p = (u_short *)&frame[*frameUsed];
+	count = min(userCount, frameLeft)>>1;
+	used = count*2;
+	while (count > 0) {
+	    data = get_user(((u_short *)userPtr)++);
+	    *p++ = data;
+	    *p++ = data;
+	    count--;
+	}
+	*frameUsed += used*2;
+    } else {
+	void *p = (u_short *)&frame[*frameUsed];
+	count = min(userCount, frameLeft) & ~3;
+	used = count;
+	memcpy_fromfs(p, userPtr, count);
+	*frameUsed += used;
+    }
+    return(used);
+}
+
+
+static long ata_ct_u16be(const u_char *userPtr, long userCount, u_char frame[],
+			 long *frameUsed, long frameLeft)
+{
+    long count, used;
+    u_long data;
+
+    if (!sound.soft.stereo) {
+	u_short *p = (u_short *)&frame[*frameUsed];
+	count = min(userCount, frameLeft)>>1;
+	used = count*2;
+	while (count > 0) {
+	    data = get_user(((u_short *)userPtr)++) ^ 0x8000;
+	    *p++ = data;
+	    *p++ = data;
+	    count--;
+	}
+	*frameUsed += used*2;
+    } else {
+	u_long *p = (u_long *)&frame[*frameUsed];
+	count = min(userCount, frameLeft)>>2;
+	used = count*4;
+	while (count > 0) {
+	    *p++ = get_user(((u_int *)userPtr)++) ^ 0x80008000;
+	    count--;
+	}
+	*frameUsed += used;
+    }
+    return(used);
+}
+
+
+static long ata_ct_s16le(const u_char *userPtr, long userCount, u_char frame[],
+			 long *frameUsed, long frameLeft)
+{
+    long count, used;
+    u_long data;
+
+    count = frameLeft;
+    if (!sound.soft.stereo) {
+	u_short *p = (u_short *)&frame[*frameUsed];
+	count = min(userCount, frameLeft)>>1;
+	used = count*2;
+	while (count > 0) {
+	    data = get_user(((u_short *)userPtr)++);
+	    data = le2be16(data);
+	    *p++ = data;
+	    *p++ = data;
+	    count--;
+	}
+	*frameUsed += used*2;
+    } else {
+	u_long *p = (u_long *)&frame[*frameUsed];
+	count = min(userCount, frameLeft)>>2;
+	used = count*4;
+	while (count > 0) {
+	    data = get_user(((u_int *)userPtr)++);
+	    data = le2be16dbl(data);
+	    *p++ = data;
+	    count--;
+	}
+	*frameUsed += used;
+    }
+    return(used);
+}
+
+
+static long ata_ct_u16le(const u_char *userPtr, long userCount, u_char frame[],
+			 long *frameUsed, long frameLeft)
+{
+    long count, used;
+    u_long data;
+
+    count = frameLeft;
+    if (!sound.soft.stereo) {
+	u_short *p = (u_short *)&frame[*frameUsed];
+	count = min(userCount, frameLeft)>>1;
+	used = count*2;
+	while (count > 0) {
+	    data = get_user(((u_short *)userPtr)++);
+	    data = le2be16(data) ^ 0x8000;
+	    *p++ = data;
+	    *p++ = data;
+	}
+	*frameUsed += used*2;
+    } else {
+	u_long *p = (u_long *)&frame[*frameUsed];
+	count = min(userCount, frameLeft)>>2;
+	used = count;
+	while (count > 0) {
+	    data = get_user(((u_int *)userPtr)++);
+	    data = le2be16dbl(data) ^ 0x80008000;
+	    *p++ = data;
+	    count--;
+	}
+	*frameUsed += used;
+    }
+    return(used);
+}
+
+
+static long ata_ctx_law(const u_char *userPtr, long userCount, u_char frame[],
+			long *frameUsed, long frameLeft)
+{
+    char *table = sound.soft.format == AFMT_MU_LAW ? ulaw2dma8 : alaw2dma8;
+    /* this should help gcc to stuff everything into registers */
+    u_long data = sound.data;
+    long bal = sound.bal;
+    long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
+    long used, usedf;
+
+    used = userCount;
+    usedf = frameLeft;
+    if (!sound.soft.stereo) {
+	u_char *p = &frame[*frameUsed];
+	while (frameLeft) {
+	    if (bal < 0) {
+		if (!userCount)
+		    break;
+		data = table[get_user(userPtr++)];
+		userCount--;
+		bal += hSpeed;
+	    }
+	    *p++ = data;
+	    frameLeft--;
+	    bal -= sSpeed;
+	}
+    } else {
+	u_short *p = (u_short *)&frame[*frameUsed];
+	while (frameLeft >= 2) {
+	    if (bal < 0) {
+		if (userCount < 2)
+		    break;
+		data = table[get_user(userPtr++)] << 8;
+		data |= table[get_user(userPtr++)];
+		userCount -= 2;
+		bal += hSpeed;
+	    }
+	    *p++ = data;
+	    frameLeft -= 2;
+	    bal -= sSpeed;
+	}
+    }
+    sound.bal = bal;
+    sound.data = data;
+    used -= userCount;
+    *frameUsed += usedf-frameLeft;
+    return(used);
+}
+
+
+static long ata_ctx_s8(const u_char *userPtr, long userCount, u_char frame[],
+		       long *frameUsed, long frameLeft)
+{
+    /* this should help gcc to stuff everything into registers */
+    u_long data = sound.data;
+    long bal = sound.bal;
+    long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
+    long used, usedf;
+
+    used = userCount;
+    usedf = frameLeft;
+    if (!sound.soft.stereo) {
+	u_char *p = &frame[*frameUsed];
+	while (frameLeft) {
+	    if (bal < 0) {
+		if (!userCount)
+		    break;
+		data = get_user(userPtr++);
+		userCount--;
+		bal += hSpeed;
+	    }
+	    *p++ = data;
+	    frameLeft--;
+	    bal -= sSpeed;
+	}
+    } else {
+	u_short *p = (u_short *)&frame[*frameUsed];
+	while (frameLeft >= 2) {
+	    if (bal < 0) {
+		if (userCount < 2)
+		    break;
+		data = get_user(((u_short *)userPtr)++);
+		userCount -= 2;
+		bal += hSpeed;
+	    }
+	    *p++ = data;
+	    frameLeft -= 2;
+	    bal -= sSpeed;
+	}
+    }
+    sound.bal = bal;
+    sound.data = data;
+    used -= userCount;
+    *frameUsed += usedf-frameLeft;
+    return(used);
+}
+
+
+static long ata_ctx_u8(const u_char *userPtr, long userCount, u_char frame[],
+		       long *frameUsed, long frameLeft)
+{
+    /* this should help gcc to stuff everything into registers */
+    u_long data = sound.data;
+    long bal = sound.bal;
+    long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
+    long used, usedf;
+
+    used = userCount;
+    usedf = frameLeft;
+    if (!sound.soft.stereo) {
+	u_char *p = &frame[*frameUsed];
+	while (frameLeft) {
+	    if (bal < 0) {
+		if (!userCount)
+		    break;
+		data = get_user(userPtr++) ^ 0x80;
+		userCount--;
+		bal += hSpeed;
+	    }
+	    *p++ = data;
+	    frameLeft--;
+	    bal -= sSpeed;
+	}
+    } else {
+	u_short *p = (u_short *)&frame[*frameUsed];
+	while (frameLeft >= 2) {
+	    if (bal < 0) {
+		if (userCount < 2)
+		    break;
+		data = get_user(((u_short *)userPtr)++) ^ 0x8080;
+		userCount -= 2;
+		bal += hSpeed;
+	    }
+	    *p++ = data;
+	    frameLeft -= 2;
+	    bal -= sSpeed;
+	}
+    }
+    sound.bal = bal;
+    sound.data = data;
+    used -= userCount;
+    *frameUsed += usedf-frameLeft;
+    return(used);
+}
+
+
+static long ata_ctx_s16be(const u_char *userPtr, long userCount, u_char frame[],
+			  long *frameUsed, long frameLeft)
+{
+    /* this should help gcc to stuff everything into registers */
+    u_long data = sound.data;
+    long bal = sound.bal;
+    long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
+    long used, usedf;
+
+    used = userCount;
+    usedf = frameLeft;
+    if (!sound.soft.stereo) {
+	u_short *p = (u_short *)&frame[*frameUsed];
+	while (frameLeft >= 4) {
+	    if (bal < 0) {
+		if (userCount < 2)
+		    break;
+		data = get_user(((u_short *)userPtr)++);
+		userCount -= 2;
+		bal += hSpeed;
+	    }
+	    *p++ = data;
+	    *p++ = data;
+	    frameLeft -= 4;
+	    bal -= sSpeed;
+	}
+    } else {
+	u_long *p = (u_long *)&frame[*frameUsed];
+	while (frameLeft >= 4) {
+	    if (bal < 0) {
+		if (userCount < 4)
+		    break;
+		data = get_user(((u_int *)userPtr)++);
+		userCount -= 4;
+		bal += hSpeed;
+	    }
+	    *p++ = data;
+	    frameLeft -= 4;
+	    bal -= sSpeed;
+	}
+    }
+    sound.bal = bal;
+    sound.data = data;
+    used -= userCount;
+    *frameUsed += usedf-frameLeft;
+    return(used);
+}
+
+
+static long ata_ctx_u16be(const u_char *userPtr, long userCount, u_char frame[],
+			  long *frameUsed, long frameLeft)
+{
+    /* this should help gcc to stuff everything into registers */
+    u_long data = sound.data;
+    long bal = sound.bal;
+    long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
+    long used, usedf;
+
+    used = userCount;
+    usedf = frameLeft;
+    if (!sound.soft.stereo) {
+	u_short *p = (u_short *)&frame[*frameUsed];
+	while (frameLeft >= 4) {
+	    if (bal < 0) {
+		if (userCount < 2)
+		    break;
+		data = get_user(((u_short *)userPtr)++) ^ 0x8000;
+		userCount -= 2;
+		bal += hSpeed;
+	    }
+	    *p++ = data;
+	    *p++ = data;
+	    frameLeft -= 4;
+	    bal -= sSpeed;
+	}
+    } else {
+	u_long *p = (u_long *)&frame[*frameUsed];
+	while (frameLeft >= 4) {
+	    if (bal < 0) {
+		if (userCount < 4)
+		    break;
+		data = get_user(((u_int *)userPtr)++) ^ 0x80008000;
+		userCount -= 4;
+		bal += hSpeed;
+	    }
+	    *p++ = data;
+	    frameLeft -= 4;
+	    bal -= sSpeed;
+	}
+    }
+    sound.bal = bal;
+    sound.data = data;
+    used -= userCount;
+    *frameUsed += usedf-frameLeft;
+    return(used);
+}
+
+
+static long ata_ctx_s16le(const u_char *userPtr, long userCount, u_char frame[],
+			  long *frameUsed, long frameLeft)
+{
+    /* this should help gcc to stuff everything into registers */
+    u_long data = sound.data;
+    long bal = sound.bal;
+    long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
+    long used, usedf;
+
+    used = userCount;
+    usedf = frameLeft;
+    if (!sound.soft.stereo) {
+	u_short *p = (u_short *)&frame[*frameUsed];
+	while (frameLeft >= 4) {
+	    if (bal < 0) {
+		if (userCount < 2)
+		    break;
+		data = get_user(((u_short *)userPtr)++);
+		data = le2be16(data);
+		userCount -= 2;
+		bal += hSpeed;
+	    }
+	    *p++ = data;
+	    *p++ = data;
+	    frameLeft -= 4;
+	    bal -= sSpeed;
+	}
+    } else {
+	u_long *p = (u_long *)&frame[*frameUsed];
+	while (frameLeft >= 4) {
+	    if (bal < 0) {
+		if (userCount < 4)
+		    break;
+		data = get_user(((u_int *)userPtr)++);
+		data = le2be16dbl(data);
+		userCount -= 4;
+		bal += hSpeed;
+	    }
+	    *p++ = data;
+	    frameLeft -= 4;
+	    bal -= sSpeed;
+	}
+    }
+    sound.bal = bal;
+    sound.data = data;
+    used -= userCount;
+    *frameUsed += usedf-frameLeft;
+    return(used);
+}
+
+
+static long ata_ctx_u16le(const u_char *userPtr, long userCount, u_char frame[],
+			  long *frameUsed, long frameLeft)
+{
+    /* this should help gcc to stuff everything into registers */
+    u_long data = sound.data;
+    long bal = sound.bal;
+    long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
+    long used, usedf;
+
+    used = userCount;
+    usedf = frameLeft;
+    if (!sound.soft.stereo) {
+	u_short *p = (u_short *)&frame[*frameUsed];
+	while (frameLeft >= 4) {
+	    if (bal < 0) {
+		if (userCount < 2)
+		    break;
+		data = get_user(((u_short *)userPtr)++);
+		data = le2be16(data) ^ 0x8000;
+		userCount -= 2;
+		bal += hSpeed;
+	    }
+	    *p++ = data;
+	    *p++ = data;
+	    frameLeft -= 4;
+	    bal -= sSpeed;
+	}
+    } else {
+	u_long *p = (u_long *)&frame[*frameUsed];
+	while (frameLeft >= 4) {
+	    if (bal < 0) {
+		if (userCount < 4)
+		    break;
+		data = get_user(((u_int *)userPtr)++);
+		data = le2be16dbl(data) ^ 0x80008000;
+		userCount -= 4;
+		bal += hSpeed;
+	    }
+	    *p++ = data;
+	    frameLeft -= 4;
+	    bal -= sSpeed;
+	}
+    }
+    sound.bal = bal;
+    sound.data = data;
+    used -= userCount;
+    *frameUsed += usedf-frameLeft;
+    return(used);
+}
+#endif /* CONFIG_ATARI */
+
+
+#ifdef CONFIG_AMIGA
+static long ami_ct_law(const u_char *userPtr, long userCount, u_char frame[],
+		       long *frameUsed, long frameLeft)
+{
+    char *table = sound.soft.format == AFMT_MU_LAW ? ulaw2dma8 : alaw2dma8;
+    long count, used;
+
+    if (!sound.soft.stereo) {
+	u_char *p = &frame[*frameUsed];
+	count = min(userCount, frameLeft) & ~1;
+	used = count;
+	while (count > 0) {
+	    *p++ = table[get_user(userPtr++)];
+	    count--;
+	}
+    } else {
+	u_char *left = &frame[*frameUsed>>1];
+	u_char *right = left+sq.block_size_half;
+	count = min(userCount, frameLeft)>>1 & ~1;
+	used = count*2;
+	while (count > 0) {
+	    *left++ = table[get_user(userPtr++)];
+	    *right++ = table[get_user(userPtr++)];
+	    count--;
+	}
+    }
+    *frameUsed += used;
+    return(used);
+}
+
+
+static long ami_ct_s8(const u_char *userPtr, long userCount, u_char frame[],
+		      long *frameUsed, long frameLeft)
+{
+    long count, used;
+
+    if (!sound.soft.stereo) {
+	void *p = &frame[*frameUsed];
+	count = min(userCount, frameLeft) & ~1;
+	used = count;
+	memcpy_fromfs(p, userPtr, count);
+    } else {
+	u_char *left = &frame[*frameUsed>>1];
+	u_char *right = left+sq.block_size_half;
+	count = min(userCount, frameLeft)>>1 & ~1;
+	used = count*2;
+	while (count > 0) {
+	    *left++ = get_user(userPtr++);
+	    *right++ = get_user(userPtr++);
+	    count--;
+	}
+    }
+    *frameUsed += used;
+    return(used);
+}
+
+
+static long ami_ct_u8(const u_char *userPtr, long userCount, u_char frame[],
+		      long *frameUsed, long frameLeft)
+{
+    long count, used;
+
+    if (!sound.soft.stereo) {
+	char *p = &frame[*frameUsed];
+	count = min(userCount, frameLeft) & ~1;
+	used = count;
+	while (count > 0) {
+	    *p++ = get_user(userPtr++) ^ 0x80;
+	    count--;
+	}
+    } else {
+	u_char *left = &frame[*frameUsed>>1];
+	u_char *right = left+sq.block_size_half;
+	count = min(userCount, frameLeft)>>1 & ~1;
+	used = count*2;
+	while (count > 0) {
+	    *left++ = get_user(userPtr++) ^ 0x80;
+	    *right++ = get_user(userPtr++) ^ 0x80;
+	    count--;
+	}
+    }
+    *frameUsed += used;
+    return(used);
+}
+
+
+static long ami_ct_s16be(const u_char *userPtr, long userCount, u_char frame[],
+			 long *frameUsed, long frameLeft)
+{
+    long count, used;
+    u_long data;
+
+    if (!sound.soft.stereo) {
+	u_char *high = &frame[*frameUsed>>1];
+	u_char *low = high+sq.block_size_half;
+	count = min(userCount, frameLeft)>>1 & ~1;
+	used = count*2;
+	while (count > 0) {
+	    data = get_user(((u_short *)userPtr)++);
+	    *high = data>>8;
+	    *low = (data>>2) & 0x3f;
+	    count--;
+	}
+    } else {
+	u_char *lefth = &frame[*frameUsed>>2];
+	u_char *leftl = lefth+sq.block_size_quarter;
+	u_char *righth = lefth+sq.block_size_half;
+	u_char *rightl = righth+sq.block_size_quarter;
+	count = min(userCount, frameLeft)>>2 & ~1;
+	used = count*4;
+	while (count > 0) {
+	    data = get_user(((u_short *)userPtr)++);
+	    *lefth = data>>8;
+	    *leftl = (data>>2) & 0x3f;
+	    data = get_user(((u_short *)userPtr)++);
+	    *righth = data>>8;
+	    *rightl = (data>>2) & 0x3f;
+	    count--;
+	}
+    }
+    *frameUsed += used;
+    return(used);
+}
+
+
+static long ami_ct_u16be(const u_char *userPtr, long userCount, u_char frame[],
+			 long *frameUsed, long frameLeft)
+{
+    long count, used;
+    u_long data;
+
+    if (!sound.soft.stereo) {
+	u_char *high = &frame[*frameUsed>>1];
+	u_char *low = high+sq.block_size_half;
+	count = min(userCount, frameLeft)>>1 & ~1;
+	used = count*2;
+	while (count > 0) {
+	    data = get_user(((u_short *)userPtr)++) ^ 0x8000;
+	    *high = data>>8;
+	    *low = (data>>2) & 0x3f;
+	    count--;
+	}
+    } else {
+	u_char *lefth = &frame[*frameUsed>>2];
+	u_char *leftl = lefth+sq.block_size_quarter;
+	u_char *righth = lefth+sq.block_size_half;
+	u_char *rightl = righth+sq.block_size_quarter;
+	count = min(userCount, frameLeft)>>2 & ~1;
+	used = count*4;
+	while (count > 0) {
+	    data = get_user(((u_short *)userPtr)++) ^ 0x8000;
+	    *lefth = data>>8;
+	    *leftl = (data>>2) & 0x3f;
+	    data = get_user(((u_short *)userPtr)++) ^ 0x8000;
+	    *righth = data>>8;
+	    *rightl = (data>>2) & 0x3f;
+	    count--;
+	}
+    }
+    *frameUsed += used;
+    return(used);
+}
+
+
+static long ami_ct_s16le(const u_char *userPtr, long userCount, u_char frame[],
+			 long *frameUsed, long frameLeft)
+{
+    long count, used;
+    u_long data;
+
+    if (!sound.soft.stereo) {
+	u_char *high = &frame[*frameUsed>>1];
+	u_char *low = high+sq.block_size_half;
+	count = min(userCount, frameLeft)>>1 & ~1;
+	used = count*2;
+	while (count > 0) {
+	    data = get_user(((u_short *)userPtr)++);
+	    data = le2be16(data);
+	    *high = data>>8;
+	    *low = (data>>2) & 0x3f;
+	    count--;
+	}
+    } else {
+	u_char *lefth = &frame[*frameUsed>>2];
+	u_char *leftl = lefth+sq.block_size_quarter;
+	u_char *righth = lefth+sq.block_size_half;
+	u_char *rightl = righth+sq.block_size_quarter;
+	count = min(userCount, frameLeft)>>2 & ~1;
+	used = count*4;
+	while (count > 0) {
+	    data = get_user(((u_short *)userPtr)++);
+	    data = le2be16(data);
+	    *lefth = data>>8;
+	    *leftl = (data>>2) & 0x3f;
+	    data = get_user(((u_short *)userPtr)++);
+	    data = le2be16(data);
+	    *righth = data>>8;
+	    *rightl = (data>>2) & 0x3f;
+	    count--;
+	}
+    }
+    *frameUsed += used;
+    return(used);
+}
+
+
+static long ami_ct_u16le(const u_char *userPtr, long userCount, u_char frame[],
+			 long *frameUsed, long frameLeft)
+{
+    long count, used;
+    u_long data;
+
+    if (!sound.soft.stereo) {
+	u_char *high = &frame[*frameUsed>>1];
+	u_char *low = high+sq.block_size_half;
+	count = min(userCount, frameLeft)>>1 & ~1;
+	used = count*2;
+	while (count > 0) {
+	    data = get_user(((u_short *)userPtr)++);
+	    data = le2be16(data) ^ 0x8000;
+	    *high = data>>8;
+	    *low = (data>>2) & 0x3f;
+	    count--;
+	}
+    } else {
+	u_char *lefth = &frame[*frameUsed>>2];
+	u_char *leftl = lefth+sq.block_size_quarter;
+	u_char *righth = lefth+sq.block_size_half;
+	u_char *rightl = righth+sq.block_size_quarter;
+	count = min(userCount, frameLeft)>>2 & ~1;
+	used = count*4;
+	while (count > 0) {
+	    data = get_user(((u_short *)userPtr)++);
+	    data = le2be16(data) ^ 0x8000;
+	    *lefth = data>>8;
+	    *leftl = (data>>2) & 0x3f;
+	    data = get_user(((u_short *)userPtr)++);
+	    data = le2be16(data) ^ 0x8000;
+	    *righth = data>>8;
+	    *rightl = (data>>2) & 0x3f;
+	    count--;
+	}
+    }
+    *frameUsed += used;
+    return(used);
+}
+#endif /* CONFIG_AMIGA */
+
+
+#ifdef CONFIG_ATARI
+static TRANS transTTNormal = {
+    ata_ct_law, ata_ct_law, ata_ct_s8, ata_ct_u8, NULL, NULL, NULL, NULL
+};
+
+static TRANS transTTExpanding = {
+    ata_ctx_law, ata_ctx_law, ata_ctx_s8, ata_ctx_u8, NULL, NULL, NULL, NULL
+};
+
+static TRANS transFalconNormal = {
+    ata_ct_law, ata_ct_law, ata_ct_s8, ata_ct_u8, ata_ct_s16be, ata_ct_u16be,
+    ata_ct_s16le, ata_ct_u16le
+};
+
+static TRANS transFalconExpanding = {
+    ata_ctx_law, ata_ctx_law, ata_ctx_s8, ata_ctx_u8, ata_ctx_s16be,
+    ata_ctx_u16be, ata_ctx_s16le, ata_ctx_u16le
+};
+#endif /* CONFIG_ATARI */
+
+#ifdef CONFIG_AMIGA
+static TRANS transAmiga = {
+    ami_ct_law, ami_ct_law, ami_ct_s8, ami_ct_u8, ami_ct_s16be, ami_ct_u16be,
+    ami_ct_s16le, ami_ct_u16le
+};
+#endif /* CONFIG_AMIGA */
+
+
+/*** Low level stuff *********************************************************/
+
+
+#ifdef CONFIG_ATARI
+
+/*
+ * Atari (TT/Falcon)
+ */
+
+static void *AtaAlloc(unsigned int size, int flags)
+{
+    int order;
+    unsigned int a_size;
+    order = 0;
+    a_size = PAGE_SIZE;
+    while (a_size < size) {
+	order++;
+	a_size <<= 1;
+    }
+    return (void *) __get_dma_pages(flags, order);
+}
+
+static void AtaFree(void *obj, unsigned int size)
+{
+    int order;
+    unsigned int a_size;
+    order = 0;
+    a_size = PAGE_SIZE;
+    while (a_size < size) {
+	order++;
+	a_size <<= 1;
+    }
+    free_pages (obj, order);
+}
+
+static int AtaIrqInit(void)
+{
+    /* Set up timer A. Timer A
+    will receive a signal upon end of playing from the sound
+    hardware. Furthermore Timer A is able to count events
+    and will cause an interrupt after a programmed number
+    of events. So all we need to keep the music playing is
+    to provide the sound hardware with new data upon
+    an interrupt from timer A. */
+    mfp.tim_ct_a = 0;		/* ++roman: Stop timer before programming! */
+    mfp.tim_dt_a = 1;		/* Cause interrupt after first event. */
+    mfp.tim_ct_a = 8;		/* Turn on event counting. */
+    /* Register interrupt handler. */
+    add_isr(IRQ_MFP_TIMA, ata_sq_interrupt, IRQ_TYPE_SLOW, NULL, "DMA sound");
+    mfp.int_en_a |= 0x20;	/* Turn interrupt on. */
+    mfp.int_mk_a |= 0x20;
+    return(1);
+}
+
+
+#define TONE_VOXWARE_TO_DB(v) \
+	(((v) < 0) ? -12 : ((v) > 100) ? 12 : ((v) - 50) * 6 / 25)
+#define TONE_DB_TO_VOXWARE(v) (((v) * 25 + ((v) > 0 ? 5 : -5)) / 6 + 50)
+
+
+static int AtaSetBass(int bass)
+{
+    sound.bass = TONE_VOXWARE_TO_DB(bass);
+    atari_microwire_cmd(MW_LM1992_BASS(sound.bass));
+    return(TONE_DB_TO_VOXWARE(sound.bass));
+}
+
+
+static int AtaSetTreble(int treble)
+{
+    sound.treble = TONE_VOXWARE_TO_DB(treble);
+    atari_microwire_cmd(MW_LM1992_TREBLE(sound.treble));
+    return(TONE_DB_TO_VOXWARE(sound.treble));
+}
+
+
+
+/*
+ * TT
+ */
+
+
+static void TTSilence(void)
+{
+    tt_dmasnd.ctrl = DMASND_CTRL_OFF;
+    atari_microwire_cmd(MW_LM1992_PSG_HIGH); /* mix in PSG signal 1:1 */
+}
+
+
+static void TTInit(void)
+{
+    int mode, i, idx;
+    const int freq[4] = {50066, 25033, 12517, 6258};
+
+    /* search a frequency that fits into the allowed error range */
+
+    idx = -1;
+    for (i = 0; i < arraysize(freq); i++)
+	/* this isn't as much useful for a TT than for a Falcon, but
+	 * then it doesn't hurt very much to implement it for a TT too.
+	 */
+	if ((100 * abs(sound.soft.speed - freq[i]) / freq[i]) < catchRadius)
+	    idx = i;
+    if (idx > -1) {
+	sound.soft.speed = freq[idx];
+	sound.trans = &transTTNormal;
+    } else
+	sound.trans = &transTTExpanding;
+
+    TTSilence();
+    sound.hard = sound.soft;
+
+    if (sound.hard.speed > 50066) {
+	/* we would need to squeeze the sound, but we won't do that */
+	sound.hard.speed = 50066;
+	mode = DMASND_MODE_50KHZ;
+	sound.trans = &transTTNormal;
+    } else if (sound.hard.speed > 25033) {
+	sound.hard.speed = 50066;
+	mode = DMASND_MODE_50KHZ;
+    } else if (sound.hard.speed > 12517) {
+	sound.hard.speed = 25033;
+	mode = DMASND_MODE_25KHZ;
+    } else if (sound.hard.speed > 6258) {
+	sound.hard.speed = 12517;
+	mode = DMASND_MODE_12KHZ;
+    } else {
+	sound.hard.speed = 6258;
+	mode = DMASND_MODE_6KHZ;
+    }
+
+    tt_dmasnd.mode = (sound.hard.stereo ?
+		      DMASND_MODE_STEREO : DMASND_MODE_MONO) |
+		     DMASND_MODE_8BIT | mode;
+
+    sound.bal = -sound.soft.speed;
+}
+
+
+static int TTSetFormat(int format)
+{
+    /* TT sound DMA supports only 8bit modes */
+
+    switch (format) {
+	case AFMT_QUERY:
+	    return(sound.soft.format);
+	case AFMT_MU_LAW:
+	case AFMT_A_LAW:
+	case AFMT_S8:
+	case AFMT_U8:
+	    break;
+	default:
+	    format = AFMT_S8;
+    }
+
+    sound.soft.format = format;
+    sound.soft.size = 8;
+    if (sound.minDev == SND_DEV_DSP) {
+	sound.dsp.format = format;
+	sound.dsp.size = 8;
+    }
+    TTInit();
+
+    return(format);
+}
+
+
+#define VOLUME_VOXWARE_TO_DB(v) \
+	(((v) < 0) ? -40 : ((v) > 100) ? 0 : ((v) * 2) / 5 - 40)
+#define VOLUME_DB_TO_VOXWARE(v) ((((v) + 40) * 5 + 1) / 2)
+
+
+static int TTSetVolume(int volume)
+{
+    sound.volume_left = VOLUME_VOXWARE_TO_DB(volume & 0xff);
+    atari_microwire_cmd(MW_LM1992_BALLEFT(sound.volume_left));
+    sound.volume_right = VOLUME_VOXWARE_TO_DB((volume & 0xff00) >> 8);
+    atari_microwire_cmd(MW_LM1992_BALRIGHT(sound.volume_right));
+    return(VOLUME_DB_TO_VOXWARE(sound.volume_left) |
+	   (VOLUME_DB_TO_VOXWARE(sound.volume_right) << 8));
+}
+
+
+
+/*
+ * Falcon
+ */
+
+
+static void FalconSilence(void)
+{
+    /* stop playback, set sample rate 50kHz for PSG sound */
+    tt_dmasnd.ctrl = DMASND_CTRL_OFF;
+    tt_dmasnd.mode = DMASND_MODE_50KHZ | DMASND_MODE_STEREO | DMASND_MODE_8BIT;
+    tt_dmasnd.int_div = 0; /* STE compatible divider */
+    tt_dmasnd.int_ctrl = 0x0;
+    tt_dmasnd.cbar_src = 0x0000; /* no matrix inputs */
+    tt_dmasnd.cbar_dst = 0x0000; /* no matrix outputs */
+    tt_dmasnd.dac_src = 1; /* connect ADC to DAC, disconnect matrix */
+    tt_dmasnd.adc_src = 3; /* ADC Input = PSG */
+}
+
+
+static void FalconInit(void)
+{
+    int divider, i, idx;
+    const int freq[8] = {49170, 32780, 24585, 19668, 16390, 12292, 9834, 8195};
+
+    /* search a frequency that fits into the allowed error range */
+
+    idx = -1;
+    for (i = 0; i < arraysize(freq); i++)
+	/* if we will tolerate 3% error 8000Hz->8195Hz (2.38%) would
+	 * be playable without expanding, but that now a kernel runtime
+	 * option
+	 */
+	if ((100 * abs(sound.soft.speed - freq[i]) / freq[i]) < catchRadius)
+	    idx = i;
+    if (idx > -1) {
+	sound.soft.speed = freq[idx];
+	sound.trans = &transFalconNormal;
+    } else
+	sound.trans = &transFalconExpanding;
+
+    FalconSilence();
+    sound.hard = sound.soft;
+
+    if (sound.hard.size == 16) {
+	/* the Falcon can play 16bit samples only in stereo */
+	sound.hard.stereo = 1;
+    }
+
+    if (sound.hard.speed > 49170) {
+	/* we would need to squeeze the sound, but we won't do that */
+	sound.hard.speed = 49170;
+	divider = 1;
+	sound.trans = &transFalconNormal;
+    } else if (sound.hard.speed > 32780) {
+	sound.hard.speed = 49170;
+	divider = 1;
+    } else if (sound.hard.speed > 24585) {
+	sound.hard.speed = 32780;
+	divider = 2;
+    } else if (sound.hard.speed > 19668) {
+	sound.hard.speed = 24585;
+	divider = 3;
+    } else if (sound.hard.speed > 16390) {
+	sound.hard.speed = 19668;
+	divider = 4;
+    } else if (sound.hard.speed > 12292) {
+	sound.hard.speed = 16390;
+	divider = 5;
+    } else if (sound.hard.speed > 9834) {
+	sound.hard.speed = 12292;
+	divider = 7;
+    } else if (sound.hard.speed > 8195) {
+	sound.hard.speed = 9834;
+	divider = 9;
+    } else {
+	sound.hard.speed = 8195;
+	divider = 11;
+    }
+    tt_dmasnd.int_div = divider;
+
+    /* Setup Falcon sound DMA for playback */
+    tt_dmasnd.int_ctrl = 0x4; /* Timer A int at play end */
+    tt_dmasnd.track_select = 0x0; /* play 1 track, track 1 */
+    tt_dmasnd.cbar_src = 0x0001; /* DMA(25MHz) --> DAC */
+    tt_dmasnd.cbar_dst = 0x0000;
+    tt_dmasnd.rec_track_select = 0;
+    tt_dmasnd.dac_src = 2; /* connect matrix to DAC */
+    tt_dmasnd.adc_src = 0; /* ADC Input = Mic */
+
+    tt_dmasnd.mode = (sound.hard.stereo ?
+		      DMASND_MODE_STEREO : DMASND_MODE_MONO) |
+		     ((sound.hard.size == 8) ?
+		       DMASND_MODE_8BIT : DMASND_MODE_16BIT) |
+		     DMASND_MODE_6KHZ;
+
+    sound.bal = -sound.soft.speed;
+}
+
+
+static int FalconSetFormat(int format)
+{
+    int size;
+    /* Falcon sound DMA supports 8bit and 16bit modes */
+
+    switch (format) {
+	case AFMT_QUERY:
+	    return(sound.soft.format);
+	case AFMT_MU_LAW:
+	case AFMT_A_LAW:
+	case AFMT_U8:
+	case AFMT_S8:
+	    size = 8;
+	    break;
+	case AFMT_S16_BE:
+	case AFMT_U16_BE:
+	case AFMT_S16_LE:
+	case AFMT_U16_LE:
+	    size = 16;
+	    break;
+	default: /* :-) */
+	    size = 8;
+	    format = AFMT_S8;
+    }
+
+    sound.soft.format = format;
+    sound.soft.size = size;
+    if (sound.minDev == SND_DEV_DSP) {
+	sound.dsp.format = format;
+	sound.dsp.size = sound.soft.size;
+    }
+
+    FalconInit();
+
+    return(format);
+}
+
+
+/* This is for the Falcon output *attenuation* in 1.5dB steps,
+ * i.e. output level from 0 to -22.5dB in -1.5dB steps.
+ */
+#define VOLUME_VOXWARE_TO_ATT(v) \
+	((v) < 0 ? 15 : (v) > 100 ? 0 : 15 - (v) * 3 / 20)
+#define VOLUME_ATT_TO_VOXWARE(v) (100 - (v) * 20 / 3)
+
+
+static int FalconSetVolume(int volume)
+{
+    sound.volume_left = VOLUME_VOXWARE_TO_ATT(volume & 0xff);
+    sound.volume_right = VOLUME_VOXWARE_TO_ATT((volume & 0xff00) >> 8);
+    tt_dmasnd.output_atten = sound.volume_left << 8 | sound.volume_right << 4;
+    return(VOLUME_ATT_TO_VOXWARE(sound.volume_left) |
+	   VOLUME_ATT_TO_VOXWARE(sound.volume_right) << 8);
+}
+
+
+static void ata_sq_play_next_frame(int index)
+{
+    char *start, *end;
+
+    /* used by AtaPlay() if all doubts whether there really is something
+     * to be played are already wiped out.
+     */
+    start = sq_block_address(sq.front);
+    end = start+((sq.count == index) ? sq.rear_size : sq.block_size);
+    /* end might not be a legal virtual address. */
+    DMASNDSetEnd(VTOP(end - 1) + 1);
+    DMASNDSetBase(VTOP(start));
+	/* Since only an even number of samples per frame can
+	be played, we might lose one byte here. (TO DO) */
+    sq.front = (sq.front+1) % sq.max_count;
+    sq.playing++;
+    tt_dmasnd.ctrl = DMASND_CTRL_ON | DMASND_CTRL_REPEAT;
+}
+
+
+static void AtaPlay(void)
+{
+    /* ++TeSche: Note that sq.playing is no longer just a flag but holds
+     * the number of frames the DMA is currently programmed for instead,
+     * may be 0, 1 (currently being played) or 2 (pre-programmed).
+     *
+     * Changes done to sq.count and sq.playing are a bit more subtle again
+     * so now I must admit I also prefer disabling the irq here rather
+     * than considering all possible situations. But the point is that
+     * disabling the irq doesn't have any bad influence on this version of
+     * the driver as we benefit from having pre-programmed the DMA
+     * whereever possible: There's no need to reload the DMA at the exact
+     * time of an interrupt but only at some time while the pre-programmed
+     * frame is playing!
+     */
+    atari_disable_irq(IRQ_MFP_TIMA);
+
+    if (sq.playing == 2 ||	/* DMA is 'full' */
+	sq.count <= 0) {	/* nothing to do */
+	atari_enable_irq(IRQ_MFP_TIMA);
+	return;
+    }
+
+    if (sq.playing == 0) {
+	/* looks like there's nothing 'in' the DMA yet, so try
+	 * to put two frames into it (at least one is available).
+	 */
+	if (sq.count == 1 && sq.rear_size < sq.block_size && !sq.syncing) {
+	    /* hmmm, the only existing frame is not
+	     * yet filled and we're not syncing?
+	     */
+	    atari_enable_irq(IRQ_MFP_TIMA);
+	    return;
+	}
+	ata_sq_play_next_frame(1);
+	if (sq.count == 1) {
+	    /* no more frames */
+	    atari_enable_irq(IRQ_MFP_TIMA);
+	    return;
+	}
+	if (sq.count == 2 && sq.rear_size < sq.block_size && !sq.syncing) {
+	    /* hmmm, there were two frames, but the second
+	     * one is not yet filled and we're not syncing?
+	     */
+	    atari_enable_irq(IRQ_MFP_TIMA);
+	    return;
+	}
+	ata_sq_play_next_frame(2);
+    } else {
+	/* there's already a frame being played so we may only stuff
+	 * one new into the DMA, but even if this may be the last
+	 * frame existing the previous one is still on sq.count.
+	 */
+	if (sq.count == 2 && sq.rear_size < sq.block_size && !sq.syncing) {
+	    /* hmmm, the only existing frame is not
+	     * yet filled and we're not syncing?
+	     */
+	    atari_enable_irq(IRQ_MFP_TIMA);
+	    return;
+	}
+	ata_sq_play_next_frame(2);
+    }
+    atari_enable_irq(IRQ_MFP_TIMA);
+}
+
+
+static void ata_sq_interrupt(int irq, struct pt_regs *fp, void *dummy)
+{
+#if 0
+    /* ++TeSche: if you should want to test this... */
+    static int cnt = 0;
+    if (sq.playing == 2)
+	if (++cnt == 10) {
+	    /* simulate losing an interrupt */
+	    cnt = 0;
+	    return;
+	}
+#endif
+
+    if (sq.ignore_int && (sound.mach.type == DMASND_FALCON)) {
+	/* ++TeSche: Falcon only: ignore first irq because it comes
+	 * immediately after starting a frame. after that, irqs come
+	 * (almost) like on the TT.
+	 */
+	sq.ignore_int = 0;
+	return;
+    }
+
+    if (!sq.playing) {
+	/* playing was interrupted and sq_reset() has already cleared
+	 * the sq variables, so better don't do anything here.
+	 */
+	WAKE_UP(sq.sync_queue);
+	return;
+    }
+
+    /* Probably ;) one frame is finished. Well, in fact it may be that a
+     * pre-programmed one is also finished because there has been a long
+     * delay in interrupt delivery and we've completely lost one, but
+     * there's no way to detect such a situation. In such a case the last
+     * frame will be played more than once and the situation will recover
+     * as soon as the irq gets through.
+     */
+    sq.count--;
+    sq.playing--;
+
+    if (!sq.playing) {
+	tt_dmasnd.ctrl = DMASND_CTRL_OFF;
+	sq.ignore_int = 1;
+    }
+
+    WAKE_UP(sq.write_queue);
+	/* At least one block of the queue is free now
+	so wake up a writing process blocked because
+	of a full queue. */
+
+    if ((sq.playing != 1) || (sq.count != 1))
+	/* We must be a bit carefully here: sq.count indicates the
+	 * number of buffers used and not the number of frames to
+	 * be played. If sq.count==1 and sq.playing==1 that means
+	 * the only remaining frame was already programmed earlier
+	 * (and is currently running) so we mustn't call AtaPlay()
+	 * here, otherwise we'll play one frame too much.
+	 */
+	AtaPlay();
+
+    if (!sq.playing) WAKE_UP(sq.sync_queue);
+	/* We are not playing after AtaPlay(), so there
+	is nothing to play any more. Wake up a process
+	waiting for audio output to drain. */
+}
+#endif /* CONFIG_ATARI */
+
+
+#ifdef CONFIG_AMIGA
+
+/*
+ * Amiga
+ */
+
+
+static void *AmiAlloc(unsigned int size, int flags)
+{
+    return(amiga_chip_alloc((long)size));
+}
+
+static void AmiFree(void *obj, unsigned int size)
+{
+    amiga_chip_free (obj);
+}
+
+static int AmiIrqInit(void)
+{
+    /* turn off DMA for audio channels */
+    custom.dmacon = AMI_AUDIO_OFF;
+
+    /* Register interrupt handler. */
+    if (!add_isr(IRQ_AMIGA_AUD0, ami_sq_interrupt, 0, NULL, "DMA sound"))
+	panic("Couldn't add audio interrupt");
+    return(1);
+}
+
+
+static void AmiSilence(void)
+{
+    /* turn off DMA for audio channels */
+    custom.dmacon = AMI_AUDIO_OFF;
+}
+
+
+static void AmiInit(void)
+{
+    int period, i;
+
+    AmiSilence();
+
+    if (sound.soft.speed)
+	period = amiga_colorclock/sound.soft.speed-1;
+    else
+	period = amiga_audio_min_period;
+    sound.hard = sound.soft;
+    sound.trans = &transAmiga;
+
+    if (period < amiga_audio_min_period) {
+	/* we would need to squeeze the sound, but we won't do that */
+	period = amiga_audio_min_period;
+	sound.hard.speed = amiga_colorclock/(period+1);
+    } else if (period > 65535) {
+	period = 65535;
+	sound.hard.speed = amiga_colorclock/(period+1);
+    }
+    for (i = 0; i < 4; i++)
+	custom.aud[i].audper = period;
+    amiga_audio_period = period;
+}
+
+
+static int AmiSetFormat(int format)
+{
+    int size;
+
+    /* Amiga sound DMA supports 8bit and 16bit (pseudo 14 bit) modes */
+
+    switch (format) {
+	case AFMT_QUERY:
+	    return(sound.soft.format);
+	case AFMT_MU_LAW:
+	case AFMT_A_LAW:
+	case AFMT_U8:
+	case AFMT_S8:
+	    size = 8;
+	    break;
+	case AFMT_S16_BE:
+	case AFMT_U16_BE:
+	case AFMT_S16_LE:
+	case AFMT_U16_LE:
+	    size = 16;
+	    break;
+	default: /* :-) */
+	    size = 8;
+	    format = AFMT_S8;
+    }
+
+    sound.soft.format = format;
+    sound.soft.size = size;
+    if (sound.minDev == SND_DEV_DSP) {
+	sound.dsp.format = format;
+	sound.dsp.size = sound.soft.size;
+    }
+    AmiInit();
+
+    return(format);
+}
+
+
+#define VOLUME_VOXWARE_TO_AMI(v) \
+	(((v) < 0) ? 0 : ((v) > 100) ? 64 : ((v) * 64)/100)
+#define VOLUME_AMI_TO_VOXWARE(v) ((v)*100/64)
+
+static int AmiSetVolume(int volume)
+{
+    sound.volume_left = VOLUME_VOXWARE_TO_AMI(volume & 0xff);
+    custom.aud[0].audvol = sound.volume_left;
+    sound.volume_right = VOLUME_VOXWARE_TO_AMI((volume & 0xff00) >> 8);
+    custom.aud[1].audvol = sound.volume_right;
+    return(VOLUME_AMI_TO_VOXWARE(sound.volume_left) |
+	   (VOLUME_AMI_TO_VOXWARE(sound.volume_right) << 8));
+}
+
+static int AmiSetTreble(int treble)
+{
+    sound.treble = treble;
+    if (treble > 50)
+	ciaa.pra |= 0x02;
+    else
+	ciaa.pra &= ~0x02;
+    return(treble);
+}
+
+
+#define AMI_PLAY_LOADED		1
+#define AMI_PLAY_PLAYING	2
+#define AMI_PLAY_MASK		3
+
+
+static void ami_sq_play_next_frame(int index)
+{
+    u_char *start, *ch0, *ch1, *ch2, *ch3;
+    u_long size;
+
+    /* used by AmiPlay() if all doubts whether there really is something
+     * to be played are already wiped out.
+     */
+    start = sq_block_address(sq.front);
+    size = (sq.count == index ? sq.rear_size : sq.block_size)>>1;
+
+    if (sound.hard.stereo) {
+	ch0 = start;
+	ch1 = start+sq.block_size_half;
+	size >>= 1;
+    } else {
+	ch0 = start;
+	ch1 = start;
+    }
+    if (sound.hard.size == 8) {
+	custom.aud[0].audlc = (u_short *)ZTWO_PADDR(ch0);
+	custom.aud[0].audlen = size;
+	custom.aud[1].audlc = (u_short *)ZTWO_PADDR(ch1);
+	custom.aud[1].audlen = size;
+	custom.dmacon = AMI_AUDIO_8;
+    } else {
+	size >>= 1;
+	custom.aud[0].audlc = (u_short *)ZTWO_PADDR(ch0);
+	custom.aud[0].audlen = size;
+	custom.aud[1].audlc = (u_short *)ZTWO_PADDR(ch1);
+	custom.aud[1].audlen = size;
+	if (sound.volume_left == 64 && sound.volume_right == 64) {
+	    /* We can play pseudo 14-bit only with the maximum volume */
+	    ch3 = ch0+sq.block_size_quarter;
+	    ch2 = ch1+sq.block_size_quarter;
+	    custom.aud[2].audlc = (u_short *)ZTWO_PADDR(ch2);
+	    custom.aud[2].audlen = size;
+	    custom.aud[3].audlc = (u_short *)ZTWO_PADDR(ch3);
+	    custom.aud[3].audlen = size;
+	    custom.dmacon = AMI_AUDIO_14;
+	} else
+	    custom.dmacon = AMI_AUDIO_8;
+    }
+    sq.front = (sq.front+1) % sq.max_count;
+    sq.playing |= AMI_PLAY_LOADED;
+}
+
+
+static void AmiPlay(void)
+{
+    int minframes = 1;
+
+    custom.intena = IF_AUD0;
+
+    if (sq.playing & AMI_PLAY_LOADED) {
+	/* There's already a frame loaded */
+	custom.intena = IF_SETCLR | IF_AUD0;
+	return;
+    }
+
+    if (sq.playing & AMI_PLAY_PLAYING)
+	/* Increase threshold: frame 1 is already being played */
+	minframes = 2;
+
+    if (sq.count < minframes) {
+	/* Nothing to do */
+	custom.intena = IF_SETCLR | IF_AUD0;
+	return;
+    }
+
+    if (sq.count <= minframes && sq.rear_size < sq.block_size && !sq.syncing) {
+	/* hmmm, the only existing frame is not
+	 * yet filled and we're not syncing?
+	 */
+	custom.intena = IF_SETCLR | IF_AUD0;
+	return;
+    }
+
+    ami_sq_play_next_frame(minframes);
+
+    custom.intena = IF_SETCLR | IF_AUD0;
+}
+
+
+static void ami_sq_interrupt(int irq, struct pt_regs *fp, void *dummy)
+{
+    int minframes = 1;
+
+    if (!sq.playing) {
+	/* Playing was interrupted and sq_reset() has already cleared
+	 * the sq variables, so better don't do anything here.
+	 */
+	WAKE_UP(sq.sync_queue);
+	return;
+    }
+
+    if (sq.playing & AMI_PLAY_PLAYING) {
+	/* We've just finished a frame */
+	sq.count--;
+	WAKE_UP(sq.write_queue);
+    }
+
+    if (sq.playing & AMI_PLAY_LOADED)
+	/* Increase threshold: frame 1 is already being played */
+	minframes = 2;
+
+    /* Shift the flags */
+    sq.playing = (sq.playing<<1) & AMI_PLAY_MASK;
+
+    if (!sq.playing)
+	/* No frame is playing, disable audio DMA */
+	custom.dmacon = AMI_AUDIO_OFF;
+
+    if (sq.count >= minframes)
+    	/* Try to play the next frame */
+	AmiPlay();
+
+    if (!sq.playing)
+	/* Nothing to play anymore.
+	   Wake up a process waiting for audio output to drain. */
+	WAKE_UP(sq.sync_queue);
+}
+#endif /* CONFIG_AMIGA */
+
+
+/*** Machine definitions *****************************************************/
+
+
+#ifdef CONFIG_ATARI
+static MACHINE machTT = {
+    DMASND_TT, AtaAlloc, AtaFree, AtaIrqInit, TTInit, TTSilence, TTSetFormat,
+    TTSetVolume, AtaSetBass, AtaSetTreble, AtaPlay
+};
+
+static MACHINE machFalcon = {
+    DMASND_FALCON, AtaAlloc, AtaFree, AtaIrqInit, FalconInit, FalconSilence,
+    FalconSetFormat, FalconSetVolume, AtaSetBass, AtaSetTreble, AtaPlay
+};
+#endif /* CONFIG_ATARI */
+
+#ifdef CONFIG_AMIGA
+static MACHINE machAmiga = {
+    DMASND_AMIGA, AmiAlloc, AmiFree, AmiIrqInit, AmiInit, AmiSilence,
+    AmiSetFormat, AmiSetVolume, NULL, AmiSetTreble, AmiPlay
+};
+#endif /* CONFIG_AMIGA */
+
+
+/*** Mid level stuff *********************************************************/
+
+
+static void sound_silence(void)
+{
+    /* update hardware settings one more */
+    (*sound.mach.init)();
+
+    (*sound.mach.silence)();
+}
+
+
+static void sound_init(void)
+{
+    (*sound.mach.init)();
+}
+
+
+static int sound_set_format(int format)
+{
+    return(*sound.mach.setFormat)(format);
+}
+
+
+static int sound_set_speed(int speed)
+{
+    if (speed < 0)
+	return(sound.soft.speed);
+
+    sound.soft.speed = speed;
+    (*sound.mach.init)();
+    if (sound.minDev == SND_DEV_DSP)
+	sound.dsp.speed = sound.soft.speed;
+
+    return(sound.soft.speed);
+}
+
+
+static int sound_set_stereo(int stereo)
+{
+    if (stereo < 0)
+	return(sound.soft.stereo);
+
+    stereo = !!stereo;    /* should be 0 or 1 now */
+
+    sound.soft.stereo = stereo;
+    if (sound.minDev == SND_DEV_DSP)
+	sound.dsp.stereo = stereo;
+    (*sound.mach.init)();
+
+    return(stereo);
+}
+
+
+static int sound_set_volume(int volume)
+{
+    return(*sound.mach.setVolume)(volume);
+}
+
+
+#ifdef CONFIG_ATARI
+static int sound_set_bass(int bass)
+{
+    return(sound.mach.setBass ? (*sound.mach.setBass)(bass) : 50);
+}
+#endif /* CONFIG_ATARI */
+
+
+static int sound_set_treble(int treble)
+{
+    return(sound.mach.setTreble ? (*sound.mach.setTreble)(treble) : 50);
+}
+
+
+static long sound_copy_translate(const u_char *userPtr, long userCount,
+				 u_char frame[], long *frameUsed,
+				 long frameLeft)
+{
+    long (*ct_func)(const u_char *, long, u_char *, long *, long) = NULL;
+
+    switch (sound.soft.format) {
+	case AFMT_MU_LAW:
+	    ct_func = sound.trans->ct_ulaw;
+	    break;
+	case AFMT_A_LAW:
+	    ct_func = sound.trans->ct_alaw;
+	    break;
+	case AFMT_S8:
+	    ct_func = sound.trans->ct_s8;
+	    break;
+	case AFMT_U8:
+	    ct_func = sound.trans->ct_u8;
+	    break;
+	case AFMT_S16_BE:
+	    ct_func = sound.trans->ct_s16be;
+	    break;
+	case AFMT_U16_BE:
+	    ct_func = sound.trans->ct_u16be;
+	    break;
+	case AFMT_S16_LE:
+	    ct_func = sound.trans->ct_s16le;
+	    break;
+	case AFMT_U16_LE:
+	    ct_func = sound.trans->ct_u16le;
+	    break;
+    }
+    if (ct_func)
+	return(ct_func(userPtr, userCount, frame, frameUsed, frameLeft));
+    else
+	return(0);
+}
+
+
+/*
+ * /dev/mixer abstraction
+ */
+
+
+#define RECLEVEL_VOXWARE_TO_GAIN(v) \
+	((v) < 0 ? 0 : (v) > 100 ? 15 : (v) * 3 / 20)
+#define RECLEVEL_GAIN_TO_VOXWARE(v) (((v) * 20 + 2) / 3)
+
+
+static void mixer_init(void)
+{
+    mixer.busy = 0;
+    sound.treble = 0;
+    sound.bass = 0;
+    switch (sound.mach.type) {
+#ifdef CONFIG_ATARI
+	case DMASND_TT:
+	    atari_microwire_cmd(MW_LM1992_VOLUME(0));
+	    sound.volume_left = 0;
+	    atari_microwire_cmd(MW_LM1992_BALLEFT(0));
+	    sound.volume_right = 0;
+	    atari_microwire_cmd(MW_LM1992_BALRIGHT(0));
+	    atari_microwire_cmd(MW_LM1992_TREBLE(0));
+	    atari_microwire_cmd(MW_LM1992_BASS(0));
+	    break;
+	case DMASND_FALCON:
+	    sound.volume_left = (tt_dmasnd.output_atten & 0xf00) >> 8;
+	    sound.volume_right = (tt_dmasnd.output_atten & 0xf0) >> 4;
+	    break;
+#endif /* CONFIG_ATARI */
+#ifdef CONFIG_AMIGA
+	case DMASND_AMIGA:
+	    sound.volume_left = 64;
+	    sound.volume_right = 64;
+	    custom.aud[0].audvol = sound.volume_left;
+	    custom.aud[3].audvol = 1;			/* For pseudo 14bit */
+	    custom.aud[1].audvol = sound.volume_right;
+	    custom.aud[2].audvol = 1;			/* For pseudo 14bit */
+	    sound.treble = 50;
+	    break;
+#endif /* CONFIG_AMIGA */
+    }
+}
+
+
+static int mixer_open(int open_mode)
+{
+    if (mixer.busy)
+	return(-EBUSY);
+    mixer.busy = 1;
+    return(0);
+}
+
+
+static int mixer_release(void)
+{
+    mixer.busy = 0;
+    return(0);
+}
+
+
+static int mixer_ioctl(struct inode *inode, struct file *file, u_int cmd,
+		       u_long arg)
+{
+    switch (sound.mach.type) {
+#ifdef CONFIG_ATARI
+	case DMASND_FALCON:
+	    switch (cmd) {
+		case SOUND_MIXER_READ_DEVMASK:
+		    return(IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_MIC | SOUND_MASK_SPEAKER));
+		case SOUND_MIXER_READ_RECMASK:
+		    return(IOCTL_OUT(arg, SOUND_MASK_MIC));
+		case SOUND_MIXER_READ_STEREODEVS:
+		    return(IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_MIC));
+		case SOUND_MIXER_READ_CAPS:
+		    return(IOCTL_OUT(arg, SOUND_CAP_EXCL_INPUT));
+		case SOUND_MIXER_READ_VOLUME:
+		    return(IOCTL_OUT(arg,
+			VOLUME_ATT_TO_VOXWARE(sound.volume_left) |
+			VOLUME_ATT_TO_VOXWARE(sound.volume_right) << 8));
+		case SOUND_MIXER_WRITE_MIC:
+		    tt_dmasnd.input_gain =
+			RECLEVEL_VOXWARE_TO_GAIN(IOCTL_IN(arg) & 0xff) << 4 |
+			RECLEVEL_VOXWARE_TO_GAIN(IOCTL_IN(arg) >> 8 & 0xff);
+		    /* fall thru, return set value */
+		case SOUND_MIXER_READ_MIC:
+		    return(IOCTL_OUT(arg,
+			RECLEVEL_GAIN_TO_VOXWARE(tt_dmasnd.input_gain >> 4 & 0xf) |
+			RECLEVEL_GAIN_TO_VOXWARE(tt_dmasnd.input_gain & 0xf) << 8));
+		case SOUND_MIXER_READ_SPEAKER:
+		    {
+			int porta;
+			cli();
+			sound_ym.rd_data_reg_sel = 14;
+			porta = sound_ym.rd_data_reg_sel;
+			sti();
+			return(IOCTL_OUT(arg, porta & 0x40 ? 0 : 100));
+		    }
+		case SOUND_MIXER_WRITE_VOLUME:
+		    return(IOCTL_OUT(arg, sound_set_volume(IOCTL_IN(arg))));
+		case SOUND_MIXER_WRITE_SPEAKER:
+		    {
+			int porta;
+			cli();
+			sound_ym.rd_data_reg_sel = 14;
+			porta = (sound_ym.rd_data_reg_sel & ~0x40) |
+				(IOCTL_IN(arg) < 50 ? 0x40 : 0);
+			sound_ym.wd_data = porta;
+			sti();
+			return(IOCTL_OUT(arg, porta & 0x40 ? 0 : 100));
+		    }
+	    }
+	    break;
+
+	case DMASND_TT:
+	    switch (cmd) {
+		case SOUND_MIXER_READ_DEVMASK:
+		    return(IOCTL_OUT(arg,
+			SOUND_MASK_VOLUME | SOUND_MASK_TREBLE | SOUND_MASK_BASS |
+			((boot_info.bi_atari.mch_cookie >> 16) == ATARI_MCH_TT ?
+			    SOUND_MASK_SPEAKER : 0)));
+		case SOUND_MIXER_READ_RECMASK:
+		    return(IOCTL_OUT(arg, 0));
+		case SOUND_MIXER_READ_STEREODEVS:
+		    return(IOCTL_OUT(arg, SOUND_MASK_VOLUME));
+		case SOUND_MIXER_READ_VOLUME:
+		    return(IOCTL_OUT(arg,
+			VOLUME_DB_TO_VOXWARE(sound.volume_left) |
+			(VOLUME_DB_TO_VOXWARE(sound.volume_right) << 8)));
+		case SOUND_MIXER_READ_BASS:
+		    return(IOCTL_OUT(arg, TONE_DB_TO_VOXWARE(sound.bass)));
+		case SOUND_MIXER_READ_TREBLE:
+		    return(IOCTL_OUT(arg, TONE_DB_TO_VOXWARE(sound.treble)));
+		case SOUND_MIXER_READ_SPEAKER:
+		    {
+			int porta;
+			if ((boot_info.bi_atari.mch_cookie >> 16) == ATARI_MCH_TT) {
+			    cli();
+			    sound_ym.rd_data_reg_sel = 14;
+			    porta = sound_ym.rd_data_reg_sel;
+			    sti();
+			    return(IOCTL_OUT(arg, porta & 0x40 ? 0 : 100));
+			} else
+			    return(-EINVAL);
+		    }
+		case SOUND_MIXER_WRITE_VOLUME:
+		    return(IOCTL_OUT(arg, sound_set_volume(IOCTL_IN(arg))));
+		case SOUND_MIXER_WRITE_BASS:
+		    return(IOCTL_OUT(arg, sound_set_bass(IOCTL_IN(arg))));
+		case SOUND_MIXER_WRITE_TREBLE:
+		    return(IOCTL_OUT(arg, sound_set_treble(IOCTL_IN(arg))));
+		case SOUND_MIXER_WRITE_SPEAKER:
+		    if ((boot_info.bi_atari.mch_cookie >> 16) == ATARI_MCH_TT) {
+			int porta;
+			cli();
+			sound_ym.rd_data_reg_sel = 14;
+			porta = (sound_ym.rd_data_reg_sel & ~0x40) |
+				(IOCTL_IN(arg) < 50 ? 0x40 : 0);
+			sound_ym.wd_data = porta;
+			sti();
+			return(IOCTL_OUT(arg, porta & 0x40 ? 0 : 100));
+		    } else
+			return(-EINVAL);
+	    }
+	    break;
+#endif /* CONFIG_ATARI */
+
+#ifdef CONFIG_AMIGA
+	case DMASND_AMIGA:
+	    switch (cmd) {
+		case SOUND_MIXER_READ_DEVMASK:
+		    return(IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_TREBLE));
+		case SOUND_MIXER_READ_RECMASK:
+		    return(IOCTL_OUT(arg, 0));
+		case SOUND_MIXER_READ_STEREODEVS:
+		    return(IOCTL_OUT(arg, SOUND_MASK_VOLUME));
+		case SOUND_MIXER_READ_VOLUME:
+		    return(IOCTL_OUT(arg,
+			VOLUME_AMI_TO_VOXWARE(sound.volume_left) |
+			VOLUME_AMI_TO_VOXWARE(sound.volume_right) << 8));
+		case SOUND_MIXER_WRITE_VOLUME:
+		    return(IOCTL_OUT(arg, sound_set_volume(IOCTL_IN(arg))));
+		case SOUND_MIXER_READ_TREBLE:
+		    return(IOCTL_OUT(arg, sound.treble));
+		case SOUND_MIXER_WRITE_TREBLE:
+		    return(IOCTL_OUT(arg, sound_set_treble(IOCTL_IN(arg))));
+	    }
+	    break;
+#endif /* CONFIG_AMIGA */
+    }
+
+    return(-EINVAL);
+}
+
+
+
+/*
+ * Sound queue stuff, the heart of the driver
+ */
+
+
+static void sq_init(int numBufs, int bufSize, char **buffers)
+{
+    sq.max_count = numBufs;
+    sq.block_size = bufSize;
+    sq.buffers = buffers;
+
+    sq.front = sq.count = 0;
+    sq.rear = -1;
+    sq.write_queue = sq.open_queue = sq.sync_queue = 0;
+    sq.busy = 0;
+    sq.syncing = 0;
+
+    sq.playing = 0;
+
+#ifdef CONFIG_ATARI
+    sq.ignore_int = 0;
+#endif /* CONFIG_ATARI */
+#ifdef CONFIG_AMIGA
+    sq.block_size_half = sq.block_size>>1;
+    sq.block_size_quarter = sq.block_size_half>>1;
+#endif /* CONFIG_AMIGA */
+
+    sound_silence();
+
+    /* whatever you like as startup mode for /dev/dsp,
+     * (/dev/audio hasn't got a startup mode). note that
+     * once changed a new open() will *not* restore these!
+     */
+    sound.dsp.format = AFMT_S8;
+    sound.dsp.stereo = 0;
+    sound.dsp.size = 8;
+
+    /* set minimum rate possible without expanding */
+    switch (sound.mach.type) {
+#ifdef CONFIG_ATARI
+	case DMASND_TT:
+	    sound.dsp.speed = 6258;
+	    break;
+	case DMASND_FALCON:
+	    sound.dsp.speed = 8195;
+	    break;
+#endif /* CONFIG_ATARI */
+#ifdef CONFIG_AMIGA
+	case DMASND_AMIGA:
+	    sound.dsp.speed = 8000;
+	    break;
+#endif /* CONFIG_AMIGA */
+    }
+
+    /* before the first open to /dev/dsp this wouldn't be set */
+    sound.soft = sound.dsp;
+}
+
+
+static void sq_play(void)
+{
+    (*sound.mach.play)();
+}
+
+
+/* ++TeSche: radically changed this one too */
+
+static int sq_write(const char *src, int uLeft)
+{
+    int uWritten = 0;
+    u_char *dest;
+    long uUsed, bUsed, bLeft;
+
+    /* ++TeSche: Is something like this necessary?
+     * Hey, that's an honest question! Or does any other part of the
+     * filesystem already checks this situation? I really don't know.
+     */
+    if (uLeft < 1)
+	return(0);
+
+    /* The interrupt doesn't start to play the last, incomplete frame.
+     * Thus we can append to it without disabling the interrupts! (Note
+     * also that sq.rear isn't affected by the interrupt.)
+     */
+
+    if (sq.count > 0 && (bLeft = sq.block_size-sq.rear_size) > 0) {
+	dest = sq_block_address(sq.rear);
+	bUsed = sq.rear_size;
+	uUsed = sound_copy_translate(src, uLeft, dest, &bUsed, bLeft);
+	src += uUsed;
+	uWritten += uUsed;
+	uLeft -= uUsed;
+	sq.rear_size = bUsed;
+    }
+
+    do {
+	if (sq.count == sq.max_count) {
+	    sq_play();
+	    if (NON_BLOCKING(sq.open_mode))
+		return(uWritten > 0 ? uWritten : -EAGAIN);
+	    SLEEP(sq.write_queue, ONE_SECOND);
+	    if (SIGNAL_RECEIVED)
+		return(uWritten > 0 ? uWritten : -EINTR);
+	}
+
+	/* Here, we can avoid disabling the interrupt by first
+	 * copying and translating the data, and then updating
+	 * the sq variables. Until this is done, the interrupt
+	 * won't see the new frame and we can work on it
+	 * undisturbed.
+	 */
+
+	dest = sq_block_address((sq.rear+1) % sq.max_count);
+	bUsed = 0;
+	bLeft = sq.block_size;
+	uUsed = sound_copy_translate(src, uLeft, dest, &bUsed, bLeft);
+	src += uUsed;
+	uWritten += uUsed;
+	uLeft -= uUsed;
+	if (bUsed) {
+	    sq.rear = (sq.rear+1) % sq.max_count;
+	    sq.rear_size = bUsed;
+	    sq.count++;
+	}
+    } while (bUsed);   /* uUsed may have been 0 */
+
+    sq_play();
+
+    return(uWritten);
+}
+
+
+static int sq_open(int open_mode)
+{
+    if (sq.busy) {
+	if (NON_BLOCKING(open_mode))
+	    return(-EBUSY);
+	while (sq.busy) {
+	    SLEEP(sq.open_queue, ONE_SECOND);
+	    if (SIGNAL_RECEIVED)
+		return(-EINTR);
+	}
+    }
+    sq.open_mode = open_mode;
+    sq.busy = 1;
+#ifdef CONFIG_ATARI
+    sq.ignore_int = 1;
+#endif /* CONFIG_ATARI */
+    return(0);
+}
+
+
+static void sq_reset(void)
+{
+    sound_silence();
+    sq.playing = 0;
+    sq.count = 0;
+    sq.front = (sq.rear+1) % sq.max_count;
+}
+
+
+static int sq_sync(void)
+{
+    int rc = 0;
+
+    sq.syncing = 1;
+    sq_play();	/* there may be an incomplete frame waiting */
+
+    while (sq.playing) {
+	SLEEP(sq.sync_queue, ONE_SECOND);
+	if (SIGNAL_RECEIVED) {
+	    /* While waiting for audio output to drain, an interrupt occured.
+	       Stop audio output immediately and clear the queue. */
+	    sq_reset();
+	    rc = -EINTR;
+	    break;
+	}
+    }
+
+    sq.syncing = 0;
+    return(rc);
+}
+
+
+static int sq_release(void)
+{
+    int rc = 0;
+    if (sq.busy) {
+	rc = sq_sync();
+	sq.busy = 0;
+	WAKE_UP(sq.open_queue);
+	/* Wake up a process waiting for the queue beeing released.
+	   Note: There may be several processes waiting for a call to open()
+		 returning. */
+    }
+    return(rc);
+}
+
+
+
+/*
+ * /dev/sndstat
+ */
+
+
+static void state_init(void)
+{
+    state.busy = 0;
+}
+
+
+/* state.buf should not overflow! */
+
+static int state_open(int open_mode)
+{
+    char *buffer = state.buf, *mach = "";
+    int len = 0;
+
+    if (state.busy)
+	return(-EBUSY);
+
+    state.ptr = 0;
+    state.busy = 1;
+
+    switch (sound.mach.type) {
+#ifdef CONFIG_ATARI
+	case DMASND_TT:
+	case DMASND_FALCON:
+	    mach = "Atari ";
+	    break;
+#endif /* CONFIG_ATARI */
+#ifdef CONFIG_AMIGA
+	case DMASND_AMIGA:
+	    mach = "Amiga ";
+	    break;
+#endif /* CONFIG_AMIGA */
+    }
+    len += sprintf(buffer+len, "%sDMA sound driver:\n", mach);
+
+    len += sprintf(buffer+len, "\tsound.format = 0x%x", sound.soft.format);
+    switch (sound.soft.format) {
+	case AFMT_MU_LAW:
+	    len += sprintf(buffer+len, " (mu-law)");
+	    break;
+	case AFMT_A_LAW:
+	    len += sprintf(buffer+len, " (A-law)");
+	    break;
+	case AFMT_U8:
+	    len += sprintf(buffer+len, " (unsigned 8 bit)");
+	    break;
+	case AFMT_S8:
+	    len += sprintf(buffer+len, " (signed 8 bit)");
+	    break;
+	case AFMT_S16_BE:
+	    len += sprintf(buffer+len, " (signed 16 bit big)");
+	    break;
+	case AFMT_U16_BE:
+	    len += sprintf(buffer+len, " (unsigned 16 bit big)");
+	    break;
+	case AFMT_S16_LE:
+	    len += sprintf(buffer+len, " (signed 16 bit little)");
+	    break;
+	case AFMT_U16_LE:
+	    len += sprintf(buffer+len, " (unsigned 16 bit little)");
+	    break;
+    }
+    len += sprintf(buffer+len, "\n");
+    len += sprintf(buffer+len, "\tsound.speed = %dHz (phys. %dHz)\n",
+		   sound.soft.speed, sound.hard.speed);
+    len += sprintf(buffer+len, "\tsound.stereo = 0x%x (%s)\n",
+		   sound.soft.stereo, sound.soft.stereo ? "stereo" : "mono");
+    switch (sound.mach.type) {
+#ifdef CONFIG_ATARI
+	case DMASND_TT:
+	    len += sprintf(buffer+len, "\tsound.volume_left = %ddB [-40...0]\n",
+			   sound.volume_left);
+	    len += sprintf(buffer+len, "\tsound.volume_right = %ddB [-40...0]\n",
+			   sound.volume_right);
+	    len += sprintf(buffer+len, "\tsound.bass = %ddB [-12...+12]\n",
+			   sound.bass);
+	    len += sprintf(buffer+len, "\tsound.treble = %ddB [-12...+12]\n",
+			   sound.treble);
+	    break;
+	case DMASND_FALCON:
+	    len += sprintf(buffer+len, "\tsound.volume_left = %ddB [-22.5...0]\n",
+			   sound.volume_left);
+	    len += sprintf(buffer+len, "\tsound.volume_right = %ddB [-22.5...0]\n",
+			   sound.volume_right);
+	    break;
+#endif /* CONFIG_ATARI */
+#ifdef CONFIG_AMIGA
+	case DMASND_AMIGA:
+	    len += sprintf(buffer+len, "\tsound.volume_left = %d [0...64]\n",
+			   sound.volume_left);
+	    len += sprintf(buffer+len, "\tsound.volume_right = %d [0...64]\n",
+			   sound.volume_right);
+	    break;
+#endif /* CONFIG_AMIGA */
+    }
+    len += sprintf(buffer+len, "\tsq.block_size = %d sq.max_count = %d\n",
+		   sq.block_size, sq.max_count);
+    len += sprintf(buffer+len, "\tsq.count = %d sq.rear_size = %d\n", sq.count,
+		   sq.rear_size);
+    len += sprintf(buffer+len, "\tsq.playing = %d sq.syncing = %d\n",
+		   sq.playing, sq.syncing);
+    state.len = len;
+    return(0);
+}
+
+
+static int state_release(void)
+{
+    state.busy = 0;
+    return(0);
+}
+
+
+static int state_read(char *dest, int count)
+{
+    int n = state.len-state.ptr;
+    if (n > count)
+	n = count;
+    if (n <= 0)
+	return(0);
+    memcpy_tofs(dest, &state.buf[state.ptr], n);
+    state.ptr += n;
+    return(n);
+}
+
+
+
+/*** High level stuff ********************************************************/
+
+
+static int sound_open(struct inode *inode, struct file *file)
+{
+    int dev = MINOR(inode->i_rdev) & 0x0f;
+
+    switch (dev) {
+	case SND_DEV_STATUS:
+	    return(state_open(file->f_flags));
+	case SND_DEV_CTL:
+	    return(mixer_open(file->f_flags));
+	case SND_DEV_DSP:
+	case SND_DEV_AUDIO:
+	    {
+		int rc = sq_open(file->f_flags);
+		if (rc == 0) {
+		    sound.minDev = dev;
+		    sound.soft = sound.dsp;
+		    sound_init();
+		    if (dev == SND_DEV_AUDIO) {
+			sound_set_speed(8000);
+			sound_set_stereo(0);
+			sound_set_format(AFMT_MU_LAW);
+		    }
+		}
+		return(rc);
+	    }
+	default:
+	    return(-ENXIO);
+    }
+}
+
+
+static int sound_fsync(struct inode *inode, struct file *filp)
+{
+    int dev = MINOR(inode->i_rdev) & 0x0f;
+
+    switch (dev) {
+	case SND_DEV_STATUS:
+	case SND_DEV_CTL:
+	    return(0);
+	case SND_DEV_DSP:
+	case SND_DEV_AUDIO:
+	    return(sq_sync());
+	default:
+	    return(unknown_minor_dev("sound_fsync", dev));
+    }
+}
+
+
+static void sound_release(struct inode *inode, struct file *file)
+{
+    int dev = MINOR(inode->i_rdev);
+
+    switch (dev & 0x0f) {
+	case SND_DEV_STATUS: state_release(); return;
+	case SND_DEV_CTL: mixer_release(); return;
+	case SND_DEV_DSP:
+	case SND_DEV_AUDIO:
+	    sq_release(); sound.soft = sound.dsp; sound_silence();
+	    return;
+	default:
+	    unknown_minor_dev("sound_release", dev);
+    }
+}
+
+
+static int sound_lseek(struct inode *inode, struct file *file, off_t offset,
+		       int orig)
+{
+    return(-EPERM);
+}
+
+
+static int sound_read(struct inode *inode, struct file *file, char *buf,
+		      int count)
+{
+    int dev = MINOR(inode->i_rdev);
+
+    switch (dev & 0x0f) {
+	case SND_DEV_STATUS:
+	    return(state_read(buf, count));
+	case SND_DEV_CTL:
+	case SND_DEV_DSP:
+	case SND_DEV_AUDIO:
+	    return(-EPERM);
+	default:
+	    return(unknown_minor_dev("sound_read", dev));
+    }
+}
+
+
+static int sound_write(struct inode *inode, struct file *file, const char *buf,
+		       int count)
+{
+    int dev = MINOR(inode->i_rdev);
+
+    switch (dev & 0x0f) {
+	case SND_DEV_STATUS:
+	case SND_DEV_CTL:
+	    return(-EPERM);
+	case SND_DEV_DSP:
+	case SND_DEV_AUDIO:
+	    return(sq_write(buf, count));
+	default:
+	    return(unknown_minor_dev("sound_write", dev));
+    }
+}
+
+
+static int ioctl_return(int *addr, int value)
+{
+    int error;
+
+    if (value < 0)
+	return(value);
+
+    error = verify_area(VERIFY_WRITE, addr, sizeof(int));
+    if (error)
+	return(error);
+
+    put_user(value, addr);
+    return(0);
+}
+
+
+static int unknown_minor_dev(char *fname, int dev)
+{
+    /* printk("%s: Unknown minor device %d\n", fname, dev); */
+    return(-ENXIO);
+}
+
+
+static int sound_ioctl(struct inode *inode, struct file *file, u_int cmd,
+		       u_long arg)
+{
+    int dev = MINOR(inode->i_rdev);
+    u_long fmt;
+
+    switch (dev & 0x0f) {
+	case SND_DEV_STATUS:
+	    return(-EPERM);
+	case SND_DEV_CTL:
+	    return(mixer_ioctl(inode, file, cmd, arg));
+	case SND_DEV_AUDIO:
+	case SND_DEV_DSP:
+	    switch (cmd) {
+		case SNDCTL_DSP_RESET:
+		    sq_reset();
+		    return(0);
+		case SNDCTL_DSP_POST:
+		case SNDCTL_DSP_SYNC:
+		    return(sound_fsync(inode, file));
+
+		/* ++TeSche: before changing any of these it's probably wise to
+		 * wait until sound playing has settled down
+		 */
+		case SNDCTL_DSP_SPEED:
+		    sound_fsync(inode, file);
+		    return(IOCTL_OUT(arg, sound_set_speed(IOCTL_IN(arg))));
+		case SNDCTL_DSP_STEREO:
+		    sound_fsync(inode, file);
+		    return(IOCTL_OUT(arg, sound_set_stereo(IOCTL_IN(arg))));
+		case SOUND_PCM_WRITE_CHANNELS:
+		    sound_fsync(inode, file);
+		    return(IOCTL_OUT(arg, sound_set_stereo(IOCTL_IN(arg)-1)+1));
+		case SNDCTL_DSP_SETFMT:
+		    sound_fsync(inode, file);
+		    return(IOCTL_OUT(arg, sound_set_format(IOCTL_IN(arg))));
+		case SNDCTL_DSP_GETFMTS:
+		    fmt = 0;
+		    if (sound.trans) {
+			if (sound.trans->ct_ulaw)
+			    fmt |= AFMT_MU_LAW;
+			if (sound.trans->ct_alaw)
+			    fmt |= AFMT_A_LAW;
+			if (sound.trans->ct_s8)
+			    fmt |= AFMT_S8;
+			if (sound.trans->ct_u8)
+			    fmt |= AFMT_U8;
+			if (sound.trans->ct_s16be)
+			    fmt |= AFMT_S16_BE;
+			if (sound.trans->ct_u16be)
+			    fmt |= AFMT_U16_BE;
+			if (sound.trans->ct_s16le)
+			    fmt |= AFMT_S16_LE;
+			if (sound.trans->ct_u16le)
+			    fmt |= AFMT_U16_LE;
+		    }
+		    return(IOCTL_OUT(arg, fmt));
+		case SNDCTL_DSP_GETBLKSIZE:
+		    return(IOCTL_OUT(arg, 10240));
+		case SNDCTL_DSP_SUBDIVIDE:
+		case SNDCTL_DSP_SETFRAGMENT:
+		    break;
+
+		default:
+		    return(mixer_ioctl(inode, file, cmd, arg));
+	    }
+	    break;
+
+	default:
+	    return(unknown_minor_dev("sound_ioctl", dev));
+    }
+    return(-EINVAL);
+}
+
+
+static struct file_operations sound_fops =
+{
+    sound_lseek,
+    sound_read,
+    sound_write,
+    NULL,
+    NULL,                      /* select */
+    sound_ioctl,
+    NULL,
+    sound_open,
+    sound_release,
+    sound_fsync
+};
+
+
+
+/*** Config & Setup **********************************************************/
+
+
+void soundcard_init(void)
+{
+    int has_sound = 0;
+    char **buffers;
+    int i;
+
+    switch (boot_info.machtype) {
+#ifdef CONFIG_ATARI
+	case MACH_ATARI:
+	    if (ATARIHW_PRESENT(PCM_8BIT)) {
+		if (ATARIHW_PRESENT(CODEC))
+		    sound.mach = machFalcon;
+		else if (ATARIHW_PRESENT(MICROWIRE))
+		    sound.mach = machTT;
+		else
+		    break;
+		if ((mfp.int_en_a & mfp.int_mk_a & 0x20) == 0)
+		    has_sound = 1;
+		else
+		    printk("DMA sound driver: Timer A interrupt already in use\n");
+	    }
+	    break;
+
+#endif /* CONFIG_ATARI */
+#ifdef CONFIG_AMIGA
+	case MACH_AMIGA:
+	    if (AMIGAHW_PRESENT(AMI_AUDIO)) {
+		sound.mach = machAmiga;
+		has_sound = 1;
+	    }
+	    break;
+#endif /* CONFIG_AMIGA */
+    }
+    if (!has_sound)
+	return;
+
+    /* Set up sound queue, /dev/audio and /dev/dsp. */
+    buffers = kmalloc (numBufs * sizeof(char *), GFP_KERNEL);
+    if (!buffers) {
+    out_of_memory:
+	printk("DMA sound driver: Not enough buffer memory, driver disabled!\n");
+	return;
+    }
+    for (i = 0; i < numBufs; i++) {
+	buffers[i] = sound.mach.dma_alloc (bufSize << 10, GFP_KERNEL);
+	if (!buffers[i]) {
+	    while (i--)
+		sound.mach.dma_free (buffers[i], bufSize << 10);
+	    kfree (buffers);
+	    goto out_of_memory;
+        }
+    }
+
+    /* Register driver with the VFS. */
+    register_chrdev(SOUND_MAJOR, "sound", &sound_fops);
+
+    sq_init(numBufs, bufSize << 10, buffers);
+
+    /* Set up /dev/sndstat. */
+    state_init();
+
+    /* Set up /dev/mixer. */
+    mixer_init();
+
+    if (!sound.mach.irqinit()) {
+	printk("DMA sound driver: Interrupt initialization failed\n");
+	return;
+    }
+
+    printk("DMA sound driver installed, using %d buffers of %dk.\n", numBufs,
+	   bufSize);
+
+    return;
+}
+
+void sound_setup(char *str, int *ints)
+{
+    /* ++Martin: stub, could possibly be merged with soundcard.c et al later */
+}
+
+void dmasound_setup(char *str, int *ints)
+{
+    /* check the bootstrap parameter for "dmasound=" */
+
+    switch (ints[0]) {
+	case 3:
+	    if ((ints[3] < 0) || (ints[3] > MAX_CATCH_RADIUS))
+		printk("dmasound_setup: illegal catch radius, using default = %d\n", catchRadius);
+	    else
+		catchRadius = ints[3];
+	    /* fall through */
+	case 2:
+	    if (ints[1] < MIN_BUFFERS)
+		printk("dmasound_setup: illegal number of buffers, using default = %d\n", numBufs);
+	    else
+		numBufs = ints[1];
+	    if (ints[2] < MIN_BUFSIZE || ints[2] > MAX_BUFSIZE)
+		printk("dmasound_setup: illegal buffer size, using default = %d\n", bufSize);
+	    else
+		bufSize = ints[2];
+	    break;
+	case 0:
+	    break;
+	default:
+	    printk("dmasound_setup: illegal number of arguments\n");
+    }
+}
diff -u --recursive --new-file v1.3.93/linux/drivers/sound/dmasound.h linux/drivers/sound/dmasound.h
--- v1.3.93/linux/drivers/sound/dmasound.h	Thu Jan  1 02:00:00 1970
+++ linux/drivers/sound/dmasound.h	Thu Apr 18 02:01:38 1996
@@ -0,0 +1,36 @@
+
+/* linux/drivers/sound/dmasound.h */
+
+/*
+ * Minor numbers for the sound driver.
+ *
+ * Unfortunately Creative called the codec chip of SB as a DSP. For this
+ * reason the /dev/dsp is reserved for digitized audio use. There is a
+ * device for true DSP processors but it will be called something else.
+ * In v3.0 it's /dev/sndproc but this could be a temporary solution.
+ */
+
+#define SND_NDEVS	256	/* Number of supported devices */
+#define SND_DEV_CTL	0	/* Control port /dev/mixer */
+#define SND_DEV_SEQ	1	/* Sequencer output /dev/sequencer (FM
+				   synthesizer and MIDI output) */
+#define SND_DEV_MIDIN	2	/* Raw midi access */
+#define SND_DEV_DSP	3	/* Digitized voice /dev/dsp */
+#define SND_DEV_AUDIO	4	/* Sparc compatible /dev/audio */
+#define SND_DEV_DSP16	5	/* Like /dev/dsp but 16 bits/sample */
+#define SND_DEV_STATUS	6	/* /dev/sndstat */
+/* #7 not in use now. Was in 2.4. Free for use after v3.0. */
+#define SND_DEV_SEQ2	8	/* /dev/sequencer, level 2 interface */
+#define SND_DEV_SNDPROC 9	/* /dev/sndproc for programmable devices */
+#define SND_DEV_PSS	SND_DEV_SNDPROC
+
+#define DSP_DEFAULT_SPEED	8000
+
+#define ON		1
+#define OFF		0
+
+#define MAX_AUDIO_DEV	5
+#define MAX_MIXER_DEV	2
+#define MAX_SYNTH_DEV	3
+#define MAX_MIDI_DEV	6
+#define MAX_TIMER_DEV	3
diff -u --recursive --new-file v1.3.93/linux/fs/Config.in linux/fs/Config.in
--- v1.3.93/linux/fs/Config.in	Mon Apr  8 19:01:44 1996
+++ linux/fs/Config.in	Mon Apr 22 15:39:27 1996
@@ -34,4 +34,6 @@
 tristate 'ISO9660 cdrom filesystem support' CONFIG_ISO9660_FS
 tristate 'OS/2 HPFS filesystem support (read only)' CONFIG_HPFS_FS
 tristate 'System V and Coherent filesystem support' CONFIG_SYSV_FS
+bool 'AFFS filesystem support' CONFIG_AFFS_FS
+bool 'UFS filesystem support (read only)' CONFIG_UFS_FS
 endmenu
diff -u --recursive --new-file v1.3.93/linux/fs/Makefile linux/fs/Makefile
--- v1.3.93/linux/fs/Makefile	Sat Mar  2 13:18:47 1996
+++ linux/fs/Makefile	Mon Apr 22 15:39:51 1996
@@ -17,7 +17,7 @@
 
 MOD_LIST_NAME := FS_MODULES
 ALL_SUB_DIRS = minix ext ext2 fat msdos vfat proc isofs nfs xiafs umsdos \
-		hpfs sysv smbfs ncpfs
+		hpfs sysv smbfs ncpfs ufs affs
 
 ifeq ($(CONFIG_QUOTA),y)
 O_OBJS += dquot.o
@@ -139,6 +139,14 @@
   ifeq ($(CONFIG_HPFS_FS),m)
   MOD_SUB_DIRS += hpfs
   endif
+endif
+
+ifeq ($(CONFIG_UFS_FS),y)
+SUB_DIRS += ufs
+endif
+
+ifeq ($(CONFIG_AFFS_FS),y)
+SUB_DIRS += affs
 endif
 
 ifeq ($(CONFIG_BINFMT_ELF),y)
diff -u --recursive --new-file v1.3.93/linux/fs/affs/Makefile linux/fs/affs/Makefile
--- v1.3.93/linux/fs/affs/Makefile	Thu Jan  1 02:00:00 1970
+++ linux/fs/affs/Makefile	Sun Feb 25 19:17:29 1996
@@ -0,0 +1,14 @@
+#
+# Makefile for the linux amiga fast filesystem routines.
+#
+# 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 := affs.o
+O_OBJS   := namei.o inode.o file.o dir.o amigaffs.o symlink.o
+M_OBJS   := $(O_TARGET)
+
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.93/linux/fs/affs/amigaffs.c linux/fs/affs/amigaffs.c
--- v1.3.93/linux/fs/affs/amigaffs.c	Thu Jan  1 02:00:00 1970
+++ linux/fs/affs/amigaffs.c	Sat Mar 30 17:46:01 1996
@@ -0,0 +1,130 @@
+/*
+ *  linux/fs/affs/amigaffs.c
+ *
+ *  (C) 1993  Ray Burr - Amiga FFS filesystem.
+ *
+ */
+
+#include <linux/fs.h>
+#include <linux/affs_fs.h>
+#include <linux/mm.h>
+
+#include "amigaffs.h"
+
+/*
+ * Functions for accessing Amiga-FFS structures.
+ *
+ */
+
+/* Get key entry number ENTRY_POS from the header block pointed to
+   by DATA.  If ENTRY_POS is invalid, -1 is returned.  This is
+   used to get entries from file and directory headers as well
+   as extension and root blocks.  In the current FFS specs, these
+   tables are defined to be the same size in all of these. */
+
+int affs_get_key_entry (int bsize, void *data, int entry_pos)
+{
+	struct dir_front *dir_front = (struct dir_front *)data;
+	int key, hash_table_size;
+
+	hash_table_size = MIDBLOCK_LONGS (bsize);
+	key = 0;
+	if (entry_pos >= 0 && entry_pos < hash_table_size)
+		key = swap_long (dir_front->hash_table[entry_pos]);
+
+	return key;
+}
+
+/* Find the next used hash entry at or after *HASH_POS in a directory's hash
+   table.  *HASH_POS is assigned that entry's number.  DIR_DATA points to
+   the directory header block in memory.  If there are no more entries,
+   0 is returned.  Otherwise, the key number in the next used hash slot
+   is returned. */
+
+int affs_find_next_hash_entry (int bsize, void *dir_data, int *hash_pos)
+{
+	struct dir_front *dir_front = (struct dir_front *)dir_data;
+	int i, hash_table_size;
+
+	hash_table_size = MIDBLOCK_LONGS (bsize);
+	if (*hash_pos < 0 || *hash_pos >= hash_table_size)
+		return -1;
+	for (i = *hash_pos; i < hash_table_size; i++)
+		if (dir_front->hash_table[i] != 0)
+			break;
+	if (i == hash_table_size)
+		return 0;
+	*hash_pos = i;
+	return swap_long (dir_front->hash_table[i]);
+}
+
+/* Get the hash_chain (next file header key in hash chain) entry from a
+   file header block in memory pointed to by FH_DATA. */
+
+int affs_get_fh_hash_link (int bsize, void *fh_data)
+{
+	struct file_end *file_end;
+	int key;
+
+	file_end = GET_END_PTR (struct file_end, fh_data, bsize);
+	key = swap_long (file_end->hash_chain);
+	return key;
+}
+
+/* Set *NAME to point to the file name in a file header block in memory
+   pointed to by FH_DATA.  The length of the name is returned. */
+
+int affs_get_file_name (int bsize, void *fh_data, char **name)
+{
+	struct file_end *file_end;
+
+	file_end = GET_END_PTR (struct file_end, fh_data, bsize);
+	if (file_end->file_name[0] == 0
+	    || file_end->file_name[0] > 30) {
+		printk ("affs_get_file_name: OOPS! bad filename\n");
+		printk ("  file_end->file_name[0] = %d\n",
+			file_end->file_name[0]);
+		*name = "***BAD_FILE***";
+		return 14;
+        }
+	*name = (char *) &file_end->file_name[1];
+        return file_end->file_name[0];
+}
+
+/* Get the key number of the first extention block for the file
+   header pointed to by FH_DATA. */
+
+int affs_get_extension (int bsize, void *fh_data)
+{
+	struct file_end *file_end;
+	int key;
+
+	file_end = GET_END_PTR (struct file_end, fh_data, bsize);
+	key = swap_long (file_end->extension);
+	return key;
+}
+
+/* Checksum a block, do various consistency checks and optionally return
+   the blocks type number.  DATA points to the block.  If their pointers
+   are non-null, *PTYPE and *STYPE are set to the primary and secondary
+   block types respectively.  Returns non-zero if the block is not
+   consistent. */
+
+int affs_checksum_block (int bsize, void *data, int *ptype, int *stype)
+{
+	if (ptype)
+		*ptype = swap_long (((long *) data)[0]);
+	if (stype)
+		*stype = swap_long (((long *) data)[bsize / 4 - 1]);
+	return 0;
+}
+
+static struct file_system_type affs_fs_type = {
+        affs_read_super, "affs", 1, NULL
+};
+
+int init_affs_fs(void)
+{
+        return register_filesystem(&affs_fs_type);
+}
+
diff -u --recursive --new-file v1.3.93/linux/fs/affs/amigaffs.h linux/fs/affs/amigaffs.h
--- v1.3.93/linux/fs/affs/amigaffs.h	Thu Jan  1 02:00:00 1970
+++ linux/fs/affs/amigaffs.h	Sun Feb 25 19:14:27 1996
@@ -0,0 +1,206 @@
+#ifndef AMIGAFFS_H
+#define AMIGAFFS_H
+
+/* Ugly macros to make the code pretty. */
+
+#define GET_END_PTR(st,p,sz) ((st *)((char *)(p)+((sz)-sizeof(st))))
+
+#define MIDBLOCK_LONGS(sz) ((sz - sizeof (struct dir_front) \
+			     - sizeof (struct dir_end)) / 4)
+
+static __inline__ unsigned long
+swap_long (unsigned long x)
+{
+#ifdef __i386__   /* bad check... should be endian check */
+  unsigned char *px;
+
+  px = (unsigned char *) &x;
+  return (  (px[3] <<  0)
+	  | (px[2] <<  8)
+	  | (px[1] << 16)
+	  | (px[0] << 24));
+#else
+  return x;
+#endif
+}
+
+typedef unsigned long	ULONG;
+typedef unsigned short	UWORD;
+typedef unsigned char	UBYTE;
+
+typedef long		LONG;
+typedef short		WORD;
+typedef char		BYTE;
+
+struct DateStamp
+{
+  ULONG ds_Days;
+  ULONG ds_Minute;
+  ULONG ds_Tick;
+};
+
+#define T_SHORT 	2
+#define T_LIST		16
+#define T_DATA		8
+
+#define ST_FILE 	-3
+#define ST_USERDIR	2
+#define ST_ROOT 	1
+#define ST_SOFTLINK	3
+#define ST_LINKFILE	-4
+#define ST_LINKDIR	4
+
+#define PROT_ARCHIVE        (1<<4)
+#define PROT_READ           (1<<3)
+#define PROT_WRITE          (1<<2)
+#define PROT_EXECUTE        (1<<1)
+#define PROT_DELETE         (1<<0)
+
+#define PROT_OTR_READ       (1<<15)
+#define PROT_OTR_WRITE      (1<<14)
+#define PROT_OTR_EXECUTE    (1<<13)
+#define PROT_OTR_DELETE     (1<<12)
+
+#define PROT_GRP_READ       (1<<11)
+#define PROT_GRP_WRITE      (1<<10)
+#define PROT_GRP_EXECUTE    (1<<9)
+#define PROT_GRP_DELETE     (1<<8)
+
+struct ffs_root_front
+{
+  LONG primary_type;
+  ULONG spare1[2];
+  ULONG hash_size;
+  ULONG spare2;
+  ULONG checksum;
+};
+
+struct ffs_root_end
+{
+  LONG bm_flag;
+  ULONG bm_keys[25];
+  ULONG bm_extend;
+  struct DateStamp dir_altered;
+  UBYTE disk_name[40];
+  struct DateStamp disk_altered;
+  struct DateStamp disk_made;
+  ULONG spare1[3];
+  LONG secondary_type;
+};
+
+struct dir_front
+{
+  LONG primary_type;
+  ULONG own_key;
+  ULONG spare1[3];
+  ULONG checksum;
+  ULONG hash_table[0];
+};
+
+struct dir_end
+{
+  ULONG spare1;
+  UWORD uid;
+  UWORD gid;
+  ULONG protect;
+  ULONG spare2;
+  UBYTE comment[92];
+  struct DateStamp created;
+  UBYTE dir_name[64];
+  ULONG hash_chain;
+  ULONG parent;
+  ULONG spare3;
+  LONG secondary_type;
+};
+
+struct file_front
+{
+  LONG primary_type;
+  ULONG own_key;
+  ULONG block_count;
+  ULONG unknown1;
+  ULONG first_data;
+  ULONG checksum;
+  ULONG blocks[0];
+};
+
+struct file_end
+{
+  ULONG spare1;
+  UWORD uid;
+  UWORD gid;
+  ULONG protect;
+  ULONG byte_size;
+  UBYTE comment[92];
+  struct DateStamp created;
+  UBYTE file_name[64];
+  ULONG hash_chain;
+  ULONG parent;
+  ULONG extension;
+  LONG secondary_type;
+};
+
+struct data_front
+{
+  LONG primary_type;
+  ULONG header;
+  ULONG seq_num;
+  ULONG data_size;
+  ULONG next_data;
+  ULONG checksum;
+};
+
+struct symlink_front
+{
+  LONG primary_type;
+  ULONG own_key;
+  LONG unused[3];
+  ULONG checksum;
+  UBYTE symname[0];
+};
+
+struct symlink_end
+{
+  ULONG spare1;
+  UWORD uid;
+  UWORD gid;
+  ULONG protect;
+  ULONG spare2;
+  UBYTE comment[92];
+  struct DateStamp created;
+  UBYTE link_name[64];
+  ULONG hash_chain;
+  ULONG parent;
+  ULONG spare3;
+  LONG secondary_type;
+};
+
+struct hardlink_front
+{
+  LONG primary_type;
+  ULONG own_key;
+  LONG unused[3];
+  ULONG checkksum;
+};
+
+struct hardlink_end
+{
+  ULONG spare1;
+  UWORD uid;
+  UWORD gid;
+  ULONG protect;
+  ULONG spare2;
+  UBYTE comment[92];
+  struct DateStamp created;
+  UBYTE link_name[32];
+  ULONG spare3;
+  ULONG original;
+  ULONG link_chain;
+  ULONG spare4[5];
+  ULONG hash_chain;
+  ULONG parent;
+  ULONG spare5;
+  LONG secondary_type;
+};
+
+#endif
diff -u --recursive --new-file v1.3.93/linux/fs/affs/dir.c linux/fs/affs/dir.c
--- v1.3.93/linux/fs/affs/dir.c	Thu Jan  1 02:00:00 1970
+++ linux/fs/affs/dir.c	Mon Apr  1 21:23:46 1996
@@ -0,0 +1,150 @@
+/*
+ *  linux/fs/affs/dir.c
+ *
+ *  (C) 1993  Ray Burr - Modified for Amiga FFS filesystem.
+ *
+ *  (C) 1992  Eric Youngdale Modified for ISO9660 filesystem.
+ *
+ *  (C) 1991  Linus Torvalds - minix filesystem
+ *
+ *  affs directory handling functions
+ */
+
+#include <linux/errno.h>
+
+#include <asm/segment.h>
+
+#include <linux/fs.h>
+#include <linux/affs_fs.h>
+#include <linux/kernel.h>
+#include <linux/affs_fs.h>
+#include <linux/stat.h>
+#include <linux/string.h>
+#include <linux/sched.h>
+
+static int affs_readdir(struct inode *, struct file *, void *, filldir_t);
+
+struct file_operations affs_dir_operations = {
+	NULL,			/* lseek - default */
+	NULL,			/* read */
+	NULL,			/* write - bad */
+	affs_readdir,		/* readdir */
+	NULL,			/* select - default */
+	NULL,			/* ioctl - default */
+	NULL,			/* mmap */
+	NULL,			/* no special open code */
+	NULL,			/* no special release code */
+	NULL			/* fsync */
+};
+
+/*
+ * directories can handle most operations...
+ */
+struct inode_operations affs_dir_inode_operations = {
+	&affs_dir_operations,	/* default directory file-ops */
+	NULL,			/* create */
+	affs_lookup,		/* lookup */
+	NULL,			/* link */
+	NULL,       		/* unlink */
+	NULL,       		/* symlink */
+	NULL,       		/* mkdir */
+	NULL,			/* rmdir */
+	NULL,			/* mknod */
+	NULL,			/* rename */
+	NULL,			/* readlink */
+	NULL,			/* follow_link */
+	NULL,			/* bmap */
+	NULL,			/* truncate */
+	NULL			/* permission */
+};
+
+/* This is used to speed up lookup.  Without this we would need to
+make a linear search of the directory to find the file that the
+directory read just returned.  This is a single element cache. */
+
+/* struct lookup_cache cache = {0,}; */
+
+static int affs_readdir(struct inode * inode, struct file * filp,
+	void * dirent, filldir_t filldir)
+{
+	int i, j, chain_pos, hash_pos, reclen, ino;
+	char *name;
+	struct buffer_head *dir_bh;
+	struct buffer_head *fh_bh;
+	void *dir_data;
+	void *fh_data;
+
+#ifdef DEBUG
+	printk ("AFFS: readdir: inode=%d f_pos=%d\n",
+		inode->i_ino, filp->f_pos);
+#endif
+	
+	if (!inode || !S_ISDIR(inode->i_mode))
+		return -EBADF;
+
+	while ((unsigned long)filp->f_pos < 2) {
+		if (filp->f_pos == 0) {
+			if (filldir (dirent, ".", 1, filp->f_pos, inode->i_ino) < 0)
+				return 0;
+		} else {
+			i = affs_parent_ino (inode);
+			if (filldir (dirent, "..", 2, filp->f_pos, i) < 0)
+				return 0;
+		}
+		filp->f_pos++;
+	}
+	/* No caching here.  I've got 16 megs why should I care?  :-) */
+	chain_pos = (filp->f_pos - 2) & 0xffff;
+	if (chain_pos == 0xffff)
+		return 0;
+	hash_pos = (filp->f_pos - 2) >> 16;
+#ifdef DEBUG
+	printk ("AFFS: hash_pos=%d chain_pos=%d\n", hash_pos, chain_pos);
+#endif
+	if (!(dir_bh = affs_pread(inode, inode->i_ino, &dir_data)))
+		return 0;
+	/* HASH_POS should already be on a used entry unless it is
+	   the first read of the directory.  Will this break the
+	   dirtell thing somehow? */
+	i = affs_find_next_hash_entry (AFFS_I2BSIZE (inode), dir_data,
+				       &hash_pos);
+	j = chain_pos;
+	for (;;) {
+		if (i <= 0) {
+#ifdef DEBUG
+			printk ("AFFS: bad f_pos in readdir\n");
+#endif
+			brelse (dir_bh);
+			return 0;
+		}
+		ino = i;
+		if (!(fh_bh = affs_pread (inode, i, &fh_data))) {
+			brelse (dir_bh);
+			return 0;
+		}
+		i = affs_get_fh_hash_link (AFFS_I2BSIZE (inode), fh_data);
+		if (j == 0) {
+			j = 1;
+			if (i <= 0) {
+				hash_pos++;
+				i = affs_find_next_hash_entry (AFFS_I2BSIZE (inode),
+							       dir_data, &hash_pos);
+				if (i <= 0)
+					chain_pos = 0xffff;
+				else
+					chain_pos = 0;
+			} else
+				chain_pos++;
+			reclen = affs_get_file_name (AFFS_I2BSIZE (inode),
+						     fh_data, &name);
+			if (filldir (dirent, name, reclen, filp->f_pos, ino) < 0) {
+				brelse (fh_bh);
+				brelse (dir_bh);
+				return 0;
+			}
+			filp->f_pos = ((hash_pos << 16) | chain_pos) + 2;
+		}
+		brelse (fh_bh);
+		j--;
+	}
+}
diff -u --recursive --new-file v1.3.93/linux/fs/affs/file.c linux/fs/affs/file.c
--- v1.3.93/linux/fs/affs/file.c	Thu Jan  1 02:00:00 1970
+++ linux/fs/affs/file.c	Sat Mar 30 18:37:05 1996
@@ -0,0 +1,174 @@
+/*
+ *  linux/fs/affs/file.c
+ *
+ *  (C) 1993  Ray Burr - Modified for Amiga FFS filesystem.
+ *
+ *  (C) 1992  Eric Youngdale Modified for ISO9660 filesystem.
+ *
+ *  (C) 1991  Linus Torvalds - minix filesystem
+ *
+ *  affs regular file handling primitives
+ */
+
+#include <asm/segment.h>
+#include <asm/system.h>
+
+#include <linux/sched.h>
+#include <linux/affs_fs.h>
+#include <linux/fcntl.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/stat.h>
+#include <linux/locks.h>
+
+#include <linux/dirent.h>
+
+#define	NBUF	16
+
+#define MIN(a,b) (((a)<(b))?(a):(b))
+#define MAX(a,b) (((a)>(b))?(a):(b))
+
+#include <linux/fs.h>
+#include <linux/affs_fs.h>
+
+#include "amigaffs.h"
+
+int affs_file_read(struct inode *, struct file *, char *, int);
+
+/*
+ * We have mostly NULL's here: the current defaults are ok for
+ * the affs filesystem.
+ */
+struct file_operations affs_file_operations = {
+	NULL,			/* lseek - default */
+	affs_file_read,		/* read */
+	NULL,			/* write */
+	NULL,			/* readdir - bad */
+	NULL,			/* select - default */
+	NULL,			/* ioctl - default */
+	generic_file_mmap,	/* mmap */
+	NULL,			/* no special open is needed */
+	NULL,			/* release */
+	NULL			/* can't fsync */
+};
+
+struct inode_operations affs_file_inode_operations = {
+	&affs_file_operations,	/* default file operations */
+	NULL,			/* create */
+	NULL,			/* lookup */
+	NULL,			/* link */
+	NULL,			/* unlink */
+	NULL,			/* symlink */
+	NULL,			/* mkdir */
+	NULL,			/* rmdir */
+	NULL,			/* mknod */
+	NULL,			/* rename */
+	NULL,			/* readlink */
+	NULL,			/* follow_link */
+	NULL /* affs_bmap */,		/* bmap */
+	NULL,			/* truncate */
+	NULL			/* permission */
+};
+
+static int affs_smap(struct inode *inode, int block)
+{
+	struct buffer_head *bh;
+	int key;
+	void *fh_data;
+
+/* FIXME */
+#define KEY_SLOTS_PER_BLOCK 72
+
+#ifdef DEBUG
+	printk ("affs_smap: ino=%d block=%d\n", inode->i_ino, block);
+#endif
+
+	if (block < 0) {
+		printk("affs_smap: block < 0");
+		return 0;
+	}
+
+	key = inode->i_ino;
+	for (;;) {
+		bh = affs_pread (inode, key, &fh_data);
+		if (!bh)
+			return 0;
+		if (block < KEY_SLOTS_PER_BLOCK)
+			break;
+		block -= KEY_SLOTS_PER_BLOCK;
+		key = affs_get_extension (AFFS_I2BSIZE (inode), fh_data);
+#ifdef DEBUG
+		printk ("affs_smap: reading extension block %d\n", key);
+#endif
+		brelse (bh);
+	}
+	key = affs_get_key_entry (AFFS_I2BSIZE (inode), fh_data,
+				  (KEY_SLOTS_PER_BLOCK - 1) - block);
+	brelse (bh);
+
+#ifdef DEBUG
+	printk ("affs_smap: key=%d\n", key);
+#endif
+	return key;
+}
+
+/*
+ * affs_file_read() is also needed by the directory read-routine,
+ * so it's not static. NOTE! reading directories directly is a bad idea,
+ * but has to be supported for now for compatability reasons with older
+ * versions.
+ */
+int affs_file_read(struct inode * inode, struct file * filp,
+		   char * buf, int count)
+{
+	char *start;
+	int left, offset, size, sector;
+	struct buffer_head *bh;
+	void *data;
+
+	if (!inode) {
+		printk("affs_file_read: inode = NULL\n");
+		return -EINVAL;
+	}
+	if (!(S_ISREG(inode->i_mode))) {
+#ifdef DEBUG
+		printk("affs_file_read: mode = %07o\n",inode->i_mode);
+#endif
+		return -EINVAL;
+	}
+	if (filp->f_pos >= inode->i_size || count <= 0)
+		return 0;
+
+	start = buf;
+	for (;;) {
+		left = MIN (inode->i_size - filp->f_pos,
+			    count - (buf - start));
+		if (!left)
+			break;
+		sector = affs_smap (inode, filp->f_pos >> AFFS_BLOCK_BITS);
+		if (!sector)
+			break;
+		offset = filp->f_pos & (AFFS_BLOCK_SIZE - 1);
+		bh = affs_pread (inode, sector, &data);
+		if (!bh)
+			break;
+		size = MIN (AFFS_BLOCK_SIZE - offset, left);
+		filp->f_pos += size;
+		memcpy_tofs (buf, data + offset, size);
+		buf += size;
+		brelse (bh);
+	}
+	if (start == buf)
+		return -EIO;
+	return buf - start;
+
+#if 0
+	if (filp->f_pos == 0 && count > 0) {
+		put_fs_byte ('X', buf++);
+		filp->f_pos++;
+		return 1;
+	}
+	else
+		return 0;
+#endif
+}
diff -u --recursive --new-file v1.3.93/linux/fs/affs/inode.c linux/fs/affs/inode.c
--- v1.3.93/linux/fs/affs/inode.c	Thu Jan  1 02:00:00 1970
+++ linux/fs/affs/inode.c	Wed Mar 20 20:01:47 1996
@@ -0,0 +1,431 @@
+/*
+ *  linux/fs/affs/inode.c
+ *
+ *  (C) 1994  Geert Uytterhoeven - Modified for MultiUserFileSystem
+ *
+ *  (C) 1993  Ray Burr - Modified for Amiga FFS filesystem.
+ *
+ *  (C) 1992  Eric Youngdale Modified for ISO9660 filesystem.
+ *
+ *  (C) 1991  Linus Torvalds - minix filesystem
+ */
+
+#include <linux/stat.h>
+#include <linux/sched.h>
+#include <linux/affs_fs.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/locks.h>
+
+#include <asm/system.h>
+#include <asm/segment.h>
+#include <linux/errno.h>
+
+#include <linux/genhd.h>
+
+#include "amigaffs.h"
+
+extern int check_cdrom_media_change(int, int);
+
+#ifdef LEAK_CHECK
+static int check_malloc = 0;
+static int check_bread = 0;
+#endif
+
+void affs_put_super(struct super_block *sb)
+{
+	lock_super(sb);
+
+#ifdef LEAK_CHECK
+	printk("Outstanding mallocs:%d, outstanding buffers: %d\n",
+	       check_malloc, check_bread);
+#endif
+	sb->s_dev = 0;
+	unlock_super(sb);
+	return;
+}
+
+static struct super_operations affs_sops = {
+	affs_read_inode,
+	NULL,			/* notify_change */
+	NULL,			/* write_inode */
+	NULL,			/* put_inode */
+	affs_put_super,
+	NULL,			/* write_super */
+	affs_statfs,
+	NULL			/* remount */
+};
+
+int affs_parent_ino(struct inode *dir)
+{
+	int root_ino = (dir->i_sb->u.affs_sb.s_root_block
+			- dir->i_sb->u.affs_sb.s_partition_offset);
+
+	if (!S_ISDIR (dir->i_mode)) {
+		printk ("affs_parent_ino: argument is not a directory\n");
+		return root_ino;
+	}
+	if (dir->i_ino == root_ino)
+		return root_ino;
+	return dir->u.affs_i.i_parent;
+}
+
+static int parse_options(char *options, struct affs_options *optp)
+{
+	char *this_opt,*value,*end;
+	int n;
+
+	optp->offset = 0;
+	optp->size = 0;
+	optp->root = 0;
+	optp->conv_links = 0;
+
+	if (!options)
+		return 1;
+	for (this_opt = strtok(options,","); this_opt; this_opt = strtok(NULL,",")) {
+		if ((value = strchr(this_opt,'='))) *value++ = 0;
+
+		if (!strcmp(this_opt,"offset") && value) {
+			n = simple_strtoul (value, &end, 10);
+			if (end == value || *end != 0)
+				return 0;
+			optp->offset = n;
+		}
+		else if (!strcmp(this_opt,"size") && value) {
+			n = simple_strtoul (value, &end, 10);
+			if (end == value || *end != 0 || n <= 0)
+				return 0;
+			optp->size = n;
+		}
+		else if (!strcmp(this_opt,"root") && value) {
+			n = simple_strtoul (value, &end, 10);
+			if (end == value || *end != 0 || n <= 0)
+				return 0;
+			optp->root = n;
+		}
+		else if (!strcmp(this_opt,"conv_symlinks")) {
+			optp->conv_links = 1;
+		}
+		else return 0;
+	}
+	return 1;
+}
+
+/* Is this The Right Way?  Should I be locking something? */
+
+static int get_device_size (dev_t dev)
+{
+	struct gendisk *gd_p;
+	int dev_size = 0;
+
+	for (gd_p = gendisk_head ; gd_p ; gd_p=gd_p->next) {
+		if (gd_p->major != MAJOR(dev))
+			continue;
+		dev_size = gd_p->part[MINOR(dev)].nr_sects;
+		break;
+	}
+	return dev_size;
+}
+
+struct super_block *affs_read_super(struct super_block *s,void *data,
+				    int silent)
+{
+	struct buffer_head *bh;
+	int dev = s->s_dev;
+	int root_block;
+	int ptype, stype;
+	void *root_data;
+	struct affs_options *optp;
+
+	optp = &s->u.affs_sb.s_options;
+
+	if (!parse_options((char *) data, optp)) {
+		s->s_dev = 0;
+		printk ("AFFS: bad mount options\n");
+		return NULL;
+	}
+
+	lock_super(s);
+
+	root_block = 0;
+	if (optp->size) {
+		s->u.affs_sb.s_partition_size = optp->size;
+	}
+	else {
+		int size = get_device_size (dev);
+		if (size == 0) {
+			s->s_dev = 0;
+			unlock_super(s);
+			printk ("affs_read_super: could not"
+				"determine device size\n");
+		}
+		s->u.affs_sb.s_partition_size = size;
+	}
+
+	s->u.affs_sb.s_partition_offset = optp->offset;
+	root_block = optp->root;
+
+	if (!root_block)
+		root_block = (s->u.affs_sb.s_partition_offset
+			      + s->u.affs_sb.s_partition_size / 2
+			      + (s->u.affs_sb.s_partition_size & 1));
+	s->u.affs_sb.s_root_block = root_block;
+
+	s->u.affs_sb.s_block_size = AFFS_BLOCK_SIZE;
+
+#if 0
+	printk ("affs_read_super: dev=0x%04x offset=%d "
+		"size=%d root=%d blocksize=%d\n",
+		dev,
+		s->u.affs_sb.s_partition_offset,
+		s->u.affs_sb.s_partition_size,
+		s->u.affs_sb.s_root_block,
+		s->u.affs_sb.s_block_size);
+#endif
+
+	bh = affs_sread (dev, root_block, &root_data);
+	if (!bh) {
+		s->s_dev = 0;
+		unlock_super(s);
+		printk ("AFFS: unable to read superblock\n");
+		return NULL;
+	}
+
+	if (affs_checksum_block (AFFS_BLOCK_SIZE, root_data, &ptype, &stype)
+	    || ptype != T_SHORT || stype != ST_ROOT) {
+		printk ("AFFS: invalid root block %d on device 0x%04x\n",
+			root_block, dev);
+		goto out;
+	}
+
+#if 1
+{
+	char *name;
+	int len;
+	char buf[33];
+	len = affs_get_file_name (AFFS_BLOCK_SIZE, root_data, &name);
+	memcpy (buf,name,len);
+	buf[len] = 0;
+#if 0
+	printk ("affs_read_super: volume name \"%s\"\n", buf);
+#endif
+}
+#endif
+
+	s->s_magic = AFFS_SUPER_MAGIC;
+
+	s->s_flags = MS_RDONLY | MS_NODEV | MS_NOSUID;
+
+	brelse(bh);
+
+	/* set up enough so that it can read an inode */
+	s->s_dev = dev;
+	s->s_op = &affs_sops;
+	s->s_blocksize = AFFS_BUFFER_SIZE;
+	s->s_mounted = iget (s, root_block - s->u.affs_sb.s_partition_offset);
+
+	unlock_super(s);
+
+	if (!(s->s_mounted)) {
+		s->s_dev = 0;
+		printk("AFFS: get root inode failed\n");
+		return NULL;
+	}
+
+	return s;
+
+ out: /* Kick out for various error conditions */
+	brelse (bh);
+	s->s_dev = 0;
+	unlock_super(s);
+	return NULL;
+}
+
+void affs_statfs (struct super_block *sb, struct statfs *buf, int bufsiz)
+{
+#ifdef DEBUG
+	printk ("AFFS: affs_statfs called\n");
+#endif
+	put_fs_long(AFFS_SUPER_MAGIC, &buf->f_type);
+	put_fs_long(sb->u.affs_sb.s_block_size, &buf->f_bsize);
+	put_fs_long(sb->u.affs_sb.s_partition_size, &buf->f_blocks);
+	put_fs_long(0, &buf->f_bfree);
+	put_fs_long(0, &buf->f_bavail);
+	put_fs_long(0, &buf->f_files);
+	put_fs_long(0, &buf->f_ffree);
+	/* Don't know what value to put in buf->f_fsid */
+}
+
+static int prot_table[9][2] = {
+	{PROT_OTR_EXECUTE, PROT_OTR_EXECUTE},	/* other: 1 = allowed */
+	{PROT_OTR_WRITE, PROT_OTR_WRITE},
+	{PROT_OTR_READ, PROT_OTR_READ},
+	{PROT_GRP_EXECUTE, PROT_GRP_EXECUTE},	/* group: 1 = allowed */
+	{PROT_GRP_WRITE, PROT_GRP_WRITE},
+	{PROT_GRP_READ, PROT_GRP_READ},
+	{PROT_EXECUTE, 0},			/* owner: 0 = allowed */
+	{PROT_WRITE, 0},
+	{PROT_READ, 0}
+};
+
+void affs_read_inode(struct inode * inode)
+{
+	struct buffer_head *bh;
+	int block;
+	void *fh_data;
+	struct file_front *file_front;
+	struct file_end *file_end;
+	int i;
+	struct hardlink_end *link_end;
+	int link;	
+
+#ifdef DEBUG
+	printk ("AFFS: entering affs_read_inode\n");
+#endif
+
+	inode->i_nlink = 1; /* at least */
+	do {
+		link = 0;
+		block = inode->i_ino;
+		if (!(bh=affs_pread (inode, block, &fh_data))) {
+			printk("AFFS: unable to read i-node block %d\n", block);
+			return;
+		}
+
+		file_front = (struct file_front *) fh_data;
+		file_end = GET_END_PTR (struct file_end, fh_data, /* coincidendly the same as  dir_end */
+					AFFS_I2BSIZE (inode));
+
+		/* don't use bitmap data for mode, uid & gid of the rootblock */
+		if (block == inode->i_sb->u.affs_sb.s_root_block) {
+			inode->u.affs_i.i_protect = 0;
+			inode->u.affs_i.i_parent = block;
+
+			inode->i_mode = S_IRWXUGO | S_IFDIR | S_ISVTX ;  /* drwxrwxrwt */
+			inode->i_nlink = 2; /* at least ..... */
+
+			inode->i_size = 0;  /* some differrent idea ? */
+
+			inode->i_uid = 0;
+			inode->i_gid = 0;
+		}
+		else { 
+
+			inode->u.affs_i.i_protect = file_end->protect;
+			inode->u.affs_i.i_parent = swap_long (file_end->parent);
+
+			inode->i_mode = 0;
+			for (i = 0; i < 9; i++)
+				if ((prot_table[i][0] & inode->u.affs_i.i_protect) == prot_table[i][1])
+					inode->i_mode |= 1<<i;
+			switch(swap_long(file_end->secondary_type)) {
+				case ST_USERDIR:
+					inode->i_mode |= ((inode->i_mode & 0444)>>2) | S_IFDIR;
+
+					inode->i_nlink++; /* There are always at least 2.  It is
+							       hard to figure out what is correct*/
+					inode->i_size = 0;
+				break;
+				case ST_SOFTLINK:
+					inode->i_mode |= S_IFLNK;
+					inode->i_size  = 0;
+				break;
+				case ST_LINKFILE:   /* doing things very easy (not really correct) */
+				case ST_LINKDIR:    /* code is _very_ inefficient (see below) */
+
+				  /* Where is struct link_end defined?
+				     ... I don't know what is going on
+				     here, someone else should
+				     probably spend some time on this */
+					link_end = (struct hardlink_end *)file_end;
+					inode->i_ino = link_end->original;
+					inode->i_nlink += 2; /* It's hard to say whats correct */
+					brelse(bh);
+					link = 1;
+				break;
+				default:
+					printk("affs: unknown secondary type %ld; assuming file\n",
+						file_end->secondary_type);
+				case ST_FILE:
+					inode->i_mode |= S_IFREG;
+					inode->i_size = swap_long (file_end->byte_size);
+				break;
+				}
+			if (file_end->uid == 0xffff)
+				inode->i_uid = 0;	/* root uid */
+			else if (file_end->uid == 0x0000) {
+				umode_t mode;
+				inode->i_uid = -1;	/* unknown uid */
+
+				/*
+				 * change the mode of the inode to duplicate the
+				 * perms of the user in the group and other fields;
+				 * the assumption is that this isn't a MultiUser
+				 * filesystem/file, so the permissions should be
+				 * the same for all users
+				 */
+				mode = (inode->i_mode >> 6) & 7;
+				inode->i_mode |= (mode << 3) | (mode);
+			} else
+				inode->i_uid = file_end->uid;
+			if (file_end->gid == 0xffff)
+				inode->i_gid = 0;	/* root gid */
+			else if (file_end->gid == 0x0000)
+				inode->i_gid = -1;	/* unknown gid */
+			else
+				inode->i_gid = file_end->gid;
+		}
+	}
+	while (link);
+
+#ifdef DEBUG
+	printk ("AFFS: read inode %d: size=%d\n", block, inode->i_size);
+#endif
+	inode->i_mtime = inode->i_atime = inode->i_ctime
+		= (swap_long (file_end->created.ds_Days) * (24 * 60 * 60)
+		   + swap_long (file_end->created.ds_Minute) * 60
+		   + swap_long (file_end->created.ds_Tick) / 50
+		   + ((8 * 365 + 2) * 24 * 60 * 60));
+
+	brelse(bh);
+
+	inode->i_op = NULL;
+	if (S_ISREG(inode->i_mode))
+		inode->i_op = &affs_file_inode_operations;
+	else if (S_ISDIR(inode->i_mode))
+		inode->i_op = &affs_dir_inode_operations;
+	else if (S_ISLNK(inode->i_mode))
+		inode->i_op = &affs_symlink_inode_operations;
+}
+
+
+#ifdef LEAK_CHECK
+#undef malloc
+#undef free_s
+#undef bread
+#undef brelse
+
+void * leak_check_malloc(unsigned int size){
+  void * tmp;
+  check_malloc++;
+  tmp = kmalloc(size, GFP_ATOMIC);
+  return tmp;
+}
+
+void leak_check_free_s(void * obj, int size){
+  check_malloc--;
+  return kfree_s(obj, size);
+}
+
+struct buffer_head * leak_check_bread(int dev, int block, int size){
+  check_bread++;
+  return bread(dev, block, size);
+}
+
+void leak_check_brelse(struct buffer_head * bh){
+  check_bread--;
+  return brelse(bh);
+}
+
+#endif
diff -u --recursive --new-file v1.3.93/linux/fs/affs/namei.c linux/fs/affs/namei.c
--- v1.3.93/linux/fs/affs/namei.c	Thu Jan  1 02:00:00 1970
+++ linux/fs/affs/namei.c	Sun Feb 25 19:14:29 1996
@@ -0,0 +1,187 @@
+/*
+ *  linux/fs/affs/namei.c
+ *
+ *  (C) 1993  Ray Burr - Modified for Amiga FFS filesystem.
+ *
+ *  (C) 1992  Eric Youngdale Modified for ISO9660 filesystem.
+ *
+ *  (C) 1991  Linus Torvalds - minix filesystem
+ */
+
+#include <linux/sched.h>
+#include <linux/affs_fs.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/stat.h>
+#include <linux/fcntl.h>
+#include <asm/segment.h>
+
+#include <linux/errno.h>
+
+
+static inline int namecompare(int len, int maxlen,
+	const char * name, const char * buffer)
+{
+	if (len >= maxlen || !buffer[len]) {
+		return strncmp (name, buffer, len) == 0;
+	}
+	return 0;
+}
+
+/*
+ * ok, we cannot use strncmp, as the name is not in our data space.
+ * Thus we'll have to use affs_match. No big problem. Match also makes
+ * some sanity tests.
+ *
+ * NOTE! unlike strncmp, affs_match returns 1 for success, 0 for failure.
+ */
+static int affs_match(int len,const char * name, char * compare, int dlen)
+{
+	if (!compare) return 0;
+
+	/* "" means "." ---> so paths like "/usr/lib//libc.a" work */
+	if (!len && dlen == 1 && compare[0] == '.')
+		return 1;
+	
+#if 0
+	if (len <= 2) printk("Match: %d %d %s %d %d \n",len,dlen,compare,de->name[0], dlen);
+#endif
+	
+	return namecompare(len,dlen,name,compare);
+}
+
+/* Avoid pulling in ctype stuff. */
+
+static int affs_toupper (int ch)
+{
+	if (ch >= 'a' && ch <= 'z')
+		ch -= ('a' - 'A');
+	return ch;
+}
+
+static int affs_hash_name (const char *name, int len)
+{
+	int i, x;
+
+	x = len;
+	for (i = 0; i < len; i++)
+		x = (x * 13 + affs_toupper (name[i])) & 0x7ff;
+	return x % 72;  /* FIXME: Assumes 512 byte blocks. */
+}
+
+static struct buffer_head *affs_find_entry(struct inode *dir,
+	const char *name, int namelen, int *ino)
+{
+	struct buffer_head *bh;
+	void *dir_data;
+	int key;
+
+	*ino = 0;
+
+	bh = affs_pread (dir, dir->i_ino, &dir_data);
+	if (!bh)
+		return NULL;
+
+	if (affs_match (namelen, name, ".", 1)) {
+		*ino = dir->i_ino;
+		return bh;
+	}
+	if (affs_match (namelen, name, "..", 2)) {
+		*ino = affs_parent_ino (dir);
+		return bh;
+	}
+	key = affs_get_key_entry (AFFS_I2BSIZE (dir), dir_data,
+				  affs_hash_name (name, namelen));
+
+	for (;;) {
+		char *cname;
+		int cnamelen;
+
+		brelse (bh);
+		if (key <= 0)
+			return NULL;
+		bh = affs_pread (dir, key, &dir_data);
+		if (!bh)
+			return NULL;
+		cnamelen = affs_get_file_name (AFFS_I2BSIZE (dir),
+					       dir_data, &cname);
+		if (affs_match (namelen, name, cname, cnamelen))
+			break;
+		key = affs_get_fh_hash_link (AFFS_I2BSIZE (dir), dir_data);
+	}
+		
+	*ino = key;
+
+	return bh;
+}
+
+int affs_lookup(struct inode * dir,const char * name, int len,
+	struct inode ** result)
+{
+	int ino;
+	struct buffer_head *bh;
+
+	*result = NULL;
+	if (!dir)
+		return -ENOENT;
+
+#ifdef DEBUG
+	printk ("lookup: %d %d\n", dir->i_ino, len);
+#endif
+
+	if (!S_ISDIR(dir->i_mode)) {
+		iput(dir);
+		return -ENOENT;
+	}
+	if (!(bh = affs_find_entry(dir, name, len, &ino))) {
+	  iput(dir);
+	  return -ENOENT;
+	}
+	brelse(bh);
+	if (!(*result = iget(dir->i_sb, ino))) {
+		iput(dir);
+		return -EACCES;
+	}
+	iput (dir);
+	return 0;
+
+#if 0
+	ino = 0;
+	while(cache.lock);
+	cache.lock = 1;
+	if (dir->i_dev == cache.dev && 
+	    dir->i_ino == cache.dir &&
+	    len == cache.dlen && 
+	    affs_match(len, name, cache.filename, cache.dlen))
+	  {
+	    ino = cache.ino;
+	    ino_back = dir->i_ino;
+	    /* These two cases are special, but since they are at the start
+	       of the directory, we can just as easily search there */
+	    if (cache.dlen == 1 && cache.filename[0] == '.') ino = 0;
+	    if (cache.dlen == 2 && cache.filename[0] == '.' && 
+		cache.filename[1] == '.') ino = 0;
+	  };
+	cache.lock = 0;
+
+	if (!ino) {
+	  if (!(bh = affs_find_entry(dir,name,len, &ino, &ino_back))) {
+	    iput(dir);
+	    return -ENOENT;
+	  }
+	  brelse(bh);
+	};
+
+	if (!(*result = iget(dir->i_sb,ino))) {
+		iput(dir);
+		return -EACCES;
+	}
+
+	/* We need this backlink for the .. entry */
+	
+	if (ino_back) (*result)->u.affs_i.i_backlink = ino_back; 
+	
+	iput(dir);
+	return 0;
+#endif
+}
diff -u --recursive --new-file v1.3.93/linux/fs/affs/symlink.c linux/fs/affs/symlink.c
--- v1.3.93/linux/fs/affs/symlink.c	Thu Jan  1 02:00:00 1970
+++ linux/fs/affs/symlink.c	Sun Feb 25 19:14:29 1996
@@ -0,0 +1,179 @@
+/*
+ *  linux/fs/affs/symlink.c
+ *
+ *  (C) 1995  Joerg Dorchain Modified for Amiga FFS filesystem
+ *            based on:
+ *
+ *  (C) 1992  Eric Youngdale Modified for ISO9660 filesystem.
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ *
+ *  isofs symlink handling code.  This is only used with the Rock Ridge
+ *  extensions to iso9660
+ */
+
+#include <asm/segment.h>
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/stat.h>
+#include <linux/malloc.h>
+#include <linux/affs_fs.h>
+
+#include "amigaffs.h"
+
+static int affs_readlink(struct inode *, char *, int);
+static int affs_follow_link(struct inode *, struct inode *, int, int, struct inode **);
+
+/*
+ * symlinks can't do much...
+ */
+struct inode_operations affs_symlink_inode_operations = {
+	NULL,			/* no file-operations */
+	NULL,			/* create */
+	NULL,			/* lookup */
+	NULL,			/* link */
+	NULL,			/* unlink */
+	NULL,			/* symlink */
+	NULL,			/* mkdir */
+	NULL,			/* rmdir */
+	NULL,			/* mknod */
+	NULL,			/* rename */
+	affs_readlink,		/* readlink */
+	affs_follow_link,	/* follow_link */
+	NULL,			/* bmap */
+	NULL,			/* truncate */
+	NULL			/* permission */
+};
+
+static int affs_follow_link(struct inode * dir, struct inode * inode,
+	int flag, int mode, struct inode ** res_inode)
+{
+	int error;
+	char * pnt;
+	struct buffer_head *bh;
+	struct symlink_front *sy_data;
+
+	if (!dir) {
+		dir = current->fs->root;
+		dir->i_count++;
+	}
+	if (!inode) {
+		iput(dir);
+		*res_inode = NULL;
+		return -ENOENT;
+	}
+	if (!S_ISLNK(inode->i_mode)) {
+		iput(dir);
+		*res_inode = inode;
+		return 0;
+	}
+	if (current->link_count > 5) {
+		iput(dir);
+		iput(inode);
+		*res_inode = NULL;
+		return -ELOOP;
+	}
+	if (!(bh = affs_pread(inode,inode->i_ino,(void **)&sy_data))) {
+		printk("affs: unable to read block %ld",inode->i_ino);
+		return 0;
+	}
+
+	pnt = sy_data->symname;
+	iput(inode);
+	current->link_count++;
+	error = open_namei(pnt,flag,mode,res_inode,dir);
+	current->link_count--;
+	brelse(bh);
+	return error;
+}
+
+static char *affs_conv_path(char *affs_path)
+{
+static char unix_path[1024]="/";
+int up,ap;
+char dp,slash;
+
+
+dp=1;
+slash=1;
+ap=0;
+up=1;
+if (affs_path[0] == 0)
+  unix_path[up++]='.';
+while ((up < 1020) && (affs_path[ap]!=0))
+ {
+  switch (affs_path[ap]) {
+    case ':':
+      if (dp == 0) {
+        slash=0;
+        unix_path[up++]=':';
+      }
+      else {
+        dp=0;
+        slash=1;
+        unix_path[up++]='/';
+      }
+      break;
+    case '/':
+      if (slash==0) {
+        slash=1;
+        unix_path[up++]='/';
+      }
+      else {
+        unix_path[up++]='.';
+        unix_path[up++]='.';
+        unix_path[up++]='/';
+      }
+      break;
+    default:
+      slash=0;
+      unix_path[up++]=affs_path[ap];
+      break;
+  }
+  ap++;
+ }
+unix_path[up]=0;
+return unix_path+dp;
+}
+
+
+static int affs_readlink(struct inode * inode, char * buffer, int buflen)
+{
+        char * pnt;
+	int i;
+	char c;
+	struct buffer_head *bh;
+	struct symlink_front *sy_data;
+
+	if (!S_ISLNK(inode->i_mode)) {
+		iput(inode);
+		return -EINVAL;
+	}
+
+	if (buflen > 1023)
+		buflen = 1023;
+	
+	if (!(bh = affs_pread(inode,inode->i_ino,(void **)&sy_data))) {
+		printk("affs: unable to read block %ld\n",inode->i_ino);
+		return -ENOENT;
+	}
+	
+	iput(inode);
+
+	pnt = sy_data->symname;
+	if (inode->i_sb->u.affs_sb.s_options.conv_links != 0)
+	  pnt = affs_conv_path(pnt);
+
+	i = 0;
+
+	while (i<buflen && (c = pnt[i])) {
+		i++;
+		put_fs_byte(c,buffer++);
+	}
+	
+	brelse(bh);
+
+	return i;
+}
diff -u --recursive --new-file v1.3.93/linux/fs/filesystems.c linux/fs/filesystems.c
--- v1.3.93/linux/fs/filesystems.c	Sat Mar  9 13:31:43 1996
+++ linux/fs/filesystems.c	Mon Apr 22 10:59:39 1996
@@ -22,6 +22,7 @@
 #include <linux/hpfs_fs.h>
 #include <linux/smb_fs.h>
 #include <linux/ncp_fs.h>
+#include <linux/ufs_fs.h>
 #include <linux/major.h>
 
 extern void device_setup(void);
@@ -98,6 +99,10 @@
 
 #ifdef CONFIG_HPFS_FS
 	init_hpfs_fs();
+#endif
+
+#ifdef CONFIG_UFS_FS
+	init_ufs_fs();
 #endif
 
 	mount_root();
diff -u --recursive --new-file v1.3.93/linux/fs/minix/truncate.c linux/fs/minix/truncate.c
--- v1.3.93/linux/fs/minix/truncate.c	Thu Jan  4 14:07:58 1996
+++ linux/fs/minix/truncate.c	Mon Apr 22 11:47:49 1996
@@ -15,8 +15,9 @@
 
 #define DIRECT_BLOCK		((inode->i_size + 1023) >> 10)
 #define INDIRECT_BLOCK(offset)	(DIRECT_BLOCK-offset)
-#define DINDIRECT_BLOCK(offset) ((DIRECT_BLOCK-offset)>>9)
-#define TINDIRECT_BLOCK(offset)	((DIRECT_BLOCK-(offset))>>9)
+#define V1_DINDIRECT_BLOCK(offset) ((DIRECT_BLOCK-offset)>>9)
+#define V2_DINDIRECT_BLOCK(offset) ((DIRECT_BLOCK-offset)>>8)
+#define TINDIRECT_BLOCK(offset) ((DIRECT_BLOCK-(offset))>>8)
 
 /*
  * Truncate has the most races in the whole filesystem: coding it is
@@ -147,10 +148,10 @@
 		return 0;
 	}
 repeat:
-	for (i = DINDIRECT_BLOCK(offset) ; i < 512 ; i ++) {
+	for (i = V1_DINDIRECT_BLOCK(offset) ; i < 512 ; i ++) {
 		if (i < 0)
 			i = 0;
-		if (i < DINDIRECT_BLOCK(offset))
+		if (i < V1_DINDIRECT_BLOCK(offset))
 			goto repeat;
 		dind = i+(unsigned short *) dind_bh->b_data;
 		retry |= V1_trunc_indirect(inode,offset+(i<<9),dind);
@@ -309,13 +310,13 @@
 		return 0;
 	}
 repeat:
-	for (i = DINDIRECT_BLOCK(offset) ; i < 256 ; i ++) {
+	for (i = V2_DINDIRECT_BLOCK(offset) ; i < 256 ; i ++) {
 		if (i < 0)
 			i = 0;
-		if (i < DINDIRECT_BLOCK(offset))
+		if (i < V2_DINDIRECT_BLOCK(offset))
 			goto repeat;
 		dind = i+(unsigned long *) dind_bh->b_data;
-		retry |= V2_trunc_indirect(inode,offset+(i<<9),dind);
+		retry |= V2_trunc_indirect(inode,offset+(i<<8),dind);
 		mark_buffer_dirty(dind_bh, 1);
 	}
 	dind = (unsigned long *) dind_bh->b_data;
@@ -360,7 +361,7 @@
                 if (i < TINDIRECT_BLOCK(offset))
                         goto repeat;
                 tind = i+(unsigned long *) tind_bh->b_data;
-                retry |= V2_trunc_dindirect(inode,offset+(i<<9),tind);
+                retry |= V2_trunc_dindirect(inode,offset+(i<<8),tind);
                 mark_buffer_dirty(tind_bh, 1);
 	}
         tind = (unsigned long *) tind_bh->b_data;
diff -u --recursive --new-file v1.3.93/linux/fs/proc/array.c linux/fs/proc/array.c
--- v1.3.93/linux/fs/proc/array.c	Fri Apr 19 10:08:01 1996
+++ linux/fs/proc/array.c	Mon Apr 22 11:29:09 1996
@@ -180,11 +180,11 @@
 	a = avenrun[0] + (FIXED_1/200);
 	b = avenrun[1] + (FIXED_1/200);
 	c = avenrun[2] + (FIXED_1/200);
-	return sprintf(buffer,"%d.%02d %d.%02d %d.%02d %d/%d\n",
+	return sprintf(buffer,"%d.%02d %d.%02d %d.%02d %d/%d %d\n",
 		LOAD_INT(a), LOAD_FRAC(a),
 		LOAD_INT(b), LOAD_FRAC(b),
 		LOAD_INT(c), LOAD_FRAC(c),
-		nr_running, nr_tasks);
+		nr_running, nr_tasks, last_pid);
 }
 
 static int get_kstat(char * buffer)
diff -u --recursive --new-file v1.3.93/linux/fs/super.c linux/fs/super.c
--- v1.3.93/linux/fs/super.c	Sun Apr 21 12:39:02 1996
+++ linux/fs/super.c	Mon Apr 22 10:59:39 1996
@@ -540,7 +540,7 @@
  * filesystems which don't use real block-devices.  -- jrs
  */
 
-static unsigned int unnamed_dev_in_use[256/32] = { 0, };
+static unsigned int unnamed_dev_in_use[256/(8*sizeof(unsigned int))] = { 0, };
 
 kdev_t get_unnamed_dev(void)
 {
diff -u --recursive --new-file v1.3.93/linux/fs/ufs/Makefile linux/fs/ufs/Makefile
--- v1.3.93/linux/fs/ufs/Makefile	Thu Jan  1 02:00:00 1970
+++ linux/fs/ufs/Makefile	Mon Apr 22 10:59:39 1996
@@ -0,0 +1,15 @@
+#
+# Makefile for the linux ufs-filesystem routines.
+#
+# 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 := ufs.o
+O_OBJS   := ufs_dir.o ufs_file.o ufs_inode.o ufs_namei.o \
+		ufs_super.o ufs_symlink.o
+M_OBJS   := $(O_TARGET)
+
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.93/linux/fs/ufs/ufs_dir.c linux/fs/ufs/ufs_dir.c
--- v1.3.93/linux/fs/ufs/ufs_dir.c	Thu Jan  1 02:00:00 1970
+++ linux/fs/ufs/ufs_dir.c	Mon Apr 22 10:59:39 1996
@@ -0,0 +1,196 @@
+/*
+ *  linux/fs/ufs/ufs_dir.c
+ *
+ * Copyright (C) 1996
+ * Adrian Rodriguez (adrian@franklins-tower.rutgers.edu)
+ * Laboratory for Computer Science Research Computing Facility
+ * Rutgers, The State University of New Jersey
+ *
+ * $Id: ufs_dir.c,v 1.1 1996/04/21 14:41:04 davem Exp $
+ *
+ */
+
+#include <linux/fs.h>
+
+/* XXX */
+extern int ufs_lookup();
+extern int ufs_bmap();
+
+static int ufs_dir_read (struct inode * inode, struct file * filp,
+	                 char * buf, int count)
+{
+	/* XXX - probably allow this for root, EISDIR for normal users */
+	return -EISDIR;
+}
+
+/*
+ * This is blatantly stolen from ext2fs
+ */
+static int
+ufs_readdir (struct inode * inode, struct file * filp, void * dirent,
+	     filldir_t filldir)
+{
+	int error = 0;
+	unsigned long offset, lblk, blk;
+	int i, stored;
+	struct buffer_head * bh;
+	struct direct * de;
+	struct super_block * sb;
+
+	if (!inode || !S_ISDIR(inode->i_mode))
+		return -EBADF;
+	sb = inode->i_sb;
+
+	if (inode->i_sb->u.ufs_sb.s_flags & UFS_DEBUG) {
+	        printk("ufs_readdir: ino %lu  f_pos %lu\n",
+	               inode->i_ino, filp->f_pos);
+	        ufs_print_inode(inode);
+	}
+
+	stored = 0;
+	bh = NULL;
+	offset = filp->f_pos & (sb->s_blocksize - 1);
+
+	while (!error && !stored && filp->f_pos < inode->i_size) {
+		lblk = (filp->f_pos) >> sb->s_blocksize_bits;
+	        blk = ufs_bmap(inode, lblk);
+	        /* XXX - ufs_bmap() call needs error checking */
+	        blk = ufs_bmap(inode, lblk);
+		bh = bread (sb->s_dev, blk, sb->s_blocksize);
+		if (!bh) {
+	                /* XXX - error - skip to the next block */
+	                printk("ufs_readdir: dir inode %lu has a hole at offset %lu\n",
+	                       inode->i_ino, (unsigned long int)filp->f_pos);
+			filp->f_pos += sb->s_blocksize - offset;
+			continue;
+		}
+
+revalidate:
+		/* If the dir block has changed since the last call to
+		 * readdir(2), then we might be pointing to an invalid
+		 * dirent right now.  Scan from the start of the block
+		 * to make sure. */
+		if (filp->f_version != inode->i_version) {
+			for (i = 0; i < sb->s_blocksize && i < offset; ) {
+				de = (struct direct *) 
+					(bh->b_data + i);
+				/* It's too expensive to do a full
+				 * dirent test each time round this
+				 * loop, but we do have to test at
+				 * least that it is non-zero.  A
+				 * failure will be detected in the
+				 * dirent test below. */
+				if (de->d_reclen < 1)
+					break;
+				i += de->d_reclen;
+			}
+			offset = i;
+			filp->f_pos = (filp->f_pos & ~(sb->s_blocksize - 1))
+				| offset;
+			filp->f_version = inode->i_version;
+		}
+		
+		while (!error && filp->f_pos < inode->i_size 
+		       && offset < sb->s_blocksize) {
+			de = (struct direct *) (bh->b_data + offset);
+	                /* XXX - put in a real ufs_check_dir_entry() */
+	                if ((de->d_reclen == 0) || (de->d_namlen == 0)) {
+	                        filp->f_pos = filp->f_pos & (sb->s_blocksize - 1) + sb->s_blocksize;
+	                        brelse(bh);
+	                        return stored;
+	                }
+#if 0
+			if (!ext2_check_dir_entry ("ext2_readdir", inode, de,
+						   bh, offset)) {
+				/* On error, skip the f_pos to the
+	                           next block. */
+				filp->f_pos = (filp->f_pos & (sb->s_blocksize - 1))
+					      + sb->s_blocksize;
+				brelse (bh);
+				return stored;
+			}
+#endif /* XXX */
+			offset += de->d_reclen;
+			if (de->d_ino) {
+				/* We might block in the next section
+				 * if the data destination is
+				 * currently swapped out.  So, use a
+				 * version stamp to detect whether or
+				 * not the directory has been modified
+				 * during the copy operation. */
+				unsigned long version;
+				dcache_add(inode, de->d_name, de->d_namlen,
+	                                   de->d_ino);
+				version = inode->i_version;
+	                        if (inode->i_sb->u.ufs_sb.s_flags & UFS_DEBUG) {
+	                                printk("ufs_readdir: filldir(%s,%lu)\n",
+	                                       de->d_name, de->d_ino);
+	                        }
+				error = filldir(dirent, de->d_name, de->d_namlen, filp->f_pos, de->d_ino);
+				if (error)
+					break;
+				if (version != inode->i_version)
+					goto revalidate;
+				stored ++;
+			}
+			filp->f_pos += de->d_reclen;
+		}
+		offset = 0;
+		brelse (bh);
+	}
+#if 0 /* XXX */
+	if (!IS_RDONLY(inode)) {
+		inode->i_atime = CURRENT_TIME;
+		inode->i_dirt = 1;
+	}
+#endif /* XXX */
+	return 0;
+}
+
+
+static struct file_operations ufs_dir_operations = {
+	NULL,			/* lseek */
+	&ufs_dir_read,		/* read */
+	NULL,			/* write */
+	&ufs_readdir,		/* readdir */
+	NULL,			/* select */
+	NULL,			/* ioctl */
+	NULL,			/* mmap */
+	NULL,			/* open */
+	NULL,			/* release */
+	&file_fsync,		/* fsync */
+	NULL,			/* fasync */
+	NULL,			/* check_media_change */
+	NULL,			/* revalidate */
+};
+
+struct inode_operations ufs_dir_inode_operations = {
+	&ufs_dir_operations,	/* default directory file operations */
+	NULL,			/* create */
+	&ufs_lookup,		/* lookup */
+	NULL,			/* link */
+	NULL,			/* unlink */
+	NULL,			/* symlink */
+	NULL,			/* mkdir */
+	NULL,			/* rmdir */
+	NULL,			/* mknod */
+	NULL,			/* rename */
+	NULL,			/* readlink */
+	NULL,			/* follow_link */
+	NULL,			/* readpage */
+	NULL,			/* writepage */
+	NULL,			/* bmap */
+	NULL,			/* truncate */
+	NULL,			/* permission */
+	NULL,			/* smap */
+};
+
+/*
+ * Local Variables: ***
+ * c-indent-level: 8 ***
+ * c-continued-statement-offset: 8 ***
+ * c-brace-offset: -8 ***
+ * c-argdecl-indent: 0 ***
+ * c-label-offset: -8 ***
+ * End: ***
+ */
diff -u --recursive --new-file v1.3.93/linux/fs/ufs/ufs_file.c linux/fs/ufs/ufs_file.c
--- v1.3.93/linux/fs/ufs/ufs_file.c	Thu Jan  1 02:00:00 1970
+++ linux/fs/ufs/ufs_file.c	Mon Apr 22 10:59:39 1996
@@ -0,0 +1,144 @@
+/*
+ *  linux/fs/ufs/ufs_file.c
+ *
+ * Copyright (C) 1996
+ * Adrian Rodriguez (adrian@franklins-tower.rutgers.edu)
+ * Laboratory for Computer Science Research Computing Facility
+ * Rutgers, The State University of New Jersey
+ *
+ * $Id: ufs_file.c,v 1.1 1996/04/21 14:41:08 davem Exp $
+ *
+ */
+
+#include <linux/fs.h>
+
+/*
+ * Return values:
+ *   0:  bmap failed
+ *  nonzero: absolute "block" number
+ */
+int ufs_bmap (struct inode * inode, int block)
+{
+	unsigned long int fsblkno, phys_block, lfsblkno;
+	struct buffer_head * bh;
+
+	/*
+	 * Note that contrary to what the BSD source calls these things,
+	 * blkno and lblkno are *frags* (1024), not UFS blocks (8192).
+	 * XXX - maybe I'm wrong, and ui_blocks is really 512-blocks...
+	 */
+
+	/*
+	 * Ok, I think I figured out what is going on.  ui_blocks is the
+	 * number of 512-byte blocks that are allocated to the file.  The
+	 * elements in ui_db[UFS_NDADDR] are pointers to 1024-byte aligned
+	 * 8192 byte objects.  The entire 8192 bytes (16 512-blocks) may
+	 * not be allocated to the file in question - use ui_blocks to see
+	 * how many of the blocks are allocated.  Also, use ui_size to see
+	 * what fraction of the last block is allocated to the file, and
+	 * what fraction is unused.  I have not yet seen a file with a
+	 * hole in it, but I'd guess that a hole must be at least 8192
+	 * bytes of zeros, and it's represented by a zero in ui_db[X].
+	 *
+	 * Yes, this means that there is more than one way to name a given
+	 * 512-byte block on the disk. Because of the 1024-byte alignment
+	 * of 8192-byte filesystem blocks, a given 512-byte disk block
+	 * could be referred to in eight different ways.
+	 */
+
+	/*
+	 * block is the logical 1024-block in the file
+	 * lfsblkno is the logical 8192-block in the file
+	 * fsblkno is the physical 8192-block
+	 * phys_block is the 1024-block
+	 */
+	lfsblkno = block>>3;
+
+	if (block < UFS_NDADDR) {
+	        /* It's a direct block */
+	        fsblkno = inode->u.ufs_i.ui_db[lfsblkno]; /* XXX */
+#if 0
+	        phys_block = ufs_cgdmin(inode->i_sb, ufs_ino2cg(inode)) +
+	                blkno%(inode->i_sb->u.ufs_sb.s_fpg);
+#endif
+	        phys_block = fsblkno + ((block & 0x7)<<10); /* XXX */
+	        if (inode->i_sb->u.ufs_sb.s_flags & UFS_DEBUG) {
+	                printk("ufs_bmap: mapped ino %lu  logical %u to %lu (phys %lu)\n",
+	                       inode->i_ino, block, fsblkno, phys_block);
+	        }
+	        return(phys_block);
+	} else {
+	        /* Need to use indirect blocks */
+	        /* XXX - bmap through indirect blocks not implemented */
+	        block -= UFS_NDADDR;
+	        if (block < (inode->i_sb->s_blocksize/sizeof(__u32))) {
+	                bh = bread(inode->i_dev, inode->u.ufs_i.ui_ib[0],
+	                           BLOCK_SIZE);
+	                if (bh == NULL) {
+	                        printk("ufs_bmap: can't map block %lu, ino %lu\n",
+	                               block + UFS_NDADDR, inode->i_ino);
+	                        return(0);
+	                }
+	                phys_block = ((__u32 *)bh->b_data)[block];
+	                brelse(bh);
+	                printk("ufs_bmap: imap ino %lu block %lu phys %lu\n",
+	                       inode->i_ino, block + UFS_NDADDR, phys_block);
+	                return(phys_block);
+	        } else {
+	                printk("ufs_bmap: ino %lu: indirect blocks not implemented\n",
+	                       inode->i_ino);
+	                return(0);
+	        }
+	}
+
+	return(0);
+}
+
+
+static struct file_operations ufs_file_operations = {
+	NULL,			/* lseek */
+	&generic_file_read,	/* read */
+	NULL,			/* write */
+	NULL,			/* readdir */
+	NULL,			/* select */
+	NULL,			/* ioctl */
+	&generic_file_mmap,	/* mmap */
+	NULL,			/* open */
+	NULL,			/* release */
+	&file_fsync,		/* fsync */  /* XXX - is this ok? */
+	NULL,			/* fasync */
+	NULL,			/* check_media_change */
+	NULL,			/* revalidate */
+};
+
+struct inode_operations ufs_file_inode_operations = {
+	&ufs_file_operations,	/* default directory file operations */
+	NULL,			/* create */
+	NULL,			/* lookup */
+	NULL,			/* link */
+	NULL,			/* unlink */
+	NULL,			/* symlink */
+	NULL,			/* mkdir */
+	NULL,			/* rmdir */
+	NULL,			/* mknod */
+	NULL,			/* rename */
+	NULL,			/* readlink */
+	NULL,			/* follow_link */
+	&generic_readpage,	/* readpage */
+	NULL,			/* writepage */
+	&ufs_bmap,		/* bmap */
+	NULL,			/* truncate */
+	NULL,			/* permission */
+	NULL,			/* smap */
+};
+
+
+/*
+ * Local Variables: ***
+ * c-indent-level: 8 ***
+ * c-continued-statement-offset: 8 ***
+ * c-brace-offset: -8 ***
+ * c-argdecl-indent: 0 ***
+ * c-label-offset: -8 ***
+ * End: ***
+ */
diff -u --recursive --new-file v1.3.93/linux/fs/ufs/ufs_inode.c linux/fs/ufs/ufs_inode.c
--- v1.3.93/linux/fs/ufs/ufs_inode.c	Thu Jan  1 02:00:00 1970
+++ linux/fs/ufs/ufs_inode.c	Mon Apr 22 10:59:39 1996
@@ -0,0 +1,237 @@
+/*
+ *  linux/fs/ufs/ufs_inode.c
+ *
+ * Copyright (C) 1996
+ * Adrian Rodriguez (adrian@franklins-tower.rutgers.edu)
+ * Laboratory for Computer Science Research Computing Facility
+ * Rutgers, The State University of New Jersey
+ *
+ * $Id: ufs_inode.c,v 1.1 1996/04/21 14:41:12 davem Exp $
+ *
+ */
+
+#include <linux/fs.h>
+#include <linux/ufs_fs.h>
+#include <linux/sched.h>
+
+extern struct inode_operations ufs_file_inode_operations;
+extern struct inode_operations ufs_dir_inode_operations;
+extern struct inode_operations ufs_symlink_inode_operations;
+extern struct file_operations ufs_file_operations;
+extern struct file_operations ufs_dir_operations;
+extern struct file_operations ufs_symlink_operations;
+
+void ufs_print_inode(struct inode * inode)
+{
+	printk("ino %lu  mode 0%6.6o  lk %d  uid %d  gid %d  sz %lu  blks %lu  cnt %u\n",
+	       inode->i_ino, inode->i_mode, inode->i_nlink, inode->i_uid, inode->i_gid, inode->i_size, inode->i_blocks, inode->i_count);
+	printk("  db <0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x>\n",
+	       inode->u.ufs_i.ui_db[0], inode->u.ufs_i.ui_db[1],
+	       inode->u.ufs_i.ui_db[2], inode->u.ufs_i.ui_db[3],
+	       inode->u.ufs_i.ui_db[4], inode->u.ufs_i.ui_db[5],
+	       inode->u.ufs_i.ui_db[6], inode->u.ufs_i.ui_db[7],
+	       inode->u.ufs_i.ui_db[8], inode->u.ufs_i.ui_db[9],
+	       inode->u.ufs_i.ui_db[10], inode->u.ufs_i.ui_db[11]);
+	printk("  gen 0x%8.8x ib <0x%x 0x%x 0x%x>\n",
+	       inode->u.ufs_i.ui_gen, inode->u.ufs_i.ui_ib[0],
+	       inode->u.ufs_i.ui_ib[1], inode->u.ufs_i.ui_ib[2]);
+}
+
+/* XXX - ufs_read_inode is a mess */
+void ufs_read_inode(struct inode * inode)
+{
+	struct super_block * sb;
+	struct ufs_inode * ufsip;
+	struct buffer_head * bh;
+
+	sb = inode->i_sb;
+
+	if (ufs_ino_ok(inode)) {
+	        printk("ufs_read_inode: bad inum %lu", inode->i_ino);
+
+	        return;
+	}
+
+#if 0
+	printk("ufs_read_inode: ino %lu  cg %u  cgino %u  ipg %u  inopb %u\n",
+	       inode->i_ino, ufs_ino2cg(inode),
+	       (inode->i_ino%sb->u.ufs_sb.s_inopb),
+	       sb->u.ufs_sb.s_ipg, sb->u.ufs_sb.s_inopb);
+#endif
+	bh = bread(inode->i_dev,
+	           ufs_cgimin(inode->i_sb, ufs_ino2cg(inode)) +
+	           (inode->i_ino%sb->u.ufs_sb.s_ipg)/(sb->u.ufs_sb.s_inopb/sb->u.ufs_sb.s_fsfrag),
+	           BLOCK_SIZE);
+	if (!bh) {
+	        printk("ufs_read_inode: can't read inode %lu from dev %d/%d",
+	               inode->i_ino, MAJOR(inode->i_dev), MINOR(inode->i_dev));
+	        return;
+	}
+
+	ufsip = (struct ufs_inode *)bh->b_data;
+	ufsip += (inode->i_ino%(sb->u.ufs_sb.s_inopb/sb->u.ufs_sb.s_fsfrag));
+
+	/*
+	 * Copy data to the in-core inode.
+	 */
+	inode->i_mode = ufsip->ui_mode;
+	inode->i_nlink = ufsip->ui_nlink;
+	if (inode->i_nlink == 0) {
+	        /* XXX */
+	        printk("ufs_read_inode: zero nlink ino %lu  dev %u/%u\n",
+	               inode->i_ino, MAJOR(inode->i_dev), MINOR(inode->i_dev));
+	        inode->i_nlink = 1;
+	        printk("ufs_read_inode: fishy ino %lu pblk %lu dev %u/%u\n",
+	               inode->i_ino,
+	               ufs_cgimin(inode->i_sb, ufs_ino2cg(inode)) +
+	               (inode->i_ino%sb->u.ufs_sb.s_ipg)/sb->u.ufs_sb.s_inopb,
+	               MAJOR(inode->i_dev), MINOR(inode->i_dev));
+	}
+	/* XXX - debugging */
+	if (ufsip->ui_gen == 0) {
+	        printk("ufs_read_inode: zero gen ino %lu pblk %lu dev %u/%u\n",
+	               inode->i_ino,
+	               ufs_cgimin(inode->i_sb, ufs_ino2cg(inode)) +
+	               (inode->i_ino%sb->u.ufs_sb.s_ipg)/sb->u.ufs_sb.s_inopb,
+	               MAJOR(inode->i_dev), MINOR(inode->i_dev));
+	}
+	/*
+	 * Since Linux currently only has 16-bit uid_t and gid_t, we can't
+	 * really support EFTs.  For the moment, we use 0 as the uid and gid
+	 * if an inode has a uid or gid that won't fit in 16 bits.  This way
+	 * random users can't get at these files, since they get dynamically
+	 * "chown()ed" to root.
+	 */
+	if (ufsip->ui_suid == UFS_USEEFT) {
+	        /* EFT */
+	        inode->i_uid = 0;
+	        printk("ufs_read_inode: EFT uid %u ino %lu dev %u/%u, using %u\n",
+	               ufsip->ui_uid, inode->i_ino, MAJOR(inode->i_dev), MINOR(inode->i_dev),
+	               inode->i_uid);
+	} else {
+	        inode->i_uid = ufsip->ui_suid;
+	}
+	if (ufsip->ui_suid == UFS_USEEFT) {
+	        /* EFT */
+	        inode->i_uid = 0;
+	        printk("ufs_read_inode: EFT gid %u ino %lu dev %u/%u, using %u\n",
+	               ufsip->ui_gid, inode->i_ino, MAJOR(inode->i_dev), MINOR(inode->i_dev),
+	               inode->i_gid);
+	} else {
+	        inode->i_gid = ufsip->ui_sgid;
+	}
+
+	/*
+	 * Linux i_size is 32 bits, so some files on a UFS filesystem may not
+	 * be readable.  I let people access the first 32 bits worth of them.
+	 * for the rw code, we may want to mark these inodes as read-only.
+	 * XXX - bug Linus to make i_size a __u64 instead of a __u32.
+	 */
+	inode->u.ufs_i.ui_size = ((__u64)(ufsip->ui_size.val[0])<<32) | (__u64)(ufsip->ui_size.val[1]);
+	inode->i_size = ufsip->ui_size.val[1]; /* XXX - endianity */
+	if (ufsip->ui_size.val[0] != 0) {
+	        inode->i_size = 0xffffffff;
+	        printk("ufs_read_inode: file too big ino %lu dev %u/%u, faking size\n",
+	               inode->i_ino, MAJOR(inode->i_dev), MINOR(inode->i_dev));
+	}
+	/*
+	 * Linux doesn't keep tv_usec around in the kernel, so we discard it.
+	 * XXX - I'm not sure what I should do about writing things.  I may
+	 * want to keep this data, but for the moment I think I'll just write
+	 * zeros for these fields when writing out inodes.
+	 */
+	inode->i_atime = ufsip->ui_atime.tv_sec;
+	inode->i_mtime = ufsip->ui_mtime.tv_sec;
+	inode->i_ctime = ufsip->ui_ctime.tv_sec;
+	inode->i_blksize = sb->u.ufs_sb.s_fsize;
+	inode->i_blocks = ufsip->ui_blocks;
+	inode->i_version = ++event; /* see linux/kernel/sched.c */
+
+	if (S_ISREG(inode->i_mode)) {
+	        inode->i_op = &ufs_file_inode_operations;
+	} else if (S_ISDIR(inode->i_mode)) {
+	        inode->i_op = &ufs_dir_inode_operations;
+	} else if (S_ISLNK(inode->i_mode)) {
+	        inode->i_op = &ufs_symlink_inode_operations;
+	} else if (S_ISCHR(inode->i_mode)) {
+	        inode->i_op = &chrdev_inode_operations;
+	} else if (S_ISBLK(inode->i_mode)) {
+	        inode->i_op = &blkdev_inode_operations;
+	} else if (S_ISFIFO(inode->i_mode)) {
+	        init_fifo(inode);
+	} else {
+	        printk("ufs_read_inode: unknown file type 0%o ino %lu dev %d/%d\n",
+	               inode->i_mode, inode->i_ino, MAJOR(inode->i_dev),
+	               MINOR(inode->i_dev));
+	        /* XXX - debugging */
+	        ufs_print_inode(inode);
+	        inode->i_op = &ufs_file_inode_operations;
+	}
+
+	/*
+	 * ufs_read_super makes sure that UFS_NDADDR and UFS_NINDIR are sane.
+	 */
+	if (S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
+	    S_ISLNK(inode->i_mode)) {
+	        int i;
+
+	        for (i = 0; i < UFS_NDADDR; i++) {
+	                inode->u.ufs_i.ui_db[i] = ufsip->ui_db[i];
+	        }
+	        for (i = 0; i < UFS_NINDIR; i++) {
+	                inode->u.ufs_i.ui_ib[i] = ufsip->ui_ib[i];
+	        }
+	}
+
+	if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) {
+	        /* XXX - should be ui_db[1] on little endian ufs filesystems */
+	        inode->i_rdev = ufsip->ui_db[0];
+	}
+
+	/* XXX - implement fast and slow symlinks */
+
+	inode->u.ufs_i.ui_flags = ufsip->ui_flags;
+	inode->u.ufs_i.ui_gen = ufsip->ui_gen; /* XXX - is this i_version? */
+	inode->u.ufs_i.ui_shadow = ufsip->ui_shadow; /* XXX */
+	inode->u.ufs_i.ui_uid = ufsip->ui_uid;
+	inode->u.ufs_i.ui_gid = ufsip->ui_gid;
+	inode->u.ufs_i.ui_oeftflag = ufsip->ui_oeftflag;
+
+	brelse(bh);
+
+	if (inode->i_sb->u.ufs_sb.s_flags & (UFS_DEBUG|UFS_DEBUG_INODE)) {
+	        ufs_print_inode(inode);
+	}
+
+	return;
+}
+
+void ufs_put_inode (struct inode * inode)
+{
+	if (inode->i_nlink)
+	        return;
+
+	printk("ufs_put_inode: nlink == 0 for inum %lu on dev %d/%d\n",
+	       inode->i_ino, MAJOR(inode->i_dev), MINOR(inode->i_dev));
+	ufs_print_inode(inode);
+	panic("ufs_put_inode: fs is read only, and nlink == 0");
+
+	/* XXX - this code goes here eventually
+	inode->i_size = 0;
+	if (inode->i_blocks)
+	        ufs_truncate(inode);
+	ufs_free_inode(inode);
+	*/
+
+	return;
+}
+
+/*
+ * Local Variables: ***
+ * c-indent-level: 8 ***
+ * c-continued-statement-offset: 8 ***
+ * c-brace-offset: -8 ***
+ * c-argdecl-indent: 0 ***
+ * c-label-offset: -8 ***
+ * End: ***
+ */
diff -u --recursive --new-file v1.3.93/linux/fs/ufs/ufs_namei.c linux/fs/ufs/ufs_namei.c
--- v1.3.93/linux/fs/ufs/ufs_namei.c	Thu Jan  1 02:00:00 1970
+++ linux/fs/ufs/ufs_namei.c	Mon Apr 22 10:59:39 1996
@@ -0,0 +1,154 @@
+/*
+ *  linux/fs/ufs/ufs_namei.c
+ *
+ * Copyright (C) 1996
+ * Adrian Rodriguez (adrian@franklins-tower.rutgers.edu)
+ * Laboratory for Computer Science Research Computing Facility
+ * Rutgers, The State University of New Jersey
+ *
+ * $Id: ufs_namei.c,v 1.1 1996/04/21 14:41:15 davem Exp $
+ *
+ */
+
+#include <linux/fs.h>
+
+extern unsigned int ufs_bmap(struct inode * inode, int block); /* XXX */
+
+/*
+ * NOTE! unlike strncmp, ext2_match returns 1 for success, 0 for failure.
+ * stolen from ext2fs
+ */
+static int ufs_match (int len, const char * const name, struct direct * d)
+{
+	if (!d || len > MAXNAMLEN) /* XXX - name space */
+		return 0;
+	/*
+	 * "" means "." ---> so paths like "/usr/lib//libc.a" work
+	 */
+	if (!len && (d->d_namlen == 1) && (d->d_name[0] == '.') &&
+	   (d->d_name[1] == '\0'))
+		return 1;
+	if (len != d->d_namlen)
+		return 0;
+	return !memcmp(name, d->d_name, len);
+}
+
+/* XXX - this is a mess, especially for endianity */
+int ufs_lookup (struct inode * dir, const char * name, int len,
+	        struct inode ** result)
+{
+	unsigned long int lfragno, fragno;
+	struct buffer_head * bh;
+	struct direct * d;
+
+	/*
+	 * Touching /xyzzy in a filesystem toggles debugging messages.
+	 */
+	if ((len == 5) && !(memcmp(name, "xyzzy", len)) &&
+	    (dir->i_ino == UFS_ROOTINO)) {
+	        dir->i_sb->u.ufs_sb.s_flags ^= UFS_DEBUG;
+	        printk("UFS debugging %s\n",
+	               (dir->i_sb->u.ufs_sb.s_flags & UFS_DEBUG) ?
+	               "on": "off");
+	        return(-ENOENT);
+	}
+
+	/*
+	 * Touching /xyzzy.i in a filesystem toggles debugging for ufs_inode.c.
+	 */
+	if ((len == 7) && !(memcmp(name, "xyzzy.i", len)) &&
+	    (dir->i_ino == UFS_ROOTINO)) {
+	        dir->i_sb->u.ufs_sb.s_flags ^= UFS_DEBUG_INODE;
+	        printk("UFS inode debugging %s\n",
+	               (dir->i_sb->u.ufs_sb.s_flags & UFS_DEBUG_INODE) ?
+	               "on": "off");
+	        return(-ENOENT);
+	}
+
+	if ((len == 7) && !(memcmp(name, "xyzzy.n", len)) &&
+	    (dir->i_ino == UFS_ROOTINO)) {
+	        dir->i_sb->u.ufs_sb.s_flags ^= UFS_DEBUG_NAMEI;
+	        printk("UFS namei debugging %s\n",
+	               (dir->i_sb->u.ufs_sb.s_flags & UFS_DEBUG_NAMEI) ?
+	               "on": "off");
+	        return(-ENOENT);
+	}
+
+	if ((len == 7) && !(memcmp(name, "xyzzy.l", len)) &&
+	    (dir->i_ino == UFS_ROOTINO)) {
+	        dir->i_sb->u.ufs_sb.s_flags ^= UFS_DEBUG_LINKS;
+	        printk("UFS symlink debugging %s\n",
+	               (dir->i_sb->u.ufs_sb.s_flags & UFS_DEBUG_LINKS) ?
+	               "on": "off");
+	        return(-ENOENT);
+	}
+
+	if (dir->i_sb->u.ufs_sb.s_flags & (UFS_DEBUG|UFS_DEBUG_NAMEI)) {
+	        printk("ufs_lookup: called for ino %lu  name %s\n",
+	               dir->i_ino, name);
+	}
+
+	/* XXX - do I want i_blocks in 512-blocks or 1024-blocks? */
+	for (lfragno = 0; lfragno < (dir->i_blocks)>>1; lfragno++) {
+	        fragno = ufs_bmap(dir, lfragno);
+	        /* XXX - ufs_bmap() call needs error checking */
+	        /* XXX - s_blocksize is actually the UFS frag size */
+	        if (dir->i_sb->u.ufs_sb.s_flags & UFS_DEBUG) {
+	                printk("ufs_lookup: ino %lu lfragno %lu  fragno %lu\n",
+	                       dir->i_ino, lfragno, fragno);
+	        }
+	        if (fragno == 0) {
+	                /* XXX - bug bug bug */
+	                return(-ENOENT);
+	        }
+	        bh = bread(dir->i_dev, fragno, dir->i_sb->s_blocksize);
+	        if (bh == NULL) {
+	                printk("ufs_lookup: bread failed: ino %lu, lfragno %u",
+	                       dir->i_ino, lfragno);
+	                return(-EIO);
+	        }
+	        d = (struct direct *)(bh->b_data);
+	        while (((char *)d - bh->b_data + d->d_reclen) <=
+	               dir->i_sb->s_blocksize) {
+	                /* XXX - skip block if d_reclen or d_namlen is 0 */
+	                if ((d->d_reclen == 0) || (d->d_namlen == 0)) {
+	                        if (dir->i_sb->u.ufs_sb.s_flags & UFS_DEBUG) {
+	                                printk("ufs_lookup: skipped space in directory, ino %lu\n",
+	                                       dir->i_ino);
+	                        }
+	                        break;
+	                }
+	                if (dir->i_sb->u.ufs_sb.s_flags & UFS_DEBUG) {
+	                        printk("lfragno 0x%x  direct d 0x%x  d_ino %u  d_reclen %u  d_namlen %u  d_name `%s'\n",
+	                               lfragno, (unsigned int)d, d->d_ino, d->d_reclen, d->d_namlen, d->d_name);
+	                }
+	                if ((d->d_namlen == len) &&
+	                    /* XXX - don't use strncmp() - see ext2fs */
+	                    (ufs_match(len, name, d))) {
+	                        /* We have a match */
+	                        *result = iget(dir->i_sb, d->d_ino);
+	                        brelse(bh);
+	                        return(0);
+	                } else {
+	                        /* XXX - bounds checking */
+	                        if (dir->i_sb->u.ufs_sb.s_flags & UFS_DEBUG) {
+	                                printk("ufs_lookup: wanted (%s,%d) got (%s,%d)\n",
+	                                       name, len, d->d_name, d->d_namlen);
+	                        }
+	                }
+	                d = (struct direct *)((char *)d + d->d_reclen);
+	        }
+	        brelse(bh);
+	}
+	return(-ENOENT);
+}
+
+/*
+ * Local Variables: ***
+ * c-indent-level: 8 ***
+ * c-continued-statement-offset: 8 ***
+ * c-brace-offset: -8 ***
+ * c-argdecl-indent: 0 ***
+ * c-label-offset: -8 ***
+ * End: ***
+ */
diff -u --recursive --new-file v1.3.93/linux/fs/ufs/ufs_super.c linux/fs/ufs/ufs_super.c
--- v1.3.93/linux/fs/ufs/ufs_super.c	Thu Jan  1 02:00:00 1970
+++ linux/fs/ufs/ufs_super.c	Mon Apr 22 10:59:39 1996
@@ -0,0 +1,265 @@
+/*
+ *  linux/fs/ufs/ufs_super.c
+ *
+ * Copyright (C) 1996
+ * Adrian Rodriguez (adrian@franklins-tower.rutgers.edu)
+ * Laboratory for Computer Science Research Computing Facility
+ * Rutgers, The State University of New Jersey
+ *
+ * $Id: ufs_super.c,v 1.1 1996/04/21 14:41:19 davem Exp $
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/ufs_fs.h>
+#include <linux/module.h>
+#include <linux/locks.h>
+
+struct super_block * ufs_read_super(struct super_block * sb, void * data, int silent);
+void ufs_put_super (struct super_block * sb);
+void ufs_statfs(struct super_block * sb, struct statfs * buf, int bufsize);
+
+extern void ufs_read_inode(struct inode * inode);
+extern void ufs_put_inode(struct inode * inode);
+
+static struct super_operations ufs_super_ops = {
+	&ufs_read_inode,
+	NULL,			/* notify_change() */
+	NULL,			/* XXX - ufs_write_inode() */
+	&ufs_put_inode,
+	&ufs_put_super,
+	NULL,			/* XXX - ufs_write_super() */
+	&ufs_statfs,
+	NULL,			/* XXX - ufs_remount() */
+};
+
+static struct file_system_type ufs_fs_type = {
+	&ufs_read_super, "ufs", 1, NULL
+};
+
+int
+init_ufs_fs(void)
+{
+	return(register_filesystem(&ufs_fs_type));
+}
+
+static void
+ufs_print_super_stuff(struct super_block * sb, struct ufs_superblock * usb)
+{
+
+	printk("fs_sblkno: 0x%8.8x\n", usb->fs_sblkno);
+	printk("fs_size: 0x%8.8x\n", usb->fs_size);
+	printk("fs_ncg: 0x%8.8x\n", usb->fs_ncg);
+	printk("fs_bsize: 0x%8.8x\n", usb->fs_bsize);
+	printk("fs_frag: 0x%8.8x\n", usb->fs_frag);
+	printk("fs_nindir: 0x%8.8x\n", usb->fs_nindir);
+	printk("fs_inopb: 0x%8.8x\n", usb->fs_inopb);
+	printk("fs_optim: 0x%8.8x\n", usb->fs_optim);
+	printk("fs_ncyl: 0x%8.8x\n", usb->fs_ncyl);
+	printk("fs_state: 0x%8.8x\n", usb->fs_state);
+	printk("fs_magic: 0x%8.8x\n", usb->fs_magic);
+	printk("fs_fsmnt: `%s'\n", usb->fs_fsmnt);
+
+	return;
+}
+
+struct super_block *
+ufs_read_super(struct super_block * sb, void * data, int silent)
+{
+	struct ufs_superblock * usb;
+	struct buffer_head * bh1, *bh2;
+
+	/* sb->s_dev and sb->s_flags are set by our caller
+	 * data is the mystery argument to sys_mount()
+	 *
+	 * Our caller also sets s_dev, s_covered, s_rd_only, s_dirt,
+	 *   and s_type when we return.
+	 */
+
+	lock_super (sb);
+
+	/* XXX - make everything read only for testing */
+	sb->s_flags |= MS_RDONLY;
+
+	if (!(bh1 = bread(sb->s_dev, UFS_SBLOCK/BLOCK_SIZE, BLOCK_SIZE)) ||
+	    !(bh2 = bread(sb->s_dev, (UFS_SBLOCK + BLOCK_SIZE)/BLOCK_SIZE,
+	                  BLOCK_SIZE))) {
+	        sb->s_dev = 0;
+	        unlock_super (sb);
+	        if (bh1) {
+	                brelse(bh1);
+	        }
+	        printk ("ufs_read_super: unable to read superblock\n");
+
+	        return 0;
+	}
+	/* XXX - redo this so we can free it later... */
+	usb = (struct ufs_superblock *)__get_free_page(GFP_KERNEL); 
+	if (usb == NULL) {
+	        printk ("ufs_read_super: get_free_page() failed\n");
+	}
+
+	memcpy((char *)usb, bh1->b_data, BLOCK_SIZE);
+	memcpy((char *)usb + BLOCK_SIZE, bh2->b_data,
+	       sizeof(struct ufs_superblock) - BLOCK_SIZE);
+
+	brelse(bh1);
+	brelse(bh2);
+
+	if (usb->fs_magic != UFS_MAGIC) {
+	        /* XXX - replace hard-coded constant with a byte-swap macro */
+	        if (usb->fs_magic == 0x54190100) {
+	                printk ("ufs_read_super: can't grok byteswapped fs on dev %d/%d\n",
+	                        MAJOR(sb->s_dev), MINOR(sb->s_dev));
+	                silent = 1;
+	        }
+	        sb->s_dev = 0;
+	        unlock_super (sb);
+	        if (!silent)
+	                printk ("ufs_read_super: bad magic number 0x%8.8x on dev %d/%d\n",
+	                        usb->fs_magic, MAJOR(sb->s_dev),
+	                        MINOR(sb->s_dev));
+	        return(NULL);
+	}
+
+	/* We found a UFS filesystem on this device. */
+
+	/* XXX - parse args */
+
+	if (usb->fs_bsize != UFS_BSIZE) {
+	        printk("ufs_read_super: fs_bsize %d != %d\n", usb->fs_bsize,
+	               UFS_BSIZE);
+	        goto ufs_read_super_lose;
+	}
+
+	if (usb->fs_fsize != UFS_FSIZE) {
+	        printk("ufs_read_super: fs_fsize %d != %d\n", usb->fs_fsize,
+	               UFS_FSIZE);
+	        goto ufs_read_super_lose;
+	}
+
+	if (usb->fs_nindir != UFS_NINDIR) {
+	        printk("ufs_read_super: fs_nindir %d != %d\n", usb->fs_nindir,
+	               UFS_NINDIR);
+	        printk("ufs_read_super: fucking Sun blows me\n");
+	}
+
+	printk("ufs_read_super: fs last mounted on \"%s\"\n", usb->fs_fsmnt);
+
+	if (usb->fs_state == UFS_FSOK - usb->fs_time) {
+	        switch(usb->fs_clean) {
+	                case UFS_FSCLEAN:
+	                  printk("ufs_read_super: fs is clean\n");
+	                  break;
+	                case UFS_FSSTABLE:
+	                  printk("ufs_read_super: fs is stable\n");
+	                  break;
+	                case UFS_FSACTIVE:
+	                  printk("ufs_read_super: fs is active\n");
+	                  sb->s_flags |= MS_RDONLY;
+	                  break;
+	                case UFS_FSBAD:
+	                  printk("ufs_read_super: fs is bad\n");
+	                  sb->s_flags |= MS_RDONLY;
+	                  break;
+	                default:
+	                  printk("ufs_read_super: can't grok fs_clean 0x%x\n",
+	                         usb->fs_clean);
+	                  sb->s_flags |= MS_RDONLY;
+	                  break;
+	        }
+	} else {
+	        printk("ufs_read_super: fs needs fsck\n");
+	        sb->s_flags |= MS_RDONLY;
+	        /* XXX - make it read only or barf if it's not (/, /usr) */
+	}
+
+	/* XXX - sanity check sb fields */
+
+	sb->s_blocksize = usb->fs_fsize;
+	sb->s_blocksize_bits = 10;  /* XXX */
+	/* XXX - sb->s_lock */
+	sb->s_op = &ufs_super_ops;
+	sb->dq_op = 0; /* XXX */
+	sb->s_magic = usb->fs_magic;
+	/* sb->s_time */
+	/* sb->s_wait */
+	/* XXX - sb->u.ufs_sb */
+	sb->u.ufs_sb.s_raw_sb = usb; /* XXX - maybe move this to the top */
+	sb->u.ufs_sb.s_flags = 0;
+	sb->u.ufs_sb.s_ncg = usb->fs_ncg;
+	sb->u.ufs_sb.s_ipg = usb->fs_ipg;
+	sb->u.ufs_sb.s_fpg = usb->fs_fpg;
+	sb->u.ufs_sb.s_fsize = usb->fs_fsize;
+	sb->u.ufs_sb.s_bsize = usb->fs_bsize;
+	sb->u.ufs_sb.s_iblkno = usb->fs_iblkno;
+	sb->u.ufs_sb.s_dblkno = usb->fs_dblkno;
+	sb->u.ufs_sb.s_cgoffset = usb->fs_cgoffset;
+	sb->u.ufs_sb.s_cgmask = usb->fs_cgmask;
+	sb->u.ufs_sb.s_inopb = usb->fs_inopb;
+	sb->u.ufs_sb.s_fsfrag = usb->fs_frag; /* XXX - rename this later */
+	sb->s_mounted = iget(sb, UFS_ROOTINO);
+
+	printk("ufs_read_super: inopb %lu\n", sb->u.ufs_sb.s_inopb);
+	/*
+	 * XXX - read cg structs?
+	 */
+
+	unlock_super(sb);
+	return(sb);
+
+       ufs_read_super_lose:
+	/* XXX - clean up */
+	return(0);
+}
+
+void ufs_put_super (struct super_block * sb)
+{
+
+	printk("ufs_put_super\n"); /* XXX */
+
+	lock_super (sb);
+	/* XXX - sync fs data, set state to ok, and flush buffers */
+	sb->s_dev = 0;
+
+	/* XXX - free allocated kernel memory */
+
+	unlock_super (sb);
+	MOD_DEC_USE_COUNT;
+
+	return;
+}
+
+void ufs_statfs(struct super_block * sb, struct statfs * buf, int bufsiz)
+{
+	struct statfs tmp;
+
+	printk("ufs_statfs\n"); /* XXX */
+	tmp.f_type = sb->s_magic;
+	tmp.f_bsize = PAGE_SIZE;
+	tmp.f_blocks = sb->u.ufs_sb.s_raw_sb->fs_dsize;
+	tmp.f_bfree = sb->u.ufs_sb.s_raw_sb->fs_cstotal.cs_nbfree;
+	tmp.f_bavail =  sb->u.ufs_sb.s_raw_sb->fs_cstotal.cs_nbfree; /* XXX */
+	tmp.f_files = sb->u.ufs_sb.s_ncg * sb->u.ufs_sb.s_ipg;
+	tmp.f_ffree = sb->u.ufs_sb.s_raw_sb->fs_cstotal.cs_nifree;
+	tmp.f_fsid.val[0] = sb->u.ufs_sb.s_raw_sb->fs_id[0];
+	tmp.f_fsid.val[1] = sb->u.ufs_sb.s_raw_sb->fs_id[1];
+	tmp.f_namelen = MAXNAMLEN;
+/*        tmp.f_spare[6] */
+
+	memcpy_tofs(buf, &tmp, bufsiz);
+
+	return;
+}
+
+
+/*
+ * Local Variables: ***
+ * c-indent-level: 8 ***
+ * c-continued-statement-offset: 8 ***
+ * c-brace-offset: -8 ***
+ * c-argdecl-indent: 0 ***
+ * c-label-offset: -8 ***
+ * End: ***
+ */
diff -u --recursive --new-file v1.3.93/linux/fs/ufs/ufs_symlink.c linux/fs/ufs/ufs_symlink.c
--- v1.3.93/linux/fs/ufs/ufs_symlink.c	Thu Jan  1 02:00:00 1970
+++ linux/fs/ufs/ufs_symlink.c	Mon Apr 22 10:59:39 1996
@@ -0,0 +1,181 @@
+/*
+ *  linux/fs/ufs/ufs_symlink.c
+ *
+ * Copyright (C) 1996
+ * Adrian Rodriguez (adrian@franklins-tower.rutgers.edu)
+ * Laboratory for Computer Science Research Computing Facility
+ * Rutgers, The State University of New Jersey
+ *
+ * $Id: ufs_symlink.c,v 1.1 1996/04/21 14:41:23 davem Exp $
+ *
+ */
+
+#include <linux/fs.h>
+#include <linux/sched.h>
+
+static int
+ufs_readlink(struct inode * inode, char * buffer, int buflen)
+{
+	unsigned long int block;
+	struct buffer_head * bh = NULL;
+	char * link;
+	int i, err;
+	char c;
+
+	if (inode->i_sb->u.ufs_sb.s_flags & (UFS_DEBUG|UFS_DEBUG_LINKS)) {
+	        printk("ufs_readlink: called on ino %lu dev %u/%u\n",
+	               inode->i_ino, MAJOR(inode->i_dev), MINOR(inode->i_dev));
+	}
+
+	if (!S_ISLNK(inode->i_mode)) {
+		iput (inode);
+		return -EINVAL;
+	}
+	if (buflen > inode->i_sb->s_blocksize - 1)
+		buflen = inode->i_sb->s_blocksize - 1;
+	if (inode->i_blocks) {
+	        /* XXX - error checking */
+	        block = ufs_bmap(inode, 0);
+	        if (inode->i_sb->u.ufs_sb.s_flags &(UFS_DEBUG|UFS_DEBUG_LINKS)) {
+	                printk("ufs_readlink: bmap got %lu for ino %lu\n",
+	                       block, inode->i_ino);
+} 
+	        bh = bread(inode->i_dev, block, BLOCK_SIZE);
+		if (!bh) {
+			iput (inode);
+	                printk("ufs_readlink: can't read block 0 for ino %lu on dev %u/%u\n",
+	                       inode->i_ino, MAJOR(inode->i_dev),
+	                       MINOR(inode->i_dev));
+			return 0;
+		}
+		link = bh->b_data;
+	}
+	else {
+	        link = (char *)&(inode->u.ufs_i.ui_db[0]);
+	}
+	i = 0;
+	while (i < buflen && (c = link[i])) {
+		i++;
+		put_user (c, buffer++);
+	}
+	iput (inode);
+	if (bh)
+		brelse (bh);
+	return i;
+
+	return(0);
+}
+
+/*
+ * XXX - blatantly stolen from ext2fs
+ */
+static int
+ufs_follow_link(struct inode * dir, struct inode * inode,
+	        int flag, int mode, struct inode ** res_inode)
+{
+	unsigned long int block;
+	int error;
+	struct buffer_head * bh;
+	char * link;
+
+	bh = NULL;
+
+	if (inode->i_sb->u.ufs_sb.s_flags & (UFS_DEBUG|UFS_DEBUG_LINKS)) {
+	        printk("ufs_follow_link: called on ino %lu dev %u/%u\n",
+	               dir->i_ino, MAJOR(dir->i_dev), MINOR(dir->i_dev));
+	}
+
+	*res_inode = NULL;
+	if (!dir) {
+	        dir = current->fs->root;
+	        dir->i_count++;
+	}
+	if (!inode) {
+		iput (dir);
+		return -ENOENT;
+	}
+	if (!S_ISLNK(inode->i_mode)) {
+		iput (dir);
+		*res_inode = inode;
+		return 0;
+	}
+	if (current->link_count > 5) {
+		iput (dir);
+		iput (inode);
+		return -ELOOP;
+	}
+	if (inode->i_blocks) {
+	        /* read the link from disk */
+	        /* XXX - error checking */
+	        block = ufs_bmap(inode, 0);
+	        bh = bread(inode->i_dev, block, BLOCK_SIZE);
+	        if (bh == NULL) {
+	                printk("ufs_follow_link: can't read block 0 for ino %lu on dev %u/%u\n",
+	                       inode->i_ino, MAJOR(inode->i_dev),
+	                       MINOR(inode->i_dev));
+	                iput(dir);
+	                iput(inode);
+	                return(-EIO);
+	        }
+	        link = bh->b_data;
+	} else {
+	        /* fast symlink */
+	        link = (char *)&(inode->u.ufs_i.ui_db[0]);
+	}
+	current->link_count++;
+	error = open_namei (link, flag, mode, res_inode, dir);
+	current->link_count--;
+	iput (inode);
+	if (bh) {
+		brelse (bh);
+	}
+	return(error);
+}
+
+
+static struct file_operations ufs_symlink_operations = {
+	NULL,			/* lseek */
+	NULL,			/* read */
+	NULL,			/* write */
+	NULL,			/* readdir */
+	NULL,			/* select */
+	NULL,			/* ioctl */
+	NULL,			/* mmap */
+	NULL,			/* open */
+	NULL,			/* release */
+	NULL,			/* fsync */  /* XXX - is this ok? */
+	NULL,			/* fasync */
+	NULL,			/* check_media_change */
+	NULL,			/* revalidate */
+};
+
+struct inode_operations ufs_symlink_inode_operations = {
+	&ufs_symlink_operations,	/* default directory file operations */
+	NULL,			/* create */
+	NULL,			/* lookup */
+	NULL,			/* link */
+	NULL,			/* unlink */
+	NULL,			/* symlink */
+	NULL,			/* mkdir */
+	NULL,			/* rmdir */
+	NULL,			/* mknod */
+	NULL,			/* rename */
+	&ufs_readlink,		/* readlink */
+	&ufs_follow_link,	/* follow_link */
+	NULL,			/* readpage */
+	NULL,			/* writepage */
+	NULL,			/* bmap */
+	NULL,			/* truncate */
+	NULL,			/* permission */
+	NULL,			/* smap */
+};
+
+/*
+ * Local Variables: ***
+ * c-indent-level: 8 ***
+ * c-continued-statement-offset: 8 ***
+ * c-brace-offset: -8 ***
+ * c-argdecl-indent: 0 ***
+ * c-label-offset: -8 ***
+ * End: ***
+ */
diff -u --recursive --new-file v1.3.93/linux/include/asm-i386/pgtable.h linux/include/asm-i386/pgtable.h
--- v1.3.93/linux/include/asm-i386/pgtable.h	Fri Apr 12 15:52:05 1996
+++ linux/include/asm-i386/pgtable.h	Mon Apr 22 12:21:13 1996
@@ -290,7 +290,7 @@
 do { \
 	(tsk)->tss.cr3 = (unsigned long) (pgdir); \
 	if ((tsk) == current) \
-		__asm__ __volatile__("movl %0,%%cr3": :"a" ((tsk)->tss.cr3)); \
+		__asm__ __volatile__("movl %0,%%cr3": :"a" (pgdir)); \
 } while (0)
 
 extern inline int pte_none(pte_t pte)		{ return !pte_val(pte); }
diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/a.out.h linux/include/asm-m68k/a.out.h
--- v1.3.93/linux/include/asm-m68k/a.out.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-m68k/a.out.h	Wed Dec 27 22:46:42 1995
@@ -0,0 +1,26 @@
+#ifndef __M68K_A_OUT_H__
+#define __M68K_A_OUT_H__
+
+struct exec
+{
+  unsigned long a_info;		/* Use macros N_MAGIC, etc for access */
+  unsigned a_text;		/* length of text, in bytes */
+  unsigned a_data;		/* length of data, in bytes */
+  unsigned a_bss;		/* length of uninitialized data area for file, in bytes */
+  unsigned a_syms;		/* length of symbol table data in file, in bytes */
+  unsigned a_entry;		/* start address */
+  unsigned a_trsize;		/* length of relocation info for text, in bytes */
+  unsigned a_drsize;		/* length of relocation info for data, in bytes */
+};
+
+#define N_TRSIZE(a)	((a).a_trsize)
+#define N_DRSIZE(a)	((a).a_drsize)
+#define N_SYMSIZE(a)	((a).a_syms)
+
+#ifdef __KERNEL__
+
+#define STACK_TOP	TASK_SIZE
+
+#endif
+
+#endif /* __M68K_A_OUT_H__ */
diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/amifd.h linux/include/asm-m68k/amifd.h
--- v1.3.93/linux/include/asm-m68k/amifd.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-m68k/amifd.h	Sun Mar  3 03:59:14 1996
@@ -0,0 +1,57 @@
+#ifndef _ASM_M68K_AMIFD_H
+#define _ASM_M68K_AMIFD_H
+
+/* Definitions for the Amiga floppy driver */
+
+#include <linux/fd.h>
+
+#define FD_MAX_UNITS    4
+
+struct fd_data_type {
+    char *name;			/* description of data type */
+    int sects;			/* sectors per track */
+#ifdef __STDC__
+    int (*read_fkt)(int, unsigned char *, unsigned long, int);
+    void (*write_fkt)(int, unsigned long, unsigned char *, int);
+#else
+    int (*read_fkt)();		/* read whole track */
+    void (*write_fkt)();		/* write whole track */
+#endif
+};
+
+#ifndef ASSEMBLER
+/*
+** Floppy type descriptions
+*/
+
+struct fd_drive_type {
+    unsigned long code;		/* code returned from drive */
+    char *name;			/* description of drive */
+    unsigned int tracks;	/* number of tracks */
+    unsigned int heads;		/* number of heads */
+    unsigned int read_size;	/* raw read size for one track */
+    unsigned int write_size;	/* raw write size for one track */
+    unsigned int sect_mult;	/* sectors and gap multiplier (HD = 2) */
+    unsigned int precomp1;	/* start track for precomp 1 */
+    unsigned int precomp2;	/* start track for precomp 2 */
+    unsigned int step_delay;	/* time (in ms) for delay after step */
+    unsigned int settle_time;	/* time to settle after dir change */
+    unsigned int side_time;	/* time needed to change sides */
+};
+
+struct amiga_floppy_struct {
+    struct fd_drive_type *type;	/* type of floppy for this unit */
+    struct fd_data_type *dtype;	/* type of floppy for this unit */
+    int track;			/* current track (-1 == unknown) */
+
+    int blocks;			/* total # blocks on disk */
+    int sects;			/* number of sectors per track */
+
+    int disk;			/* disk in drive (-1 == unknown) */
+    int motor;			/* true when motor is at speed */
+    int busy;			/* true when drive is active */
+    int status;			/* current error code for unit */
+};
+#endif
+
+#endif
diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/amifdreg.h linux/include/asm-m68k/amifdreg.h
--- v1.3.93/linux/include/asm-m68k/amifdreg.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-m68k/amifdreg.h	Wed Dec 27 22:46:43 1995
@@ -0,0 +1,81 @@
+#ifndef _LINUX_AMIFDREG_H
+#define _LINUX_AMIFDREG_H
+
+/*
+** CIAAPRA bits (read only)
+*/
+
+#define DSKRDY      (0x1<<5)        /* disk ready when low */
+#define DSKTRACK0   (0x1<<4)        /* head at track zero when low */
+#define DSKPROT     (0x1<<3)        /* disk protected when low */
+#define DSKCHANGE   (0x1<<2)        /* low when disk removed */
+
+/*
+** CIAAPRB bits (read/write)
+*/
+
+#define DSKMOTOR    (0x1<<7)        /* motor on when low */
+#define DSKSEL3     (0x1<<6)        /* select drive 3 when low */
+#define DSKSEL2     (0x1<<5)        /* select drive 2 when low */
+#define DSKSEL1     (0x1<<4)        /* select drive 1 when low */
+#define DSKSEL0     (0x1<<3)        /* select drive 0 when low */
+#define DSKSIDE     (0x1<<2)        /* side selection: 0 = upper, 1 = lower */
+#define DSKDIREC    (0x1<<1)        /* step direction: 0=in, 1=out (to trk 0) */
+#define DSKSTEP     (0x1)           /* pulse low to step head 1 track */
+
+/*
+** DSKBYTR bits (read only)
+*/
+
+#define DSKBYT      (1<<15)         /* register contains valid byte when set */
+#define DMAON       (1<<14)         /* disk DMA enabled */
+#define DISKWRITE   (1<<13)         /* disk write bit in DSKLEN enabled */
+#define WORDEQUAL   (1<<12)         /* DSKSYNC register match when true */
+/* bits 7-0 are data */
+
+/*
+** ADKCON/ADKCONR bits
+*/
+
+#ifndef SETCLR
+#define ADK_SETCLR      (1<<15)     /* control bit */
+#endif
+#define ADK_PRECOMP1    (1<<14)     /* precompensation selection */
+#define ADK_PRECOMP0    (1<<13)     /* 00=none, 01=140ns, 10=280ns, 11=500ns */
+#define ADK_MFMPREC     (1<<12)     /* 0=GCR precomp., 1=MFM precomp. */
+#define ADK_WORDSYNC    (1<<10)     /* enable DSKSYNC auto DMA */
+#define ADK_MSBSYNC     (1<<9)      /* when 1, enable sync on MSbit (for GCR) */
+#define ADK_FAST        (1<<8)      /* bit cell: 0=2us (GCR), 1=1us (MFM) */
+ 
+/*
+** DSKLEN bits
+*/
+
+#define DSKLEN_DMAEN    (1<<15)
+#define DSKLEN_WRITE    (1<<14)
+
+/*
+** INTENA/INTREQ bits
+*/
+
+#define DSKINDEX    (0x1<<4)        /* DSKINDEX bit */
+
+/*
+** Misc
+*/
+ 
+#define MFM_SYNC    0x4489          /* standard MFM sync value */
+
+/* Values for FD_COMMAND */
+#define FD_RECALIBRATE		0x07	/* move to track 0 */
+#define FD_SEEK			0x0F	/* seek track */
+#define FD_READ			0xE6	/* read with MT, MFM, SKip deleted */
+#define FD_WRITE		0xC5	/* write with MT, MFM */
+#define FD_SENSEI		0x08	/* Sense Interrupt Status */
+#define FD_SPECIFY		0x03	/* specify HUT etc */
+#define FD_FORMAT		0x4D	/* format one track */
+#define FD_VERSION		0x10	/* get version code */
+#define FD_CONFIGURE		0x13	/* configure FIFO operation */
+#define FD_PERPENDICULAR	0x12	/* perpendicular r/w mode */
+
+#endif /* _LINUX_AMIFDREG_H */
diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/amigahw.h linux/include/asm-m68k/amigahw.h
--- v1.3.93/linux/include/asm-m68k/amigahw.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-m68k/amigahw.h	Wed Dec 27 22:46:43 1995
@@ -0,0 +1,246 @@
+/*
+** asm-m68k/amigahw.h -- This header defines some macros and pointers for
+**                    the various Amiga custom hardware registers.
+**                    The naming conventions used here conform to those
+**                    used in the Amiga Hardware Reference Manual, 3rd Edition
+**
+** Copyright 1992 by Greg Harp
+**
+** This file is subject to the terms and conditions of the GNU General Public
+** License.  See the file README.legal in the main directory of this archive
+** for more details.
+**
+** Created: 9/24/92 by Greg Harp
+*/
+
+#ifndef _ASMm68k_AMIGAHW_H_
+#define _ASMm68k_AMIGAHW_H_
+
+struct CUSTOM {
+    u_short bltddat;
+    u_short dmaconr;
+    u_short vposr;
+    u_short vhposr;
+    u_short dskdatr;
+    u_short joy0dat;
+    u_short joy1dat;
+    u_short clxdat;
+    u_short adkconr;
+    u_short pot0dat;
+    u_short pot1dat;
+    u_short potgor;
+    u_short serdatr;
+    u_short dskbytr;
+    u_short intenar;
+    u_short intreqr;
+    u_char  *dskptr;
+    u_short dsklen;
+    u_short dskdat;
+    u_short refptr;
+    u_short vposw;
+    u_short vhposw;
+    u_short copcon;
+    u_short serdat;
+    u_short serper;
+    u_short potgo;
+    u_short joytest;
+    u_short strequ;
+    u_short strvbl;
+    u_short strhor;
+    u_short strlong;
+    u_short bltcon0;
+    u_short bltcon1;
+    u_short bltafwm;
+    u_short bltalwm;
+    u_char  *bltcpt;
+    u_char  *bltbpt;
+    u_char  *bltapt;
+    u_char  *bltdpt;
+    u_short bltsize;
+    u_char  pad2d;
+    u_char  bltcon0l;
+    u_short bltsizv;
+    u_short bltsizh;
+    u_short bltcmod;
+    u_short bltbmod;
+    u_short bltamod;
+    u_short bltdmod;
+    u_short spare2[4];
+    u_short bltcdat;
+    u_short bltbdat;
+    u_short bltadat;
+    u_short spare3[3];
+    u_short deniseid;
+    u_short dsksync;
+    u_short *cop1lc;
+    u_short *cop2lc;
+    u_short copjmp1;
+    u_short copjmp2;
+    u_short copins;
+    u_short diwstrt;
+    u_short diwstop;
+    u_short ddfstrt;
+    u_short ddfstop;
+    u_short dmacon;
+    u_short clxcon;
+    u_short intena;
+    u_short intreq;
+    u_short adkcon;
+    struct {
+	u_short	*audlc;
+	u_short audlen;
+	u_short audper;
+	u_short audvol;
+	u_short auddat;
+	u_short audspare[2];
+    } aud[4];
+    u_char  *bplpt[8];
+    u_short bplcon0;
+    u_short bplcon1;
+    u_short bplcon2;
+    u_short bplcon3;
+    u_short bpl1mod;
+    u_short bpl2mod;
+    u_short bplcon4;
+    u_short clxcon2;
+    u_short bpldat[8];
+    u_char  *sprpt[8];
+    struct {
+	u_short pos;
+	u_short ctl;
+	u_short dataa;
+	u_short datab;
+    } spr[8];
+    u_short color[32];
+    u_short htotal;
+    u_short hsstop;
+    u_short hbstrt;
+    u_short hbstop;
+    u_short vtotal;
+    u_short vsstop;
+    u_short vbstrt;
+    u_short vbstop;
+    u_short sprhstrt;
+    u_short sprhstop;
+    u_short bplhstrt;
+    u_short bplhstop;
+    u_short hhposw;
+    u_short hhposr;
+    u_short beamcon0;
+    u_short hsstrt;
+    u_short vsstrt;
+    u_short hcenter;
+    u_short diwhigh;
+    u_short spare4[11];
+    u_short fmode;
+};
+
+/*
+ * DMA register bits
+ */
+#define DMAF_SETCLR		(0x8000)
+#define DMAF_AUD0		(0x0001)
+#define DMAF_AUD1		(0x0002)
+#define DMAF_AUD2		(0x0004)
+#define DMAF_AUD3		(0x0008)
+#define DMAF_DISK		(0x0010)
+#define DMAF_SPRITE		(0x0020)
+#define DMAF_BLITTER		(0x0040)
+#define DMAF_COPPER		(0x0080)
+#define DMAF_RASTER		(0x0100)
+#define DMAF_MASTER		(0x0200)
+#define DMAF_BLITHOG		(0x0400)
+#define DMAF_BLTNZERO		(0x2000)
+#define DMAF_BLTDONE		(0x4000)
+#define DMAF_ALL		(0x01FF)
+
+struct CIA {
+    u_char pra; 		char pad0[0xff];
+    u_char prb; 		char pad1[0xff];
+    u_char ddra;		char pad2[0xff];
+    u_char ddrb;		char pad3[0xff];
+    u_char talo;		char pad4[0xff];
+    u_char tahi;		char pad5[0xff];
+    u_char tblo;		char pad6[0xff];
+    u_char tbhi;		char pad7[0xff];
+    u_char todlo;		char pad8[0xff];
+    u_char todmid;		char pad9[0xff];
+    u_char todhi;		char pada[0x1ff];
+    u_char sdr; 		char padb[0xff];
+    u_char icr; 		char padc[0xff];
+    u_char cra; 		char padd[0xff];
+    u_char crb; 		char pade[0xff];
+};
+
+#if 1
+#define zTwoBase (0x80000000)
+#define ZTWO_PADDR(x) (((unsigned long)(x))-zTwoBase)
+#define ZTWO_VADDR(x) (((unsigned long)(x))+zTwoBase)
+#else
+#define zTwoBase 0
+#define ZTWO_PADDR(x) (x)
+#define ZTWO_VADDR(x) (x)
+#endif
+
+#define CUSTOM_PHYSADDR     (0xdff000)
+#define custom ((*(volatile struct CUSTOM *)(zTwoBase+CUSTOM_PHYSADDR)))
+
+#define CIAA_PHYSADDR	  (0xbfe001)
+#define CIAB_PHYSADDR	  (0xbfd000)
+#define ciaa   ((*(volatile struct CIA *)(zTwoBase + CIAA_PHYSADDR)))
+#define ciab   ((*(volatile struct CIA *)(zTwoBase + CIAB_PHYSADDR)))
+
+#define CHIP_PHYSADDR	    (0x000000)
+#define chipaddr ((unsigned long)(zTwoBase + CHIP_PHYSADDR))
+void amiga_chip_init (void);
+void *amiga_chip_alloc (long size);
+void amiga_chip_free (void *);
+
+struct tod3000 {
+  unsigned int  :28, second2:4;	/* lower digit */
+  unsigned int  :28, second1:4;	/* upper digit */
+  unsigned int  :28, minute2:4;	/* lower digit */
+  unsigned int  :28, minute1:4;	/* upper digit */
+  unsigned int  :28, hour2:4;	/* lower digit */
+  unsigned int  :28, hour1:4;	/* upper digit */
+  unsigned int  :28, weekday:4;
+  unsigned int  :28, day2:4;	/* lower digit */
+  unsigned int  :28, day1:4;	/* upper digit */
+  unsigned int  :28, month2:4;	/* lower digit */
+  unsigned int  :28, month1:4;	/* upper digit */
+  unsigned int  :28, year2:4;	/* lower digit */
+  unsigned int  :28, year1:4;	/* upper digit */
+  unsigned int  :28, cntrl1:4;	/* control-byte 1 */
+  unsigned int  :28, cntrl2:4;	/* control-byte 2 */  
+  unsigned int  :28, cntrl3:4;	/* control-byte 3 */
+};
+#define TOD3000_CNTRL1_HOLD	0
+#define TOD3000_CNTRL1_FREE	9
+#define TOD_3000 ((struct tod3000 *)(zTwoBase+0xDC0000))
+
+struct tod2000 {
+  unsigned int  :28, second2:4;	/* lower digit */
+  unsigned int  :28, second1:4;	/* upper digit */
+  unsigned int  :28, minute2:4;	/* lower digit */
+  unsigned int  :28, minute1:4;	/* upper digit */
+  unsigned int  :28, hour2:4;	/* lower digit */
+  unsigned int  :28, hour1:4;	/* upper digit */
+  unsigned int  :28, day2:4;	/* lower digit */
+  unsigned int  :28, day1:4;	/* upper digit */
+  unsigned int  :28, month2:4;	/* lower digit */
+  unsigned int  :28, month1:4;	/* upper digit */
+  unsigned int  :28, year2:4;	/* lower digit */
+  unsigned int  :28, year1:4;	/* upper digit */
+  unsigned int  :28, weekday:4;
+  unsigned int  :28, cntrl1:4;	/* control-byte 1 */
+  unsigned int  :28, cntrl2:4;	/* control-byte 2 */  
+  unsigned int  :28, cntrl3:4;	/* control-byte 3 */
+};
+
+#define TOD2000_CNTRL1_HOLD	(1<<0)
+#define TOD2000_CNTRL1_BUSY	(1<<1)
+#define TOD2000_CNTRL3_24HMODE	(1<<2)
+#define TOD2000_HOUR1_PM	(1<<2)
+#define TOD_2000 ((struct tod2000 *)(zTwoBase+0xDC0000))
+
+#endif /* asm-m68k/amigahw.h */
diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/amigaints.h linux/include/asm-m68k/amigaints.h
--- v1.3.93/linux/include/asm-m68k/amigaints.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-m68k/amigaints.h	Fri Mar  1 00:29:19 1996
@@ -0,0 +1,99 @@
+/*
+** amigaints.h -- Amiga Linux interrupt handling structs and prototypes
+**
+** Copyright 1992 by Greg Harp
+**
+** This file is subject to the terms and conditions of the GNU General Public
+** License.  See the file README.legal in the main directory of this archive
+** for more details.
+**
+** Created 10/2/92 by Greg Harp
+*/
+
+#ifndef _ASMm68k_AMIGAINTS_H_
+#define _ASMm68k_AMIGAINTS_H_
+
+/*
+** Amiga Interrupt sources.
+**
+*/
+
+#define NUM_AMIGA_SOURCES   (24)
+
+/* vertical blanking interrupt */
+#define IRQ_AMIGA_VERTB     (IRQ_MACHSPEC | 0)
+
+/* copper interrupt */
+#define IRQ_AMIGA_COPPER    (IRQ_MACHSPEC | 1)
+
+/* Audio interrupts */
+#define IRQ_AMIGA_AUD0	    (IRQ_MACHSPEC | 2)
+#define IRQ_AMIGA_AUD1	    (IRQ_MACHSPEC | 3)
+#define IRQ_AMIGA_AUD2	    (IRQ_MACHSPEC | 4)
+#define IRQ_AMIGA_AUD3	    (IRQ_MACHSPEC | 5)
+
+/* Blitter done interrupt */
+#define IRQ_AMIGA_BLIT	    (IRQ_MACHSPEC | 6)
+
+/* floppy disk interrupts */
+#define IRQ_AMIGA_DSKSYN    (IRQ_MACHSPEC | 7)
+#define IRQ_AMIGA_DSKBLK    (IRQ_MACHSPEC | 8)
+
+/* builtin serial port interrupts */
+#define IRQ_AMIGA_RBF	    (IRQ_MACHSPEC | 9)
+#define IRQ_AMIGA_TBE	    (IRQ_MACHSPEC | 10)
+
+/* CIA interrupt sources */
+#define IRQ_AMIGA_CIAA_TA   (IRQ_MACHSPEC | 11)
+#define IRQ_AMIGA_CIAA_TB   (IRQ_MACHSPEC | 12)
+#define IRQ_AMIGA_CIAA_ALRM (IRQ_MACHSPEC | 13)
+#define IRQ_AMIGA_CIAA_SP   (IRQ_MACHSPEC | 14)
+#define IRQ_AMIGA_CIAA_FLG  (IRQ_MACHSPEC | 15)
+#define IRQ_AMIGA_CIAB_TA   (IRQ_MACHSPEC | 16)
+#define IRQ_AMIGA_CIAB_TB   (IRQ_MACHSPEC | 17)
+#define IRQ_AMIGA_CIAB_ALRM (IRQ_MACHSPEC | 18)
+#define IRQ_AMIGA_CIAB_SP   (IRQ_MACHSPEC | 19)
+#define IRQ_AMIGA_CIAB_FLG  (IRQ_MACHSPEC | 20)
+
+#define IRQ_AMIGA_SOFT      (IRQ_MACHSPEC | 21)
+
+#define IRQ_AMIGA_PORTS	    (IRQ_MACHSPEC | 22)
+#define IRQ_AMIGA_EXTER	    (IRQ_MACHSPEC | 23)
+
+#define IRQ_FLOPPY	    IRQ_AMIGA_DSKBLK
+
+/* INTREQR masks */
+#define IRQ1_MASK   0x0007	/* INTREQR mask for IRQ 1 */
+#define IRQ2_MASK   0x0008	/* INTREQR mask for IRQ 2 */
+#define IRQ3_MASK   0x0070	/* INTREQR mask for IRQ 3 */
+#define IRQ4_MASK   0x0780	/* INTREQR mask for IRQ 4 */
+#define IRQ5_MASK   0x1800	/* INTREQR mask for IRQ 5 */
+#define IRQ6_MASK   0x2000	/* INTREQR mask for IRQ 6 */
+#define IRQ7_MASK   0x4000	/* INTREQR mask for IRQ 7 */
+
+#define IF_SETCLR   0x8000      /* set/clr bit */
+#define IF_INTEN    0x4000	/* master interrupt bit in INT* registers */
+#define IF_EXTER    0x2000	/* external level 6 and CIA B interrupt */
+#define IF_DSKSYN   0x1000	/* disk sync interrupt */
+#define IF_RBF	    0x0800	/* serial receive buffer full interrupt */
+#define IF_AUD3     0x0400	/* audio channel 3 done interrupt */
+#define IF_AUD2     0x0200	/* audio channel 2 done interrupt */
+#define IF_AUD1     0x0100	/* audio channel 1 done interrupt */
+#define IF_AUD0     0x0080	/* audio channel 0 done interrupt */
+#define IF_BLIT     0x0040	/* blitter done interrupt */
+#define IF_VERTB    0x0020	/* vertical blanking interrupt */
+#define IF_COPER    0x0010	/* copper interrupt */
+#define IF_PORTS    0x0008	/* external level 2 and CIA A interrupt */
+#define IF_SOFT     0x0004	/* software initiated interrupt */
+#define IF_DSKBLK   0x0002	/* diskblock DMA finished */
+#define IF_TBE	    0x0001	/* serial transmit buffer empty interrupt */
+
+/* CIA interrupt control register bits */
+
+#define CIA_ICR_TA   0x01
+#define CIA_ICR_TB   0x02
+#define CIA_ICR_ALRM 0x04
+#define CIA_ICR_SP   0x08
+#define CIA_ICR_FLG  0x10
+
+#endif /* asm-m68k/amigaints.h */
diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/amigamouse.h linux/include/asm-m68k/amigamouse.h
--- v1.3.93/linux/include/asm-m68k/amigamouse.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-m68k/amigamouse.h	Thu Feb 29 17:41:01 1996
@@ -0,0 +1,26 @@
+#ifndef _ASMm68k_AMIGAMOUSE_H
+#define _ASMm68k_AMIGAMOUSE_H
+
+/*
+ *  linux/include/asm-m68k/amigamouse.h: header file for Amiga Mouse driver
+ *  by Michael Rausch
+ */
+
+/*
+#define MSE_INT_OFF()	outb(MSE_DISABLE_INTERRUPTS, MSE_CONTROL_PORT)
+#define MSE_INT_ON()	outb(MSE_ENABLE_INTERRUPTS, MSE_CONTROL_PORT)
+*/ 
+
+struct mouse_status {
+	unsigned char	buttons;
+	unsigned char	latch_buttons;
+	int		dx;
+	int		dy;	
+	int 		present;
+	int		ready;
+	int		active;
+	struct wait_queue *wait;
+	struct fasync_struct *fasyncptr;
+};
+
+#endif
diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/amigardb.h linux/include/asm-m68k/amigardb.h
--- v1.3.93/linux/include/asm-m68k/amigardb.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-m68k/amigardb.h	Wed Dec 27 22:46:44 1995
@@ -0,0 +1,126 @@
+#ifndef _LINUX_AMIGARDB_H
+#define _LINUX_AMIGARDB_H 1
+
+#define ULONG	u_long
+#define LONG	long
+#define UBYTE	u_char
+
+/* definitions for the Amiga RigidDiskBlock layout, which always starts in 
+   cylinder 0 of a medium. Taken from page 254f of the RKM: Devices */
+
+struct RigidDiskBlock {
+    ULONG   rdb_ID;		/* 4 character identifier */
+    ULONG   rdb_SummedLongs;	/* size of this checksummed structure */
+    LONG    rdb_ChkSum;		/* block checksum (longword sum to zero) */
+    ULONG   rdb_HostID;		/* SCSI Target ID of host */
+    ULONG   rdb_BlockBytes;	/* size of disk blocks */
+    ULONG   rdb_Flags;		/* see below for defines */
+    /* block list heads */
+    ULONG   rdb_BadBlockList;	/* optional bad block list */
+    ULONG   rdb_PartitionList;	/* optional first partition block */
+    ULONG   rdb_FileSysHeaderList; /* optional file system header block */
+    ULONG   rdb_DriveInit;	/* optional drive-specific init code */
+				/* DriveInit(lun,rdb,ior): "C" stk & d0/a0/a1 */
+    ULONG   rdb_Reserved1[6];	/* set to $ffffffff */
+    /* physical drive characteristics */
+    ULONG   rdb_Cylinders;	/* number of drive cylinders */
+    ULONG   rdb_Sectors;	/* sectors per track */
+    ULONG   rdb_Heads;		/* number of drive heads */
+    ULONG   rdb_Interleave;	/* interleave */
+    ULONG   rdb_Park;		/* landing zone cylinder */
+    ULONG   rdb_Reserved2[3];
+    ULONG   rdb_WritePreComp;	/* starting cylinder: write precompensation */
+    ULONG   rdb_ReducedWrite;	/* starting cylinder: reduced write current */
+    ULONG   rdb_StepRate;	/* drive step rate */
+    ULONG   rdb_Reserved3[5];
+    /* logical drive characteristics */
+    ULONG   rdb_RDBBlocksLo;	/* low block of range reserved for hardblocks */
+    ULONG   rdb_RDBBlocksHi;	/* high block of range for these hardblocks */
+    ULONG   rdb_LoCylinder;	/* low cylinder of partitionable disk area */
+    ULONG   rdb_HiCylinder;	/* high cylinder of partitionable data area */
+    ULONG   rdb_CylBlocks;	/* number of blocks available per cylinder */
+    ULONG   rdb_AutoParkSeconds; /* zero for no auto park */
+    ULONG   rdb_HighRDSKBlock;	/* highest block used by RDSK */
+				/* (not including replacement bad blocks) */
+    ULONG   rdb_Reserved4;
+    /* drive identification */
+    char    rdb_DiskVendor[8];
+    char    rdb_DiskProduct[16];
+    char    rdb_DiskRevision[4];
+    char    rdb_ControllerVendor[8];
+    char    rdb_ControllerProduct[16];
+    char    rdb_ControllerRevision[4];
+    ULONG   rdb_Reserved5[10];
+};
+
+#define	IDNAME_RIGIDDISK	0x5244534B	/* 'RDSK' */
+
+#define	RDB_LOCATION_LIMIT	16
+
+#define	RDBFB_LAST	0	/* no disks exist to be configured after */
+#define	RDBFF_LAST	0x01L	/*   this one on this controller */
+#define	RDBFB_LASTLUN	1	/* no LUNs exist to be configured greater */
+#define	RDBFF_LASTLUN	0x02L	/*   than this one at this SCSI Target ID */
+#define	RDBFB_LASTTID	2	/* no Target IDs exist to be configured */
+#define	RDBFF_LASTTID	0x04L	/*   greater than this one on this SCSI bus */
+#define	RDBFB_NORESELECT 3	/* don't bother trying to perform reselection */
+#define	RDBFF_NORESELECT 0x08L	/*   when talking to this drive */
+#define	RDBFB_DISKID	4	/* rdb_Disk... identification valid */
+#define	RDBFF_DISKID	0x10L
+#define	RDBFB_CTRLRID	5	/* rdb_Controller... identification valid */
+#define	RDBFF_CTRLRID	0x20L
+				/* added 7/20/89 by commodore: */
+#define RDBFB_SYNCH	6	/* drive supports scsi synchronous mode */
+#define RDBFF_SYNCH	0x40L	/* CAN BE DANGEROUS TO USE IF IT DOESN'T! */
+
+struct PartitionBlock {
+    ULONG   pb_ID;		/* 4 character identifier */
+    ULONG   pb_SummedLongs;	/* size of this checksummed structure */
+    LONG    pb_ChkSum;		/* block checksum (longword sum to zero) */
+    ULONG   pb_HostID;		/* SCSI Target ID of host */
+    ULONG   pb_Next;		/* block number of the next PartitionBlock */
+    ULONG   pb_Flags;		/* see below for defines */
+    ULONG   pb_Reserved1[2];
+    ULONG   pb_DevFlags;	/* preferred flags for OpenDevice */
+    UBYTE   pb_DriveName[32];	/* preferred DOS device name: BSTR form */
+				/* (not used if this name is in use) */
+    ULONG   pb_Reserved2[15];	/* filler to 32 longwords */
+    ULONG   pb_Environment[17];	/* environment vector for this partition */
+    ULONG   pb_EReserved[15];	/* reserved for future environment vector */
+};
+
+#define	IDNAME_PARTITION	0x50415254	/* 'PART' */
+
+#define	PBFB_BOOTABLE	0	/* this partition is intended to be bootable */
+#define	PBFF_BOOTABLE	1L	/*   (expected directories and files exist) */
+#define	PBFB_NOMOUNT	1	/* do not mount this partition (e.g. manually */
+#define	PBFF_NOMOUNT	2L	/*   mounted, but space reserved here) */
+
+/* this is from <dos/filehandler.h> */
+
+#define DE_TABLESIZE	0	/* minimum value is 11 (includes NumBuffers) */
+#define DE_SIZEBLOCK	1	/* in longwords: standard value is 128 */
+#define DE_SECORG	2	/* not used; must be 0 */
+#define DE_NUMHEADS	3	/* # of heads (surfaces). drive specific */
+#define DE_SECSPERBLK	4	/* not used; must be 1 */
+#define DE_BLKSPERTRACK 5	/* blocks per track. drive specific */
+#define DE_RESERVEDBLKS 6	/* unavailable blocks at start.	 usually 2 */
+#define DE_PREFAC	7	/* not used; must be 0 */
+#define DE_INTERLEAVE	8	/* usually 0 */
+#define DE_LOWCYL	9	/* starting cylinder. typically 0 */
+#define DE_UPPERCYL	10	/* max cylinder.  drive specific */
+#define DE_NUMBUFFERS	11	/* starting # of buffers.  typically 5 */
+#define DE_MEMBUFTYPE	12	/* type of mem to allocate for buffers. */
+#define DE_BUFMEMTYPE	12	/* same as above, better name
+				 * 1 is public, 3 is chip, 5 is fast */
+#define DE_MAXTRANSFER	13	/* Max number bytes to transfer at a time */
+#define DE_MASK		14	/* Address Mask to block out certain memory */
+#define DE_BOOTPRI	15	/* Boot priority for autoboot */
+#define DE_DOSTYPE	16	/* ASCII (HEX) string showing filesystem type;
+				 * 0X444F5300 is old filesystem,
+				 * 0X444F5301 is fast file system */
+#define DE_BAUD		17	/* Baud rate for serial handler */
+#define DE_CONTROL	18	/* Control word for handler/filesystem */
+#define DE_BOOTBLOCKS	19	/* Number of blocks containing boot code */
+
+#endif /* _LINUX_AMIGARDB_H */
diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/amigatypes.h linux/include/asm-m68k/amigatypes.h
--- v1.3.93/linux/include/asm-m68k/amigatypes.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-m68k/amigatypes.h	Thu Mar  7 18:54:36 1996
@@ -0,0 +1,59 @@
+/*
+** linux/amigatypes.h -- Types used in Amiga Linux kernel source
+**
+** Copyright 1992 by Greg Harp
+**
+** This file is subject to the terms and conditions of the GNU General Public
+** License.  See the file README.legal in the main directory of this archive
+** for more details.
+**
+** Created 09/29/92 by Greg Harp
+**
+** Moved all Zorro definitions to asm/zorro.h which is where they
+** really belong - 24/11/95 Jes Sorensen
+*/
+
+#ifndef _LINUX_AMIGATYPES_H_
+#define _LINUX_AMIGATYPES_H_
+
+#ifdef __KERNEL__ /* only if compiling the kernel */
+#include <linux/types.h>
+#endif
+
+/*
+ * Different models of Amiga
+ */
+#define AMI_UNKNOWN	(0)
+#define AMI_500		(1)
+#define AMI_500PLUS	(2)
+#define AMI_600		(3)
+#define AMI_1000	(4)
+#define AMI_1200	(5)
+#define AMI_2000	(6)
+#define AMI_2500	(7)
+#define AMI_3000	(8)
+#define AMI_3000T	(9)
+#define AMI_3000PLUS	(10)
+#define AMI_4000	(11)
+#define AMI_4000T	(12)
+#define AMI_CDTV	(13)
+#define AMI_CD32	(14)
+#define AMI_DRACO	(15)
+
+/*
+ * chipsets
+ */
+#define CS_STONEAGE (0)
+#define CS_OCS	    (1)
+#define CS_ECS	    (2)
+#define CS_AGA	    (3)
+
+/*
+ * Amiga clocks
+ */
+
+extern u_long amiga_masterclock;			/* 28 MHz */
+extern u_long amiga_colorclock;				/* 3.5 MHz */
+#define amiga_eclock	boot_info.bi_amiga.eclock	/* 700 kHz */
+
+#endif /* asm-m68k/amigatypes.h */
diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/amihdreg.h linux/include/asm-m68k/amihdreg.h
--- v1.3.93/linux/include/asm-m68k/amihdreg.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-m68k/amihdreg.h	Mon Apr  1 00:50:11 1996
@@ -0,0 +1,31 @@
+#ifndef _LINUX_AMIHDREG_H
+#define _LINUX_AMIHDREG_H
+
+/*
+ * This file contains some defines for the Amiga IDE hd controller.
+ * Various sources. Check out some definitions (see comments with
+ * a ques).
+ */
+
+#define IDE_DISABLE_IRQ  0x02
+#define IDE_ENABLE_IRQ   0x00
+ 
+/* Bases of the hard drive controller */
+#define HD_BASE_A4000   0xdd2020
+#define HD_BASE_A1200   0xda0000
+
+/* Offsets from one of the above bases */
+#define AMI_HD_ERROR	(0x06)		/* see err-bits */
+#define AMI_HD_NSECTOR	(0x0a)		/* nr of sectors to read/write */
+#define AMI_HD_SECTOR	(0x0e)		/* starting sector */
+#define AMI_HD_LCYL	(0x12)		/* starting cylinder */
+#define AMI_HD_HCYL	(0x16)		/* high byte of starting cyl */
+#define AMI_HD_SELECT	(0x1a)		/* 101dhhhh , d=drive, hhhh=head */
+#define AMI_HD_STATUS	(0x1e)		/* see status-bits */
+#define AMI_HD_CMD	(0x101a)
+
+/* These are at different offsets from the base */
+#define HD_A4000_IRQ	(0xdd3020)	/* MSB = 1, Harddisk is source of interrupt */
+#define HD_A1200_IRQ	(0xda9000)	/* MSB = 1, Harddisk is source of interrupt */
+
+#endif
diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/atafd.h linux/include/asm-m68k/atafd.h
--- v1.3.93/linux/include/asm-m68k/atafd.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-m68k/atafd.h	Thu Mar  7 21:59:49 1996
@@ -0,0 +1,12 @@
+#ifndef _ASM_M68K_FD_H
+#define _ASM_M68K_FD_H
+
+/* Definitions for the Atari Floppy driver */
+
+struct atari_format_descr {
+    int track;			/* to be formatted */
+    int head;			/*   ""     ""     */
+    int sect_offset;		/* offset of first sector */
+};
+
+#endif
diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/atafdreg.h linux/include/asm-m68k/atafdreg.h
--- v1.3.93/linux/include/asm-m68k/atafdreg.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-m68k/atafdreg.h	Mon Mar  4 22:47:31 1996
@@ -0,0 +1,79 @@
+#ifndef _LINUX_FDREG_H
+#define _LINUX_FDREG_H
+
+/*
+** WD1772 stuff
+ */
+
+/* register codes */
+
+#define FDCSELREG_STP   (0x80)   /* command/status register */
+#define FDCSELREG_TRA   (0x82)   /* track register */
+#define FDCSELREG_SEC   (0x84)   /* sector register */
+#define FDCSELREG_DTA   (0x86)   /* data register */
+
+/* register names for FDC_READ/WRITE macros */
+
+#define FDCREG_CMD		0
+#define FDCREG_STATUS	0
+#define FDCREG_TRACK	2
+#define FDCREG_SECTOR	4
+#define FDCREG_DATA		6
+
+/* command opcodes */
+
+#define FDCCMD_RESTORE  (0x00)   /*  -                   */
+#define FDCCMD_SEEK     (0x10)   /*   |                  */
+#define FDCCMD_STEP     (0x20)   /*   |  TYP 1 Commands  */
+#define FDCCMD_STIN     (0x40)   /*   |                  */
+#define FDCCMD_STOT     (0x60)   /*  -                   */
+#define FDCCMD_RDSEC    (0x80)   /*  -   TYP 2 Commands  */
+#define FDCCMD_WRSEC    (0xa0)   /*  -          "        */
+#define FDCCMD_RDADR    (0xc0)   /*  -                   */
+#define FDCCMD_RDTRA    (0xe0)   /*   |  TYP 3 Commands  */
+#define FDCCMD_WRTRA    (0xf0)   /*  -                   */
+#define FDCCMD_FORCI    (0xd0)   /*  -   TYP 4 Command   */
+
+/* command modifier bits */
+
+#define FDCCMDADD_SR6   (0x00)   /* step rate settings */
+#define FDCCMDADD_SR12  (0x01)
+#define FDCCMDADD_SR2   (0x02)
+#define FDCCMDADD_SR3   (0x03)
+#define FDCCMDADD_V     (0x04)   /* verify */
+#define FDCCMDADD_H     (0x08)   /* wait for spin-up */
+#define FDCCMDADD_U     (0x10)   /* update track register */
+#define FDCCMDADD_M     (0x10)   /* multiple sector access */
+#define FDCCMDADD_E     (0x04)   /* head settling flag */
+#define FDCCMDADD_P     (0x02)   /* precompensation off */
+#define FDCCMDADD_A0    (0x01)   /* DAM flag */
+
+/* status register bits */
+
+#define	FDCSTAT_MOTORON	(0x80)   /* motor on */
+#define	FDCSTAT_WPROT	(0x40)   /* write protected (FDCCMD_WR*) */
+#define	FDCSTAT_SPINUP	(0x20)   /* motor speed stable (Type I) */
+#define	FDCSTAT_DELDAM	(0x20)   /* sector has deleted DAM (Type II+III) */
+#define	FDCSTAT_RECNF	(0x10)   /* record not found */
+#define	FDCSTAT_CRC		(0x08)   /* CRC error */
+#define	FDCSTAT_TR00	(0x04)   /* Track 00 flag (Type I) */
+#define	FDCSTAT_LOST	(0x04)   /* Lost Data (Type II+III) */
+#define	FDCSTAT_IDX		(0x02)   /* Index status (Type I) */
+#define	FDCSTAT_DRQ		(0x02)   /* DRQ status (Type II+III) */
+#define	FDCSTAT_BUSY	(0x01)   /* FDC is busy */
+
+
+/* PSG Port A Bit Nr 0 .. Side Sel .. 0 -> Side 1  1 -> Side 2 */
+#define DSKSIDE     (0x01)
+        
+#define DSKDRVNONE  (0x06)
+#define DSKDRV0     (0x02)
+#define DSKDRV1     (0x04)
+
+/* step rates */
+#define	FDCSTEP_6	0x00
+#define	FDCSTEP_12	0x01
+#define	FDCSTEP_2	0x02
+#define	FDCSTEP_3	0x03
+
+#endif
diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/atari_joystick.h linux/include/asm-m68k/atari_joystick.h
--- v1.3.93/linux/include/asm-m68k/atari_joystick.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-m68k/atari_joystick.h	Sat Mar 30 14:11:24 1996
@@ -0,0 +1,22 @@
+#ifndef _LINUX_ATARI_JOYSTICK_H
+#define _LINUX_ATARI_JOYSTICK_H
+
+/*
+ * linux/include/linux/atari_joystick.h
+ * header file for Atari Joystick driver
+ * by Robert de Vries (robert@and.nl) on 19Jul93
+ */
+
+void atari_joystick_interrupt(char*);
+int atari_joystick_init(void);
+extern int atari_mouse_buttons;
+
+struct joystick_status {
+	char		fire;
+	char		dir;
+	int		ready;
+	int		active;
+	struct wait_queue *wait;
+};
+
+#endif
diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/atari_mouse.h linux/include/asm-m68k/atari_mouse.h
--- v1.3.93/linux/include/asm-m68k/atari_mouse.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-m68k/atari_mouse.h	Mon Mar  4 22:47:32 1996
@@ -0,0 +1,20 @@
+#ifndef _LINUX_ATARI_MOUSE_H
+#define _LINUX_ATARI_MOUSE_H
+
+/*
+ * linux/include/linux/atari_mouse.h
+ * header file for Atari Mouse driver
+ * by Robert de Vries (robert@and.nl) on 19Jul93
+ */
+
+struct mouse_status {
+	char		buttons;
+	short		dx;
+	short		dy;
+	int		ready;
+	int		active;
+	struct wait_queue *wait;
+	struct fasync_struct *fasyncptr;
+};
+
+#endif
diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/atari_rootsec.h linux/include/asm-m68k/atari_rootsec.h
--- v1.3.93/linux/include/asm-m68k/atari_rootsec.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-m68k/atari_rootsec.h	Wed Dec 27 22:46:46 1995
@@ -0,0 +1,34 @@
+#ifndef _LINUX_ATARI_ROOTSEC_H
+#define _LINUX_ATARI_ROOTSEC_H
+
+/*
+ * linux/include/linux/atari_rootsec.h
+ * definitions for Atari Rootsector layout
+ * by Andreas Schwab (schwab@ls5.informatik.uni-dortmund.de)
+ *
+ * modified for ICD/Supra partitioning scheme restricted to at most 12
+ * partitions
+ * by Guenther Kelleter (guenther@pool.informatik.rwth-aachen.de)
+ */
+
+struct partition_info
+{
+  u_char flg;			/* bit 0: active; bit 7: bootable */
+  char id[3];			/* "GEM", "BGM", "XGM", or other */
+  u_long st;			/* start of partition */
+  u_long siz;			/* length of partition */
+};
+
+struct rootsector
+{
+  char unused[0x156];		/* room for boot code */
+  struct partition_info icdpart[8];	/* info for ICD-partitions 5..12 */
+  char unused2[0xc];
+  u_long hd_siz;		/* size of disk in blocks */
+  struct partition_info part[4];
+  u_long bsl_st;		/* start of bad sector list */
+  u_long bsl_cnt;		/* length of bad sector list */
+  u_short checksum;		/* checksum for bootable disks */
+};
+
+#endif /* _LINUX_ATARI_ROOTSEC_H */
diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/atari_stdma.h linux/include/asm-m68k/atari_stdma.h
--- v1.3.93/linux/include/asm-m68k/atari_stdma.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-m68k/atari_stdma.h	Fri Apr 19 02:35:24 1996
@@ -0,0 +1,22 @@
+
+#ifndef _atari_stdma_h
+#define _atari_stdma_h
+
+
+#include <asm/irq.h>
+
+
+/***************************** Prototypes *****************************/
+
+void stdma_lock(isrfunc isr, void *data); 
+void stdma_release( void );
+int stdma_others_waiting( void );
+int stdma_islocked( void );
+void *stdma_locked_by( void );
+void stdma_init( void );
+
+/************************* End of Prototypes **************************/
+
+
+
+#endif  /* _atari_stdma_h */
diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/atarihdreg.h linux/include/asm-m68k/atarihdreg.h
--- v1.3.93/linux/include/asm-m68k/atarihdreg.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-m68k/atarihdreg.h	Fri Apr 19 02:35:24 1996
@@ -0,0 +1,24 @@
+#ifndef _LINUX_ATAHDREG_H
+#define _LINUX_ATAHDREG_H
+
+/*
+ * This file contains some defines for the Falcon IDE hd controller.
+ * Various sources. Check out some definitions (see comments with
+ * a ques).
+ */
+
+#define ATA_HD_BASE	0xfff00000
+
+#define ATA_HD_DATA	0x00	/* _CTL when writing */
+#define ATA_HD_ERROR	0x05	/* see err-bits */
+#define ATA_HD_NSECTOR	0x09	/* nr of sectors to read/write */
+#define ATA_HD_SECTOR	0x0d	/* starting sector */
+#define ATA_HD_LCYL	0x11	/* starting cylinder */
+#define ATA_HD_HCYL	0x15	/* high byte of starting cyl */
+#define ATA_HD_CURRENT	0x19	/* 101dhhhh , d=drive, hhhh=head */
+#define ATA_HD_STATUS	0x1d	/* see status-bits */
+
+#define ATA_HD_CMD	0x39
+#define ATA_HD_ALTSTATUS 0x39	/* same as HD_STATUS but doesn't clear irq */
+
+#endif	/* _LINUX_ATAHDREG_H */
diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/atarihw.h linux/include/asm-m68k/atarihw.h
--- v1.3.93/linux/include/asm-m68k/atarihw.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-m68k/atarihw.h	Mon Mar  4 22:47:32 1996
@@ -0,0 +1,633 @@
+/*
+** linux/atarihw.h -- This header defines some macros and pointers for
+**                    the various Atari custom hardware registers.
+**
+** Copyright 1994 by Bj”rn Brauel
+**
+** 5/1/94 Roman Hodek:
+**   Added definitions for TT specific chips.
+**
+** This file is subject to the terms and conditions of the GNU General Public
+** License.  See the file README.legal in the main directory of this archive
+** for more details.
+**
+*/
+
+#ifndef _LINUX_ATARIHW_H_
+#define _LINUX_ATARIHW_H_
+
+#include <linux/types.h>
+
+/* Reading the MFP port register gives a machine independant delay, since the
+ * MFP always has a 8 MHz clock. This avoids problems with the varying length
+ * of nops on various machines. Somebody claimed that the tstb takes 600 ns.
+ */
+#define	MFPDELAY() \
+	__asm__ __volatile__ ( "tstb %0" : : "m" (mfp.par_dt_reg) : "cc" );
+
+/* Memory used for screen ram and stdma buffers */
+void atari_stram_init (void);
+void *atari_stram_alloc (long size, unsigned long *start_mem );
+void atari_stram_free (void *);
+
+extern int is_medusa;
+
+/* Do cache push/invalidate for DMA read/write. This function obeys the
+ * snooping on some machines (Medusa) and processors: The Medusa itself can
+ * snoop, but only the '040 can source data from its cache to DMA writes i.e.,
+ * reads from memory). Both '040 and '060 invalidate cache entries on snooped
+ * DMA reads (i.e., writes to memory).
+ */
+
+#include <linux/mm.h>
+#include <asm/pgtable.h>
+
+static inline void dma_cache_maintainance( unsigned long paddr,
+					  unsigned long len,
+					  int writeflag )
+
+{
+	if (writeflag) {
+		if (!is_medusa || m68k_is040or060 == 6)
+			cache_push( paddr, len );
+	}
+	else {
+		if (!is_medusa)
+			cache_clear( paddr, len );
+	}
+}
+
+
+/* 
+** Shifter  
+ */
+#define ST_LOW  0
+#define ST_MID  1
+#define ST_HIGH 2
+#define TT_LOW  7
+#define TT_MID  4
+#define TT_HIGH 6
+
+#define SHF_BAS (0xffff8200)    
+struct SHIFTER 
+ {
+ 	u_char pad1;
+	u_char bas_hi;
+	u_char pad2;
+	u_char bas_md;
+	u_char pad3;
+	u_char volatile vcounthi;
+ 	u_char pad4;
+ 	u_char volatile vcountmid;
+ 	u_char pad5;
+ 	u_char volatile vcountlow;
+ 	u_char volatile syncmode;
+ 	u_char pad6;
+ 	u_char pad7; 
+	u_char bas_lo;
+ };
+# define shifter ((*(volatile struct SHIFTER *)SHF_BAS))
+
+#define SHF_FBAS (0xffff820e)
+struct SHIFTER_F030
+ {
+  u_short off_next;
+  u_short scn_width;
+ };                             
+# define shifter_f030 ((*(volatile struct SHIFTER_F030 *)SHF_FBAS))
+
+
+#define	SHF_TBAS (0xffff8200)
+struct SHIFTER_TT {
+	u_char	char_dummy0;
+	u_char	bas_hi;			/* video mem base addr, high and mid byte */
+	u_char	char_dummy1;
+	u_char	bas_md;
+	u_char	char_dummy2;
+	u_char	vcount_hi;		/* pointer to currently displayed byte */
+	u_char	char_dummy3;
+	u_char	vcount_md;
+	u_char	char_dummy4;
+	u_char	vcount_lo;
+	u_short	st_sync;		/* ST compatible sync mode register, unused */
+	u_char	char_dummy5;
+	u_char	bas_lo;			/* video mem addr, low byte */
+	u_char	char_dummy6[2+3*16];
+	/* $ffff8240: */
+	u_short	color_reg[16];	/* 16 color registers */
+	u_char	st_shiftmode;	/* ST compatible shift mode register, unused */
+	u_char  char_dummy7;
+	u_short tt_shiftmode;	/* TT shift mode register */
+
+
+};
+#define	shifter_tt	((*(volatile struct SHIFTER_TT *)SHF_TBAS))
+
+/* values for shifter_tt->tt_shiftmode */
+#define	TT_SHIFTER_STLOW		0x0000
+#define	TT_SHIFTER_STMID		0x0100
+#define	TT_SHIFTER_STHIGH		0x0200
+#define	TT_SHIFTER_TTLOW		0x0700
+#define	TT_SHIFTER_TTMID		0x0400
+#define	TT_SHIFTER_TTHIGH		0x0600
+#define	TT_SHIFTER_MODEMASK	0x0700
+#define TT_SHIFTER_NUMMODE	0x0008
+#define	TT_SHIFTER_PALETTE_MASK	0x000f
+#define	TT_SHIFTER_GRAYMODE		0x1000
+
+/* 256 TT palette registers */
+#define	TT_PALETTE_BASE	(0xffff8400)
+#define	tt_palette	((volatile u_short *)TT_PALETTE_BASE)
+
+#define	TT_PALETTE_RED_MASK		0x0f00
+#define	TT_PALETTE_GREEN_MASK	0x00f0
+#define	TT_PALETTE_BLUE_MASK	0x000f
+
+/*
+** Falcon030 VIDEL Video Controller
+** for description see File 'linux\tools\atari\hardware.txt
+ */
+#define f030_col ((u_long *)		0xffff9800)
+#define f030_xreg ((u_short*)		0xffff8282)
+#define f030_yreg ((u_short*)		0xffff82a2)
+#define f030_creg ((u_short*)		0xffff82c0)
+#define f030_sreg ((u_short*)		0xffff8260)
+#define f030_mreg ((u_short*)		0xffff820a)
+#define f030_linewidth ((u_short*)      0xffff820e)
+#define f030_hscroll ((u_char*)		0xffff8265)
+
+#define VIDEL_BAS (0xffff8260)
+struct VIDEL {
+	u_short st_shift;
+	u_short pad1;
+	u_char  xoffset_s;
+	u_char  xoffset;
+	u_short f_shift;
+	u_char  pad2[0x1a];
+	u_short hht;
+	u_short hbb;
+	u_short hbe;
+	u_short hdb;
+	u_short hde;
+	u_short hss;
+	u_char  pad3[0x14];
+	u_short vft;
+	u_short vbb;
+	u_short vbe;
+	u_short vdb;
+	u_short vde;
+	u_short vss;
+	u_char  pad4[0x12];
+	u_short control;
+	u_short mode;
+};
+#define	videl	((*(volatile struct VIDEL *)VIDEL_BAS))
+
+/*
+** DMA/WD1772 Disk Controller
+ */                          
+ 
+#define FWD_BAS (0xffff8604)  
+struct DMA_WD
+ {
+  u_short fdc_acces_seccount;
+  u_short dma_mode_status;
+  u_char dma_vhi;	/* Some extended ST-DMAs can handle 32 bit addresses */
+  u_char dma_hi;
+  u_char char_dummy2;
+  u_char dma_md;
+  u_char char_dummy3;
+  u_char dma_lo;
+  u_short fdc_speed;
+ };
+# define dma_wd ((*(volatile struct DMA_WD *)FWD_BAS))
+/* alias */
+#define	st_dma dma_wd
+/* The two highest bytes of an extended DMA as a short; this is a must
+ * for the Medusa.
+ */
+#define st_dma_ext_dmahi (*((volatile unsigned short *)0xffff8608))
+
+/*
+** YM2149 Sound Chip
+** access in bytes
+ */
+
+#define YM_BAS (0xffff8800)
+struct SOUND_YM
+ {
+  u_char rd_data_reg_sel;
+  u_char char_dummy1;
+  u_char wd_data;
+ };
+#define sound_ym ((*(volatile struct SOUND_YM *)YM_BAS))
+
+/* TT SCSI DMA */
+
+#define	TT_SCSI_DMA_BAS	(0xffff8700)
+struct TT_DMA {
+	u_char	char_dummy0;
+	u_char	dma_addr_hi;
+	u_char	char_dummy1;
+	u_char	dma_addr_hmd;
+	u_char	char_dummy2;
+	u_char	dma_addr_lmd;
+	u_char	char_dummy3;
+	u_char	dma_addr_lo;
+	u_char	char_dummy4;
+	u_char	dma_cnt_hi;
+	u_char	char_dummy5;
+	u_char	dma_cnt_hmd;
+	u_char	char_dummy6;
+	u_char	dma_cnt_lmd;
+	u_char	char_dummy7;
+	u_char	dma_cnt_lo;
+	u_long	dma_restdata;
+	u_short	dma_ctrl;
+};
+#define	tt_scsi_dma	((*(volatile struct TT_DMA *)TT_SCSI_DMA_BAS))
+
+/* TT SCSI Controller 5380 */
+
+#define	TT_5380_BAS	(0xffff8781)
+struct TT_5380 {
+	u_char	scsi_data;
+	u_char	char_dummy1;
+	u_char	scsi_icr;
+	u_char	char_dummy2;
+	u_char	scsi_mode;
+	u_char	char_dummy3;
+	u_char	scsi_tcr;
+	u_char	char_dummy4;
+	u_char	scsi_idstat;
+	u_char	char_dummy5;
+	u_char	scsi_dmastat;
+	u_char	char_dummy6;
+	u_char	scsi_targrcv;
+	u_char	char_dummy7;
+	u_char	scsi_inircv;
+};
+#define	tt_scsi			((*(volatile struct TT_5380 *)TT_5380_BAS))
+#define	tt_scsi_regp	((volatile char *)TT_5380_BAS)
+
+
+/* 
+** Falcon DMA Sound Subsystem
+** not implemented yet
+ */     
+
+/*
+** Falcon Blitter
+*/
+
+#define BLT_BAS (0xffff8a00)
+
+struct BLITTER
+ {
+  u_short halftone[16];
+  u_short src_x_inc;
+  u_short src_y_inc;
+  u_long src_address;
+  u_short endmask1;  
+  u_short endmask2;  
+  u_short endmask3;
+  u_short dst_x_inc;
+  u_short dst_y_inc;
+  u_long dst_adress;
+  u_short wd_per_line;
+  u_short ln_per_bb;
+  u_short hlf_op_reg;
+  u_short log_op_reg;
+  u_short lin_nm_reg;
+  u_short skew_reg;  
+ };
+# define blitter ((*(volatile struct BLITTER *)BLT_BAS))
+
+
+/*
+** SCC Z8530
+ */
+ 
+#define SCC_BAS (0xffff8c81)
+struct SCC
+ {
+  u_char cha_a_ctrl;
+  u_char char_dummy1;
+  u_char cha_a_data;
+  u_char char_dummy2;
+  u_char cha_b_ctrl;
+  u_char char_dummy3;
+  u_char cha_b_data;
+ };
+# define scc ((*(volatile struct SCC*)SCC_BAS))
+
+/* The ESCC (Z85230) in an Atari ST. The channels are revered! */
+# define st_escc ((*(volatile struct SCC*)0xfffffa31))
+# define st_escc_dsr ((*(volatile char *)0xfffffa39))
+
+/* TT SCC DMA Controller (same chip as SCSI DMA) */
+
+#define	TT_SCC_DMA_BAS	(0xffff8c01)
+#define	tt_scc_dma	((*(volatile struct TT_DMA *)TT_SCC_DMA_BAS))
+
+/*
+** VIDEL Palette Register 
+ */
+
+#define FPL_BAS (0xffff9800)
+struct VIDEL_PALETTE
+ {
+  u_long reg[256];
+ };
+# define videl_palette ((*(volatile struct VIDEL_PALETTE*)FPL_BAS))
+
+
+/*
+** Falcon DSP Host Interface
+** not implemented yet
+ */
+ 
+/*
+** MFP 68901
+ */
+ 
+#define MFP_BAS (0xfffffa01)
+struct MFP
+ {
+  u_char par_dt_reg;
+  u_char char_dummy1;
+  u_char active_edge;
+  u_char char_dummy2;
+  u_char data_dir;
+  u_char char_dummy3;
+  u_char int_en_a;
+  u_char char_dummy4;
+  u_char int_en_b;
+  u_char char_dummy5;
+  u_char int_pn_a;
+  u_char char_dummy6;
+  u_char int_pn_b;
+  u_char char_dummy7;
+  u_char int_sv_a;
+  u_char char_dummy8;
+  u_char int_sv_b;
+  u_char char_dummy9;
+  u_char int_mk_a;
+  u_char char_dummy10;
+  u_char int_mk_b;
+  u_char char_dummy11;
+  u_char vec_adr;
+  u_char char_dummy12;
+  u_char tim_ct_a;
+  u_char char_dummy13;
+  u_char tim_ct_b;
+  u_char char_dummy14;
+  u_char tim_ct_cd;
+  u_char char_dummy15;
+  u_char tim_dt_a;
+  u_char char_dummy16;
+  u_char tim_dt_b;
+  u_char char_dummy17;
+  u_char tim_dt_c;
+  u_char char_dummy18;
+  u_char tim_dt_d;
+  u_char char_dummy19;
+  u_char sync_char;
+  u_char char_dummy20;
+  u_char usart_ctr;
+  u_char char_dummy21;
+  u_char rcv_stat;
+  u_char char_dummy22;
+  u_char trn_stat;
+  u_char char_dummy23;
+  u_char usart_dta;
+ };
+# define mfp ((*(volatile struct MFP*)MFP_BAS))
+
+/* TT's second MFP */
+
+#define	TT_MFP_BAS	(0xfffffa81)
+# define tt_mfp ((*(volatile struct MFP*)TT_MFP_BAS))
+
+
+/* TT System Control Unit */
+
+#define	TT_SCU_BAS	(0xffff8e01)
+struct TT_SCU {
+	u_char	sys_mask;
+	u_char	char_dummy1;
+	u_char	sys_stat;
+	u_char	char_dummy2;
+	u_char	softint;
+	u_char	char_dummy3;
+	u_char	vmeint;
+	u_char	char_dummy4;
+	u_char	gp_reg1;
+	u_char	char_dummy5;
+	u_char	gp_reg2;
+	u_char	char_dummy6;
+	u_char	vme_mask;
+	u_char	char_dummy7;
+	u_char	vme_stat;
+};
+#define	tt_scu	((*(volatile struct TT_SCU *)TT_SCU_BAS))
+
+/* TT real time clock */
+
+#define	TT_RTC_BAS	(0xffff8961)
+struct TT_RTC {
+	u_char	regsel;
+	u_char	dummy;
+	u_char	data;
+};
+#define	tt_rtc	((*(volatile struct TT_RTC *)TT_RTC_BAS))
+
+
+/*
+** ACIA 6850
+ */
+/* constants for the ACIA registers */
+
+/* baudrate selection and reset (Baudrte = clock/factor) */
+#define ACIA_DIV1  0
+#define ACIA_DIV16 1
+#define ACIA_DIV64 2
+#define ACIA_RESET 3
+
+/* character format */
+#define ACIA_D7E2S (0<<2)	/* 7 data, even parity, 2 stop */
+#define ACIA_D7O2S (1<<2)	/* 7 data, odd parity, 2 stop */
+#define ACIA_D7E1S (2<<2)	/* 7 data, even parity, 1 stop */
+#define ACIA_D7O1S (3<<2)	/* 7 data, odd parity, 1 stop */
+#define ACIA_D8N2S (4<<2)	/* 8 data, no parity, 2 stop */
+#define ACIA_D8N1S (5<<2)	/* 8 data, no parity, 1 stop */
+#define ACIA_D8E1S (6<<2)	/* 8 data, even parity, 1 stop */
+#define ACIA_D8O1S (7<<2)	/* 8 data, odd parity, 1 stop */
+
+/* transmit control */
+#define ACIA_RLTID (0<<5)	/* RTS low, TxINT disabled */
+#define ACIA_RLTIE (1<<5)	/* RTS low, TxINT enabled */
+#define ACIA_RHTID (2<<5)	/* RTS high, TxINT disabled */
+#define ACIA_RLTIDSB (3<<5)	/* RTS low, TxINT disabled, send break */
+
+/* receive control */
+#define ACIA_RID (0<<7)		/* RxINT disabled */
+#define ACIA_RIE (1<<7)		/* RxINT enabled */
+
+/* status fields of the ACIA */
+#define ACIA_RDRF 1		/* Receive Data Register Full */
+#define ACIA_TDRE (1<<1)	/* Transmit Data Register Empty */
+#define ACIA_DCD  (1<<2)	/* Data Carrier Detect */
+#define ACIA_CTS  (1<<3)	/* Clear To Send */
+#define ACIA_FE   (1<<4)	/* Framing Error */
+#define ACIA_OVRN (1<<5)	/* Receiver Overrun */
+#define ACIA_PE   (1<<6)	/* Parity Error */
+#define ACIA_IRQ  (1<<7)	/* Interrupt Request */
+
+#define ACIA_BAS (0xfffffc00)
+struct ACIA 
+ {
+  u_char key_ctrl;
+  u_char char_dummy1;
+  u_char key_data;
+  u_char char_dummy2;
+  u_char mid_ctrl;
+  u_char char_dummy3;
+  u_char mid_data;
+ };
+# define acia ((*(volatile struct ACIA*)ACIA_BAS))
+
+#define	TT_DMASND_BAS (0xffff8900)
+struct TT_DMASND {
+	u_char	int_ctrl;	/* Falcon: Interrupt control */
+	u_char	ctrl;
+	u_char	pad2;
+	u_char	bas_hi;
+	u_char	pad3;
+	u_char	bas_mid;
+	u_char	pad4;
+	u_char	bas_low;
+	u_char	pad5;
+	u_char	addr_hi;
+	u_char	pad6;
+	u_char	addr_mid;
+	u_char	pad7;
+	u_char	addr_low;
+	u_char	pad8;
+	u_char	end_hi;
+	u_char	pad9;
+	u_char	end_mid;
+	u_char	pad10;
+	u_char	end_low;
+	u_char	pad11[12];
+	u_char	track_select;	/* Falcon */
+	u_char	mode;
+ 	u_char	pad12[14];
+ 	/* Falcon only: */
+ 	u_short	cbar_src;
+ 	u_short cbar_dst;
+ 	u_char	ext_div;
+ 	u_char	int_div;
+ 	u_char	rec_track_select;
+ 	u_char	dac_src;
+ 	u_char	adc_src;
+ 	u_char	input_gain;
+ 	u_short	output_atten;
+};
+# define tt_dmasnd ((*(volatile struct TT_DMASND *)TT_DMASND_BAS))
+
+#define	DMASND_CTRL_OFF		0x00
+#define	DMASND_CTRL_ON		0x01
+#define	DMASND_CTRL_REPEAT	0x02
+#define	DMASND_MODE_MONO	0x80
+#define	DMASND_MODE_STEREO	0x00
+#define DMASND_MODE_8BIT	0x00
+#define DMASND_MODE_16BIT	0x40	/* Falcon only */
+#define	DMASND_MODE_6KHZ	0x00	/* Falcon: mute */
+#define	DMASND_MODE_12KHZ	0x01
+#define	DMASND_MODE_25KHZ	0x02
+#define	DMASND_MODE_50KHZ	0x03
+
+#define DMASNDSetBase(bufstart)						\
+    do {								\
+	tt_dmasnd.bas_hi  = (unsigned char)(((bufstart) & 0xff0000) >> 16); \
+	tt_dmasnd.bas_mid = (unsigned char)(((bufstart) & 0x00ff00) >> 8); \
+	tt_dmasnd.bas_low = (unsigned char) ((bufstart) & 0x0000ff); \
+    } while( 0 )
+
+#define DMASNDGetAdr() ((tt_dmasnd.addr_hi << 16) +	\
+			(tt_dmasnd.addr_mid << 8) +	\
+			(tt_dmasnd.addr_low))
+
+#define DMASNDSetEnd(bufend)				\
+    do {						\
+	tt_dmasnd.end_hi  = (unsigned char)(((bufend) & 0xff0000) >> 16); \
+	tt_dmasnd.end_mid = (unsigned char)(((bufend) & 0x00ff00) >> 8); \
+	tt_dmasnd.end_low = (unsigned char) ((bufend) & 0x0000ff); \
+    } while( 0 )
+
+
+#define	TT_MICROWIRE_BAS	(0xffff8922)
+struct TT_MICROWIRE {
+	u_short	data;
+	u_short	mask;
+};
+# define tt_microwire ((*(volatile struct TT_MICROWIRE *)TT_MICROWIRE_BAS))
+
+#define	MW_LM1992_ADDR		0x0400
+
+#define	MW_LM1992_VOLUME(dB)	\
+    (0x0c0 | ((dB) < -80 ? 0 : (dB) > 0 ? 40 : (((dB) + 80) / 2)))
+#define	MW_LM1992_BALLEFT(dB)	\
+    (0x140 | ((dB) < -40 ? 0 : (dB) > 0 ? 20 : (((dB) + 40) / 2)))
+#define	MW_LM1992_BALRIGHT(dB)	\
+    (0x100 | ((dB) < -40 ? 0 : (dB) > 0 ? 20 : (((dB) + 40) / 2)))
+#define	MW_LM1992_TREBLE(dB)	\
+    (0x080 | ((dB) < -12 ? 0 : (dB) > 12 ? 12 : (((dB) / 2) + 6)))
+#define	MW_LM1992_BASS(dB)	\
+    (0x040 | ((dB) < -12 ? 0 : (dB) > 12 ? 12 : (((dB) / 2) + 6)))
+
+#define	MW_LM1992_PSG_LOW	0x000
+#define	MW_LM1992_PSG_HIGH	0x001
+#define	MW_LM1992_PSG_OFF	0x002
+
+#define MSTE_RTC_BAS	(0xfffffc21)
+
+struct MSTE_RTC {
+	u_char sec_ones;
+	u_char dummy1;
+	u_char sec_tens;
+	u_char dummy2;
+	u_char min_ones;
+	u_char dummy3;
+	u_char min_tens;
+	u_char dummy4;
+	u_char hr_ones;
+	u_char dummy5;
+	u_char hr_tens;
+	u_char dummy6;
+	u_char weekday;
+	u_char dummy7;
+	u_char day_ones;
+	u_char dummy8;
+	u_char day_tens;
+	u_char dummy9;
+	u_char mon_ones;
+	u_char dummy10;
+	u_char mon_tens;
+	u_char dummy11;
+	u_char year_ones;
+	u_char dummy12;
+	u_char year_tens;
+	u_char dummy13;
+	u_char mode;
+	u_char dummy14;
+	u_char test;
+	u_char dummy15;
+	u_char reset;
+};
+
+#define mste_rtc ((*(volatile struct MSTE_RTC *)MSTE_RTC_BAS))
+
+#endif /* linux/atarihw.h */
+
diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/atariints.h linux/include/asm-m68k/atariints.h
--- v1.3.93/linux/include/asm-m68k/atariints.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-m68k/atariints.h	Mon Mar  4 22:47:32 1996
@@ -0,0 +1,220 @@
+/*
+** atariints.h -- Atari Linux interrupt handling structs and prototypes
+**
+** Copyright 1994 by Bj”rn Brauel
+**
+** 5/2/94 Roman Hodek:
+**   TT interupt definitions added.
+**
+** 12/02/96: (Roman)
+**   Adapted to new int handling scheme (see ataints.c); revised numbering
+**
+** This file is subject to the terms and conditions of the GNU General Public
+** License.  See the file README.legal in the main directory of this archive
+** for more details.
+**
+*/
+
+#ifndef _LINUX_ATARIINTS_H_
+#define _LINUX_ATARIINTS_H_
+
+#include <asm/irq.h>
+#include <asm/atarihw.h>
+
+/*
+** Atari Interrupt sources.
+**
+*/
+
+#define STMFP_SOURCE_BASE   8
+#define TTMFP_SOURCE_BASE   24
+#define SCC_SOURCE_BASE	    40
+#define VME_SOURCE_BASE		56
+#define VME_MAX_SOURCES		16
+
+#define NUM_ATARI_SOURCES   (VME_SOURCE_BASE+VME_MAX_SOURCES-STMFP_SOURCE_BASE)
+
+/* convert vector number to int source number */
+#define IRQ_VECTOR_TO_SOURCE(v)	((v) - ((v) < 0x20 ? 0x18 : (0x40-8)))
+
+/* convert irq_handler index to vector number */
+#define IRQ_SOURCE_TO_VECTOR(i)	((i) + ((i) < 8 ? 0x18 : (0x40-8)))
+
+/* interrupt service types */
+#define IRQ_TYPE_SLOW     0
+#define IRQ_TYPE_FAST     1
+#define IRQ_TYPE_PRIO     2
+
+#define	IRQ_SUPRIOUS      (IRQ_MACHSPEC | 0)
+
+/* auto-vector interrupts */
+#define IRQ_AUTO_1        (IRQ_MACHSPEC | 1)
+#define IRQ_AUTO_2        (IRQ_MACHSPEC | 2)
+#define IRQ_AUTO_3        (IRQ_MACHSPEC | 3)
+#define IRQ_AUTO_4        (IRQ_MACHSPEC | 4)
+#define IRQ_AUTO_5        (IRQ_MACHSPEC | 5)
+#define IRQ_AUTO_6        (IRQ_MACHSPEC | 6)
+#define IRQ_AUTO_7        (IRQ_MACHSPEC | 7)
+
+/* ST-MFP interrupts */
+#define IRQ_MFP_BUSY      (IRQ_MACHSPEC | 8)
+#define IRQ_MFP_DCD       (IRQ_MACHSPEC | 9)
+#define IRQ_MFP_CTS  	  (IRQ_MACHSPEC | 10)
+#define IRQ_MFP_GPU 	  (IRQ_MACHSPEC | 11)
+#define IRQ_MFP_TIMD      (IRQ_MACHSPEC | 12)
+#define IRQ_MFP_TIMC	  (IRQ_MACHSPEC | 13)
+#define IRQ_MFP_ACIA	  (IRQ_MACHSPEC | 14)
+#define IRQ_MFP_FDC       (IRQ_MACHSPEC | 15)
+#define IRQ_MFP_ACSI      IRQ_MFP_FDC
+#define IRQ_MFP_FSCSI     IRQ_MFP_FDC
+#define IRQ_MFP_IDE       IRQ_MFP_FDC
+#define IRQ_MFP_TIMB      (IRQ_MACHSPEC | 16)
+#define IRQ_MFP_SERERR    (IRQ_MACHSPEC | 17)
+#define IRQ_MFP_SEREMPT   (IRQ_MACHSPEC | 18)
+#define IRQ_MFP_RECERR    (IRQ_MACHSPEC | 19)
+#define IRQ_MFP_RECFULL   (IRQ_MACHSPEC | 20)
+#define IRQ_MFP_TIMA      (IRQ_MACHSPEC | 21)
+#define IRQ_MFP_RI        (IRQ_MACHSPEC | 22)
+#define IRQ_MFP_MMD       (IRQ_MACHSPEC | 23)
+
+/* TT-MFP interrupts */
+#define IRQ_TT_MFP_IO0       (IRQ_MACHSPEC | 24)
+#define IRQ_TT_MFP_IO1       (IRQ_MACHSPEC | 25)
+#define IRQ_TT_MFP_SCC	     (IRQ_MACHSPEC | 26)
+#define IRQ_TT_MFP_RI 	     (IRQ_MACHSPEC | 27)
+#define IRQ_TT_MFP_TIMD      (IRQ_MACHSPEC | 28)
+#define IRQ_TT_MFP_TIMC	     (IRQ_MACHSPEC | 29)
+#define IRQ_TT_MFP_DRVRDY    (IRQ_MACHSPEC | 30)
+#define IRQ_TT_MFP_SCSIDMA   (IRQ_MACHSPEC | 31)
+#define IRQ_TT_MFP_TIMB      (IRQ_MACHSPEC | 32)
+#define IRQ_TT_MFP_SERERR    (IRQ_MACHSPEC | 33)
+#define IRQ_TT_MFP_SEREMPT   (IRQ_MACHSPEC | 34)
+#define IRQ_TT_MFP_RECERR    (IRQ_MACHSPEC | 35)
+#define IRQ_TT_MFP_RECFULL   (IRQ_MACHSPEC | 36)
+#define IRQ_TT_MFP_TIMA      (IRQ_MACHSPEC | 37)
+#define IRQ_TT_MFP_RTC       (IRQ_MACHSPEC | 38)
+#define IRQ_TT_MFP_SCSI      (IRQ_MACHSPEC | 39)
+
+/* SCC interrupts */
+#define IRQ_SCCB_TX	     (IRQ_MACHSPEC | 40)
+#define IRQ_SCCB_STAT	     (IRQ_MACHSPEC | 42)
+#define IRQ_SCCB_RX	     (IRQ_MACHSPEC | 44)
+#define IRQ_SCCB_SPCOND	     (IRQ_MACHSPEC | 46)
+#define IRQ_SCCA_TX	     (IRQ_MACHSPEC | 48)
+#define IRQ_SCCA_STAT	     (IRQ_MACHSPEC | 50)
+#define IRQ_SCCA_RX	     (IRQ_MACHSPEC | 52)
+#define IRQ_SCCA_SPCOND	     (IRQ_MACHSPEC | 54)
+
+
+#define INT_CLK   24576	    /* CLK while int_clk =2.456MHz and divide = 100 */
+#define INT_TICKS 246	    /* to make sched_time = 99.902... HZ */
+
+
+#define MFP_ENABLE	0
+#define MFP_PENDING	1
+#define MFP_SERVICE	2
+#define MFP_MASK	3
+
+/* Utility functions for setting/clearing bits in the interrupt registers of
+ * the MFP. 'type' should be constant, if 'irq' is constant, too, code size is
+ * reduced. set_mfp_bit() is nonsense for PENDING and SERVICE registers. */
+
+static inline int get_mfp_bit( unsigned irq, int type )
+
+{	unsigned char	mask, *reg;
+	
+	mask = 1 << (irq & 7);
+	reg = (unsigned char *)&mfp.int_en_a + type*4 +
+		  ((irq & 8) >> 2) + (((irq-8) & 16) << 3);
+	return( *reg & mask );
+}
+
+static inline void set_mfp_bit( unsigned irq, int type )
+
+{	unsigned char	mask, *reg;
+	
+	mask = 1 << (irq & 7);
+	reg = (unsigned char *)&mfp.int_en_a + type*4 +
+		  ((irq & 8) >> 2) + (((irq-8) & 16) << 3);
+	__asm__ __volatile__ ( "orb %0,%1"
+			      : : "di" (mask), "m" (*reg) : "memory" );
+}
+
+static inline void clear_mfp_bit( unsigned irq, int type )
+
+{	unsigned char	mask, *reg;
+	
+	mask = ~(1 << (irq & 7));
+	reg = (unsigned char *)&mfp.int_en_a + type*4 +
+		  ((irq & 8) >> 2) + (((irq-8) & 16) << 3);
+	if (type == MFP_PENDING || type == MFP_SERVICE)
+		__asm__ __volatile__ ( "moveb %0,%1"
+				      : : "di" (mask), "m" (*reg) : "memory" );
+	else
+		__asm__ __volatile__ ( "andb %0,%1"
+				      : : "di" (mask), "m" (*reg) : "memory" );
+}
+
+/*
+ * {en,dis}able_irq have the usual semantics of temporary blocking the
+ * interrupt, but not loosing requests that happen between disabling and
+ * enabling. This is done with the MFP mask registers.
+ */
+
+static inline void atari_enable_irq( unsigned irq )
+
+{
+	irq &= ~IRQ_MACHSPEC;
+	if (irq < STMFP_SOURCE_BASE || irq >= SCC_SOURCE_BASE) return;
+	set_mfp_bit( irq, MFP_MASK );
+}
+
+static inline void atari_disable_irq( unsigned irq )
+
+{
+	irq &= ~IRQ_MACHSPEC;
+	if (irq < STMFP_SOURCE_BASE || irq >= SCC_SOURCE_BASE) return;
+	clear_mfp_bit( irq, MFP_MASK );
+}
+
+/*
+ * In opposite to {en,dis}able_irq, requests between turn{off,on}_irq are not
+ * "stored"
+ */
+
+extern inline void atari_turnon_irq( unsigned irq )
+
+{
+	irq &= ~IRQ_MACHSPEC;
+	if (irq < STMFP_SOURCE_BASE || irq >= SCC_SOURCE_BASE) return;
+	set_mfp_bit( irq, MFP_ENABLE );
+}
+
+extern inline void atari_turnoff_irq( unsigned irq )
+
+{
+	irq &= ~IRQ_MACHSPEC;
+	if (irq < STMFP_SOURCE_BASE || irq >= SCC_SOURCE_BASE) return;
+	clear_mfp_bit( irq, MFP_ENABLE );
+	clear_mfp_bit( irq, MFP_PENDING );
+}
+
+extern inline void atari_clear_pending_irq( unsigned irq )
+
+{
+	irq &= ~IRQ_MACHSPEC;
+	if (irq < STMFP_SOURCE_BASE || irq >= SCC_SOURCE_BASE) return;
+	clear_mfp_bit( irq, MFP_PENDING );
+}
+
+extern inline int atari_irq_pending( unsigned irq )
+
+{
+	irq &= ~IRQ_MACHSPEC;
+	if (irq < STMFP_SOURCE_BASE || irq >= SCC_SOURCE_BASE) return( 0 );
+	return( get_mfp_bit( irq, MFP_PENDING ) );
+}
+
+unsigned long atari_register_vme_int( void );
+
+#endif /* linux/atariints.h */
diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/atarikb.h linux/include/asm-m68k/atarikb.h
--- v1.3.93/linux/include/asm-m68k/atarikb.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-m68k/atarikb.h	Mon Mar  4 22:47:32 1996
@@ -0,0 +1,40 @@
+/*
+** atarikb.h -- This header contains the prototypes of functions of
+**              the intelligent keyboard of the Atari needed by the
+**              mouse and joystick drivers.
+**
+** Copyright 1994 by Robert de Vries
+**
+** This file is subject to the terms and conditions of the GNU General Public
+** License.  See the file README.legal in the main directory of this archive
+** for more details.
+**
+** Created: 20 Feb 1994 by Robert de Vries
+*/
+
+#ifndef _LINUX_ATARIKB_H
+#define _LINUX_ATARIKB_H
+
+void ikbd_write(const char *, int);
+void ikbd_mouse_button_action(int mode);
+void ikbd_mouse_rel_pos(void);
+void ikbd_mouse_abs_pos(int xmax, int ymax);
+void ikbd_mouse_kbd_mode(int dx, int dy);
+void ikbd_mouse_thresh(int x, int y);
+void ikbd_mouse_scale(int x, int y);
+void ikbd_mouse_pos_get(int *x, int *y);
+void ikbd_mouse_pos_set(int x, int y);
+void ikbd_mouse_y0_bot(void);
+void ikbd_mouse_y0_top(void);
+void ikbd_mouse_disable(void);
+void ikbd_joystick_event_on(void);
+void ikbd_joystick_event_off(void);
+void ikbd_joystick_get_state(void);
+void ikbd_joystick_disable(void);
+
+/* Hook for MIDI serial driver */
+extern void (*atari_MIDI_interrupt_hook) (void);
+/* Hook for mouse driver */
+extern void (*atari_mouse_interrupt_hook) (char *);
+
+#endif /* _LINUX_ATARIKB_H */
diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/atomic.h linux/include/asm-m68k/atomic.h
--- v1.3.93/linux/include/asm-m68k/atomic.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-m68k/atomic.h	Fri Apr  5 19:33:18 1996
@@ -0,0 +1,63 @@
+#ifndef __ARCH_M68K_ATOMIC__
+#define __ARCH_M68K_ATOMIC__
+
+/*
+ * Atomic operations that C can't guarantee us.  Useful for
+ * resource counting etc..
+ */
+
+/*
+ * We do not have SMP m68k systems, so we don't have to deal with that.
+ */
+
+/*
+ * Make sure gcc doesn't try to be clever and move things around
+ * 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)
+
+typedef int atomic_t;
+
+static __inline__ void atomic_add(atomic_t i, atomic_t *v)
+{
+	__asm__ __volatile__(
+		"addl %1,%0"
+		:"=m" (__atomic_fool_gcc(v))
+		:"ir" (i), "m" (__atomic_fool_gcc(v)));
+}
+
+static __inline__ void atomic_sub(atomic_t i, atomic_t *v)
+{
+	__asm__ __volatile__(
+		"subl  %1,%0"
+		:"=m" (__atomic_fool_gcc(v))
+		:"ir" (i), "m" (__atomic_fool_gcc(v)));
+}
+
+static __inline__ void atomic_inc(atomic_t *v)
+{
+	__asm__ __volatile__(
+		"addql #1,%0"
+		:"=m" (__atomic_fool_gcc(v))
+		:"m" (__atomic_fool_gcc(v)));
+}
+
+static __inline__ void atomic_dec(atomic_t *v)
+{
+	__asm__ __volatile__(
+		"subql #1,%0"
+		:"=m" (__atomic_fool_gcc(v))
+		:"m" (__atomic_fool_gcc(v)));
+}
+
+static __inline__ int atomic_dec_and_test(atomic_t *v)
+{
+	__asm__ __volatile__(
+		"subql #1,%0"
+		:"=m" (__atomic_fool_gcc(v))
+		:"m" (__atomic_fool_gcc(v)));
+	return (*v <= 0);
+}
+
+#endif /* __ARCH_M68K_ATOMIC __ */
diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/bitops.h linux/include/asm-m68k/bitops.h
--- v1.3.93/linux/include/asm-m68k/bitops.h	Tue Nov 29 22:15:49 1994
+++ linux/include/asm-m68k/bitops.h	Wed Mar  6 20:01:26 1996
@@ -11,10 +11,7 @@
 /*
  * Require 68020 or better.
  *
- * They don't use the standard m680x0 bit ordering.
- * Instead, the use the standard m680x0 bitfield ordering.
- *
- * Thus, bit 0 is the MSB of addr; bit 32 is the MSB of (addr+1).
+ * They use the standard big-endian m680x0 bit ordering.
  */
 
 extern __inline__ int set_bit(int nr,void * vaddr)
@@ -22,7 +19,7 @@
 	char retval;
 
 	__asm__ __volatile__ ("bfset %2@{%1:#1}; sne %0"
-	     : "=d" (retval) : "d" (nr), "a" (vaddr));
+	     : "=d" (retval) : "d" (nr^31), "a" (vaddr));
 
 	return retval;
 }
@@ -32,7 +29,7 @@
 	char retval;
 
 	__asm__ __volatile__ ("bfclr %2@{%1:#1}; sne %0"
-	     : "=d" (retval) : "d" (nr), "a" (vaddr));
+	     : "=d" (retval) : "d" (nr^31), "a" (vaddr));
 
 	return retval;
 }
@@ -42,7 +39,7 @@
 	char retval;
 
 	__asm__ __volatile__ ("bfchg %2@{%1:#1}; sne %0"
-	     : "=d" (retval) : "d" (nr), "a" (vaddr));
+	     : "=d" (retval) : "d" (nr^31), "a" (vaddr));
 
 	return retval;
 }
@@ -52,51 +49,52 @@
 	char retval;
 
 	__asm__ __volatile__ ("bftst %2@{%1:#1}; sne %0"
-	     : "=d" (retval) : "d" (nr), "a" (vaddr));
+	     : "=d" (retval) : "d" (nr^31), "a" (vaddr));
 
 	return retval;
 }
 
-extern inline int find_first_zero_bit(void * vaddr, unsigned size)
+extern __inline__ int find_first_zero_bit(void * vaddr, unsigned size)
 {
-	unsigned long res;
-	unsigned long *p;
-	unsigned long *addr = vaddr;
+	unsigned long *p = vaddr, *addr = vaddr;
+	unsigned long allones = ~0UL;
+	int res;
+	unsigned long num;
 
 	if (!size)
 		return 0;
-	__asm__ __volatile__ ("    moveq #-1,d0\n\t"
-			      "1:"
-			      "    cmpl  %1@+,d0\n\t"
-			      "    bne   2f\n\t"
-			      "    subql #1,%0\n\t"
-			      "    bne   1b\n\t"
-			      "    bra   5f\n\t"
-			      "2:"
-			      "    movel %1@-,d0\n\t"
-			      "    notl  d0\n\t"
-			      "    bfffo d0{#0,#0},%0\n\t"
-			      "5:"
-			      : "=d" (res), "=a" (p)
-			      : "0" ((size + 31) >> 5), "1" (addr)
-			      : "d0");
-	return ((p - addr) << 5) + res;
+
+	while (*p++ == allones)
+	{
+		if (size <= 32)
+			return (p - addr) << 5;
+		size -= 32;
+	}
+
+	num = ~*--p;
+	__asm__ __volatile__ ("bfffo %1{#0,#0},%0"
+			      : "=d" (res) : "d" (num & -num));
+	return ((p - addr) << 5) + (res ^ 31);
 }
 
-static inline int find_next_zero_bit (void *vaddr, int size,
+extern __inline__ int find_next_zero_bit (void *vaddr, int size,
 				      int offset)
 {
 	unsigned long *addr = vaddr;
 	unsigned long *p = addr + (offset >> 5);
-	int set = 0, bit = offset & 31, res;
+	int set = 0, bit = offset & 31UL, res;
+
+	if (offset >= size)
+		return size;
 
 	if (bit) {
+		unsigned long num = ~*p & (~0UL << bit);
+
 		/* Look for zero in first longword */
-		__asm__("bfffo %1{#0,#0},%0"
-			: "=d" (set)
-			: "d" (~*p << bit));
-		if (set < (32 - bit))
-			return set + offset;
+		__asm__ __volatile__ ("bfffo %1{#0,#0},%0"
+				      : "=d" (res) : "d" (num & -num));
+		if (res < 32)
+			return (offset & ~31UL) + (res ^ 31);
                 set = 32 - bit;
 		p++;
 	}
@@ -109,12 +107,151 @@
  * ffz = Find First Zero in word. Undefined if no zero exists,
  * so code should check against ~0UL first..
  */
-extern inline unsigned long ffz(unsigned long word)
+extern __inline__ unsigned long ffz(unsigned long word)
 {
+	int res;
+
 	__asm__ __volatile__ ("bfffo %1{#0,#0},%0"
-			      : "=d" (word)
-			      : "d" (~(word)));
-	return word;
+			      : "=d" (res) : "d" (~word & -~word));
+	return res ^ 31;
+}
+
+/* Bitmap functions for the minix filesystem */
+
+extern __inline__ int
+minix_find_first_zero_bit (const void *vaddr, unsigned size)
+{
+	const unsigned short *p = vaddr, *addr = vaddr;
+	int res;
+	unsigned short num;
+
+	if (!size)
+		return 0;
+
+	while (*p++ == 0xffff)
+	{
+		if (size <= 16)
+			return (p - addr) << 4;
+		size -= 16;
+	}
+
+	num = ~*--p;
+	__asm__ __volatile__ ("bfffo %1{#16,#16},%0"
+			      : "=d" (res) : "d" (num & -num));
+	return ((p - addr) << 4) + (res ^ 31);
+}
+
+extern __inline__ int
+minix_set_bit (int nr, void *vaddr)
+{
+	char retval;
+
+	__asm__ __volatile__ ("bfset %2{%1:#1}; sne %0"
+	     : "=d" (retval) : "d" (nr^15), "m" (*(char *)vaddr));
+
+	return retval;
+}
+
+extern __inline__ int
+minix_clear_bit (int nr, void *vaddr)
+{
+	char retval;
+
+	__asm__ __volatile__ ("bfclr %2{%1:#1}; sne %0"
+	     : "=d" (retval) : "d" (nr^15), "m" (*(char *) vaddr));
+
+	return retval;
+}
+
+extern __inline__ int
+minix_test_bit (int nr, const void *vaddr)
+{
+	char retval;
+
+	__asm__ __volatile__ ("bftst %2{%1:#1}; sne %0"
+	     : "=d" (retval) : "d" (nr^15), "m" (*(const char *) vaddr));
+
+	return retval;
+}
+
+/* Bitmap functions for the ext2 filesystem. */
+
+extern __inline__ int
+ext2_set_bit (int nr, void *vaddr)
+{
+	char retval;
+
+	__asm__ __volatile__ ("bfset %2{%1,#1}; sne %0"
+	     : "=d" (retval) : "d" (nr^7), "m" (*(char *) vaddr));
+
+	return retval;
+}
+
+extern __inline__ int
+ext2_clear_bit (int nr, void *vaddr)
+{
+	char retval;
+
+	__asm__ __volatile__ ("bfclr %2{%1,#1}; sne %0"
+	     : "=d" (retval) : "d" (nr^7), "m" (*(char *) vaddr));
+
+	return retval;
+}
+
+extern __inline__ int
+ext2_test_bit (int nr, const void *vaddr)
+{
+	char retval;
+
+	__asm__ __volatile__ ("bftst %2{%1,#1}; sne %0"
+	     : "=d" (retval) : "d" (nr^7), "m" (*(const char *) vaddr));
+
+	return retval;
+}
+
+extern __inline__ int
+ext2_find_first_zero_bit (const void *vaddr, unsigned size)
+{
+	const unsigned long *p = vaddr, *addr = vaddr;
+	int res;
+
+	if (!size)
+		return 0;
+
+	while (*p++ == ~0UL)
+	{
+		if (size <= 32)
+			return (p - addr) << 5;
+		size -= 32;
+	}
+
+	--p;
+	for (res = 0; res < 32; res++)
+		if (!ext2_test_bit (res, p))
+			break;
+	return (p - addr) * 32 + res;
+}
+
+extern __inline__ int
+ext2_find_next_zero_bit (const void *vaddr, unsigned size, unsigned offset)
+{
+	const unsigned long *addr = vaddr;
+	const unsigned long *p = addr + (offset >> 5);
+	int bit = offset & 31UL, res;
+
+	if (offset >= size)
+		return size;
+
+	if (bit) {
+		/* Look for zero in first longword */
+		for (res = bit; res < 32; res++)
+			if (!ext2_test_bit (res, p))
+				return (p - addr) * 32 + res;
+		p++;
+	}
+	/* No zero yet, search remaining full bytes for a zero */
+	res = ext2_find_first_zero_bit (p, size - 32 * (p - addr));
+	return (p - addr) * 32 + res;
 }
 
 #endif /* _M68K_BITOPS_H */
diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/bootinfo.h linux/include/asm-m68k/bootinfo.h
--- v1.3.93/linux/include/asm-m68k/bootinfo.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-m68k/bootinfo.h	Tue Apr  9 00:13:55 1996
@@ -0,0 +1,237 @@
+/*
+** asm/bootinfo.h -- Definition of the Linux/68K boot information structure
+**
+** Copyright 1992 by Greg Harp
+**
+** This file is subject to the terms and conditions of the GNU General Public
+** License.  See the file README.legal in the main directory of this archive
+** for more details.
+**
+** Created 09/29/92 by Greg Harp
+**
+** 5/2/94 Roman Hodek:
+**   Added bi_atari part of the machine dependant union bi_un; for now it
+**	 contains just a model field to distinguish between TT and Falcon.
+*/
+
+#ifndef BOOTINFO_H
+#define BOOTINFO_H
+
+#ifndef __ASSEMBLY__
+
+#include <asm/zorro.h>
+
+/*
+ * Amiga specific part of bootinfo structure.
+ */
+
+#define NUM_AUTO    16
+
+#define AMIGAHW_DECLARE(name)	unsigned name : 1
+#define AMIGAHW_SET(name)	(boot_info.bi_amiga.hw_present.name = 1)
+#define AMIGAHW_PRESENT(name)	(boot_info.bi_amiga.hw_present.name)
+
+struct bi_Amiga {
+  int model;				/* Amiga Model (3000?) */
+  int num_autocon;			/* # of autoconfig devices found */
+  struct ConfigDev autocon[NUM_AUTO];	/* up to 16 autoconfig devices */
+  unsigned long chip_size;		/* size of chip memory (bytes) */
+  unsigned char vblank; 		/* VBLANK frequency */
+  unsigned char psfreq; 		/* power supply frequency */
+  unsigned long eclock; 		/* EClock frequency */
+  unsigned long chipset;		/* native chipset present */
+  struct {
+    /* video hardware */
+    AMIGAHW_DECLARE(AMI_VIDEO);		/* Amiga Video */
+    AMIGAHW_DECLARE(AMI_BLITTER);	/* Amiga Blitter */
+    AMIGAHW_DECLARE(AMBER_FF);		/* Amber Flicker Fixer */
+    /* sound hardware */
+    AMIGAHW_DECLARE(AMI_AUDIO);		/* Amiga Audio */
+    /* disk storage interfaces */
+    AMIGAHW_DECLARE(AMI_FLOPPY);	/* Amiga Floppy */
+    AMIGAHW_DECLARE(A3000_SCSI);	/* SCSI (wd33c93, A3000 alike) */
+    AMIGAHW_DECLARE(A4000_SCSI);	/* SCSI (ncr53c710, A4000T alike) */
+    AMIGAHW_DECLARE(A1200_IDE);		/* IDE (A1200 alike) */
+    AMIGAHW_DECLARE(A4000_IDE);		/* IDE (A4000 alike) */
+    AMIGAHW_DECLARE(CD_ROM);		/* CD ROM drive */
+    /* other I/O hardware */
+    AMIGAHW_DECLARE(AMI_KEYBOARD);	/* Amiga Keyboard */
+    AMIGAHW_DECLARE(AMI_MOUSE);		/* Amiga Mouse */
+    AMIGAHW_DECLARE(AMI_SERIAL);	/* Amiga Serial */
+    AMIGAHW_DECLARE(AMI_PARALLEL);	/* Amiga Parallel */
+    /* real time clocks */
+    AMIGAHW_DECLARE(A2000_CLK);		/* Hardware Clock (A2000 alike) */
+    AMIGAHW_DECLARE(A3000_CLK);		/* Hardware Clock (A3000 alike) */
+    /* supporting hardware */
+    AMIGAHW_DECLARE(CHIP_RAM);		/* Chip RAM */
+    AMIGAHW_DECLARE(PAULA);		/* Paula (8364) */
+    AMIGAHW_DECLARE(DENISE);		/* Denise (8362) */
+    AMIGAHW_DECLARE(DENISE_HR);		/* Denise (8373) */
+    AMIGAHW_DECLARE(LISA);		/* Lisa (8375) */
+    AMIGAHW_DECLARE(AGNUS_PAL);		/* Normal/Fat PAL Agnus (8367/8371) */
+    AMIGAHW_DECLARE(AGNUS_NTSC);	/* Normal/Fat NTSC Agnus (8361/8370) */
+    AMIGAHW_DECLARE(AGNUS_HR_PAL);	/* Fat Hires PAL Agnus (8372) */
+    AMIGAHW_DECLARE(AGNUS_HR_NTSC);	/* Fat Hires NTSC Agnus (8372) */
+    AMIGAHW_DECLARE(ALICE_PAL);		/* PAL Alice (8374) */
+    AMIGAHW_DECLARE(ALICE_NTSC);	/* NTSC Alice (8374) */
+    AMIGAHW_DECLARE(MAGIC_REKICK);	/* A3000 Magic Hard Rekick */
+    AMIGAHW_DECLARE(ZORRO);		/* Zorro AutoConfig */
+  } hw_present;
+};
+
+
+/* Atari specific part of bootinfo */
+
+/*
+ * Define several Hardware-Chips for indication so that for the ATARI we do
+ * no longer decide whether it is a Falcon or other machine . It's just
+ * important what hardware the machine uses
+ */
+
+/* ++roman 08/08/95: rewritten from ORing constants to a C bitfield */
+
+#define ATARIHW_DECLARE(name)	unsigned name : 1
+#define ATARIHW_SET(name)	(boot_info.bi_atari.hw_present.name = 1)
+#define ATARIHW_PRESENT(name)	(boot_info.bi_atari.hw_present.name)
+
+struct bi_Atari {
+  struct {
+    /* video hardware */
+    ATARIHW_DECLARE(STND_SHIFTER);	/* ST-Shifter - no base low ! */
+    ATARIHW_DECLARE(EXTD_SHIFTER);	/* STe-Shifter - 24 bit adress */
+    ATARIHW_DECLARE(TT_SHIFTER);	/* TT-Shifter */
+    ATARIHW_DECLARE(VIDEL_SHIFTER);	/* Falcon-Shifter */
+    /* sound hardware */
+    ATARIHW_DECLARE(YM_2149);		/* Yamaha YM 2149 */
+    ATARIHW_DECLARE(PCM_8BIT);		/* PCM-Sound in STe-ATARI */
+    ATARIHW_DECLARE(CODEC);		/* CODEC Sound (Falcon) */
+    /* disk storage interfaces */
+    ATARIHW_DECLARE(TT_SCSI);		/* Directly mapped NCR5380 */
+    ATARIHW_DECLARE(ST_SCSI);		/* NCR5380 via ST-DMA (Falcon) */
+    ATARIHW_DECLARE(ACSI);		/* Standard ACSI like in STs */
+    ATARIHW_DECLARE(IDE);		/* IDE Interface */
+    ATARIHW_DECLARE(FDCSPEED);		/* 8/16 MHz switch for FDC */
+    /* other I/O hardware */
+    ATARIHW_DECLARE(ST_MFP);		/* The ST-MFP (there should
+					   be no Atari without
+					   it... but who knows?) */
+    ATARIHW_DECLARE(TT_MFP);		/* 2nd MFP */
+    ATARIHW_DECLARE(SCC);		/* Serial Communications Contr. */
+    ATARIHW_DECLARE(ST_ESCC);		/* SCC Z83230 in an ST */
+    ATARIHW_DECLARE(ANALOG_JOY);	/* Paddle Interface for STe
+					   and Falcon */
+    ATARIHW_DECLARE(MICROWIRE);		/* Microwire Interface */
+    /* DMA */
+    ATARIHW_DECLARE(STND_DMA);		/* 24 Bit limited ST-DMA */
+    ATARIHW_DECLARE(EXTD_DMA);		/* 32 Bit ST-DMA */
+    ATARIHW_DECLARE(SCSI_DMA);		/* DMA for the NCR5380 */
+    ATARIHW_DECLARE(SCC_DMA);		/* DMA for the SCC */
+    /* real time clocks */
+    ATARIHW_DECLARE(TT_CLK);		/* TT compatible clock chip */
+    ATARIHW_DECLARE(MSTE_CLK);		/* Mega ST(E) clock chip */
+    /* supporting hardware */
+    ATARIHW_DECLARE(SCU);		/* System Control Unit */
+    ATARIHW_DECLARE(BLITTER);		/* Blitter */
+    ATARIHW_DECLARE(VME);		/* VME Bus */
+  } hw_present;
+  unsigned long mch_cookie;		/* _MCH cookie from TOS */
+};
+
+/* mch_cookie values (upper word) */
+#define	ATARI_MCH_ST		0
+#define	ATARI_MCH_STE		1
+#define	ATARI_MCH_TT		2
+#define	ATARI_MCH_FALCON	3
+
+/*
+ * CPU and FPU types
+ */
+#define CPU_68020    (1)
+#define CPU_68030    (2)
+#define CPU_68040    (4)
+#define CPU_68060    (8)
+#define CPU_MASK     (31)
+#define FPU_68881    (32)
+#define FPU_68882    (64)
+#define FPU_68040    (128)	/* Internal FPU */
+#define FPU_68060    (256)	/* Internal FPU */
+
+struct mem_info {
+  unsigned long addr;		/* physical address of memory chunk */
+  unsigned long size;		/* length of memory chunk (in bytes) */
+};
+
+#define NUM_MEMINFO  4
+
+#endif /* __ASSEMBLY__ */
+
+#define MACH_AMIGA   1
+#define MACH_ATARI   2
+#define MACH_MAC     3
+
+#ifndef __ASSEMBLY__
+
+#define MACH_IS_AMIGA	(boot_info.machtype == MACH_AMIGA)
+#define MACH_IS_ATARI	(boot_info.machtype == MACH_ATARI)
+
+#define CL_SIZE      (256)
+
+struct bootinfo {
+  unsigned long machtype;		/* machine type */
+  unsigned long cputype;		/* system CPU & FPU */
+  struct mem_info memory[NUM_MEMINFO];	/* memory description */
+  int num_memory;			/* # of memory blocks found */
+  unsigned long ramdisk_size;		/* ramdisk size in 1024 byte blocks */
+  unsigned long ramdisk_addr;		/* address of the ram disk in mem */
+  char command_line[CL_SIZE];		/* kernel command line parameters */
+  union {
+    struct bi_Amiga bi_ami; 	/* Amiga specific information */
+    struct bi_Atari bi_ata; 	/* Atari specific information */
+  } bi_un;
+};
+#define bi_amiga bi_un.bi_ami
+#define bi_atari bi_un.bi_ata
+#define bi_mac	 bi_un.bi_mac
+
+extern struct bootinfo
+    boot_info;
+
+#endif /* __ASSEMBLY__ */
+
+
+/*
+ * Stuff for bootinfo interface versioning
+ *
+ * At the start of kernel code, a 'struct bootversion' is located. bootstrap
+ * checks for a matching version of the interface before booting a kernel, to
+ * avoid user confusion if kernel and bootstrap don't work together :-)
+ *
+ * If incompatible changes are made to the bootinfo interface, the major
+ * number below should be stepped (and the minor reset to 0) for the
+ * appropriate machine. If a change is backward-compatible, the minor should
+ * be stepped. "Backwards-compatible" means that booting will work, but
+ * certain features may not.
+ */
+
+#define BOOTINFOV_MAGIC			0x4249561A	/* 'BIV^Z' */
+#define MK_BI_VERSION(major,minor)	(((major)<<16)+(minor))
+#define BI_VERSION_MAJOR(v)		(((v) >> 16) & 0xffff)
+#define BI_VERSION_MINOR(v)		((v) & 0xffff)
+
+#ifndef __ASSEMBLY__
+
+struct bootversion {
+    unsigned short branch;
+    unsigned long magic;
+    struct {
+       unsigned long machtype;
+       unsigned long version;
+    } machversions[0];
+};
+
+#endif /* __ASSEMBLY__ */
+
+#define AMIGA_BOOTI_VERSION    MK_BI_VERSION( 1, 0 )
+#define ATARI_BOOTI_VERSION    MK_BI_VERSION( 1, 0 )
+
+#endif /* BOOTINFO_H */
diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/bugs.h linux/include/asm-m68k/bugs.h
--- v1.3.93/linux/include/asm-m68k/bugs.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-m68k/bugs.h	Wed Dec 27 22:46:49 1995
@@ -0,0 +1,16 @@
+/*
+ *  include/asm-m68k/bugs.h
+ *
+ *  Copyright (C) 1994  Linus Torvalds
+ */
+
+/*
+ * This is included by init/main.c to check for architecture-dependent bugs.
+ *
+ * Needs:
+ *	void check_bugs(void);
+ */
+
+static void check_bugs(void)
+{
+}
diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/byteorder.h linux/include/asm-m68k/byteorder.h
--- v1.3.93/linux/include/asm-m68k/byteorder.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-m68k/byteorder.h	Sun Mar 31 01:09:52 1996
@@ -0,0 +1,14 @@
+#ifndef _M68K_BYTEORDER_H
+#define _M68K_BYTEORDER_H
+
+#ifdef __KERNEL__
+#define __BIG_ENDIAN
+#endif
+#define __BIG_ENDIAN_BITFIELD
+
+#define ntohl(x) x
+#define ntohs(x) x
+#define htonl(x) x
+#define htons(x) x
+
+#endif
diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/checksum.h linux/include/asm-m68k/checksum.h
--- v1.3.93/linux/include/asm-m68k/checksum.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-m68k/checksum.h	Sat Apr  6 12:42:22 1996
@@ -0,0 +1,175 @@
+#ifndef _M68K_CHECKSUM_H
+#define _M68K_CHECKSUM_H
+
+/*
+ * computes the checksum of a memory block at buff, length len,
+ * and adds in "sum" (32-bit)
+ *
+ * returns a 32-bit number suitable for feeding into itself
+ * or csum_tcpudp_magic
+ *
+ * this function must be called with even lengths, except
+ * for the last fragment, which may be odd
+ *
+ * it's best to have buff aligned on a 32-bit boundary
+ */
+unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum);
+
+/*
+ * the same as csum_partial_copy, but copies from src while it
+ * checksums
+ *
+ * here even more important to align src and dst on a 32-bit (or even
+ * better 64-bit) boundary
+ */
+
+unsigned int csum_partial_copy(const char *src, char *dst, int len, int sum);
+
+
+/*
+ * the same as csum_partial_copy, but copies from user space.
+ *
+ * here even more important to align src and dst on a 32-bit (or even
+ * better 64-bit) boundary
+ */
+
+unsigned int csum_partial_copy_fromuser(const char *src, char *dst, int len, int sum);
+
+
+/*
+ *	This is a version of ip_compute_csum() optimized for IP headers,
+ *	which always checksum on 4 octet boundaries.
+ *
+ */
+static inline unsigned short
+ip_fast_csum(unsigned char *iph, unsigned int ihl)
+{
+	unsigned int sum = 0;
+
+	__asm__ ("subqw #1,%2\n"
+		 "1:\t"
+		 "movel %1@+,%/d0\n\t"
+		 "addxl %/d0,%0\n\t"
+		 "dbra  %2,1b\n\t"
+		 "movel %0,%/d0\n\t"
+		 "swap  %/d0\n\t"
+		 "addxw %/d0,%0\n\t"
+		 "clrw  %/d0\n\t"
+		 "addxw %/d0,%0\n\t"
+		 : "=d" (sum), "=a" (iph), "=d" (ihl)
+		 : "0" (sum), "1" (iph), "2" (ihl)
+		 : "d0");
+	return ~sum;
+}
+
+
+
+/*
+ * computes the checksum of the TCP/UDP pseudo-header
+ * returns a 16-bit checksum, already complemented
+ */
+
+static inline unsigned short int
+csum_tcpudp_magic(unsigned long saddr, unsigned long daddr, unsigned short len,
+		  unsigned short proto, unsigned int sum)
+{
+	__asm__ ("addl  %1,%0\n\t"
+		 "addxl %4,%0\n\t"
+		 "addxl %5,%0\n\t"
+		 "movl  %0,%1\n\t"
+		 "swap  %1\n\t"
+		 "addxw %1,%0\n\t"
+		 "clrw  %1\n\t"
+		 "addxw %1,%0\n\t"
+		 : "=&d" (sum), "=&d" (saddr)
+		 : "0" (daddr), "1" (saddr), "d" (len + proto),
+		   "d"(sum));
+	return ~sum;
+}
+
+/*
+ *	Fold a partial checksum without adding pseudo headers
+ */
+
+static inline unsigned int csum_fold(unsigned int sum)
+{
+	unsigned int tmp = sum;
+	__asm__("swap %1\n\t"
+		"addw %1, %0\n\t"
+		"clrw %1\n\t"
+		"addxw %1, %0"
+		: "=&d" (sum), "=&d" (tmp)
+		: "0" (sum), "1" (sum));
+	return ~sum;
+}
+
+/*
+ * this routine is used for miscellaneous IP-like checksums, mainly
+ * in icmp.c
+ */
+
+#if 1
+static inline unsigned short
+ip_compute_csum(unsigned char * buff, int len)
+{
+	unsigned int sum;
+	unsigned int scratch;
+
+	__asm__("movel %0,%1\n\t"
+		"swap  %1\n\t"
+		"addw  %1,%0\n\t"
+		"clrw  %1\n\t"
+		"addxw %1,%0\n\t"
+		: "=d" (sum), "=d" (scratch)
+		: "0" (csum_partial(buff, len, 0)));
+	return ~sum;
+}
+#else
+static inline unsigned short
+ip_compute_csum(unsigned char * buff, int len)
+{
+	unsigned long sum = 0;
+
+  /* Do the first multiple of 4 bytes and convert to 16 bits. */
+  if (len > 3)
+    {
+      int dummy;
+      __asm__ ("subql #1,%2\n\t"
+	       "1:\t"
+	       "movel %1@+,%/d0\n\t"
+	       "addxl %/d0,%0\n\t"
+	       "dbra %2,1b\n\t"
+	       "movel %0,%/d0\n\t"
+	       "swap %/d0\n\t"
+	       "addxw %/d0,%0\n\t"
+	       "clrw %/d0\n\t"
+	       "addxw %/d0,%0"
+	       : "=d" (sum), "=a" (buff), "=d" (dummy)
+	       : "0" (sum), "1" (buff), "2" (len >> 2)
+	       : "d0");
+    }
+  if (len & 2)
+    {
+      __asm__ ("addw %1@+,%0\n\t"
+	       "addxw %2,%0"
+	       : "=d" (sum), "=a" (buff)
+	       : "d" (0), "0" (sum), "1" (buff));
+    }
+  if (len & 1)
+    {
+      __asm__ ("movew %1@,%/d0\n\t"
+	       "clrb %/d0\n\t"
+	       "addw %/d0,%0\n\t"
+	       "clrw %/d0\n\t"
+	       "addxw %/d0,%0"
+	       : "=d" (sum)
+	       : "a" (buff), "0" (sum)
+	       : "d0");
+    }
+
+	sum =~sum;
+	return(sum & 0xffff);
+}
+#endif
+
+#endif /* _M68K_CHECKSUM_H */
diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/delay.h linux/include/asm-m68k/delay.h
--- v1.3.93/linux/include/asm-m68k/delay.h	Mon Nov 28 20:41:29 1994
+++ linux/include/asm-m68k/delay.h	Sat Feb 24 19:42:43 1996
@@ -9,16 +9,13 @@
 
 extern __inline__ void __delay(int loops)
 {
-	__asm__("\n\tmovel %0,d0\n1:\tsubql #1,d0\n\tbpls 1b\n"
+	__asm__("\n\tmovel %0,%/d0\n1:\tsubql #1,%/d0\n\tbpls 1b\n"
 		: /* no outputs */
 		: "g" (loops)
 		: "d0");
 }
 
 /*
- * division by multiplication: you don't have to worry about
- * loss of precision.
- *
  * Use only for very small delays ( < 1 msec).  Should probably use a
  * lookup table, really, as the multiplications take much too long with
  * short delays.  This is a "reasonable" implementation, though (and the
@@ -27,14 +24,24 @@
  */
 extern __inline__ void udelay(unsigned long usecs)
 {
-	asm ("mulul %1,d0,%0\n\t"
-	     "divul  %2,d0,%0"
+	usecs *= 0x000010c6;		/* 2**32 / 1000000 */
+
+	asm ("mulul %1,%0:%2"
 	     : "=d" (usecs)
 	     : "d" (usecs),
-	       "i" (1000000),
-	       "0" (loops_per_sec)
-	     : "d0");
+	       "d" (loops_per_sec));
 	__delay(usecs);
+}
+
+extern __inline__ unsigned long muldiv(unsigned long a, unsigned long b, unsigned long c)
+{
+	__asm__("mulul %1,%/d0:%0\n\tdivul %2,%/d0:%0"
+		:"=d" (a)
+		:"d" (b),
+		"d" (c),
+		"0" (a)
+		:"d0");
+	return a;
 }
 
 #endif /* defined(_M68K_DELAY_H) */
diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/dma.h linux/include/asm-m68k/dma.h
--- v1.3.93/linux/include/asm-m68k/dma.h	Mon Nov 28 21:44:45 1994
+++ linux/include/asm-m68k/dma.h	Sat Apr 13 14:31:08 1996
@@ -1,6 +1,12 @@
 #ifndef _M68K_DMA_H
 #define _M68K_DMA_H 1
 
-/* dummy for m68k */
+/* Don't define MAX_DMA_ADDRESS; it's useless on the m68k and any
+   occurence should be flagged as an error.  */
+
+#define MAX_DMA_CHANNELS 8
+
+extern int request_dma(unsigned int dmanr, const char * device_id);	/* reserve a DMA channel */
+extern void free_dma(unsigned int dmanr);	/* release it again */
 
 #endif /* _M68K_DMA_H */
diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/elf.h linux/include/asm-m68k/elf.h
--- v1.3.93/linux/include/asm-m68k/elf.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-m68k/elf.h	Tue Mar 12 21:25:20 1996
@@ -0,0 +1,22 @@
+#ifndef __ASMm68k_ELF_H
+#define __ASMm68k_ELF_H
+
+/*
+ * ELF register definitions..
+ */
+
+#include <asm/ptrace.h>
+
+typedef unsigned long elf_greg_t;
+
+#define ELF_NGREG 20 /* d1-d7/a0-a6/d0/usp/orig_d0/sr/pc/fmtvec */
+typedef elf_greg_t elf_gregset_t[ELF_NGREG];
+
+/* XXX temporary */
+/*
+typedef unsigned long elf_fpregset_t;
+*/
+
+typedef struct user_m68kfp_struct elf_fpregset_t;
+
+#endif
diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/errno.h linux/include/asm-m68k/errno.h
--- v1.3.93/linux/include/asm-m68k/errno.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-m68k/errno.h	Wed Dec 27 22:46:55 1995
@@ -0,0 +1,127 @@
+#ifndef _M68K_ERRNO_H
+#define _M68K_ERRNO_H
+
+#define	EPERM		 1	/* Operation not permitted */
+#define	ENOENT		 2	/* No such file or directory */
+#define	ESRCH		 3	/* No such process */
+#define	EINTR		 4	/* Interrupted system call */
+#define	EIO		 5	/* I/O error */
+#define	ENXIO		 6	/* No such device or address */
+#define	E2BIG		 7	/* Arg list too long */
+#define	ENOEXEC		 8	/* Exec format error */
+#define	EBADF		 9	/* Bad file number */
+#define	ECHILD		10	/* No child processes */
+#define	EAGAIN		11	/* Try again */
+#define	ENOMEM		12	/* Out of memory */
+#define	EACCES		13	/* Permission denied */
+#define	EFAULT		14	/* Bad address */
+#define	ENOTBLK		15	/* Block device required */
+#define	EBUSY		16	/* Device or resource busy */
+#define	EEXIST		17	/* File exists */
+#define	EXDEV		18	/* Cross-device link */
+#define	ENODEV		19	/* No such device */
+#define	ENOTDIR		20	/* Not a directory */
+#define	EISDIR		21	/* Is a directory */
+#define	EINVAL		22	/* Invalid argument */
+#define	ENFILE		23	/* File table overflow */
+#define	EMFILE		24	/* Too many open files */
+#define	ENOTTY		25	/* Not a typewriter */
+#define	ETXTBSY		26	/* Text file busy */
+#define	EFBIG		27	/* File too large */
+#define	ENOSPC		28	/* No space left on device */
+#define	ESPIPE		29	/* Illegal seek */
+#define	EROFS		30	/* Read-only file system */
+#define	EMLINK		31	/* Too many links */
+#define	EPIPE		32	/* Broken pipe */
+#define	EDOM		33	/* Math argument out of domain of func */
+#define	ERANGE		34	/* Math result not representable */
+#define	EDEADLK		35	/* Resource deadlock would occur */
+#define	ENAMETOOLONG	36	/* File name too long */
+#define	ENOLCK		37	/* No record locks available */
+#define	ENOSYS		38	/* Function not implemented */
+#define	ENOTEMPTY	39	/* Directory not empty */
+#define	ELOOP		40	/* Too many symbolic links encountered */
+#define	EWOULDBLOCK	EAGAIN	/* Operation would block */
+#define	ENOMSG		42	/* No message of desired type */
+#define	EIDRM		43	/* Identifier removed */
+#define	ECHRNG		44	/* Channel number out of range */
+#define	EL2NSYNC	45	/* Level 2 not synchronized */
+#define	EL3HLT		46	/* Level 3 halted */
+#define	EL3RST		47	/* Level 3 reset */
+#define	ELNRNG		48	/* Link number out of range */
+#define	EUNATCH		49	/* Protocol driver not attached */
+#define	ENOCSI		50	/* No CSI structure available */
+#define	EL2HLT		51	/* Level 2 halted */
+#define	EBADE		52	/* Invalid exchange */
+#define	EBADR		53	/* Invalid request descriptor */
+#define	EXFULL		54	/* Exchange full */
+#define	ENOANO		55	/* No anode */
+#define	EBADRQC		56	/* Invalid request code */
+#define	EBADSLT		57	/* Invalid slot */
+#define	EDEADLOCK	58	/* File locking deadlock error */
+#define	EBFONT		59	/* Bad font file format */
+#define	ENOSTR		60	/* Device not a stream */
+#define	ENODATA		61	/* No data available */
+#define	ETIME		62	/* Timer expired */
+#define	ENOSR		63	/* Out of streams resources */
+#define	ENONET		64	/* Machine is not on the network */
+#define	ENOPKG		65	/* Package not installed */
+#define	EREMOTE		66	/* Object is remote */
+#define	ENOLINK		67	/* Link has been severed */
+#define	EADV		68	/* Advertise error */
+#define	ESRMNT		69	/* Srmount error */
+#define	ECOMM		70	/* Communication error on send */
+#define	EPROTO		71	/* Protocol error */
+#define	EMULTIHOP	72	/* Multihop attempted */
+#define	EDOTDOT		73	/* RFS specific error */
+#define	EBADMSG		74	/* Not a data message */
+#define	EOVERFLOW	75	/* Value too large for defined data type */
+#define	ENOTUNIQ	76	/* Name not unique on network */
+#define	EBADFD		77	/* File descriptor in bad state */
+#define	EREMCHG		78	/* Remote address changed */
+#define	ELIBACC		79	/* Can not access a needed shared library */
+#define	ELIBBAD		80	/* Accessing a corrupted shared library */
+#define	ELIBSCN		81	/* .lib section in a.out corrupted */
+#define	ELIBMAX		82	/* Attempting to link in too many shared libraries */
+#define	ELIBEXEC	83	/* Cannot exec a shared library directly */
+#define	EILSEQ		84	/* Illegal byte sequence */
+#define	ERESTART	85	/* Interrupted system call should be restarted */
+#define	ESTRPIPE	86	/* Streams pipe error */
+#define	EUSERS		87	/* Too many users */
+#define	ENOTSOCK	88	/* Socket operation on non-socket */
+#define	EDESTADDRREQ	89	/* Destination address required */
+#define	EMSGSIZE	90	/* Message too long */
+#define	EPROTOTYPE	91	/* Protocol wrong type for socket */
+#define	ENOPROTOOPT	92	/* Protocol not available */
+#define	EPROTONOSUPPORT	93	/* Protocol not supported */
+#define	ESOCKTNOSUPPORT	94	/* Socket type not supported */
+#define	EOPNOTSUPP	95	/* Operation not supported on transport endpoint */
+#define	EPFNOSUPPORT	96	/* Protocol family not supported */
+#define	EAFNOSUPPORT	97	/* Address family not supported by protocol */
+#define	EADDRINUSE	98	/* Address already in use */
+#define	EADDRNOTAVAIL	99	/* Cannot assign requested address */
+#define	ENETDOWN	100	/* Network is down */
+#define	ENETUNREACH	101	/* Network is unreachable */
+#define	ENETRESET	102	/* Network dropped connection because of reset */
+#define	ECONNABORTED	103	/* Software caused connection abort */
+#define	ECONNRESET	104	/* Connection reset by peer */
+#define	ENOBUFS		105	/* No buffer space available */
+#define	EISCONN		106	/* Transport endpoint is already connected */
+#define	ENOTCONN	107	/* Transport endpoint is not connected */
+#define	ESHUTDOWN	108	/* Cannot send after transport endpoint shutdown */
+#define	ETOOMANYREFS	109	/* Too many references: cannot splice */
+#define	ETIMEDOUT	110	/* Connection timed out */
+#define	ECONNREFUSED	111	/* Connection refused */
+#define	EHOSTDOWN	112	/* Host is down */
+#define	EHOSTUNREACH	113	/* No route to host */
+#define	EALREADY	114	/* Operation already in progress */
+#define	EINPROGRESS	115	/* Operation now in progress */
+#define	ESTALE		116	/* Stale NFS file handle */
+#define	EUCLEAN		117	/* Structure needs cleaning */
+#define	ENOTNAM		118	/* Not a XENIX named type file */
+#define	ENAVAIL		119	/* No XENIX semaphores available */
+#define	EISNAM		120	/* Is a named type file */
+#define	EREMOTEIO	121	/* Remote I/O error */
+#define	EDQUOT		122	/* Quota exceeded */
+
+#endif /* _M68K_ERRNO_H */
diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/fcntl.h linux/include/asm-m68k/fcntl.h
--- v1.3.93/linux/include/asm-m68k/fcntl.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-m68k/fcntl.h	Wed Dec 27 22:46:55 1995
@@ -0,0 +1,64 @@
+#ifndef _M68K_FCNTL_H
+#define _M68K_FCNTL_H
+
+/* open/fcntl - O_SYNC is only implemented on blocks devices and on files
+   located on an ext2 file system */
+#define O_ACCMODE	  0003
+#define O_RDONLY	    00
+#define O_WRONLY	    01
+#define O_RDWR		    02
+#define O_CREAT		  0100	/* not fcntl */
+#define O_EXCL		  0200	/* not fcntl */
+#define O_NOCTTY	  0400	/* not fcntl */
+#define O_TRUNC		 01000	/* not fcntl */
+#define O_APPEND	 02000
+#define O_NONBLOCK	 04000
+#define O_NDELAY	O_NONBLOCK
+#define O_SYNC		010000
+#define FASYNC		020000	/* fcntl, for BSD compatibility */
+
+#define F_DUPFD		0	/* dup */
+#define F_GETFD		1	/* get f_flags */
+#define F_SETFD		2	/* set f_flags */
+#define F_GETFL		3	/* more flags (cloexec) */
+#define F_SETFL		4
+#define F_GETLK		5
+#define F_SETLK		6
+#define F_SETLKW	7
+
+#define F_SETOWN	8	/*  for sockets. */
+#define F_GETOWN	9	/*  for sockets. */
+
+/* for F_[GET|SET]FL */
+#define FD_CLOEXEC	1	/* actually anything with low bit set goes */
+
+/* for posix fcntl() and lockf() */
+#define F_RDLCK		0
+#define F_WRLCK		1
+#define F_UNLCK		2
+
+/* for old implementation of bsd flock () */
+#define F_EXLCK		4	/* or 3 */
+#define F_SHLCK		8	/* or 4 */
+
+/* operations for bsd flock(), also used by the kernel implementation */
+#define LOCK_SH		1	/* shared lock */
+#define LOCK_EX		2	/* exclusive lock */
+#define LOCK_NB		4	/* or'd with one of the above to prevent
+				   blocking */
+#define LOCK_UN		8	/* remove lock */
+
+#ifdef __KERNEL__
+#define F_POSIX		1
+#define F_FLOCK		2
+#endif /* __KERNEL__ */
+
+struct flock {
+	short l_type;
+	short l_whence;
+	off_t l_start;
+	off_t l_len;
+	pid_t l_pid;
+};
+
+#endif /* _M68K_FCNTL_H */
diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/font.h linux/include/asm-m68k/font.h
--- v1.3.93/linux/include/asm-m68k/font.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-m68k/font.h	Mon Apr  1 21:11:19 1996
@@ -0,0 +1,32 @@
+/*
+ *  asm-m68k/font.h -- `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 README.legal in the main directory of this archive
+ *  for more details.
+ */
+
+#ifndef _ASM_M68K_FONT_H_
+#define _ASM_M68K_FONT_H_
+
+#include <linux/types.h>
+
+
+   /*
+    *    Find a font with a specific name
+    */
+
+extern int findsoftfont(char *name, int *width, int *heigth, u_char *data[]);
+
+
+   /*
+    *    Get the default font for a specific screen size
+    */
+
+extern void getdefaultfont(int xres, int yres, char *name[], int *width,
+                           int *height, u_char *data[]);
+
+
+#endif /* _ASM_M68K_FONT_H_ */
diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/ide.h linux/include/asm-m68k/ide.h
--- v1.3.93/linux/include/asm-m68k/ide.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-m68k/ide.h	Tue Apr  9 00:13:55 1996
@@ -0,0 +1,221 @@
+#ifndef _M68K_IDE_H
+#define _M68K_IDE_H
+
+/* Copyright(c) 1996 Kars de Jong */
+/* Based on the ide driver from 1.2.13pl8 */
+
+#include <linux/config.h>
+
+#ifdef CONFIG_AMIGA
+#include <asm/amigahw.h>
+#include <asm/amihdreg.h>
+#include <asm/amigaints.h>
+#endif /* CONFIG_AMIGA */
+
+#ifdef CONFIG_ATARI
+#include <asm/atarihw.h>
+#include <asm/atarihdreg.h>
+#include <asm/atariints.h>
+#include <asm/atari_stdma.h>
+#endif /* CONFIG_ATARI */
+
+#include <asm/bootinfo.h>
+
+struct hd_regs_struct {
+  unsigned int hd_error,
+  hd_nsector,
+  hd_sector,
+  hd_lcyl,
+  hd_hcyl,
+  hd_select,
+  hd_status;
+};
+
+static struct hd_regs_struct hd_regs;
+static void probe_m68k_ide (void);
+
+/* Undefine these again, they were defined for the PC. */
+#undef IDE_ERROR_OFFSET
+#undef IDE_NSECTOR_OFFSET
+#undef IDE_SECTOR_OFFSET
+#undef IDE_LCYL_OFFSET
+#undef IDE_HCYL_OFFSET
+#undef IDE_SELECT_OFFSET
+#undef IDE_STATUS_OFFSET
+#undef IDE_FEATURE_OFFSET
+#undef IDE_COMMAND_OFFSET
+#undef SELECT_DRIVE
+
+#define IDE_ERROR_OFFSET	hd_regs.hd_error
+#define IDE_NSECTOR_OFFSET	hd_regs.hd_nsector
+#define IDE_SECTOR_OFFSET	hd_regs.hd_sector
+#define IDE_LCYL_OFFSET		hd_regs.hd_lcyl
+#define IDE_HCYL_OFFSET		hd_regs.hd_hcyl
+#define IDE_SELECT_OFFSET	hd_regs.hd_select
+#define IDE_STATUS_OFFSET	hd_regs.hd_status
+#define IDE_FEATURE_OFFSET	IDE_ERROR_OFFSET
+#define IDE_COMMAND_OFFSET	IDE_STATUS_OFFSET
+
+#undef SUPPORT_VLB_SYNC
+#define SUPPORT_VLB_SYNC 0
+
+#undef HD_DATA
+#define HD_DATA NULL
+
+#define SELECT_DRIVE(hwif,drive)  OUT_BYTE((drive)->select.all, hwif->io_base+IDE_SELECT_OFFSET);
+
+#define insl(data_reg, buffer, wcount) insw(data_reg, buffer, wcount<<1)
+#define outsl(data_reg, buffer, wcount) outsw(data_reg, buffer, wcount<<1)
+
+#define insw(port, buf, nr) \
+    if (nr % 16) \
+	__asm__ __volatile__ \
+	       ("movel %0,%/a0; \
+		 movel %1,%/a1; \
+		 movel %2,%/d6; \
+		 subql #1,%/d6; \
+	       1:movew %/a0@,%/a1@+; \
+		 dbra %/d6,1b" : \
+		: "g" (port), "g" (buf), "g" (nr) \
+		: "a0", "a1", "d6"); \
+    else \
+	__asm__ __volatile__ \
+	       ("movel %0,%/a0; \
+		 movel %1,%/a1; \
+		 movel %2,%/d6; \
+		 lsrl  #4,%/d6; \
+		 subql #1,%/d6; \
+	       1:movew %/a0@,%/a1@+; \
+		 movew %/a0@,%/a1@+; \
+		 movew %/a0@,%/a1@+; \
+		 movew %/a0@,%/a1@+; \
+		 movew %/a0@,%/a1@+; \
+		 movew %/a0@,%/a1@+; \
+		 movew %/a0@,%/a1@+; \
+		 movew %/a0@,%/a1@+; \
+		 movew %/a0@,%/a1@+; \
+		 movew %/a0@,%/a1@+; \
+		 movew %/a0@,%/a1@+; \
+		 movew %/a0@,%/a1@+; \
+		 movew %/a0@,%/a1@+; \
+		 movew %/a0@,%/a1@+; \
+		 movew %/a0@,%/a1@+; \
+		 movew %/a0@,%/a1@+; \
+		 dbra %/d6,1b" : \
+		: "g" (port), "g" (buf), "g" (nr) \
+		: "a0", "a1", "d6");
+
+#define outsw(port, buf, nr) \
+    if (nr % 16) \
+	__asm__ __volatile__ \
+	       ("movel %0,%/a0; \
+		 movel %1,%/a1; \
+		 movel %2,%/d6; \
+		 subql #1,%/d6; \
+	       1:movew %/a1@+,%/a0@; \
+		 dbra %/d6,1b" : \
+		: "g" (port), "g" (buf), "g" (nr) \
+		: "a0", "a1", "d6"); \
+    else \
+	__asm__ __volatile__ \
+	       ("movel %0,%/a0; \
+		 movel %1,%/a1; \
+		 movel %2,%/d6; \
+		 lsrl  #4,%/d6; \
+		 subql #1,%/d6; \
+	       1:movew %/a1@+,%/a0@; \
+		 movew %/a1@+,%/a0@; \
+		 movew %/a1@+,%/a0@; \
+		 movew %/a1@+,%/a0@; \
+		 movew %/a1@+,%/a0@; \
+		 movew %/a1@+,%/a0@; \
+		 movew %/a1@+,%/a0@; \
+		 movew %/a1@+,%/a0@; \
+		 movew %/a1@+,%/a0@; \
+		 movew %/a1@+,%/a0@; \
+		 movew %/a1@+,%/a0@; \
+		 movew %/a1@+,%/a0@; \
+		 movew %/a1@+,%/a0@; \
+		 movew %/a1@+,%/a0@; \
+		 movew %/a1@+,%/a0@; \
+		 movew %/a1@+,%/a0@; \
+		 dbra %/d6,1b" : \
+		: "g" (port), "g" (buf), "g" (nr) \
+		: "a0", "a1", "d6");
+
+#define T_CHAR          (0x0000)        /* char:  don't touch  */
+#define T_SHORT         (0x4000)        /* short: 12 -> 21     */
+#define T_INT           (0x8000)        /* int:   1234 -> 4321 */
+#define T_TEXT          (0xc000)        /* text:  12 -> 21     */
+
+#define T_MASK_TYPE     (0xc000)
+#define T_MASK_COUNT    (0x3fff)
+
+#define D_CHAR(cnt)     (T_CHAR  | (cnt))
+#define D_SHORT(cnt)    (T_SHORT | (cnt))
+#define D_INT(cnt)      (T_INT   | (cnt))
+#define D_TEXT(cnt)     (T_TEXT  | (cnt))
+
+static u_short driveid_types[] = {
+	D_SHORT(10),	/* config - vendor2 */
+	D_TEXT(20),	/* serial_no */
+	D_SHORT(3),	/* buf_type - ecc_bytes */
+	D_TEXT(48),	/* fw_rev - model */
+	D_CHAR(2),	/* max_multsect - vendor3 */
+	D_SHORT(1),	/* dword_io */
+	D_CHAR(2),	/* vendor4 - capability */
+	D_SHORT(1),	/* reserved50 */
+	D_CHAR(4),	/* vendor5 - tDMA */
+	D_SHORT(4),	/* field_valid - cur_sectors */
+	D_INT(1),	/* cur_capacity */
+	D_CHAR(2),	/* multsect - multsect_valid */
+	D_INT(1),	/* lba_capacity */
+	D_SHORT(194)	/* dma_1word - reservedyy */
+};
+
+#define num_driveid_types       (sizeof(driveid_types)/sizeof(*driveid_types))
+
+static __inline__ void big_endianize_driveid(struct hd_driveid *id)
+{
+   u_char *p = (u_char *)id;
+   int i, j, cnt;
+   u_char t;
+
+   for (i = 0; i < num_driveid_types; i++) {
+      cnt = driveid_types[i] & T_MASK_COUNT;
+      switch (driveid_types[i] & T_MASK_TYPE) {
+         case T_CHAR:
+            p += cnt;
+            break;
+         case T_SHORT:
+            for (j = 0; j < cnt; j++) {
+               t = p[0];
+               p[0] = p[1];
+               p[1] = t;
+               p += 2;
+            }
+            break;
+         case T_INT:
+            for (j = 0; j < cnt; j++) {
+               t = p[0];
+               p[0] = p[3];
+               p[3] = t;
+               t = p[1];
+               p[1] = p[2];
+               p[2] = t;
+               p += 4;
+            }
+            break;
+         case T_TEXT:
+            for (j = 0; j < cnt; j += 2) {
+               t = p[0];
+               p[0] = p[1];
+               p[1] = t;
+               p += 2;
+            }
+            break;
+      }
+   }
+}
+
+#endif /* _M68K_IDE_H */
diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/io.h linux/include/asm-m68k/io.h
--- v1.3.93/linux/include/asm-m68k/io.h	Mon Nov 28 20:59:32 1994
+++ linux/include/asm-m68k/io.h	Wed Dec 27 22:46:55 1995
@@ -5,7 +5,7 @@
 {
 	register unsigned char _v;
 
-	__asm__ __volatile__ ("moveb %1,%0":"=r" (_v):"m" (*addr));
+	__asm__ __volatile__ ("moveb %1,%0":"=dm" (_v):"m" (*addr));
 	return _v;
 }
 #define inb_p(addr) get_user_byte_io((char *)(addr))
@@ -15,10 +15,36 @@
 {
 	__asm__ __volatile__ ("moveb %0,%1"
 			      : /* no outputs */
-			      :"r" (val),"m" (*addr)
+			      :"idm" (val),"m" (*addr)
 			      : "memory");
 }
 #define outb_p(x,addr) put_user_byte_io((x),(char *)(addr))
 #define outb(x,addr) put_user_byte_io((x),(char *)(addr))
+
+/*
+ * Change virtual addresses to physical addresses and vv.
+ * These are trivial on the 1:1 Linux/i386 mapping (but if we ever
+ * make the kernel segment mapped at 0, we need to do translation
+ * on the i386 as well)
+ */
+extern unsigned long mm_vtop(unsigned long addr);
+extern unsigned long mm_ptov(unsigned long addr);
+
+extern inline unsigned long virt_to_phys(volatile void * address)
+{
+	return (unsigned long) mm_vtop((unsigned long)address);
+}
+
+extern inline void * phys_to_virt(unsigned long address)
+{
+	return (void *) mm_ptov(address);
+}
+
+/*
+ * IO bus memory addresses are also 1:1 with the physical address
+ */
+#define virt_to_bus virt_to_phys
+#define bus_to_virt phys_to_virt
+
 
 #endif /* _M68K_IO_H */
diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/ioctl.h linux/include/asm-m68k/ioctl.h
--- v1.3.93/linux/include/asm-m68k/ioctl.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-m68k/ioctl.h	Sat Mar 23 14:31:14 1996
@@ -0,0 +1,80 @@
+/* $Id: ioctl.h,v 1.4 1996/03/23 12:31:12 root Exp root $
+ *
+ * linux/ioctl.h for Linux by H.H. Bergman.
+ */
+
+#ifndef _M68K_IOCTL_H
+#define _M68K_IOCTL_H
+
+/* ioctl command encoding: 32 bits total, command in lower 16 bits,
+ * size of the parameter structure in the lower 14 bits of the
+ * upper 16 bits.
+ * Encoding the size of the parameter structure in the ioctl request
+ * is useful for catching programs compiled with old versions
+ * and to avoid overwriting user space outside the user buffer area.
+ * The highest 2 bits are reserved for indicating the ``access mode''.
+ * NOTE: This limits the max parameter size to 16kB -1 !
+ */
+
+/*
+ * I don't really have any idea about what this should look like, so
+ * for the time being, this is heavily based on the PC definitions.
+ */
+
+/*
+ * The following is for compatibility across the various Linux
+ * platforms.  The i386 ioctl numbering scheme doesn't really enforce
+ * a type field.  De facto, however, the top 8 bits of the lower 16
+ * bits are indeed used as a type field, so we might just as well make
+ * this explicit here.  Please be sure to use the decoding macros
+ * below from now on.
+ */
+#define _IOC_NRBITS	8
+#define _IOC_TYPEBITS	8
+#define _IOC_SIZEBITS	14
+#define _IOC_DIRBITS	2
+
+#define _IOC_NRMASK	((1 << _IOC_NRBITS)-1)
+#define _IOC_TYPEMASK	((1 << _IOC_TYPEBITS)-1)
+#define _IOC_SIZEMASK	((1 << _IOC_SIZEBITS)-1)
+#define _IOC_DIRMASK	((1 << _IOC_DIRBITS)-1)
+
+#define _IOC_NRSHIFT	0
+#define _IOC_TYPESHIFT	(_IOC_NRSHIFT+_IOC_NRBITS)
+#define _IOC_SIZESHIFT	(_IOC_TYPESHIFT+_IOC_TYPEBITS)
+#define _IOC_DIRSHIFT	(_IOC_SIZESHIFT+_IOC_SIZEBITS)
+
+/*
+ * Direction bits.
+ */
+#define _IOC_NONE	0U
+#define _IOC_WRITE	1U
+#define _IOC_READ	2U
+
+#define _IOC(dir,type,nr,size) \
+	(((dir)  << _IOC_DIRSHIFT) | \
+	 ((type) << _IOC_TYPESHIFT) | \
+	 ((nr)   << _IOC_NRSHIFT) | \
+	 ((size) << _IOC_SIZESHIFT))
+
+/* used to create numbers */
+#define _IO(type,nr)		_IOC(_IOC_NONE,(type),(nr),0)
+#define _IOR(type,nr,size)	_IOC(_IOC_READ,(type),(nr),sizeof(size))
+#define _IOW(type,nr,size)	_IOC(_IOC_WRITE,(type),(nr),sizeof(size))
+#define _IOWR(type,nr,size)	_IOC(_IOC_READ|_IOC_WRITE,(type),(nr),sizeof(size))
+
+/* used to decode ioctl numbers.. */
+#define _IOC_DIR(nr)		(((nr) >> _IOC_DIRSHIFT) & _IOC_DIRMASK)
+#define _IOC_TYPE(nr)		(((nr) >> _IOC_TYPESHIFT) & _IOC_TYPEMASK)
+#define _IOC_NR(nr)		(((nr) >> _IOC_NRSHIFT) & _IOC_NRMASK)
+#define _IOC_SIZE(nr)		(((nr) >> _IOC_SIZESHIFT) & _IOC_SIZEMASK)
+
+/* ...and for the drivers/sound files... */
+
+#define IOC_IN		(_IOC_WRITE << _IOC_DIRSHIFT)
+#define IOC_OUT		(_IOC_READ << _IOC_DIRSHIFT)
+#define IOC_INOUT	((_IOC_WRITE|_IOC_READ) << _IOC_DIRSHIFT)
+#define IOCSIZE_MASK	(_IOC_SIZEMASK << _IOC_SIZESHIFT)
+#define IOCSIZE_SHIFT	(_IOC_SIZESHIFT)
+
+#endif /* _M68K_IOCTL_H */
diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/ioctls.h linux/include/asm-m68k/ioctls.h
--- v1.3.93/linux/include/asm-m68k/ioctls.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-m68k/ioctls.h	Fri Apr  5 14:08:13 1996
@@ -0,0 +1,74 @@
+#ifndef __ARCH_M68K_IOCTLS_H__
+#define __ARCH_M68K_IOCTLS_H__
+
+#include <asm/ioctl.h>
+
+/* 0x54 is just a magic number to make these relatively unique ('T') */
+
+#define TCGETS		0x5401
+#define TCSETS		0x5402
+#define TCSETSW		0x5403
+#define TCSETSF		0x5404
+#define TCGETA		0x5405
+#define TCSETA		0x5406
+#define TCSETAW		0x5407
+#define TCSETAF		0x5408
+#define TCSBRK		0x5409
+#define TCXONC		0x540A
+#define TCFLSH		0x540B
+#define TIOCEXCL	0x540C
+#define TIOCNXCL	0x540D
+#define TIOCSCTTY	0x540E
+#define TIOCGPGRP	0x540F
+#define TIOCSPGRP	0x5410
+#define TIOCOUTQ	0x5411
+#define TIOCSTI		0x5412
+#define TIOCGWINSZ	0x5413
+#define TIOCSWINSZ	0x5414
+#define TIOCMGET	0x5415
+#define TIOCMBIS	0x5416
+#define TIOCMBIC	0x5417
+#define TIOCMSET	0x5418
+#define TIOCGSOFTCAR	0x5419
+#define TIOCSSOFTCAR	0x541A
+#define FIONREAD	0x541B
+#define TIOCINQ		FIONREAD
+#define TIOCLINUX	0x541C
+#define TIOCCONS	0x541D
+#define TIOCGSERIAL	0x541E
+#define TIOCSSERIAL	0x541F
+#define TIOCPKT		0x5420
+#define FIONBIO		0x5421
+#define TIOCNOTTY	0x5422
+#define TIOCSETD	0x5423
+#define TIOCGETD	0x5424
+#define TCSBRKP		0x5425	/* Needed for POSIX tcsendbreak() */
+#define TIOCTTYGSTRUCT	0x5426  /* For debugging only */
+#define FIONCLEX	0x5450  /* these numbers need to be adjusted. */
+#define FIOCLEX		0x5451
+#define FIOASYNC	0x5452
+#define TIOCSERCONFIG	0x5453
+#define TIOCSERGWILD	0x5454
+#define TIOCSERSWILD	0x5455
+#define TIOCGLCKTRMIOS	0x5456
+#define TIOCSLCKTRMIOS	0x5457
+#define TIOCSERGSTRUCT	0x5458 /* For debugging only */
+#define TIOCSERGETLSR   0x5459 /* Get line status register */
+#define TIOCSERGETMULTI 0x545A /* Get multiport config  */
+#define TIOCSERSETMULTI 0x545B /* Set multiport config */
+
+#define TIOCMIWAIT	0x545C	/* wait for a change on serial input line(s) */
+#define TIOCGICOUNT	0x545D	/* read serial port inline interrupt counts */
+
+/* Used for packet mode */
+#define TIOCPKT_DATA		 0
+#define TIOCPKT_FLUSHREAD	 1
+#define TIOCPKT_FLUSHWRITE	 2
+#define TIOCPKT_STOP		 4
+#define TIOCPKT_START		 8
+#define TIOCPKT_NOSTOP		16
+#define TIOCPKT_DOSTOP		32
+
+#define TIOCSER_TEMT    0x01	/* Transmitter physically empty */
+
+#endif /* __ARCH_M68K_IOCTLS_H__ */
diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/irq.h linux/include/asm-m68k/irq.h
--- v1.3.93/linux/include/asm-m68k/irq.h	Mon Nov 28 21:03:09 1994
+++ linux/include/asm-m68k/irq.h	Mon Apr  1 22:16:35 1996
@@ -1,6 +1,116 @@
 #ifndef _M68K_IRQ_H_
 #define _M68K_IRQ_H_
 
-/* dummy for m68k */
+extern void disable_irq(unsigned int);
+extern void enable_irq(unsigned int);
+
+#include <linux/config.h>
+
+/*
+ * This should be the same as the max(NUM_X_SOURCES) for all the
+ * different m68k hosts compiled into the kernel.
+ * Currently the Atari has 72 and the Amiga 24, but if both are
+ * supported in the kernel it is better to make room for 72.
+ */
+#if defined(CONFIG_ATARI)
+#define NR_IRQS 72
+#else
+#define NR_IRQS 24
+#endif
+
+/*
+ * Interrupt source definitions
+ * General interrupt sources are the level 1-7.
+ * Adding an interrupt service routine for one of these sources
+ * results in the addition of that routine to a chain of routines.
+ * Each one is called in succession.  Each individual interrupt
+ * service routine should determine if the device associated with
+ * that routine requires service.
+ */
+
+#define IRQ1		 (1)    /* level 1 interrupt */
+#define IRQ2		 (2)    /* level 2 interrupt */
+#define IRQ3		 (3)    /* level 3 interrupt */
+#define IRQ4		 (4)    /* level 4 interrupt */
+#define IRQ5		 (5)    /* level 5 interrupt */
+#define IRQ6		 (6)    /* level 6 interrupt */
+#define IRQ7		 (7)    /* level 7 interrupt (non-maskable) */
+
+/*
+ * "Generic" interrupt sources
+ */
+
+#define IRQ_SCHED_TIMER  (8)    /* interrupt source for scheduling timer */
+
+/*
+ * Machine specific interrupt sources.
+ *
+ * Adding an interrupt service routine for a source with this bit
+ * set indicates a special machine specific interrupt source.
+ * The machine specific files define these sources.
+ */
+
+#define IRQ_MACHSPEC	 (0x10000000L)
+
+#ifndef ISRFUNC_T
+struct pt_regs;
+typedef void (*isrfunc) (int irq, struct pt_regs * regs, void *data);
+#define ISRFUNC_T
+#endif /* ISRFUNC_T */
+
+/*
+ * This structure is used to chain together the ISRs for a particular
+ * interrupt source (if it supports chaining).
+ */
+typedef struct isr_node {
+    isrfunc	    isr;
+    int 	    pri;
+    void            *data;
+    char	    *name;
+    struct isr_node *next;
+} isr_node_t;
+
+/* count of spurious interrupts */
+extern volatile unsigned long num_spurious;
+
+/*
+ * This function returns a new isr_node_t
+ */
+extern isr_node_t *new_isr_node(void);
+
+/*
+ * This function is used to add a specific interrupt service routine
+ * for the specified interrupt source.
+ *
+ * If the source is machine specific, it will be passed along to the
+ * machine specific routine.
+ *
+ * "data" is user specified data which will be passed to the isr routine.
+ *
+ * (isrfunc is defined in linux/config.h)
+ */
+extern int add_isr (unsigned long source, isrfunc isr, int pri, void
+		    *data, char *name);
+
+/*
+ * This routine will remove an isr for the specified interrupt source.
+ */
+extern int remove_isr (unsigned long source, isrfunc isr);
+
+/*
+ * This routine will insert an isr_node_t into a chain of nodes, using
+ * the priority stored in the node.
+ */
+extern void insert_isr (isr_node_t **listp, isr_node_t *node);
+
+/*
+ * This routine will delete the isr node for isr from a chain of nodes
+ */
+extern void delete_isr (isr_node_t **listp, isrfunc isr);
+
+/*
+ * This routine may be used to call the isr routines in the passed list.
+ */
+extern void call_isr_list (int irq, isr_node_t *p, struct pt_regs *fp);
 
 #endif /* _M68K_IRQ_H_ */
diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/machdep.h linux/include/asm-m68k/machdep.h
--- v1.3.93/linux/include/asm-m68k/machdep.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-m68k/machdep.h	Tue Apr  9 00:15:45 1996
@@ -0,0 +1,46 @@
+#ifndef _M68K_MACHDEP_H
+#define _M68K_MACHDEP_H
+
+struct pt_regs;
+struct kbd_repeat;
+struct mktime;
+struct hwclk_time;
+struct gendisk;
+struct buffer_head;
+
+#ifndef ISRFUNC_T
+typedef void (*isrfunc) (int irq, struct pt_regs *fp, void *data);
+#define ISRFUNC_T
+#endif /* ISRFUNC_T */
+
+extern void (*mach_sched_init)(isrfunc);
+extern int (*mach_keyb_init) (void);
+extern int (*mach_kbdrate) (struct kbd_repeat *);
+extern void (*mach_kbd_leds) (unsigned int);
+extern void (*mach_init_INTS) (void);
+extern int (*mach_add_isr) (unsigned long source, isrfunc handler,
+			    int pri, void *data, char *name);
+extern int (*mach_remove_isr) (unsigned long source, isrfunc handler);
+extern int (*mach_get_irq_list)(char *buf, int len);
+extern void (*mach_process_int) (int level, struct pt_regs *fp);
+extern void (*mach_enable_irq) (unsigned);
+extern void (*mach_disable_irq) (unsigned);
+extern unsigned long (*mach_gettimeoffset)(void);
+extern void (*mach_gettod)(int *year, int *mon, int *day, int *hour,
+			   int *min, int *sec);
+extern int (*mach_hwclk)(int, struct hwclk_time*);
+extern int (*mach_set_clock_mmss)(unsigned long);
+extern void (*mach_check_partition) (struct gendisk *hd, unsigned int dev);
+extern void (*mach_mksound)( unsigned int count, unsigned int ticks );
+extern void (*mach_reset)( void );
+extern int (*mach_floppy_init) (void);
+extern unsigned long (*mach_hd_init) (unsigned long, unsigned long);
+extern void (*mach_hd_setup)(char *, int *);
+extern void (*waitbut)(void);
+extern struct fb_info *(*mach_fb_init)(long *);
+extern long mach_max_dma_address;
+extern void (*mach_debug_init)(void);
+extern void (*mach_video_setup)(char *, int *);
+extern void (*mach_floppy_setup)(char *, int *);
+
+#endif /* _M68K_MACHDEP_H */
diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/mman.h linux/include/asm-m68k/mman.h
--- v1.3.93/linux/include/asm-m68k/mman.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-m68k/mman.h	Sat Mar 23 22:23:19 1996
@@ -0,0 +1,31 @@
+#ifndef __M68K_MMAN_H__
+#define __M68K_MMAN_H__
+
+#define PROT_READ	0x1		/* page can be read */
+#define PROT_WRITE	0x2		/* page can be written */
+#define PROT_EXEC	0x4		/* page can be executed */
+#define PROT_NONE	0x0		/* page can not be accessed */
+
+#define MAP_SHARED	0x01		/* Share changes */
+#define MAP_PRIVATE	0x02		/* Changes are private */
+#define MAP_TYPE	0x0f		/* Mask for type of mapping */
+#define MAP_FIXED	0x10		/* Interpret addr exactly */
+#define MAP_ANONYMOUS	0x20		/* don't use a file */
+
+#define MAP_GROWSDOWN	0x0100		/* stack-like segment */
+#define MAP_DENYWRITE	0x0800		/* ETXTBSY */
+#define MAP_EXECUTABLE	0x1000		/* mark it as a executable */
+#define MAP_LOCKED	0x2000		/* pages are locked */
+
+#define MS_ASYNC	1		/* sync memory asynchronously */
+#define MS_INVALIDATE	2		/* invalidate the caches */
+#define MS_SYNC		4		/* synchronous memory sync */
+
+#define MCL_CURRENT	1		/* lock all current mappings */
+#define MCL_FUTURE	2		/* lock all future mappings */
+
+/* compatibility flags */
+#define MAP_ANON	MAP_ANONYMOUS
+#define MAP_FILE	0
+
+#endif /* __M68K_MMAN_H__ */
diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/mmu_context.h linux/include/asm-m68k/mmu_context.h
--- v1.3.93/linux/include/asm-m68k/mmu_context.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-m68k/mmu_context.h	Wed Mar 27 22:45:37 1996
@@ -0,0 +1,9 @@
+#ifndef __68K_MMU_CONTEXT_H
+#define __68K_MMU_CONTEXT_H
+
+/*
+ * get a new mmu context.. do we need this on the m68k?
+ */
+#define get_mmu_context(x) do { } while (0)
+
+#endif
diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/page.h linux/include/asm-m68k/page.h
--- v1.3.93/linux/include/asm-m68k/page.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-m68k/page.h	Sat Mar 23 22:26:13 1996
@@ -0,0 +1,72 @@
+#ifndef _M68K_PAGE_H
+#define _M68K_PAGE_H
+
+/* PAGE_SHIFT determines the page size */
+#define PAGE_SHIFT	12
+#define PAGE_SIZE	(1UL << PAGE_SHIFT)
+#define PAGE_MASK	(~(PAGE_SIZE-1))
+
+#ifdef __KERNEL__
+
+#define STRICT_MM_TYPECHECKS
+
+#ifdef STRICT_MM_TYPECHECKS
+/*
+ * These are used to make use of C type-checking..
+ */
+typedef struct { unsigned long pte; } pte_t;
+typedef struct { unsigned long pmd[16]; } pmd_t;
+typedef struct { unsigned long pgd; } pgd_t;
+typedef struct { unsigned long pgprot; } pgprot_t;
+
+#define pte_val(x)	((x).pte)
+#define pmd_val(x)	((&x)->pmd[0])
+#define pgd_val(x)	((x).pgd)
+#define pgprot_val(x)	((x).pgprot)
+
+#define __pte(x)	((pte_t) { (x) } )
+#define __pmd(x)	((pmd_t) { (x) } )
+#define __pgd(x)	((pgd_t) { (x) } )
+#define __pgprot(x)	((pgprot_t) { (x) } )
+
+#else
+/*
+ * .. while these make it easier on the compiler
+ */
+typedef unsigned long pte_t;
+typedef struct { unsigned long pmd[16]; } pmd_t;
+typedef unsigned long pgd_t;
+typedef unsigned long pgprot_t;
+
+#define pte_val(x)	(x)
+#define pmd_val(x)	((&x)->pmd[0])
+#define pgd_val(x)	(x)
+#define pgprot_val(x)	(x)
+
+#define __pte(x)	(x)
+#define __pmd(x)	((pmd_t) { (x) } )
+#define __pgd(x)	(x)
+#define __pgprot(x)	(x)
+
+#endif
+
+/* m68k_is040or060 is != 0 for a '040 or higher; used numbers are 4 for 68040
+ * and 6 for 68060 */
+extern int m68k_is040or060;
+
+/* This is the cache mode to be used for pages containing page descriptors for
+ * processors >= '040. It is in pte_mknocache(), and the variable is defined
+ * and initialized in head.S */
+extern int m68k_pgtable_cachemode;
+
+/* to align the pointer to the (next) page boundary */
+#define PAGE_ALIGN(addr)	(((addr)+PAGE_SIZE-1)&PAGE_MASK)
+
+/* This handles the memory map.. */
+#define PAGE_OFFSET		0
+#define MAP_NR(addr)		(((unsigned long)(addr)) >> PAGE_SHIFT)
+#define MAP_PAGE_RESERVED	(1<<15)
+
+#endif /* __KERNEL__ */
+
+#endif /* _M68K_PAGE_H */
diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/param.h linux/include/asm-m68k/param.h
--- v1.3.93/linux/include/asm-m68k/param.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-m68k/param.h	Wed Dec 27 22:47:20 1995
@@ -0,0 +1,20 @@
+#ifndef _M68K_PARAM_H
+#define _M68K_PARAM_H
+
+#ifndef HZ
+#define HZ 100
+#endif
+
+#define EXEC_PAGESIZE	4096
+
+#ifndef NGROUPS
+#define NGROUPS		32
+#endif
+
+#ifndef NOGROUP
+#define NOGROUP		(-1)
+#endif
+
+#define MAXHOSTNAMELEN	64	/* max length of hostname */
+
+#endif /* _M68K_PARAM_H */
diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/pgtable.h linux/include/asm-m68k/pgtable.h
--- v1.3.93/linux/include/asm-m68k/pgtable.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-m68k/pgtable.h	Thu Apr 18 03:00:00 1996
@@ -0,0 +1,586 @@
+#ifndef _M68K_PGTABLE_H
+#define _M68K_PGTABLE_H
+
+/*
+ * This file contains the functions and defines necessary to modify and use
+ * the m68k page table tree.
+ */
+
+#define __flush_tlb() \
+do { 	\
+	if (m68k_is040or060) \
+		__asm__ __volatile__(".word 0xf510\n"::); /* pflushan */ \
+	else \
+		__asm__ __volatile__("pflusha\n"::); \
+} while (0)
+
+#if 1
+static inline void __flush_tlb_one(unsigned long addr)
+{
+	if (m68k_is040or060) {
+		register unsigned long a0 __asm__ ("a0") = addr;
+		__asm__ __volatile__(".word 0xf508" /* pflush (%a0) */
+				     : : "a" (a0));
+	} else
+		__asm__ __volatile__("pflush #0,#0,(%0)" : : "a" (addr));
+}
+#else
+#define __flush_tlb_one(addr) __flush_tlb()
+#endif
+
+#define flush_tlb() __flush_tlb()
+#define flush_tlb_all() flush_tlb()
+
+static inline void flush_tlb_mm(struct mm_struct *mm)
+{
+	if (mm == current->mm)
+		__flush_tlb();
+}
+
+static inline void flush_tlb_page(struct vm_area_struct *vma,
+	unsigned long addr)
+{
+	if (vma->vm_mm == current->mm)
+		__flush_tlb_one(addr);
+}
+
+static inline void flush_tlb_range(struct mm_struct *mm,
+	unsigned long start, unsigned long end)
+{
+	if (mm == current->mm)
+		__flush_tlb();
+}
+
+/* Certain architectures need to do special things when pte's
+ * within a page table are directly modified.  Thus, the following
+ * hook is made available.
+ */
+#define set_pte(pteptr, pteval) ((*(pteptr)) = (pteval))
+
+/* PMD_SHIFT determines the size of the area a second-level page table can map */
+#define PMD_SHIFT	22
+#define PMD_SIZE	(1UL << PMD_SHIFT)
+#define PMD_MASK	(~(PMD_SIZE-1))
+
+/* PGDIR_SHIFT determines what a third-level page table entry can map */
+#define PGDIR_SHIFT	25
+#define PGDIR_SIZE	(1UL << PGDIR_SHIFT)
+#define PGDIR_MASK	(~(PGDIR_SIZE-1))
+
+/*
+ * entries per page directory level: the m68k is configured as three-level,
+ * so we do have PMD level physically.
+ */
+#define PTRS_PER_PTE	1024
+#define PTRS_PER_PMD	8
+#define PTRS_PER_PGD	128
+
+/* the no. of pointers that fit on a page: this will go away */
+#define PTRS_PER_PAGE	(PAGE_SIZE/sizeof(void*))
+
+/* Just any arbitrary offset to the start of the vmalloc VM area: the
+ * current 8MB value just means that there will be a 8MB "hole" after the
+ * physical memory until the kernel virtual memory starts.  That means that
+ * any out-of-bounds memory accesses will hopefully be caught.
+ * The vmalloc() routines leaves a hole of 4kB between each vmalloced
+ * area for the same reason. ;)
+ */
+#define VMALLOC_OFFSET	(8*1024*1024)
+#define VMALLOC_START ((high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
+#define VMALLOC_VMADDR(x) ((unsigned long)(x))
+
+/*
+ * Definitions for MMU descriptors
+ */
+#define _PAGE_PRESENT	0x001
+#define _PAGE_SHORT	0x002
+#define _PAGE_RONLY	0x004
+#define _PAGE_ACCESSED	0x008
+#define _PAGE_DIRTY	0x010
+#define _PAGE_GLOBAL040	0x400	/* 68040 global bit, used for kva descs */
+#define _PAGE_COW	0x800	/* implemented in software */
+#define _PAGE_NOCACHE030 0x040	/* 68030 no-cache mode */
+#define _PAGE_NOCACHE	0x060	/* 68040 cache mode, non-serialized */
+#define _PAGE_NOCACHE_S	0x040	/* 68040 no-cache mode, serialized */
+#define _PAGE_CACHE040	0x020	/* 68040 cache mode, cachable, copyback */
+#define _PAGE_CACHE040W	0x000	/* 68040 cache mode, cachable, write-through */
+
+#define _DESCTYPE_MASK	0x003
+
+#define _CACHEMASK040	(~0x060)
+#define _TABLE_MASK	(0xfffffff0)
+
+#define _PAGE_TABLE	(_PAGE_SHORT)
+#define _PAGE_CHG_MASK  (PAGE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY | _PAGE_NOCACHE)
+
+#define PAGE_NONE	__pgprot(_PAGE_PRESENT | _PAGE_RONLY | _PAGE_ACCESSED | _PAGE_CACHE040)
+#define PAGE_SHARED	__pgprot(_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_CACHE040)
+#define PAGE_COPY	__pgprot(_PAGE_PRESENT | _PAGE_RONLY | _PAGE_ACCESSED | _PAGE_CACHE040)
+#define PAGE_READONLY	__pgprot(_PAGE_PRESENT | _PAGE_RONLY | _PAGE_ACCESSED | _PAGE_CACHE040)
+#define PAGE_KERNEL	__pgprot(_PAGE_PRESENT | _PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_CACHE040)
+
+/*
+ * The m68k can't do page protection for execute, and considers that the same are read.
+ * Also, write permissions imply read permissions. This is the closest we can get..
+ */
+#define __P000	PAGE_NONE
+#define __P001	PAGE_READONLY
+#define __P010	PAGE_COPY
+#define __P011	PAGE_COPY
+#define __P100	PAGE_READONLY
+#define __P101	PAGE_READONLY
+#define __P110	PAGE_COPY
+#define __P111	PAGE_COPY
+
+#define __S000	PAGE_NONE
+#define __S001	PAGE_READONLY
+#define __S010	PAGE_SHARED
+#define __S011	PAGE_SHARED
+#define __S100	PAGE_READONLY
+#define __S101	PAGE_READONLY
+#define __S110	PAGE_SHARED
+#define __S111	PAGE_SHARED
+
+/* zero page used for unitialized stuff */
+extern unsigned long empty_zero_page;
+
+/*
+ * BAD_PAGETABLE is used when we need a bogus page-table, while
+ * BAD_PAGE is used for a bogus page.
+ *
+ * ZERO_PAGE is a global shared page that is always zero: used
+ * for zero-mapped memory areas etc..
+ */
+extern pte_t __bad_page(void);
+extern pte_t * __bad_pagetable(void);
+
+#define BAD_PAGETABLE __bad_pagetable()
+#define BAD_PAGE __bad_page()
+#define ZERO_PAGE empty_zero_page
+
+/* number of bits that fit into a memory pointer */
+#define BITS_PER_PTR			(8*sizeof(unsigned long))
+
+/* to align the pointer to a pointer address */
+#define PTR_MASK			(~(sizeof(void*)-1))
+
+/* sizeof(void*)==1<<SIZEOF_PTR_LOG2 */
+/* 64-bit machines, beware!  SRB. */
+#define SIZEOF_PTR_LOG2			2
+
+/* to find an entry in a page-table */
+#define PAGE_PTR(address) \
+((unsigned long)(address)>>(PAGE_SHIFT-SIZEOF_PTR_LOG2)&PTR_MASK&~PAGE_MASK)
+
+extern unsigned long high_memory;
+
+/* For virtual address to physical address conversion */
+extern unsigned long mm_vtop(unsigned long addr) __attribute__ ((const));
+extern unsigned long mm_ptov(unsigned long addr) __attribute__ ((const));
+#define VTOP(addr)  (mm_vtop((unsigned long)(addr)))
+#define PTOV(addr)  (mm_ptov((unsigned long)(addr)))
+
+/*
+ * Conversion functions: convert a page and protection to a page entry,
+ * and a page entry and page directory to the page they refer to.
+ */
+extern inline pte_t mk_pte(unsigned long page, pgprot_t pgprot)
+{ pte_t pte; pte_val(pte) = VTOP(page) | pgprot_val(pgprot); return pte; }
+
+extern inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
+{ pte_val(pte) = (pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot); return pte; }
+
+extern inline void pmd_set(pmd_t * pmdp, pte_t * ptep)
+{
+	int i;
+
+	ptep = (pte_t *) VTOP(ptep);
+	for (i = 0; i < 16; i++, ptep += PTRS_PER_PTE/16)
+		pmdp->pmd[i] = _PAGE_TABLE | (unsigned long)ptep;
+}
+
+/* early termination version of the above */
+extern inline void pmd_set_et(pmd_t * pmdp, pte_t * ptep)
+{
+	int i;
+
+	ptep = (pte_t *) VTOP(ptep);
+	for (i = 0; i < 16; i++, ptep += PTRS_PER_PTE/16)
+		pmdp->pmd[i] = _PAGE_PRESENT | (unsigned long)ptep;
+}
+
+extern inline void pgd_set(pgd_t * pgdp, pmd_t * pmdp)
+{ pgd_val(*pgdp) = _PAGE_TABLE | VTOP(pmdp); }
+
+extern inline unsigned long pte_page(pte_t pte)
+{ return PTOV(pte_val(pte) & PAGE_MASK); }
+
+extern inline unsigned long pmd_page2(pmd_t *pmd)
+{ return PTOV(pmd_val(*pmd) & _TABLE_MASK); }
+#define pmd_page(pmd) pmd_page2(&(pmd))
+
+extern inline unsigned long pgd_page(pgd_t pgd)
+{ return PTOV(pgd_val(pgd) & _TABLE_MASK); }
+
+extern inline int pte_none(pte_t pte)		{ return !pte_val(pte); }
+extern inline int pte_present(pte_t pte)	{ return pte_val(pte) & _PAGE_PRESENT; }
+extern inline void pte_clear(pte_t *ptep)	{ pte_val(*ptep) = 0; }
+
+extern inline int pmd_none2(pmd_t *pmd)		{ return !pmd_val(*pmd); }
+#define pmd_none(pmd) pmd_none2(&(pmd))
+extern inline int pmd_bad2(pmd_t *pmd)		{ return (pmd_val(*pmd) & _DESCTYPE_MASK) != _PAGE_TABLE || pmd_page(*pmd) > high_memory; }
+#define pmd_bad(pmd) pmd_bad2(&(pmd))
+extern inline int pmd_present2(pmd_t *pmd)	{ return pmd_val(*pmd) & _PAGE_TABLE; }
+#define pmd_present(pmd) pmd_present2(&(pmd))
+extern inline void pmd_clear(pmd_t * pmdp)
+{
+	int i;
+
+	for (i = 0; i < 16; i++)
+		pmdp->pmd[i] = 0;
+}
+
+extern inline int pgd_none(pgd_t pgd)		{ return !pgd_val(pgd); }
+extern inline int pgd_bad(pgd_t pgd)		{ return (pgd_val(pgd) & _DESCTYPE_MASK) != _PAGE_TABLE || pgd_page(pgd) > high_memory; }
+extern inline int pgd_present(pgd_t pgd)	{ return pgd_val(pgd) & _PAGE_TABLE; }
+
+extern inline void pgd_clear(pgd_t * pgdp)	{ pgd_val(*pgdp) = 0; }
+
+/*
+ * The following only work if pte_present() is true.
+ * Undefined behaviour if not..
+ */
+extern inline int pte_read(pte_t pte)		{ return 1; }
+extern inline int pte_write(pte_t pte)		{ return !(pte_val(pte) & _PAGE_RONLY); }
+extern inline int pte_exec(pte_t pte)		{ return 1; }
+extern inline int pte_dirty(pte_t pte)		{ return pte_val(pte) & _PAGE_DIRTY; }
+extern inline int pte_young(pte_t pte)		{ return pte_val(pte) & _PAGE_ACCESSED; }
+
+extern inline pte_t pte_wrprotect(pte_t pte)	{ pte_val(pte) |= _PAGE_RONLY; return pte; }
+extern inline pte_t pte_rdprotect(pte_t pte)	{ return pte; }
+extern inline pte_t pte_exprotect(pte_t pte)	{ return pte; }
+extern inline pte_t pte_mkclean(pte_t pte)	{ pte_val(pte) &= ~_PAGE_DIRTY; return pte; }
+extern inline pte_t pte_mkold(pte_t pte)	{ pte_val(pte) &= ~_PAGE_ACCESSED; return pte; }
+extern inline pte_t pte_mkwrite(pte_t pte)	{ pte_val(pte) &= ~_PAGE_RONLY; return pte; }
+extern inline pte_t pte_mkread(pte_t pte)	{ return pte; }
+extern inline pte_t pte_mkexec(pte_t pte)	{ return pte; }
+extern inline pte_t pte_mkdirty(pte_t pte)	{ pte_val(pte) |= _PAGE_DIRTY; return pte; }
+extern inline pte_t pte_mkyoung(pte_t pte)	{ pte_val(pte) |= _PAGE_ACCESSED; return pte; }
+extern inline pte_t pte_mknocache(pte_t pte)
+{
+	pte_val(pte) = (pte_val(pte) & _CACHEMASK040) | m68k_pgtable_cachemode;
+	return pte;
+}
+extern inline pte_t pte_mkcache(pte_t pte)	{ pte_val(pte) = (pte_val(pte) & _CACHEMASK040) | _PAGE_CACHE040; return pte; }
+
+/* to set the page-dir */
+extern inline void SET_PAGE_DIR(struct task_struct * tsk, pgd_t * pgdir)
+{
+	tsk->tss.pagedir_v = (unsigned long *)pgdir;
+	tsk->tss.pagedir_p = VTOP(pgdir);
+	tsk->tss.crp[0] = 0x80000000 | _PAGE_SHORT;
+	tsk->tss.crp[1] = tsk->tss.pagedir_p;
+	if (tsk == current) {
+		if (m68k_is040or060)
+			__asm__ __volatile__ (".word 0xf510\n\t" /* pflushan */
+					      "movel %0@,%/d0\n\t"
+					      ".long 0x4e7b0806\n\t"
+					      /* movec d0,urp */
+					      : : "a" (&tsk->tss.crp[1])
+					      : "d0");
+		else
+			__asm__ __volatile__ ("movec  %/cacr,%/d0\n\t"
+					      "oriw #0x0808,%/d0\n\t"
+					      "movec %/d0,%/cacr\n\t"
+					      "pmove %0@,%/crp\n\t"
+					      : : "a" (&tsk->tss.crp[0])
+					      : "d0");
+	}
+}
+
+#define PAGE_DIR_OFFSET(tsk,address) pgd_offset((tsk),(address))
+
+/* to find an entry in a page-table-directory */
+extern inline pgd_t * pgd_offset(struct mm_struct * mm, unsigned long address)
+{
+	return mm->pgd + (address >> PGDIR_SHIFT);
+}
+
+extern pgd_t swapper_pg_dir[128];
+extern pgd_t kernel_pg_dir[128];
+
+extern inline pgd_t * pgd_offset_k(unsigned long address)
+{
+	return kernel_pg_dir + (address >> PGDIR_SHIFT);
+}
+
+
+/* Find an entry in the second-level page table.. */
+extern inline pmd_t * pmd_offset(pgd_t * dir, unsigned long address)
+{
+	return (pmd_t *) pgd_page(*dir) + ((address >> PMD_SHIFT) & (PTRS_PER_PMD-1));
+}
+
+/* Find an entry in the third-level page table.. */ 
+extern inline pte_t * pte_offset(pmd_t * pmdp, unsigned long address)
+{
+	return (pte_t *) pmd_page(*pmdp) + ((address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1));
+}
+
+/*
+ * Allocate and free page tables. The xxx_kernel() versions are
+ * used to allocate a kernel page table - this turns on ASN bits
+ * if any.
+ */
+
+extern inline void nocache_page (unsigned long vaddr)
+{
+	if (m68k_is040or060) {
+		pgd_t *dir;
+		pmd_t *pmdp;
+		pte_t *ptep;
+
+		dir = pgd_offset_k(vaddr);
+		pmdp = pmd_offset(dir,vaddr);
+		ptep = pte_offset(pmdp,vaddr);
+		*ptep = pte_mknocache(*ptep);
+	}
+}
+
+static inline void cache_page (unsigned long vaddr)
+{
+	if (m68k_is040or060) {
+		pgd_t *dir;
+		pmd_t *pmdp;
+		pte_t *ptep;
+
+		dir = pgd_offset_k(vaddr);
+		pmdp = pmd_offset(dir,vaddr);
+		ptep = pte_offset(pmdp,vaddr);
+		*ptep = pte_mkcache(*ptep);
+	}
+}
+
+
+extern inline void pte_free(pte_t * pte)
+{
+	cache_page((unsigned long)pte);
+	free_page((unsigned long) pte);
+}
+
+extern inline pte_t * pte_alloc(pmd_t * pmd, unsigned long address)
+{
+	address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
+	if (pmd_none(*pmd)) {
+		pte_t * page = (pte_t *)get_free_page(GFP_KERNEL);
+		if (pmd_none(*pmd)) {
+			if (page) {
+				nocache_page((unsigned long)page);
+				pmd_set(pmd,page);
+				return page + address;
+			}
+			pmd_set(pmd, BAD_PAGETABLE);
+			return NULL;
+		}
+		free_page((unsigned long)page);
+	}
+	if (pmd_bad(*pmd)) {
+		printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
+		pmd_set(pmd, BAD_PAGETABLE);
+		return NULL;
+	}
+	return (pte_t *) pmd_page(*pmd) + address;
+}
+
+extern pmd_t *get_pointer_table (void);
+extern void free_pointer_table (pmd_t *);
+extern pmd_t *get_kpointer_table (void);
+extern void free_kpointer_table (pmd_t *);
+
+extern inline void pmd_free(pmd_t * pmd)
+{
+	free_pointer_table (pmd);
+}
+
+extern inline pmd_t * pmd_alloc(pgd_t * pgd, unsigned long address)
+{
+	address = (address >> PMD_SHIFT) & (PTRS_PER_PMD - 1);
+	if (pgd_none(*pgd)) {
+		pmd_t *page = get_pointer_table();
+		if (pgd_none(*pgd)) {
+			if (page) {
+				pgd_set(pgd, page);
+				return page + address;
+			}
+			pgd_set(pgd, (pmd_t *)BAD_PAGETABLE);
+			return NULL;
+		}
+		free_pointer_table(page);
+	}
+	if (pgd_bad(*pgd)) {
+		printk("Bad pgd in pmd_alloc: %08lx\n", pgd_val(*pgd));
+		pgd_set(pgd, (pmd_t *)BAD_PAGETABLE);
+		return NULL;
+	}
+	return (pmd_t *) pgd_page(*pgd) + address;
+}
+
+extern inline void pte_free_kernel(pte_t * pte)
+{
+	cache_page((unsigned long)pte);
+	free_page((unsigned long) pte);
+}
+
+extern inline pte_t * pte_alloc_kernel(pmd_t * pmd, unsigned long address)
+{
+	address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
+	if (pmd_none(*pmd)) {
+		pte_t * page = (pte_t *) get_free_page(GFP_KERNEL);
+		if (pmd_none(*pmd)) {
+			if (page) {
+				nocache_page((unsigned long)page);
+				pmd_set(pmd, page);
+				return page + address;
+			}
+			pmd_set(pmd, BAD_PAGETABLE);
+			return NULL;
+		}
+		free_page((unsigned long) page);
+	}
+	if (pmd_bad(*pmd)) {
+		printk("Bad pmd in pte_alloc_kernel: %08lx\n", pmd_val(*pmd));
+		pmd_set(pmd, BAD_PAGETABLE);
+		return NULL;
+	}
+	return (pte_t *) pmd_page(*pmd) + address;
+}
+
+extern inline void pmd_free_kernel(pmd_t * pmd)
+{
+	free_kpointer_table(pmd);
+}
+
+extern inline pmd_t * pmd_alloc_kernel(pgd_t * pgd, unsigned long address)
+{
+	address = (address >> PMD_SHIFT) & (PTRS_PER_PMD - 1);
+	if (pgd_none(*pgd)) {
+		pmd_t *page = get_kpointer_table();
+		if (pgd_none(*pgd)) {
+			if (page) {
+				pgd_set(pgd, page);
+				return page + address;
+			}
+			pgd_set(pgd, (pmd_t *)BAD_PAGETABLE);
+			return NULL;
+		}
+		free_kpointer_table(page);
+	}
+	if (pgd_bad(*pgd)) {
+		printk("Bad pgd in pmd_alloc_kernel: %08lx\n", pgd_val(*pgd));
+		pgd_set(pgd, (pmd_t *)BAD_PAGETABLE);
+		return NULL;
+	}
+	return (pmd_t *) pgd_page(*pgd) + address;
+}
+
+extern inline void pgd_free(pgd_t * pgd)
+{
+	free_pointer_table ((pmd_t *) pgd);
+}
+
+extern inline pgd_t * pgd_alloc(void)
+{
+	return (pgd_t *)get_pointer_table ();
+}
+
+#define flush_icache() \
+do { \
+	if (m68k_is040or060) \
+		asm (".word 0xf498"); /* CINVA I */ \
+	else \
+		asm ("movec %/cacr,%/d0;" \
+		     "oriw %0,%/d0;" \
+		     "movec %/d0,%/cacr" \
+		     : /* no outputs */ \
+		     : "i" (FLUSH_I) \
+		     : "d0"); \
+} while (0)
+
+/*
+ * invalidate the cache for the specified memory range.
+ * It starts at the physical address specified for
+ * the given number of bytes.
+ */
+extern void cache_clear (unsigned long paddr, int len);
+/*
+ * push any dirty cache in the specified memory range.
+ * It starts at the physical address specified for
+ * the given number of bytes.
+ */
+extern void cache_push (unsigned long paddr, int len);
+
+/*
+ * push and invalidate pages in the specified user virtual
+ * memory range.
+ */
+extern void cache_push_v (unsigned long vaddr, int len);
+
+#if 0
+#define flush_cache_all()		    do { \
+                   if (m68k_is040or060 >= 4) \
+                     __asm__ __volatile__ (".word 0xf478\n" ::); \
+                                            } while (0)
+#define flush_cache_mm(mm)		   flush_cache_all()
+#define flush_cache_range(mm, start, end)  flush_cache_all()
+#define flush_cache_page(vma, vmaddr)	   flush_cache_all()
+#define flush_page_to_ram(page)		   flush_cache_all()
+#else
+#define flush_cache_all()			do { } while (0)
+#define flush_cache_mm(mm)			do { } while (0)
+#define flush_cache_range(mm, start, end)	do { } while (0)
+#define flush_cache_page(vma, vmaddr)		do { } while (0)
+#define flush_page_to_ram(page)			do { } while (0)
+#endif
+
+/* cache code */
+#define FLUSH_I_AND_D	(0x00000808)
+#define FLUSH_I 	(0x00000008)
+
+/*
+ * Check if the addr/len goes up to the end of a physical
+ * memory chunk.  Used for DMA functions.
+ */
+int mm_end_of_chunk (unsigned long addr, int len);
+
+/*
+ * Map some physical address range into the kernel address space. The
+ * code is copied and adapted from map_chunk().
+ */
+extern unsigned long kernel_map(unsigned long paddr, unsigned long size,
+				int nocacheflag, unsigned long *memavailp );
+/*
+ * Change the cache mode of some kernel address range.
+ */
+extern void kernel_set_cachemode( unsigned long address, unsigned long size,
+				  unsigned cmode );
+
+/* Values for nocacheflag and cmode */
+#define	KERNELMAP_FULL_CACHING		0
+#define	KERNELMAP_NOCACHE_SER		1
+#define	KERNELMAP_NOCACHE_NONSER	2
+#define	KERNELMAP_NO_COPYBACK		3
+
+/*
+ * The m68k doesn't have any external MMU info: the kernel page
+ * tables contain all the necessary information.
+ */
+extern inline void update_mmu_cache(struct vm_area_struct * vma,
+	unsigned long address, pte_t pte)
+{
+}
+
+#define SWP_TYPE(entry)  (((entry) >> 2) & 0x7f)
+#define SWP_OFFSET(entry) ((entry) >> 9)
+#define SWP_ENTRY(type,offset) (((type) << 2) | ((offset) << 9))
+
+#endif /* _M68K_PGTABLE_H */
diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/posix_types.h linux/include/asm-m68k/posix_types.h
--- v1.3.93/linux/include/asm-m68k/posix_types.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-m68k/posix_types.h	Fri Apr  5 14:08:18 1996
@@ -0,0 +1,42 @@
+#ifndef __ARCH_I386_POSIX_TYPES_H
+#define __ARCH_I386_POSIX_TYPES_H
+
+/*
+ * This file is generally used by user-level software, so you need to
+ * be a little careful about namespace pollution etc.  Also, we cannot
+ * assume GCC is being used.
+ */
+
+typedef unsigned short	__kernel_dev_t;
+typedef unsigned long	__kernel_ino_t;
+typedef unsigned short	__kernel_mode_t;
+typedef unsigned short	__kernel_nlink_t;
+typedef long		__kernel_off_t;
+typedef int		__kernel_pid_t;
+typedef unsigned short	__kernel_uid_t;
+typedef unsigned short	__kernel_gid_t;
+typedef unsigned int	__kernel_size_t;
+typedef int		__kernel_ssize_t;
+typedef int		__kernel_ptrdiff_t;
+typedef long		__kernel_time_t;
+typedef long		__kernel_clock_t;
+typedef int		__kernel_daddr_t;
+typedef char *		__kernel_caddr_t;
+
+#ifdef __GNUC__
+typedef long long	__kernel_loff_t;
+#endif
+
+#undef	__FD_SET
+#define	__FD_SET(d, set)	((set)->fds_bits[__FDELT(d)] |= __FDMASK(d))
+
+#undef	__FD_CLR
+#define	__FD_CLR(d, set)	((set)->fds_bits[__FDELT(d)] &= ~__FDMASK(d))
+
+#undef	__FD_ISSET
+#define	__FD_ISSET(d, set)	((set)->fds_bits[__FDELT(d)] & __FDMASK(d))
+
+#undef	__FD_ZERO
+#define __FD_ZERO(fdsetp) (memset (fdsetp, 0, sizeof(*(fd_set *)fdsetp)))
+
+#endif
diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/processor.h linux/include/asm-m68k/processor.h
--- v1.3.93/linux/include/asm-m68k/processor.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-m68k/processor.h	Sun Mar 24 12:21:16 1996
@@ -0,0 +1,92 @@
+/*
+ * include/asm-m68k/processor.h
+ *
+ * Copyright (C) 1995 Hamish Macdonald
+ */
+
+#ifndef __ASM_M68K_PROCESSOR_H
+#define __ASM_M68K_PROCESSOR_H
+
+#include <asm/segment.h>
+
+/*
+ * User space process size: 3.75GB. This is hardcoded into a few places,
+ * so don't change it unless you know what you are doing.
+ */
+#define TASK_SIZE	(0xF0000000UL)
+
+/*
+ * Bus types
+ */
+#define EISA_bus__is_a_macro	1
+#define EISA_bus 0
+#define MCA_bus__is_a_macro	1
+#define MCA_bus 0
+
+/*
+ * The m68k has no problems with write protection
+ */
+#define wp_works_ok__is_a_macro	1
+#define wp_works_ok 1
+
+/* MAX floating point unit state size (FSAVE/FRESTORE) */
+#define FPSTATESIZE   (216/sizeof(unsigned short))
+
+/* 
+ * if you change this structure, you must change the code and offsets
+ * in m68k/machasm.S
+ */
+   
+struct thread_struct {
+	unsigned long  ksp;		/* kernel stack pointer */
+	unsigned long  usp;		/* user stack pointer */
+	unsigned short sr;		/* saved status register */
+	unsigned short fs;		/* saved fs (sfc, dfc) */
+	unsigned long  *pagedir_v;	/* root page table virtual addr */
+	unsigned long  pagedir_p;	/* root page table physaddr */
+	unsigned long  crp[2];		/* cpu root pointer */
+	unsigned long  esp0;		/* points to SR of stack frame */
+	unsigned long  fp[8*3];
+	unsigned long  fpcntl[3];	/* fp control regs */
+	unsigned short fpstate[FPSTATESIZE];  /* floating point state */
+};
+
+#define INIT_MMAP { &init_mm, 0, 0x40000000, __pgprot(_PAGE_PRESENT|_PAGE_ACCESSED), VM_READ | VM_WRITE | VM_EXEC }
+
+#define INIT_TSS  { \
+	sizeof(init_kernel_stack) + (long) init_kernel_stack, 0, \
+	PS_S, KERNEL_DS, \
+	NULL, 0, {0, 0}, 0 \
+}
+
+#define alloc_kernel_stack()    get_free_page(GFP_KERNEL)
+#define free_kernel_stack(page) free_page((page))
+
+/*
+ * Do necessary setup to start up a newly executed thread.
+ */
+static inline void start_thread(struct pt_regs * regs, unsigned long pc,
+				unsigned long usp)
+{
+	unsigned long nilstate = 0;
+
+	/* clear floating point state */
+	__asm__ __volatile__ ("frestore %0@" : : "a" (&nilstate));
+
+	/* reads from user space */
+	set_fs(USER_DS);
+
+	regs->pc = pc;
+	regs->sr &= ~0x2000;
+	wrusp(usp);
+}
+
+/*
+ * Return saved PC of a blocked thread.
+ */
+extern inline unsigned long thread_saved_pc(struct thread_struct *t)
+{
+	return ((unsigned long *)((struct switch_stack *)t->ksp)->a6)[1];
+}
+
+#endif
diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/ptrace.h linux/include/asm-m68k/ptrace.h
--- v1.3.93/linux/include/asm-m68k/ptrace.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-m68k/ptrace.h	Wed Mar 20 22:03:24 1996
@@ -0,0 +1,73 @@
+#ifndef _M68K_PTRACE_H
+#define _M68K_PTRACE_H
+
+#define PT_D1	   0
+#define PT_D2	   1
+#define PT_D3	   2
+#define PT_D4	   3
+#define PT_D5	   4
+#define PT_D6	   5
+#define PT_D7	   6
+#define PT_A0	   7
+#define PT_A1	   8
+#define PT_A2	   9
+#define PT_A3	   10
+#define PT_A4	   11
+#define PT_A5	   12
+#define PT_A6	   13
+#define PT_D0	   14
+#define PT_USP	   15
+#define PT_ORIG_D0 16
+#define PT_SR	   17
+#define PT_PC	   18
+
+#ifndef __ASSEMBLY__
+
+/* this struct defines the way the registers are stored on the
+   stack during a system call. */
+
+struct pt_regs {
+  long     d1;
+  long     d2;
+  long     d3;
+  long     d4;
+  long     d5;
+  long     a0;
+  long     a1;
+  long     d0;
+  long     orig_d0;
+  long     stkadj;
+  unsigned short sr;
+  unsigned long  pc;
+  unsigned format :  4; /* frame format specifier */
+  unsigned vector : 12; /* vector offset */
+};
+
+/*
+ * This is the extended stack used by signal handlers and the context
+ * switcher: it's pushed after the normal "struct pt_regs".
+ */
+struct switch_stack {
+	unsigned long  d6;
+	unsigned long  d7;
+	unsigned long  a2;
+	unsigned long  a3;
+	unsigned long  a4;
+	unsigned long  a5;
+	unsigned long  a6;
+	unsigned long  retpc;
+};
+
+#ifdef __KERNEL__
+
+#ifndef PS_S
+#define PS_S  (0x2000)
+#define PS_M  (0x1000)
+#endif
+
+#define user_mode(regs) (!((regs)->sr & PS_S))
+#define instruction_pointer(regs) ((regs)->pc)
+extern void show_regs(struct pt_regs *);
+#endif /* __KERNEL__ */
+#endif /* __ASSEMBLY__ */
+#endif /* _M68K_PTRACE_H */
diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/resource.h linux/include/asm-m68k/resource.h
--- v1.3.93/linux/include/asm-m68k/resource.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-m68k/resource.h	Sat Mar 23 14:56:25 1996
@@ -0,0 +1,37 @@
+#ifndef _M68K_RESOURCE_H
+#define _M68K_RESOURCE_H
+
+/*
+ * Resource limits
+ */
+
+#define RLIMIT_CPU	0		/* CPU time in ms */
+#define RLIMIT_FSIZE	1		/* Maximum filesize */
+#define RLIMIT_DATA	2		/* max data size */
+#define RLIMIT_STACK	3		/* max stack size */
+#define RLIMIT_CORE	4		/* max core file size */
+#define RLIMIT_RSS	5		/* max resident set size */
+#define RLIMIT_NPROC	6		/* max number of processes */
+#define RLIMIT_NOFILE	7		/* max number of open files */
+#define RLIMIT_MEMLOCK	8		/* max locked-in-memory address space*/
+
+#define RLIM_NLIMITS	9
+
+#ifdef __KERNEL__
+
+#define INIT_RLIMITS	\
+{                       \
+  {LONG_MAX, LONG_MAX}, \
+  {LONG_MAX, LONG_MAX}, \
+  {LONG_MAX, LONG_MAX}, \
+  {_STK_LIM, _STK_LIM}, \
+  {       0, LONG_MAX}, \
+  {LONG_MAX, LONG_MAX}, \
+  {MAX_TASKS_PER_USER, MAX_TASKS_PER_USER}, \
+  {NR_OPEN, NR_OPEN},   \
+  {LONG_MAX, LONG_MAX}  \
+}
+
+#endif /* __KERNEL__ */
+
+#endif /* _M68K_RESOURCE_H */
diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/segment.h linux/include/asm-m68k/segment.h
--- v1.3.93/linux/include/asm-m68k/segment.h	Tue Nov 29 22:08:54 1994
+++ linux/include/asm-m68k/segment.h	Sat Apr 13 14:31:08 1996
@@ -1,197 +1,326 @@
+#ifndef _M68K_SEGMENT_H
+#define _M68K_SEGMENT_H
+
+/* define constants */
+/* Address spaces (FC0-FC2) */
+#define USER_DATA     (1)
+#ifndef USER_DS
+#define USER_DS       (USER_DATA)
+#endif
+#define USER_PROGRAM  (2)
+#define SUPER_DATA    (5)
+#ifndef KERNEL_DS
+#define KERNEL_DS     (SUPER_DATA)
+#endif
+#define SUPER_PROGRAM (6)
+#define CPU_SPACE     (7)
+
+#ifndef __ASSEMBLY__
+
 /*
- *  linux/include/asm-m68k/segment.h
- *
- *  Copyright (C) 1991, 1992  Linus Torvalds
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file README.legal in the main directory of this archive
- * for more details.
+ * Uh, these should become the main single-value transfer routines..
+ * They automatically use the right size if we just have the right
+ * pointer type..
  */
+#define put_user(x,ptr) __put_user((unsigned long)(x),(ptr),sizeof(*(ptr)))
+#define get_user(ptr) ((__typeof__(*(ptr)))__get_user((ptr),sizeof(*(ptr))))
 
 /*
- * 680x0 support added by Hamish Macdonald
+ * This is a silly but good way to make sure that
+ * the __put_user function is indeed always optimized,
+ * and that we use the correct sizes..
  */
+extern int bad_user_access_length(void);
 
-#ifndef _M68K_SEGMENT_H
-#define _M68K_SEGMENT_H
+#define __ptr(x) ((unsigned long *)(x))
 
-static inline unsigned char get_user_byte(const char * addr)
+static inline void __put_user(unsigned long x, void * y, int size)
 {
-	register unsigned char _v;
-
-	__asm__ __volatile__ ("movesb %1,%0":"=r" (_v):"m" (*addr));
-	return _v;
+	switch (size) {
+		case 1:
+			__asm__ ("movesb %0,%1"
+				: /* no outputs */
+				:"r" (x),"m" (*__ptr(y)) : "memory");
+			break;
+		case 2:
+			__asm__ ("movesw %0,%1"
+				: /* no outputs */
+				:"r" (x),"m" (*__ptr(y)) : "memory");
+			break;
+		case 4:
+			__asm__ ("movesl %0,%1"
+				: /* no outputs */
+				:"r" (x),"m" (*__ptr(y)) : "memory");
+			break;
+		default:
+			bad_user_access_length();
+	}
 }
 
-#define get_fs_byte(addr) get_user_byte((char *)(addr))
-
-static inline unsigned short get_user_word(const short *addr)
+static inline unsigned long __get_user(const void * y, int size)
 {
-	unsigned short _v;
+	unsigned long result;
 
-	__asm__ __volatile__ ("movesw %1,%0":"=r" (_v):"m" (*addr));
-	return _v;
+	switch (size) {
+		case 1:
+			__asm__ ("movesb %1,%0"
+				 :"=r" (result)
+				 :"m" (*__ptr(y)));
+			return (unsigned char) result;
+		case 2:
+			__asm__ ("movesw %1,%0"
+				 :"=r" (result)
+				 :"m" (*__ptr(y)));
+			return (unsigned short) result;
+		case 4:
+			__asm__ ("movesl %1,%0"
+				 :"=r" (result)
+				 :"m" (*__ptr(y)));
+			return result;
+		default:
+			return bad_user_access_length();
+	}
 }
+#undef __ptr
 
-#define get_fs_word(addr) get_user_word((short *)(addr))
+/*
+ * These are deprecated..
+ *
+ * Use "put_user()" and "get_user()" with the proper pointer types instead.
+ */
 
-static inline unsigned long get_user_long(const int *addr)
+#define get_fs_byte(addr) __get_user((const unsigned char *)(addr),1)
+#define get_fs_word(addr) __get_user((const unsigned short *)(addr),2)
+#define get_fs_long(addr) __get_user((const unsigned int *)(addr),4)
+
+#define put_fs_byte(x,addr) __put_user((x),(unsigned char *)(addr),1)
+#define put_fs_word(x,addr) __put_user((x),(unsigned short *)(addr),2)
+#define put_fs_long(x,addr) __put_user((x),(unsigned int *)(addr),4)
+
+#ifdef WE_REALLY_WANT_TO_USE_A_BROKEN_INTERFACE
+
+static inline unsigned char get_user_byte(const char * addr)
 {
-	unsigned long _v;
+	return __get_user(addr,1);
+}
 
-	__asm__ __volatile__ ("movesl %1,%0":"=r" (_v):"m" (*addr)); \
-	return _v;
+static inline unsigned short get_user_word(const short *addr)
+{
+	return __get_user(addr,2);
 }
 
-#define get_fs_long(addr) get_user_long((int *)(addr))
+static inline unsigned long get_user_long(const int *addr)
+{
+	return __get_user(addr,4);
+}
 
 static inline void put_user_byte(char val,char *addr)
 {
-	__asm__ __volatile__ ("movesb %0,%1": /* no outputs */ :"r" (val),"m" (*addr) : "memory");
+	__put_user(val, addr, 1);
 }
 
-#define put_fs_byte(x,addr) put_user_byte((x),(char *)(addr))
-
 static inline void put_user_word(short val,short * addr)
 {
-	__asm__ __volatile__ ("movesw %0,%1": /* no outputs */ :"r" (val),"m" (*addr) : "memory");
+	__put_user(val, addr, 2);
 }
 
-#define put_fs_word(x,addr) put_user_word((x),(short *)(addr))
-
 static inline void put_user_long(unsigned long val,int * addr)
 {
-	__asm__ __volatile__ ("movesl %0,%1": /* no outputs */ :"r" (val),"m" (*addr) : "memory");
+	__put_user(val, addr, 4);
 }
 
-#define put_fs_long(x,addr) put_user_long((x),(int *)(addr))
+#endif
 
 static inline void __generic_memcpy_tofs(void * to, const void * from, unsigned long n)
 {
+	unsigned long tmp;
 	if (n == 0) return;
-	__asm__ __volatile__ ("1:\n\t"
-			      "moveb %1@+,d0\n\t"
-			      "movesb d0,%2@+\n\t"
+	tmp = n;
+	n >>= 2;
+	if (n != 0)
+		__asm__ ("1:\t"
+			 "movel %1@+,%/d0\n\t"
+			 "movesl %/d0,%2@+\n\t"
 			      "dbra %0,1b\n\t"
 			      "clrw %0\n\t"
 			      "subql #1,%0\n\t"
-			      "bccs 1b"
+			 "bccs 1b\n\t"
 			      : "=d" (n), "=a" (from), "=a" (to)
-			      : "1" (from), "2" (to), "0" (n-1)
+			 : "0" (n-1), "1" (from), "2" (to)
+			 : "d0", "memory");
+	if (tmp & 2)
+		__asm__ ("movew %0@+,%/d0\n\t"
+			 "movesw %/d0,%1@+\n\t"
+			 : "=a" (from), "=a" (to)
+			 : "0" (from), "1" (to)
+			 : "d0", "memory");
+	if (tmp & 1)
+		__asm__ ("moveb %0@,%/d0\n\t"
+			 "movesb %/d0,%1@\n\t"
+			 : /* no outputs */
+			 : "a" (from), "a" (to)
 			      : "d0", "memory");
 }
 
 static inline void __constant_memcpy_tofs(void * to, const void * from, unsigned long n)
 {
-	if (n == 0) {
-			return;
-	} else if (n == 1) {
-			put_user_byte(*(const char *) from, (char *) to);
-			return;
-	} else if (n == 2) {
-			put_user_word(*(const short *) from, (short *) to);
-			return;
-	} else if (n == 3) {
-			put_user_word(*(const short *) from, (short *) to);
-			put_user_byte(*(2+(const char *) from), 2+(char *) to);
-			return;
-	} else if (n == 4) {
-			put_user_long(*(const int *) from, (int *) to);
-			return;
-	}
-#if 0
-#define COMMON(x) \
-__asm__("cld\n\t" \
-	"push %%es\n\t" \
-	"push %%fs\n\t" \
-	"pop %%es\n\t" \
-	"rep ; movsl\n\t" \
-	x \
-	"pop %%es" \
-	: /* no outputs */ \
-	:"c" (n/4),"D" ((long) to),"S" ((long) from) \
-	:"cx","di","si")
-
-	switch (n % 4) {
+	switch (n) {
 		case 0:
-			COMMON("");
 			return;
 		case 1:
-			COMMON("movsb\n\t");
+			__put_user(*(const char *) from, (char *) to, 1);
 			return;
 		case 2:
-			COMMON("movsw\n\t");
+			__put_user(*(const short *) from, (short *) to, 2);
 			return;
 		case 3:
-			COMMON("movsw\n\tmovsb\n\t");
+			__put_user(*(const short *) from, (short *) to, 2);
+			__put_user(*(2+(const char *) from), 2+(char *) to, 1);
+			return;
+		case 4:
+			__put_user(*(const int *) from, (int *) to, 4);
+			return;
+		case 8:
+			__put_user(*(const int *) from, (int *) to, 4);
+			__put_user(*(1+(const int *) from), 1+(int *) to, 4);
+			return;
+		case 12:
+			__put_user(*(const int *) from, (int *) to, 4);
+			__put_user(*(1+(const int *) from), 1+(int *) to, 4);
+			__put_user(*(2+(const int *) from), 2+(int *) to, 4);
+			return;
+		case 16:
+			__put_user(*(const int *) from, (int *) to, 4);
+			__put_user(*(1+(const int *) from), 1+(int *) to, 4);
+			__put_user(*(2+(const int *) from), 2+(int *) to, 4);
+			__put_user(*(3+(const int *) from), 3+(int *) to, 4);
 			return;
 	}
+#define COMMON(x)                     \
+__asm__ __volatile__ ("1:\n\t"        \
+            "movel %1@+,%/d0\n\t"     \
+            "movesl %/d0,%2@+\n\t"    \
+            "dbra %0,1b\n\t"          \
+            "clrw %0\n\t"             \
+            "subql #1,%0\n\t"         \
+            "bccs 1b\n\t"             \
+            x                     \
+            : "=d" (n), "=a" (from), "=a" (to)    \
+            : "1" (from), "2" (to), "0" (n/4-1)   \
+            : "d0", "memory");
+
+  switch (n % 4) {
+      case 0:
+          COMMON("");
+          return;
+      case 1:
+          COMMON("moveb %1@+,%/d0; movesb %/d0,%2@+");
+          return;
+      case 2:
+          COMMON("movew %1@+,%/d0; movesw %/d0,%2@+");
+          return;
+      case 3:
+          COMMON("movew %1@+,%/d0; movesw %/d0,%2@+\n\t"
+                 "moveb %1@+,%/d0; movesb %/d0,%2@+");
+          return;
+  }
 #undef COMMON
-#else
-        __generic_memcpy_tofs(to,from,n);
-#endif
 }
 
 static inline void __generic_memcpy_fromfs(void * to, const void * from, unsigned long n)
 {
+	unsigned long tmp;
 	if (n == 0) return;
-	__asm__ __volatile__ ("1:\n\t"
-			      "movesb %1@+,d0\n\t"
-			      "moveb d0,%2@+\n\t"
+	tmp = n;
+	n >>= 2;
+	if (n != 0)
+		__asm__ ("1:\t"
+			 "movesl %1@+,%/d0\n\t"
+			 "movel %/d0,%2@+\n\t"
 			      "dbra %0,1b\n\t"
 			      "clrw %0\n\t"
 			      "subql #1,%0\n\t"
-			      "bccs 1b"
+			 "bccs 1b\n\t"
 			      : "=d" (n), "=a" (from), "=a" (to)
-			      : "1" (from), "2" (to), "0" (n-1)
+			 : "0" (n-1), "1" (from), "2" (to)
+			 : "d0", "memory");
+	if (tmp & 2)
+		__asm__ ("movesw %0@+,%/d0\n\t"
+			 "movew %/d0,%1@+\n\t"
+			 : "=a" (from), "=a" (to)
+			 : "0" (from), "1" (to)
+			 : "d0", "memory");
+	if (tmp & 1)
+		__asm__ ("movesb %0@,%/d0\n\t"
+			 "moveb %/d0,%1@\n\t"
+			 : /* no outputs */
+			 : "a" (from), "a" (to)
 			      : "d0", "memory");
 }
 
 static inline void __constant_memcpy_fromfs(void * to, const void * from, unsigned long n)
 {
-	if (n == 0) {
-			return;
-	} else if (n == 1) {
-			*(char *)to = get_user_byte((const char *) from);
-			return;
-	} else if (n == 2) {
-			*(short *)to = get_user_word((const short *) from);
-			return;
-	} else if (n == 3) {
-			*(short *) to = get_user_word((const short *) from);
-			*(2+(char *) to) = get_user_byte(2+(const char *) from);
-			return;
-	} else if (n == 4) {
-			*(int *) to = get_user_long((const int *) from);
-			return;
-	}
-#if 0
-#define COMMON(x) \
-__asm__("cld\n\t" \
-	"rep ; fs ; movsl\n\t" \
-	x \
-	: /* no outputs */ \
-	:"c" (n/4),"D" ((long) to),"S" ((long) from) \
-	:"cx","di","si","memory")
-
-	switch (n % 4) {
+	switch (n) {
 		case 0:
-			COMMON("");
 			return;
 		case 1:
-			COMMON("fs ; movsb");
+			*(char *)to = __get_user((const char *) from, 1);
 			return;
 		case 2:
-			COMMON("fs ; movsw");
+			*(short *)to = __get_user((const short *) from, 2);
 			return;
 		case 3:
-			COMMON("fs ; movsw\n\tfs ; movsb");
+			*(short *) to = __get_user((const short *) from, 2);
+			*((char *) to + 2) = __get_user(2+(const char *) from, 1);
+			return;
+		case 4:
+			*(int *) to = __get_user((const int *) from, 4);
+			return;
+		case 8:
+			*(int *) to = __get_user((const int *) from, 4);
+			*(1+(int *) to) = __get_user(1+(const int *) from, 4);
+			return;
+		case 12:
+			*(int *) to = __get_user((const int *) from, 4);
+			*(1+(int *) to) = __get_user(1+(const int *) from, 4);
+			*(2+(int *) to) = __get_user(2+(const int *) from, 4);
+			return;
+		case 16:
+			*(int *) to = __get_user((const int *) from, 4);
+			*(1+(int *) to) = __get_user(1+(const int *) from, 4);
+			*(2+(int *) to) = __get_user(2+(const int *) from, 4);
+			*(3+(int *) to) = __get_user(3+(const int *) from, 4);
 			return;
 	}
+#define COMMON(x)                     \
+__asm__ __volatile__ ("1:\n\t"        \
+            "movesl %1@+,%/d0\n\t"    \
+            "movel %/d0,%2@+\n\t"     \
+            "dbra %0,1b\n\t"          \
+            "clrw %0\n\t"             \
+            "subql #1,%0\n\t"         \
+            "bccs 1b\n\t"             \
+            x                         \
+            : "=d" (n), "=a" (from), "=a" (to)    \
+            : "1" (from), "2" (to), "0" (n/4-1)   \
+            : "d0", "memory");
+
+  switch (n % 4) {
+      case 0:
+          COMMON("");
+          return;
+      case 1:
+          COMMON("movesb %1@+,%/d0; moveb %/d0,%2@+");
+          return;
+      case 2:
+          COMMON("movesw %1@+,%/d0; movew %/d0,%2@+");
+          return;
+      case 3:
+          COMMON("movesw %1@+,%/d0; movew %/d0,%2@+\n\t"
+                 "movesb %1@+,%/d0; moveb %/d0,%2@+");
+          return;
+  }
 #undef COMMON
-#else
-        __generic_memcpy_fromfs(to,from,n);
-#endif
 }
 
 #define memcpy_fromfs(to, from, n) \
@@ -211,7 +340,7 @@
 static inline unsigned long get_fs(void)
 {
 	unsigned long _v;
-	__asm__ ("movec dfc,%0":"=r" (_v):);
+	__asm__ ("movec %/dfc,%0":"=r" (_v):);
 
 	return _v;
 }
@@ -219,23 +348,16 @@
 static inline unsigned long get_ds(void)
 {
     /* return the supervisor data space code */
-    return 0x5;
+    return KERNEL_DS;
 }
 
 static inline void set_fs(unsigned long val)
 {
-	__asm__ __volatile__ ("movec %0,sfc\n\t"
-			      "movec %0,dfc\n\t"
-			      : /* no outputs */ : "r" (val), "r" (val) : "memory");
+	__asm__ __volatile__ ("movec %0,%/sfc\n\t"
+			      "movec %0,%/dfc\n\t"
+			      : /* no outputs */ : "r" (val) : "memory");
 }
 
-/* define constants */
-/* Address spaces (FC0-FC2) */
-#ifndef USER_DS
-#define USER_DS       (1)
-#endif
-#ifndef KERNEL_DS
-#define KERNEL_DS     (5)
-#endif
+#endif /* __ASSEMBLY__ */
 
 #endif /* _M68K_SEGMENT_H */
diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/shm.h linux/include/asm-m68k/shm.h
--- v1.3.93/linux/include/asm-m68k/shm.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-m68k/shm.h	Wed Dec 27 22:47:22 1995
@@ -0,0 +1,24 @@
+#ifndef _M68K_SHM_H
+#define _M68K_SHM_H
+
+/* format of page table entries that correspond to shared memory pages
+   currently out in swap space (see also mm/swap.c):
+   bits 0-1 (PAGE_PRESENT) is  = 0
+   bits 8..2 (SWP_TYPE) are = SHM_SWP_TYPE
+   bits 31..9 are used like this:
+   bits 15..9 (SHM_ID) the id of the shared memory segment
+   bits 30..16 (SHM_IDX) the index of the page within the shared memory segment
+                    (actually only bits 25..16 get used since SHMMAX is so low)
+   bit 31 (SHM_READ_ONLY) flag whether the page belongs to a read-only attach
+*/
+/* on the m68k both bits 0 and 1 must be zero */
+
+#define SHM_ID_SHIFT	9
+#define _SHM_ID_BITS	7
+#define SHM_ID_MASK	((1<<_SHM_ID_BITS)-1)
+
+#define SHM_IDX_SHIFT	(SHM_ID_SHIFT+_SHM_ID_BITS)
+#define _SHM_IDX_BITS	15
+#define SHM_IDX_MASK	((1<<_SHM_IDX_BITS)-1)
+
+#endif /* _M68K_SHM_H */
diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/shmparam.h linux/include/asm-m68k/shmparam.h
--- v1.3.93/linux/include/asm-m68k/shmparam.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-m68k/shmparam.h	Sat Mar 30 14:11:42 1996
@@ -0,0 +1,44 @@
+#ifndef _M68K_SHMPARAM_H
+#define _M68K_SHMPARAM_H
+
+/* address range for shared memory attaches if no address passed to shmat() */
+#define SHM_RANGE_START	0xC0000000
+#define SHM_RANGE_END	0xD0000000
+
+/*
+ * Format of a swap-entry for shared memory pages currently out in
+ * swap space (see also mm/swap.c).
+ *
+ * SWP_TYPE = SHM_SWP_TYPE
+ * SWP_OFFSET is used as follows:
+ *
+ *  bits 0..6 : id of shared memory segment page belongs to (SHM_ID)
+ *  bits 7..21: index of page within shared memory segment (SHM_IDX)
+ *		(actually fewer bits get used since SHMMAX is so low)
+ */
+
+/*
+ * Keep _SHM_ID_BITS as low as possible since SHMMNI depends on it and
+ * there is a static array of size SHMMNI.
+ */
+#define _SHM_ID_BITS	7
+#define SHM_ID_MASK	((1<<_SHM_ID_BITS)-1)
+
+#define SHM_IDX_SHIFT	(_SHM_ID_BITS)
+#define _SHM_IDX_BITS	15
+#define SHM_IDX_MASK	((1<<_SHM_IDX_BITS)-1)
+
+/*
+ * _SHM_ID_BITS + _SHM_IDX_BITS must be <= 24 on the i386 and
+ * SHMMAX <= (PAGE_SIZE << _SHM_IDX_BITS).
+ */
+
+#define SHMMAX 0x1000000		/* max shared seg size (bytes) */
+#define SHMMIN 1 /* really PAGE_SIZE */	/* min shared seg size (bytes) */
+#define SHMMNI (1<<_SHM_ID_BITS)	/* max num of segs system wide */
+#define SHMALL				/* max shm system wide (pages) */ \
+	(1<<(_SHM_IDX_BITS+_SHM_ID_BITS))
+#define	SHMLBA PAGE_SIZE		/* attach addr a multiple of this */
+#define SHMSEG SHMMNI			/* max shared segs per process */
+
+#endif /* _M68K_SHMPARAM_H */
diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/sigcontext.h linux/include/asm-m68k/sigcontext.h
--- v1.3.93/linux/include/asm-m68k/sigcontext.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-m68k/sigcontext.h	Thu Mar  7 20:28:49 1996
@@ -0,0 +1,19 @@
+#ifndef _ASMm68k_SIGCONTEXT_H
+#define _ASMm68k_SIGCONTEXT_H
+
+struct sigcontext_struct {
+	unsigned long  sc_mask; 	/* old sigmask */
+	unsigned long  sc_usp;		/* old user stack pointer */
+	unsigned long  sc_d0;
+	unsigned long  sc_d1;
+	unsigned long  sc_a0;
+	unsigned long  sc_a1;
+	unsigned short sc_sr;
+	unsigned long  sc_pc;
+	unsigned short sc_formatvec;
+	unsigned long  sc_fpregs[2*3];  /* room for two fp registers */
+	unsigned long  sc_fpcntl[3];
+	unsigned char  sc_fpstate[216];
+};
+
+#endif
diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/signal.h linux/include/asm-m68k/signal.h
--- v1.3.93/linux/include/asm-m68k/signal.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-m68k/signal.h	Tue Apr  9 00:36:14 1996
@@ -0,0 +1,96 @@
+#ifndef _M68K_SIGNAL_H
+#define _M68K_SIGNAL_H
+
+typedef unsigned long sigset_t;		/* at least 32 bits */
+
+#define _NSIG             32
+#define NSIG		_NSIG
+
+#define SIGHUP		 1
+#define SIGINT		 2
+#define SIGQUIT		 3
+#define SIGILL		 4
+#define SIGTRAP		 5
+#define SIGABRT		 6
+#define SIGIOT		 6
+#define SIGBUS		 7
+#define SIGFPE		 8
+#define SIGKILL		 9
+#define SIGUSR1		10
+#define SIGSEGV		11
+#define SIGUSR2		12
+#define SIGPIPE		13
+#define SIGALRM		14
+#define SIGTERM		15
+#define SIGSTKFLT	16
+#define SIGCHLD		17
+#define SIGCONT		18
+#define SIGSTOP		19
+#define SIGTSTP		20
+#define SIGTTIN		21
+#define SIGTTOU		22
+#define SIGURG		23
+#define SIGXCPU		24
+#define SIGXFSZ		25
+#define SIGVTALRM	26
+#define SIGPROF		27
+#define SIGWINCH	28
+#define SIGIO		29
+#define SIGPOLL		SIGIO
+/*
+#define SIGLOST		29
+*/
+#define SIGPWR		30
+#define	SIGUNUSED	31
+
+/*
+ * 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
+ * the sigaction structure as a stack pointer. This is now possible due to
+ * the changes in signal handling. LBT 010493.
+ * SA_INTERRUPT is a no-op, but left due to historical reasons. Use the
+ * SA_RESTART flag to get restarting signals (which were the default long ago)
+ * SA_SHIRQ flag is for shared interrupt support on PCI and EISA.
+ */
+#define SA_NOCLDSTOP	1
+#define SA_SHIRQ	0x04000000
+#define SA_STACK	0x08000000
+#define SA_RESTART	0x10000000
+#define SA_INTERRUPT	0x20000000
+#define SA_NOMASK	0x40000000
+#define SA_ONESHOT	0x80000000
+
+#ifdef __KERNEL__
+/*
+ * These values of sa_flags are used only by the kernel as part of the
+ * irq handling routines.
+ *
+ * SA_INTERRUPT is also used by the irq handling routines.
+ */
+#define SA_PROBE SA_ONESHOT
+#define SA_SAMPLE_RANDOM SA_RESTART
+#endif
+
+#define SIG_BLOCK          0	/* for blocking signals */
+#define SIG_UNBLOCK        1	/* for unblocking signals */
+#define SIG_SETMASK        2	/* for setting the signal mask */
+
+/* Type of a signal handler.  */
+typedef void (*__sighandler_t)(int);
+
+#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 */
+
+struct sigaction {
+	__sighandler_t sa_handler;
+	sigset_t sa_mask;
+	unsigned long sa_flags;
+	void (*sa_restorer)(void);
+};
+
+#ifdef __KERNEL__
+#include <asm/sigcontext.h>
+#endif
+
+#endif /* _M68K_SIGNAL_H */
diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/socket.h linux/include/asm-m68k/socket.h
--- v1.3.93/linux/include/asm-m68k/socket.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-m68k/socket.h	Fri Apr  5 14:08:26 1996
@@ -0,0 +1,25 @@
+#ifndef _ASM_SOCKET_H
+#define _ASM_SOCKET_H
+
+#include <asm/sockios.h>
+
+/* For setsockoptions(2) */
+#define SOL_SOCKET	1
+
+#define SO_DEBUG	1
+#define SO_REUSEADDR	2
+#define SO_TYPE		3
+#define SO_ERROR	4
+#define SO_DONTROUTE	5
+#define SO_BROADCAST	6
+#define SO_SNDBUF	7
+#define SO_RCVBUF	8
+#define SO_KEEPALIVE	9
+#define SO_OOBINLINE	10
+#define SO_NO_CHECK	11
+#define SO_PRIORITY	12
+#define SO_LINGER	13
+#define SO_BSDCOMPAT	14
+/* To add :#define SO_REUSEPORT 15 */
+
+#endif /* _ASM_SOCKET_H */
diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/sockios.h linux/include/asm-m68k/sockios.h
--- v1.3.93/linux/include/asm-m68k/sockios.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-m68k/sockios.h	Fri Apr  5 14:08:30 1996
@@ -0,0 +1,12 @@
+#ifndef __ARCH_M68K_SOCKIOS__
+#define __ARCH_M68K_SOCKIOS__
+
+/* Socket-level I/O control calls. */
+#define FIOSETOWN 	0x8901
+#define SIOCSPGRP	0x8902
+#define FIOGETOWN	0x8903
+#define SIOCGPGRP	0x8904
+#define SIOCATMARK	0x8905
+#define SIOCGSTAMP	0x8906		/* Get stamp */
+
+#endif /* __ARCH_M68K_SOCKIOS__ */
diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/stat.h linux/include/asm-m68k/stat.h
--- v1.3.93/linux/include/asm-m68k/stat.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-m68k/stat.h	Wed Dec 27 22:47:26 1995
@@ -0,0 +1,41 @@
+#ifndef _M68K_STAT_H
+#define _M68K_STAT_H
+
+struct old_stat {
+	unsigned short st_dev;
+	unsigned short st_ino;
+	unsigned short st_mode;
+	unsigned short st_nlink;
+	unsigned short st_uid;
+	unsigned short st_gid;
+	unsigned short st_rdev;
+	unsigned long  st_size;
+	unsigned long  st_atime;
+	unsigned long  st_mtime;
+	unsigned long  st_ctime;
+};
+
+struct new_stat {
+	unsigned short st_dev;
+	unsigned short __pad1;
+	unsigned long st_ino;
+	unsigned short st_mode;
+	unsigned short st_nlink;
+	unsigned short st_uid;
+	unsigned short st_gid;
+	unsigned short st_rdev;
+	unsigned short __pad2;
+	unsigned long  st_size;
+	unsigned long  st_blksize;
+	unsigned long  st_blocks;
+	unsigned long  st_atime;
+	unsigned long  __unused1;
+	unsigned long  st_mtime;
+	unsigned long  __unused2;
+	unsigned long  st_ctime;
+	unsigned long  __unused3;
+	unsigned long  __unused4;
+	unsigned long  __unused5;
+};
+
+#endif /* _M68K_STAT_H */
diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/statfs.h linux/include/asm-m68k/statfs.h
--- v1.3.93/linux/include/asm-m68k/statfs.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-m68k/statfs.h	Wed Dec 27 22:47:26 1995
@@ -0,0 +1,21 @@
+#ifndef _M68K_STATFS_H
+#define _M68K_STATFS_H
+
+typedef struct {
+	long    val[2];
+} fsid_t;
+
+struct statfs {
+	long f_type;
+	long f_bsize;
+	long f_blocks;
+	long f_bfree;
+	long f_bavail;
+	long f_files;
+	long f_ffree;
+	fsid_t f_fsid;
+	long f_namelen;
+	long f_spare[6];
+};
+
+#endif /* _M68K_STATFS_H */
diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/string.h linux/include/asm-m68k/string.h
--- v1.3.93/linux/include/asm-m68k/string.h	Sat Jan  7 12:39:37 1995
+++ linux/include/asm-m68k/string.h	Sat Mar 30 14:11:50 1996
@@ -1,20 +1,20 @@
 #ifndef _M68K_STRING_H_
 #define _M68K_STRING_H_
 
-#define __USE_PORTABLE_STRINGS_H_
-
+#define __HAVE_ARCH_STRCPY
 extern inline char * strcpy(char * dest,const char *src)
 {
   char *xdest = dest;
 
   __asm__ __volatile__
        ("1:\tmoveb %1@+,%0@+\n\t"
-        "bne 1b"
+        "jne 1b"
 	: "=a" (dest), "=a" (src)
         : "0" (dest), "1" (src) : "memory");
   return xdest;
 }
 
+#define __HAVE_ARCH_STRNCPY
 extern inline char * strncpy(char *dest, const char *src, size_t n)
 {
   char *xdest = dest;
@@ -24,9 +24,9 @@
 
   __asm__ __volatile__
        ("1:\tmoveb %1@+,%0@+\n\t"
-	"beq 2f\n\t"
+	"jeq 2f\n\t"
         "subql #1,%2\n\t"
-        "bne 1b\n\t"
+        "jne 1b\n\t"
         "2:"
         : "=a" (dest), "=a" (src), "=d" (n)
         : "0" (dest), "1" (src), "2" (n)
@@ -34,10 +34,116 @@
   return xdest;
 }
 
-#define __USE_PORTABLE_strcat
+#define __HAVE_ARCH_STRCAT
+extern inline char * strcat(char * dest, const char * src)
+{
+	char *tmp = dest;
+
+	while (*dest)
+		dest++;
+	while ((*dest++ = *src++))
+		;
+
+	return tmp;
+}
+
+#define __HAVE_ARCH_STRNCAT
+extern inline char * strncat(char *dest, const char *src, size_t count)
+{
+	char *tmp = dest;
+
+	if (count) {
+		while (*dest)
+			dest++;
+		while ((*dest++ = *src++)) {
+			if (--count == 0) {
+				*dest++='\0';
+				break;
+			}
+		}
+	}
+
+	return tmp;
+}
+
+#define __HAVE_ARCH_STRCHR
+extern inline char * strchr(const char * s, int c)
+{
+  const char ch = c;
+  
+  for(; *s != ch; ++s)
+    if (*s == '\0')
+      return( NULL );
+  return( (char *) s);
+}
+
+#define __HAVE_ARCH_STRPBRK
+extern inline char * strpbrk(const char * cs,const char * ct)
+{
+  const char *sc1,*sc2;
+  
+  for( sc1 = cs; *sc1 != '\0'; ++sc1)
+    for( sc2 = ct; *sc2 != '\0'; ++sc2)
+      if (*sc1 == *sc2)
+	return((char *) sc1);
+  return( NULL );
+}
+
+#define __HAVE_ARCH_STRSPN
+extern inline size_t strspn(const char *s, const char *accept)
+{
+  const char *p;
+  const char *a;
+  size_t count = 0;
+
+  for (p = s; *p != '\0'; ++p)
+    {
+      for (a = accept; *a != '\0'; ++a)
+        if (*p == *a)
+          break;
+      if (*a == '\0')
+        return count;
+      else
+        ++count;
+    }
+
+  return count;
+}
+
+#define __HAVE_ARCH_STRTOK
+extern inline char * strtok(char * s,const char * ct)
+{
+  char *sbegin, *send;
+  
+  sbegin  = s ? s : ___strtok;
+  if (!sbegin) {
+	  return NULL;
+  }
+  sbegin += strspn(sbegin,ct);
+  if (*sbegin == '\0') {
+    ___strtok = NULL;
+    return( NULL );
+  }
+  send = strpbrk( sbegin, ct);
+  if (send && *send != '\0')
+    *send++ = '\0';
+  ___strtok = send;
+  return (sbegin);
+}
+
+/* strstr !! */
+
+#define __HAVE_ARCH_STRLEN
+extern inline size_t strlen(const char * s)
+{
+  const char *sc;
+  for (sc = s; *sc != '\0'; ++sc) ;
+  return(sc - s);
+}
 
-#define __USE_PORTABLE_strncat
+/* strnlen !! */
 
+#define __HAVE_ARCH_STRCMP
 extern inline int strcmp(const char * cs,const char * ct)
 {
   char __res;
@@ -45,10 +151,10 @@
   __asm__
        ("1:\tmoveb %0@+,%2\n\t" /* get *cs */
         "cmpb %1@+,%2\n\t"      /* compare a byte */
-        "bne  2f\n\t"           /* not equal, break out */
+        "jne  2f\n\t"           /* not equal, break out */
         "tstb %2\n\t"           /* at end of cs? */
-        "bne  1b\n\t"           /* no, keep going */
-        "bra  3f\n\t"		/* strings are equal */
+        "jne  1b\n\t"           /* no, keep going */
+        "jra  3f\n\t"		/* strings are equal */
         "2:\tsubb %1@-,%2\n\t"  /* *cs - *ct */
         "3:"
         : "=a" (cs), "=a" (ct), "=d" (__res)
@@ -56,6 +162,7 @@
   return __res;
 }
 
+#define __HAVE_ARCH_STRNCMP
 extern inline int strncmp(const char * cs,const char * ct,size_t count)
 {
   char __res;
@@ -65,13 +172,13 @@
   __asm__
        ("1:\tmovb %0@+,%3\n\t"          /* get *cs */
         "cmpb   %1@+,%3\n\t"            /* compare a byte */
-        "bne    3f\n\t"                 /* not equal, break out */
+        "jne    3f\n\t"                 /* not equal, break out */
         "tstb   %3\n\t"                 /* at end of cs? */
-        "beq    4f\n\t"                 /* yes, all done */
+        "jeq    4f\n\t"                 /* yes, all done */
         "subql  #1,%2\n\t"              /* no, adjust count */
-        "bne    1b\n\t"                 /* more to do, keep going */
+        "jne    1b\n\t"                 /* more to do, keep going */
         "2:\tmoveq #0,%3\n\t"           /* strings are equal */
-        "bra    4f\n\t"
+        "jra    4f\n\t"
         "3:\tsubb %1@-,%3\n\t"          /* *cs - *ct */
         "4:"
         : "=a" (cs), "=a" (ct), "=d" (count), "=d" (__res)
@@ -79,76 +186,173 @@
   return __res;
 }
 
-#define __USE_PORTABLE_strchr
-
-#define __USE_PORTABLE_strlen
-
-#define __USE_PORTABLE_strspn
-
-#define __USE_PORTABLE_strpbrk
-
-#define __USE_PORTABLE_strtok
-
-extern inline void * memset(void * s,char c,size_t count)
+#define __HAVE_ARCH_MEMSET
+extern inline void * memset(void * s,int c,size_t count)
 {
   void *xs = s;
+  size_t temp;
 
   if (!count)
     return xs;
-  __asm__ __volatile__
-       ("1:\tmoveb %3,%0@+\n\t"
-	"subql #1,%1\n\t"
-        "bne 1b"
-	: "=a" (s), "=d" (count)
-        : "0" (s), "d" (c), "1" (count)
-	: "memory");
+  c &= 0xff;
+  if ((long) s & 1)
+    {
+      char *cs = s;
+      *cs++ = c;
+      s = cs;
+      count--;
+    }
+  c |= c << 8;
+  if (count > 2 && (long) s & 2)
+    {
+      short *ss = s;
+      *ss++ = c;
+      s = ss;
+      count -= 2;
+    }
+  temp = count >> 2;
+  if (temp)
+    {
+      long *ls = s;
+      c |= c << 16;
+      temp--;
+      do
+	*ls++ = c;
+      while (temp--);
+      s = ls;
+    }
+  if (count & 2)
+    {
+      short *ss = s;
+      *ss++ = c;
+      s = ss;
+    }
+  if (count & 1)
+    {
+      char *cs = s;
+      *cs = c;
+    }
   return xs;
 }
 
-extern inline void * memcpy(void * to, const void * from, size_t n)
-{
-  void *xto = to;
-
-  if (!n)
-    return xto;
-  __asm__ __volatile__
-       ("1:\tmoveb %1@+,%0@+\n\t"
-	"subql #1,%2\n\t"
-        "bne 1b"
-        : "=a" (to), "=a" (from), "=d" (n)
-        : "0" (to), "1" (from), "2" (n)
-        : "memory" );
-  return xto;
-}
+#define __HAVE_ARCH_MEMCPY
+#define memcpy(to, from, n) \
+(__builtin_constant_p(n) ? \
+ __builtin_memcpy((to),(from),(n)) : \
+ memcpy((to),(from),(n)))
 
+#define __HAVE_ARCH_MEMMOVE
 extern inline void * memmove(void * dest,const void * src, size_t n)
 {
   void *xdest = dest;
+  size_t temp;
 
   if (!n)
     return xdest;
 
   if (dest < src)
-    __asm__ __volatile__
-       ("1:\tmoveb %1@+,%0@+\n\t"
-	"subql #1,%2\n\t"
-        "bne 1b"
-        : "=a" (dest), "=a" (src), "=d" (n)
-        : "0" (dest), "1" (src), "2" (n)
-        : "memory" );
+    {
+      if ((long) dest & 1)
+	{
+	  char *cdest = dest;
+	  const char *csrc = src;
+	  *cdest++ = *csrc++;
+	  dest = cdest;
+	  src = csrc;
+	  n--;
+	}
+      if (n > 2 && (long) dest & 2)
+	{
+	  short *sdest = dest;
+	  const short *ssrc = src;
+	  *sdest++ = *ssrc++;
+	  dest = sdest;
+	  src = ssrc;
+	  n -= 2;
+	}
+      temp = n >> 2;
+      if (temp)
+	{
+	  long *ldest = dest;
+	  const long *lsrc = src;
+	  temp--;
+	  do
+	    *ldest++ = *lsrc++;
+	  while (temp--);
+	  dest = ldest;
+	  src = lsrc;
+	}
+      if (n & 2)
+	{
+	  short *sdest = dest;
+	  const short *ssrc = src;
+	  *sdest++ = *ssrc++;
+	  dest = sdest;
+	  src = ssrc;
+	}
+      if (n & 1)
+	{
+	  char *cdest = dest;
+	  const char *csrc = src;
+	  *cdest = *csrc;
+	}
+    }
   else
-    __asm__ __volatile__
-       ("1:\tmoveb %1@-,%0@-\n\t"
-	"subql #1,%2\n\t"
-        "bne 1b"
-        : "=a" (dest), "=a" (src), "=d" (n)
-        : "0" (dest+n), "1" (src+n), "2" (n)
-        : "memory" );
+    {
+      dest = (char *) dest + n;
+      src = (const char *) src + n;
+      if ((long) dest & 1)
+	{
+	  char *cdest = dest;
+	  const char *csrc = src;
+	  *--cdest = *--csrc;
+	  dest = cdest;
+	  src = csrc;
+	  n--;
+	}
+      if (n > 2 && (long) dest & 2)
+	{
+	  short *sdest = dest;
+	  const short *ssrc = src;
+	  *--sdest = *--ssrc;
+	  dest = sdest;
+	  src = ssrc;
+	  n -= 2;
+	}
+      temp = n >> 2;
+      if (temp)
+	{
+	  long *ldest = dest;
+	  const long *lsrc = src;
+	  temp--;
+	  do
+	    *--ldest = *--lsrc;
+	  while (temp--);
+	  dest = ldest;
+	  src = lsrc;
+	}
+      if (n & 2)
+	{
+	  short *sdest = dest;
+	  const short *ssrc = src;
+	  *--sdest = *--ssrc;
+	  dest = sdest;
+	  src = ssrc;
+	}
+      if (n & 1)
+	{
+	  char *cdest = dest;
+	  const char *csrc = src;
+	  *--cdest = *--csrc;
+	}
+    }
   return xdest;
 }
 
-#define __USE_PORTABLE_memcmp
-
-#define __USE_PORTABLE_memscan
+#define __HAVE_ARCH_MEMCMP
+#define memcmp(cs, ct, n) \
+(__builtin_constant_p(n) ? \
+ __builtin_memcmp((cs),(ct),(n)) : \
+ memcmp((cs),(ct),(n)))
 
 #endif /* _M68K_STRING_H_ */
diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/system.h linux/include/asm-m68k/system.h
--- v1.3.93/linux/include/asm-m68k/system.h	Thu Jan  5 13:47:08 1995
+++ linux/include/asm-m68k/system.h	Sun Mar 31 18:38:57 1996
@@ -1,53 +1,140 @@
+#ifndef _M68K_SYSTEM_H
+#define _M68K_SYSTEM_H
+
+#include <linux/config.h> /* get configuration macros */
+#include <linux/linkage.h>
+#include <asm/segment.h>
+
+extern inline unsigned long rdusp(void) {
+  	unsigned long usp;
+
+	__asm__ __volatile__("movec %/usp,%0"
+			     : "=d" (usp));
+	return usp;
+}
+
+extern inline void wrusp(unsigned long usp) {
+	__asm__ __volatile__("movec %0,%/usp"
+			     :
+			     : "d" (usp));
+}
+
 /*
- *  linux/include/asm-m68k/system.h
- *
- *  Copyright (C) 1991, 1992  Linus Torvalds
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file README.legal in the main directory of this archive
- * for more details.
+ * switch_to(n) should switch tasks to task ptr, first checking that
+ * ptr isn't the current task, in which case it does nothing.  This
+ * also clears the TS-flag if the task we switched to has used the
+ * math co-processor latest.
  */
-
 /*
- * 680x0 support added by Hamish Macdonald
+ * switch_to() saves the extra registers, that are not saved
+ * automatically by SAVE_SWITCH_STACK in resume(), ie. d0-d5 and
+ * a0-a1. Some of these are used by schedule() and its predecessors
+ * and so we might get see unexpected behaviors when a task returns
+ * with unexpected register values.
+ *
+ * syscall stores these regsiters itself and none of them are used
+ * by syscall after the function in the syscall has been called.
+ *
+ * Beware that resume now expects *next to be in d1 and the offset of
+ * tss to be in a1. This saves a few instructions as we no longer have
+ * to push them onto the stack and read them back right after.
+ *
+ * 02/17/96 - Jes Sorensen (jds@kom.auc.dk)
  */
+asmlinkage void resume(void);
+#define switch_to(prev,next) { \
+  register int k __asm__ ("a1") = (int)&((struct task_struct *)0)->tss; \
+  register int n __asm__ ("d1") = (int)next; \
+  __asm__ __volatile__("jbsr " SYMBOL_NAME_STR(resume) "\n\t" \
+		       : : "a" (k), "d" (n) \
+		       : "d0", "d1", "d2", "d3", "d4", "d5", "a0", "a1"); \
+}
 
-#ifndef _M68K_SYSTEM_H
-#define _M68K_SYSTEM_H
+#define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
+#define tas(ptr) (xchg((ptr),1))
 
-#include <linux/config.h> /* get configuration macros */
+struct __xchg_dummy { unsigned long a[100]; };
+#define __xg(x) ((volatile struct __xchg_dummy *)(x))
 
 #if defined(CONFIG_ATARI) && !defined(CONFIG_AMIGA) && !defined(CONFIG_MAC)
 /* block out HSYNC on the atari */
-#define sti() __asm__ __volatile__ ("andiw #0xfbff,sr": : : "memory")
+#define sti() __asm__ __volatile__ ("andiw #0xfbff,%/sr": : : "memory")
 #else /* portable version */
-#define sti() __asm__ __volatile__ ("andiw #0xf8ff,sr": : : "memory")
+#define sti() __asm__ __volatile__ ("andiw #0xf8ff,%/sr": : : "memory")
 #endif /* machine compilation types */ 
-#define cli() __asm__ __volatile__ ("oriw  #0x0700,sr": : : "memory")
+#define cli() __asm__ __volatile__ ("oriw  #0x0700,%/sr": : : "memory")
 #define nop() __asm__ __volatile__ ("nop"::)
 
 #define save_flags(x) \
-__asm__ __volatile__("movew sr,%0":"=d" (x) : /* no input */ :"memory")
+__asm__ __volatile__("movew %/sr,%0":"=d" (x) : /* no input */ :"memory")
 
 #define restore_flags(x) \
-__asm__ __volatile__("movew %0,sr": /* no outputs */ :"d" (x) : "memory")
+__asm__ __volatile__("movew %0,%/sr": /* no outputs */ :"d" (x) : "memory")
 
 #define iret() __asm__ __volatile__ ("rte": : :"memory", "sp", "cc")
 
-#define move_to_user_mode() \
-    __asm__ __volatile__ ("movel sp,usp\n\t"     /* setup user sp       */ \
-			  "movec %0,msp\n\t"     /* setup kernel sp     */ \
-			  "andiw #0xdfff,sr"     /* return to user mode */ \
-			  : /* no output */                                \
-			  : "r" (current->kernel_stack_page + PAGE_SIZE)   \
-			  : "memory", "sp")
-
-static inline void clear_fpu(void) {
-	unsigned long nilstate = 0;
-	__asm__ __volatile__ ("frestore %0@" : : "a" (&nilstate));
+#if 1
+static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int size)
+{
+  unsigned long tmp, flags;
+
+  save_flags(flags);
+  cli();
+
+  switch (size) {
+  case 1:
+    __asm__ __volatile__
+    ("moveb %2,%0\n\t"
+     "moveb %1,%2"
+    : "=&d" (tmp) : "d" (x), "m" (*__xg(ptr)) : "memory");
+    break;
+  case 2:
+    __asm__ __volatile__
+    ("movew %2,%0\n\t"
+     "movew %1,%2"
+    : "=&d" (tmp) : "d" (x), "m" (*__xg(ptr)) : "memory");
+    break;
+  case 4:
+    __asm__ __volatile__
+    ("movel %2,%0\n\t"
+     "movel %1,%2"
+    : "=&d" (tmp) : "d" (x), "m" (*__xg(ptr)) : "memory");
+    break;
+  }
+  restore_flags(flags);
+  return tmp;
 }
-
-#define halt() \
-        __asm__ __volatile__ ("halt")
+#else
+static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int size)
+{
+	switch (size) {
+	    case 1:
+		__asm__ __volatile__
+			("moveb %2,%0\n\t"
+			 "1:\n\t"
+			 "casb %0,%1,%2\n\t"
+			 "jne 1b"
+			 : "=&d" (x) : "d" (x), "m" (*__xg(ptr)) : "memory");
+		break;
+	    case 2:
+		__asm__ __volatile__
+			("movew %2,%0\n\t"
+			 "1:\n\t"
+			 "casw %0,%1,%2\n\t"
+			 "jne 1b"
+			 : "=&d" (x) : "d" (x), "m" (*__xg(ptr)) : "memory");
+		break;
+	    case 4:
+		__asm__ __volatile__
+			("movel %2,%0\n\t"
+			 "1:\n\t"
+			 "casl %0,%1,%2\n\t"
+			 "jne 1b"
+			 : "=&d" (x) : "d" (x), "m" (*__xg(ptr)) : "memory");
+		break;
+	}
+	return x;
+}
+#endif
 
 #endif /* _M68K_SYSTEM_H */
diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/termbits.h linux/include/asm-m68k/termbits.h
--- v1.3.93/linux/include/asm-m68k/termbits.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-m68k/termbits.h	Fri Apr  5 14:51:56 1996
@@ -0,0 +1,161 @@
+#ifndef __ARCH_M68K_TERMBITS_H__
+#define __ARCH_M68K_TERMBITS_H__
+
+#include <linux/posix_types.h>
+
+typedef unsigned char	cc_t;
+typedef unsigned int	speed_t;
+typedef unsigned int	tcflag_t;
+
+#define NCCS 19
+struct termios {
+	tcflag_t c_iflag;		/* input mode flags */
+	tcflag_t c_oflag;		/* output mode flags */
+	tcflag_t c_cflag;		/* control mode flags */
+	tcflag_t c_lflag;		/* local mode flags */
+	cc_t c_line;			/* line discipline */
+	cc_t c_cc[NCCS];		/* control characters */
+};
+
+/* c_cc characters */
+#define VINTR 0
+#define VQUIT 1
+#define VERASE 2
+#define VKILL 3
+#define VEOF 4
+#define VTIME 5
+#define VMIN 6
+#define VSWTC 7
+#define VSTART 8
+#define VSTOP 9
+#define VSUSP 10
+#define VEOL 11
+#define VREPRINT 12
+#define VDISCARD 13
+#define VWERASE 14
+#define VLNEXT 15
+#define VEOL2 16
+
+
+/* c_iflag bits */
+#define IGNBRK	0000001
+#define BRKINT	0000002
+#define IGNPAR	0000004
+#define PARMRK	0000010
+#define INPCK	0000020
+#define ISTRIP	0000040
+#define INLCR	0000100
+#define IGNCR	0000200
+#define ICRNL	0000400
+#define IUCLC	0001000
+#define IXON	0002000
+#define IXANY	0004000
+#define IXOFF	0010000
+#define IMAXBEL	0020000
+
+/* c_oflag bits */
+#define OPOST	0000001
+#define OLCUC	0000002
+#define ONLCR	0000004
+#define OCRNL	0000010
+#define ONOCR	0000020
+#define ONLRET	0000040
+#define OFILL	0000100
+#define OFDEL	0000200
+#define NLDLY	0000400
+#define   NL0	0000000
+#define   NL1	0000400
+#define CRDLY	0003000
+#define   CR0	0000000
+#define   CR1	0001000
+#define   CR2	0002000
+#define   CR3	0003000
+#define TABDLY	0014000
+#define   TAB0	0000000
+#define   TAB1	0004000
+#define   TAB2	0010000
+#define   TAB3	0014000
+#define   XTABS	0014000
+#define BSDLY	0020000
+#define   BS0	0000000
+#define   BS1	0020000
+#define VTDLY	0040000
+#define   VT0	0000000
+#define   VT1	0040000
+#define FFDLY	0100000
+#define   FF0	0000000
+#define   FF1	0100000
+
+/* c_cflag bit meaning */
+#define CBAUD	0010017
+#define  B0	0000000		/* hang up */
+#define  B50	0000001
+#define  B75	0000002
+#define  B110	0000003
+#define  B134	0000004
+#define  B150	0000005
+#define  B200	0000006
+#define  B300	0000007
+#define  B600	0000010
+#define  B1200	0000011
+#define  B1800	0000012
+#define  B2400	0000013
+#define  B4800	0000014
+#define  B9600	0000015
+#define  B19200	0000016
+#define  B38400	0000017
+#define EXTA B19200
+#define EXTB B38400
+#define CSIZE	0000060
+#define   CS5	0000000
+#define   CS6	0000020
+#define   CS7	0000040
+#define   CS8	0000060
+#define CSTOPB	0000100
+#define CREAD	0000200
+#define PARENB	0000400
+#define PARODD	0001000
+#define HUPCL	0002000
+#define CLOCAL	0004000
+#define CBAUDEX 0010000
+#define  B57600  0010001
+#define  B115200 0010002
+#define  B230400 0010003
+#define CIBAUD	  002003600000	/* input baud rate (not used) */
+#define CRTSCTS	  020000000000		/* flow control */
+
+/* c_lflag bits */
+#define ISIG	0000001
+#define ICANON	0000002
+#define XCASE	0000004
+#define ECHO	0000010
+#define ECHOE	0000020
+#define ECHOK	0000040
+#define ECHONL	0000100
+#define NOFLSH	0000200
+#define TOSTOP	0000400
+#define ECHOCTL	0001000
+#define ECHOPRT	0002000
+#define ECHOKE	0004000
+#define FLUSHO	0010000
+#define PENDIN	0040000
+#define IEXTEN	0100000
+
+
+/* tcflow() and TCXONC use these */
+#define	TCOOFF		0
+#define	TCOON		1
+#define	TCIOFF		2
+#define	TCION		3
+
+/* tcflush() and TCFLSH use these */
+#define	TCIFLUSH	0
+#define	TCOFLUSH	1
+#define	TCIOFLUSH	2
+
+/* tcsetattr uses these */
+#define	TCSANOW		0
+#define	TCSADRAIN	1
+#define	TCSAFLUSH	2
+
+#endif /* __ARCH_M68K_TERMBITS_H__ */
diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/termios.h linux/include/asm-m68k/termios.h
--- v1.3.93/linux/include/asm-m68k/termios.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-m68k/termios.h	Fri Apr  5 14:52:09 1996
@@ -0,0 +1,89 @@
+#ifndef _M68K_TERMIOS_H
+#define _M68K_TERMIOS_H
+
+#include <asm/termbits.h>
+#include <asm/ioctls.h>
+ 
+struct winsize {
+	unsigned short ws_row;
+	unsigned short ws_col;
+	unsigned short ws_xpixel;
+	unsigned short ws_ypixel;
+};
+
+#define NCC 8
+struct termio {
+	unsigned short c_iflag;		/* input mode flags */
+	unsigned short c_oflag;		/* output mode flags */
+	unsigned short c_cflag;		/* control mode flags */
+	unsigned short c_lflag;		/* local mode flags */
+	unsigned char c_line;		/* line discipline */
+	unsigned char c_cc[NCC];	/* control characters */
+};
+
+#ifdef __KERNEL__
+/*	intr=^C		quit=^|		erase=del	kill=^U
+	eof=^D		vtime=\0	vmin=\1		sxtc=\0
+	start=^Q	stop=^S		susp=^Z		eol=\0
+	reprint=^R	discard=^U	werase=^W	lnext=^V
+	eol2=\0
+*/
+#define INIT_C_CC "\003\034\177\025\004\0\1\0\021\023\032\0\022\017\027\026\0"
+#endif
+
+/* modem lines */
+#define TIOCM_LE	0x001
+#define TIOCM_DTR	0x002
+#define TIOCM_RTS	0x004
+#define TIOCM_ST	0x008
+#define TIOCM_SR	0x010
+#define TIOCM_CTS	0x020
+#define TIOCM_CAR	0x040
+#define TIOCM_RNG	0x080
+#define TIOCM_DSR	0x100
+#define TIOCM_CD	TIOCM_CAR
+#define TIOCM_RI	TIOCM_RNG
+
+/* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */
+
+/* line disciplines */
+#define N_TTY		0
+#define N_SLIP		1
+#define N_MOUSE		2
+#define N_PPP		3
+#define N_STRIP		4
+
+#ifdef __KERNEL__
+
+/*
+ * Translate a "termio" structure into a "termios". Ugh.
+ */
+extern inline void trans_from_termio(struct termio * termio,
+	struct termios * termios)
+{
+#define SET_LOW_BITS(x,y)	((x) = (0xffff0000 & (x)) | (y))
+	SET_LOW_BITS(termios->c_iflag, termio->c_iflag);
+	SET_LOW_BITS(termios->c_oflag, termio->c_oflag);
+	SET_LOW_BITS(termios->c_cflag, termio->c_cflag);
+	SET_LOW_BITS(termios->c_lflag, termio->c_lflag);
+#undef SET_LOW_BITS
+	memcpy(termios->c_cc, termio->c_cc, NCC);
+}
+
+/*
+ * Translate a "termios" structure into a "termio". Ugh.
+ */
+extern inline void trans_to_termio(struct termios * termios,
+	struct termio * termio)
+{
+	termio->c_iflag = termios->c_iflag;
+	termio->c_oflag = termios->c_oflag;
+	termio->c_cflag = termios->c_cflag;
+	termio->c_lflag = termios->c_lflag;
+	termio->c_line	= termios->c_line;
+	memcpy(termio->c_cc, termios->c_cc, NCC);
+}
+
+#endif	/* __KERNEL__ */
+
+#endif /* _M68K_TERMIOS_H */
diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/traps.h linux/include/asm-m68k/traps.h
--- v1.3.93/linux/include/asm-m68k/traps.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-m68k/traps.h	Mon Apr  1 21:07:26 1996
@@ -0,0 +1,241 @@
+/*
+ *  linux/include/asm/traps.h
+ *
+ *  Copyright (C) 1993        Hamish Macdonald
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file README.legal in the main directory of this archive
+ * for more details.
+ */
+
+#ifndef _M68K_TRAPS_H
+#define _M68K_TRAPS_H
+
+typedef void (*e_vector)(void);
+
+extern e_vector vectors[];
+
+#define VEC_BUSERR  (2)
+#define VEC_ADDRERR (3)
+#define VEC_ILLEGAL (4)
+#define VEC_ZERODIV (5)
+#define VEC_CHK     (6)
+#define VEC_TRAP    (7)
+#define VEC_PRIV    (8)
+#define VEC_TRACE   (9)
+#define VEC_LINE10  (10)
+#define VEC_LINE11  (11)
+#define VEC_RESV1   (12)
+#define VEC_COPROC  (13)
+#define VEC_FORMAT  (14)
+#define VEC_UNINT   (15)
+#define VEC_SPUR    (24)
+#define VEC_INT1    (25)
+#define VEC_INT2    (26)
+#define VEC_INT3    (27)
+#define VEC_INT4    (28)
+#define VEC_INT5    (29)
+#define VEC_INT6    (30)
+#define VEC_INT7    (31)
+#define VEC_SYS     (32)
+#define VEC_TRAP1   (33)
+#define VEC_TRAP2   (34)
+#define VEC_TRAP3   (35)
+#define VEC_TRAP4   (36)
+#define VEC_TRAP5   (37)
+#define VEC_TRAP6   (38)
+#define VEC_TRAP7   (39)
+#define VEC_TRAP8   (40)
+#define VEC_TRAP9   (41)
+#define VEC_TRAP10  (42)
+#define VEC_TRAP11  (43)
+#define VEC_TRAP12  (44)
+#define VEC_TRAP13  (45)
+#define VEC_TRAP14  (46)
+#define VEC_TRAP15  (47)
+#define VEC_FPBRUC  (48)
+#define VEC_FPIR    (49)
+#define VEC_FPDIVZ  (50)
+#define VEC_FPUNDER (51)
+#define VEC_FPOE    (52)
+#define VEC_FPOVER  (53)
+#define VEC_FPNAN   (54)
+#define VEC_FPUNSUP (55)
+#define	VEC_UNIMPEA (60)
+#define	VEC_UNIMPII (61)
+
+#define VECOFF(vec) ((vec)<<2)
+
+/* Status register bits */
+#define PS_T  (0x8000)
+#define PS_S  (0x2000)
+#define PS_M  (0x1000)
+#define PS_C  (0x0001)
+
+/* bits for 68020/68030 special status word */
+
+#define FC    (0x8000)
+#define FB    (0x4000)
+#define RC    (0x2000)
+#define RB    (0x1000)
+#define DF    (0x0100)
+#define RM    (0x0080)
+#define RW    (0x0040)
+#define SZ    (0x0030)
+#define DFC   (0x0007)
+
+/* bits for 68030 MMU status register (mmusr,psr) */
+
+#define MMU_B	     (0x8000)    /* bus error */
+#define MMU_L	     (0x4000)    /* limit violation */
+#define MMU_S	     (0x2000)    /* supervisor violation */
+#define MMU_WP	     (0x0800)    /* write-protected */
+#define MMU_I	     (0x0400)    /* invalid descriptor */
+#define MMU_M	     (0x0200)    /* ATC entry modified */
+#define MMU_T	     (0x0040)    /* transparent translation */
+#define MMU_NUM      (0x0007)    /* number of levels traversed */
+
+
+/* bits for 68040 special status word */
+#define CP_040	(0x8000)
+#define CU_040	(0x4000)
+#define CT_040	(0x2000)
+#define CM_040	(0x1000)
+#define MA_040	(0x0800)
+#define ATC_040 (0x0400)
+#define LK_040	(0x0200)
+#define RW_040	(0x0100)
+#define SIZ_040 (0x0060)
+#define TT_040	(0x0018)
+#define TM_040	(0x0007)
+
+/* bits for 68040 write back status word */
+#define WBV_040   (0x80)
+#define WBSIZ_040 (0x60)
+#define WBBYT_040 (0x20)
+#define WBWRD_040 (0x40)
+#define WBLNG_040 (0x00)
+#define WBTT_040  (0x18)
+#define WBTM_040  (0x07)
+
+/* bus access size codes */
+#define BA_SIZE_BYTE    (0x20)
+#define BA_SIZE_WORD    (0x40)
+#define BA_SIZE_LONG    (0x00)
+#define BA_SIZE_LINE    (0x60)
+
+/* bus access transfer type codes */
+#define BA_TT_MOVE16    (0x08)
+
+/* bits for 68040 MMU status register (mmusr) */
+#define MMU_B_040   (0x0800)
+#define MMU_G_040   (0x0400)
+#define MMU_S_040   (0x0080)
+#define MMU_CM_040  (0x0060)
+#define MMU_M_040   (0x0010)
+#define MMU_WP_040  (0x0004)
+#define MMU_T_040   (0x0002)
+#define MMU_R_040   (0x0001)
+
+/* bits in the 68060 fault status long word (FSLW) */
+#define	MMU060_MA	(0x08000000)	/* misaligned */
+#define	MMU060_LK	(0x02000000)	/* locked transfer */
+#define	MMU060_RW	(0x01800000)	/* read/write */
+# define MMU060_RW_W	(0x00800000)	/* write */
+# define MMU060_RW_R	(0x01000000)	/* read */
+# define MMU060_RW_RMW	(0x01800000)	/* read/modify/write */
+# define MMU060_W		(0x00800000)	/* general write, includes rmw */
+#define	MMU060_SIZ	(0x00600000)	/* transfer size */
+#define	MMU060_TT	(0x00180000)	/* transfer type (TT) bits */
+#define	MMU060_TM	(0x00070000)	/* transfer modifier (TM) bits */
+#define	MMU060_IO	(0x00008000)	/* intruction or operand */
+#define	MMU060_PBE	(0x00004000)	/* push buffer bus error */
+#define	MMU060_SBE	(0x00002000)	/* store buffer bus error */
+#define	MMU060_PTA	(0x00001000)	/* pointer A fault */
+#define	MMU060_PTB	(0x00000800)	/* pointer B fault */
+#define	MMU060_IL	(0x00000400)	/* double indirect descr fault */
+#define	MMU060_PF	(0x00000200)	/* page fault (invalid descr) */
+#define	MMU060_SP	(0x00000100)	/* supervisor protection */
+#define	MMU060_WP	(0x00000080)	/* write protection */
+#define	MMU060_TWE	(0x00000040)	/* bus error on table search */
+#define	MMU060_RE	(0x00000020)	/* bus error on read */
+#define	MMU060_WE	(0x00000010)	/* bus error on write */
+#define	MMU060_TTR	(0x00000008)	/* error caused by TTR translation */
+#define	MMU060_BPE	(0x00000004)	/* branch prediction error */
+#define	MMU060_SEE	(0x00000001)	/* software emulated error */
+
+/* cases of missing or invalid descriptors */
+#define MMU060_DESC_ERR	(MMU060_TWE | MMU060_PTA | MMU060_PTB | \
+						 MMU060_IL  | MMU060_PF)
+/* bits that indicate real errors */
+#define MMU060_ERR_BITS	(MMU060_PBE | MMU060_SBE | MMU060_DESC_ERR | \
+						 MMU060_SP  | MMU060_WP  | MMU060_RE | \
+						 MMU060_WE)
+
+/* structure for stack frames */
+
+struct frame {
+    struct pt_regs ptregs;
+    union {
+	    struct {
+		    unsigned long  iaddr;    /* instruction address */
+	    } fmt2;
+	    struct {
+		    unsigned long  effaddr;  /* effective address */
+	    } fmt3;
+	    struct {
+		    unsigned long  effaddr;  /* effective address */
+		    unsigned long  pc;	     /* pc of faulted instr */
+	    } fmt4;
+	    struct {
+		    unsigned long  effaddr;  /* effective address */
+		    unsigned short ssw;      /* special status word */
+		    unsigned short wb3s;     /* write back 3 status */
+		    unsigned short wb2s;     /* write back 2 status */
+		    unsigned short wb1s;     /* write back 1 status */
+		    unsigned long  faddr;    /* fault address */
+		    unsigned long  wb3a;     /* write back 3 address */
+		    unsigned long  wb3d;     /* write back 3 data */
+		    unsigned long  wb2a;     /* write back 2 address */
+		    unsigned long  wb2d;     /* write back 2 data */
+		    unsigned long  wb1a;     /* write back 1 address */
+		    unsigned long  wb1dpd0;  /* write back 1 data/push data 0*/
+		    unsigned long  pd1;      /* push data 1*/
+		    unsigned long  pd2;      /* push data 2*/
+		    unsigned long  pd3;      /* push data 3*/
+	    } fmt7;
+	    struct {
+		    unsigned long  iaddr;    /* instruction address */
+		    unsigned short int1[4];  /* internal registers */
+	    } fmt9;
+	    struct {
+		    unsigned short int1;
+		    unsigned short ssw;      /* special status word */
+		    unsigned short isc;      /* instruction stage c */
+		    unsigned short isb;      /* instruction stage b */
+		    unsigned long  daddr;    /* data cycle fault address */
+		    unsigned short int2[2];
+		    unsigned long  dobuf;    /* data cycle output buffer */
+		    unsigned short int3[2];
+	    } fmta;
+	    struct {
+		    unsigned short int1;
+		    unsigned short ssw;     /* special status word */
+		    unsigned short isc;     /* instruction stage c */
+		    unsigned short isb;     /* instruction stage b */
+		    unsigned long  daddr;   /* data cycle fault address */
+		    unsigned short int2[2];
+		    unsigned long  dobuf;   /* data cycle output buffer */
+		    unsigned short int3[4];
+		    unsigned long  baddr;   /* stage B address */
+		    unsigned short int4[2];
+		    unsigned long  dibuf;   /* data cycle input buffer */
+		    unsigned short int5[3];
+		    unsigned	   ver : 4; /* stack frame version # */
+		    unsigned	   int6:12;
+		    unsigned short int7[18];
+	    } fmtb;
+    } un;
+};
+
+#endif /* _M68K_TRAPS_H */
diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/types.h linux/include/asm-m68k/types.h
--- v1.3.93/linux/include/asm-m68k/types.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-m68k/types.h	Fri Apr  5 14:08:41 1996
@@ -0,0 +1,52 @@
+#ifndef _M68K_TYPES_H
+#define _M68K_TYPES_H
+
+/*
+ * This file is never included by application software unless
+ * explicitly requested (e.g., via linux/types.h) in which case the
+ * application is Linux specific so (user-) name space pollution is
+ * not a major issue.  However, for interoperability, libraries still
+ * need to be careful to avoid a name clashes.
+ */
+
+typedef unsigned short umode_t;
+
+/*
+ * __xx is ok: it doesn't pollute the POSIX namespace. Use these in the
+ * header files exported to user space
+ */
+
+typedef __signed__ char __s8;
+typedef unsigned char __u8;
+
+typedef __signed__ short __s16;
+typedef unsigned short __u16;
+
+typedef __signed__ int __s32;
+typedef unsigned int __u32;
+
+#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
+typedef __signed__ long long __s64;
+typedef unsigned long long __u64;
+#endif
+
+/*
+ * These aren't exported outside the kernel to avoid name space clashes
+ */
+#ifdef __KERNEL__
+
+typedef signed char s8;
+typedef unsigned char u8;
+
+typedef signed short s16;
+typedef unsigned short u16;
+
+typedef signed int s32;
+typedef unsigned int u32;
+
+typedef signed long long s64;
+typedef unsigned long long u64;
+
+#endif /* __KERNEL__ */
+
+#endif /* _M68K_TYPES_H */
diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/unistd.h linux/include/asm-m68k/unistd.h
--- v1.3.93/linux/include/asm-m68k/unistd.h	Mon Nov 28 20:49:07 1994
+++ linux/include/asm-m68k/unistd.h	Thu Apr 18 03:00:00 1996
@@ -1,6 +1,288 @@
 #ifndef _ASM_M68K_UNISTD_H_
 #define _ASM_M68K_UNISTD_H_
 
+/*
+ * This file contains the system call numbers.
+ */
+
+#define __NR_setup		  0	/* used only by init, to get system going */
+#define __NR_exit		  1
+#define __NR_fork		  2
+#define __NR_read		  3
+#define __NR_write		  4
+#define __NR_open		  5
+#define __NR_close		  6
+#define __NR_waitpid		  7
+#define __NR_creat		  8
+#define __NR_link		  9
+#define __NR_unlink		 10
+#define __NR_execve		 11
+#define __NR_chdir		 12
+#define __NR_time		 13
+#define __NR_mknod		 14
+#define __NR_chmod		 15
+#define __NR_chown		 16
+#define __NR_break		 17
+#define __NR_oldstat		 18
+#define __NR_lseek		 19
+#define __NR_getpid		 20
+#define __NR_mount		 21
+#define __NR_umount		 22
+#define __NR_setuid		 23
+#define __NR_getuid		 24
+#define __NR_stime		 25
+#define __NR_ptrace		 26
+#define __NR_alarm		 27
+#define __NR_oldfstat		 28
+#define __NR_pause		 29
+#define __NR_utime		 30
+#define __NR_stty		 31
+#define __NR_gtty		 32
+#define __NR_access		 33
+#define __NR_nice		 34
+#define __NR_ftime		 35
+#define __NR_sync		 36
+#define __NR_kill		 37
+#define __NR_rename		 38
+#define __NR_mkdir		 39
+#define __NR_rmdir		 40
+#define __NR_dup		 41
+#define __NR_pipe		 42
+#define __NR_times		 43
+#define __NR_prof		 44
+#define __NR_brk		 45
+#define __NR_setgid		 46
+#define __NR_getgid		 47
+#define __NR_signal		 48
+#define __NR_geteuid		 49
+#define __NR_getegid		 50
+#define __NR_acct		 51
+#define __NR_phys		 52
+#define __NR_lock		 53
+#define __NR_ioctl		 54
+#define __NR_fcntl		 55
+#define __NR_mpx		 56
+#define __NR_setpgid		 57
+#define __NR_ulimit		 58
+#define __NR_oldolduname	 59
+#define __NR_umask		 60
+#define __NR_chroot		 61
+#define __NR_ustat		 62
+#define __NR_dup2		 63
+#define __NR_getppid		 64
+#define __NR_getpgrp		 65
+#define __NR_setsid		 66
+#define __NR_sigaction		 67
+#define __NR_sgetmask		 68
+#define __NR_ssetmask		 69
+#define __NR_setreuid		 70
+#define __NR_setregid		 71
+#define __NR_sigsuspend		 72
+#define __NR_sigpending		 73
+#define __NR_sethostname	 74
+#define __NR_setrlimit		 75
+#define __NR_getrlimit		 76
+#define __NR_getrusage		 77
+#define __NR_gettimeofday	 78
+#define __NR_settimeofday	 79
+#define __NR_getgroups		 80
+#define __NR_setgroups		 81
+#define __NR_select		 82
+#define __NR_symlink		 83
+#define __NR_oldlstat		 84
+#define __NR_readlink		 85
+#define __NR_uselib		 86
+#define __NR_swapon		 87
+#define __NR_reboot		 88
+#define __NR_readdir		 89
+#define __NR_mmap		 90
+#define __NR_munmap		 91
+#define __NR_truncate		 92
+#define __NR_ftruncate		 93
+#define __NR_fchmod		 94
+#define __NR_fchown		 95
+#define __NR_getpriority	 96
+#define __NR_setpriority	 97
+#define __NR_profil		 98
+#define __NR_statfs		 99
+#define __NR_fstatfs		100
+#define __NR_ioperm		101
+#define __NR_socketcall		102
+#define __NR_syslog		103
+#define __NR_setitimer		104
+#define __NR_getitimer		105
+#define __NR_stat		106
+#define __NR_lstat		107
+#define __NR_fstat		108
+#define __NR_olduname		109
+#define __NR_iopl		/* 110 */ not supported
+#define __NR_vhangup		111
+#define __NR_idle		112
+#define __NR_vm86		/* 113 */ not supported
+#define __NR_wait4		114
+#define __NR_swapoff		115
+#define __NR_sysinfo		116
+#define __NR_ipc		117
+#define __NR_fsync		118
+#define __NR_sigreturn		119
+#define __NR_clone		120
+#define __NR_setdomainname	121
+#define __NR_uname		122
+#define __NR_modify_ldt		123
+#define __NR_adjtimex		124
+#define __NR_mprotect		125
+#define __NR_sigprocmask	126
+#define __NR_create_module	127
+#define __NR_init_module	128
+#define __NR_delete_module	129
+#define __NR_get_kernel_syms	130
+#define __NR_quotactl		131
+#define __NR_getpgid		132
+#define __NR_fchdir		133
+#define __NR_bdflush		134
+#define __NR_sysfs		135
+#define __NR_personality	136
+#define __NR_afs_syscall	137 /* Syscall for Andrew File System */
+#define __NR_setfsuid		138
+#define __NR_setfsgid		139
+#define __NR__llseek		140
+#define __NR_getdents		141
+#define __NR__newselect		142
+#define __NR_flock		143
+#define __NR_msync		144
+#define __NR_readv		145
+#define __NR_writev		146
+#define __NR_getsid		147
+#define __NR_fdatasync		148
+#define __NR__sysctl		149
+#define __NR_mlock		150
+#define __NR_munlock		151
+#define __NR_mlockall		152
+#define __NR_munlockall		153
+#define __NR_sched_setparam		154
+#define __NR_sched_getparam		155
+#define __NR_sched_setscheduler		156
+#define __NR_sched_getscheduler		157
+#define __NR_sched_yield		158
+#define __NR_sched_get_priority_max	159
+#define __NR_sched_get_priority_min	160
+#define __NR_sched_rr_get_interval	161
+#define __NR_nanosleep		162
+#define __NR_mremap		163
+
+#ifdef __ELF__
+
+#define _syscall0(type,name) \
+type name(void) \
+{ \
+register long __res __asm__ ("%d0") = __NR_##name; \
+__asm__ __volatile__ ("trap  #0" \
+                      : "=g" (__res) \
+                      : "0" (__NR_##name) \
+		      : "%d0"); \
+if (__res >= 0) \
+	return (type) __res; \
+errno = -__res; \
+return -1; \
+}
+
+#define _syscall1(type,name,atype,a) \
+type name(atype a) \
+{ \
+register long __res __asm__ ("%d0") = __NR_##name; \
+__asm__ __volatile__ ("movel %2,%/d1\n\t" \
+                      "trap  #0" \
+                      : "=g" (__res) \
+                      : "0" (__NR_##name), "g" ((long)(a)) \
+                      : "%d0", "%d1"); \
+if (__res >= 0) \
+	return (type) __res; \
+errno = -__res; \
+return -1; \
+}
+
+#define _syscall2(type,name,atype,a,btype,b) \
+type name(atype a,btype b) \
+{ \
+register long __res __asm__ ("%d0") = __NR_##name; \
+__asm__ __volatile__ ("movel %2,%/d1\n\t" \
+		      "movel %3,%/d2\n\t" \
+                      "trap  #0" \
+                      : "=g" (__res) \
+                      : "0" (__NR_##name), "g" ((long)(a)), \
+                                          "g" ((long)(b)) \
+                      : "%d0", "%d1", "%d2"); \
+if (__res >= 0) \
+	return (type) __res; \
+errno = -__res; \
+return -1; \
+}
+
+#define _syscall3(type,name,atype,a,btype,b,ctype,c) \
+type name(atype a,btype b,ctype c) \
+{ \
+register long __res __asm__ ("%d0") = __NR_##name; \
+__asm__ __volatile__ ("movel %2,%/d1\n\t" \
+		      "movel %3,%/d2\n\t" \
+		      "movel %4,%/d3\n\t" \
+                      "trap  #0" \
+                      : "=g" (__res) \
+                      : "0" (__NR_##name), "g" ((long)(a)), \
+                                          "g" ((long)(b)), \
+                                          "g" ((long)(c)) \
+                      : "%d0", "%d1", "%d2", "%d3"); \
+if (__res >= 0) \
+	return (type) __res; \
+errno = -__res; \
+return -1; \
+}
+
+#define _syscall4(type,name,atype,a,btype,b,ctype,c,dtype,d) \
+type name (atype a, btype b, ctype c, dtype d) \
+{ \
+register long __res __asm__ ("%d0") = __NR_##name; \
+__asm__ __volatile__ ("movel %2,%/d1\n\t" \
+		      "movel %3,%/d2\n\t" \
+		      "movel %4,%/d3\n\t" \
+		      "movel %5,%/d4\n\t" \
+                      "trap  #0" \
+                      : "=g" (__res) \
+                      : "0" (__NR_##name), "g" ((long)(a)), \
+                                          "g" ((long)(b)), \
+					  "g" ((long)(c)), \
+					  "g" ((long)(d))  \
+                      : "%d0", "%d1", "%d2", "%d3", "%d4"); \
+if (__res >= 0) \
+	return (type) __res; \
+errno = -__res; \
+return -1; \
+}
+
+#define _syscall5(type,name,atype,a,btype,b,ctype,c,dtype,d,etype,e) \
+type name (atype a,btype b,ctype c,dtype d,etype e) \
+{ \
+register long __res __asm__ ("%d0") = __NR_##name; \
+__asm__ __volatile__ ("movel %2,%/d1\n\t" \
+		      "movel %3,%/d2\n\t" \
+		      "movel %4,%/d3\n\t" \
+		      "movel %5,%/d4\n\t" \
+		      "movel %6,%/d5\n\t" \
+                      "trap  #0" \
+                      : "=g" (__res) \
+                      : "0" (__NR_##name), "g" ((long)(a)), \
+                                          "g" ((long)(b)), \
+					  "g" ((long)(c)), \
+					  "g" ((long)(d)), \
+					  "g" ((long)(e))  \
+                      : "%d0", "%d1", "%d2", "%d3", "%d4", "%d5"); \
+if (__res >= 0) \
+	return (type) __res; \
+errno = -__res; \
+return -1; \
+}
+
+#else /* not ELF; a.out */
+
 /* XXX - _foo needs to be __foo, while __NR_bar could be _NR_bar. */
 #define _syscall0(type,name) \
 type name(void) \
@@ -110,5 +392,75 @@
 errno = -__res; \
 return -1; \
 }
+
+#endif /* ELF or otherwise */
+
+#ifdef __KERNEL_SYSCALLS__
+
+/*
+ * we need this inline - forking from kernel space will result
+ * in NO COPY ON WRITE (!!!), until an execve is executed. This
+ * is no problem, but for the stack. This is handled by not letting
+ * main() use the stack at all after fork(). Thus, no function
+ * calls - which means inline code for fork too, as otherwise we
+ * would use the stack upon exit from 'fork()'.
+ *
+ * Actually only pause and fork are needed inline, so that there
+ * won't be any messing with the stack from main(), but we define
+ * some others too.
+ */
+#define __NR__exit __NR_exit
+static inline _syscall0(int,idle)
+static inline _syscall0(int,fork)
+static inline _syscall2(int,clone,unsigned long,flags,char *,usp)
+static inline _syscall0(int,pause)
+static inline _syscall0(int,setup)
+static inline _syscall0(int,sync)
+static inline _syscall0(pid_t,setsid)
+static inline _syscall3(int,write,int,fd,const char *,buf,off_t,count)
+static inline _syscall1(int,dup,int,fd)
+static inline _syscall3(int,execve,const char *,file,char **,argv,char **,envp)
+static inline _syscall3(int,open,const char *,file,int,flag,int,mode)
+static inline _syscall1(int,close,int,fd)
+static inline _syscall1(int,_exit,int,exitcode)
+static inline _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options)
+
+/*
+ * This is the mechanism for creating a new kernel thread.
+ *
+ * NOTE! Only a kernel-only process(ie the swapper or direct descendants
+ * who haven't done an "execve()") should use this: it will work within
+ * a system call from a "real" process, but the process memory space will
+ * not be free'd until both the parent and the child have exited.
+ */
+static inline pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
+{
+	register long retval __asm__ ("d0") = __NR_clone;
+	register long clone_arg __asm__ ("d1") = flags | CLONE_VM;
+
+	__asm__ __volatile__
+	  ("movel %%sp,%%d2\n\t"
+	   "trap #0\n\t"		/* Linux/m68k system call */
+	   "cmpl %%sp,%%d2\n\t"		/* child or parent */
+	   "jeq 1f\n\t"			/* parent - jump */
+	   "movel %3,%%sp@-\n\t"	/* push argument */
+	   "jsr %4@\n\t"		/* call fn */
+	   "movel %2,%0\n\t"		/* exit */
+	   "trap #0\n"
+	   "1:"
+	   : "=d" (retval)
+	   : "0" (__NR_clone), "i" (__NR_exit),
+	     "r" (arg), "a" (fn), "d" (clone_arg)
+	   : "d0", "d2");
+
+	return retval;
+}
+
+static inline pid_t wait(int * wait_stat)
+{
+	return waitpid(-1,wait_stat,0);
+}
+
+#endif
 
 #endif /* _ASM_M68K_UNISTD_H_ */
diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/user.h linux/include/asm-m68k/user.h
--- v1.3.93/linux/include/asm-m68k/user.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-m68k/user.h	Wed Mar 13 22:31:42 1996
@@ -0,0 +1,72 @@
+#ifndef _M68K_USER_H
+#define _M68K_USER_H
+
+#include <asm/page.h>
+#include <linux/ptrace.h>
+/* Core file format: The core file is written in such a way that gdb
+   can understand it and provide useful information to the user (under
+   linux we use the 'trad-core' bfd).  There are quite a number of
+   obstacles to being able to view the contents of the floating point
+   registers, and until these are solved you will not be able to view the
+   contents of them.  Actually, you can read in the core file and look at
+   the contents of the user struct to find out what the floating point
+   registers contain.
+   The actual file contents are as follows:
+   UPAGE: 1 page consisting of a user struct that tells gdb what is present
+   in the file.  Directly after this is a copy of the task_struct, which
+   is currently not used by gdb, but it may come in useful at some point.
+   All of the registers are stored as part of the upage.  The upage should
+   always be only one page.
+   DATA: The data area is stored.  We use current->end_text to
+   current->brk to pick up all of the user variables, plus any memory
+   that may have been malloced.  No attempt is made to determine if a page
+   is demand-zero or if a page is totally unused, we just cover the entire
+   range.  All of the addresses are rounded in such a way that an integral
+   number of pages is written.
+   STACK: We need the stack information in order to get a meaningful
+   backtrace.  We need to write the data from (esp) to
+   current->start_stack, so we round each of these off in order to be able
+   to write an integer number of pages.
+   The minimum core file size is 3 pages, or 12288 bytes.
+*/
+
+struct user_m68kfp_struct {
+	unsigned long  fpregs[8*3];	/* fp0-fp7 registers */
+	unsigned long  fpcntl[3];	/* fp control regs */
+};
+
+/* When the kernel dumps core, it starts by dumping the user struct -
+   this will be used by gdb to figure out where the data and stack segments
+   are within the file, and what virtual addresses to use. */
+struct user{
+/* We start with the registers, to mimic the way that "memory" is returned
+   from the ptrace(3,...) function.  */
+  struct pt_regs regs;		/* Where the registers are actually stored */
+  struct switch_stack regs2;	/* Backward compatibility, sort of */
+/* ptrace does not yet supply these.  Someday.... */
+  int u_fpvalid;		/* True if math co-processor being used. */
+                                /* for this mess. Not yet used. */
+  struct user_m68kfp_struct m68kfp; /* Math Co-processor registers. */
+/* The rest of this junk is to help gdb figure out what goes where */
+  unsigned long int u_tsize;	/* Text segment size (pages). */
+  unsigned long int u_dsize;	/* Data segment size (pages). */
+  unsigned long int u_ssize;	/* Stack segment size (pages). */
+  unsigned long start_code;     /* Starting virtual address of text. */
+  unsigned long start_stack;	/* Starting virtual address of stack area.
+				   This is actually the bottom of the stack,
+				   the top of the stack is always found in the
+				   esp register.  */
+  long int signal;     		/* Signal that caused the core dump. */
+  int reserved;			/* No longer used */
+  struct pt_regs * u_ar0;	/* Used by gdb to help find the values for */
+				/* the registers. */
+  struct user_m68kfp_struct* u_fpstate;	/* Math Co-processor pointer. */
+  unsigned long magic;		/* To uniquely identify a core file */
+  char u_comm[32];		/* User command that was responsible */
+};
+#define NBPG PAGE_SIZE
+#define UPAGES 1
+#define HOST_TEXT_START_ADDR (u.start_code)
+#define HOST_STACK_END_ADDR (u.start_stack + u.u_ssize * NBPG)
+
+#endif
diff -u --recursive --new-file v1.3.93/linux/include/asm-m68k/zorro.h linux/include/asm-m68k/zorro.h
--- v1.3.93/linux/include/asm-m68k/zorro.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-m68k/zorro.h	Wed Mar 20 19:53:26 1996
@@ -0,0 +1,345 @@
+/*
+ * asm-m68k/zorro.h -- Amiga AutoConfig (Zorro) Expansion Device Definitions
+ *
+ * Copyright (C) 1995 Geert Uytterhoeven
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file README.legal in the main directory of this archive
+ * for more details.
+ */
+
+#ifndef _ASM_M68K_ZORRO_H_
+#define _ASM_M68K_ZORRO_H_
+
+#include <linux/config.h>
+#include <asm/amigatypes.h>
+
+
+/*
+ * Defined Board Manufacturers
+ *
+ * Please update arch/m68k/amiga/zorro.c if you make changes here
+ * Many IDs were obtained by using ExpName V1.4 ((C) Richard Körber)
+ * and by looking at the NetBSD-Amiga kernel source
+ */
+
+#define MANUF_MEMPHIS          (0x0100)	/* Memphis */
+#define PROD_STORMBRINGER      (0x00)	/* Stormbringer */
+
+#define MANUF_COMMODORE2       (0x0201)	/* Commodore Germany */
+#define PROD_A2088             (0x01)	/* CBM A2088 Bridgeboard */
+#define PROD_A2386SX           (0x67)	/* CBM A2386-SX Bridgeboard */
+
+#define MANUF_COMMODORE        (0x0202)	/* Commodore USA */
+#define PROD_A2090A            (0x01)	/* CBM A2090/A2090A HD Controller */
+#define PROD_A590              (0x02)	/* CBM A590 SCSI Controller */
+#define PROD_A2091             (0x03)	/* CBM A2091 SCSI Controller */
+#define PROD_A2090B            (0x04)	/* CBM A2090B 2090 Autoboot Card */
+#define PROD_ARCNET            (0x09)	/* CBM A2060 Arcnet Card */
+#define PROD_CBMRAM            (0x0A)	/* CBM A2052/58.RAM | 590/2091.RAM */
+#define PROD_A560RAM           (0x20)	/* CBM A560 Memory Module */
+#define PROD_A2232PROTO        (0x45)	/* CBM A2232 Serial Prototype */
+#define PROD_A2232             (0x46)	/* CBM A2232 Serial Production */
+#define PROD_A2620             (0x50)	/* CBM A2620 68020/RAM Card */
+#define PROD_A2630             (0x51)	/* CBM A2630 68030/RAM Card */
+#define PROD_A4091             (0x54)	/* CBM A4091 SCSI Controller */
+#define PROD_ROMULATOR         (0x60)	/* CBM Romulator Card */
+#define PROD_A3000TESTFIX      (0x61)	/* CBM A3000 Test Fixture */
+#define PROD_A2065             (0x70)	/* CBM A2065 Ethernet Card */
+
+#define MANUF_CARDCO           (0x03EC)	/* Cardco */
+#define PROD_CC_A2410          (0xF5)	/* Cardco A2410 Hires Graphics Card */
+
+#define MANUF_MICROBOTICS      (0x03F2)	/* MicroBotics */
+#define PROD_VXL_30            (0x45)	/* VXL-30 Turbo Board */
+
+#define MANUF_ASDG             (0x03FF)	/* ASDG */
+#define PROD_LAN_ROVER         (0xFE)	/* Lan Rover Ethernet */
+#define PROD_ASDG_DUAL_SERIAL  (0xFF)	/* Dual Serial Card */
+
+#define MANUF_UNIV_OF_LOWELL   (0x0406)	/* University of Lowell */
+#define PROD_A2410             (0x00)	/* CBM A2410 Hires Graphics Card */
+
+#define MANUF_AMERISTAR        (0x041D)	/* Ameristar */
+#define PROD_AMERISTAR2065     (0x01)	/* A2065 Ethernet Card */
+#define PROD_A560              (0x09)	/* Arcnet Card */
+#define PROD_A4066             (0x0A)	/* A4066 Ethernet Card */
+
+#define MANUF_SUPRA            (0x0420)	/* Supra */
+#define PROD_WORDSYNC          (0x0C)	/* Supra Wordsync SCSI Controller */
+#define PROD_WORDSYNC_II       (0x0D)	/* Supra Wordsync II SCSI Controller */
+#define PROD_SUPRA_2400MODEM   (0x10)	/* Supra 2400 Modem */
+
+#define MANUF_CSA              (0x0422)	/* CSA */
+#define PROD_MAGNUM            (0x11)	/* Magnum 40 SCSI Controller */
+#define PROD_12GAUGE           (0x15)	/* 12 Gauge SCSI Controller */
+
+#define MANUF_HACKER           (0x07DB)	/* Test only: no product definitions */
+
+#define MANUF_POWER_COMPUTING  (0x07DC)	/* Power Computing */
+#define PROD_DKB_1240          (0x12)	/* Viper II Turbo Board (DKB 1240) */
+
+#define MANUF_GVP              (0x07E1)	/* Great Valley Products */
+#define PROD_GVPIISCSI         (0x0B)	/* GVP Series II SCSI Controller */
+#define PROD_GVPIISCSI_2       (0x09)	/* evidence that the driver works
+					   for this product code also */
+#define PROD_GVPIIRAM          (0x0A)	/* GVP Series II RAM */
+#define PROD_GFORCE_040_SCSI   (0x16)	/* GForce 040 with SCSI (new) */
+#define PROD_GVPIV_24          (0x20)	/* GVP IV-24 Graphics Board */
+#define PROD_GVP               (0x0B)	/* This code is used by a wide range of
+					   GVP products - use the epc to
+					   identify it correctly */
+/* #define PROD_GVPIO_EXT      (0xFF)*/	/* GVP I/O Extender */
+
+#define MANUF_PPI              (0x07EA)	/* Progressive Peripherals Inc. */
+#define PROD_MERCURY           (0x00)	/* Mercury Turbo Board */
+#define PROD_PPS_A3000_040     (0x01)	/* PP&S A3000 68040 Turbo Board */
+#define PROD_PPS_A2000_040     (0x69)	/* PP&S A2000 68040 Turbo Board */
+#define PROD_ZEUS              (0x96)	/* Zeus SCSI Controller */
+#define PROD_PPS_A500_040      (0xBB)	/* PP&S A500 68040 Turbo Board */
+
+#define MANUF_BSC              (0x07FE)	/* BSC */
+#define PROD_ALF_3_SCSI        (0x03)	/* BSC ALF 3 SCSI Controller */
+
+#define MANUF_C_LTD            (0x0802)	/* C Ltd. */
+#define PROD_KRONOS_SCSI       (0x04)	/* Kronos SCSI Controller */
+
+#define MANUF_JOCHHEIM         (0x0804)	/* Jochheim */
+#define PROD_JOCHHEIM_RAM      (0x01)	/* Jochheim RAM */
+
+#define MANUF_CHECKPOINT       (0x0807)	/* Checkpoint Technologies */
+#define PROD_SERIAL_SOLUTION   (0x00)	/* Serial Solution */
+
+#define MANUF_GOLEM            (0x0819)	/* Golem */
+#define PROD_GOLEM_SCSI_II     (0x02)	/* Golem SCSI-II Controller */
+
+#define MANUF_HARDITAL_SYNTHES (0x0817)	/* Hardital Synthesis */
+#define PROD_HARDITAL_SCSI     (0x01)	/* Hardital Synthesis SCSI Controller */
+
+#define MANUF_BSC2             (0x082C)	/* BSC */
+#define PROD_OKTAGON_SCSI      (0x05)	/* BSC Oktagon 2008 SCSI Controller */
+#define PROD_TANDEM            (0x06)	/* BSC Tandem */
+#define PROD_OKTAGON_RAM       (0x08)	/* BSC Oktagon 2008 RAM */
+#define PROD_MULTIFACE_I       (0x10)	/* Alfa Data MultiFace I */
+#define PROD_MULTIFACE_II      (0x11)	/* Alfa Data MultiFace II */
+#define PROD_MULTIFACE_III     (0x12)	/* Alfa Data MultiFace III */
+#define PROD_ISDN_MASTER       (0x40)	/* BSC ISDN Master */
+
+#define MANUF_ADV_SYS_SOFT     (0x0836)	/* Advanced Systems & Software */
+#define PROD_NEXUS_SCSI        (0x01)	/* Nexus SCSI Controller */
+#define PROD_NEXUS_RAM         (0x08)	/* Nexus RAM */
+
+#define MANUF_IVS              (0x0840)	/* IVS */
+#define PROD_TRUMPCARD_500     (0x30)	/* Trumpcard 500 SCSI Controller */
+#define PROD_TRUMPCARD         (0x34)	/* Trumpcard SCSI Controller */
+#define PROD_VECTOR            (0xF3)	/* Vector SCSI Controller */
+
+#define MANUF_XPERT_PRODEV     (0x0845)	/* XPert/ProDev */
+#define PROD_MERLIN_RAM        (0x03)	/* Merlin Graphics Board */
+#define PROD_MERLIN_REG        (0x04)
+
+#define MANUF_HYDRA_SYSTEMS    (0x0849)	/* Hydra Systems */
+#define PROD_AMIGANET          (0x01)	/* Amiganet Board */
+
+#define MANUF_DIG_MICRONICS    (0x0851)	/* Digital Micronics Inc */
+#define PROD_DMI_RESOLVER      (0x01)	/* DMI Resolver Graphics Board */
+
+#define MANUF_HELFRICH1        (0x0861)	/* Helfrich */
+#define PROD_RAINBOW3          (0x21)	/* Rainbow3 Graphics Board */
+
+#define MANUF_SW_RESULT_ENTS   (0x0866)	/* Software Result Enterprises */
+#define PROD_GG2PLUS           (0x01)	/* GG2+ Bus Converter */
+
+#define MANUF_VILLAGE_TRONIC   (0x0877)	/* Village Tronic */
+#define PROD_PICASSO_II_RAM    (0x0B)	/* Picasso II Graphics Board */
+#define PROD_PICASSO_II_REG    (0x0C)
+#define PROD_ARIADNE           (0xC9)	/* Ariadne Ethernet */
+
+#define MANUF_UTILITIES_ULTD   (0x087B)	/* Utilities Unlimited */
+#define PROD_EMPLANT_DELUXE    (0x15)	/* Emplant Deluxe SCSI Controller */
+#define PROD_EMPLANT_DELUXE2   (0x20)	/* Emplant Deluxe SCSI Controller */
+
+#define MANUF_MTEC             (0x0890)	/* MTEC Germany */
+#define PROD_MTEC_68030        (0x03)	/* 68030 Turbo Board */
+#define PROD_MTEC_T1230        (0x20)	/* MTEC T1230/28 Turbo Board */
+
+#define MANUF_GVP2             (0x0891)	/* Great Valley Products */
+#define PROD_SPECTRUM_RAM      (0x01)	/* GVP Spectrum Graphics Board */
+#define PROD_SPECTRUM_REG      (0x02)
+
+#define MANUF_HELFRICH2        (0x0893)	/* Helfrich */
+#define PROD_PICCOLO_RAM       (0x05)	/* Piccolo Graphics Board */
+#define PROD_PICCOLO_REG       (0x06)
+#define PROD_PEGGY_PLUS        (0x07)	/* PeggyPlus MPEG Decoder Board */
+#define PROD_SD64_RAM          (0x0A)	/* SD64 Graphics Board */
+#define PROD_SD64_REG          (0x0B)
+
+#define MANUF_MACROSYSTEMS     (0x089B)	/* MacroSystems USA */
+#define PROD_WARP_ENGINE       (0x13)	/* Warp Engine SCSI Controller */
+
+#define MANUF_HARMS_PROF       (0x0A00)	/* Harms Professional */
+#define PROD_3500_TURBO        (0xD0)	/* 3500 Turbo board */
+
+#define MANUF_VORTEX           (0x2017)	/* Vortex */
+#define PROD_GOLDEN_GATE_386   (0x07)	/* Golden Gate 80386 Board */
+#define PROD_GOLDEN_GATE_RAM   (0x08)	/* Golden Gate RAM */
+#define PROD_GOLDEN_GATE_486   (0x09)	/* Golden Gate 80486 Board */
+
+#define MANUF_DATAFLYER        (0x2062)	/* DataFlyer */
+#define PROD_DATAFLYER_4000SX  (0x01)	/* DataFlyer 4000SX SCSI Controller */
+
+#define MANUF_PHASE5           (0x2140)	/* Phase5 */
+#define PROD_FASTLANE_RAM      (0x0A)	/* FastLane RAM */
+#define PROD_FASTLANE_SCSI     (0x0B)	/* FastLane/Blizzard 1230-II SCSI */
+#define PROD_BLIZZARD_1230_III (0x0D)	/* Blizzard 1230-III Turbo Board */
+#define PROD_BLIZZARD_1230_IV  (0x11)	/* Blizzard 1230-IV Turbo Board */
+#define PROD_CYBERVISION       (0x22)	/* CyberVision64 Graphics Board */
+
+#define MANUF_APOLLO           (0x2222)	/* Apollo */
+#define PROD_AT_APOLLO         (0x22)	/* AT-Apollo */
+#define PROD_APOLLO_TURBO      (0x23)	/* Apollo Turbo Board */
+
+#define MANUF_UWE_GERLACH      (0x3FF7)	/* Uwe Gerlach */
+#define PROD_UG_RAM_ROM        (0xd4)	/* RAM/ROM */
+
+#define MANUF_MACROSYSTEMS2    (0x4754)	/* MacroSystems Germany */
+#define PROD_MAESTRO           (0x03)	/* Maestro */
+#define PROD_VLAB              (0x04)	/* VLab */
+#define PROD_MAESTRO_PRO       (0x05)	/* Maestro Pro */
+#define PROD_RETINA_Z2         (0x06)	/* Retina Z2 Graphics Board */
+#define PROD_MULTI_EVOLUTION   (0x08)	/* MultiEvolution */
+#define PROD_RETINA_Z3         (0x10)	/* Retina Z3 Graphics Board */
+
+
+/* Illegal Manufacturer IDs. These do NOT appear in amiga/zorro.c! */
+
+#define MANUF_HACKER_INC       (0x07DB)	/* Hacker Inc. */
+#define PROD_HACKER_SCSI       (0x01)	/* Hacker Inc. SCSI Controller */
+
+#define MANUF_RES_MNGT_FORCE   (0x07DB)	/* Resource Management Force */
+#define PROD_QUICKNET          (0x02)	/* QuickNet Ethernet */
+
+
+/*
+ * GVP's identifies most of their product through the 'extended
+ * product code' (epc). The epc has to be and'ed with the GVPEPCMASK
+ * before the identification.
+ */
+
+#define GVP_EPCMASK (0xf8)
+
+enum GVP_ident {
+  GVP_GFORCE_040      = 0x20,
+  GVP_GFORCE_040_SCSI = 0x30,
+  GVP_A1291_SCSI      = 0x40,
+  GVP_COMBO_R4        = 0x60,
+  GVP_COMBO_R4_SCSI   = 0x70,
+  GVP_PHONEPAK        = 0x78,
+  GVP_IOEXT           = 0x98,
+  GVP_GFORCE_030      = 0xa0,
+  GVP_GFORCE_030_SCSI = 0xb0,
+  GVP_A530            = 0xc0,
+  GVP_A530_SCSI       = 0xd0,
+  GVP_COMBO_R3        = 0xe0,
+  GVP_COMBO_R3_SCSI   = 0xf0,
+  GVP_SERIESII        = 0xf8,
+};
+
+enum GVP_flags {
+  GVP_IO       = 0x01,
+  GVP_ACCEL    = 0x02,
+  GVP_SCSI     = 0x04,
+  GVP_24BITDMA = 0x08,
+  GVP_25BITDMA = 0x10,
+  GVP_NOBANK   = 0x20,
+  GVP_14MHZ    = 0x40,
+};
+
+
+struct Node {
+    struct  Node *ln_Succ;	/* Pointer to next (successor) */
+    struct  Node *ln_Pred;	/* Pointer to previous (predecessor) */
+    u_char  ln_Type;
+    char    ln_Pri;		/* Priority, for sorting */
+    char    *ln_Name;		/* ID string, null terminated */
+};
+
+struct ExpansionRom {
+    /* -First 16 bytes of the expansion ROM */
+    u_char	er_Type;	/* Board type, size and flags */
+    u_char	er_Product;	/* Product number, assigned by manufacturer */
+    u_char	er_Flags;	/* Flags */
+    u_char	er_Reserved03;	/* Must be zero ($ff inverted) */
+    u_short	er_Manufacturer; /* Unique ID,ASSIGNED BY COMMODORE-AMIGA! */
+    u_long	er_SerialNumber; /* Available for use by manufacturer */
+    u_short	er_InitDiagVec;	/* Offset to optional "DiagArea" structure */
+    u_char	er_Reserved0c;
+    u_char	er_Reserved0d;
+    u_char	er_Reserved0e;
+    u_char	er_Reserved0f;
+};
+
+/* er_Type board type bits */
+#define ERT_TYPEMASK	0xc0
+#define ERT_ZORROII	0xc0
+#define ERT_ZORROIII	0x80
+
+/* other bits defined in er_Type */
+#define ERTB_MEMLIST	5		/* Link RAM into free memory list */
+#define ERTF_MEMLIST	(1<<5)
+
+struct ConfigDev {
+    struct Node 	cd_Node;
+    u_char		cd_Flags;	/* (read/write) */
+    u_char		cd_Pad; 	/* reserved */
+    struct ExpansionRom cd_Rom; 	/* copy of board's expansion ROM */
+    void		*cd_BoardAddr;	/* where in memory the board was placed */
+    u_long		cd_BoardSize;	/* size of board in bytes */
+    u_short		cd_SlotAddr;	/* which slot number (PRIVATE) */
+    u_short		cd_SlotSize;	/* number of slots (PRIVATE) */
+    void		*cd_Driver;	/* pointer to node of driver */
+    struct ConfigDev	*cd_NextCD;	/* linked list of drivers to config */
+    u_long		cd_Unused[4];	/* for whatever the driver wants */
+};
+
+
+/*
+ * Zorro Functions
+ */
+
+extern int zorro_find(int manuf, int prod, int part, int index);
+extern struct ConfigDev *zorro_get_board(int key);
+extern void zorro_config_board(int key, int part);
+extern void zorro_unconfig_board(int key, int part);
+
+
+/*
+ * Bitmask indicating portions of available Zorro II RAM that are unused
+ * by the system. Every bit represents a 64K chunk, for a maximum of 8MB
+ * (128 chunks, physical 0x00200000-0x009fffff).
+ *
+ * If you want to use (= allocate) portions of this RAM, you should clear
+ * the corresponding bits.
+ */
+
+extern u_long zorro_unused_z2ram[4];
+
+#define Z2RAM_START		(0x00200000)
+#define Z2RAM_END		(0x00a00000)
+#define Z2RAM_SIZE		(0x00800000)
+#define Z2RAM_CHUNKSIZE		(0x00010000)
+#define Z2RAM_CHUNKMASK		(0x0000ffff)
+#define Z2RAM_CHUNKSHIFT	(16)
+
+
+/*
+ * Verbose Board Identification
+ */
+
+#ifdef CONFIG_ZORRO
+extern void zorro_identify(void);
+extern int zorro_get_list(char *buffer);
+#endif CONFIG_ZORRO
+
+
+#endif /* _ASM_M68K_ZORRO_H_ */
diff -u --recursive --new-file v1.3.93/linux/include/asm-sparc/pgtable.h linux/include/asm-sparc/pgtable.h
--- v1.3.93/linux/include/asm-sparc/pgtable.h	Sun Apr 21 19:22:12 1996
+++ linux/include/asm-sparc/pgtable.h	Mon Apr 22 10:59:40 1996
@@ -1,4 +1,4 @@
-/* $Id: pgtable.h,v 1.45 1996/04/18 03:29:21 davem Exp $ */
+/* $Id: pgtable.h,v 1.46 1996/04/21 11:01:53 davem Exp $ */
 #ifndef _SPARC_PGTABLE_H
 #define _SPARC_PGTABLE_H
 
diff -u --recursive --new-file v1.3.93/linux/include/asm-sparc/smp.h linux/include/asm-sparc/smp.h
--- v1.3.93/linux/include/asm-sparc/smp.h	Sun Apr 21 19:22:12 1996
+++ linux/include/asm-sparc/smp.h	Mon Apr 22 10:59:40 1996
@@ -6,10 +6,7 @@
 #ifndef _SPARC_SMP_H
 #define _SPARC_SMP_H
 
-#ifdef __SMP__
-
 #ifndef __ASSEMBLY__
-
 /* PROM provided per-processor information we need
  * to start them all up.
  */
@@ -18,6 +15,11 @@
 	int prom_node;
 	int mid;
 };
+#endif /* !(__ASSEMBLY__) */
+
+#ifdef __SMP__
+
+#ifndef __ASSEMBLY__
 
 extern struct prom_cpuinfo linux_cpus[NCPUS];
 
diff -u --recursive --new-file v1.3.93/linux/include/linux/affs_fs.h linux/include/linux/affs_fs.h
--- v1.3.93/linux/include/linux/affs_fs.h	Thu Jan  1 02:00:00 1970
+++ linux/include/linux/affs_fs.h	Fri Apr  5 16:04:01 1996
@@ -0,0 +1,101 @@
+
+#ifndef _AFFS_FS_H
+#define _AFFS_FS_H
+
+#include <linux/types.h>
+/*
+ * The affs filesystem constants/structures
+ */
+
+#define AFFS_BLOCK_BITS 9
+#define AFFS_BLOCK_SIZE 512
+
+#define AFFS_BUFFER_BITS 9
+#define AFFS_BUFFER_SIZE 512
+
+#define AFFS_BLOCK_NUMBER(X) (X<<1)
+
+#define AFFS_SUPER_MAGIC 0xadff
+
+/* Get the filesystem block size given an inode. */
+#define AFFS_I2BSIZE(inode) ((inode)->i_sb->u.affs_sb.s_block_size)
+
+/* Read the device block that contains filesystem block ("sector"). */
+
+static inline struct buffer_head *affs_sread(int dev,int sector,void **start)
+{
+ 	struct buffer_head *bh;
+	int mask;
+
+	bh = bread (dev, sector >> (BLOCK_SIZE_BITS - AFFS_BLOCK_BITS), 1024);
+	if (!bh)
+		return NULL;
+	mask = (1 << (BLOCK_SIZE_BITS - AFFS_BLOCK_BITS)) - 1;
+    	*start = bh->b_data + ((sector & mask) << AFFS_BLOCK_BITS);
+	return bh;
+}
+
+/* Use affs_sread() to read a "sector", but take the filesystems partition
+   offset into account. */
+
+static inline struct buffer_head *affs_pread(struct inode *inode,
+					     int sector, void **start)
+{
+	int offset = inode->i_sb->u.affs_sb.s_partition_offset;
+	return affs_sread (inode->i_dev, sector + offset, start);
+}
+
+/* amigaffs.c prototypes */
+
+extern int affs_get_key_entry (int bsize, void *data, int entry_pos);
+extern int affs_find_next_hash_entry (int bsize, void *dir_data, int *hash_pos);
+extern int affs_get_fh_hash_link (int bsize, void *fh_data);
+extern int affs_get_file_name (int bsize, void *fh_data, char **name);
+extern int affs_get_extension (int bsize, void *fh_data);
+extern int affs_checksum_block (int bsize, void *data, int *ptype, int *stype);
+
+/* The stuff that follows may be totally unneeded. I have not checked to see 
+ which prototypes we are still using.  */
+
+extern int affs_open(struct inode * inode, struct file * filp);
+extern void affs_release(struct inode * inode, struct file * filp);
+extern int affs_lookup(struct inode * dir,const char * name, int len,
+	struct inode ** result);
+extern unsigned long affs_count_free_inodes(struct super_block *sb);
+extern int affs_new_block(int dev);
+extern int affs_free_block(int dev, int block);
+extern int affs_bmap(struct inode *,int);
+
+extern void affs_put_super(struct super_block *);
+extern struct super_block *affs_read_super(struct super_block *,void *,int);
+extern void affs_read_inode(struct inode *);
+extern void affs_put_inode(struct inode *);
+extern void affs_statfs(struct super_block *, struct statfs *, int);
+extern int affs_parent_ino(struct inode *dir);
+extern int affs_lseek(struct inode *, struct file *, off_t, int);
+extern int affs_read(struct inode *, struct file *, char *, int);
+extern int affs_file_read(struct inode *, struct file *, char *, int);
+extern int init_affs_fs(void);
+
+extern struct inode_operations affs_file_inode_operations;
+extern struct inode_operations affs_dir_inode_operations;
+extern struct inode_operations affs_symlink_inode_operations;
+extern struct inode_operations affs_chrdev_inode_operations;
+extern struct inode_operations affs_blkdev_inode_operations;
+
+extern struct file_operations affs_file_operations;
+extern struct file_operations affs_dir_operations;
+
+/* The following macros are used to check for memory leaks. */
+#ifdef LEAK_CHECK
+#define free_s leak_check_free_s
+#define malloc leak_check_malloc
+#define bread leak_check_bread
+#define brelse leak_check_brelse
+extern void * leak_check_malloc(unsigned int size);
+extern void leak_check_free_s(void * obj, int size);
+extern struct buffer_head * leak_check_bread(int dev, int block, int size);
+extern void leak_check_brelse(struct buffer_head * bh);
+#endif /* LEAK_CHECK */
+
+#endif
diff -u --recursive --new-file v1.3.93/linux/include/linux/affs_fs_i.h linux/include/linux/affs_fs_i.h
--- v1.3.93/linux/include/linux/affs_fs_i.h	Thu Jan  1 02:00:00 1970
+++ linux/include/linux/affs_fs_i.h	Sun Feb 25 19:22:45 1996
@@ -0,0 +1,12 @@
+#ifndef _AFFS_FS_I
+#define _AFFS_FS_I
+
+/*
+ * affs fs inode data in memory
+ */
+struct affs_inode_info {
+	int i_protect;	/* unused attribute bits */
+	int i_parent;   /* parent ino */
+};
+
+#endif
diff -u --recursive --new-file v1.3.93/linux/include/linux/affs_fs_sb.h linux/include/linux/affs_fs_sb.h
--- v1.3.93/linux/include/linux/affs_fs_sb.h	Thu Jan  1 02:00:00 1970
+++ linux/include/linux/affs_fs_sb.h	Sun Feb 25 19:22:45 1996
@@ -0,0 +1,37 @@
+#ifndef _AFFS_FS_SB
+#define _AFFS_FS_SB
+
+/*
+ * super-block data in memory
+ *
+ * Block numbers are for FFS-sized (normally 512 bytes) blocks.
+ *
+ */
+
+/* Mount options */
+
+struct affs_options {
+	int offset;
+	int size;
+	int root;
+	int nocase:1;			/* Ignore case in filenames. */
+	int conv_links:1;		/* convert pathnames symlinks point to */
+};
+
+struct affs_sb_info {
+	int s_partition_offset;         /* Offset to start in blocks. */
+	int s_partition_size;		/* Partition size in blocks. */
+	int s_root_block;		/* Absolute FFS root block number. */
+	int s_block_size;		/* Block size in bytes. */
+	char s_volume_name[42];
+	struct affs_options s_options;
+};
+
+#endif
+
+
+
+
+
+
+
diff -u --recursive --new-file v1.3.93/linux/include/linux/console.h linux/include/linux/console.h
--- v1.3.93/linux/include/linux/console.h	Thu Jan  1 02:00:00 1970
+++ linux/include/linux/console.h	Fri Apr  5 17:46:12 1996
@@ -0,0 +1,122 @@
+/*
+ *  linux/include/linux/console.h
+ *
+ *  Copyright (C) 1993        Hamish Macdonald
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file README.legal in the main directory of this archive
+ * for more details.
+ *
+ * Changed:
+ * 10-Mar-94: Arno Griffioen: Conversion for vt100 emulator port from PC LINUX
+ */
+
+#ifndef _LINUX_CONSOLE_H_
+#define _LINUX_CONSOLE_H_ 1
+
+#define NPAR 16
+
+struct vc_data {
+	unsigned long	vc_screenbuf_size;
+	unsigned short	vc_num;			/* Console number */
+	unsigned short	vc_video_erase_char;	/* Background erase character */
+	unsigned char	vc_attr;		/* Current attributes */
+	unsigned char	vc_def_color;		/* Default colors */
+	unsigned char	vc_color;		/* Foreground & background */
+	unsigned char	vc_s_color;		/* Saved foreground & background */
+	unsigned char	vc_ulcolor;		/* Colour for underline mode */
+	unsigned char	vc_halfcolor;		/* Colour for half intensity mode */
+	unsigned long	vc_origin;		/* Used for EGA/VGA fast scroll	*/
+	unsigned long	vc_scr_end;		/* Used for EGA/VGA fast scroll	*/
+	unsigned short	*vc_pos;
+	unsigned long	vc_x,vc_y;
+	unsigned long	vc_top,vc_bottom;
+	unsigned long	vc_rows,vc_cols;
+	unsigned long	vc_size_row;
+	unsigned long	vc_state;
+	unsigned long	vc_npar,vc_par[NPAR];
+	unsigned short	*vc_video_mem_start;
+	unsigned long	vc_video_mem_end;	/* End of video RAM (sort of)	*/
+	unsigned long	vc_saved_x;
+	unsigned long	vc_saved_y;
+	/* mode flags */
+	unsigned long	vc_charset	: 1;	/* Character set G0 / G1 */
+	unsigned long	vc_s_charset	: 1;	/* Saved character set */
+	unsigned long	vc_disp_ctrl	: 1;	/* Display chars < 32? */
+	unsigned long	vc_toggle_meta	: 1;	/* Toggle high bit? */
+	unsigned long	vc_decscnm	: 1;	/* Screen Mode */
+	unsigned long	vc_decom	: 1;	/* Origin Mode */
+	unsigned long	vc_decawm	: 1;	/* Autowrap Mode */
+	unsigned long	vc_deccm	: 1;	/* Cursor Visible */
+	unsigned long	vc_decim	: 1;	/* Insert Mode */
+	unsigned long	vc_deccolm	: 1;	/* 80/132 Column Mode */
+	/* attribute flags */
+	unsigned long	vc_intensity	: 2;	/* 0=half-bright, 1=normal, 2=bold */
+	unsigned long	vc_underline	: 1;
+	unsigned long	vc_blink	: 1;
+	unsigned long	vc_reverse	: 1;
+	unsigned long	vc_s_intensity	: 2;	/* saved rendition */
+	unsigned long	vc_s_underline	: 1;
+	unsigned long	vc_s_blink	: 1;
+	unsigned long	vc_s_reverse	: 1;
+	/* misc */
+	unsigned long	vc_ques		: 1;
+	unsigned long	vc_need_wrap	: 1;
+	unsigned long	vc_can_do_color	: 1;
+	unsigned long	vc_has_scrolled : 1;	/* Info for unblank_screen */
+	unsigned long	vc_kmalloced	: 1;	/* kfree_s() needed */
+	unsigned long	vc_report_mouse : 2;
+	unsigned char	vc_utf		: 1;	/* Unicode UTF-8 encoding */
+	unsigned char	vc_utf_count;
+	unsigned long	vc_utf_char;
+	unsigned long	vc_tab_stop[5];		/* Tab stops. 160 columns. */
+	unsigned short  *vc_translate;
+	unsigned char 	vc_G0_charset;
+	unsigned char 	vc_G1_charset;
+	unsigned char 	vc_saved_G0;
+	unsigned char 	vc_saved_G1;
+	unsigned int	vc_bell_pitch;		/* Console bell pitch */
+	unsigned int	vc_bell_duration;	/* Console bell duration */
+	struct consw 	*vc_sw;
+	/* additional information is in vt_kern.h */
+};
+
+/*
+ * this is what the terminal answers to a ESC-Z or csi0c query.
+ */
+#define VT100ID "\033[?1;2c"
+#define VT102ID "\033[?6c"
+
+/* DPC: 1994-04-13 !!! con_putcs is new entry !!! */
+
+struct consw {
+    unsigned long (*con_startup)(unsigned long, char **);
+    void   (*con_init)(struct vc_data *);
+    int    (*con_deinit)(struct vc_data *);
+    int    (*con_clear)(struct vc_data *, int, int, int, int);
+    int    (*con_putc)(struct vc_data *, int, int, int);
+    int    (*con_putcs)(struct vc_data *, const char *, int, int, int);
+    int    (*con_cursor)(struct vc_data *, int);
+    int    (*con_scroll)(struct vc_data *, int, int, int, int);
+    int    (*con_bmove)(struct vc_data *, int, int, int, int, int, int);
+    int    (*con_switch)(struct vc_data *);
+    int    (*con_blank)(int);
+};
+
+extern struct consw *conswitchp;
+
+/* flag bits */
+#define CON_INITED  (1)
+
+/* scroll */
+#define SM_UP       (1)
+#define SM_DOWN     (2)
+#define SM_LEFT     (3)
+#define SM_RIGHT    (4)
+
+/* cursor */
+#define CM_DRAW     (1)
+#define CM_ERASE    (2)
+#define CM_MOVE     (3)
+
+#endif /* linux/console.h */
diff -u --recursive --new-file v1.3.93/linux/include/linux/fb.h linux/include/linux/fb.h
--- v1.3.93/linux/include/linux/fb.h	Thu Jan  1 02:00:00 1970
+++ linux/include/linux/fb.h	Fri Apr 19 08:14:38 1996
@@ -0,0 +1,293 @@
+#ifndef _LINUX_FB_H
+#define _LINUX_FB_H
+
+/* Definitions of frame buffers						*/
+
+#ifdef __KERNEL__
+#include <linux/config.h>
+#include <linux/fs.h>
+#endif
+
+/* ioctls
+   0x46 is 'F'								*/
+#define FBIOGET_VSCREENINFO 	0x4600
+#define FBIOPUT_VSCREENINFO 	0x4601
+#define FBIOGET_FSCREENINFO 	0x4602
+#define FBIOGETCMAP		0x4604
+#define FBIOPUTCMAP		0x4605
+#define FBIOPAN_DISPLAY         0x4606
+
+#define FB_TYPE_PACKED_PIXELS		0	/* Packed Pixels	*/
+#define FB_TYPE_PLANES			1	/* Non interleaved planes */
+#define FB_TYPE_INTERLEAVED_PLANES	2	/* Interleaved planes	*/
+
+#define FB_VISUAL_MONO01		0	/* Monochr. 1=Black 0=White */
+#define FB_VISUAL_MONO10		1	/* Monochr. 1=White 0=Black */
+#define FB_VISUAL_TRUECOLOR		2	/* True color	*/
+#define FB_VISUAL_PSEUDOCOLOR		3	/* Pseudo color (like atari) */
+#define FB_VISUAL_DIRECTCOLOR		4	/* Direct color */
+#define FB_VISUAL_STATIC_PSEUDOCOLOR	5	/* Pseudo color readonly */
+#define FB_VISUAL_STATIC_DIRECTCOLOR	6	/* Direct color readonly */
+
+struct fb_fix_screeninfo {
+	char id[16];			/* identification string eg "TT Builtin" */
+	unsigned long smem_start;	/* Start of frame buffer mem */
+	unsigned long smem_len;		/* Length of frame buffer mem */	
+	int type;			/* see FB_TYPE_* 		*/
+	int type_aux;			/* Interleave for interleaved Planes */
+	int visual;			/* see FB_VISUAL_*  		*/ 
+	u_short xpanstep;               /* zero if no hardware panning  */
+        u_short ypanstep;               /* zero if no hardware panning  */
+        u_short ywrapstep;              /* zero if no hardware ywrap    */
+        short reserved[11];             /* Reserved for future compatibility */
+};
+
+struct fb_bitfield {
+	int offset;			/* beginning of bitfield	*/
+	int length;			/* length of bitfield		*/
+	int msb_right;			/* != 0 : Most significant bit is */ 
+					/* right */ 
+};
+
+#define FB_NONSTD_HAM		1	/* Hold-And-Modify (HAM)        */
+
+#define FB_ACTIVATE_NOW		0	/* set values immediately (or vbl)*/
+#define FB_ACTIVATE_NXTOPEN	1	/* activate on next open	*/
+#define FB_ACTIVATE_TEST	2	/* don't set, round up impossible */
+#define FB_ACTIVATE_MASK       15
+					/* values			*/
+#define FB_ACTIVATE_VBL	       16	/* activate values on next vbl  */
+#define FB_CHANGE_CMAP_VBL     32	/* change colormap on vbl	*/
+
+#define FB_ACCEL_NONE		0	/* no hardware accelerator	*/
+#define FB_ACCEL_ATARIBLITT	1	/* Atari Blitter		*/
+#define FB_ACCEL_AMIGABLITT	2	/* Amiga Blitter                */
+#define FB_ACCEL_CYBERVISION	3	/* Cybervision64 (S3 Trio64)    */
+
+#define FB_SYNC_HOR_HIGH_ACT	1	/* horizontal sync high active	*/
+#define FB_SYNC_VERT_HIGH_ACT	2	/* vertical sync high active	*/
+#define FB_SYNC_EXT		4	/* external sync		*/
+#define FB_SYNC_COMP_HIGH_ACT	8	/* composite sync high active   */
+#define FB_SYNC_BROADCAST	16	/* broadcast video timings      */
+					/* vtotal = 144d/288n/576i => PAL  */
+					/* vtotal = 121d/242n/484i => NTSC */
+
+#define FB_VMODE_NONINTERLACED  0	/* non interlaced */
+#define FB_VMODE_INTERLACED 	1	/* interlaced	*/
+#define FB_VMODE_DOUBLE		2	/* double scan */
+#define FB_VMODE_MASK		255
+
+#define FB_VMODE_YWRAP		256	/* ywrap instead of panning     */
+
+struct fb_var_screeninfo {
+	int xres;			/* visible resolution		*/
+	int yres;
+	int xres_virtual;		/* virtual resolution		*/
+	int yres_virtual;
+	int xoffset;			/* offset from virtual to visible */
+	int yoffset;			/* resolution			*/
+
+	int bits_per_pixel;		/* guess what 			*/
+	int grayscale;			/* != 0 Graylevels instead of colors */
+
+	struct fb_bitfield red;		/* bitfield in fb mem if true color, */
+	struct fb_bitfield green;	/* else only length is significant */
+	struct fb_bitfield blue;
+	struct fb_bitfield transp;	/* transparency			*/	
+
+	int nonstd;			/* != 0 Non standard pixel format */
+
+	int activate;			/* see FB_ACTIVATE_* 		*/
+
+	int height;			/* height of picture in mm    */
+	int width;			/* width of picture in mm     */
+
+	int accel;			/* see FB_ACCEL_*		*/
+
+	/* Timing: All values in pixclocks, except pixclock (of course) */
+	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	*/
+	int sync;			/* see FB_SYNC_*		*/
+	int vmode;			/* see FB_VMODE_*		*/
+	int reserved[6];		/* Reserved for future compatibility */
+};
+
+struct fb_cmap {
+	int start;			/* First entry	*/
+	int len;			/* Number of entries */
+	unsigned short *red;		/* Red values	*/
+	unsigned short *green;
+	unsigned short *blue;
+	unsigned short *transp;		/* transparency, can be NULL */
+};
+
+#ifdef __KERNEL__
+
+struct fb_ops {
+	/* get non setable parameters	*/
+	int (*fb_get_fix) (struct fb_fix_screeninfo *, int); 
+	/* get setable parameters	*/
+	int (*fb_get_var) (struct fb_var_screeninfo *, int);		
+	/* set setable parameters	*/
+	int (*fb_set_var) (struct fb_var_screeninfo *, int);		
+	/* get colormap			*/
+	int (*fb_get_cmap) (struct fb_cmap *, int, int);
+	/* set colormap			*/
+	int (*fb_set_cmap) (struct fb_cmap *, int, int);
+	/* pan display                   */
+        int (*fb_pan_display) (struct fb_var_screeninfo *, int);
+        /* perform fb specific ioctl	*/
+	int (*fb_ioctl)(struct inode *, struct file *, unsigned int,
+			unsigned long, int);
+};
+
+int register_framebuffer(char *, int *, struct fb_ops *, int, 
+			 struct fb_var_screeninfo *);
+int unregister_framebuffer(int);
+
+   /*
+    *    This is the interface between the low-level console driver and the
+    *    low-level frame buffer device
+    */
+
+struct display {
+/*
+ * As long as the old Amiga screen driver is being used, we have to
+ * include these old parameters.
+ */
+#if defined(CONFIG_AMIGA)
+  ushort scr_max_height;	/* screen dimensions */
+  ushort scr_max_width;
+  ushort scr_height;
+  ushort scr_width;
+  ushort scr_depth;
+  int bytes_per_row;		/* offset to one line below */
+  
+  ulong crsrcol;
+
+  ushort scroll_latch;		/* Vblank support for hardware scroll */
+  ushort y_wrap;
+  ushort cursor_latch;		/* Hardware cursor */
+  ushort *cursor, *dummy;
+  ushort cursor_flash;
+  ushort cursor_visible;
+
+  /* Some chipreg values we need to rebuild copper lists */
+  ushort diwstrt_v, diwstrt_h;	/* display window control */
+  ushort diwstop_v, diwstop_h;
+  ushort bplcon0;		/* display mode */
+  ushort htotal;
+
+  u_char *bitplane[8];		/* pointers to display bitplanes */
+  ulong plane_size;
+
+  ushort *coplist1hdr;		/* List 1 static  component */
+  ushort *coplist1dyn;		/* List 1 dynamic component */
+  ushort *coplist2hdr;		/* List 2 static  component */
+  ushort *coplist2dyn;		/* List 2 dynamic component */
+
+#endif
+
+   /* Filled in by the frame buffer device */
+
+   struct fb_var_screeninfo var;    /* variable infos. yoffset and vmode */
+                                    /* are updated by fbcon.c */
+   struct fb_cmap cmap;             /* colormap */
+   u_char *screen_base;             /* pointer to top of virtual screen */    
+   int visual;
+   int type;                        /* see FB_TYPE_* */
+   int type_aux;                    /* Interleave for interleaved Planes */
+   u_short ypanstep;                /* zero if no hardware ypan */
+   u_short ywrapstep;               /* zero if no hardware ywrap */
+   u_short can_soft_blank;          /* zero if no hardware blanking */
+   u_short inverse;                 /* != 0 text black on white as default */
+
+#if 0
+   struct fb_fix_cursorinfo fcrsr;
+   struct fb_var_cursorinfo *vcrsr;
+   struct fb_cursorstate crsrstate;
+#endif
+
+   /* Filled in by the low-level console driver */
+
+   struct vc_data *conp;            /* pointer to console data */
+   int cursor_x;                    /* current cursor position */
+   int cursor_y;
+   int fgcol;                       /* text colors */
+   int bgcol;
+   u_long next_line;                /* offset to one line below */
+   u_long next_plane;               /* offset to next plane */
+   u_char *fontdata;                /* Font associated to this display */
+   int fontheight;
+   int fontwidth;
+   struct display_switch *dispsw;   /* low level operations */
+   u_short scrollmode;              /* Scroll Method */
+   short yscroll;                   /* Hardware scrolling */
+}; 
+
+
+struct fb_info {
+   char modename[40];               /* at boottime detected video mode */
+   struct display *disp;            /* pointer to display variables */
+   char fontname[40];               /* default font name */
+   int (*changevar)(int);           /* tell console var has changed */
+   int (*switch_con)(int);          /* tell fb to switch consoles */
+   int (*updatevar)(int);           /* tell fb to update the vars */
+   void (*blank)(int);              /* tell fb to (un)blank the screen */
+};
+
+#endif /* __KERNEL__ */
+
+#if 1
+
+#define FBCMD_GET_CURRENTPAR	    0xDEAD0005
+#define FBCMD_SET_CURRENTPAR        0xDEAD8005
+
+#endif
+
+
+#if 1 /* Preliminary */
+
+   /*
+    *    Hardware Cursor
+    */
+
+#define FBIOGET_FCURSORINFO     0x4607
+#define FBIOGET_VCURSORINFO     0x4608
+#define FBIOPUT_VCURSORINFO     0x4609
+#define FBIOGET_CURSORSTATE     0x460A
+#define FBIOPUT_CURSORSTATE     0x460B
+
+
+struct fb_fix_cursorinfo {
+	u_short crsr_width;		/* width and height of the cursor in */
+	u_short crsr_height;		/* pixels (zero if no cursor)	*/
+	u_short crsr_xsize;		/* cursor size in display pixels */
+	u_short crsr_ysize;
+	u_short crsr_color1;		/* colormap entry for cursor color1 */
+	u_short crsr_color2;		/* colormap entry for cursor color2 */
+};
+
+struct fb_var_cursorinfo {
+	u_long data[256];	       /* max. 64x64 (ilbm, 2 planes)	*/
+};
+
+struct fb_cursorstate {
+	short xoffset;
+	short yoffset;
+	u_short mode;
+};
+
+#define FB_CURSOR_OFF		0
+#define FB_CURSOR_ON		1
+#define FB_CURSOR_FLASH		2
+
+#endif /* Preliminary */
+
+
+#endif /* _LINUX_FB_H */
diff -u --recursive --new-file v1.3.93/linux/include/linux/fdreg.h linux/include/linux/fdreg.h
--- v1.3.93/linux/include/linux/fdreg.h	Sun Apr 21 19:22:16 1996
+++ linux/include/linux/fdreg.h	Mon Apr 22 11:32:02 1996
@@ -120,7 +120,7 @@
 #define FDC_8272A	0x20	/* Intel 8272a, NEC 765 */
 #define FDC_765ED	0x30	/* Non-Intel 1MB-compatible FDC, can't detect */
 #define FDC_82072	0x40	/* Intel 82072; 8272a + FIFO + DUMPREGS */
-#define FDC_82072A	0x50	/* 82072A (on Sparcs) */
+#define FDC_82072A	0x45	/* 82072A (on Sparcs) */
 #define FDC_82077_ORIG	0x51	/* Original version of 82077AA, sans LOCK */
 #define FDC_82077	0x52	/* 82077AA-1 */
 #define FDC_82078_UNKN	0x5f	/* Unknown 82078 variant */
diff -u --recursive --new-file v1.3.93/linux/include/linux/fs.h linux/include/linux/fs.h
--- v1.3.93/linux/include/linux/fs.h	Sun Apr 21 19:22:16 1996
+++ linux/include/linux/fs.h	Mon Apr 22 15:42:17 1996
@@ -224,6 +224,7 @@
 #include <linux/nfs_fs_i.h>
 #include <linux/xia_fs_i.h>
 #include <linux/sysv_fs_i.h>
+#include <linux/ufs_fs_i.h>
 
 /*
  * Attribute flags.  These should be or-ed together to figure out what
@@ -311,6 +312,7 @@
 		struct nfs_inode_info nfs_i;
 		struct xiafs_inode_info xiafs_i;
 		struct sysv_inode_info sysv_i;
+		struct ufs_inode_info ufs_i;
 		struct socket socket_i;
 		void * generic_ip;
 	} u;
@@ -400,6 +402,7 @@
 #include <linux/nfs_fs_sb.h>
 #include <linux/xia_fs_sb.h>
 #include <linux/sysv_fs_sb.h>
+#include <linux/ufs_fs_sb.h>
 
 struct super_block {
 	kdev_t s_dev;
@@ -427,6 +430,7 @@
 		struct nfs_sb_info nfs_sb;
 		struct xiafs_sb_info xiafs_sb;
 		struct sysv_sb_info sysv_sb;
+		struct ufs_sb_info ufs_sb;
 		void *generic_sbp;
 	} u;
 };
diff -u --recursive --new-file v1.3.93/linux/include/linux/interrupt.h linux/include/linux/interrupt.h
--- v1.3.93/linux/include/linux/interrupt.h	Wed Apr  3 16:06:57 1996
+++ linux/include/linux/interrupt.h	Mon Apr 22 07:14:01 1996
@@ -31,6 +31,7 @@
 	TQUEUE_BH,
 	DIGI_BH,
 	SERIAL_BH,
+	RISCOM8_BH,
 	NET_BH,
 	IMMEDIATE_BH,
 	KEYBOARD_BH,
diff -u --recursive --new-file v1.3.93/linux/include/linux/lp_intern.h linux/include/linux/lp_intern.h
--- v1.3.93/linux/include/linux/lp_intern.h	Thu Jan  1 02:00:00 1970
+++ linux/include/linux/lp_intern.h	Mon Mar  4 22:55:14 1996
@@ -0,0 +1,22 @@
+#ifndef _LINUX_LP_INTERN_H_
+#define _LINUX_LP_INTERN_H_
+
+/*
+ * split in two parts by Joerg Dorchain
+ * usr/include/linux/lp.h  modified for Amiga by Michael Rausch
+ * modified for Atari by Andreas Schwab
+ * bug fixed by Jes Sorensen 18/8-94:
+ *     It was not possible to compile the kernel only for Atari or Amiga.
+ *
+ * linux i386 version  c.1991-1992 James Wiegand
+ * many modifications copyright (C) 1992 Michael K. Johnson
+ * Interrupt support added 1993 Nigel Gamble
+ */
+
+#include <linux/types.h>
+#include <linux/lp_m68k.h>
+
+int lp_internal_init(struct lp_struct *, int, int, int);
+
+#endif
+
diff -u --recursive --new-file v1.3.93/linux/include/linux/lp_m68k.h linux/include/linux/lp_m68k.h
--- v1.3.93/linux/include/linux/lp_m68k.h	Thu Jan  1 02:00:00 1970
+++ linux/include/linux/lp_m68k.h	Thu Mar 14 22:38:20 1996
@@ -0,0 +1,109 @@
+#ifndef _LINUX_LP_H
+#define _LINUX_LP_H
+
+/*
+ * split in two parts by Joerg Dorchain
+ * usr/include/linux/lp.h  modified for Amiga by Michael Rausch
+ * modified for Atari by Andreas Schwab
+ * bug fixed by Jes Sorensen 18/8-94:
+ *     It was not possible to compile the kernel only for Atari or Amiga.
+ *
+ * linux i386 version  c.1991-1992 James Wiegand
+ * many modifications copyright (C) 1992 Michael K. Johnson
+ * Interrupt support added 1993 Nigel Gamble
+ */
+
+#include <linux/autoconf.h>
+#include <asm/bootinfo.h>
+
+/*
+ * Per POSIX guidelines, this module reserves the LP and lp prefixes
+ * These are the lp_table[minor].flags flags...
+ */
+#define LP_EXIST 0x0001
+#define LP_BUSY	 0x0004
+#define LP_ABORT 0x0040
+#define LP_CAREFUL 0x0080
+#define LP_ABORTOPEN 0x0100
+
+/* timeout for each character.  This is relative to bus cycles -- it
+ * is the count in a busy loop.  THIS IS THE VALUE TO CHANGE if you
+ * have extremely slow printing, or if the machine seems to slow down
+ * a lot when you print.  If you have slow printing, increase this
+ * number and recompile, and if your system gets bogged down, decrease
+ * this number.  This can be changed with the tunelp(8) command as well.
+ */
+
+#define LP_INIT_CHAR 1000
+
+/* The parallel port specs apparently say that there needs to be
+ * a .5usec wait before and after the strobe.  Since there are wildly
+ * different computers running linux, I can't come up with a perfect
+ * value, but since it worked well on most printers before without,
+ * I'll initialize it to 0.
+ */
+
+#define LP_INIT_WAIT 0
+
+/* This is the amount of time that the driver waits for the printer to
+ * catch up when the printer's buffer appears to be filled.  If you
+ * want to tune this and have a fast printer (i.e. HPIIIP), decrease
+ * this number, and if you have a slow printer, increase this number.
+ * This is in hundredths of a second, the default 2 being .05 second.
+ * Or use the tunelp(8) command, which is especially nice if you want
+ * change back and forth between character and graphics printing, which
+ * are wildly different...
+ */
+
+#define LP_INIT_TIME 40
+
+/* IOCTL numbers */
+#define LPCHAR   0x0601  /* corresponds to LP_INIT_CHAR */
+#define LPTIME   0x0602  /* corresponds to LP_INIT_TIME */
+#define LPABORT  0x0604  /* call with TRUE arg to abort on error,
+			    FALSE to retry.  Default is retry.  */
+#define LPSETIRQ 0x0605  /* call with new IRQ number,
+			    or 0 for polling (no IRQ) */
+#define LPGETIRQ 0x0606  /* get the current IRQ number */
+#define LPWAIT   0x0608  /* corresponds to LP_INIT_WAIT */
+#define LPCAREFUL   0x0609  /* call with TRUE arg to require out-of-paper, off-
+			    line, and error indicators good on all writes,
+			    FALSE to ignore them.  Default is ignore. */
+#define LPABORTOPEN 0x060a  /* call with TRUE arg to abort open() on error,
+			    FALSE to ignore error.  Default is ignore.  */
+#define LPGETSTATUS 0x060b  /* return LP_S(minor) */
+#define LPRESET     0x060c  /* reset printer */
+
+/* timeout for printk'ing a timeout, in jiffies (100ths of a second).
+   This is also used for re-checking error conditions if LP_ABORT is
+   not set.  This is the default behavior. */
+
+#define LP_TIMEOUT_INTERRUPT	(60 * HZ)
+#define LP_TIMEOUT_POLLED	(10 * HZ)
+
+
+#define LP_BUFFER_SIZE 1024 /*256*/
+
+struct lp_struct {
+	char *name;
+	unsigned int irq;
+	void (*lp_out)(int,int);	/*output char function*/
+	int (*lp_is_busy)(int);
+	int (*lp_has_pout)(int);
+	int (*lp_is_online)(int);
+	int (*lp_my_interrupt)(int);
+	int flags;		/*for BUSY... */
+	unsigned int chars;	/*busy timeout */
+	unsigned int time;	/*wait time */
+	unsigned int wait;
+	struct wait_queue *lp_wait_q; /*strobe wait */
+	char lp_buffer[LP_BUFFER_SIZE];
+	int do_print;
+	unsigned long copy_size,bytes_written;
+};
+
+extern struct lp_struct lp_table[];
+
+extern int lp_init(void);
+
+#endif
diff -u --recursive --new-file v1.3.93/linux/include/linux/major.h linux/include/linux/major.h
--- v1.3.93/linux/include/linux/major.h	Sun Apr 21 19:22:16 1996
+++ linux/include/linux/major.h	Mon Apr 22 07:14:01 1996
@@ -61,6 +61,8 @@
 #define IDE3_MAJOR	34
 #define NETLINK_MAJOR	36
 #define IDETAPE_MAJOR	37
+#define RISCOM8_NORMAL_MAJOR 48
+#define RISCOM8_CALLOUT_MAJOR 49
 #define APBLOCK_MAJOR   60   /* AP1000 Block device */
 #define DDV_MAJOR       61   /* AP1000 DDV block device */
 /*
diff -u --recursive --new-file v1.3.93/linux/include/linux/mm.h linux/include/linux/mm.h
--- v1.3.93/linux/include/linux/mm.h	Fri Apr 19 10:08:02 1996
+++ linux/include/linux/mm.h	Mon Apr 22 15:42:17 1996
@@ -252,7 +252,7 @@
 extern unsigned long put_dirty_page(struct task_struct * tsk,unsigned long page,
 	unsigned long address);
 
-extern void free_page_tables(struct task_struct * tsk);
+extern void free_page_tables(struct mm_struct * mm);
 extern void clear_page_tables(struct task_struct * tsk);
 extern int new_page_tables(struct task_struct * tsk);
 extern int copy_page_tables(struct task_struct * to);
diff -u --recursive --new-file v1.3.93/linux/include/linux/mtio.h linux/include/linux/mtio.h
--- v1.3.93/linux/include/linux/mtio.h	Mon Apr  8 19:01:46 1996
+++ linux/include/linux/mtio.h	Mon Apr 22 11:13:22 1996
@@ -234,6 +234,7 @@
 #define MT_ST_AUTO_LOCK		0x40
 #define MT_ST_DEF_WRITES	0x80
 #define MT_ST_CAN_BSR		0x100
+#define MT_ST_NO_BLKLIMS	0x200
 
 /* The mode parameters to be controlled. Parameter chosen with bits 20-28 */
 #define MT_ST_CLEAR_DEFAULT	0xfffff
diff -u --recursive --new-file v1.3.93/linux/include/linux/sched.h linux/include/linux/sched.h
--- v1.3.93/linux/include/linux/sched.h	Sun Apr 21 12:39:03 1996
+++ linux/include/linux/sched.h	Mon Apr 22 15:42:17 1996
@@ -63,6 +63,7 @@
 #define CT_TO_USECS(x)	(((x) % HZ) * 1000000/HZ)
 
 extern int nr_running, nr_tasks;
+extern int last_pid;
 
 #define FIRST_TASK task[0]
 #define LAST_TASK task[NR_TASKS-1]
diff -u --recursive --new-file v1.3.93/linux/include/linux/tty.h linux/include/linux/tty.h
--- v1.3.93/linux/include/linux/tty.h	Sun Apr 21 19:22:16 1996
+++ linux/include/linux/tty.h	Mon Apr 22 15:42:17 1996
@@ -291,6 +291,7 @@
 extern int cy_init(void);
 extern int stl_init(void);
 extern int stli_init(void);
+extern int riscom8_init(void);
 
 extern int tty_paranoia_check(struct tty_struct *tty, kdev_t device,
 			      const char *routine);
diff -u --recursive --new-file v1.3.93/linux/include/linux/ufs_fs.h linux/include/linux/ufs_fs.h
--- v1.3.93/linux/include/linux/ufs_fs.h	Thu Jan  1 02:00:00 1970
+++ linux/include/linux/ufs_fs.h	Mon Apr 22 11:01:45 1996
@@ -0,0 +1,198 @@
+/*
+ *  linux/include/linux/ufs_fs.h
+ *
+ * Copyright (C) 1996
+ * Adrian Rodriguez (adrian@franklins-tower.rutgers.edu)
+ * Laboratory for Computer Science Research Computing Facility
+ * Rutgers, The State University of New Jersey
+ *
+ * $Id: ufs_fs.h,v 1.1 1996/04/21 14:45:11 davem Exp $
+ *
+ */
+
+#ifndef __LINUX_UFS_FS_H
+#define __LINUX_UFS_FS_H
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/time.h>
+#include <linux/stat.h>
+
+#define UFS_BBLOCK 0
+#define UFS_BBSIZE 8192
+#define UFS_SBLOCK 8192
+#define UFS_SBSIZE 8192
+
+#define UFS_MAGIC 0x00011954
+
+#define UFS_FSIZE 1024
+#define UFS_BSIZE 8192
+
+#define UFS_NDADDR 12
+#define UFS_NINDIR 3
+
+#define UFS_ROOTINO 2
+
+#define UFS_USEEFT  ((__u16)65535)
+
+#define UFS_FSOK      0x7c269d38
+#define UFS_FSACTIVE  ((char)0x00)
+#define UFS_FSCLEAN   ((char)0x01)
+#define UFS_FSSTABLE  ((char)0x02)
+#define UFS_FSBAD     ((char)0xff)
+
+/* Flags for ufs_sb_info */
+#define UFS_DEBUG       0x00000001
+#define UFS_DEBUG_INODE 0x00000002
+#define UFS_DEBUG_NAMEI 0x00000004
+#define UFS_DEBUG_LINKS 0x00000008
+
+
+/* Test if the inode number is valid. */
+#define ufs_ino_ok(inode)  ((inode->i_ino < 2) &&  \
+	                    (inode->i_ino > (inode->i_sb->u.ufs_sb.s_ncg * inode->i_sb->u.ufs_sb.s_ipg - 1)))
+
+/* Convert (sb,cg) to the first physical block number for that cg. */
+#define ufs_cgstart(sb, cg)   \
+  (((sb)->u.ufs_sb.s_fpg * (cg)) + (sb)->u.ufs_sb.s_cgoffset * ((cg) & ~((sb)->u.ufs_sb.s_cgmask)))
+
+/* Convert (sb,cg) to the first phys. block number for inodes in that cg. */
+#define ufs_cgimin(sb, cg) (ufs_cgstart((sb), (cg)) + (sb)->u.ufs_sb.s_iblkno)
+#define ufs_cgdmin(sb, cg) (ufs_cgstart((sb), (cg)) + (sb)->u.ufs_sb.s_dblkno)
+
+/* Convert an inode number to a cg number. */
+/* XXX - this can be optimized if s_ipg is a power of 2. */
+#define ufs_ino2cg(inode)  ((inode)->i_ino/(inode)->i_sb->u.ufs_sb.s_ipg)
+
+#define	MAXNAMLEN 255
+
+struct direct {
+	__u32  d_ino;			/* inode number of this entry */
+	__u16  d_reclen;		/* length of this entry */
+	__u16  d_namlen;		/* actual length of d_name */
+	char   d_name[MAXNAMLEN + 1];	/* file name */
+};
+
+#define MAXMNTLEN 512
+#define MAXCSBUFS 32
+
+struct csum {
+	__u32	cs_ndir;	/* number of directories */
+	__u32	cs_nbfree;	/* number of free blocks */
+	__u32	cs_nifree;	/* number of free inodes */
+	__u32	cs_nffree;	/* number of free frags */
+};
+
+typedef struct _ufsquad {
+	__u32 val[2];
+} ufsquad;
+
+/*
+ * This is the actual superblock, as it is laid out on the disk.
+ */
+struct ufs_superblock {
+	__u32	fs_link;	/* UNUSED */
+	__u32	fs_rlink;	/* UNUSED */
+	__u32	fs_sblkno;
+	__u32	fs_cblkno;
+	__u32	fs_iblkno;
+	__u32	fs_dblkno;
+	__u32	fs_cgoffset;
+	__u32	fs_cgmask;
+	time_t	fs_time;	/* XXX - check type */
+	__u32	fs_size;
+	__u32	fs_dsize;
+	__u32	fs_ncg;
+	__u32	fs_bsize;
+	__u32	fs_fsize;
+	__u32	fs_frag;
+	__u32	fs_minfree;
+	__u32	fs_rotdelay;
+	__u32	fs_rps;
+	__u32	fs_bmask;
+	__u32	fs_fmask;
+	__u32	fs_bshift;
+	__u32	fs_fshift;
+	__u32	fs_maxcontig;
+	__u32	fs_maxbpg;
+	__u32	fs_fragshift;
+	__u32	fs_fsbtodb;
+	__u32	fs_sbsize;
+	__u32	fs_csmask;
+	__u32	fs_csshift;
+	__u32	fs_nindir;
+	__u32	fs_inopb;
+	__u32	fs_nspf;
+	__u32	fs_optim;
+	__u32	fs_XXX1;
+	__u32	fs_interleave;
+	__u32	fs_trackskew;
+	__u32	fs_id[2];
+	__u32	fs_csaddr;
+	__u32	fs_cssize;
+	__u32	fs_cgsize;
+	__u32	fs_ntrak;
+	__u32	fs_nsect;
+	__u32	fs_spc;
+	__u32	fs_ncyl;
+	__u32	fs_cpg;
+	__u32	fs_ipg;
+	__u32	fs_fpg;
+	struct csum fs_cstotal;
+	__u8	fs_fmod;
+	__u8	fs_clean;
+	__u8	fs_ronly;
+	__u8	fs_flags;
+	__u8	fs_fsmnt[MAXMNTLEN];
+	__u32	fs_cgrotor;
+	struct csum * fs_csp[MAXCSBUFS];
+	__u32	fs_cpc;
+	__u16	fs_opostbl[16][8];	/* old rotation block list head */
+	__s32	fs_sparecon[55];	/* reserved for future constants */
+	__s32	fs_state;		/* file system state time stamp */
+	ufsquad	fs_qbmask;		/* ~usb_bmask - for use with __s64 size */
+	ufsquad	fs_qfmask;		/* ~usb_fmask - for use with __s64 size */
+	__s32	fs_postblformat;	/* format of positional layout tables */
+	__s32	fs_nrpos;		/* number of rotaional positions */
+	__s32	fs_postbloff;		/* (__s16) rotation block list head */
+	__s32	fs_rotbloff;		/* (__u8) blocks for each rotation */
+	__s32	fs_magic;		/* magic number */
+	__u8	fs_space[1];		/* list of blocks for each rotation */
+
+};
+
+/*
+ * structure of an on-disk inode
+ */
+struct ufs_inode {
+	__u16	ui_mode;		/*  0x0 */
+	__u16	ui_nlink;		/*  0x2 */
+	__u16	ui_suid;		/*  0x4 */
+	__u16	ui_sgid;		/*  0x6 */
+	ufsquad	ui_size;		/*  0x8 */  /* XXX - should be __u64 */
+	struct timeval ui_atime;	/* 0x10 */
+	struct timeval ui_mtime;	/* 0x18 */
+	struct timeval ui_ctime;	/* 0x20 */
+	__u32	ui_db[UFS_NDADDR];		/* 0x28 data blocks */
+	__u32	ui_ib[UFS_NINDIR];		/* 0x58 indirect blocks */
+	__u32	ui_flags;		/* 0x64 unused */
+	__u32	ui_blocks;		/* 0x68 blocks in use */
+	__u32	ui_gen;			/* 0x6c generation number XXX - what is this? */
+	__u32	ui_shadow;		/* 0x70 shadow inode XXX - what is this?*/
+	__u32	ui_uid;			/* 0x74 long EFT version of uid */
+	__u32	ui_gid;			/* 0x78 long EFT version of gid */
+	__u32	ui_oeftflag;		/* 0x7c reserved */
+};
+
+extern int init_ufs_fs(void);
+
+#endif /* __LINUX_UFS_FS_H */
+/*
+ * Local Variables: ***
+ * c-indent-level: 8 ***
+ * c-continued-statement-offset: 8 ***
+ * c-brace-offset: -8 ***
+ * c-argdecl-indent: 0 ***
+ * c-label-offset: -8 ***
+ * End: ***
+ */
diff -u --recursive --new-file v1.3.93/linux/include/linux/ufs_fs_i.h linux/include/linux/ufs_fs_i.h
--- v1.3.93/linux/include/linux/ufs_fs_i.h	Thu Jan  1 02:00:00 1970
+++ linux/include/linux/ufs_fs_i.h	Mon Apr 22 12:46:59 1996
@@ -0,0 +1,30 @@
+/*
+ *  linux/include/linux/ufs_fs_i.h
+ *
+ * Copyright (C) 1996
+ * Adrian Rodriguez (adrian@franklins-tower.rutgers.edu)
+ * Laboratory for Computer Science Research Computing Facility
+ * Rutgers, The State University of New Jersey
+ *
+ * $Id: ufs_fs_i.h,v 1.1 1996/04/21 14:45:13 davem Exp $
+ *
+ */
+
+#ifndef _LINUX_UFS_FS_I_H
+#define _LINUX_UFS_FS_I_H
+
+#include <linux/ufs_fs.h>
+
+struct ufs_inode_info {
+	__u64	ui_size;
+	__u32	ui_flags;
+	__u32	ui_gen;
+	__u32	ui_shadow;
+	__u32	ui_uid;
+	__u32	ui_gid;
+	__u32	ui_oeftflag;
+	__u32	ui_db[UFS_NDADDR];
+	__u32	ui_ib[UFS_NINDIR];
+};
+
+#endif /* _LINUX_UFS_FS_I_H */
diff -u --recursive --new-file v1.3.93/linux/include/linux/ufs_fs_sb.h linux/include/linux/ufs_fs_sb.h
--- v1.3.93/linux/include/linux/ufs_fs_sb.h	Thu Jan  1 02:00:00 1970
+++ linux/include/linux/ufs_fs_sb.h	Mon Apr 22 10:59:40 1996
@@ -0,0 +1,43 @@
+/*
+ *  linux/include/linux/ufs_fs_sb.h
+ *
+ * Copyright (C) 1996
+ * Adrian Rodriguez (adrian@franklins-tower.rutgers.edu)
+ * Laboratory for Computer Science Research Computing Facility
+ * Rutgers, The State University of New Jersey
+ *
+ * $Id: ufs_fs_sb.h,v 1.1 1996/04/21 14:45:15 davem Exp $
+ *
+ */
+
+#ifndef __LINUX_UFS_FS_SB_H
+#define __LINUX_UFS_FS_SB_H
+
+
+struct ufs_sb_info {
+	struct ufs_superblock * s_raw_sb;
+	__u32	s_flags; /* internal flags for UFS code */
+	__u32	s_ncg;	 /* used in ufs_read_inode */
+	__u32	s_ipg;	 /* used in ufs_read_inode */
+	__u32	s_fpg;
+	__u32	s_fsize;
+	__u32	s_bsize;
+	__u32	s_iblkno;
+	__u32	s_dblkno;
+	__u32	s_cgoffset;
+	__u32	s_cgmask;
+	__u32	s_inopb;
+	__u32	s_fsfrag;
+};
+
+#endif /* __LINUX_UFS_FS_SB_H */
+
+/*
+ * Local Variables: ***
+ * c-indent-level: 8 ***
+ * c-continued-statement-offset: 8 ***
+ * c-brace-offset: -8 ***
+ * c-argdecl-indent: 0 ***
+ * c-label-offset: -8 ***
+ * End: ***
+ */
diff -u --recursive --new-file v1.3.93/linux/include/net/ip_masq.h linux/include/net/ip_masq.h
--- v1.3.93/linux/include/net/ip_masq.h	Wed Apr 10 17:02:26 1996
+++ linux/include/net/ip_masq.h	Mon Apr 22 15:48:38 1996
@@ -27,6 +27,7 @@
 #define IP_MASQ_F_NO_DADDR      	0x08 	/* no daddr yet */
 #define IP_MASQ_F_HASHED		0x10 	/* hashed entry */
 #define IP_MASQ_F_SAW_FIN		0x20 	/* tcp fin pkt seen */
+#define IP_MASQ_F_SAW_RST		0x40 	/* tcp rst pkt seen */
 
 #ifdef __KERNEL__
 
@@ -52,6 +53,7 @@
 	__u32 		saddr, daddr, maddr;	/* src, dst & masq addresses */
         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 */
 };
 
@@ -101,6 +103,7 @@
 struct ip_masq_app
 {
         struct ip_masq_app *next;
+	char *name;		/* name of application proxy */
         unsigned type;          /* type = proto<<16 | port (host byte order)*/
         int n_attach;
         int (*masq_init_1)      /* ip_masq initializer */
@@ -141,6 +144,11 @@
  */
 extern int ip_masq_app_pkt_out(struct ip_masq *, struct sk_buff **skb_p, struct device *dev);
 extern int ip_masq_app_pkt_in(struct ip_masq *, struct sk_buff **skb_p, struct device *dev);
+
+/*
+ *	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);
 
 /*
  *	/proc/net entry
diff -u --recursive --new-file v1.3.93/linux/init/main.c linux/init/main.c
--- v1.3.93/linux/init/main.c	Sun Apr 21 19:22:16 1996
+++ linux/init/main.c	Mon Apr 22 15:12:29 1996
@@ -138,6 +138,9 @@
 #ifdef CONFIG_ISDN_DRV_PCBIT
 extern void pcbit_setup(char *str, int *ints);
 #endif
+#ifdef CONFIG_RISCOM8
+extern void riscom8_setup(char *str, int *ints);
+#endif
 
 
 #if defined(CONFIG_SYSVIPC) || defined(CONFIG_KERNELD)
@@ -346,6 +349,9 @@
 #ifdef CONFIG_DIGI
 	{ "digi=", pcxx_setup },
 #endif
+#ifdef CONFIG_RISCOM8
+	{ "riscom8=", riscom8_setup },
+#endif
 	{ 0, 0 }
 };
 
@@ -639,6 +645,8 @@
 
 	for (i=1; i<smp_num_cpus; i++)
 	{
+		struct task_struct *n, *p;
+
 		j = cpu_logical_map[i];
 		/*
 		 *	We use kernel_thread for the idlers which are
@@ -650,6 +658,14 @@
 		 */
 		current_set[j]=task[i];
 		current_set[j]->processor=j;
+		cli();
+		n = task[i]->next_run;
+		p = task[i]->prev_run;
+		nr_running--;
+		n->prev_run = p;
+		p->next_run = n;
+		task[i]->next_run = task[i]->prev_run = task[i];
+		sti();
 	}
 }		
 
diff -u --recursive --new-file v1.3.93/linux/kernel/exit.c linux/kernel/exit.c
--- v1.3.93/linux/kernel/exit.c	Tue Apr  2 13:32:23 1996
+++ linux/kernel/exit.c	Mon Apr 22 12:14:50 1996
@@ -17,6 +17,8 @@
 #include <linux/malloc.h>
 
 #include <asm/segment.h>
+#include <asm/pgtable.h>
+
 extern void sem_exit (void);
 extern void acct_process (long exitcode);
 extern void kerneld_exit(void);
@@ -423,21 +425,26 @@
 
 void exit_sighand(struct task_struct *tsk)
 {
-  __exit_sighand(tsk);
+	__exit_sighand(tsk);
 }
 
 static inline void exit_mm(void)
 {
 	struct mm_struct * mm = current->mm;
 
+	/* Set us up to use the kernel mm state */
+	flush_cache_mm(mm);
+	flush_tlb_mm(mm);
+	init_mm.count++;
+	current->mm = &init_mm;
 	current->swappable = 0;
-	if (mm) {
-		if (!--mm->count) {
-			exit_mmap(mm);
-			free_page_tables(current);
-			kfree(mm);
-		}
-		current->mm = NULL;
+	SET_PAGE_DIR(current, swapper_pg_dir);
+
+	/* free the old state - not used any more */
+	if (!--mm->count) {
+		exit_mmap(mm);
+		free_page_tables(mm);
+		kfree(mm);
 	}
 }
 
diff -u --recursive --new-file v1.3.93/linux/kernel/fork.c linux/kernel/fork.c
--- v1.3.93/linux/kernel/fork.c	Sun Mar 24 20:07:01 1996
+++ linux/kernel/fork.c	Mon Apr 22 13:08:47 1996
@@ -29,6 +29,7 @@
 int nr_tasks=1;
 int nr_running=1;
 unsigned long int total_forks=0;	/* Handle normal Linux uptimes. */
+int last_pid=0;
 
 static inline int find_empty_process(void)
 {
@@ -59,7 +60,6 @@
 
 static int get_pid(unsigned long flags)
 {
-	static int last_pid = 0;
 	struct task_struct *p;
 
 	if (flags & CLONE_PID)
@@ -114,26 +114,27 @@
 
 static inline int copy_mm(unsigned long clone_flags, struct task_struct * tsk)
 {
-	if (clone_flags & CLONE_VM) {
-		SET_PAGE_DIR(tsk, current->mm->pgd);
-		current->mm->count++;
+	if (!(clone_flags & CLONE_VM)) {
+		struct mm_struct * mm = kmalloc(sizeof(*tsk->mm), GFP_KERNEL);
+		if (!mm)
+			return -1;
+		*mm = *current->mm;
+		mm->count = 1;
+		mm->def_flags = 0;
+		tsk->mm = mm;
+		tsk->min_flt = tsk->maj_flt = 0;
+		tsk->cmin_flt = tsk->cmaj_flt = 0;
+		tsk->nswap = tsk->cnswap = 0;
+		if (new_page_tables(tsk))
+			return -1;
+		if (dup_mmap(mm)) {
+			free_page_tables(mm);
+			return -1;
+		}
 		return 0;
 	}
-	tsk->mm = kmalloc(sizeof(*tsk->mm), GFP_KERNEL);
-	if (!tsk->mm)
-		return -1;
-	*tsk->mm = *current->mm;
-	tsk->mm->count = 1;
-	tsk->mm->def_flags = 0;
-	tsk->min_flt = tsk->maj_flt = 0;
-	tsk->cmin_flt = tsk->cmaj_flt = 0;
-	tsk->nswap = tsk->cnswap = 0;
-	if (new_page_tables(tsk))
-		return -1;
-	if (dup_mmap(tsk->mm)) {
-		free_page_tables(tsk);
-		return -1;
-	}
+	SET_PAGE_DIR(tsk, current->mm->pgd);
+	current->mm->count++;
 	return 0;
 }
 
diff -u --recursive --new-file v1.3.93/linux/kernel/sched.c linux/kernel/sched.c
--- v1.3.93/linux/kernel/sched.c	Fri Apr 12 15:52:10 1996
+++ linux/kernel/sched.c	Mon Apr 22 15:14:08 1996
@@ -336,7 +336,10 @@
 	/*
 	 *	This is safe as we do not permit re-entry of schedule()
 	 */
-	prev->processor = NO_PROC_ID;	
+	prev->processor = NO_PROC_ID;
+#define idle_task (task[this_cpu])
+#else
+#define idle_task (&init_task)
 #endif	
 
 /*
@@ -346,7 +349,7 @@
  */
 /* this is the scheduler proper: */
 	c = -1000;
-	next = &init_task;
+	next = idle_task;
 	while (p != &init_task) {
 		int weight = goodness(p, prev, this_cpu);
 		if (weight > c)
@@ -359,20 +362,13 @@
 		for_each_task(p)
 			p->counter = (p->counter >> 1) + p->priority;
 	}
-#ifdef __SMP__	
-	
-	/*
-	 *	Context switching between two idle threads is pointless.
-	 */
-	if(!prev->pid && !next->pid)
-		next=prev;
+#ifdef __SMP__
 	/*
 	 *	Allocate process to CPU
 	 */
 	 
 	 next->processor = this_cpu;
 	 next->last_processor = this_cpu;
-	 
 #endif	 
 #ifdef __SMP_PROF__ 
 	/* mark processor running an idle thread */
@@ -1437,9 +1433,12 @@
 	 *	process right in SMP mode.
 	 */
 	int cpu=smp_processor_id();
+#ifndef __SMP__	
 	current_set[cpu]=&init_task;
-#ifdef __SMP__	
+#else
 	init_task.processor=cpu;
+	for(cpu = 0; cpu < NR_CPUS; cpu++)
+		current_set[cpu] = &init_task;
 #endif
 	init_bh(TIMER_BH, timer_bh);
 	init_bh(TQUEUE_BH, tqueue_bh);
diff -u --recursive --new-file v1.3.93/linux/mm/filemap.c linux/mm/filemap.c
--- v1.3.93/linux/mm/filemap.c	Sun Apr 21 19:22:17 1996
+++ linux/mm/filemap.c	Mon Apr 22 08:48:09 1996
@@ -424,8 +424,8 @@
  *   We try to have a limit of MAX_READWINDOW = 48K.
  */
 
-#define MAX_READWINDOW (PAGE_SIZE*12)
-#define MAX_READAHEAD (PAGE_SIZE*7)
+#define MAX_READWINDOW (PAGE_SIZE*32)
+#define MAX_READAHEAD (PAGE_SIZE*16)
 #define MIN_READAHEAD (PAGE_SIZE)
 
 static inline unsigned long generic_file_readahead(struct file * filp, struct inode * inode,
diff -u --recursive --new-file v1.3.93/linux/mm/memory.c linux/mm/memory.c
--- v1.3.93/linux/mm/memory.c	Sun Apr 21 19:22:17 1996
+++ linux/mm/memory.c	Mon Apr 22 12:14:21 1996
@@ -147,20 +147,16 @@
  * page table directory to the kernel page tables and then frees the old
  * page table directory.
  */
-void free_page_tables(struct task_struct * tsk)
+void free_page_tables(struct mm_struct * mm)
 {
 	int i;
 	pgd_t * page_dir;
 
-	page_dir = tsk->mm->pgd;
+	page_dir = mm->pgd;
 	if (!page_dir || page_dir == swapper_pg_dir) {
-		printk("%s trying to free kernel page-directory: not good\n", tsk->comm);
+		printk("Trying to free kernel page-directory: not good\n");
 		return;
 	}
-	flush_cache_mm(tsk->mm);
-	flush_tlb_mm(tsk->mm);
-	SET_PAGE_DIR(tsk, swapper_pg_dir);
-	tsk->mm->pgd = swapper_pg_dir;	/* or else... */
 	for (i = 0 ; i < USER_PTRS_PER_PGD ; i++)
 		free_one_pgd(page_dir + i);
 	pgd_free(page_dir);
diff -u --recursive --new-file v1.3.93/linux/mm/page_io.c linux/mm/page_io.c
--- v1.3.93/linux/mm/page_io.c	Wed Apr 17 09:06:33 1996
+++ linux/mm/page_io.c	Mon Apr 22 08:43:45 1996
@@ -67,8 +67,10 @@
 		return;
 	}
 	/* Make sure we are the only process doing I/O with this swap page. */
-	while (set_bit(offset,p->swap_lockmap))
+	while (set_bit(offset,p->swap_lockmap)) {
+		run_task_queue(&tq_disk);
 		sleep_on(&lock_queue);
+	}
 	if (rw == READ)
 		kstat.pswpin++;
 	else
diff -u --recursive --new-file v1.3.93/linux/net/ipv4/ip_masq.c linux/net/ipv4/ip_masq.c
--- v1.3.93/linux/net/ipv4/ip_masq.c	Wed Apr 17 09:06:33 1996
+++ linux/net/ipv4/ip_masq.c	Mon Apr 22 11:27:00 1996
@@ -73,6 +73,7 @@
         X(ip_masq_set_expire),
         X(ip_masq_free_ports),
 	X(ip_masq_expire),
+	X(ip_masq_out_get_2),
 #include <linux/symtab_end.h>
 };
 
@@ -127,14 +128,14 @@
         hash = ip_masq_hash_key(ms->protocol, ms->maddr, ms->mport);
         ms->m_link = ip_masq_m_tab[hash];
         ip_masq_m_tab[hash] = ms;
-        
+
         /*
          *	Hash by proto,s{addr,port}
          */
         hash = ip_masq_hash_key(ms->protocol, ms->saddr, ms->sport);
         ms->s_link = ip_masq_s_tab[hash];
         ip_masq_s_tab[hash] = ms;
-        
+
 
         ms->flags |= IP_MASQ_F_HASHED;
         return 1;
@@ -172,7 +173,7 @@
                         *ms_p = ms->s_link;
                         break;
                 }
-       
+
         ms->flags &= ~IP_MASQ_F_HASHED;
         return 1;
 }
@@ -204,7 +205,7 @@
         s_port = portptr[0];
         d_addr = iph->daddr;
         d_port = portptr[1];
-        
+
         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 &&
@@ -224,8 +225,6 @@
 struct ip_masq *
 ip_masq_out_get(struct iphdr *iph)
 {
-        unsigned hash;
-        struct ip_masq *ms;
  	__u16 *portptr;
         int protocol;
         __u32 s_addr, d_addr;
@@ -237,7 +236,24 @@
         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);
+}
+
+/*
+ *	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.
+ */
+
+struct ip_masq *
+ip_masq_out_get_2(int protocol, __u32 s_addr, __u16 s_port, __u32 d_addr, __u16 d_port)
+{
+        unsigned hash;
+        struct ip_masq *ms;
+
         hash = ip_masq_hash_key(protocol, s_addr, s_port);
         for(ms = ip_masq_s_tab[hash]; ms ; ms = ms->s_link) {
 		if (protocol == ms->protocol &&
@@ -245,7 +261,7 @@
                     d_addr == ms->daddr && d_port == ms->dport )
                         return ms;
         }
-        
+
         return NULL;
 }
 
@@ -259,7 +275,7 @@
 {
         unsigned hash;
         struct ip_masq *ms;
-        
+
         hash = ip_masq_hash_key(protocol, m_addr, m_port);
         for(ms = ip_masq_m_tab[hash]; ms ; ms = ms->m_link) {
  		if ( protocol==ms->protocol &&
@@ -288,7 +304,7 @@
                 ip_masq_unbind_app(ms);
                 kfree_s(ms,sizeof(*ms));
         }
-        
+
 	restore_flags(flags);
 }
 
@@ -304,9 +320,9 @@
         int ports_tried, *free_ports_p;
 	unsigned long flags;
         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("ip_masq_new(proto=%s): no free ports.\n",
@@ -330,7 +346,8 @@
         ms->daddr	   = daddr;
         ms->dport	   = dport;
         ms->flags	   = mflags;
-        
+        ms->app_data	   = NULL;
+
         if (proto == IPPROTO_UDP)
                 ms->flags |= IP_MASQ_F_NO_DADDR;
         
@@ -434,7 +451,7 @@
 		ntohl(iph->saddr), ntohs(portptr[0]),
 		ntohl(iph->daddr), ntohs(portptr[1]));
 #endif
-        
+
         ms = ip_masq_out_get(iph);
         if (ms!=NULL)
                 ip_masq_set_expire(ms,0);
@@ -442,8 +459,8 @@
 	/*
 	 *	Nope, not found, create a new entry for it
 	 */
-	 
-	if (ms==NULL) 
+	
+	if (ms==NULL)
 	{
                 ms = ip_masq_new(dev, iph->protocol,
                                  iph->saddr, portptr[0],
@@ -452,18 +469,18 @@
                 if (ms == NULL)
 			return;
  	}
- 
+
  	/*
  	 *	Change the fragments origin
  	 */
- 	 
+ 	
  	size = skb->len - ((unsigned char *)portptr - skb->h.raw);
         /*
          *	Set iph addr and port from ip_masq obj.
          */
  	iph->saddr = ms->maddr;
  	portptr[0] = ms->mport;
- 
+
  	/*
  	 *	Attempt ip_masq_app call.
          *	will fix ip_masq and iph seq stuff
@@ -478,42 +495,48 @@
                 portptr = (__u16 *)&(((char *)iph)[iph->ihl*4]);
                 size = skb->len - ((unsigned char *)portptr-skb->h.raw);
         }
-        
+
  	/*
  	 *	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 
+ 	else
  	{
  		struct tcphdr *th;
  		th = (struct tcphdr *)portptr;
- 
+
  		/*
  		 *	Timeout depends if FIN packet was seen
+		 *	Very short timeout if RST packet seen.
  		 */
- 		if (ms->flags & IP_MASQ_F_SAW_FIN || th->fin)
+ 		if (ms->flags & IP_MASQ_F_SAW_RST || th->rst)
+                {
+                        timeout = 1;
+ 			ms->flags |= IP_MASQ_F_SAW_RST;
+ 		}
+ 		else if (ms->flags & IP_MASQ_F_SAW_FIN || th->fin)
                 {
                         timeout = ip_masq_expire->tcp_fin_timeout;
  			ms->flags |= IP_MASQ_F_SAW_FIN;
  		}
  		else timeout = ip_masq_expire->tcp_timeout;
- 
+
 		skb->csum = csum_partial((void *)(th + 1), size - sizeof(*th), 0);
  		tcp_send_check(th,iph->saddr,iph->daddr,size,skb);
  	}
         ip_masq_set_expire(ms, timeout);
  	ip_send_check(iph);
- 
+
  #ifdef DEBUG_CONFIG_IP_MASQUERADE
  	printk("O-routed from %lX:%X over %s\n",ntohl(ms->maddr),ntohs(ms->mport),dev->name);
  #endif
  }
- 
+
  /*
   *	Check if it's an masqueraded port, look it up,
   *	and send it on it's way...
@@ -530,10 +553,10 @@
  	__u16	*portptr;
  	struct ip_masq	*ms;
 	unsigned short  frag;
- 
+
  	if (iph->protocol!=IPPROTO_UDP && iph->protocol!=IPPROTO_TCP)
  		return 0;
- 
+
 	/*
    	 * Toss fragments, since we handle them in ip_rcv()
 	 */
@@ -549,7 +572,7 @@
  	if (ntohs(portptr[1]) < PORT_MASQ_BEGIN ||
  	    ntohs(portptr[1]) > PORT_MASQ_END)
  		return 0;
- 
+
 #ifdef DEBUG_CONFIG_IP_MASQUERADE
  	printk("Incoming %s %lX:%X -> %lX:%X\n",
  		masq_proto_name(iph->protocol),
@@ -559,17 +582,17 @@
  	/*
  	 * reroute to original host:port if found...
          */
-        
+
         ms = ip_masq_in_get(iph);
-        
+
         if (ms != NULL)
         {
                 int size;
-        
+
                 /*
                  *	Set dport if not defined yet.
                  */
-                
+
                 if ( ms->flags & IP_MASQ_F_NO_DPORT && ms->protocol == IPPROTO_TCP ) {
                         ms->flags &= ~IP_MASQ_F_NO_DPORT;
                         ms->dport = portptr[0];
@@ -589,34 +612,53 @@
                 size = skb->len - ((unsigned char *)portptr - skb->h.raw);
                 iph->daddr = ms->saddr;
                 portptr[1] = ms->sport;
-                
+
                 /*
                  *	Attempt ip_masq_app call.
                  *	will fix ip_masq and iph ack_seq stuff
                  */
-                
+
                 if (ip_masq_app_pkt_in(ms, skb_p, dev) != 0)
                 {
                         /*
                          *	skb has changed, update pointers.
                          */
-                        
+
                         skb = *skb_p;
                         iph = skb->h.iph;
                         portptr = (__u16 *)&(((char *)iph)[iph->ihl*4]);
                         size = skb->len - ((unsigned char *)portptr-skb->h.raw);
                 }
-                
+
                 /*
-                 * Yug! adjust UDP/TCP and IP checksums
+                 * Yug! adjust UDP/TCP and IP checksums, also update
+		 * UDP timeouts since you cannot depend on traffic
+		 * going through the other way to hold the timeout open.
+		 * (With TCP the ACK packets hold the tunnel open).
+		 * If a TCP RST is seen collapse the tunnel!
                  */
                 if (iph->protocol==IPPROTO_UDP)
+		{
+			unsigned long 	timeout;
                         recalc_check((struct udphdr *)portptr,iph->saddr,iph->daddr,size);
+			ip_masq_set_expire(ms, 0);
+			ip_masq_set_expire(ms, ip_masq_expire->udp_timeout);
+		}
                 else
                 {
+			struct tcphdr *th;
                         skb->csum = csum_partial((void *)(((struct tcphdr *)portptr) + 1),
                                                  size - sizeof(struct tcphdr), 0);
                         tcp_send_check((struct tcphdr *)portptr,iph->saddr,iph->daddr,size,skb);
+			/* Check if TCP RST */
+			th = (struct tcphdr *)portptr;
+			if (th->rst)
+			{
+				ip_masq_set_expire(ms, 0);
+				ms->flags |= IP_MASQ_F_SAW_RST;
+				ip_masq_set_expire(ms, 1);
+			}
+
                 }
                 ip_send_check(iph);
 #ifdef DEBUG_CONFIG_IP_MASQUERADE
@@ -624,7 +666,7 @@
 #endif
                 return 1;
  	}
-        
+
  	/* sorry, all this trouble for a no-hit :) */
  	return 0;
 }
@@ -695,7 +737,7 @@
  *	Initialize ip masquerading
  */
 int ip_masq_init(void)
-{  
+{
         register_symtab (&ip_masq_syms);
 	proc_net_register(&(struct proc_dir_entry) {
 		PROC_NET_IPMSQHST, 13, "ip_masquerade",
@@ -704,6 +746,6 @@
 		ip_msqhst_procinfo
 	});
         ip_masq_app_init();
-        
+
         return 0;
 }
diff -u --recursive --new-file v1.3.93/linux/net/ipv4/ip_masq_app.c linux/net/ipv4/ip_masq_app.c
--- v1.3.93/linux/net/ipv4/ip_masq_app.c	Fri Apr 12 15:52:12 1996
+++ linux/net/ipv4/ip_masq_app.c	Mon Apr 22 11:27:00 1996
@@ -437,24 +437,35 @@
         int len=0;
         struct ip_masq_app * mapp;
         unsigned idx;
-        len=sprintf(buffer,"prot port    n_attach\n");
+
+	if (offset < 22)
+		len=sprintf(buffer,"%-21s\n", "prot port    n_attach");
+	pos = 22;
+
         for (idx=0 ; idx < IP_MASQ_APP_TAB_SIZE; idx++)
                 for (mapp = ip_masq_app_base[idx]; mapp ; mapp = mapp->next) {
-                        len += sprintf(buffer+len, "%s  %-7u %-7d\n",
+			/* 
+			 * If you change the length of this sprintf, then all
+			 * the length calculations need fixing too!
+			 * Line length = 22 (3 + 2 + 7 + 1 + 7 + 1 + 1)
+			 */
+			pos += 22;
+			if (pos < offset)
+				continue;
+
+                        len += sprintf(buffer+len, "%-3s  %-7u %-7d \n",
                                        masq_proto_name(IP_MASQ_APP_PROTO(mapp->type)),
                                        IP_MASQ_APP_PORT(mapp->type), mapp->n_attach);
-                        pos=begin+len;
-                        if(pos<offset) {
-                                len=0;
-                                begin=pos;
-                        }
-                        if(pos>offset+length)
-                                break;
+
+                        if(len >= length)
+                                goto done;
                 }
-        *start=buffer+(offset-begin);
-        len-=(offset-begin);
-        if(len>length)
-                len=length;	
+done:
+	begin = len - (pos - offset);
+        *start = buffer + begin;
+        len -= begin;
+        if (len > length)
+                len = length;	
         return len;
 }
 
diff -u --recursive --new-file v1.3.93/linux/net/ipv4/ip_masq_ftp.c linux/net/ipv4/ip_masq_ftp.c
--- v1.3.93/linux/net/ipv4/ip_masq_ftp.c	Wed Apr 10 17:02:28 1996
+++ linux/net/ipv4/ip_masq_ftp.c	Mon Apr 22 11:27:00 1996
@@ -66,12 +66,12 @@
 	iph = skb->h.iph;
         th = (struct tcphdr *)&(((char *)iph)[iph->ihl*4]);
         data = (char *)&th[1];
-        
+
         data_limit = skb->h.raw + skb->len - 18;
 
 	while (data < data_limit)
 	{
-		if (memcmp(data,"PORT ",5) && memcmp(data,"port ",5)) 
+		if (memcmp(data,"PORT ",5) && memcmp(data,"port ",5))
 		{
 			data ++;
 			continue;
@@ -99,21 +99,38 @@
 		from = (p1<<24) | (p2<<16) | (p3<<8) | p4;
 		port = (p5<<8) | p6;
 #if DEBUG_CONFIG_IP_MASQ_FTP
-		printk("PORT %lX:%X detected\n",from,port);
+		printk("PORT %X:%X detected\n",from,port);
 #endif	
 		/*
-		 * Now create an masquerade entry for it
+		 * Now update or create an masquerade entry for it
 		 */
-                n_ms = ip_masq_new(dev, IPPROTO_TCP,
-                                   htonl(from), htons(port),
-                                   iph->daddr, 0,
-                                   IP_MASQ_F_NO_DPORT);
-                                   
-		if (n_ms==NULL)
-			return 0;
+#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,
+					 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(dev, IPPROTO_TCP,
+					   htonl(from), htons(port),
+					   iph->daddr, 0,
+					   IP_MASQ_F_NO_DPORT);
+					
+			if (n_ms==NULL)
+				return 0;
+		}
+
+                /*
+                 * 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);
 
-                ip_masq_set_expire(n_ms, ip_masq_expire->tcp_fin_timeout);
-                
 		/*
 		 * Replace the old PORT with the new one
 		 */
@@ -123,7 +140,10 @@
 			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	
+
 		/*
 		 * Calculate required delta-offset to keep TCP happy
 		 */
@@ -133,8 +153,8 @@
 		/*
 		 *	No shift.
 		 */
-		 
-		if (diff==0) 
+		
+		if (diff==0)
 		{
 			/*
 			 * simple case, just replace the old PORT cmd
@@ -153,6 +173,7 @@
 
 struct ip_masq_app ip_masq_ftp = {
         NULL,			/* next */
+	"ftp",			/* name */
         0,                      /* type */
         0,                      /* n_attach */
         masq_ftp_init_1,        /* ip_masq_init_1 */
diff -u --recursive --new-file v1.3.93/linux/net/ipv4/ip_masq_irc.c linux/net/ipv4/ip_masq_irc.c
--- v1.3.93/linux/net/ipv4/ip_masq_irc.c	Wed Apr 10 17:02:28 1996
+++ linux/net/ipv4/ip_masq_irc.c	Mon Apr 22 11:27:00 1996
@@ -224,6 +224,7 @@
 
 struct ip_masq_app ip_masq_irc = {
         NULL,			/* next */
+	"irc",			/* name */
         0,                      /* type */
         0,                      /* n_attach */
         masq_irc_init_1,        /* init_1 */
diff -u --recursive --new-file v1.3.93/linux/net/ipv4/ipip.c linux/net/ipv4/ipip.c
--- v1.3.93/linux/net/ipv4/ipip.c	Sun Apr 21 12:39:03 1996
+++ linux/net/ipv4/ipip.c	Mon Apr 22 12:31:47 1996
@@ -74,6 +74,25 @@
 	skb->h.iph=(struct iphdr *)skb->data;
 	skb->ip_hdr=(struct iphdr *)skb->data;
 	memset(skb->proto_priv, 0, sizeof(struct options));
+	if (skb->ip_hdr->ihl > 5) 
+	{
+		if (ip_options_compile(NULL, skb))
+			return 0;
+	}
+	
+#ifdef CONFIG_FIREWALL
+	/*
+	 *	Check the firewall [well spotted Olaf]
+	 */
+	 
+	if((err=call_in_firewall(PF_INET, skb->dev, skb->ip_hdr))<FW_ACCEPT)
+	{
+		if(err==FW_REJECT)
+			icmp_send(skb,ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0 , dev);
+		kfree_skb(skb, FREE_READ);
+		return 0;
+	}	
+#endif
 
 	/*
 	 *	If you want to add LZ compressed IP or things like that here,
@@ -81,12 +100,13 @@
 	 */
 	
 	/* skb=lzw_uncompress(skb); */
-
+	
 	/*
-	 *	Feed it to the IP layer.
+	 *	Feed to IP forward.
 	 */
-	ip_rcv(skb, dev, NULL);
-
+	 
+	if(ip_forward(skb, dev, 0, daddr))
+		kfree_skb(skb, FREE_READ);
 	MOD_DEC_USE_COUNT;
 	return(0);
 }
diff -u --recursive --new-file v1.3.93/linux/scripts/Menuconfig linux/scripts/Menuconfig
--- v1.3.93/linux/scripts/Menuconfig	Fri Apr 19 10:08:03 1996
+++ linux/scripts/Menuconfig	Mon Apr 22 11:11:13 1996
@@ -36,9 +36,9 @@
 [ -z "$BASH" ] && { echo "Menuconfig requires bash" 1>&2; exit 1; }
 
 #
-# Cache function definitions
+# Cache function definitions, turn off posix compliance
 #
-set -h
+set -h +o posix
 
 
 
@@ -84,7 +84,7 @@
 
 	echo -ne "'$2' '[$flag] $1' " >>MCmenu
 
-	echo -e "function $2 () { l_bool '$2' \"\$1\" }\n" >>MCradiolists
+	echo -e "function $2 () { l_bool '$2' \"\$1\" ;}\n" >>MCradiolists
 }
 
 #
@@ -109,7 +109,7 @@
 		echo -ne "'$2' '<$flag> $1' " >>MCmenu
 	
 		echo -e "
-		function $2 () { l_tristate '$2' \"\$1\" }" >>MCradiolists
+		function $2 () { l_tristate '$2' \"\$1\" ;}" >>MCradiolists
 	fi
 }
 
@@ -147,7 +147,7 @@
 
 	echo -ne "'$2' '($x) $1' " >>MCmenu
 
-	echo -e "function $2 () { l_int '$1' '$2' '$3' '$x' }" >>MCradiolists
+	echo -e "function $2 () { l_int '$1' '$2' '$3' '$x' ;}" >>MCradiolists
 }
 
 #
@@ -158,7 +158,7 @@
 
 	echo -ne "'$2' '($x) $1' " >>MCmenu
 
-	echo -e "function $2 () { l_hex '$1' '$2' '$3' '$x' }" >>MCradiolists
+	echo -e "function $2 () { l_hex '$1' '$2' '$3' '$x' ;}" >>MCradiolists
 }
 
 #
@@ -196,7 +196,7 @@
 
 	echo -e "
 	function $firstchoice () \
-		{ l_choice '$title' \"$choices\" $current }" >>MCradiolists
+		{ l_choice '$title' \"$choices\" $current ;}" >>MCradiolists
 }
 
 } # END load_functions()
@@ -331,7 +331,7 @@
 
 	echo -ne "'$2' '<$flag> $1' " >>MCmenu
 
-	echo -e "function $2 () { l_mod_bool '$2' \"\$1\" }" >>MCradiolists
+	echo -e "function $2 () { l_mod_bool '$2' \"\$1\" ;}" >>MCradiolists
 }
 
 #
@@ -1020,7 +1020,7 @@
 set_geometry () {
 	# Some distributions export these with incorrect values
 	# which can really screw up some ncurses programs.
-	unset LINES COLUMNS
+	LINES=  COLUMNS=
 
 	ROWS=${1:-24}  COLS=${2:-80} 
 
